diff gen/tollvm.cpp @ 86:fd32135dca3e trunk

[svn r90] Major updates to the gen directory. Redesigned the 'elem' struct. Much more... !!! Lots of bugfixes. Added support for special foreach on strings. Added std.array, std.utf, std.ctype and std.uni to phobos. Changed all the .c files in the gen dir to .cpp (it *is* C++ after all)
author lindquist
date Sat, 03 Nov 2007 14:44:58 +0100
parents gen/tollvm.c@f869c636a113
children 058d3925950e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/tollvm.cpp	Sat Nov 03 14:44:58 2007 +0100
@@ -0,0 +1,1565 @@
+#include <iostream>
+
+#include "gen/llvm.h"
+
+#include "mtype.h"
+#include "dsymbol.h"
+#include "aggregate.h"
+#include "declaration.h"
+#include "init.h"
+
+#include "gen/tollvm.h"
+#include "gen/irstate.h"
+#include "gen/logger.h"
+#include "gen/runtime.h"
+#include "gen/arrays.h"
+#include "gen/dvalue.h"
+
+bool DtoIsPassedByRef(Type* type)
+{
+    TY t = DtoDType(type)->ty;
+    return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray);
+}
+
+Type* DtoDType(Type* t)
+{
+    if (t->ty == Ttypedef) {
+        Type* bt = t->toBasetype();
+        assert(bt);
+        return DtoDType(bt);
+    }
+    return t;
+}
+
+const llvm::Type* DtoType(Type* t)
+{
+    assert(t);
+    switch (t->ty)
+    {
+    // integers
+    case Tint8:
+    case Tuns8:
+    case Tchar:
+        return (const llvm::Type*)llvm::Type::Int8Ty;
+    case Tint16:
+    case Tuns16:
+    case Twchar:
+        return (const llvm::Type*)llvm::Type::Int16Ty;
+    case Tint32:
+    case Tuns32:
+    case Tdchar:
+        return (const llvm::Type*)llvm::Type::Int32Ty;
+    case Tint64:
+    case Tuns64:
+        return (const llvm::Type*)llvm::Type::Int64Ty;
+
+    case Tbool:
+        return (const llvm::Type*)llvm::ConstantInt::getTrue()->getType();
+
+    // floats
+    case Tfloat32:
+    case Timaginary32:
+        return llvm::Type::FloatTy;
+    case Tfloat64:
+    case Timaginary64:
+    case Tfloat80:
+    case Timaginary80:
+        return llvm::Type::DoubleTy;
+
+    // complex
+    case Tcomplex32:
+    case Tcomplex64:
+    case Tcomplex80:
+        assert(0 && "complex number types not yet implemented");
+
+    // pointers
+    case Tpointer: {
+        assert(t->next);
+        if (t->next->ty == Tvoid)
+            return (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+        else
+            return (const llvm::Type*)llvm::PointerType::get(DtoType(t->next));
+    }
+
+    // arrays
+    case Tarray:
+        return DtoArrayType(t);
+    case Tsarray:
+        return DtoStaticArrayType(t);
+
+    // void
+    case Tvoid:
+        return llvm::Type::VoidTy;
+
+    // aggregates
+    case Tstruct:    {
+        if (t->llvmType == 0)
+        {
+            // recursive or cyclic declaration
+            if (!gIR->structs.empty())
+            {
+                IRStruct* found = 0;
+                for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i)
+                {
+                    if (t == i->type)
+                    {
+                        return i->recty.get();
+                    }
+                }
+            }
+
+            // forward declaration
+            TypeStruct* ts = (TypeStruct*)t;
+            assert(ts->sym);
+            ts->sym->toObjFile();
+        }
+        return t->llvmType;
+    }
+
+    case Tclass:    {
+        if (t->llvmType == 0)
+        {
+            // recursive or cyclic declaration
+            if (!gIR->structs.empty())
+            {
+                IRStruct* found = 0;
+                for (IRState::StructVector::iterator i=gIR->structs.begin(); i!=gIR->structs.end(); ++i)
+                {
+                    if (t == i->type)
+                    {
+                        return llvm::PointerType::get(i->recty.get());
+                    }
+                }
+            }
+
+            // forward declaration
+            TypeClass* tc = (TypeClass*)t;
+            assert(tc->sym);
+            tc->sym->toObjFile();
+        }
+        return llvm::PointerType::get(t->llvmType);
+    }
+
+    // functions
+    case Tfunction:
+    {
+        if (t->llvmType == 0) {
+            return DtoFunctionType(t,NULL);
+        }
+        else {
+            return t->llvmType;
+        }
+    }
+
+    // delegates
+    case Tdelegate:
+    {
+        if (t->llvmType == 0) {
+            return DtoDelegateType(t);
+        }
+        else {
+            return t->llvmType;
+        }
+    }
+
+    // typedefs
+    // enum
+    case Ttypedef:
+    case Tenum:
+    {
+        Type* bt = t->toBasetype();
+        assert(bt);
+        return DtoType(bt);
+    }
+
+    default:
+        printf("trying to convert unknown type with value %d\n", t->ty);
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::FunctionType* DtoFunctionType(Type* type, const llvm::Type* thistype, bool ismain)
+{
+    TypeFunction* f = (TypeFunction*)type;
+    assert(f != 0);
+
+    bool typesafeVararg = false;
+    if (f->linkage == LINKd && f->varargs == 1) {
+        typesafeVararg = true;
+    }
+
+    // return value type
+    const llvm::Type* rettype;
+    const llvm::Type* actualRettype;
+    Type* rt = f->next;
+    bool retinptr = false;
+    bool usesthis = false;
+
+    if (ismain) {
+        rettype = llvm::Type::Int32Ty;
+        actualRettype = rettype;
+    }
+    else {
+        assert(rt);
+        if (DtoIsPassedByRef(rt)) {
+            rettype = llvm::PointerType::get(DtoType(rt));
+            actualRettype = llvm::Type::VoidTy;
+            f->llvmRetInPtr = retinptr = true;
+        }
+        else {
+            rettype = DtoType(rt);
+            actualRettype = rettype;
+        }
+    }
+
+    // parameter types
+    std::vector<const llvm::Type*> paramvec;
+
+    if (retinptr) {
+        Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
+        paramvec.push_back(rettype);
+    }
+
+    if (thistype) {
+        paramvec.push_back(thistype);
+        usesthis = true;
+    }
+
+    if (typesafeVararg) {
+        ClassDeclaration* ti = Type::typeinfo;
+        if (!ti->llvmInitZ)
+            ti->toObjFile();
+        assert(ti->llvmInitZ);
+        std::vector<const llvm::Type*> types;
+        types.push_back(DtoSize_t());
+        types.push_back(llvm::PointerType::get(llvm::PointerType::get(ti->llvmInitZ->getType())));
+        const llvm::Type* t1 = llvm::StructType::get(types);
+        paramvec.push_back(llvm::PointerType::get(t1));
+        paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
+    }
+
+    size_t n = Argument::dim(f->parameters);
+
+    for (int i=0; i < n; ++i) {
+        Argument* arg = Argument::getNth(f->parameters, i);
+        // ensure scalar
+        Type* argT = DtoDType(arg->type);
+        assert(argT);
+
+        if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
+            //assert(arg->vardecl);
+            //arg->vardecl->refparam = true;
+        }
+        else
+            arg->llvmCopy = true;
+
+        const llvm::Type* at = DtoType(argT);
+        if (llvm::isa<llvm::StructType>(at)) {
+            Logger::println("struct param");
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else if (llvm::isa<llvm::ArrayType>(at)) {
+            Logger::println("sarray param");
+            assert(argT->ty == Tsarray);
+            //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
+            paramvec.push_back(llvm::PointerType::get(at));
+        }
+        else if (llvm::isa<llvm::OpaqueType>(at)) {
+            Logger::println("opaque param");
+            if (argT->ty == Tstruct || argT->ty == Tclass)
+                paramvec.push_back(llvm::PointerType::get(at));
+            else
+            assert(0);
+        }
+        /*if (llvm::isa<llvm::StructType>(at) || argT->ty == Tstruct || argT->ty == Tsarray) {
+            paramvec.push_back(llvm::PointerType::get(at));
+        }*/
+        else {
+            if (!arg->llvmCopy) {
+                Logger::println("ref param");
+                at = llvm::PointerType::get(at);
+            }
+            else {
+                Logger::println("in param");
+            }
+            paramvec.push_back(at);
+        }
+    }
+
+    // construct function type
+    bool isvararg = !typesafeVararg && f->varargs;
+    llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
+
+    f->llvmRetInPtr = retinptr;
+    f->llvmUsesThis = usesthis;
+    return functype;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static const llvm::FunctionType* DtoVaFunctionType(FuncDeclaration* fdecl)
+{
+    TypeFunction* f = (TypeFunction*)fdecl->type;
+    assert(f != 0);
+
+    const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    std::vector<const llvm::Type*> args;
+
+    if (fdecl->llvmInternal == LLVMva_start) {
+        args.push_back(i8pty);
+    }
+    else if (fdecl->llvmInternal == LLVMva_intrinsic) {
+        size_t n = Argument::dim(f->parameters);
+        for (size_t i=0; i<n; ++i) {
+            args.push_back(i8pty);
+        }
+    }
+    else
+    assert(0);
+
+    const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
+    f->llvmType = fty;
+    return fty;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
+{
+    if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
+        return DtoVaFunctionType(fdecl);
+    }
+
+    // type has already been resolved
+    if (fdecl->type->llvmType != 0) {
+        return llvm::cast<llvm::FunctionType>(fdecl->type->llvmType);
+    }
+
+    const llvm::Type* thisty = NULL;
+    if (fdecl->needThis()) {
+        if (AggregateDeclaration* ad = fdecl->isMember()) {
+            Logger::print("isMember = this is: %s\n", ad->type->toChars());
+            thisty = DtoType(ad->type);
+            Logger::cout() << "this llvm type: " << *thisty << '\n';
+            if (llvm::isa<llvm::StructType>(thisty) || thisty == gIR->topstruct().recty.get())
+                thisty = llvm::PointerType::get(thisty);
+        }
+        else
+        assert(0);
+    }
+    else if (fdecl->isNested()) {
+        thisty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    }
+
+    const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, fdecl->isMain());
+    fdecl->type->llvmType = functype;
+    return functype;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::StructType* DtoDelegateType(Type* t)
+{
+    const llvm::Type* i8ptr = llvm::PointerType::get(llvm::Type::Int8Ty);
+    const llvm::Type* func = DtoFunctionType(t->next, i8ptr);
+    const llvm::Type* funcptr = llvm::PointerType::get(func);
+
+    std::vector<const llvm::Type*> types;
+    types.push_back(i8ptr);
+    types.push_back(funcptr);
+    return llvm::StructType::get(types);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::Type* DtoStructType(Type* t)
+{
+    assert(0);
+    std::vector<const llvm::Type*> types;
+    return llvm::StructType::get(types);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false)
+{
+    assert(bits == 32 || bits == 64);
+    const llvm::Type* int8ty =    (const llvm::Type*)llvm::Type::Int8Ty;
+    const llvm::Type* int32ty =   (const llvm::Type*)llvm::Type::Int32Ty;
+    const llvm::Type* int64ty =   (const llvm::Type*)llvm::Type::Int64Ty;
+    const llvm::Type* int8ptrty = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+    const llvm::Type* voidty =    (const llvm::Type*)llvm::Type::VoidTy;
+
+    assert(gIR);
+    assert(gIR->module);
+
+    // parameter types
+    std::vector<const llvm::Type*> pvec;
+    pvec.push_back(int8ptrty);
+    pvec.push_back(set?int8ty:int8ptrty);
+    pvec.push_back(bits==32?int32ty:int64ty);
+    pvec.push_back(int32ty);
+    llvm::FunctionType* functype = llvm::FunctionType::get(voidty, pvec, false);
+    return new llvm::Function(functype, llvm::GlobalValue::ExternalLinkage, name, gIR->module);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memset.i32
+llvm::Function* LLVM_DeclareMemSet32()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memset.i32", 32, true);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Function* LLVM_DeclareMemSet64()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memset.i64", 64, true);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memcpy.i32
+llvm::Function* LLVM_DeclareMemCpy32()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i32", 32);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+// llvm.memcpy.i64
+llvm::Function* LLVM_DeclareMemCpy64()
+{
+    static llvm::Function* _func = 0;
+    if (_func == 0) {
+        _func = LLVM_DeclareMemIntrinsic("llvm.memcpy.i64", 64);
+    }
+    return _func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoStructZeroInit(llvm::Value* v)
+{
+    assert(gIR);
+    uint64_t n = gTargetData->getTypeSize(v->getType()->getContainedType(0));
+    //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
+    llvm::Type* sarrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* sarr = new llvm::BitCastInst(v,sarrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = sarr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+
+    return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoStructCopy(llvm::Value* dst, llvm::Value* src)
+{
+    Logger::cout() << "dst = " << *dst << " src = " << *src << '\n';
+    assert(dst->getType() == src->getType());
+    assert(gIR);
+
+    uint64_t n = gTargetData->getTypeSize(dst->getType()->getContainedType(0));
+    //llvm::Type* sarrty = llvm::PointerType::get(llvm::ArrayType::get(llvm::Type::Int8Ty, n));
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+llvm::Constant* DtoConstStructInitializer(StructInitializer* si)
+{
+    llvm::StructType* structtype = llvm::cast<llvm::StructType>(si->ad->llvmType);
+    size_t n = structtype->getNumElements();
+
+    assert(si->value.dim == si->vars.dim);
+
+    std::vector<llvm::Constant*> inits;
+    inits.resize(n, NULL);
+    for (int i = 0; i < si->value.dim; ++i)
+    {
+        Initializer* ini = (Initializer*)si->value.data[i];
+        assert(ini);
+
+        VarDeclaration* vd = (VarDeclaration*)si->vars.data[i];
+        Type* vdtype = DtoDType(vd->type);
+        assert(vd);
+        Logger::println("vars[%d] = %s", i, vd->toChars());
+
+        llvm::Constant* v = 0;
+
+        assert(vd->llvmFieldIndex >= 0);
+        unsigned idx = vd->llvmFieldIndex;
+
+        if (ExpInitializer* ex = ini->isExpInitializer())
+        {
+            v = ex->exp->toConstElem(gIR);
+        }
+        else if (StructInitializer* si = ini->isStructInitializer())
+        {
+            v = DtoConstStructInitializer(si);
+        }
+        else if (ArrayInitializer* ai = ini->isArrayInitializer())
+        {
+            v = DtoConstArrayInitializer(ai);
+        }
+        else if (ini->isVoidInitializer())
+        {
+            v = llvm::UndefValue::get(structtype->getElementType(idx));
+        }
+        else
+        assert(v);
+
+        inits[idx] = v;
+        Logger::cout() << "init[" << idx << "] = " << *v << '\n';
+    }
+
+    // fill out nulls
+    assert(si->ad->llvmInitZ);
+    if (si->ad->llvmInitZ->isNullValue())
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (inits[i] == 0)
+            {
+                inits[i] = llvm::Constant::getNullValue(structtype->getElementType(i));
+            }
+        }
+    }
+    else
+    {
+        for (int i = 0; i < n; ++i)
+        {
+            if (inits[i] == 0)
+            {
+                inits[i] = si->ad->llvmInitZ->getOperand(i);
+            }
+        }
+    }
+
+    return llvm::ConstantStruct::get(structtype, inits);
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoNullDelegate(llvm::Value* v)
+{
+    assert(gIR);
+    d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+    llvm::Type* i8p_ty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* arr = new llvm::BitCastInst(v,i8p_ty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemSet32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = arr;
+    llargs[1] = llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false);
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    llvm::Value* ret = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+
+    return ret;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoDelegateCopy(llvm::Value* dst, llvm::Value* src)
+{
+    assert(dst->getType() == src->getType());
+    assert(gIR);
+
+    d_uns64 n = (global.params.is64bit) ? 16 : 8;
+
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+    llvm::Value* srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+
+    llvm::Function* fn = LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    return new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoCompareDelegate(TOK op, llvm::Value* lhs, llvm::Value* rhs)
+{
+    llvm::ICmpInst::Predicate pred = (op == TOKequal) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
+    llvm::Value* l = gIR->ir->CreateLoad(DtoGEPi(lhs,0,0,"tmp"),"tmp");
+    llvm::Value* r = gIR->ir->CreateLoad(DtoGEPi(rhs,0,0,"tmp"),"tmp");
+    llvm::Value* b1 = gIR->ir->CreateICmp(pred,l,r,"tmp");
+    l = gIR->ir->CreateLoad(DtoGEPi(lhs,0,1,"tmp"),"tmp");
+    r = gIR->ir->CreateLoad(DtoGEPi(rhs,0,1,"tmp"),"tmp");
+    llvm::Value* b2 = gIR->ir->CreateICmp(pred,l,r,"tmp");
+    llvm::Value* b = gIR->ir->CreateAnd(b1,b2,"tmp");
+    if (op == TOKnotequal)
+        return gIR->ir->CreateNot(b,"tmp");
+    return b;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::GlobalValue::LinkageTypes DtoLinkage(PROT prot, uint stc)
+{
+    switch(prot)
+    {
+    case PROTprivate:
+        return llvm::GlobalValue::InternalLinkage;
+
+    case PROTpublic:
+    case PROTpackage:
+    case PROTprotected:
+    case PROTexport:
+        return llvm::GlobalValue::ExternalLinkage;
+
+    case PROTundefined:
+    case PROTnone:
+        assert(0 && "Unsupported linkage type");
+    }
+    return llvm::GlobalValue::ExternalLinkage;
+
+/*      ExternalLinkage = 0, LinkOnceLinkage, WeakLinkage, AppendingLinkage,
+  InternalLinkage, DLLImportLinkage, DLLExportLinkage, ExternalWeakLinkage,
+  GhostLinkage */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+unsigned DtoCallingConv(LINK l)
+{
+    if (l == LINKc)
+        return llvm::CallingConv::C;
+    else if (l == LINKd || l == LINKdefault)
+        return llvm::CallingConv::Fast;
+    else if (l == LINKwindows)
+        return llvm::CallingConv::X86_StdCall;
+    else
+        assert(0 && "Unsupported calling convention");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoPointedType(llvm::Value* ptr, llvm::Value* val)
+{
+    const llvm::Type* ptrTy = ptr->getType()->getContainedType(0);
+    const llvm::Type* valTy = val->getType();
+    // ptr points to val's type
+    if (ptrTy == valTy)
+    {
+        return val;
+    }
+    // ptr is integer pointer
+    else if (ptrTy->isInteger())
+    {
+        // val is integer
+        assert(valTy->isInteger());
+        const llvm::IntegerType* pt = llvm::cast<const llvm::IntegerType>(ptrTy);
+        const llvm::IntegerType* vt = llvm::cast<const llvm::IntegerType>(valTy);
+        if (pt->getBitWidth() < vt->getBitWidth()) {
+            return new llvm::TruncInst(val, pt, "tmp", gIR->scopebb());
+        }
+        else
+        assert(0);
+    }
+    // something else unsupported
+    else
+    {
+        Logger::cout() << *ptrTy << '|' << *valTy << '\n';
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoBoolean(llvm::Value* val)
+{
+    const llvm::Type* t = val->getType();
+    if (t->isInteger())
+    {
+        if (t == llvm::Type::Int1Ty)
+            return val;
+        else {
+            llvm::Value* zero = llvm::ConstantInt::get(t, 0, false);
+            return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, val, zero, "tmp", gIR->scopebb());
+        }
+    }
+    else if (llvm::isa<llvm::PointerType>(t)) {
+        const llvm::Type* st = DtoSize_t();
+        llvm::Value* ptrasint = new llvm::PtrToIntInst(val,st,"tmp",gIR->scopebb());
+        llvm::Value* zero = llvm::ConstantInt::get(st, 0, false);
+        return new llvm::ICmpInst(llvm::ICmpInst::ICMP_NE, ptrasint, zero, "tmp", gIR->scopebb());
+    }
+    else
+    {
+        Logger::cout() << *t << '\n';
+    }
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::Type* DtoSize_t()
+{
+    if (global.params.is64bit)
+    return llvm::Type::Int64Ty;
+    else
+    return llvm::Type::Int32Ty;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoMain()
+{
+    // emit main function llvm style
+    // int main(int argc, char**argv, char**env);
+
+    assert(gIR != 0);
+    IRState& ir = *gIR;
+
+    assert(ir.emitMain && ir.mainFunc);
+
+    // parameter types
+    std::vector<const llvm::Type*> pvec;
+    pvec.push_back((const llvm::Type*)llvm::Type::Int32Ty);
+    const llvm::Type* chPtrType = (const llvm::Type*)llvm::PointerType::get(llvm::Type::Int8Ty);
+    pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
+    pvec.push_back((const llvm::Type*)llvm::PointerType::get(chPtrType));
+    const llvm::Type* rettype = (const llvm::Type*)llvm::Type::Int32Ty;
+
+    llvm::FunctionType* functype = llvm::FunctionType::get(rettype, pvec, false);
+    llvm::Function* func = new llvm::Function(functype,llvm::GlobalValue::ExternalLinkage,"main",ir.module);
+
+    llvm::BasicBlock* bb = new llvm::BasicBlock("entry",func);
+
+    // call static ctors
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_ctors");
+    new llvm::CallInst(fn,"",bb);
+
+    // call user main function
+    llvm::CallInst* call = new llvm::CallInst(ir.mainFunc,"ret",bb);
+    call->setCallingConv(ir.mainFunc->getCallingConv());
+
+    // call static dtors
+    fn = LLVM_D_GetRuntimeFunction(ir.module,"_d_run_module_dtors");
+    new llvm::CallInst(fn,"",bb);
+
+    // return
+    new llvm::ReturnInst(call,bb);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance)
+{
+    Array* arr = &tc->sym->dtors;
+    for (size_t i=0; i<arr->dim; i++)
+    {
+        FuncDeclaration* fd = (FuncDeclaration*)arr->data[i];
+        assert(fd->llvmValue);
+        new llvm::CallInst(fd->llvmValue, instance, "", gIR->scopebb());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoInitClass(TypeClass* tc, llvm::Value* dst)
+{
+    assert(gIR);
+
+    assert(tc->llvmType);
+    uint64_t size_t_size = gTargetData->getTypeSize(DtoSize_t());
+    uint64_t n = gTargetData->getTypeSize(tc->llvmType) - size_t_size;
+
+    // set vtable field
+    llvm::Value* vtblvar = DtoGEPi(dst,0,0,"tmp",gIR->scopebb());
+    assert(tc->sym->llvmVtbl);
+    new llvm::StoreInst(tc->sym->llvmVtbl, vtblvar, gIR->scopebb());
+
+    // copy the static initializer
+    if (n > 0) {
+        assert(tc->llvmInit);
+        assert(dst->getType() == tc->llvmInit->getType());
+
+        llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+        llvm::Value* dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+        dstarr = DtoGEPi(dstarr,size_t_size,"tmp",gIR->scopebb());
+
+        llvm::Value* srcarr = new llvm::BitCastInst(tc->llvmInit,arrty,"tmp",gIR->scopebb());
+        srcarr = DtoGEPi(srcarr,size_t_size,"tmp",gIR->scopebb());
+
+        llvm::Function* fn = LLVM_DeclareMemCpy32();
+        std::vector<llvm::Value*> llargs;
+        llargs.resize(4);
+        llargs[0] = dstarr;
+        llargs[1] = srcarr;
+        llargs[2] = llvm::ConstantInt::get(llvm::Type::Int32Ty, n, false);
+        llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+        new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* DtoConstInitializer(Type* type, Initializer* init)
+{
+    llvm::Constant* _init = 0; // may return zero
+    if (!init)
+    {
+        Logger::println("const default initializer for %s", type->toChars());
+        _init = type->defaultInit()->toConstElem(gIR);
+    }
+    else if (ExpInitializer* ex = init->isExpInitializer())
+    {
+        Logger::println("const expression initializer");
+        _init = ex->exp->toConstElem(gIR);
+    }
+    else if (StructInitializer* si = init->isStructInitializer())
+    {
+        Logger::println("const struct initializer");
+        _init = DtoConstStructInitializer(si);
+    }
+    else if (ArrayInitializer* ai = init->isArrayInitializer())
+    {
+        Logger::println("const array initializer");
+        _init = DtoConstArrayInitializer(ai);
+    }
+    else if (init->isVoidInitializer())
+    {
+        Logger::println("const void initializer");
+        const llvm::Type* ty = DtoType(type);
+        _init = llvm::Constant::getNullValue(ty);
+    }
+    else {
+        Logger::println("unsupported const initializer: %s", init->toChars());
+    }
+    return _init;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoInitializer(Initializer* init)
+{
+    if (ExpInitializer* ex = init->isExpInitializer())
+    {
+        Logger::println("expression initializer");
+        return ex->exp->toElem(gIR);
+    }
+    else if (init->isVoidInitializer())
+    {
+        // do nothing
+    }
+    else {
+        Logger::println("unsupported initializer: %s", init->toChars());
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoGEP(llvm::Value* ptr, llvm::Value* i0, llvm::Value* i1, const std::string& var, llvm::BasicBlock* bb)
+{
+    std::vector<llvm::Value*> v(2);
+    v[0] = i0;
+    v[1] = i1;
+    Logger::cout() << "DtoGEP: " << *ptr << '\n';
+    return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+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 << "':";
+    for (size_t i=0; i<n; ++i)
+    {
+        ostr << ' ' << i;
+        dst[i] = llvm::ConstantInt::get(llvm::Type::Int32Ty, src[i], false);
+    }
+    ostr << '\n';
+    return new llvm::GetElementPtrInst(ptr, dst.begin(), dst.end(), var, bb?bb:gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i, const std::string& var, llvm::BasicBlock* bb)
+{
+    return new llvm::GetElementPtrInst(ptr, llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false), var, bb?bb:gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoGEPi(llvm::Value* ptr, unsigned i0, unsigned i1, const std::string& var, llvm::BasicBlock* bb)
+{
+    std::vector<llvm::Value*> v(2);
+    v[0] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i0, false);
+    v[1] = llvm::ConstantInt::get(llvm::Type::Int32Ty, i1, false);
+    return new llvm::GetElementPtrInst(ptr, v.begin(), v.end(), var, bb?bb:gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+static llvm::Function* DtoDeclareVaFunction(FuncDeclaration* fdecl)
+{
+    TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
+    const llvm::FunctionType* fty = DtoVaFunctionType(fdecl);
+    llvm::Constant* fn = 0;
+
+    if (fdecl->llvmInternal == LLVMva_start) {
+        fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
+        assert(fn);
+    }
+    else if (fdecl->llvmInternal == LLVMva_intrinsic) {
+        fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
+        assert(fn);
+    }
+    else
+    assert(0);
+
+    llvm::Function* func = llvm::cast_or_null<llvm::Function>(fn);
+    assert(func);
+    assert(func->isIntrinsic());
+    fdecl->llvmValue = func;
+    return func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Function* DtoDeclareFunction(FuncDeclaration* fdecl)
+{
+    if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
+        return DtoDeclareVaFunction(fdecl);
+    }
+
+    // mangled name
+    char* mangled_name;
+    if (fdecl->llvmInternal == LLVMintrinsic)
+        mangled_name = fdecl->llvmInternal1;
+    else
+        mangled_name = fdecl->mangle();
+
+    // unit test special handling
+    if (fdecl->isUnitTestDeclaration())
+    {
+        assert(0 && "no unittests yet");
+        /*const llvm::FunctionType* fnty = llvm::FunctionType::get(llvm::Type::VoidTy, std::vector<const llvm::Type*>(), false);
+        // make the function
+        llvm::Function* func = gIR->module->getFunction(mangled_name);
+        if (func == 0)
+            func = new llvm::Function(fnty,llvm::GlobalValue::InternalLinkage,mangled_name,gIR->module);
+        func->setCallingConv(llvm::CallingConv::Fast);
+        fdecl->llvmValue = func;
+        return func;
+        */
+    }
+
+    // regular function
+    TypeFunction* f = (TypeFunction*)DtoDType(fdecl->type);
+    assert(f != 0);
+
+    if (fdecl->llvmValue != 0) {
+        if (!llvm::isa<llvm::Function>(fdecl->llvmValue))
+        {
+            Logger::cout() << *fdecl->llvmValue << '\n';
+            assert(0);
+        }
+        return llvm::cast<llvm::Function>(fdecl->llvmValue);
+    }
+
+    Logger::print("FuncDeclaration::toObjFile(%s): %s\n", fdecl->needThis()?"this":"static",fdecl->toChars());
+    LOG_SCOPE;
+
+    if (fdecl->llvmInternal == LLVMintrinsic && fdecl->fbody) {
+        error("intrinsics cannot have function bodies");
+        fatal();
+    }
+
+    // construct function
+    const llvm::FunctionType* functype = (f->llvmType == 0) ? DtoFunctionType(fdecl) : llvm::cast<llvm::FunctionType>(f->llvmType);
+
+    // make the function
+    llvm::Function* func = gIR->module->getFunction(mangled_name);
+    if (func == 0) {
+        func = new llvm::Function(functype,DtoLinkage(fdecl->protection, fdecl->storage_class),mangled_name,gIR->module);
+    }
+
+    if (fdecl->llvmInternal != LLVMintrinsic)
+        func->setCallingConv(DtoCallingConv(f->linkage));
+
+    fdecl->llvmValue = func;
+    f->llvmType = functype;
+    assert(llvm::isa<llvm::FunctionType>(f->llvmType));
+
+    if (fdecl->isMain()) {
+        gIR->mainFunc = func;
+    }
+
+    // name parameters
+    llvm::Function::arg_iterator iarg = func->arg_begin();
+    int k = 0;
+    if (f->llvmRetInPtr) {
+        iarg->setName("retval");
+        f->llvmRetArg = iarg;
+        ++iarg;
+    }
+    if (f->llvmUsesThis) {
+        iarg->setName("this");
+        ++iarg;
+    }
+    int varargs = -1;
+    if (f->linkage == LINKd && f->varargs == 1)
+        varargs = 0;
+    for (; iarg != func->arg_end(); ++iarg)
+    {
+        Argument* arg = Argument::getNth(f->parameters, k++);
+        //arg->llvmValue = iarg;
+        //Logger::println("identifier: '%s' %p\n", arg->ident->toChars(), arg->ident);
+        if (arg && arg->ident != 0) {
+            if (arg->vardecl) {
+                arg->vardecl->llvmValue = iarg;
+            }
+            iarg->setName(arg->ident->toChars());
+        }
+        else if (!arg && varargs >= 0) {
+            if (varargs == 0) {
+                iarg->setName("_arguments");
+                fdecl->llvmArguments = iarg;
+            }
+            else if (varargs == 1) {
+                iarg->setName("_argptr");
+                fdecl->llvmArgPtr = iarg;
+            }
+            else
+            assert(0);
+            varargs++;
+        }
+        else {
+            iarg->setName("unnamed");
+        }
+    }
+
+    Logger::cout() << "func decl: " << *func << '\n';
+
+    return func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoRealloc(llvm::Value* ptr, const llvm::Type* ty)
+{
+    /*size_t sz = gTargetData->getTypeSize(ty);
+    llvm::ConstantInt* n = llvm::ConstantInt::get(DtoSize_t(), sz, false);
+    if (ptr == 0) {
+        llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
+        ptr = llvm::ConstantPointerNull::get(i8pty);
+    }
+    return DtoRealloc(ptr, n);*/
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoRealloc(llvm::Value* ptr, llvm::Value* n)
+{
+    assert(ptr);
+    assert(n);
+
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_realloc");
+    assert(fn);
+
+    llvm::Value* newptr = ptr;
+
+    llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    if (ptr->getType() != i8pty) {
+        newptr = new llvm::BitCastInst(ptr,i8pty,"tmp",gIR->scopebb());
+    }
+
+    std::vector<llvm::Value*> args;
+    args.push_back(newptr);
+    args.push_back(n);
+    llvm::Value* ret = new llvm::CallInst(fn, args.begin(), args.end(), "tmprealloc", gIR->scopebb());
+
+    return ret->getType() == ptr->getType() ? ret : new llvm::BitCastInst(ret,ptr->getType(),"tmp",gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoAssert(llvm::Value* cond, llvm::Value* loc, llvm::Value* msg)
+{
+    assert(loc);
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(3);
+    llargs[0] = cond ? DtoBoolean(cond) : llvm::ConstantInt::getFalse();
+    llargs[1] = loc;
+    llargs[2] = msg ? msg : llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+
+    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_assert");
+    assert(fn);
+    llvm::CallInst* call = new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+    call->setCallingConv(llvm::CallingConv::C);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoArgument(const llvm::Type* paramtype, Argument* fnarg, Expression* argexp)
+{
+    llvm::Value* retval = 0;
+
+    bool haslvals = !gIR->exps.empty();
+    if (haslvals)
+        gIR->exps.push_back(IRExp(NULL,NULL,NULL));
+
+    DValue* arg = argexp->toElem(gIR);
+
+    if (haslvals)
+        gIR->exps.pop_back();
+
+    if (arg->inPlace()) {
+        retval = arg->getRVal();
+        return retval;
+    }
+
+    Type* realtype = DtoDType(argexp->type);
+    TY argty = realtype->ty;
+    if (DtoIsPassedByRef(realtype)) {
+        if (!fnarg || !fnarg->llvmCopy) {
+            if (DSliceValue* sv = arg->isSlice()) {
+                retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
+                DtoSetArray(retval, DtoArrayLen(sv), DtoArrayPtr(sv));
+            }
+            else {
+                retval = arg->getRVal();
+            }
+        }
+        else {
+            llvm::Value* allocaInst = 0;
+            llvm::BasicBlock* entryblock = &gIR->topfunc()->front();
+            //const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(arg->mem->getType());
+            const llvm::Type* realtypell = DtoType(realtype);
+            const llvm::PointerType* pty = llvm::PointerType::get(realtypell);
+            if (argty == Tstruct) {
+                allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
+                DValue* dst = new DVarValue(realtype, allocaInst, true);
+                DtoAssign(dst,arg);
+                delete dst;
+            }
+            else if (argty == Tdelegate) {
+                allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
+                DValue* dst = new DVarValue(realtype, allocaInst, true);
+                DtoAssign(dst,arg);
+                delete dst;
+            }
+            else if (argty == Tarray) {
+                if (arg->isSlice()) {
+                    allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint());
+                }
+                else {
+                    allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
+                }
+            }
+            else
+            assert(0);
+
+            DValue* dst = new DVarValue(realtype, allocaInst, true);
+            DtoAssign(dst,arg);
+            delete dst;
+
+            retval = allocaInst;
+        }
+    }
+    else if (!fnarg || fnarg->llvmCopy) {
+        Logger::println("regular arg");
+        if (DSliceValue* sl = arg->isSlice()) {
+            if (sl->ptr) Logger::cout() << "ptr = " << *sl->ptr << '\n';
+            if (sl->len) Logger::cout() << "len = " << *sl->len << '\n';
+            assert(0);
+        }
+        else {
+            retval = arg->getRVal();
+        }
+    }
+    else {
+        Logger::println("as ptr arg");
+        retval = arg->getLVal();
+        if (paramtype && retval->getType() != paramtype)
+        {
+            assert(0);
+            /*assert(retval->getType() == paramtype->getContainedType(0));
+            new llvm::StoreInst(retval, arg->getLVal(), gIR->scopebb());
+            retval = arg->getLVal();*/
+        }
+    }
+
+    if (fnarg && paramtype && retval->getType() != paramtype) {
+        // this is unfortunately needed with the way SymOffExp is overused
+        // and static arrays can end up being a pointer to their element type
+        if (arg->isField()) {
+            retval = gIR->ir->CreateBitCast(retval, paramtype, "tmp");
+        }
+        else {
+            Logger::cout() << "got '" << *retval->getType() << "' expected '" << *paramtype << "'\n";
+            assert(0 && "parameter type that was actually passed is invalid");
+        }
+    }
+
+    delete arg;
+
+    return retval;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoNestedVariable(VarDeclaration* vd)
+{
+    FuncDeclaration* fd = vd->toParent()->isFuncDeclaration();
+    assert(fd != NULL);
+
+    IRFunction* fcur = &gIR->func();
+    FuncDeclaration* f = fcur->decl;
+
+    // on this stack
+    if (fd == f) {
+        llvm::Value* v = DtoGEPi(vd->llvmValue,0,unsigned(vd->llvmNestedIndex),"tmp");
+        if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))) {
+            Logger::cout() << "1267 loading: " << *v << '\n';
+            v = gIR->ir->CreateLoad(v,"tmp");
+        }
+        return v;
+    }
+
+    // on a caller stack
+    llvm::Value* ptr = f->llvmThisVar;
+    assert(ptr);
+
+    f = f->toParent()->isFuncDeclaration();
+    assert(f);
+    assert(f->llvmNested);
+    const llvm::Type* nesttype = f->llvmNested->getType();
+    assert(nesttype);
+
+    ptr = gIR->ir->CreateBitCast(ptr, nesttype, "tmp");
+
+    Logger::cout() << "nested var reference:" << '\n' << *ptr << *nesttype << '\n';
+
+    while (f) {
+        if (fd == f) {
+            llvm::Value* v = DtoGEPi(ptr,0,vd->llvmNestedIndex,"tmp");
+            if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type))) {
+                Logger::cout() << "1291 loading: " << *v << '\n';
+                v = gIR->ir->CreateLoad(v,"tmp");
+            }
+            return v;
+        }
+        else {
+            ptr = DtoGEPi(ptr,0,0,"tmp");
+            ptr = gIR->ir->CreateLoad(ptr,"tmp");
+        }
+        f = f->toParent()->isFuncDeclaration();
+    }
+
+    assert(0 && "nested var not found");
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoAssign(DValue* lhs, DValue* rhs)
+{
+    Type* t = DtoDType(lhs->getType());
+    Type* t2 = DtoDType(rhs->getType());
+
+    if (t->ty == Tstruct) {
+        if (t2 != t) {
+            // TODO: fix this, use 'rhs' for something
+            DtoStructZeroInit(lhs->getLVal());
+        }
+        else if (!rhs->inPlace()) {
+            DtoStructCopy(lhs->getLVal(),rhs->getRVal());
+        }
+    }
+    else if (t->ty == Tarray) {
+        // lhs is slice
+        if (DSliceValue* s = lhs->isSlice()) {
+            if (DSliceValue* s2 = rhs->isSlice()) {
+                DtoArrayCopy(s, s2);
+            }
+            else if (t->next == t2) {
+                if (s->len)
+                    DtoArrayInit(s->ptr, s->len, rhs->getRVal());
+                else
+                    DtoArrayInit(s->ptr, rhs->getRVal());
+            }
+            else
+            assert(rhs->inPlace());
+        }
+        // rhs is slice
+        else if (DSliceValue* s = rhs->isSlice()) {
+            DtoSetArray(lhs->getLVal(),s->len,s->ptr);
+        }
+        // null
+        else if (rhs->isNull()) {
+            DtoNullArray(lhs->getLVal());
+        }
+        // reference assignment
+        else {
+            DtoArrayAssign(lhs->getLVal(), rhs->getRVal());
+        }
+    }
+    else if (t->ty == Tsarray) {
+        DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal());
+    }
+    else if (t->ty == Tdelegate) {
+        if (rhs->isNull())
+            DtoNullDelegate(lhs->getLVal());
+        else if (!rhs->inPlace())
+            DtoDelegateCopy(lhs->getLVal(), rhs->getRVal());
+    }
+    else if (t->ty == Tclass) {
+        assert(t2->ty == Tclass);
+        // assignment to this in constructor special case
+        if (lhs->isThis()) {
+            llvm::Value* tmp = rhs->getRVal();
+            FuncDeclaration* fdecl = gIR->func().decl;
+            // respecify the this param
+            if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar))
+                fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint());
+            DtoStore(tmp, fdecl->llvmThisVar);
+        }
+        // regular class ref -> class ref assignment
+        else {
+            DtoStore(rhs->getRVal(), lhs->getLVal());
+        }
+    }
+    else {
+        llvm::Value* r = rhs->getRVal();
+        llvm::Value* l = lhs->getLVal();
+        Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
+        gIR->ir->CreateStore(r, l);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::ConstantInt* DtoConstSize_t(size_t i)
+{
+    return llvm::ConstantInt::get(DtoSize_t(), i, false);
+}
+llvm::ConstantInt* DtoConstUint(unsigned i)
+{
+    return llvm::ConstantInt::get(llvm::Type::Int32Ty, i, false);
+}
+llvm::ConstantInt* DtoConstInt(int i)
+{
+    return llvm::ConstantInt::get(llvm::Type::Int32Ty, i, true);
+}
+llvm::Constant* DtoConstBool(bool b)
+{
+    return llvm::ConstantInt::get(llvm::Type::Int1Ty, b, false);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* DtoConstString(const char* str)
+{
+    std::string s(str);
+    llvm::Constant* init = llvm::ConstantArray::get(s, true);
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
+        init->getType(), true,llvm::GlobalValue::InternalLinkage, init, "stringliteral", gIR->module);
+    llvm::Constant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
+    return DtoConstSlice(
+        DtoConstSize_t(s.length()),
+        llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2)
+    );
+}
+llvm::Constant* DtoConstStringPtr(const char* str, const char* section)
+{
+    std::string s(str);
+    llvm::Constant* init = llvm::ConstantArray::get(s, true);
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(
+        init->getType(), true,llvm::GlobalValue::InternalLinkage, init, "stringliteral", gIR->module);
+    if (section) gvar->setSection(section);
+    llvm::Constant* idxs[2] = { DtoConstUint(0), DtoConstUint(0) };
+    return llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoMemCpy(llvm::Value* dst, llvm::Value* src, llvm::Value* nbytes)
+{
+    assert(dst->getType() == src->getType());
+
+    llvm::Type* arrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    llvm::Value *dstarr, *srcarr;
+    if (dst->getType() == arrty)
+    {
+        dstarr = dst;
+        srcarr = src;
+    }
+    else
+    {
+        dstarr = new llvm::BitCastInst(dst,arrty,"tmp",gIR->scopebb());
+        srcarr = new llvm::BitCastInst(src,arrty,"tmp",gIR->scopebb());
+    }
+
+    llvm::Function* fn = (global.params.is64bit) ? LLVM_DeclareMemCpy64() : LLVM_DeclareMemCpy32();
+    std::vector<llvm::Value*> llargs;
+    llargs.resize(4);
+    llargs[0] = dstarr;
+    llargs[1] = srcarr;
+    llargs[2] = nbytes;
+    llargs[3] = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+
+    new llvm::CallInst(fn, llargs.begin(), llargs.end(), "", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoLoad(llvm::Value* src)
+{
+    return gIR->ir->CreateLoad(src,"tmp");
+}
+
+void DtoStore(llvm::Value* src, llvm::Value* dst)
+{
+    gIR->ir->CreateStore(src,dst);
+}
+
+bool DtoCanLoad(llvm::Value* ptr)
+{
+    if (llvm::isa<llvm::PointerType>(ptr->getType())) {
+        return ptr->getType()->getContainedType(0)->isFirstClassType();
+    }
+    return false;
+}
+
+llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
+{
+    return gIR->ir->CreateBitCast(v, t, "tmp");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoIndexStruct(llvm::Value* ptr, StructDeclaration* sd, Type* t, unsigned os, std::vector<unsigned>& idxs)
+{
+    Logger::println("checking for offset %u type %s:", os, t->toChars());
+    LOG_SCOPE;
+
+    if (idxs.empty())
+        idxs.push_back(0);
+
+    const llvm::Type* llt = llvm::PointerType::get(DtoType(t));
+
+    for (unsigned i=0; i<sd->fields.dim; ++i) {
+        VarDeclaration* vd = (VarDeclaration*)sd->fields.data[i];
+        Type* vdtype = DtoDType(vd->type);
+        Logger::println("found %u type %s", vd->offset, vdtype->toChars());
+        assert(vd->llvmFieldIndex >= 0);
+        if (os == vd->offset && vdtype == t) {
+            idxs.push_back(vd->llvmFieldIndex);
+            ptr = DtoGEP(ptr, idxs, "tmp");
+            if (ptr->getType() != llt)
+                ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
+            if (vd->llvmFieldIndexOffset)
+                ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
+            return ptr;
+        }
+        else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) {
+            TypeStruct* ts = (TypeStruct*)vdtype;
+            StructDeclaration* ssd = ts->sym;
+            idxs.push_back(vd->llvmFieldIndex);
+            if (vd->llvmFieldIndexOffset) {
+                Logger::println("has union field offset");
+                ptr = DtoGEP(ptr, idxs, "tmp");
+                if (ptr->getType() != llt)
+                    ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
+                ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
+                std::vector<unsigned> tmp;
+                return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
+            }
+            else {
+                const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type));
+                if (ptr->getType() != sty) {
+                    ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
+                    std::vector<unsigned> tmp;
+                    return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
+                }
+                else {
+                    return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs);
+                }
+            }
+        }
+    }
+
+    size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0));
+    assert(os % llt_sz == 0);
+    ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
+    return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+bool DtoIsTemplateInstance(Dsymbol* s)
+{
+    if (!s) return false;
+    if (s->isTemplateInstance() && !s->isTemplateMixin())
+        return true;
+    else if (s->parent)
+        return DtoIsTemplateInstance(s->parent);
+    return false;
+}