changeset 1211:50dc0db06238

Merge
author Frits van Bommel <fvbommel wxs.nl>
date Sun, 12 Apr 2009 22:22:15 +0200
parents 3d4581761b4c (diff) e45984519be7 (current diff)
children df2227fdc860
files gen/toir.cpp
diffstat 14 files changed, 510 insertions(+), 228 deletions(-) [+]
line wrap: on
line diff
--- a/gen/classes.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/classes.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -15,6 +15,7 @@
 #include "gen/functions.h"
 #include "gen/runtime.h"
 #include "gen/dvalue.h"
+#include "gen/nested.h"
 
 #include "ir/irstruct.h"
 
@@ -1330,7 +1331,7 @@
     // index vtbl
     funcval = DtoGEPi(funcval, 0, fdecl->vtblIndex, fdecl->toChars());
     // load funcptr
-    funcval = DtoLoad(funcval);
+    funcval = DtoAlignedLoad(funcval);
 
     if (Logger::enabled())
         Logger::cout() << "funcval: " << *funcval << '\n';
--- a/gen/dvalue.h	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/dvalue.h	Sun Apr 12 22:22:15 2009 +0200
@@ -38,8 +38,8 @@
 
     Type*& getType() { assert(type); return type; }
 
-    virtual LLValue* getLVal() { assert(0); return 0; }
-    virtual LLValue* getRVal() { assert(0); return 0; }
+    virtual llvm::Value* getLVal() { assert(0); return 0; }
+    virtual llvm::Value* getRVal() { assert(0); return 0; }
 
     virtual bool isLVal() { return false; }
 
@@ -60,11 +60,11 @@
 // immediate d-value
 struct DImValue : DValue
 {
-    LLValue* val;
+    llvm::Value* val;
 
-    DImValue(Type* t, LLValue* v) : DValue(t), val(v) { }
+    DImValue(Type* t, llvm::Value* v) : DValue(t), val(v) { }
 
-    virtual LLValue* getRVal() { assert(val); return val; }
+    virtual llvm::Value* getRVal() { assert(val); return val; }
 
     virtual DImValue* isIm() { return this; }
 };
@@ -72,11 +72,11 @@
 // constant d-value
 struct DConstValue : DValue
 {
-    LLConstant* c;
+    llvm::Constant* c;
 
-    DConstValue(Type* t, LLConstant* con) : DValue(t), c(con) {}
+    DConstValue(Type* t, llvm::Constant* con) : DValue(t), c(con) {}
 
-    virtual LLValue* getRVal();
+    virtual llvm::Value* getRVal();
 
     virtual DConstValue* isConst() { return this; }
 };
@@ -84,7 +84,7 @@
 // null d-value
 struct DNullValue : DConstValue
 {
-    DNullValue(Type* t, LLConstant* con) : DConstValue(t,con) {}
+    DNullValue(Type* t, llvm::Constant* con) : DConstValue(t,con) {}
     virtual DNullValue* isNull() { return this; }
 };
 
@@ -92,14 +92,14 @@
 struct DVarValue : DValue
 {
     VarDeclaration* var;
-    LLValue* val;
+    llvm::Value* val;
 
-    DVarValue(Type* t, VarDeclaration* vd, LLValue* llvmValue);
-    DVarValue(Type* t, LLValue* llvmValue);
+    DVarValue(Type* t, VarDeclaration* vd, llvm::Value* llvmValue);
+    DVarValue(Type* t, llvm::Value* llvmValue);
 
     virtual bool isLVal() { return true; }
-    virtual LLValue* getLVal();
-    virtual LLValue* getRVal();
+    virtual llvm::Value* getLVal();
+    virtual llvm::Value* getRVal();
 
     virtual DVarValue* isVar() { return this; }
 };
@@ -107,19 +107,19 @@
 // field d-value
 struct DFieldValue : DVarValue
 {
-    DFieldValue(Type* t, LLValue* llvmValue) : DVarValue(t, llvmValue) {}
+    DFieldValue(Type* t, llvm::Value* llvmValue) : DVarValue(t, llvmValue) {}
     virtual DFieldValue* isField() { return this; }
 };
 
 // slice d-value
 struct DSliceValue : DValue
 {
-    LLValue* len;
-    LLValue* ptr;
+    llvm::Value* len;
+    llvm::Value* ptr;
 
-    DSliceValue(Type* t, LLValue* l, LLValue* p) : DValue(t), len(l), ptr(p) {}
+    DSliceValue(Type* t, llvm::Value* l, llvm::Value* p) : DValue(t), len(l), ptr(p) {}
 
-    virtual LLValue* getRVal();
+    virtual llvm::Value* getRVal();
 
     virtual DSliceValue* isSlice() { return this; }
 };
