[svn r102] Further delayed emission of function bodies to avoid problems with circular-forward-references.

Now uses the DMD _adEq(void[], void[], TypeInfo) runtime function for array equality comparison.
This commit is contained in:
Tomas Lindquist Olsen
2007-11-14 23:39:10 +01:00
parent 46d8929fb6
commit 302015d7e8
13 changed files with 163 additions and 120 deletions

View File

@@ -546,93 +546,60 @@ void DtoCatArrays(llvm::Value* arr, Expression* exp1, Expression* exp2)
}
//////////////////////////////////////////////////////////////////////////////////////////
llvm::Value* DtoStaticArrayCompare(TOK op, llvm::Value* l, llvm::Value* r)
llvm::Value* DtoArrayEquals(TOK op, DValue* l, DValue* r)
{
const char* fname;
if (op == TOKequal)
fname = "_d_static_array_eq";
else if (op == TOKnotequal)
fname = "_d_static_array_neq";
else
assert(0);
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_adEq");
assert(fn);
assert(l->getType() == r->getType());
assert(isaPointer(l->getType()));
const llvm::Type* arrty = l->getType()->getContainedType(0);
assert(isaArray(arrty));
llvm::Value* ll = new llvm::BitCastInst(l, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp", gIR->scopebb());
llvm::Value* rr = new llvm::BitCastInst(r, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp", gIR->scopebb());
llvm::Value* n = llvm::ConstantInt::get(DtoSize_t(),gTargetData->getTypeSize(arrty),false);
llvm::Value* lmem;
llvm::Value* rmem;
std::vector<llvm::Value*> args;
args.push_back(ll);
args.push_back(rr);
args.push_back(n);
return new llvm::CallInst(fn, args.begin(), args.end(), "tmp", gIR->scopebb());
}
// cast static arrays to dynamic ones, this turns them into DSliceValues
Type* l_ty = DtoDType(l->getType());
Type* r_ty = DtoDType(r->getType());
assert(l_ty->next == r_ty->next);
Type* a_ty = new Type(Tarray, l_ty->next);
if (l_ty->ty == Tsarray)
l = DtoCastArray(l, a_ty);
if (r_ty->ty == Tsarray)
r = DtoCastArray(r, a_ty);
//////////////////////////////////////////////////////////////////////////////////////////
llvm::Value* DtoDynArrayCompare(TOK op, llvm::Value* l, llvm::Value* r)
{
const char* fname;
if (op == TOKequal)
fname = "_d_dyn_array_eq";
else if (op == TOKnotequal)
fname = "_d_dyn_array_neq";
else
assert(0);
llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);
assert(fn);
Logger::cout() << "lhsType:" << *l->getType() << "\nrhsType:" << *r->getType() << '\n';
assert(l->getType() == r->getType());
assert(isaPointer(l->getType()));
const llvm::StructType* structType = isaStruct(l->getType()->getContainedType(0));
assert(structType);
const llvm::Type* elemType = structType->getElementType(1)->getContainedType(0);
std::vector<const llvm::Type*> arrTypes;
arrTypes.push_back(DtoSize_t());
arrTypes.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
const llvm::StructType* arrType = llvm::StructType::get(arrTypes);
llvm::Value* llmem = l;
llvm::Value* rrmem = r;
if (structType != arrType) {
llmem= new llvm::AllocaInst(arrType,"tmparr",gIR->topallocapoint());
llvm::Value* ll = gIR->ir->CreateLoad(DtoGEPi(l, 0,0, "tmp"),"tmp");
ll = DtoArrayCastLength(ll, elemType, llvm::Type::Int8Ty);
llvm::Value* lllen = DtoGEPi(llmem, 0,0, "tmp");
gIR->ir->CreateStore(ll,lllen);
ll = gIR->ir->CreateLoad(DtoGEPi(l, 0,1, "tmp"),"tmp");
ll = new llvm::BitCastInst(ll, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp", gIR->scopebb());
llvm::Value* llptr = DtoGEPi(llmem, 0,1, "tmp");
gIR->ir->CreateStore(ll,llptr);
rrmem = new llvm::AllocaInst(arrType,"tmparr",gIR->topallocapoint());
llvm::Value* rr = gIR->ir->CreateLoad(DtoGEPi(r, 0,0, "tmp"),"tmp");
rr = DtoArrayCastLength(rr, elemType, llvm::Type::Int8Ty);
llvm::Value* rrlen = DtoGEPi(rrmem, 0,0, "tmp");
gIR->ir->CreateStore(rr,rrlen);
rr = gIR->ir->CreateLoad(DtoGEPi(r, 0,1, "tmp"),"tmp");
rr = new llvm::BitCastInst(rr, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp", gIR->scopebb());
llvm::Value* rrptr = DtoGEPi(rrmem, 0,1, "tmp");
gIR->ir->CreateStore(rr,rrptr);
// we need to give slices storage
if (l->isSlice()) {
lmem = new llvm::AllocaInst(DtoType(l->getType()), "tmpparam", gIR->topallocapoint());
DtoSetArray(lmem, DtoArrayLen(l), DtoArrayPtr(l));
}
else
lmem = l->getRVal();
if (r->isSlice()) {
rmem = new llvm::AllocaInst(DtoType(r->getType()), "tmpparam", gIR->topallocapoint());
DtoSetArray(rmem, DtoArrayLen(r), DtoArrayPtr(r));
}
else
rmem = r->getRVal();
const llvm::Type* pt = fn->getFunctionType()->getParamType(0);
std::vector<llvm::Value*> args;
args.push_back(llmem);
args.push_back(rrmem);
return new llvm::CallInst(fn, args.begin(), args.end(), "tmp", gIR->scopebb());
args.push_back(DtoBitCast(lmem,pt));
args.push_back(DtoBitCast(rmem,pt));
TypeInfoDeclaration* ti = DtoDType(l->getType())->next->getTypeInfoDeclaration();
if (!ti->llvmValue) {
ti->toObjFile();
}
Logger::cout() << "typeinfo decl: " << *ti->llvmValue << '\n';
pt = fn->getFunctionType()->getParamType(2);
args.push_back(DtoBitCast(ti->llvmValue, pt));
llvm::Value* res = gIR->ir->CreateCall(fn, args.begin(), args.end(), "tmp");
if (op == TOKnotequal)
res = gIR->ir->CreateNot(res, "tmp");
return res;
}
//////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -27,9 +27,8 @@ void DtoCatArrays(llvm::Value* arr, Expression* e1, Expression* e2);
void DtoStaticArrayCopy(llvm::Value* dst, llvm::Value* src);
llvm::Value* DtoStaticArrayCompare(TOK op, llvm::Value* l, llvm::Value* r);
llvm::Value* DtoArrayEquals(TOK op, DValue* l, DValue* r);
llvm::Value* DtoDynArrayCompare(TOK op, llvm::Value* l, llvm::Value* r);
llvm::Value* DtoDynArrayIs(TOK op, llvm::Value* l, llvm::Value* r);
llvm::Value* DtoArrayCastLength(llvm::Value* len, const llvm::Type* elemty, const llvm::Type* newelemty);

View File

@@ -162,6 +162,10 @@ struct IRState
// builder helper
IRBuilderHelper ir;
// functions queued for lazy definition
typedef std::vector<FuncDeclaration*> FuncDeclVector;
FuncDeclVector funcQueue;
};
#endif // LLVMDC_GEN_IRSTATE_H

View File

@@ -61,9 +61,6 @@ void LLVM_D_FreeRuntime()
llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name)
{
// TODO maybe check the target module first, to allow overriding the runtime on a pre module basis?
// could be done and seems like it could be neat too :)
if (global.params.noruntime) {
error("No implicit runtime calls allowed with -noruntime option enabled");
fatal();
@@ -74,10 +71,14 @@ llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name
LLVM_D_InitRuntime();
}
llvm::Function* fn = M->getFunction(name);
llvm::Function* fn = target->getFunction(name);
if (fn)
return fn;
fn = M->getFunction(name);
if (!fn) {
error("Runtime function '%s' was not found", name);
fatal();
printf("Runtime function '%s' was not found\n", name);
assert(0);
//return NULL;
}

View File

@@ -26,8 +26,7 @@
void CompoundStatement::toIR(IRState* p)
{
static int csi = 0;
Logger::println("CompoundStatement::toIR(%d):\n<<<\n%s>>>", csi++, toChars());
Logger::println("CompoundStatement::toIR()");
LOG_SCOPE;
for (int i=0; i<statements->dim; i++)

View File

@@ -64,6 +64,7 @@ DValue* DeclarationExp::toElem(IRState* p)
//allocainst->setAlignment(vd->type->alignsize()); // TODO
vd->llvmValue = allocainst;
}
Logger::cout() << "llvm value for decl: " << *vd->llvmValue << '\n';
DValue* ie = DtoInitializer(vd->init);
}
@@ -1364,19 +1365,14 @@ DValue* SymOffExp::toElem(IRState* p)
Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars());
LOG_SCOPE;
assert(0 && "SymOffExp::toElem should no longer be called :/");
if (VarDeclaration* vd = var->isVarDeclaration())
{
Logger::println("VarDeclaration");
if (!vd->llvmTouched && vd->isDataseg())
vd->toObjFile();
// TODO
/*
if (vd->isTypedefDeclaration()) {
e->istypeinfo = true;
}
*/
assert(vd->llvmValue);
Type* t = DtoDType(type);
Type* tnext = DtoDType(t->next);
@@ -1540,6 +1536,7 @@ DValue* DotVarExp::toElem(IRState* p)
llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
llvm::Value* vtblidx = llvm::ConstantInt::get(llvm::Type::Int32Ty, (size_t)fdecl->vtblIndex, false);
Logger::cout() << "vthis: " << *vthis << '\n';
funcval = DtoGEP(vthis, zero, zero, "tmp", p->scopebb());
funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
funcval = DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb());
@@ -1871,15 +1868,10 @@ DValue* EqualExp::toElem(IRState* p)
}
eval = new llvm::FCmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
}
else if (t->ty == Tsarray)
else if (t->ty == Tsarray || t->ty == Tarray)
{
Logger::println("static array");
eval = DtoStaticArrayCompare(op,l->getRVal(),r->getRVal());
}
else if (t->ty == Tarray)
{
Logger::println("dynamic array");
eval = DtoDynArrayCompare(op,l->getRVal(),r->getRVal());
Logger::println("static or dynamic array");
eval = DtoArrayEquals(op,l,r);
}
else if (t->ty == Tdelegate)
{
@@ -2568,12 +2560,21 @@ DValue* ArrayLiteralExp::toElem(IRState* p)
else
assert(0);
Logger::cout() << "array literal mem: " << *mem << '\n';
for (unsigned i=0; i<elements->dim; ++i)
{
Expression* expr = (Expression*)elements->data[i];
llvm::Value* elemAddr = DtoGEPi(mem,0,i,"tmp",p->scopebb());
DVarValue* vv = new DVarValue(expr->type, elemAddr, true);
p->exps.push_back(IRExp(NULL, expr, vv));
DValue* e = expr->toElem(p);
new llvm::StoreInst(e->getRVal(), elemAddr, p->scopebb());
p->exps.pop_back();
DImValue* im = e->isIm();
if (!im || !im->inPlace()) {
DtoAssign(vv, e);
}
}
if (ty->ty == Tsarray)

View File

@@ -818,7 +818,7 @@ llvm::Value* DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const st
std::vector<llvm::Value*> v(2);
v[0] = i0;
v[1] = i1;
Logger::cout() << "DtoGEP: " << *ptr << '\n';
//Logger::cout() << "DtoGEP: " << *ptr << '\n';
return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
}
@@ -827,15 +827,15 @@ llvm::Value* DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const st
llvm::Value* DtoGEP(llvm::Value* ptr, const std::vector<unsigned>& src, const std::string& var, llvm::BasicBlock* bb)
{
size_t n = src.size();
std::vector<llvm::Value*> dst(n);
std::ostream& ostr = Logger::cout();
ostr << "indices for '" << *ptr << "':";
std::vector<llvm::Value*> dst(n, NULL);
//std::ostream& ostr = Logger::cout();
//ostr << "indices for '" << *ptr << "':";
for (size_t i=0; i<n; ++i)
{
ostr << ' ' << i;
//ostr << ' ' << i;
dst[i] = llvm::ConstantInt::get(llvm::Type::Int32Ty, src[i], false);
}
ostr << '\n';
//ostr << '\n';*/
return new llvm::GetElementPtrInst(ptr, dst.begin(), dst.end(), var, bb?bb:gIR->scopebb());
}
@@ -1423,7 +1423,7 @@ DValue* DtoCastClass(DValue* val, Type* _to)
{
const llvm::Type* tolltype = DtoType(_to);
Type* to = DtoDType(_to);
assert(to->ty == Tclass);
assert(to->ty == Tclass || to->ty == Tpointer);
llvm::Value* rval = new llvm::BitCastInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
return new DImValue(_to, rval);
}
@@ -1628,6 +1628,8 @@ bool DtoCanLoad(llvm::Value* ptr)
llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
{
if (v->getType() == t)
return v;
return gIR->ir->CreateBitCast(v, t, "tmp");
}

