diff gen/toobj.cpp @ 100:5071469303d4 trunk

[svn r104] TONS OF FIXES. Split up declaration, constant initializer gen and definition for globals, structs, classes and functions. Improved ClassInfo support (not complete), not in vtable yet. Fixed a bunch of forward reference problems. Much more. Major commit! :)
author lindquist
date Fri, 16 Nov 2007 08:21:47 +0100
parents 6789050b5ad1
children 027b8d8b71ec
line wrap: on
line diff
--- a/gen/toobj.cpp	Thu Nov 15 00:24:44 2007 +0100
+++ b/gen/toobj.cpp	Fri Nov 16 08:21:47 2007 +0100
@@ -36,6 +36,8 @@
 #include "gen/tollvm.h"
 #include "gen/arrays.h"
 #include "gen/structs.h"
+#include "gen/classes.h"
+#include "gen/functions.h"
 #include "gen/todebug.h"
 #include "gen/runtime.h"
 
@@ -90,12 +92,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();
-        }
+    // process deferred const initializers
+    for (size_t i=0; i<ir.constInitQueue.size(); ++i) {
+        DtoConstInitDsymbol(ir.constInitQueue[i]);
+    }
+
+    // process deferred definitions
+    for (size_t i=0; i<ir.defineQueue.size(); ++i) {
+        DtoDefineDsymbol(ir.defineQueue[i]);
     }
 
     // generate ModuleInfo
