changeset 719:7261ff0f95ff

Implemented first class delegates. closes #101
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Wed, 22 Oct 2008 21:50:08 +0200
parents 72ee105be27b
children e177ae483f8e
files dmd/statement.c gen/functions.cpp gen/llvmhelpers.cpp gen/runtime.cpp gen/tocall.cpp gen/toir.cpp gen/tollvm.cpp gen/toobj.cpp
diffstat 8 files changed, 155 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/statement.c	Wed Oct 22 20:00:57 2008 +0200
+++ b/dmd/statement.c	Wed Oct 22 21:50:08 2008 +0200
@@ -1517,6 +1517,9 @@
 	    Expression *flde;
 	    Identifier *id;
 	    Type *tret;
+        TypeDelegate* dgty;
+        TypeDelegate* dgty2;
+        TypeDelegate* fldeTy;
 
 	    tret = func->type->nextOf();
 
@@ -1600,6 +1603,7 @@
 		 */
 		//LDC: Build arguments.
 		static FuncDeclaration *aaApply2_fd = NULL;
+        static TypeDelegate* aaApply2_dg;
 		if(!aaApply2_fd) {
 		    Arguments* args = new Arguments;
 		    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
@@ -1607,25 +1611,28 @@
 		    Arguments* dgargs = new Arguments;
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
-		    TypeDelegate* dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
-		    args->push(new Argument(STCin, dgty, NULL, NULL));
+		    aaApply2_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
+		    args->push(new Argument(STCin, aaApply2_dg, NULL, NULL));
 		    aaApply2_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply2");
 		}
 		static FuncDeclaration *aaApply_fd = NULL;
+        static TypeDelegate* aaApply_dg;
 		if(!aaApply_fd) {
 		    Arguments* args = new Arguments;
 		    args->push(new Argument(STCin, Type::tvoid->pointerTo(), NULL, NULL));
 		    args->push(new Argument(STCin, Type::tsize_t, NULL, NULL));
 		    Arguments* dgargs = new Arguments;
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
-		    TypeDelegate* dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
-		    args->push(new Argument(STCin, dgty, NULL, NULL));
+		    aaApply_dg = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
+		    args->push(new Argument(STCin, aaApply_dg, NULL, NULL));
 		    aaApply_fd = FuncDeclaration::genCfunc(args, Type::tindex, "_aaApply");
 		}
 		if (dim == 2) {
 		    fdapply = aaApply2_fd;
+            fldeTy = aaApply2_dg;
 		} else {
 		    fdapply = aaApply_fd;
+            fldeTy = aaApply_dg;
 		}
 		ec = new VarExp(0, fdapply);
 		Expressions *exps = new Expressions();
@@ -1633,7 +1640,15 @@
 		size_t keysize = taa->key->size();
 		keysize = (keysize + 3) & ~3;
 		exps->push(new IntegerExp(0, keysize, Type::tsize_t));
+
+        // LDC paint delegate argument to the type runtime expects
+        if (!fldeTy->equals(flde->type))
+        {
+            flde = new CastExp(loc, flde, flde->type);
+            flde->type = fldeTy;
+        }
 		exps->push(flde);
+
 		e = new CallExp(loc, ec, exps);
 		e->type = Type::tindex;	// don't run semantic() on e
 	    }
@@ -1674,13 +1689,13 @@
 		    Arguments* dgargs = new Arguments;
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
-		    TypeDelegate* dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
+		    dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
 		    args->push(new Argument(STCin, dgty, NULL, NULL));
 		    fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
 		} else {
 		    Arguments* dgargs = new Arguments;
 		    dgargs->push(new Argument(STCin, Type::tvoidptr, NULL, NULL));
-		    TypeDelegate* dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
+		    dgty = new TypeDelegate(new TypeFunction(dgargs, Type::tindex, 0, LINKd));
 		    args->push(new Argument(STCin, dgty, NULL, NULL));
 		    fdapply = FuncDeclaration::genCfunc(args, Type::tindex, fdname);
 		}
