changeset 98:6789050b5ad1 trunk

[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.
author lindquist
date Wed, 14 Nov 2007 23:39:10 +0100
parents c4e161556a21
children a676a7743642
files gen/arrays.cpp gen/arrays.h gen/irstate.h gen/runtime.cpp gen/statements.cpp gen/toir.cpp gen/tollvm.cpp gen/toobj.cpp gen/typinf.cpp llvmdc.kdevelop.filelist lphobos/build.sh lphobos/internal/adi.d test/arrays11.d
diffstat 13 files changed, 162 insertions(+), 119 deletions(-) [+]
line wrap: on
line diff
--- a/gen/arrays.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/arrays.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -546,93 +546,60 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
-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);
-    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);
-
-    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());
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
-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);
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_adEq");
     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);
+    llvm::Value* lmem;
+    llvm::Value* rmem;
 
-    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());
+    // 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* 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);
+    // 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();
 
-        rrmem = new llvm::AllocaInst(arrType,"tmparr",gIR->topallocapoint());
+    if (r->isSlice()) {
+        rmem = new llvm::AllocaInst(DtoType(r->getType()), "tmpparam", gIR->topallocapoint());
+        DtoSetArray(rmem, DtoArrayLen(r), DtoArrayPtr(r));
+    }
+    else
+        rmem = r->getRVal();
 
-        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);
-    }
+    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;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/arrays.h	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/arrays.h	Wed Nov 14 23:39:10 2007 +0100
@@ -27,9 +27,8 @@
 
 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);
--- a/gen/irstate.h	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/irstate.h	Wed Nov 14 23:39:10 2007 +0100
@@ -162,6 +162,10 @@
 
     // builder helper
     IRBuilderHelper ir;
+
+    // functions queued for lazy definition
+    typedef std::vector<FuncDeclaration*> FuncDeclVector;
+    FuncDeclVector funcQueue;
 };
 
 #endif // LLVMDC_GEN_IRSTATE_H
--- a/gen/runtime.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/runtime.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -61,9 +61,6 @@
 
 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_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;
     }
 
--- a/gen/statements.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/statements.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -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++)
--- a/gen/toir.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/toir.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -64,6 +64,7 @@
                 //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 @@
     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 @@
 
             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 @@
         }
         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 @@
     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)
--- a/gen/tollvm.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/tollvm.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -818,7 +818,7 @@
     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, 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 @@
 {
     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 @@
 
 llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
 {
+    if (v->getType() == t)
+        return v;
     return gIR->ir->CreateBitCast(v, t, "tmp");
 }
 
--- a/gen/toobj.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/toobj.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -90,6 +90,14 @@
         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 @@
     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 @@
         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]);
         }
     }
 
--- a/gen/typinf.cpp	Wed Nov 14 20:18:01 2007 +0100
+++ b/gen/typinf.cpp	Wed Nov 14 23:39:10 2007 +0100
@@ -243,14 +243,18 @@
     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 {
--- a/llvmdc.kdevelop.filelist	Wed Nov 14 20:18:01 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Wed Nov 14 23:39:10 2007 +0100
@@ -221,6 +221,7 @@
 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/structs4.d
 test/structs5.d
 test/structs6.d
+test/structs7.d
 test/switch1.d
 test/sync1.d
 test/templ1.d
--- a/lphobos/build.sh	Wed Nov 14 20:18:01 2007 +0100
+++ b/lphobos/build.sh	Wed Nov 14 23:39:10 2007 +0100
@@ -18,9 +18,6 @@
 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 @@
 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
--- a/lphobos/internal/adi.d	Wed Nov 14 20:18:01 2007 +0100
+++ b/lphobos/internal/adi.d	Wed Nov 14 23:39:10 2007 +0100
@@ -38,6 +38,7 @@
 import std.outofmemory;
 import std.utf;
 
+pragma(LLVM_internal, "notypeinfo")
 struct Array
 {
     size_t length;
@@ -478,6 +479,7 @@
     {
     printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
     }
+    printf("sz = %u\n", sz);
 +/
 
     if (sz == 1)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/arrays11.d	Wed Nov 14 23:39:10 2007 +0100
@@ -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();
+}