@@ -322,183 +326,7 @@
 
 void StructDeclaration::toObjFile()
 {
-    TypeStruct* ts = (TypeStruct*)DtoDType(type);
-    if (llvmType != 0)
-        return;
-
-    static int sdi = 0;
-    Logger::print("StructDeclaration::toObjFile(%d): %s\n", sdi++, toChars());
-    LOG_SCOPE;
-
-    gIR->structs.push_back(IRStruct(ts));
-
-    for (int k=0; k < members->dim; k++) {
-        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
-        dsym->toObjFile();
-    }
-
-    Logger::println("doing struct fields");
-
-    const llvm::StructType* structtype = 0;
-    std::vector<llvm::Constant*> fieldinits;
-
-    if (gIR->topstruct().offsets.empty())
-    {
-        std::vector<const llvm::Type*> fieldtypes;
-        Logger::println("has no fields");
-        fieldtypes.push_back(llvm::Type::Int8Ty);
-        fieldinits.push_back(llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
-        structtype = llvm::StructType::get(fieldtypes);
-    }
-    else
-    {
-        Logger::println("has fields");
-        std::vector<const llvm::Type*> fieldtypes;
-        unsigned prevsize = (unsigned)-1;
-        unsigned lastoffset = (unsigned)-1;
-        const llvm::Type* fieldtype = NULL;
-        llvm::Constant* fieldinit = NULL;
-        size_t fieldpad = 0;
-        int idx = 0;
-        for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
-            // first iteration
-            if (lastoffset == (unsigned)-1) {
-                lastoffset = i->first;
-                assert(lastoffset == 0);
-                fieldtype = DtoType(i->second.var->type);
-                fieldinit = i->second.init;
-                prevsize = gTargetData->getTypeSize(fieldtype);
-                i->second.var->llvmFieldIndex = idx;
-            }
-            // colliding offset?
-            else if (lastoffset == i->first) {
-                const llvm::Type* t = DtoType(i->second.var->type);
-                size_t s = gTargetData->getTypeSize(t);
-                if (s > prevsize) {
-                    fieldpad += s - prevsize;
-                    prevsize = s;
-                }
-                llvmHasUnions = true;
-                i->second.var->llvmFieldIndex = idx;
-            }
-            // intersecting offset?
-            else if (i->first < (lastoffset + prevsize)) {
-                const llvm::Type* t = DtoType(i->second.var->type);
-                size_t s = gTargetData->getTypeSize(t);
-                assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
-                llvmHasUnions = true;
-                i->second.var->llvmFieldIndex = idx;
-                i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s;
-            }
-            // fresh offset
-            else {
-                // commit the field
-                fieldtypes.push_back(fieldtype);
-                fieldinits.push_back(fieldinit);
-                if (fieldpad) {
-                    // match up with below
-                    std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
-                    llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
-                    fieldtypes.push_back(c->getType());
-                    fieldinits.push_back(c);
-                    idx++;
-                }
-
-                idx++;
-
-                // start new
-                lastoffset = i->first;
-                fieldtype = DtoType(i->second.var->type);
-                fieldinit = i->second.init;
-                prevsize = gTargetData->getTypeSize(fieldtype);
-                i->second.var->llvmFieldIndex = idx;
-                fieldpad = 0;
-            }
-        }
-        fieldtypes.push_back(fieldtype);
-        fieldinits.push_back(fieldinit);
-        if (fieldpad) {
-            // match up with above
-            std::vector<llvm::Constant*> vals(fieldpad, llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
-            llvm::Constant* c = llvm::ConstantArray::get(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad), vals);
-            fieldtypes.push_back(c->getType());
-            fieldinits.push_back(c);
-        }
-
-        Logger::println("creating struct type");
-        structtype = llvm::StructType::get(fieldtypes);
-    }
-
-    // refine abstract types for stuff like: struct S{S* next;}
-    if (gIR->topstruct().recty != 0)
-    {
-        llvm::PATypeHolder& pa = gIR->topstruct().recty;
-        llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
-        structtype = isaStruct(pa.get());
-    }
-
-    ts->llvmType = structtype;
-    llvmType = structtype;
-
-    if (parent->isModule()) {
-        gIR->module->addTypeName(mangle(),ts->llvmType);
-    }
-
-    llvmUnion = new DUnion; // uses gIR->topstruct()
-
-    // generate static data
-    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
-    llvm::Constant* _init = 0;
-
-    // always generate the constant initalizer
-    if (!zeroInit) {
-        Logger::println("Not zero initialized");
-        //assert(tk == gIR->gIR->topstruct()().size());
-        #ifndef LLVMD_NO_LOGGER
-        Logger::cout() << "struct type: " << *structtype << '\n';
-        for (size_t k=0; k<fieldinits.size(); ++k) {
-            Logger::cout() << "Type:" << '\n';
-            Logger::cout() << *fieldinits[k]->getType() << '\n';
-            Logger::cout() << "Value:" << '\n';
-            Logger::cout() << *fieldinits[k] << '\n';
-        }
-        Logger::cout() << "Initializer printed" << '\n';
-        #endif
-        llvmInitZ = llvm::ConstantStruct::get(structtype,fieldinits);
-    }
-    else {
-        Logger::println("Zero initialized");
-        llvmInitZ = llvm::ConstantAggregateZero::get(structtype);
-    }
-
-    // only provide the constant initializer for the defining module
-    if (getModule() == gIR->dmodule)
-    {
-        _init = llvmInitZ;
-    }
-
-    std::string initname("_D");
-    initname.append(mangle());
-    initname.append("6__initZ");
-    llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, _init, initname, gIR->module);
-    ts->llvmInit = initvar;
-
-    // generate member function definitions
-    gIR->topstruct().queueFuncs = false;
-    IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
-    size_t n = mfs.size();
-    for (size_t i=0; i<n; ++i) {
-        //mfs[i]->toObjFile();
-        gIR->funcQueue.push_back(mfs[i]);
-    }
-
-    llvmDModule = gIR->dmodule;
-
-    gIR->structs.pop_back();
-
-    // generate typeinfo
-    if (getModule() == gIR->dmodule && llvmInternal != LLVMnotypeinfo)
-        type->getTypeInfo(NULL);
+    DtoDeclareStruct(this);
 }
 
 /* ================================================================== */
@@ -534,186 +362,9 @@
 
 /* ================================================================== */
 