@@ -1690,7 +1705,15 @@
 		if (tab->ty == Tsarray)
 		   aggr = aggr->castTo(sc, tn->arrayOf());
         exps->push(aggr);
+
+        // LDC paint delegate argument to the type runtime expects
+        if (!dgty->equals(flde->type))
+        {
+            flde = new CastExp(loc, flde, flde->type);
+            flde->type = dgty;
+        }
 		exps->push(flde);
+
 		e = new CallExp(loc, ec, exps);
 		e->type = Type::tindex;	// don't run semantic() on e
 	    }
--- a/gen/functions.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/functions.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -123,15 +123,24 @@
 
         const LLType* at = DtoType(argT);
 
+        // handle lazy args
+        if (arg->storageClass & STClazy)
+        {
+            Logger::println("lazy param");
+            TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd);
+            TypeDelegate *ltd = new TypeDelegate(ltf);
+            at = DtoType(ltd);
+            paramvec.push_back(at);
+        }
         // opaque types need special handling
-        if (llvm::isa<llvm::OpaqueType>(at)) {
+        else if (llvm::isa<llvm::OpaqueType>(at)) {
             Logger::println("opaque param");
             assert(argT->ty == Tstruct || argT->ty == Tclass);
             paramvec.push_back(getPtrToType(at));
         }
-        // structs and delegates are passed as a reference, but by value
-        else if (argT->ty == Tstruct || argT->ty == Tdelegate) {
-            Logger::println("struct/sarray param");
+        // structs are passed as a reference, but by value
+        else if (argT->ty == Tstruct) {
+            Logger::println("struct param");
             if (!refOrOut)
                 arg->llvmAttrs |= llvm::Attribute::ByVal;
             paramvec.push_back(getPtrToType(at));
@@ -156,23 +165,6 @@
                 arg->llvmAttrs |= ea;
             paramvec.push_back(at);
         }
-
-        // handle lazy args
-        if (arg->storageClass & STClazy)
-        {
-            if (Logger::enabled())
-                Logger::cout() << "for lazy got: " << *paramvec.back() << '\n';
-
-            TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd);
-            TypeDelegate *ltd = new TypeDelegate(ltf);
-            at = getPtrToType(DtoType(ltd));
-
-            if (Logger::enabled())
-                Logger::cout() << "lazy updated to: " << *at << '\n';
-
-            paramvec.back() = at;
-            // lazy doesn't need byval as the delegate is not visible to the user
-        }
     }
 
     // construct function type
@@ -652,13 +644,14 @@
             IrLocal* irloc = vd->ir.irLocal;
             assert(irloc);
 
-            bool refoutlazy = vd->storage_class & (STCref | STCout | STClazy);
+            bool refout = vd->storage_class & (STCref | STCout);
+            bool lazy = vd->storage_class & STClazy;
 
-            if (refoutlazy)
+            if (refout)
             {
                 continue;
             }
-            else if (DtoIsPassedByRef(vd->type))
+            else if (!lazy && DtoIsPassedByRef(vd->type))
             {
                 LLValue* vdirval = irloc->value;
                 if (global.params.symdebug && !(isaArgument(vdirval) && !isaArgument(vdirval)->hasByValAttr()))
@@ -875,6 +868,13 @@
         else
             arg = new DImValue(argexp->type, arg->getRVal());
     }