@@ -128,12 +128,12 @@
 struct DFuncValue : DValue
 {
     FuncDeclaration* func;
-    LLValue* val;
-    LLValue* vthis;
+    llvm::Value* val;
+    llvm::Value* vthis;
 
-    DFuncValue(FuncDeclaration* fd, LLValue* v, LLValue* vt = 0);
+    DFuncValue(FuncDeclaration* fd, llvm::Value* v, llvm::Value* vt = 0);
 
-    virtual LLValue* getRVal();
+    virtual llvm::Value* getRVal();
 
     virtual DFuncValue* isFunc() { return this; }
 };
--- a/gen/functions.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/functions.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -21,6 +21,7 @@
 #include "gen/classes.h"
 #include "gen/dvalue.h"
 #include "gen/abi.h"
+#include "gen/nested.h"
 
 using namespace llvm::Attribute;
 
@@ -672,13 +673,6 @@
     // debug info - after all allocas, but before any llvm.dbg.declare etc
     if (global.params.symdebug) DtoDwarfFuncStart(fd);
 
-    // need result variable?
-    if (fd->vresult) {
-        Logger::println("vresult value");
-        fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
-        fd->vresult->ir.irLocal->value = DtoAlloca(DtoType(fd->vresult->type), "function_vresult");
-    }
-    
     // this hack makes sure the frame pointer elimination optimization is disabled.
     // this this eliminates a bunch of inline asm related issues.
     if (fd->inlineAsm)
@@ -775,100 +769,20 @@
         fd->nestedVars.insert(fd->vresult);
     }
 
-    // construct nested variables array
-    if (!fd->nestedVars.empty())
+    DtoCreateNestedContext(fd);
+
+#if DMDV2
+    if (fd->vresult && fd->vresult->nestedrefs.dim)
+#else
+    if (fd->vresult && fd->vresult->nestedref)
+#endif
     {
-        Logger::println("has nested frame");
-        // start with adding all enclosing parent frames until a static parent is reached
-        int nparelems = 0;
-        if (!fd->isStatic())
-        {
-            Dsymbol* par = fd->toParent2();
-            while (par)
-            {
-                if (FuncDeclaration* parfd = par->isFuncDeclaration())
-                {
-                    nparelems += parfd->nestedVars.size();
-                    // stop at first static
-                    if (parfd->isStatic())
-                        break;
-                }
-                else if (ClassDeclaration* parcd = par->isClassDeclaration())
-                {
-                    // nothing needed
-                }
-                else
-                {
-                    break;
-                }
-
-                par = par->toParent2();
-            }
-        }
-        int nelems = fd->nestedVars.size() + nparelems;
-        
-        // make array type for nested vars
-        const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
+        DtoNestedInit(fd->vresult);
+    } else if (fd->vresult) {
+        fd->vresult->ir.irLocal = new IrLocal(fd->vresult);
+        fd->vresult->ir.irLocal->value = DtoAlloca(DtoType(fd->vresult->type), fd->vresult->toChars());
+    }
     