-static void LLVM_AddBaseClassData(BaseClasses* bcs)
-{
-    // add base class data members first
-    for (int j=0; j<bcs->dim; j++)
-    {
-        BaseClass* bc = (BaseClass*)(bcs->data[j]);
-        assert(bc);
-        Logger::println("Adding base class members of %s", bc->base->toChars());
-        LOG_SCOPE;
-
-        LLVM_AddBaseClassData(&bc->base->baseclasses);
-        for (int k=0; k < bc->base->members->dim; k++) {
-            Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
-            if (dsym->isVarDeclaration())
-            {
-                dsym->toObjFile();
-            }
-        }
-    }
-}
-
 void ClassDeclaration::toObjFile()
 {
-    TypeClass* ts = (TypeClass*)DtoDType(type);
-    if (ts->llvmType != 0 || llvmInProgress)
-        return;
-
-    llvmInProgress = true;
-
-    static int fdi = 0;
-    Logger::print("ClassDeclaration::toObjFile(%d): %s\n", fdi++, toChars());
-    LOG_SCOPE;
-
-    gIR->structs.push_back(IRStruct(ts));
-    gIR->classes.push_back(this);
-
-    // add vtable
-    llvm::PATypeHolder pa = llvm::OpaqueType::get();
-    const llvm::Type* vtabty = llvm::PointerType::get(pa);
-
-    std::vector<const llvm::Type*> fieldtypes;
-    fieldtypes.push_back(vtabty);
-
-    std::vector<llvm::Constant*> fieldinits;
-    fieldinits.push_back(0);
-
-    // base classes first
-    LLVM_AddBaseClassData(&baseclasses);
-
-    // then add own members
-    for (int k=0; k < members->dim; k++) {
-        Dsymbol* dsym = (Dsymbol*)(members->data[k]);
-        dsym->toObjFile();
-    }
-
-    // fill out fieldtypes/inits
-    for (IRStruct::OffsetMap::iterator i=gIR->topstruct().offsets.begin(); i!=gIR->topstruct().offsets.end(); ++i) {
-        fieldtypes.push_back(DtoType(i->second.var->type));
-        fieldinits.push_back(i->second.init);
-    }
-
-    const llvm::StructType* structtype = llvm::StructType::get(fieldtypes);
-    // refine abstract types for stuff like: class C {C next;}
-    if (gIR->topstruct().recty != 0)
-    {
-        llvm::PATypeHolder& pa = gIR->topstruct().recty;
-        llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(structtype);
-        structtype = isaStruct(pa.get());
-    }
-
-    ts->llvmType = structtype;
-    llvmType = structtype;
-
-    bool needs_definition = false;
-    if (parent->isModule()) {
-        gIR->module->addTypeName(mangle(),ts->llvmType);
-        needs_definition = (getModule() == gIR->dmodule);
-    }
-    else {
-        assert(0 && "class parent is not a module");
-    }
-
-    // generate vtable
-    llvm::GlobalVariable* svtblVar = 0;
-    std::vector<llvm::Constant*> sinits;
-    std::vector<const llvm::Type*> sinits_ty;
-    sinits.reserve(vtbl.dim);
-    sinits_ty.reserve(vtbl.dim);
-
-    for (int k=0; k < vtbl.dim; k++)
-    {
-        Dsymbol* dsym = (Dsymbol*)vtbl.data[k];
-        assert(dsym);
-        //Logger::cout() << "vtblsym: " << dsym->toChars() << '\n';
-
-        if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
-            fd->toObjFile();
-            assert(fd->llvmValue);
-            llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
-            sinits.push_back(c);
-            sinits_ty.push_back(c->getType());
-        }
-        else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
-            const llvm::Type* cty = llvm::PointerType::get(llvm::Type::Int8Ty);
-            llvm::Constant* c = llvm::Constant::getNullValue(cty);
-            sinits.push_back(c);
-            sinits_ty.push_back(cty);
-        }
-        else
-        assert(0);
-    }
-
-    const llvm::StructType* svtbl_ty = 0;
-    if (!sinits.empty())
-    {
-        llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
-
-        std::string varname("_D");
-        varname.append(mangle());
-        varname.append("6__vtblZ");
-
-        std::string styname(mangle());
-        styname.append("__vtblTy");
-
-        svtbl_ty = llvm::StructType::get(sinits_ty);
-        gIR->module->addTypeName(styname, svtbl_ty);
-        svtblVar = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module);
-
-        llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(svtbl_ty, sinits));
-        if (needs_definition)
-            svtblVar->setInitializer(llvmConstVtbl);
-        llvmVtbl = svtblVar;
-    }
-
-    ////////////////////////////////////////////////////////////////////////////////
-
-    // refine for final vtable type
-    llvm::cast<llvm::OpaqueType>(pa.get())->refineAbstractTypeTo(svtbl_ty);
-    svtbl_ty = isaStruct(pa.get());
-    structtype = isaStruct(gIR->topstruct().recty.get());
-    ts->llvmType = structtype;
-    llvmType = structtype;
-
-    // generate initializer
-    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
-    llvm::Constant* _init = 0;
-
-    // first field is always the vtable
-    assert(svtblVar != 0);
-    fieldinits[0] = svtblVar;
-
-    llvmInitZ = _init = llvm::ConstantStruct::get(structtype,fieldinits);
-    assert(_init);
-
-    std::string initname("_D");
-    initname.append(mangle());
-    initname.append("6__initZ");
-    //Logger::cout() << *_init << '\n';
-    llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType, true, _linkage, NULL, initname, gIR->module);
-    ts->llvmInit = initvar;
-
-    if (needs_definition) {
-        initvar->setInitializer(_init);
-        // generate member functions
-        gIR->topstruct().queueFuncs = false;
-        IRStruct::FuncDeclVector& mfs = gIR->topstruct().funcs;
-        size_t n = mfs.size();
-        for (size_t i=0; i<n; ++i) {
-            //mfs[i]->toObjFile();
-            gIR->funcQueue.push_back(mfs[i]);
-        }
-    }
-
-    gIR->classes.pop_back();
-    gIR->structs.pop_back();
-
-    llvmInProgress = false;
-
-    //     if (ClassDeclaration::classinfo != this)
-    //         DtoClassInfo(this);
+    DtoDeclareClass(this);
 }
 
 /******************************************
@@ -732,7 +383,6 @@
 {
     Logger::print("VarDeclaration::toObjFile(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
-    llvm::Module* M = gIR->module;
 
     if (aliassym)
     {
@@ -747,81 +397,40 @@
         if (llvmTouched) return;
         else llvmTouched = true;
 
-        bool _isconst = false;
-        if (isConst() && (init && !init->isExpInitializer()))
-            _isconst = true;
+        llvmIRGlobal = new IRGlobal(this);
+
+        Logger::println("parent: %s (%s)", parent->toChars(), parent->kind());
+
+        bool _isconst = isConst();
+        if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer())
+            _isconst = false;
 
         llvm::GlobalValue::LinkageTypes _linkage;
         bool istempl = false;
+        bool static_local = false;
         if ((storage_class & STCcomdat) || (parent && DtoIsTemplateInstance(parent))) {
             _linkage = llvm::GlobalValue::WeakLinkage;
             istempl = true;
         }
-        else if (parent && parent->isFuncDeclaration())
+        else if (parent && parent->isFuncDeclaration()) {
             _linkage = llvm::GlobalValue::InternalLinkage;
+            static_local = true;
+        }
         else
             _linkage = DtoLinkage(protection, storage_class);
 
-        Type* t = DtoDType(type);
-
-        const llvm::Type* _type = DtoType(t);
-        assert(_type);
-
-        llvm::Constant* _init = 0;
-        bool _signed = !type->isunsigned();
+        const llvm::Type* _type = llvmIRGlobal->type.get();
 
         Logger::println("Creating global variable");
         std::string _name(mangle());
 
-        bool emitRTstaticInit = false;
-
-        if (!(storage_class & STCextern) && (getModule() == gIR->dmodule || istempl))
-        {
-            if (parent && parent->isFuncDeclaration() && init && init->isExpInitializer()) {
-                _init = DtoConstInitializer(t, NULL);
-                emitRTstaticInit = true;
-            }
-            else {
-                _init = DtoConstInitializer(t, init);
-            }
-
-            //Logger::cout() << "initializer: " << *_init << '\n';
-            if (_type != _init->getType()) {
-                Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n";
-                // zero initalizer
-                if (_init->isNullValue())
-                    _init = llvm::Constant::getNullValue(_type);
-                // pointer to global constant (struct.init)
-                else if (llvm::isa<llvm::GlobalVariable>(_init))
-                {
-                    assert(_init->getType()->getContainedType(0) == _type);
-                    llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init);
-                    assert(t->ty == Tstruct);
-                    TypeStruct* ts = (TypeStruct*)t;
-                    assert(ts->sym->llvmInitZ);
-                    _init = ts->sym->llvmInitZ;
-                }
-                // array single value init
-                else if (isaArray(_type))
-                {
-                    _init = DtoConstStaticArray(_type, _init);
-                }
-                else {
-                    Logger::cout() << "Unexpected initializer type: " << *_type << '\n';
-                    //assert(0);
-                }
-            }
-        }
-
-        if (_init && _init->getType() != _type)
-            _type = _init->getType();
-        llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,_init,_name,M);
+        llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_type,_isconst,_linkage,NULL,_name,gIR->module);
         llvmValue = gvar;
 
-        if (emitRTstaticInit)
-            DtoLazyStaticInit(istempl, gvar, init, t);
-
-        llvmDModule = gIR->dmodule;
+        if (static_local)
+            DtoConstInitGlobal(this);
+        else
+            gIR->constInitQueue.push_back(this);
 
         //if (storage_class & STCprivate)
         //    gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility);
@@ -832,47 +441,10 @@
     {
         Logger::println("Aggregate var declaration: '%s' offset=%d", toChars(), offset);
 
-        Type* t = DtoDType(type);
-        const llvm::Type* _type = DtoType(t);
-
-        llvm::Constant*_init = DtoConstInitializer(t, init);
-        assert(_init);
-        Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n';
-        if (_type != _init->getType())
-        {
-            if (t->ty == Tsarray)
-            {
-                const llvm::ArrayType* arrty = isaArray(_type);
-                uint64_t n = arrty->getNumElements();
-                std::vector<llvm::Constant*> vals(n,_init);
-                _init = llvm::ConstantArray::get(arrty, vals);
-            }
-            else if (t->ty == Tarray)
-            {
-                assert(isaStruct(_type));
-                _init = llvm::ConstantAggregateZero::get(_type);
-            }
-            else if (t->ty == Tstruct)
-            {
-                const llvm::StructType* structty = isaStruct(_type);
-                TypeStruct* ts = (TypeStruct*)t;
-                assert(ts);
-                assert(ts->sym);
-                assert(ts->sym->llvmInitZ);
-                _init = ts->sym->llvmInitZ;
-            }
-            else if (t->ty == Tclass)
-            {
-                _init = llvm::Constant::getNullValue(_type);
-            }
-            else {
-                Logger::println("failed for type %s", type->toChars());
-                assert(0);
-            }
-        }
+        const llvm::Type* _type = DtoType(type);
 
         // add the field in the IRStruct
-        gIR->topstruct().offsets.insert(std::make_pair(offset, IRStruct::Offset(this,_init)));
+        gIR->topstruct()->offsets.insert(std::make_pair(offset, IRStruct::Offset(this, _type)));
     }
 
     Logger::println("VarDeclaration::toObjFile is done");
@@ -901,254 +473,5 @@
 
 void FuncDeclaration::toObjFile()
 {
-    if (llvmDModule) {
-        assert(llvmValue != 0);
-        return;
-    }
-
-    if (llvmRunTimeHack) {
-        Logger::println("runtime hack func chars: %s", toChars());
-        if (!llvmValue)
-            llvmValue = LLVM_D_GetRuntimeFunction(gIR->module, toChars());
-        return;
-    }
-
-    if (isUnitTestDeclaration()) {
-        Logger::attention("ignoring unittest declaration: %s", toChars());
-        return;
-    }
-
-    Type* t = DtoDType(type);
-    TypeFunction* f = (TypeFunction*)t;
-
-    bool declareOnly = false;
-    if (parent)
-    {
-    if (TemplateInstance* tinst = parent->isTemplateInstance()) {
-        TemplateDeclaration* tempdecl = tinst->tempdecl;
-        if (tempdecl->llvmInternal == LLVMva_start)
-        {
-            Logger::println("magic va_start found");
-            llvmInternal = LLVMva_start;
-            declareOnly = true;
-        }
-        else if (tempdecl->llvmInternal == LLVMva_arg)
-        {
-            Logger::println("magic va_arg found");
-            llvmInternal = LLVMva_arg;
-            return;
-        }
-    }
-    }
-
-    llvm::Function* func = DtoDeclareFunction(this);
-
-    if (declareOnly)
-        return;
-
-    if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) {
-        if (!llvmQueued) {
-            Logger::println("queueing %s", toChars());
-            gIR->topstruct().funcs.push_back(this);
-            llvmQueued = true;
-        }
-        return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete
-    }
-
-    // debug info
-    if (global.params.symdebug) {
-        Module* mo = getModule();
-        if (!mo->llvmCompileUnit) {
-            mo->llvmCompileUnit = DtoDwarfCompileUnit(mo,false);
-        }
-        llvmDwarfSubProgram = DtoDwarfSubProgram(this, mo->llvmCompileUnit);
-    }
-
-    assert(f->llvmType);
-    const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
-
-    // template instances should have weak linkage
-    if (parent && DtoIsTemplateInstance(parent)) {
-        func->setLinkage(llvm::GlobalValue::WeakLinkage);
-    }
-
-    // only members of the current module maybe be defined
-    if (getModule() == gIR->dmodule || DtoIsTemplateInstance(parent))
-    {
-        llvmDModule = gIR->dmodule;
-
-        // handle static constructor / destructor
-        if (isStaticCtorDeclaration() || isStaticDtorDeclaration()) {
-            const llvm::ArrayType* sctor_type = llvm::ArrayType::get(llvm::PointerType::get(functype),1);
-            //Logger::cout() << "static ctor type: " << *sctor_type << '\n';
-
-            llvm::Constant* sctor_func = llvm::cast<llvm::Constant>(llvmValue);
-            //Logger::cout() << "static ctor func: " << *sctor_func << '\n';
-
-            llvm::Constant* sctor_init = llvm::ConstantArray::get(sctor_type,&sctor_func,1);
-
-            //Logger::cout() << "static ctor init: " << *sctor_init << '\n';
-
-            // output the llvm.global_ctors array
-            const char* varname = isStaticCtorDeclaration() ? "_d_module_ctor_array" : "_d_module_dtor_array";
-            llvm::GlobalVariable* sctor_arr = new llvm::GlobalVariable(sctor_type, false, llvm::GlobalValue::AppendingLinkage, sctor_init, varname, gIR->module);
-        }
-
-        // function definition
-        if (fbody != 0)
-        {
-            gIR->functions.push_back(IRFunction(this));
-            gIR->func().func = func;
-
-            // first make absolutely sure the type is up to date
-            f->llvmType = llvmValue->getType()->getContainedType(0);
-
-            //Logger::cout() << "func type: " << *f->llvmType << '\n';
-
-            // this handling
-            if (f->llvmUsesThis) {
-                Logger::println("uses this");
-                if (f->llvmRetInPtr)
-                    llvmThisVar = ++func->arg_begin();
-                else
-                    llvmThisVar = func->arg_begin();
-                assert(llvmThisVar != 0);
-            }
-
-            if (isMain())
-                gIR->emitMain = true;
-
-            llvm::BasicBlock* beginbb = new llvm::BasicBlock("entry",func);
-            llvm::BasicBlock* endbb = new llvm::BasicBlock("endentry",func);
-
-            //assert(gIR->scopes.empty());
-            gIR->scopes.push_back(IRScope(beginbb, endbb));
-
-                // create alloca point
-                f->llvmAllocaPoint = new llvm::BitCastInst(llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false),llvm::Type::Int32Ty,"alloca point",gIR->scopebb());
-                gIR->func().allocapoint = f->llvmAllocaPoint;
-
-                // give arguments storage
-                size_t n = Argument::dim(f->parameters);
-                for (int i=0; i < n; ++i) {
-                    Argument* arg = Argument::getNth(f->parameters, i);
-                    if (arg && arg->vardecl) {
-                        VarDeclaration* vd = arg->vardecl;
-                        if (!vd->llvmNeedsStorage || vd->nestedref || vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))
-                            continue;
-                        llvm::Value* a = vd->llvmValue;
-                        assert(a);
-                        std::string s(a->getName());
-                        Logger::println("giving argument '%s' storage", s.c_str());
-                        s.append("_storage");
-                        llvm::Value* v = new llvm::AllocaInst(a->getType(),s,f->llvmAllocaPoint);
-                        gIR->ir->CreateStore(a,v);
-                        vd->llvmValue = v;
-                    }
-                    else {
-                        Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0);
-                    }
-                }
-
-                // debug info
-                if (global.params.symdebug) DtoDwarfFuncStart(this);
-
-                llvm::Value* parentNested = NULL;
-                if (FuncDeclaration* fd = toParent()->isFuncDeclaration()) {
-                    parentNested = fd->llvmNested;
-                }
-
-                // construct nested variables struct
-                if (!llvmNestedVars.empty() || parentNested) {
-                    std::vector<const llvm::Type*> nestTypes;
-                    int j = 0;
-                    if (parentNested) {
-                        nestTypes.push_back(parentNested->getType());
-                        j++;
-                    }
-                    for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) {
-                        VarDeclaration* vd = *i;
-                        vd->llvmNestedIndex = j++;
-                        if (vd->isParameter()) {
-                            assert(vd->llvmValue);
-                            nestTypes.push_back(vd->llvmValue->getType());
-                        }
-                        else {
-                            nestTypes.push_back(DtoType(vd->type));
-                        }
-                    }
-                    const llvm::StructType* nestSType = llvm::StructType::get(nestTypes);
-                    Logger::cout() << "nested var struct has type:" << '\n' << *nestSType;
-                    llvmNested = new llvm::AllocaInst(nestSType,"nestedvars",f->llvmAllocaPoint);
-                    if (parentNested) {
-                        assert(llvmThisVar);
-                        llvm::Value* ptr = gIR->ir->CreateBitCast(llvmThisVar, parentNested->getType(), "tmp");
-                        gIR->ir->CreateStore(ptr, DtoGEPi(llvmNested, 0,0, "tmp"));
-                    }
-                    for (std::set<VarDeclaration*>::iterator i=llvmNestedVars.begin(); i!=llvmNestedVars.end(); ++i) {
-                        VarDeclaration* vd = *i;
-                        if (vd->isParameter()) {
-                            gIR->ir->CreateStore(vd->llvmValue, DtoGEPi(llvmNested, 0, vd->llvmNestedIndex, "tmp"));
-                            vd->llvmValue = llvmNested;
-                        }
-                    }
-                }
-
-                // copy _argptr to a memory location
-                if (f->linkage == LINKd && f->varargs == 1)
-                {
-                    llvm::Value* argptrmem = new llvm::AllocaInst(llvmArgPtr->getType(), "_argptrmem", gIR->topallocapoint());
-                    new llvm::StoreInst(llvmArgPtr, argptrmem, gIR->scopebb());
-                    llvmArgPtr = argptrmem;
-                }
-
-                // output function body
-                fbody->toIR(gIR);
-
-                // llvm requires all basic blocks to end with a TerminatorInst but DMD does not put a return statement
-                // in automatically, so we do it here.
-                if (!isMain()) {
-                    if (!gIR->scopereturned()) {
-                        // pass the previous block into this block
-                        if (global.params.symdebug) DtoDwarfFuncEnd(this);
-                        if (func->getReturnType() == llvm::Type::VoidTy) {
-                            new llvm::ReturnInst(gIR->scopebb());
-                        }
-                        else {
-                            new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), gIR->scopebb());
-                        }
-                    }
-                }
-
-                // erase alloca point
-                f->llvmAllocaPoint->eraseFromParent();
-                f->llvmAllocaPoint = 0;
-                gIR->func().allocapoint = 0;
-
-            gIR->scopes.pop_back();
-
-            // get rid of the endentry block, it's never used
-            assert(!func->getBasicBlockList().empty());
-            func->getBasicBlockList().pop_back();
-
-            // if the last block is empty now, it must be unreachable or it's a bug somewhere else
-            // would be nice to figure out how to assert that this is correct
-            llvm::BasicBlock* lastbb = &func->getBasicBlockList().back();
-            if (lastbb->empty()) {
-                if (lastbb->getNumUses() == 0)
-                    lastbb->eraseFromParent();
-                else {
-                    new llvm::UnreachableInst(lastbb);
-                    /*if (func->getReturnType() == llvm::Type::VoidTy) {
-                        new llvm::ReturnInst(lastbb);
-                    }
-                    else {
-                        new llvm::ReturnInst(llvm::UndefValue::get(func->getReturnType()), lastbb);
-                    }*/
-                }
-            }
-
-            gIR->functions.pop_back();
-        }
-    }
+    DtoDeclareFunction(this);
 }