+    // lazy arg
+    else if (fnarg && (fnarg->storageClass & STClazy))
+    {
+        assert(argexp->type->toBasetype()->ty == Tdelegate);
+        assert(!arg->isLVal());
+        return arg;
+    }
     // byval arg, but expr has no storage yet
     else if (DtoIsPassedByRef(argexp->type) && (arg->isSlice() || arg->isNull()))
     {
--- a/gen/llvmhelpers.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/llvmhelpers.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -452,15 +452,11 @@
         }
     }
     else if (t->ty == Tdelegate) {
-        if (rhs->isNull())
-            DtoAggrZeroInit(lhs->getLVal());
-        else {
-            LLValue* l = lhs->getLVal();
-            LLValue* r = rhs->getRVal();
-            if (Logger::enabled())
-                Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
-            DtoAggrCopy(l, r);
-        }
+        LLValue* l = lhs->getLVal();
+        LLValue* r = rhs->getRVal();
+        if (Logger::enabled())
+            Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
+        DtoStore(r, l);
     }
     else if (t->ty == Tclass) {
         assert(t2->ty == Tclass);
@@ -694,21 +690,15 @@
 
 DValue* DtoCastDelegate(Loc& loc, DValue* val, Type* to)
 {
-    LLValue* res = 0;
-    to = to->toBasetype();
-
-    if (to->ty == Tdelegate)
+    if (to->toBasetype()->ty == Tdelegate)
     {
-        const LLType* toll = getPtrToType(DtoType(to));
-        res = DtoBitCast(val->getRVal(), toll);
+        return DtoPaintType(loc, val, to);
     }
     else
     {
         error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
         fatal();
     }
-
-    return new DImValue(to, res);
 }
 
 DValue* DtoCast(Loc& loc, DValue* val, Type* to)
@@ -773,6 +763,31 @@
             return new DImValue(to, DtoAggrPair(len, ptr, "tmp"));
         }
     }
+    else if (from->ty == Tdelegate)
+    {
+        Type* dgty = to->toBasetype();
+        assert(dgty->ty == Tdelegate);
+        if (val->isLVal())
+        {
+            LLValue* ptr = val->getLVal();
+            assert(isaPointer(ptr));
+            ptr = DtoBitCast(ptr, getPtrToType(DtoType(dgty)));
+            if (Logger::enabled())
+                Logger::cout() << "dg ptr: " << *ptr << '\n';
+            return new DVarValue(to, ptr);
+        }
+        else
+        {
+            LLValue* dg = val->getRVal();
+            LLValue* context = gIR->ir->CreateExtractValue(dg, 0, ".context");
+            LLValue* funcptr = gIR->ir->CreateExtractValue(dg, 1, ".funcptr");
+            funcptr = DtoBitCast(funcptr, DtoType(dgty)->getContainedType(1));
+            LLValue* aggr = DtoAggrPair(context, funcptr, "tmp");
+            if (Logger::enabled())
+                Logger::cout() << "dg: " << *aggr << '\n';
+            return new DImValue(to, aggr);
+        }
+    }
     else if (from->ty == Tpointer || from->ty == Tclass || from->ty == Taarray)
     {
         Type* b = to->toBasetype();
--- a/gen/runtime.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/runtime.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -119,11 +119,7 @@
     types.push_back(rt_ptr(LLType::Int8Ty));
     types.push_back(rt_ptr(LLType::Int8Ty));
     const llvm::FunctionType* fty = llvm::FunctionType::get(LLType::Int32Ty, types, false);
-
-    std::vector<const LLType*> t;
-    t.push_back(rt_ptr(LLType::Int8Ty));
-    t.push_back(rt_ptr(fty));
-    return rt_ptr(llvm::StructType::get(t));
+    return llvm::StructType::get(rt_ptr(LLType::Int8Ty), rt_ptr(fty), 0);
 }
 
 static const LLType* rt_dg2()
@@ -133,11 +129,7 @@
     types.push_back(rt_ptr(LLType::Int8Ty));
     types.push_back(rt_ptr(LLType::Int8Ty));
     const llvm::FunctionType* fty = llvm::FunctionType::get(LLType::Int32Ty, types, false);
-
-    std::vector<const LLType*> t;
-    t.push_back(rt_ptr(LLType::Int8Ty));
-    t.push_back(rt_ptr(fty));
-    return rt_ptr(llvm::StructType::get(t));
+    return llvm::StructType::get(rt_ptr(LLType::Int8Ty), rt_ptr(fty), 0);
 }
 
 static void LLVM_D_BuildRuntimeModule()