-        // alloca it
-        LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".nested_vars");
-        
-        // copy parent frame into beginning
-        if (nparelems)
-        {
-            LLValue* src = irfunction->nestArg;
-            if (!src)
-            {
-                assert(irfunction->thisArg);
-                assert(fd->isMember2());
-                LLValue* thisval = DtoLoad(irfunction->thisArg);
-                ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
-                assert(cd);
-                assert(cd->vthis);
-                src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis"));
-            }
-            DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE));
-        }
-        
-        // store in IrFunction
-        irfunction->nestedVar = nestedVars;
-        
-        // go through all nested vars and assign indices
-        int idx = nparelems;
-        for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
-        {
-            VarDeclaration* vd = *i;
-            if (!vd->ir.irLocal)
-                vd->ir.irLocal = new IrLocal(vd);
-
-            if (vd->isParameter())
-            {
-                Logger::println("nested param: %s", vd->toChars());
-                LLValue* gep = DtoGEPi(nestedVars, 0, idx);
-                LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
-                DtoStore(val, gep);
-            }
-            else
-            {
-                Logger::println("nested var:   %s", vd->toChars());
-            }
-
-            vd->ir.irLocal->nestedIndex = idx++;
-        }
-
-        // fixup nested result variable
-    #if DMDV2
-        if (fd->vresult && fd->vresult->nestedrefs.dim) {
-    #else
-        if (fd->vresult && fd->vresult->nestedref) {
-    #endif
-            Logger::println("nested vresult value: %s", fd->vresult->toChars());
-            LLValue* gep = DtoGEPi(nestedVars, 0, fd->vresult->ir.irLocal->nestedIndex);
-            LLValue* val = DtoBitCast(fd->vresult->ir.irLocal->value, getVoidPtrType());
-            DtoStore(val, gep);
-        }
-    }
-
     // copy _argptr and _arguments to a memory location
     if (f->linkage == LINKd && f->varargs == 1)
     {
--- a/gen/llvmhelpers.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/llvmhelpers.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -1,3 +1,4 @@
+#include "gen/llvmhelpers.h"
 #include "gen/llvm.h"
 #include "llvm/Target/TargetMachineRegistry.h"
 
@@ -9,7 +10,6 @@
 #include "module.h"
 
 #include "gen/tollvm.h"
-#include "gen/llvmhelpers.h"
 #include "gen/irstate.h"
 #include "gen/runtime.h"
 #include "gen/logger.h"
@@ -21,6 +21,7 @@
 #include "gen/typeinf.h"
 #include "gen/todebug.h"
 #include "gen/cl_options.h"
+#include "gen/nested.h"
 #include "ir/irmodule.h"
 
 #include <stack>
@@ -313,75 +314,6 @@
 
 /****************************************************************************************/
 /*////////////////////////////////////////////////////////////////////////////////////////
-// NESTED VARIABLE HELPERS
-////////////////////////////////////////////////////////////////////////////////////////*/
-
-DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
-{
-    Dsymbol* vdparent = vd->toParent2();
-    assert(vdparent);
-    
-    IrFunction* irfunc = gIR->func();
-    
-    // is the nested variable in this scope?
-    if (vdparent == irfunc->decl)
-    {
-        LLValue* val = vd->ir.getIrValue();
-        return new DVarValue(astype, vd, val);
-    }
-    
-    // get it from the nested context
-    LLValue* ctx = 0;
-    if (irfunc->decl->isMember2())
-    {
-        ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
-        LLValue* val = DtoLoad(irfunc->thisArg);
-        ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
-    }
-    else
-        ctx = irfunc->nestArg;
-    assert(ctx);
-    
-    assert(vd->ir.irLocal);
-    LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
-    val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
-    val = DtoLoad(val);
-    assert(vd->ir.irLocal->value);
-    val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
-    return new DVarValue(astype, vd, val);
-}
-
-LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
-{
-    Logger::println("DtoNestedContext for %s", sym->toPrettyChars());
-    LOG_SCOPE;
-
-    IrFunction* irfunc = gIR->func();
-
-    // if this func has its own vars that are accessed by nested funcs
-    // use its own context
-    if (irfunc->nestedVar)
-        return irfunc->nestedVar;
-    // otherwise, it may have gotten a context from the caller
-    else if (irfunc->nestArg)
-        return irfunc->nestArg;
-    // or just have a this argument
-    else if (irfunc->thisArg)
-    {
-        ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
-        if (!cd || !cd->vthis)
-            return getNullPtr(getVoidPtrType());
-        LLValue* val = DtoLoad(irfunc->thisArg);
-        return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
-    }
-    else
-    {
-        return getNullPtr(getVoidPtrType());
-    }
-}
-
-/****************************************************************************************/
-/*////////////////////////////////////////////////////////////////////////////////////////
 // ASSIGNMENT HELPER (store this in that)
 ////////////////////////////////////////////////////////////////////////////////////////*/
 
@@ -946,22 +878,7 @@
                 Logger::println("has nestedref set");
                 assert(vd->ir.irLocal);
                 
-                // alloca as usual if no value already
-                if (!vd->ir.irLocal->value)
-                {
-                    vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars());
-                }
-                
-                // store the address into the nested vars array
-                
-                assert(vd->ir.irLocal->nestedIndex >= 0);
-                LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, vd->ir.irLocal->nestedIndex);
-                
-                assert(isaPointer(vd->ir.irLocal->value));
-                LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
-                
-                DtoStore(val, gep);
-                
+                DtoNestedInit(vd);
             }
             // normal stack variable, allocate storage on the stack if it has not already been done
             else if(!vd->ir.irLocal) {
@@ -1110,12 +1027,7 @@
         else
             assert(!addr || addr == var->ir.irLocal->value);
 
-        // store the address into the nested vars array
-        assert(var->ir.irLocal->nestedIndex >= 0);
-        LLValue* gep = DtoGEPi(gIR->func()->decl->ir.irFunc->nestedVar, 0, var->ir.irLocal->nestedIndex);
-        assert(isaPointer(var->ir.irLocal->value));
-        LLValue* val = DtoBitCast(var->ir.irLocal->value, getVoidPtrType());
-        DtoStore(val, gep);
+        DtoNestedInit(var);
     }
     // normal local variable
     else