View File

@@ -90,6 +90,14 @@ Module::genobjfile()
dsym->toObjFile();
}
// check if there are queued function definitions, if so process their bodies now
if (!ir.funcQueue.empty()) {
size_t n = ir.funcQueue.size();
for (size_t i=0; i<n; ++i) {
ir.funcQueue[i]->toObjFile();
}
}
// generate ModuleInfo
genmoduleinfo();
@@ -480,7 +488,8 @@ void StructDeclaration::toObjFile()
IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
size_t n = mfs.size();
for (size_t i=0; i<n; ++i) {
mfs[i]->toObjFile();
//mfs[i]->toObjFile();
gIR->funcQueue.push_back(mfs[i]);
}
llvmDModule = gIR->dmodule;
@@ -693,7 +702,8 @@ void ClassDeclaration::toObjFile()
IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
size_t n = mfs.size();
for (size_t i=0; i<n; ++i) {
mfs[i]->toObjFile();
//mfs[i]->toObjFile();
gIR->funcQueue.push_back(mfs[i]);
}
}

View File

@@ -243,14 +243,18 @@ void TypeInfoDeclaration::toObjFile()
Logger::println("TypeInfoDeclaration::toObjFile()");
LOG_SCOPE;
std::string mangled(mangle());
Logger::println("type = '%s'", tinfo->toChars());
Logger::println("typeinfo mangle: %s", mangle());
Logger::println("typeinfo mangle: %s", mangled.c_str());
// this is a declaration of a builtin __initZ var
if (tinfo->builtinTypeInfo()) {
llvmValue = LLVM_D_GetRuntimeGlobal(gIR->module, mangle());
llvmValue = LLVM_D_GetRuntimeGlobal(gIR->module, mangled.c_str());
assert(llvmValue);
Logger::cout() << "Got typeinfo var:" << '\n' << *llvmValue << '\n';
mangled.append("__TYPE");
gIR->module->addTypeName(mangled, llvmValue->getType()->getContainedType(0));
Logger::println("Got typeinfo var: %s", llvmValue->getName().c_str());
}
// custom typedef
else {

View File

@@ -221,6 +221,7 @@ test/alloca1.d
test/arrayinit.d
test/arrays.d
test/arrays10.d
test/arrays11.d
test/arrays2.d
test/arrays3.d
test/arrays4.d
@@ -377,6 +378,7 @@ test/structs3.d
test/structs4.d
test/structs5.d
test/structs6.d
test/structs7.d
test/switch1.d
test/sync1.d
test/templ1.d

View File

@@ -18,9 +18,6 @@ echo "compiling module init backend"
llvm-as -f -o=obj/moduleinit_backend.bc internal/moduleinit_backend.ll || exit 1
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/internal.*.bc` ../lib/llvmdcore.bc obj/moduleinit_backend.bc || exit 1
echo "compiling object implementation"
llvmdc internal/objectimpl.d -c -odobj || exit 1
llvm-link -f -o=../lib/llvmdcore.bc obj/objectimpl.bc ../lib/llvmdcore.bc || exit 1
echo "compiling typeinfo 1"
rebuild typeinfos1.d -c -oqobj -dc=llvmdc-posix || exit 1
@@ -41,6 +38,10 @@ llvm-link -f -o=../lib/llvmdcore.bc obj/qsort2.bc ../lib/llvmdcore.bc || exit 1
llvmdc internal/adi.d -c -odobj || exit
llvm-link -f -o=../lib/llvmdcore.bc obj/adi.bc ../lib/llvmdcore.bc || exit 1
echo "compiling object implementation"
llvmdc internal/objectimpl.d -c -odobj || exit 1
llvm-link -f -o=../lib/llvmdcore.bc obj/objectimpl.bc ../lib/llvmdcore.bc || exit 1
echo "compiling llvm runtime support"
rebuild llvmsupport.d -c -oqobj -dc=llvmdc-posix || exit 1
llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1

View File

@@ -38,6 +38,7 @@ import std.c.string;
import std.outofmemory;
import std.utf;
pragma(LLVM_internal, "notypeinfo")
struct Array
{
size_t length;
@@ -478,6 +479,7 @@ extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
{
printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
}
printf("sz = %u\n", sz);
+/
if (sz == 1)

51
test/arrays11.d Normal file
View File

@@ -0,0 +1,51 @@
module arrays11;
void ints()
{
int[] a = [1,2,3,4,5,6];
{assert(a == a);}
int[] b = [4,5,6,7,8,9];
{assert(a != b);}
{assert(a[3..$] == b[0..3]);}
}
void floats()
{
float[] a = [1.0f, 2.0f, 3.0f, 4.0f];
{assert(a == a);}
float[] b = [2.0f, 3.0f, 5.0f];
{assert(a != b);}
{assert(a[1..3] == b[0..2]);}
}
struct S
{
int i;
int j;
int opEquals(S s)
{
return (i == s.i) && (j == s.j);
}
}
void structs()
{
S[] a = [S(0,0), S(1,0), S(2,0), S(3,0)];
{assert(a == a);}
S[] b = [S(0,1), S(1,0), S(2,0), S(3,1)];
{assert(a != b);}
{assert(a[1..3] == b[1..3]);}
S[2] c = [S(2,0), S(3,1)];
{assert(c == b[2..$]);}
}
void main()
{
ints();
floats();
structs();
}