@@ -365,10 +357,8 @@
         types.push_back(TY); \
         types.push_back(rt_dg1()); \
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
-        llvm::AttrListPtr palist; \
-        palist = palist.addAttr(2, llvm::Attribute::ByVal); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M)->setAttributes(palist); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
     }
     STR_APPLY1(stringTy, "_aApplycw1", "_aApplycd1")
     STR_APPLY1(wstringTy, "_aApplywc1", "_aApplywd1")
@@ -384,10 +374,8 @@
         types.push_back(TY); \
         types.push_back(rt_dg2()); \
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
-        llvm::AttrListPtr palist; \
-        palist = palist.addAttr(2, llvm::Attribute::ByVal); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M)->setAttributes(palist); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
     }
     STR_APPLY2(stringTy, "_aApplycw2", "_aApplycd2")
     STR_APPLY2(wstringTy, "_aApplywc2", "_aApplywd2")
@@ -402,10 +390,8 @@
         types.push_back(TY); \
         types.push_back(rt_dg1()); \
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
-        llvm::AttrListPtr palist; \
-        palist = palist.addAttr(2, llvm::Attribute::ByVal); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M)->setAttributes(palist); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
     }
     STR_APPLY_R1(stringTy, "_aApplyRcw1", "_aApplyRcd1")
     STR_APPLY_R1(wstringTy, "_aApplyRwc1", "_aApplyRwd1")
@@ -420,10 +406,8 @@
         types.push_back(TY); \
         types.push_back(rt_dg2()); \
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
-        llvm::AttrListPtr palist; \
-        palist = palist.addAttr(2, llvm::Attribute::ByVal); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist); \
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M)->setAttributes(palist); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
     }
     STR_APPLY_R2(stringTy, "_aApplyRcw2", "_aApplyRcd2")
     STR_APPLY_R2(wstringTy, "_aApplyRwc2", "_aApplyRwd2")
@@ -662,9 +646,7 @@
         types.push_back(sizeTy);
         types.push_back(rt_dg1());
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
-        llvm::AttrListPtr palist;
-        palist = palist.addAttr(3, llvm::Attribute::ByVal);
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist);
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
     }
 
     // int _aaApply2(AA aa, size_t keysize, dg2_t dg)
@@ -675,9 +657,7 @@
         types.push_back(sizeTy);
         types.push_back(rt_dg2());
         const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
-        llvm::AttrListPtr palist;
-        palist = palist.addAttr(3, llvm::Attribute::ByVal);
-        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M)->setAttributes(palist);
+        llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
     }
 
     /////////////////////////////////////////////////////////////////////////////////////