--- a/gen/llvmhelpers.h	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/llvmhelpers.h	Sun Apr 12 22:22:15 2009 +0200
@@ -2,7 +2,10 @@
 #define LDC_GEN_LLVMHELPERS_H
 
 #include "gen/llvm.h"
+#include "gen/dvalue.h"
+
 #include "statement.h"
+#include "mtype.h"
 
 // this is used for tracking try-finally, synchronized and volatile scopes
 struct EnclosingHandler
@@ -64,15 +67,6 @@
 /// Leaves a monitor lock.
 void DtoLeaveMonitor(LLValue* v);
 
-// nested variable and context helpers
-
-/// Gets the context value for a call to a nested function or newing a nested
-/// class with arbitrary nesting.
-LLValue* DtoNestedContext(Loc loc, Dsymbol* sym);
-
-/// Gets the DValue of a nested variable with arbitrary nesting.
-DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd);
-
 // basic operations
 void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/nested.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -0,0 +1,411 @@
+#include "gen/nested.h"
+
+#include "gen/dvalue.h"
+#include "gen/irstate.h"
+#include "gen/llvmhelpers.h"
+#include "gen/logger.h"
+#include "gen/tollvm.h"
+
+#include "llvm/Support/CommandLine.h"
+namespace cl = llvm::cl;
+
+/// What the context pointer for a nested function looks like
+enum NestedCtxType {
+    /// Context is void*[] of pointers to variables.
+    /// Variables from higher levels are at the front.
+    NCArray,
+    
+    /// Context is a struct containing variables belonging to the parent function.
+    /// If the parent function itself has a parent function, one of the members is
+    /// a pointer to its context. (linked-list style)
+    // FIXME: implement
+    // TODO: Functions without any variables accessed by nested functions, but
+    //       with a parent whose variables are accessed, can use the parent's
+    //       context.
+    // NOTE: This is what DMD seems to do.
+    NCStruct,
+    
+    /// Context is a list of pointers to structs. Each function with variables
+    /// accessed by nested functions puts them in a struct, and appends a
+    /// pointer to that struct to it's local copy of the list.
+    NCHybrid
+};
+
+static cl::opt<NestedCtxType> nestedCtx("nested-ctx",
+    cl::desc("How to construct a nested function's context:"),
+    cl::ZeroOrMore,
+    cl::values(
+        clEnumValN(NCArray,  "array",  "Array of pointers to variables (including multi-level)"),
+        //clEnumValN(NCStruct, "struct", "Struct of variables (with multi-level via linked list)"),
+        clEnumValN(NCHybrid, "hybrid", "List of pointers to structs of variables, one per level."),
+        clEnumValEnd),
+    cl::init(NCHybrid));
+
+
+/****************************************************************************************/
+/*////////////////////////////////////////////////////////////////////////////////////////
+// NESTED VARIABLE HELPERS
+////////////////////////////////////////////////////////////////////////////////////////*/
+
+static FuncDeclaration* getParentFunc(Dsymbol* sym) {
+    Dsymbol* parent = sym->parent;
+    assert(parent);
+    while (parent && !parent->isFuncDeclaration())
+        parent = parent->parent;
+    
+    return (parent ? parent->isFuncDeclaration() : NULL);
+}
+
+DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd)
+{
+    Logger::println("DtoNestedVariable for %s @ %s", vd->toChars(), loc.toChars());
+    LOG_SCOPE;
+    
+    ////////////////////////////////////
+    // Locate context value
+    
+    Dsymbol* vdparent = vd->toParent2();
+    assert(vdparent);
+    
+    IrFunction* irfunc = gIR->func();
+    
+    // is the nested variable in this scope?
+    if (vdparent == irfunc->decl)
+    {
+        LLValue* val = vd->ir.getIrValue();
+        return new DVarValue(astype, vd, val);
+    }
+    
+    // get the nested context
+    LLValue* ctx = 0;
+    if (irfunc->decl->isMember2())
+    {
+        ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
+        LLValue* val = DtoLoad(irfunc->thisArg);
+        ctx = DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
+    }
+    else
+        ctx = irfunc->nestArg;
+    assert(ctx);
+    
+    assert(vd->ir.irLocal);
+    
+    ////////////////////////////////////
+    // Extract variable from nested context
+    
+    if (nestedCtx == NCArray) {
+        LLValue* val = DtoBitCast(ctx, getPtrToType(getVoidPtrType()));
+        val = DtoGEPi1(val, vd->ir.irLocal->nestedIndex);
+        val = DtoAlignedLoad(val);
+        assert(vd->ir.irLocal->value);
+        val = DtoBitCast(val, vd->ir.irLocal->value->getType(), vd->toChars());
+        return new DVarValue(astype, vd, val);
+    }
+    else if (nestedCtx == NCHybrid) {
+        FuncDeclaration *parentfunc = getParentFunc(vd);
+        assert(parentfunc && "No parent function for nested variable?");
+        
+        LLValue* val = DtoBitCast(ctx, LLPointerType::getUnqual(parentfunc->ir.irFunc->framesType));
+        val = DtoGEPi(val, 0, vd->ir.irLocal->nestedDepth);
+        val = DtoAlignedLoad(val, (std::string(".frame.") + parentfunc->toChars()).c_str());
+        val = DtoGEPi(val, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
+        if (vd->ir.irLocal->byref)
+            val = DtoAlignedLoad(val);
+        return new DVarValue(astype, vd, val);
+    }
+    else {
+        assert(0 && "Not implemented yet");
+    }
+}
+
+void DtoNestedInit(VarDeclaration* vd)
+{
+    Logger::println("DtoNestedInit for %s", vd->toChars());
+    LOG_SCOPE
+    
+    LLValue* nestedVar = gIR->func()->decl->ir.irFunc->nestedVar;
+    
+    if (nestedCtx == NCArray) {
+        // alloca as usual if no value already
+        if (!vd->ir.irLocal->value)
+            vd->ir.irLocal->value = DtoAlloca(DtoType(vd->type), vd->toChars());
+        
+        // store the address into the nested vars array
+        assert(vd->ir.irLocal->nestedIndex >= 0);
+        LLValue* gep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedIndex);
+        
+        assert(isaPointer(vd->ir.irLocal->value));
+        LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
+        
+        DtoAlignedStore(val, gep);
+    }
+    else if (nestedCtx == NCHybrid) {
+        assert(vd->ir.irLocal->value && "Nested variable without storage?");
+        if (!vd->isParameter() && (vd->isRef() || vd->isOut())) {
+            Logger::println("Initializing non-parameter byref value");
+            LLValue* framep = DtoGEPi(nestedVar, 0, vd->ir.irLocal->nestedDepth);
+            
+            FuncDeclaration *parentfunc = getParentFunc(vd);
+            assert(parentfunc && "No parent function for nested variable?");
+            LLValue* frame = DtoAlignedLoad(framep, (std::string(".frame.") + parentfunc->toChars()).c_str());
+            
+            LLValue* slot = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex);
+            DtoAlignedStore(vd->ir.irLocal->value, slot);
+        } else {
+            // Already initialized in DtoCreateNestedContext
+        }
+    }
+    else {
+        assert(0 && "Not implemented yet");
+    }
+}
+
+LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
+{
+    Logger::println("DtoNestedContext for %s", sym->toPrettyChars());
+    LOG_SCOPE;
+
+    IrFunction* irfunc = gIR->func();
+
+    // if this func has its own vars that are accessed by nested funcs
+    // use its own context
+    if (irfunc->nestedVar)
+        return irfunc->nestedVar;
+    // otherwise, it may have gotten a context from the caller
+    else if (irfunc->nestArg)
+        return irfunc->nestArg;
+    // or just have a this argument
+    else if (irfunc->thisArg)
+    {
+        ClassDeclaration* cd = irfunc->decl->isMember2()->isClassDeclaration();
+        if (!cd || !cd->vthis)
+            return getNullPtr(getVoidPtrType());
+        LLValue* val = DtoLoad(irfunc->thisArg);
+        return DtoLoad(DtoGEPi(val, 0,cd->vthis->ir.irField->index, ".vthis"));
+    }
+    else
+    {
+        return getNullPtr(getVoidPtrType());
+    }
+}
+
+void DtoCreateNestedContext(FuncDeclaration* fd) {
+    Logger::println("DtoCreateNestedContext for %s", fd->toChars());
+    LOG_SCOPE
+    
+    if (nestedCtx == NCArray) {
+        // construct nested variables array
+        if (!fd->nestedVars.empty())
+        {
+            Logger::println("has nested frame");
+            // start with adding all enclosing parent frames until a static parent is reached
+            int nparelems = 0;
+            if (!fd->isStatic())
+            {
+                Dsymbol* par = fd->toParent2();
+                while (par)
+                {
+                    if (FuncDeclaration* parfd = par->isFuncDeclaration())
+                    {
+                        nparelems += parfd->nestedVars.size();
+                        // stop at first static
+                        if (parfd->isStatic())
+                            break;
+                    }
+                    else if (ClassDeclaration* parcd = par->isClassDeclaration())
+                    {
+                        // nothing needed
+                    }
+                    else
+                    {
+                        break;
+                    }
+
+                    par = par->toParent2();
+                }
+            }
+            int nelems = fd->nestedVars.size() + nparelems;
+            
+            // make array type for nested vars
+            const LLType* nestedVarsTy = LLArrayType::get(getVoidPtrType(), nelems);
+        
+            // alloca it
+            LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".nested_vars");
+            
+            IrFunction* irfunction = fd->ir.irFunc;
+            
+            // copy parent frame into beginning
+            if (nparelems)
+            {
+                LLValue* src = irfunction->nestArg;
+                if (!src)
+                {
+                    assert(irfunction->thisArg);
+                    assert(fd->isMember2());
+                    LLValue* thisval = DtoLoad(irfunction->thisArg);
+                    ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
+                    assert(cd);
+                    assert(cd->vthis);
+                    src = DtoLoad(DtoGEPi(thisval, 0,cd->vthis->ir.irField->index, ".vthis"));
+                }
+                DtoMemCpy(nestedVars, src, DtoConstSize_t(nparelems*PTRSIZE),
+                    getABITypeAlign(getVoidPtrType()));
+            }
+            
+            // store in IrFunction
+            irfunction->nestedVar = nestedVars;
+            
+            // go through all nested vars and assign indices
+            int idx = nparelems;
+            for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
+            {
+                VarDeclaration* vd = *i;
+                if (!vd->ir.irLocal)
+                    vd->ir.irLocal = new IrLocal(vd);
+
+                if (vd->isParameter())
+                {
+                    Logger::println("nested param: %s", vd->toChars());
+                    LLValue* gep = DtoGEPi(nestedVars, 0, idx);
+                    LLValue* val = DtoBitCast(vd->ir.irLocal->value, getVoidPtrType());
+                    DtoAlignedStore(val, gep);
+                }
+                else
+                {
+                    Logger::println("nested var:   %s", vd->toChars());
+                }
+
+                vd->ir.irLocal->nestedIndex = idx++;
+            }
+        }
+    }
+    else if (nestedCtx == NCHybrid) {
+        // construct nested variables array
+        if (!fd->nestedVars.empty())
+        {
+            Logger::println("has nested frame");
+            // start with adding all enclosing parent frames until a static parent is reached
+            typedef std::vector<const LLType*> TypeVec;
+            TypeVec frametypes;
+            if (!fd->isStatic()) {
+                Dsymbol* par = fd->toParent2();
+                while (par) {
+                    if (FuncDeclaration* parfd = par->isFuncDeclaration()) {
+                        // skip functions without nested parameters
+                        if (!parfd->nestedVars.empty()) {
+                            // Copy the types of parent function frames.
+                            const LLStructType* parft = parfd->ir.irFunc->framesType;
+                            frametypes.insert(frametypes.begin(), parft->element_begin(), parft->element_end());
+                            break;  // That's all the info needed.
+                        }
+                    } else if (ClassDeclaration* parcd = par->isClassDeclaration()) {
+                        // skip
+                    } else {
+                        break;
+                    }
+                    par = par->toParent2();
+                }
+            }
+            unsigned depth = frametypes.size();
+            
+            // Construct a struct for the direct nested variables of this function, and update their indices to match.
+            // TODO: optimize ordering for minimal space usage?
+            TypeVec types;
+            for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
+            {
+                VarDeclaration* vd = *i;
+                if (!vd->ir.irLocal)
+                    vd->ir.irLocal = new IrLocal(vd);
+                
+                vd->ir.irLocal->nestedDepth = depth;
+                vd->ir.irLocal->nestedIndex = types.size();
+                if (vd->isParameter()) {
+                    // Parameters already have storage associated with them (to handle byref etc.),
+                    // so handle specially for now by storing a pointer instead of a value.
+                    assert(vd->ir.irLocal->value);
+                    // FIXME: don't do this for normal parameters?
+                    types.push_back(vd->ir.irLocal->value->getType());
+                } else if (vd->isRef() || vd->isOut()) {
+                    // Foreach variables can also be by reference, for instance.
+                    types.push_back(DtoType(vd->type->pointerTo()));
+                } else {
+                    types.push_back(DtoType(vd->type));
+                }
+                if (Logger::enabled()) {
+                    Logger::println("Nested var: %s", vd->toChars());
+                    Logger::cout() << "of type: " << *types.back() << '\n';
+                }
+            }
+            // Append current frame type to frame type list
+            const LLType* frameType = LLStructType::get(types);
+            frametypes.push_back(LLPointerType::getUnqual(frameType));
+            
+            // make struct type for nested frame list
+            const LLStructType* nestedVarsTy = LLStructType::get(frametypes);
+            
+            // Store type in IrFunction
+            IrFunction* irfunction = fd->ir.irFunc;
+            irfunction->framesType = nestedVarsTy;
+            
+            // alloca it
+            // FIXME: For D2, this should be a gc_malloc (or similar) call, not alloca
+            LLValue* nestedVars = DtoAlloca(nestedVarsTy, ".frame_list");
+            
+            // copy parent frames into beginning
+            if (depth != 0)
+            {
+                LLValue* src = irfunction->nestArg;
+                if (!src)
+                {
+                    assert(irfunction->thisArg);
+                    assert(fd->isMember2());
+                    LLValue* thisval = DtoLoad(irfunction->thisArg);
+                    ClassDeclaration* cd = fd->isMember2()->isClassDeclaration();
+                    assert(cd);
+                    assert(cd->vthis);
+                    Logger::println("Indexing to 'this'");
+                    src = DtoLoad(DtoGEPi(thisval, 0, cd->vthis->ir.irField->index, ".vthis"));
+                }
+                src = DtoBitCast(src, getVoidPtrType());
+                LLValue* dst = DtoBitCast(nestedVars, getVoidPtrType());
+                DtoMemCpy(dst, src, DtoConstSize_t(depth * PTRSIZE),
+                    getABITypeAlign(getVoidPtrType()));
+            }
+            
+            // Create frame for current function and append to frames list
+            LLValue* frame = DtoAlloca(frameType, ".frame");
+            // store current frame in list
+            DtoAlignedStore(frame, DtoGEPi(nestedVars, 0, depth));
+            
+            // store context in IrFunction
+            irfunction->nestedVar = nestedVars;
+            
+            // go through all nested vars and assign addresses where possible.
+            for (std::set<VarDeclaration*>::iterator i=fd->nestedVars.begin(); i!=fd->nestedVars.end(); ++i)
+            {
+                VarDeclaration* vd = *i;
+                
+                LLValue* gep = DtoGEPi(frame, 0, vd->ir.irLocal->nestedIndex, vd->toChars());
+                if (vd->isParameter()) {
+                    Logger::println("nested param: %s", vd->toChars());
+                    DtoAlignedStore(vd->ir.irLocal->value, gep);
+                    vd->ir.irLocal->byref = true;
+                } else if (vd->isRef() || vd->isOut()) {
+                    // This slot is initialized in DtoNestedInit, to handle things like byref foreach variables
+                    // which move around in memory.
+                    vd->ir.irLocal->byref = true;
+                } else {
+                    Logger::println("nested var:   %s", vd->toChars());
+                    if (vd->ir.irLocal->value)
+                        Logger::cout() << "Pre-existing value: " << *vd->ir.irLocal->value << '\n';
+                    assert(!vd->ir.irLocal->value);
+                    vd->ir.irLocal->value = gep;
+                    vd->ir.irLocal->byref = false;
+                }
+            }
+        }
+    }
+    else {
+        assert(0 && "Not implemented yet");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/nested.h	Sun Apr 12 22:22:15 2009 +0200
@@ -0,0 +1,25 @@
+#ifndef LDC_GEN_NESTED_H
+#define LDC_GEN_NESTED_H
+
+#include "declaration.h"
+#include "mtype.h"
+#include "gen/dvalue.h"
+
+///////////////////////////////////////////////////////////
+// Nested variable and context helpers
+///////////////////////////////////////////////////////////
+
+/// Creates the context value for a nested function.
+void DtoCreateNestedContext(FuncDeclaration* fd);
+
+/// Allocate space for variable accessed from nested function.
+void DtoNestedInit(VarDeclaration* vd);
+
+/// Gets the context value for a call to a nested function or newing a nested
+/// class with arbitrary nesting.
+llvm::Value* DtoNestedContext(Loc loc, Dsymbol* sym);
+
+/// Gets the DValue of a nested variable with arbitrary nesting.
+DValue* DtoNestedVariable(Loc loc, Type* astype, VarDeclaration* vd);
+
+#endif
--- a/gen/tocall.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/tocall.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -9,6 +9,7 @@
 #include "gen/dvalue.h"
 #include "gen/functions.h"
 #include "gen/abi.h"
+#include "gen/nested.h"
 
 #include "gen/logger.h"
 
--- a/gen/toir.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/toir.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -36,6 +36,7 @@
 #include "gen/aa.h"
 #include "gen/functions.h"
 #include "gen/todebug.h"
+#include "gen/nested.h"
 
 #include "llvm/Support/ManagedStatic.h"
 
--- a/gen/tollvm.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/tollvm.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -426,7 +426,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes)
+void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes, unsigned align)
 {
     dst = DtoBitCast(dst,getVoidPtrType());
     src = DtoBitCast(src,getVoidPtrType());
@@ -435,7 +435,7 @@
     llvm::Function* fn = llvm::Intrinsic::getDeclaration(gIR->module,
         llvm::Intrinsic::memcpy, &intTy, 1);
 
-    gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(0), "");
+    gIR->ir->CreateCall4(fn, dst, src, nbytes, DtoConstUint(align), "");
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -573,11 +573,20 @@
 {
 //     if (Logger::enabled())
 //         Logger::cout() << "loading " << *src <<  '\n';
-    LLValue* ld = gIR->ir->CreateLoad(src, name ? name : "tmp");
+    llvm::LoadInst* ld = gIR->ir->CreateLoad(src, name ? name : "tmp");
     //ld->setVolatile(gIR->func()->inVolatile);
     return ld;
 }
 
+// Like DtoLoad, but the pointer is guaranteed to be aligned appropriately for the type.
+LLValue* DtoAlignedLoad(LLValue* src, const char* name)
+{
+    llvm::LoadInst* ld = gIR->ir->CreateLoad(src, name ? name : "tmp");
+    ld->setAlignment(getABITypeAlign(ld->getType()));
+    return ld;
+}
+
+
 void DtoStore(LLValue* src, LLValue* dst)
 {
 //     if (Logger::enabled())
@@ -586,6 +595,13 @@
     //st->setVolatile(gIR->func()->inVolatile);
 }
 
+// Like DtoStore, but the pointer is guaranteed to be aligned appropriately for the type.
+void DtoAlignedStore(LLValue* src, LLValue* dst)
+{
+    llvm::StoreInst* st = gIR->ir->CreateStore(src,dst);
+    st->setAlignment(getABITypeAlign(src->getType()));
+}
+
 //////////////////////////////////////////////////////////////////////////////////////////
 
 LLValue* DtoBitCast(LLValue* v, const LLType* t, const char* name)
--- a/gen/tollvm.h	Sun Apr 12 19:56:03 2009 +0200
+++ b/gen/tollvm.h	Sun Apr 12 22:22:15 2009 +0200
@@ -63,7 +63,9 @@
 
 // llvm wrappers
 LLValue* DtoLoad(LLValue* src, const char* name=0);