--- a/gen/tocall.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/tocall.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -75,11 +75,18 @@
     }
     else if (type->ty == Tdelegate)
     {
-        LLValue* dg = fn->getRVal();
-        if (Logger::enabled())
-            Logger::cout() << "delegate: " << *dg << '\n';
-        LLValue* funcptr = DtoGEPi(dg, 0, 1);
-        return DtoLoad(funcptr);
+        if (fn->isLVal())
+        {
+            LLValue* dg = fn->getLVal();
+            LLValue* funcptr = DtoGEPi(dg, 0, 1);
+            return DtoLoad(funcptr);
+        }
+        else
+        {
+            LLValue* dg = fn->getRVal();
+            assert(isaStruct(dg));
+            return gIR->ir->CreateExtractValue(dg, 1, ".funcptr");
+        }
     }
     else
     {
@@ -266,7 +273,15 @@
         // ... or a delegate context arg
         else if (delegatecall)
         {
-            LLValue* ctxarg = DtoLoad(DtoGEPi(fnval->getRVal(), 0,0));
+            LLValue* ctxarg;
+            if (fnval->isLVal())
+            {
+                ctxarg = DtoLoad(DtoGEPi(fnval->getLVal(), 0,0));
+            }
+            else
+            {
+                ctxarg = gIR->ir->CreateExtractValue(fnval->getRVal(), 0, ".ptr");
+            }
             assert(ctxarg->getType() == argiter->get());
             ++argiter;
             args.push_back(ctxarg);
--- a/gen/toir.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/toir.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -110,11 +110,17 @@
         // function parameter
         else if (vd->isParameter()) {
             Logger::println("function param");
+            Logger::println("type: %s", vd->type->toChars());
             FuncDeclaration* fd = vd->toParent2()->isFuncDeclaration();
             if (fd && fd != p->func()->decl) {
                 Logger::println("nested parameter");
                 return DtoNestedVariable(loc, type, vd);
             }
+            else if (vd->storage_class & STClazy) {
+                Logger::println("lazy parameter");
+                assert(type->ty == Tdelegate);
+                return new DVarValue(type, vd->ir.getIrValue());
+            }
             else if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa<llvm::AllocaInst>(vd->ir.getIrValue())) {
                 return new DVarValue(type, vd, vd->ir.getIrValue());
             }
@@ -1833,7 +1839,8 @@
 
     const LLPointerType* int8ptrty = getPtrToType(LLType::Int8Ty);
 
-    LLValue* lval = DtoAlloca(DtoType(type), "tmpdelegate");
+    assert(type->toBasetype()->ty == Tdelegate);
+    const LLType* dgty = DtoType(type);
 
     DValue* u = e1->toElem(p);
     LLValue* uval;
@@ -1859,11 +1866,7 @@
     if (Logger::enabled())
         Logger::cout() << "context = " << *uval << '\n';
 
-    LLValue* context = DtoGEPi(lval,0,0);
     LLValue* castcontext = DtoBitCast(uval, int8ptrty);
-    DtoStore(castcontext, context);
-
-    LLValue* fptr = DtoGEPi(lval,0,1);
 
     Logger::println("func: '%s'", func->toPrettyChars());
 
@@ -1880,10 +1883,9 @@
         castfptr = func->ir.irFunc->func;
     }
 
-    castfptr = DtoBitCast(castfptr, fptr->getType()->getContainedType(0));
-    DtoStore(castfptr, fptr);
-
-    return new DImValue(type, lval);
+    castfptr = DtoBitCast(castfptr, dgty->getContainedType(1));
+
+    return new DImValue(type, DtoAggrPair(castcontext, castfptr, ".dg"));
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -2098,12 +2100,9 @@
     DtoForceDefineDsymbol(fd);
     assert(fd->ir.irFunc->func);
 
-    LLValue *lval, *fptr;
     if(fd->tok == TOKdelegate) {
         const LLType* dgty = DtoType(type);
-        lval = DtoAlloca(dgty,"dgstorage");
-
-        LLValue* context = DtoGEPi(lval,0,0);
+
         LLValue* cval;
         IrFunction* irfn = p->func();
         if (irfn->nestedVar)
@@ -2112,15 +2111,11 @@
             cval = irfn->nestArg;
         else
             cval = getNullPtr(getVoidPtrType());
-        cval = DtoBitCast(cval, context->getType()->getContainedType(0));
-        DtoStore(cval, context);
-
-        fptr = DtoGEPi(lval,0,1,"tmp",p->scopebb());
-
-        LLValue* castfptr = DtoBitCast(fd->ir.irFunc->func, fptr->getType()->getContainedType(0));
-        DtoStore(castfptr, fptr);
-
-        return new DVarValue(type, lval);
+        cval = DtoBitCast(cval, dgty->getContainedType(0));
+
+        LLValue* castfptr = DtoBitCast(fd->ir.irFunc->func, dgty->getContainedType(1));
+
+        return new DImValue(type, DtoAggrPair(cval, castfptr, ".func"));
 
     } else if(fd->tok == TOKfunction) {
         return new DImValue(type, fd->ir.irFunc->func);
--- a/gen/tollvm.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/tollvm.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -25,14 +25,14 @@
 {
     Type* typ = type->toBasetype();
     TY t = typ->ty;
-    return (t == Tstruct || t == Tdelegate || t == Tsarray);
+    return (t == Tstruct || t == Tsarray);
 }
 
 bool DtoIsReturnedInArg(Type* type)
 {
     Type* typ = type->toBasetype();
     TY t = typ->ty;
-    return (t == Tstruct || t == Tdelegate || t == Tsarray);
+    return (t == Tstruct || t == Tsarray);
 }
 
 unsigned DtoShouldExtend(Type* type)
@@ -221,6 +221,7 @@
 
 const LLStructType* DtoDelegateType(Type* t)
 {
+    assert(t->ty == Tdelegate);
     const LLType* i8ptr = getVoidPtrType();
     const LLType* func = DtoFunctionType(t->next, NULL, i8ptr);
     const LLType* funcptr = getPtrToType(func);
@@ -235,25 +236,22 @@
     llvm::Value *b1, *b2;
     if (rhs == NULL)
     {
-        LLValue* l = DtoLoad(DtoGEPi(lhs,0,0));
-        LLValue* r = llvm::Constant::getNullValue(l->getType());
-        b1 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
-        l = DtoLoad(DtoGEPi(lhs,0,1));
-        r = llvm::Constant::getNullValue(l->getType());
-        b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
+        rhs = LLConstant::getNullValue(lhs->getType());
     }
-    else
-    {
-        LLValue* l = DtoLoad(DtoGEPi(lhs,0,0));
-        LLValue* r = DtoLoad(DtoGEPi(rhs,0,0));
-        b1 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
-        l = DtoLoad(DtoGEPi(lhs,0,1));
-        r = DtoLoad(DtoGEPi(rhs,0,1));
-        b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
-    }
+
+    LLValue* l = gIR->ir->CreateExtractValue(lhs, 0);
+    LLValue* r = gIR->ir->CreateExtractValue(rhs, 0);
+    b1 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
+
+    l = gIR->ir->CreateExtractValue(lhs, 1);
+    r = gIR->ir->CreateExtractValue(rhs, 1);
+    b2 = gIR->ir->CreateICmp(llvm::ICmpInst::ICMP_EQ,l,r,"tmp");
+
     LLValue* b = gIR->ir->CreateAnd(b1,b2,"tmp");
+
     if (op == TOKnotequal || op == TOKnotidentity)
         return gIR->ir->CreateNot(b,"tmp");
+
     return b;
 }
 
@@ -557,8 +555,8 @@
 
 LLValue* DtoLoad(LLValue* src, const char* name)
 {
-    if (Logger::enabled())
-        Logger::cout() << "loading " << *src <<  '\n';
+//     if (Logger::enabled())
+//         Logger::cout() << "loading " << *src <<  '\n';
     LLValue* ld = gIR->ir->CreateLoad(src, name ? name : "tmp");
     //ld->setVolatile(gIR->func()->inVolatile);
     return ld;
@@ -566,8 +564,8 @@
 
 void DtoStore(LLValue* src, LLValue* dst)
 {
-    if (Logger::enabled())
-        Logger::cout() << "storing " << *src << " into " << *dst << '\n';
+//     if (Logger::enabled())
+//         Logger::cout() << "storing " << *src << " into " << *dst << '\n';
     LLValue* st = gIR->ir->CreateStore(src,dst);
     //st->setVolatile(gIR->func()->inVolatile);
 }
--- a/gen/toobj.cpp	Wed Oct 22 20:00:57 2008 +0200
+++ b/gen/toobj.cpp	Wed Oct 22 21:50:08 2008 +0200
@@ -75,7 +75,7 @@
     Logger::println("Generating module: %s\n", (md ? md->toChars() : toChars()));
     LOG_SCOPE;
 
-    //printf("codegen: %s\n", srcfile->toChars());
+    printf("codegen: %s\n", srcfile->toChars());
 
     // start by deleting the old object file
     deleteObjFile();