+LLValue* DtoAlignedLoad(LLValue* src, const char* name=0);
 void DtoStore(LLValue* src, LLValue* dst);
+void DtoAlignedStore(LLValue* src, LLValue* dst);
 LLValue* DtoBitCast(LLValue* v, const LLType* t, const char* name=0);
 LLConstant* DtoBitCast(LLConstant* v, const LLType* t);
 
@@ -117,8 +119,9 @@
  * @param dst Destination memory.
  * @param src Source memory.
  * @param nbytes Number of bytes to copy.
+ * @param align The minimum alignment of the source and destination memory.
  */
-void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes);
+void DtoMemCpy(LLValue* dst, LLValue* src, LLValue* nbytes, unsigned align = 0);
 
 /**
  * Generates a call to C memcmp.
--- a/ir/irfunction.cpp	Sun Apr 12 19:56:03 2009 +0200
+++ b/ir/irfunction.cpp	Sun Apr 12 22:22:15 2009 +0200
@@ -111,6 +111,7 @@
     nestArg = NULL;
 
     nestedVar = NULL;
+    framesType = NULL;
     
     _arguments = NULL;
     _argptr = NULL;
--- a/ir/irfunction.h	Sun Apr 12 19:56:03 2009 +0200
+++ b/ir/irfunction.h	Sun Apr 12 22:22:15 2009 +0200
@@ -45,6 +45,7 @@
     llvm::Value* nestArg; // nested function 'this' arg
     
     llvm::Value* nestedVar; // nested var alloca
+    const llvm::StructType* framesType; // type of nested context (not for -nested-ctx=array)
     
     llvm::Value* _arguments;
     llvm::Value* _argptr;
--- a/ir/irvar.h	Sun Apr 12 19:56:03 2009 +0200
+++ b/ir/irvar.h	Sun Apr 12 22:22:15 2009 +0200
@@ -26,6 +26,8 @@
 {
     IrLocal(VarDeclaration* v);
 
+    bool byref;         // Not used for -nested-ctx=array
+    int nestedDepth;    // ditto
     int nestedIndex;
 };