diff gen/toir.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/toir.c@f869c636a113
children 058d3925950e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/toir.cpp	Sat Nov 03 14:44:58 2007 +0100
@@ -0,0 +1,3089 @@
+// Backend stubs
+
+/* DMDFE backend stubs
+ * This file contains the implementations of the backend routines.
+ * For dmdfe these do nothing but print a message saying the module
+ * has been parsed. Substitute your own behaviors for these routimes.
+ */
+
+#include <stdio.h>
+#include <math.h>
+#include <sstream>
+#include <fstream>
+#include <iostream>
+
+#include "gen/llvm.h"
+
+#include "total.h"
+#include "init.h"
+#include "symbol.h"
+#include "mtype.h"
+#include "hdrgen.h"
+#include "port.h"
+
+#include "gen/irstate.h"
+#include "gen/elem.h"
+#include "gen/logger.h"
+#include "gen/tollvm.h"
+#include "gen/runtime.h"
+#include "gen/arrays.h"
+
+#include "gen/dvalue.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DeclarationExp::toElem(IRState* p)
+{
+    Logger::print("DeclarationExp::toElem: %s | T=%s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    // variable declaration
+    if (VarDeclaration* vd = declaration->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration");
+
+        // static
+        if (vd->isDataseg())
+        {
+            vd->toObjFile();
+        }
+        else
+        {
+            Logger::println("vdtype = %s", vd->type->toChars());
+            // referenced by nested delegate?
+            if (vd->nestedref) {
+                Logger::println("has nestedref set");
+                vd->llvmValue = p->func().decl->llvmNested;
+                assert(vd->llvmValue);
+                assert(vd->llvmNestedIndex >= 0);
+            }
+            // normal stack variable
+            else {
+                // allocate storage on the stack
+                const llvm::Type* lltype = DtoType(vd->type);
+                llvm::AllocaInst* allocainst = new llvm::AllocaInst(lltype, vd->toChars(), p->topallocapoint());
+                //allocainst->setAlignment(vd->type->alignsize()); // TODO
+                vd->llvmValue = allocainst;
+            }
+            DValue* ie = DtoInitializer(vd->init);
+            delete ie;
+        }
+
+        return new DVarValue(vd, vd->llvmValue, true);
+    }
+    // struct declaration
+    else if (StructDeclaration* s = declaration->isStructDeclaration())
+    {
+        Logger::println("StructDeclaration");
+        s->toObjFile();
+    }
+    // function declaration
+    else if (FuncDeclaration* f = declaration->isFuncDeclaration())
+    {
+        Logger::println("FuncDeclaration");
+        f->toObjFile();
+    }
+    // alias declaration
+    else if (AliasDeclaration* a = declaration->isAliasDeclaration())
+    {
+        Logger::println("AliasDeclaration - no work");
+        // do nothing
+    }
+    else if (EnumDeclaration* e = declaration->isEnumDeclaration())
+    {
+        Logger::println("EnumDeclaration - no work");
+        // do nothing
+    }
+    // unsupported declaration
+    else
+    {
+        error("Only Var/Struct-Declaration is supported for DeclarationExp");
+        assert(0);
+    }
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* VarExp::toElem(IRState* p)
+{
+    Logger::print("VarExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    assert(var);
+    if (VarDeclaration* vd = var->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration %s", vd->toChars());
+
+        // _arguments
+        if (vd->ident == Id::_arguments)
+        {
+            Logger::println("Id::_arguments");
+            if (!vd->llvmValue)
+                vd->llvmValue = p->func().decl->llvmArguments;
+            assert(vd->llvmValue);
+            return new DVarValue(vd, vd->llvmValue, true);
+        }
+        // _argptr
+        else if (vd->ident == Id::_argptr)
+        {
+            Logger::println("Id::_argptr");
+            if (!vd->llvmValue)
+                vd->llvmValue = p->func().decl->llvmArgPtr;
+            assert(vd->llvmValue);
+            return new DVarValue(vd, vd->llvmValue, true);
+        }
+        // _dollar
+        else if (vd->ident == Id::dollar)
+        {
+            Logger::println("Id::dollar");
+            assert(!p->arrays.empty());
+            llvm::Value* tmp = DtoArrayLen(p->arrays.back());
+            return new DVarValue(vd, tmp, false);
+        }
+        // typeinfo
+        else if (TypeInfoDeclaration* tid = vd->isTypeInfoDeclaration())
+        {
+            Logger::println("TypeInfoDeclaration");
+            tid->toObjFile();
+            assert(tid->llvmValue);
+            const llvm::Type* vartype = DtoType(type);
+            llvm::Value* m;
+            if (tid->llvmValue->getType() != llvm::PointerType::get(vartype))
+                m = p->ir->CreateBitCast(tid->llvmValue, vartype, "tmp");
+            else
+                m = tid->llvmValue;
+            return new DVarValue(vd, m, true);
+        }
+        // nested variable
+        else if (vd->nestedref) {
+            Logger::println("nested variable");
+            return new DVarValue(vd, DtoNestedVariable(vd), true);
+        }
+        // function parameter
+        else if (vd->isParameter()) {
+            Logger::println("function param");
+            if (!vd->llvmValue) {
+                // TODO: determine this properly
+                // this happens when the DMD frontend generates by pointer wrappers for struct opEquals(S) and opCmp(S)
+                vd->llvmValue = &p->func().func->getArgumentList().back();
+            }
+            if (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type) || llvm::isa<llvm::AllocaInst>(vd->llvmValue)) {
+                return new DVarValue(vd, vd->llvmValue, true);
+            }
+            else if (llvm::isa<llvm::Argument>(vd->llvmValue)) {
+                return new DImValue(type, vd->llvmValue);
+            }
+            else assert(0);
+        }
+        else {
+            // take care of forward references of global variables
+            if (!vd->llvmTouched && vd->isDataseg())
+                vd->toObjFile();
+            assert(vd->llvmValue);
+            return new DVarValue(vd, vd->llvmValue, true);
+        }
+    }
+    else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
+    {
+        Logger::println("FuncDeclaration");
+        if (fdecl->llvmInternal != LLVMva_arg)// && fdecl->llvmValue == 0)
+            fdecl->toObjFile();
+        return new DFuncValue(fdecl, fdecl->llvmValue);
+    }
+    else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration())
+    {
+        // this seems to be the static initialiser for structs
+        Type* sdecltype = DtoDType(sdecl->type);
+        Logger::print("Sym: type=%s\n", sdecltype->toChars());
+        assert(sdecltype->ty == Tstruct);
+        TypeStruct* ts = (TypeStruct*)sdecltype;
+        assert(ts->llvmInit);
+        return new DVarValue(type, ts->llvmInit, true);
+    }
+    else
+    {
+        assert(0 && "Unimplemented VarExp type");
+    }
+
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* VarExp::toConstElem(IRState* p)
+{
+    Logger::print("VarExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    if (SymbolDeclaration* sdecl = var->isSymbolDeclaration())
+    {
+        // this seems to be the static initialiser for structs
+        Type* sdecltype = DtoDType(sdecl->type);
+        Logger::print("Sym: type=%s\n", sdecltype->toChars());
+        assert(sdecltype->ty == Tstruct);
+        TypeStruct* ts = (TypeStruct*)sdecltype;
+        assert(ts->sym->llvmInitZ);
+        return ts->sym->llvmInitZ;
+    }
+    assert(0 && "Only support const var exp is SymbolDeclaration");
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* IntegerExp::toElem(IRState* p)
+{
+    Logger::print("IntegerExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    llvm::Constant* c = toConstElem(p);
+    return new DConstValue(type, c);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* IntegerExp::toConstElem(IRState* p)
+{
+    Logger::print("IntegerExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    const llvm::Type* t = DtoType(type);
+    if (llvm::isa<llvm::PointerType>(t)) {
+        llvm::Constant* i = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)value,false);
+        return llvm::ConstantExpr::getIntToPtr(i, t);
+    }
+    else if (llvm::isa<llvm::IntegerType>(t)) {
+        return llvm::ConstantInt::get(t,(uint64_t)value,!type->isunsigned());
+    }
+    assert(0);
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* RealExp::toElem(IRState* p)
+{
+    Logger::print("RealExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    llvm::Constant* c = toConstElem(p);
+    return new DConstValue(type, c);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* RealExp::toConstElem(IRState* p)
+{
+    Logger::print("RealExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    Type* t = DtoDType(type);
+    const llvm::Type* fty = DtoType(t);
+    if (t->ty == Tfloat32 || t->ty == Timaginary32)
+        return llvm::ConstantFP::get(fty,float(value));
+    else if (t->ty == Tfloat64 || t->ty == Timaginary64 || t->ty == Tfloat80 || t->ty == Timaginary80)
+        return llvm::ConstantFP::get(fty,double(value));
+    assert(0);
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* NullExp::toElem(IRState* p)
+{
+    Logger::print("NullExp::toElem(type=%s): %s\n", type->toChars(),toChars());
+    LOG_SCOPE;
+    llvm::Constant* c = toConstElem(p);
+    return new DNullValue(type, c);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* NullExp::toConstElem(IRState* p)
+{
+    Logger::print("NullExp::toConstElem(type=%s): %s\n", type->toChars(),toChars());
+    LOG_SCOPE;
+    const llvm::Type* t = DtoType(type);
+    if (type->ty == Tarray) {
+        assert(llvm::isa<llvm::StructType>(t));
+        return llvm::ConstantAggregateZero::get(t);
+    }
+    else {
+        return llvm::Constant::getNullValue(t);
+    }
+    assert(0);
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* StringExp::toElem(IRState* p)
+{
+    Logger::print("StringExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    Type* dtype = DtoDType(type);
+    Type* cty = DtoDType(dtype->next);
+
+    const llvm::Type* ct = DtoType(dtype->next);
+    //printf("ct = %s\n", type->next->toChars());
+    const llvm::ArrayType* at = llvm::ArrayType::get(ct,len+1);
+
+    llvm::Constant* _init;
+    if (cty->ty == Tchar) {
+        uint8_t* str = (uint8_t*)string;
+        std::string cont((char*)str, len);
+        _init = llvm::ConstantArray::get(cont,true);
+    }
+    else if (cty->ty == Twchar) {
+        uint16_t* str = (uint16_t*)string;
+        std::vector<llvm::Constant*> vals;
+        for(size_t i=0; i<len; ++i) {
+            vals.push_back(llvm::ConstantInt::get(ct, str[i], false));;
+        }
+        vals.push_back(llvm::ConstantInt::get(ct, 0, false));
+        _init = llvm::ConstantArray::get(at,vals);
+    }
+    else if (cty->ty == Tdchar) {
+        uint32_t* str = (uint32_t*)string;
+        std::vector<llvm::Constant*> vals;
+        for(size_t i=0; i<len; ++i) {
+            vals.push_back(llvm::ConstantInt::get(ct, str[i], false));;
+        }
+        vals.push_back(llvm::ConstantInt::get(ct, 0, false));
+        _init = llvm::ConstantArray::get(at,vals);
+    }
+    else
+    assert(0);
+
+    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage;
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(at,true,_linkage,_init,"stringliteral",gIR->module);
+
+    llvm::ConstantInt* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Constant* idxs[2] = { zero, zero };
+    llvm::Constant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
+
+    if (dtype->ty == Tarray) {
+        llvm::Constant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false);
+        if (!p->topexp() || p->topexp()->e2 != this) {
+            llvm::Value* tmpmem = new llvm::AllocaInst(DtoType(dtype),"tempstring",p->topallocapoint());
+            DtoSetArray(tmpmem, clen, arrptr);
+            return new DVarValue(type, tmpmem, true);
+        }
+        else if (p->topexp()->e2 == this) {
+            DValue* arr = p->topexp()->v;
+            assert(arr);
+            DtoSetArray(arr->getLVal(), clen, arrptr);
+            return new DImValue(type, arr->getLVal(), true);
+        }
+        assert(0);
+    }
+    else if (dtype->ty == Tsarray) {
+        const llvm::Type* dstType = llvm::PointerType::get(llvm::ArrayType::get(ct, len));
+        llvm::Value* emem = (gvar->getType() == dstType) ? gvar : DtoBitCast(gvar, dstType);
+        return new DVarValue(type, emem, true);
+    }
+    else if (dtype->ty == Tpointer) {
+        return new DImValue(type, arrptr);
+    }
+
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* StringExp::toConstElem(IRState* p)
+{
+    Logger::print("StringExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    uint8_t* str = (uint8_t*)string;
+    std::string cont((char*)str, len);
+
+    Type* t = DtoDType(type);
+
+    if (t->ty == Tsarray) {
+        return llvm::ConstantArray::get(cont,false);
+    }
+    llvm::Constant* _init = llvm::ConstantArray::get(cont,true);
+
+    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::InternalLinkage;//WeakLinkage;
+    llvm::GlobalVariable* gvar = new llvm::GlobalVariable(_init->getType(),true,_linkage,_init,"stringliteral",gIR->module);
+
+    llvm::ConstantInt* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Constant* idxs[2] = { zero, zero };
+    llvm::Constant* arrptr = llvm::ConstantExpr::getGetElementPtr(gvar,idxs,2);
+
+    if (t->ty == Tpointer) {
+        return arrptr;
+    }
+
+    if (t->ty == Tarray) {
+        llvm::Constant* clen = llvm::ConstantInt::get(DtoSize_t(),len,false);
+        return DtoConstSlice(clen, arrptr);
+    }
+
+    assert(0);
+    return NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AssignExp::toElem(IRState* p)
+{
+    Logger::print("AssignExp::toElem: %s | %s = %s\n", toChars(), e1->type->toChars(), e2->type ? e2->type->toChars() : 0);
+    LOG_SCOPE;
+
+    p->exps.push_back(IRExp(e1,e2,NULL));
+
+    DValue* l = e1->toElem(p);
+    p->topexp()->v = l;
+    DValue* r = e2->toElem(p);
+
+    p->exps.pop_back();
+
+    if (l->isArrayLen())
+        DtoResizeDynArray(l->getLVal(), r->getRVal());
+    else
+        DtoAssign(l, r);
+    return l;
+
+    /*
+    if (l->type == DValue::ARRAYLEN)
+    {
+        DtoResizeDynArray(l->mem, r->getValue());
+        delete r;
+        delete l;
+        return 0;
+    }
+
+    Type* e1type = DtoDType(e1->type);
+    Type* e2type = DtoDType(e2->type);
+    TY e1ty = e1type->ty;
+    TY e2ty = e2type->ty;
+
+    DValue* e = new DValue(this);
+    e->type = DValue::VAR;
+
+    // struct
+    if (e1ty == Tstruct) {
+        e->mem = l->mem;
+        // struct + struct
+        if (e2ty == Tstruct) {
+            // struct literals do the assignment themselvs (in place)
+            if (!r->inplace) {
+                DtoStructCopy(l->mem,r->getValue());
+            }
+            else {
+                e->inplace = true;
+            }
+        }
+        // struct + const int
+        else if (e2type->isintegral()){
+            IntegerExp* iexp = (IntegerExp*)e2;
+            assert(iexp->value == 0 && "Only integral struct initializer allowed is zero");
+            DtoStructZeroInit(l->mem);
+        }
+        // :x
+        else
+        assert(0 && "struct = unknown");
+    }
+    else if (e1ty == Tsarray) {
+        assert(0 && "static array not supported");
+    }
+    else if (e1ty == Tarray) {
+        if (e2type->isscalar() || e2type->ty == Tclass){
+            if (l->type == DValue::SLICE) {
+                DtoArrayInit(l->mem, l->arg, r->getValue());
+            }
+            else {
+                DtoArrayInit(l->mem, r->getValue());
+            }
+        }
+        else if (e2ty == Tarray) {
+            //new llvm::StoreInst(r->val,l->val,p->scopebb());
+            if (r->type == DValue::NUL) {
+                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
+                assert(c->isNullValue());
+                DtoNullArray(l->mem);
+                e->mem = l->mem;
+            }
+            else if (r->type == DValue::SLICE) {
+                if (l->type == DValue::SLICE) {
+                    DtoArrayCopy(l,r);
+                    e->type = DValue::SLICE;
+                    e->mem = l->mem;
+                    e->arg = l->arg;
+                }
+                else {
+                    DtoSetArray(l->mem,r->arg,r->mem);
+                    e->mem = l->mem;
+                }
+            }
+            else {
+                // new expressions write directly to the array reference
+                // so do string literals
+                e->mem = l->mem;
+                if (!r->inplace) {
+                    assert(r->mem);
+                    DtoArrayAssign(l->mem, r->mem);
+                }
+                else {
+                    e->inplace = true;
+                }
+            }
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tpointer) {
+        e->mem = l->mem;
+        if (e2ty == Tpointer) {
+            llvm::Value* v = r->field ? r->mem : r->getValue();
+            Logger::cout() << "*=*: " << *v << ", " << *l->mem << '\n';
+            new llvm::StoreInst(v, l->mem, p->scopebb());
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tclass) {
+        if (e2ty == Tclass) {
+            llvm::Value* tmp = r->getValue();
+            Logger::cout() << "tmp: " << *tmp << " ||| " << *l->mem << '\n';
+            // assignment to this in constructor special case
+            if (l->isthis) {
+                FuncDeclaration* fdecl = p->func().decl;
+                // respecify the this param
+                if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar))
+                    fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", p->topallocapoint());
+                new llvm::StoreInst(tmp, fdecl->llvmThisVar, p->scopebb());
+                e->mem = fdecl->llvmThisVar;
+            }
+            // regular class ref -> class ref assignment
+            else {
+                new llvm::StoreInst(tmp, l->mem, p->scopebb());
+                e->mem = l->mem;
+            }
+        }
+        else
+        assert(0);
+    }
+    else if (e1ty == Tdelegate) {
+        Logger::println("Assigning to delegate");
+        if (e2ty == Tdelegate) {
+            if (r->type == DValue::NUL) {
+                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
+                if (c->isNullValue()) {
+                    DtoNullDelegate(l->mem);
+                    e->mem = l->mem;
+                }
+                else
+                assert(0);
+            }
+            else if (r->inplace) {
+                // do nothing
+                e->inplace = true;
+                e->mem = l->mem;
+            }
+            else {
+                DtoDelegateCopy(l->mem, r->getValue());
+                e->mem = l->mem;
+            }
+        }
+        else
+        assert(0);
+    }
+    // !struct && !array && !pointer && !class
+    else {
+        Logger::cout() << *l->mem << '\n';
+        new llvm::StoreInst(r->getValue(),l->mem,p->scopebb());
+        e->mem = l->mem;
+    }
+
+    delete r;
+    delete l;
+
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AddExp::toElem(IRState* p)
+{
+    Logger::print("AddExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    Type* t = DtoDType(type);
+    Type* e1type = DtoDType(e1->type);
+    Type* e2type = DtoDType(e2->type);
+
+    if (e1type != e2type) {
+        if (e1type->ty == Tpointer && e1type->next->ty == Tstruct) {
+            assert(r->isConst());
+            llvm::ConstantInt* cofs = llvm::cast<llvm::ConstantInt>(r->isConst()->c);
+
+            TypeStruct* ts = (TypeStruct*)e1type->next;
+            std::vector<unsigned> offsets;
+            llvm::Value* v = DtoIndexStruct(l->getRVal(), ts->sym, t->next, cofs->getZExtValue(), offsets);
+            return new DFieldValue(type, v, true);
+        }
+        else if (e1->type->ty == Tpointer) {
+            llvm::Value* v = new llvm::GetElementPtrInst(l->getRVal(), r->getRVal(), "tmp", p->scopebb());
+            return new DImValue(type, v);
+        }
+        assert(0);
+    }
+    else {
+        return DtoBinAdd(l,r);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AddAssignExp::toElem(IRState* p)
+{
+    Logger::print("AddAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    p->exps.push_back(IRExp(e1,e2,NULL));
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+    p->exps.pop_back();
+
+    DValue* res;
+    if (DtoDType(e1->type)->ty == Tpointer) {
+        llvm::Value* gep = new llvm::GetElementPtrInst(l->getRVal(),r->getRVal(),"tmp",p->scopebb());
+        res = new DImValue(type, gep);
+    }
+    else {
+        res = DtoBinAdd(l,r);
+    }
+    DtoAssign(l, res);
+
+    return l;
+
+    /*
+
+    Type* e1type = DtoDType(e1->type);
+
+    DValue* e = new DValue(this);
+    llvm::Value* val = 0;
+    if (e1type->ty == Tpointer) {
+        val = e->mem = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+    else {
+        val = e->val = llvm::BinaryOperator::createAdd(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+
+    assert(l->mem);
+    new llvm::StoreInst(val,l->mem,p->scopebb());
+    e->type = DValue::VAR;
+
+    delete l;
+    delete r;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* MinExp::toElem(IRState* p)
+{
+    Logger::print("MinExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    if (DtoDType(e1->type)->ty == Tpointer) {
+        llvm::Value* left = p->ir->CreatePtrToInt(l->getRVal(), DtoSize_t(), "tmp");
+        llvm::Value* right = p->ir->CreatePtrToInt(r->getRVal(), DtoSize_t(), "tmp");
+        llvm::Value* diff = p->ir->CreateSub(left,right,"tmp");
+        if (diff->getType() != DtoType(type))
+            diff = p->ir->CreateIntToPtr(diff, DtoType(type));
+        return new DImValue(type, diff);
+    }
+    else {
+        return DtoBinSub(l,r);
+    }
+
+    /*
+    llvm::Value* left = l->getValue();
+    if (llvm::isa<llvm::PointerType>(left->getType()))
+        left = new llvm::PtrToIntInst(left,DtoSize_t(),"tmp",p->scopebb());
+
+    llvm::Value* right = r->getValue();
+    if (llvm::isa<llvm::PointerType>(right->getType()))
+        right = new llvm::PtrToIntInst(right,DtoSize_t(),"tmp",p->scopebb());
+
+    e->val = llvm::BinaryOperator::createSub(left,right,"tmp",p->scopebb());
+    e->type = DValue::VAL;
+
+    const llvm::Type* totype = DtoType(type);
+    if (e->val->getType() != totype) {
+        assert(0);
+        assert(llvm::isa<llvm::PointerType>(e->val->getType()));
+        assert(llvm::isa<llvm::IntegerType>(totype));
+        e->val = new llvm::IntToPtrInst(e->val,totype,"tmp",p->scopebb());
+    }
+
+    delete l;
+    delete r;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* MinAssignExp::toElem(IRState* p)
+{
+    Logger::print("MinAssignExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    DValue* res;
+    if (DtoDType(e1->type)->ty == Tpointer) {
+        llvm::Value* tmp = r->getRVal();
+        llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false);
+        tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb());
+        tmp = new llvm::GetElementPtrInst(l->getRVal(),tmp,"tmp",p->scopebb());
+        res = new DImValue(type, tmp);
+    }
+    else {
+        res = DtoBinSub(l,r);
+    }
+    DtoAssign(l, res);
+
+    return l;
+
+    /*
+
+    Type* e1type = DtoDType(e1->type);
+
+    llvm::Value* tmp = 0;
+    if (e1type->ty == Tpointer) {
+        tmp = r->getValue();
+        llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false);
+        tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb());
+        tmp = new llvm::GetElementPtrInst(l->getValue(),tmp,"tmp",p->scopebb());
+    }
+    else {
+        tmp = llvm::BinaryOperator::createSub(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    }
+
+    assert(l->mem);
+    new llvm::StoreInst(tmp, l->mem, p->scopebb());
+
+    delete l;
+    delete r;
+
+    DValue* e = new DValue(this);
+    e->val = tmp;
+    e->type = DValue::VAR;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* MulExp::toElem(IRState* p)
+{
+    Logger::print("MulExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    return DtoBinMul(l,r);
+    /*
+    if (l->dvalue && r->dvalue) {
+        Logger::println("DVALUE PATH");
+        e->dvalue = DtoBinMul(l->dvalue, r->dvalue);
+        e->val = e->dvalue->getRVal();
+    }
+    else {
+        llvm::Value* vl = l->getValue();
+        llvm::Value* vr = r->getValue();
+        Logger::cout() << "mul: " << *vl << ", " << *vr << '\n';
+        e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
+        e->dvalue = new DImValue(type, e->val);
+    }
+    e->type = DValue::VAL;
+    delete l;
+    delete r;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* MulAssignExp::toElem(IRState* p)
+{
+    Logger::print("MulAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    DValue* res = DtoBinMul(l,r);
+    DtoAssign(l, res);
+
+    return l;
+
+    /*
+    llvm::Value* vl = l->getValue();
+    llvm::Value* vr = r->getValue();
+    Logger::cout() << "mulassign: " << *vl << ", " << *vr << '\n';
+    llvm::Value* tmp = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
+
+    assert(l->mem);
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    DValue* e = new DValue(this);
+    e->val = tmp;
+    e->type = DValue::VAR;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DivExp::toElem(IRState* p)
+{
+    Logger::print("DivExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    return DtoBinDiv(l, r);
+    /*
+
+    Type* t = DtoDType(type);
+
+    if (t->isunsigned())
+        e->val = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isintegral())
+        e->val = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isfloating())
+        e->val = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+    e->type = DValue::VAL;
+    delete l;
+    delete r;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DivAssignExp::toElem(IRState* p)
+{
+    Logger::print("DivAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    DValue* res = DtoBinDiv(l,r);
+    DtoAssign(l, res);
+
+    return l;
+
+    /*
+
+    Type* t = DtoDType(type);
+
+    llvm::Value* tmp;
+    if (t->isunsigned())
+        tmp = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isintegral())
+        tmp = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isfloating())
+        tmp = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+
+    assert(l->mem);
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    DValue* e = new DValue(this);
+    e->val = tmp;
+    e->type = DValue::VAR;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ModExp::toElem(IRState* p)
+{
+    Logger::print("ModExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    return DtoBinRem(l, r);
+    /*
+    Type* t = DtoDType(type);
+
+    if (t->isunsigned())
+        e->val = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isintegral())
+        e->val = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isfloating())
+        e->val = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+    e->type = DValue::VAL;
+    delete l;
+    delete r;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ModAssignExp::toElem(IRState* p)
+{
+    Logger::print("ModAssignExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    DValue* res = DtoBinRem(l, r);
+    DtoAssign(l, res);
+
+    return l;
+
+    /*
+
+    Type* t = DtoDType(type);
+
+    llvm::Value* tmp;
+    if (t->isunsigned())
+        tmp = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isintegral())
+        tmp = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else if (t->isfloating())
+        tmp = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
+    else
+        assert(0);
+
+    assert(l->mem);
+    new llvm::StoreInst(tmp,l->mem,p->scopebb());
+
+    delete l;
+    delete r;
+
+    DValue* e = new DValue(this);
+    e->val = tmp;
+    e->type = DValue::VAR;
+    return e;
+    */
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CallExp::toElem(IRState* p)
+{
+    Logger::print("CallExp::toElem: %s\n", toChars());
+    LOG_SCOPE;
+
+    DValue* fn = e1->toElem(p);
+
+    TypeFunction* tf = 0;
+    Type* e1type = DtoDType(e1->type);
+
+    bool delegateCall = false;
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty,1,false);
+    LINK dlink = LINKdefault;
+
+    // hidden struct return parameter handling
+    bool retinptr = false;
+
+    // regular functions
+    if (e1type->ty == Tfunction) {
+        tf = (TypeFunction*)e1type;
+        if (tf->llvmRetInPtr) {
+            retinptr = true;
+        }
+        dlink = tf->linkage;
+    }
+
+    // delegates
+    else if (e1type->ty == Tdelegate) {
+        Logger::println("delegateTy = %s\n", e1type->toChars());
+        assert(e1type->next->ty == Tfunction);
+        tf = (TypeFunction*)e1type->next;
+        if (tf->llvmRetInPtr) {
+            retinptr = true;
+        }
+        dlink = tf->linkage;
+        delegateCall = true;
+    }
+
+    // invalid
+    else {
+        assert(tf);
+    }
+
+    // va args
+    bool va_magic = false;
+    bool va_intrinsic = false;
+    DFuncValue* dfv = fn->isFunc();
+    if (dfv && dfv->func) {
+        FuncDeclaration* fndecl = dfv->func;
+        if (fndecl->llvmInternal == LLVMva_intrinsic) {
+            va_magic = true;
+            va_intrinsic = true;
+        }
+        else if (fndecl->llvmInternal == LLVMva_start) {
+            va_magic = true;
+        }
+        else if (fndecl->llvmInternal == LLVMva_arg) {
+            //Argument* fnarg = Argument::getNth(tf->parameters, 0);
+            Expression* exp = (Expression*)arguments->data[0];
+            DValue* expelem = exp->toElem(p);
+            Type* t = DtoDType(type);
+            const llvm::Type* llt = DtoType(type);
+            if (DtoIsPassedByRef(t))
+                llt = llvm::PointerType::get(llt);
+            return new DImValue(type, p->ir->CreateVAArg(expelem->getLVal(),llt,"tmp"));
+        }
+    }
+
+    // args
+    size_t n = arguments->dim;
+    DFuncValue* dfn = fn->isFunc();
+    if (dfn && dfn->func && dfn->func->llvmInternal == LLVMva_start)
+        n = 1;
+    if (delegateCall || (dfn && dfn->vthis)) n++;
+    if (retinptr) n++;
+    if (tf->linkage == LINKd && tf->varargs == 1) n+=2;
+    if (dfn && dfn->func && dfn->func->isNested()) n++;
+
+    llvm::Value* funcval = fn->getRVal();
+    assert(funcval != 0);
+    std::vector<llvm::Value*> llargs(n, 0);
+
+    const llvm::FunctionType* llfnty = 0;
+
+    // normal function call
+    if (llvm::isa<llvm::FunctionType>(funcval->getType())) {
+        llfnty = llvm::cast<llvm::FunctionType>(funcval->getType());
+    }
+    // pointer to something
+    else if (llvm::isa<llvm::PointerType>(funcval->getType())) {
+        // pointer to function pointer - I think this not really supposed to happen, but does :/
+        // seems like sometimes we get a func* other times a func**
+        if (llvm::isa<llvm::PointerType>(funcval->getType()->getContainedType(0))) {
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+        }
+        // function pointer
+        if (llvm::isa<llvm::FunctionType>(funcval->getType()->getContainedType(0))) {
+            //Logger::cout() << "function pointer type:\n" << *funcval << '\n';
+            llfnty = llvm::cast<llvm::FunctionType>(funcval->getType()->getContainedType(0));
+        }
+        // struct pointer - delegate
+        else if (llvm::isa<llvm::StructType>(funcval->getType()->getContainedType(0))) {
+            funcval = DtoGEP(funcval,zero,one,"tmp",p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            const llvm::Type* ty = funcval->getType()->getContainedType(0);
+            llfnty = llvm::cast<llvm::FunctionType>(ty);
+        }
+        // unknown
+        else {
+            Logger::cout() << "what kind of pointer are we calling? : " << *funcval->getType() << '\n';
+        }
+    }
+    else {
+        Logger::cout() << "what are we calling? : " << *funcval << '\n';
+    }
+    assert(llfnty);
+    //Logger::cout() << "Function LLVM type: " << *llfnty << '\n';
+
+    // argument handling
+    llvm::FunctionType::param_iterator argiter = llfnty->param_begin();
+    int j = 0;
+
+    IRExp* topexp = p->topexp();
+
+    bool isInPlace = false;
+
+    // hidden struct return arguments
+    if (retinptr) {
+        if (topexp && topexp->e2 == this) {
+            assert(topexp->v);
+            llvm::Value* tlv = topexp->v->getLVal();
+            assert(llvm::isa<llvm::StructType>(tlv->getType()->getContainedType(0)));
+            llargs[j] = tlv;
+            if (DtoIsPassedByRef(tf->next)) {
+                isInPlace = true;
+            }
+            else
+            assert(0);
+        }
+        else {
+            llargs[j] = new llvm::AllocaInst(argiter->get()->getContainedType(0),"rettmp",p->topallocapoint());
+        }
+        ++j;
+        ++argiter;
+    }
+
+    // this arguments
+    if (dfn && dfn->vthis) {
+        Logger::println("This Call");
+        if (dfn->vthis->getType() != argiter->get()) {
+            //Logger::cout() << *fn->thisparam << '|' << *argiter->get() << '\n';
+            llargs[j] = new llvm::BitCastInst(dfn->vthis, argiter->get(), "tmp", p->scopebb());
+        }
+        else {
+            llargs[j] = dfn->vthis;
+        }
+        ++j;
+        ++argiter;
+    }
+    // delegate context arguments
+    else if (delegateCall) {
+        Logger::println("Delegate Call");
+        llvm::Value* contextptr = DtoGEP(fn->getRVal(),zero,zero,"tmp",p->scopebb());
+        llargs[j] = new llvm::LoadInst(contextptr,"tmp",p->scopebb());
+        ++j;
+        ++argiter;
+    }
+    // nested call
+    else if (dfn && dfn->func && dfn->func->isNested()) {
+        Logger::println("Nested Call");
+        llvm::Value* contextptr = p->func().decl->llvmNested;
+        assert(contextptr);
+        llargs[j] = p->ir->CreateBitCast(contextptr, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+        ++j;
+        ++argiter;
+    }
+
+    // va arg function special argument passing
+    if (va_magic) {
+        size_t n = va_intrinsic ? arguments->dim : 1;
+        for (int i=0; i<n; i++,j++)
+        {
+            Argument* fnarg = Argument::getNth(tf->parameters, i);
+            Expression* exp = (Expression*)arguments->data[i];
+            DValue* expelem = exp->toElem(p);
+            llargs[j] = p->ir->CreateBitCast(expelem->getLVal(), llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+        }
+    }
+    // regular arguments
+    else {
+        if (tf->linkage == LINKd && tf->varargs == 1)
+        {
+            Logger::println("doing d-style variadic arguments");
+
+            std::vector<const llvm::Type*> vtypes;
+            std::vector<llvm::Value*> vvalues;
+            std::vector<llvm::Value*> vtypeinfos;
+
+            for (int i=0; i<arguments->dim; i++) {
+                Argument* fnarg = Argument::getNth(tf->parameters, i);
+                Expression* argexp = (Expression*)arguments->data[i];
+                vvalues.push_back(DtoArgument(NULL, fnarg, argexp));
+                vtypes.push_back(vvalues.back()->getType());
+
+                TypeInfoDeclaration* tidecl = argexp->type->getTypeInfoDeclaration();
+                tidecl->toObjFile();
+                assert(tidecl->llvmValue);
+                vtypeinfos.push_back(tidecl->llvmValue);
+            }
+
+            const llvm::StructType* vtype = llvm::StructType::get(vtypes);
+            llvm::Value* mem = new llvm::AllocaInst(vtype,"_argptr_storage",p->topallocapoint());
+            for (unsigned i=0; i<vtype->getNumElements(); ++i)
+                p->ir->CreateStore(vvalues[i], DtoGEPi(mem,0,i,"tmp"));
+
+            //llvm::Constant* typeinfoparam = llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(llfnty->getParamType(j)));
+            assert(Type::typeinfo->llvmInitZ);
+            const llvm::Type* typeinfotype = llvm::PointerType::get(Type::typeinfo->llvmInitZ->getType());
+            Logger::cout() << "typeinfo ptr type: " << *typeinfotype << '\n';
+            const llvm::ArrayType* typeinfoarraytype = llvm::ArrayType::get(typeinfotype,vtype->getNumElements());
+            llvm::Value* typeinfomem = new llvm::AllocaInst(typeinfoarraytype,"_arguments_storage",p->topallocapoint());
+            for (unsigned i=0; i<vtype->getNumElements(); ++i) {
+                llvm::Value* v = p->ir->CreateBitCast(vtypeinfos[i], typeinfotype, "tmp");
+                p->ir->CreateStore(v, DtoGEPi(typeinfomem,0,i,"tmp"));
+            }
+
+            llvm::Value* typeinfoarrayparam = new llvm::AllocaInst(llfnty->getParamType(j)->getContainedType(0),"_arguments_array",p->topallocapoint());
+            p->ir->CreateStore(DtoConstSize_t(vtype->getNumElements()), DtoGEPi(typeinfoarrayparam,0,0,"tmp"));
+            llvm::Value* casttypeinfomem = p->ir->CreateBitCast(typeinfomem, llvm::PointerType::get(typeinfotype), "tmp");
+            p->ir->CreateStore(casttypeinfomem, DtoGEPi(typeinfoarrayparam,0,1,"tmp"));
+
+            llargs[j] = typeinfoarrayparam;;
+            j++;
+            llargs[j] = p->ir->CreateBitCast(mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+            j++;
+            llargs.resize(2);
+        }
+        else {
+            Logger::println("doing normal arguments");
+            for (int i=0; i<arguments->dim; i++,j++) {
+                Argument* fnarg = Argument::getNth(tf->parameters, i);
+                llargs[j] = DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
+                // this hack is necessary :/
+                if (dfn && dfn->func && dfn->func->llvmRunTimeHack) {
+                    if (llargs[j]->getType() != llfnty->getParamType(j))
+                        llargs[j] = DtoBitCast(llargs[j], llfnty->getParamType(j));
+                }
+            }
+            Logger::println("%d params passed", n);
+            for (int i=0; i<n; ++i) {
+                assert(llargs[i]);
+                Logger::cout() << *llargs[i] << '\n';
+            }
+        }
+    }
+
+    // void returns cannot not be named
+    const char* varname = "";
+    if (llfnty->getReturnType() != llvm::Type::VoidTy)
+        varname = "tmp";
+
+    Logger::cout() << "Calling: " << *funcval->getType() << '\n';
+
+    // call the function
+    llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
+    llvm::Value* retllval = (retinptr) ? llargs[0] : call;
+
+    // set calling convention
+    if (dfn && dfn->func) {
+        int li = dfn->func->llvmInternal;
+        if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) {
+            call->setCallingConv(DtoCallingConv(dlink));
+        }
+    }
+    else if (delegateCall) {
+        call->setCallingConv(DtoCallingConv(dlink));
+    }
+    else if (dfn && dfn->cc != (unsigned)-1) {
+        call->setCallingConv(dfn->cc);
+    }
+
+    return new DImValue(type, retllval, isInPlace);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CastExp::toElem(IRState* p)
+{
+    Logger::print("CastExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+
+    const llvm::Type* tolltype = DtoType(to);
+    Type* fromtype = DtoDType(e1->type);
+    Type* totype = DtoDType(to);
+    int lsz = fromtype->size();
+    int rsz = totype->size();
+
+    // this makes sure the strange lvalue casts don't screw things up
+    llvm::Value* rval = 0;
+    llvm::Value* rval2 = 0;
+    bool isslice = false;
+
+    if (fromtype->isintegral()) {
+        if (totype->isintegral()) {
+            if (lsz < rsz) {
+                Logger::cout() << "cast to: " << *tolltype << '\n';
+                if (fromtype->isunsigned() || fromtype->ty == Tbool) {
+                    rval = new llvm::ZExtInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+                } else {
+                    rval = new llvm::SExtInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+                }
+            }
+            else if (lsz > rsz) {
+                rval = new llvm::TruncInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+            else {
+                rval = new llvm::BitCastInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+        }
+        else if (totype->isfloating()) {
+            if (fromtype->isunsigned()) {
+                rval = new llvm::UIToFPInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+            else {
+                rval = new llvm::SIToFPInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+        }
+        else if (totype->ty == Tpointer) {
+            rval = p->ir->CreateIntToPtr(u->getRVal(), tolltype, "tmp");
+        }
+        else {
+            assert(0);
+        }
+    }
+    else if (fromtype->isfloating()) {
+        if (totype->isfloating()) {
+            if ((fromtype->ty == Tfloat80 || fromtype->ty == Tfloat64) && (totype->ty == Tfloat80 || totype->ty == Tfloat64)) {
+                rval = u->getRVal();
+            }
+            else if (lsz < rsz) {
+                rval = new llvm::FPExtInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+            else if (lsz > rsz) {
+                rval = new llvm::FPTruncInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+            else {
+                assert(0);
+            }
+        }
+        else if (totype->isintegral()) {
+            if (totype->isunsigned()) {
+                rval = new llvm::FPToUIInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+            else {
+                rval = new llvm::FPToSIInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+            }
+        }
+        else {
+            assert(0);
+        }
+    }
+    else if (fromtype->ty == Tclass) {
+        //assert(to->ty == Tclass);
+        rval = new llvm::BitCastInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+    }
+    else if (fromtype->ty == Tarray || fromtype->ty == Tsarray) {
+        Logger::cout() << "from array or sarray" << '\n';
+        if (totype->ty == Tpointer) {
+            Logger::cout() << "to pointer" << '\n';
+            assert(fromtype->next == totype->next || totype->next->ty == Tvoid);
+            llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+            llvm::Value* ptr = DtoGEP(u->getRVal(),zero,one,"tmp",p->scopebb());
+            rval = new llvm::LoadInst(ptr, "tmp", p->scopebb());
+            if (fromtype->next != totype->next)
+                rval = p->ir->CreateBitCast(rval, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+        }
+        else if (totype->ty == Tarray) {
+            Logger::cout() << "to array" << '\n';
+            const llvm::Type* ptrty = DtoType(totype->next);
+            if (ptrty == llvm::Type::VoidTy)
+                ptrty = llvm::Type::Int8Ty;
+            ptrty = llvm::PointerType::get(ptrty);
+
+            const llvm::Type* ety = DtoType(fromtype->next);
+            if (ety == llvm::Type::VoidTy)
+                ety = llvm::Type::Int8Ty;
+
+            if (DSliceValue* usl = u->isSlice()) {
+                rval = new llvm::BitCastInst(usl->ptr, ptrty, "tmp", p->scopebb());
+                if (fromtype->next->size() == totype->next->size())
+                    rval2 = usl->len;
+                else
+                    rval2 = DtoArrayCastLength(usl->len, ety, ptrty->getContainedType(0));
+            }
+            else {
+                llvm::Value* uval = u->getRVal();
+                if (fromtype->ty == Tsarray) {
+                    Logger::cout() << "uvalTy = " << *uval->getType() << '\n';
+                    assert(llvm::isa<llvm::PointerType>(uval->getType()));
+                    const llvm::ArrayType* arrty = llvm::cast<llvm::ArrayType>(uval->getType()->getContainedType(0));
+                    rval2 = llvm::ConstantInt::get(DtoSize_t(), arrty->getNumElements(), false);
+                    rval2 = DtoArrayCastLength(rval2, ety, ptrty->getContainedType(0));
+                    rval = new llvm::BitCastInst(uval, ptrty, "tmp", p->scopebb());
+                }
+                else {
+                    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+                    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+                    rval2 = DtoGEP(uval,zero,zero,"tmp",p->scopebb());
+                    rval2 = new llvm::LoadInst(rval2, "tmp", p->scopebb());
+                    rval2 = DtoArrayCastLength(rval2, ety, ptrty->getContainedType(0));
+
+                    rval = DtoGEP(uval,zero,one,"tmp",p->scopebb());
+                    rval = new llvm::LoadInst(rval, "tmp", p->scopebb());
+                    //Logger::cout() << *e->mem->getType() << '|' << *ptrty << '\n';
+                    rval = new llvm::BitCastInst(rval, ptrty, "tmp", p->scopebb());
+                }
+            }
+            isslice = true;
+        }
+        else if (totype->ty == Tsarray) {
+            Logger::cout() << "to sarray" << '\n';
+            assert(0);
+        }
+        else {
+            assert(0);
+        }
+    }
+    else if (fromtype->ty == Tpointer) {
+        if (totype->ty == Tpointer || totype->ty == Tclass) {
+            llvm::Value* src = u->getRVal();
+            Logger::cout() << "src: " << *src << "to type: " << *tolltype << '\n';
+            rval = new llvm::BitCastInst(src, tolltype, "tmp", p->scopebb());
+        }
+        else if (totype->isintegral()) {
+            rval = new llvm::PtrToIntInst(u->getRVal(), tolltype, "tmp", p->scopebb());
+        }
+        else
+        assert(0);
+    }
+    else {
+        assert(0);
+    }
+
+    if (isslice) {
+        return new DSliceValue(type, rval2, rval);
+    }
+    else if (u->isLValueCast() || u->isVar()) {
+        return new DLValueCast(type, u->getLVal(), rval);
+    }
+    else if (p->topexp() && p->topexp()->e1 == this) {
+        llvm::Value* lval = u->getLVal();
+        Logger::cout() << "lval: " << *lval << "rval: " << *rval << '\n';
+        return new DLValueCast(type, lval, rval);
+    }
+    else {
+        Logger::cout() << "im rval: " << *rval << '\n';
+        return new DImValue(type, rval);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* SymOffExp::toElem(IRState* p)
+{
+    Logger::print("SymOffExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    if (VarDeclaration* vd = var->isVarDeclaration())
+    {
+        Logger::println("VarDeclaration");
+        if (!vd->llvmTouched && vd->isDataseg())
+            vd->toObjFile();
+
+        // TODO
+        /*
+        if (vd->isTypedefDeclaration()) {
+            e->istypeinfo = true;
+        }
+        */
+
+        assert(vd->llvmValue);
+        Type* t = DtoDType(type);
+        Type* tnext = DtoDType(t->next);
+        Type* vdtype = DtoDType(vd->type);
+
+        llvm::Value* llvalue = vd->nestedref ? DtoNestedVariable(vd) : vd->llvmValue;
+        llvm::Value* varmem = 0;
+
+        if (vdtype->ty == Tstruct && !(t->ty == Tpointer && t->next == vdtype)) {
+            Logger::println("struct");
+            TypeStruct* vdt = (TypeStruct*)vdtype;
+            assert(vdt->sym);
+
+            const llvm::Type* llt = DtoType(t);
+            if (offset == 0) {
+                varmem = p->ir->CreateBitCast(llvalue, llt, "tmp");
+            }
+            else {
+                std::vector<unsigned> dst;
+                varmem = DtoIndexStruct(llvalue,vdt->sym, tnext, offset, dst);
+            }
+        }
+        else if (vdtype->ty == Tsarray) {
+            Logger::println("sarray");
+
+            assert(llvalue);
+            //e->arg = llvalue; // TODO
+
+            const llvm::Type* llt = DtoType(t);
+            llvm::Value* off = 0;
+            if (offset != 0) {
+                Logger::println("offset = %d\n", offset);
+            }
+            if (llvalue->getType() != llt) {
+                varmem = p->ir->CreateBitCast(llvalue, llt, "tmp");
+                if (offset != 0)
+                    varmem = DtoGEPi(varmem, offset, "tmp");
+            }
+            else {
+                assert(offset == 0);
+                varmem = DtoGEPi(llvalue,0,0,"tmp");
+            }
+        }
+        else if (offset == 0) {
+            Logger::println("normal symoff");
+
+            assert(llvalue);
+            varmem = llvalue;
+
+            const llvm::Type* llt = DtoType(t);
+            if (llvalue->getType() != llt) {
+                varmem = p->ir->CreateBitCast(varmem, llt, "tmp");
+            }
+        }
+        else {
+            assert(0);
+        }
+        return new DFieldValue(type, varmem, true);
+    }
+    else if (FuncDeclaration* fd = var->isFuncDeclaration())
+    {
+        Logger::println("FuncDeclaration");
+
+        if (fd->llvmValue == 0)
+            fd->toObjFile();
+        return new DFuncValue(fd, fd->llvmValue);
+    }
+
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* PtrExp::toElem(IRState* p)
+{
+    Logger::print("PtrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* a = e1->toElem(p);
+
+    if (p->topexp() && p->topexp()->e1 == this) {
+        Logger::println("lval PtrExp");
+        //if (a->isField()) return a;
+        return new DVarValue(type, a->getRVal(), true);
+    }
+
+    llvm::Value* lv = a->getRVal();
+    llvm::Value* v = lv;
+    if (DtoCanLoad(v))
+        v = DtoLoad(v);
+    return new DLValueCast(type, lv, v);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DotVarExp::toElem(IRState* p)
+{
+    Logger::print("DotVarExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+
+    Type* t = DtoDType(type);
+    Type* e1type = DtoDType(e1->type);
+
+    Logger::print("e1->type=%s\n", e1type->toChars());
+
+    if (VarDeclaration* vd = var->isVarDeclaration()) {
+        llvm::Value* arrptr;
+        if (e1type->ty == Tpointer) {
+            assert(e1type->next->ty == Tstruct);
+            TypeStruct* ts = (TypeStruct*)e1type->next;
+            Logger::println("Struct member offset:%d", vd->offset);
+            llvm::Value* src = l->getRVal();
+            std::vector<unsigned> vdoffsets;
+            arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets);
+        }
+        else if (e1->type->ty == Tclass) {
+            TypeClass* tc = (TypeClass*)e1type;
+            Logger::println("Class member offset: %d", vd->offset);
+            std::vector<unsigned> vdoffsets(1,0);
+            tc->sym->offsetToIndex(vd->type, vd->offset, vdoffsets);
+            llvm::Value* src = l->getRVal();
+            Logger::cout() << "src: " << *src << '\n';
+            arrptr = DtoGEP(src,vdoffsets,"tmp",p->scopebb());
+        }
+        else
+            assert(0);
+
+        Logger::cout() << "mem: " << *arrptr << '\n';
+        return new DVarValue(vd, arrptr, true);
+    }
+    else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
+    {
+        if (fdecl->llvmValue == 0)
+        {
+            fdecl->toObjFile();
+        }
+
+        llvm::Value* funcval = fdecl->llvmValue;
+        llvm::Value* vthis = l->getRVal();
+        unsigned cc = (unsigned)-1;
+
+        // virtual call
+        if (fdecl->isVirtual()) {
+            assert(fdecl->vtblIndex > 0);
+            assert(e1type->ty == Tclass);
+
+            llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+            llvm::Value* vtblidx = llvm::ConstantInt::get(llvm::Type::Int32Ty, (size_t)fdecl->vtblIndex, false);
+            funcval = DtoGEP(vthis, zero, zero, "tmp", p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            funcval = DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb());
+            funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
+            assert(funcval->getType() == fdecl->llvmValue->getType());
+            cc = DtoCallingConv(fdecl->linkage);
+        }
+        return new DFuncValue(fdecl, funcval, vthis);
+    }
+    else {
+        printf("unknown: %s\n", var->toChars());
+    }
+
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ThisExp::toElem(IRState* p)
+{
+    Logger::print("ThisExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    if (VarDeclaration* vd = var->isVarDeclaration()) {
+        llvm::Value* v = p->func().decl->llvmThisVar;
+        if (llvm::isa<llvm::AllocaInst>(v))
+            v = new llvm::LoadInst(v, "tmp", p->scopebb());
+        return new DThisValue(vd, v);
+    }
+
+    assert(0);
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AddrExp::toElem(IRState* p)
+{
+    Logger::print("AddrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+    DValue* v = e1->toElem(p);
+    if (v->isField())
+        return v;
+    return new DFieldValue(type, v->getLVal(), false);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* IndexExp::toElem(IRState* p)
+{
+    Logger::print("IndexExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+
+    Type* e1type = DtoDType(e1->type);
+
+    p->arrays.push_back(l); // if $ is used it must be an array so this is fine.
+    DValue* r = e2->toElem(p);
+    p->arrays.pop_back();
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    llvm::Value* arrptr = 0;
+    if (e1type->ty == Tpointer) {
+        arrptr = new llvm::GetElementPtrInst(l->getRVal(),r->getRVal(),"tmp",p->scopebb());
+    }
+    else if (e1type->ty == Tsarray) {
+        arrptr = DtoGEP(l->getRVal(), zero, r->getRVal(),"tmp",p->scopebb());
+    }
+    else if (e1type->ty == Tarray) {
+        arrptr = DtoGEP(l->getLVal(),zero,one,"tmp",p->scopebb());
+        arrptr = new llvm::LoadInst(arrptr,"tmp",p->scopebb());
+        arrptr = new llvm::GetElementPtrInst(arrptr,r->getRVal(),"tmp",p->scopebb());
+    }
+    assert(arrptr);
+    return new DVarValue(type, arrptr, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* SliceExp::toElem(IRState* p)
+{
+    Logger::print("SliceExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    Type* t = DtoDType(type);
+    Type* e1type = DtoDType(e1->type);
+
+    DValue* v = e1->toElem(p);
+    llvm::Value* vmem = v->getLVal();
+    assert(vmem);
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    llvm::Value* emem = 0;
+    llvm::Value* earg = 0;
+
+    // partial slice
+    if (lwr)
+    {
+        assert(upr);
+        p->arrays.push_back(v);
+        DValue* lo = lwr->toElem(p);
+
+        bool lwr_is_zero = false;
+        if (DConstValue* cv = lo->isConst())
+        {
+            assert(llvm::isa<llvm::ConstantInt>(cv->c));
+
+            if (e1type->ty == Tpointer) {
+                emem = v->getRVal();
+            }
+            else if (e1type->ty == Tarray) {
+                llvm::Value* tmp = DtoGEP(vmem,zero,one,"tmp",p->scopebb());
+                emem = new llvm::LoadInst(tmp,"tmp",p->scopebb());
+            }
+            else if (e1type->ty == Tsarray) {
+                emem = DtoGEP(vmem,zero,zero,"tmp",p->scopebb());
+            }
+            else
+            assert(emem);
+
+            llvm::ConstantInt* c = llvm::cast<llvm::ConstantInt>(cv->c);
+            if (!(lwr_is_zero = c->isZero())) {
+                emem = new llvm::GetElementPtrInst(emem,cv->c,"tmp",p->scopebb());
+            }
+        }
+        else
+        {
+            if (e1type->ty == Tarray) {
+                llvm::Value* tmp = DtoGEP(vmem,zero,one,"tmp",p->scopebb());
+                tmp = new llvm::LoadInst(tmp,"tmp",p->scopebb());
+                emem = new llvm::GetElementPtrInst(tmp,lo->getRVal(),"tmp",p->scopebb());
+            }
+            else if (e1type->ty == Tsarray) {
+                emem = DtoGEP(vmem,zero,lo->getRVal(),"tmp",p->scopebb());
+            }
+            else if (e1type->ty == Tpointer) {
+                emem = new llvm::GetElementPtrInst(v->getRVal(),lo->getRVal(),"tmp",p->scopebb());
+            }
+            else {
+                Logger::println("type = %s", e1type->toChars());
+                assert(0);
+            }
+        }
+
+        DValue* up = upr->toElem(p);
+        p->arrays.pop_back();
+
+        if (DConstValue* cv = up->isConst())
+        {
+            assert(llvm::isa<llvm::ConstantInt>(cv->c));
+            if (lwr_is_zero) {
+                earg = cv->c;
+            }
+            else {
+                if (lo->isConst()) {
+                    llvm::Constant* clo = llvm::cast<llvm::Constant>(lo->getRVal());
+                    llvm::Constant* cup = llvm::cast<llvm::Constant>(cv->c);
+                    earg = llvm::ConstantExpr::getSub(cup, clo);
+                }
+                else {
+                    earg = llvm::BinaryOperator::createSub(cv->c, lo->getRVal(), "tmp", p->scopebb());
+                }
+            }
+        }
+        else
+        {
+            if (lwr_is_zero) {
+                earg = up->getRVal();
+            }
+            else {
+                earg = llvm::BinaryOperator::createSub(up->getRVal(), lo->getRVal(), "tmp", p->scopebb());
+            }
+        }
+    }
+    // full slice
+    else
+    {
+        emem = vmem;
+    }
+
+    return new DSliceValue(type,earg,emem);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CmpExp::toElem(IRState* p)
+{
+    Logger::print("CmpExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    Type* t = DtoDType(e1->type);
+    Type* e2t = DtoDType(e2->type);
+    assert(t == e2t);
+
+    llvm::Value* eval = 0;
+
+    if (t->isintegral() || t->ty == Tpointer)
+    {
+        llvm::ICmpInst::Predicate cmpop;
+        bool skip = false;
+        switch(op)
+        {
+        case TOKlt:
+        case TOKul:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULT : llvm::ICmpInst::ICMP_SLT;
+            break;
+        case TOKle:
+        case TOKule:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_ULE : llvm::ICmpInst::ICMP_SLE;
+            break;
+        case TOKgt:
+        case TOKug:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGT : llvm::ICmpInst::ICMP_SGT;
+            break;
+        case TOKge:
+        case TOKuge:
+            cmpop = t->isunsigned() ? llvm::ICmpInst::ICMP_UGE : llvm::ICmpInst::ICMP_SGE;
+            break;
+        case TOKue:
+            cmpop = llvm::ICmpInst::ICMP_EQ;
+            break;
+        case TOKlg:
+            cmpop = llvm::ICmpInst::ICMP_NE;
+            break;
+        case TOKleg:
+            skip = true;
+            eval = llvm::ConstantInt::getTrue();
+            break;
+        case TOKunord:
+            skip = true;
+            eval = llvm::ConstantInt::getFalse();
+            break;
+
+        default:
+            assert(0);
+        }
+        if (!skip)
+        {
+            eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
+        }
+    }
+    else if (t->isfloating())
+    {
+        llvm::FCmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKlt:
+            cmpop = llvm::FCmpInst::FCMP_OLT;break;
+        case TOKle:
+            cmpop = llvm::FCmpInst::FCMP_OLE;break;
+        case TOKgt:
+            cmpop = llvm::FCmpInst::FCMP_OGT;break;
+        case TOKge:
+            cmpop = llvm::FCmpInst::FCMP_OGE;break;
+        case TOKunord:
+            cmpop = llvm::FCmpInst::FCMP_UNO;break;
+        case TOKule:
+            cmpop = llvm::FCmpInst::FCMP_ULE;break;
+        case TOKul:
+            cmpop = llvm::FCmpInst::FCMP_ULT;break;
+        case TOKuge:
+            cmpop = llvm::FCmpInst::FCMP_UGE;break;
+        case TOKug:
+            cmpop = llvm::FCmpInst::FCMP_UGT;break;
+        case TOKue:
+            cmpop = llvm::FCmpInst::FCMP_UEQ;break;
+        case TOKlg:
+            cmpop = llvm::FCmpInst::FCMP_ONE;break;
+        case TOKleg:
+            cmpop = llvm::FCmpInst::FCMP_ORD;break;
+
+        default:
+            assert(0);
+        }
+        eval = new llvm::FCmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
+    }
+    else
+    {
+        assert(0 && "Unsupported CmpExp type");
+    }
+
+    return new DImValue(type, eval);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* EqualExp::toElem(IRState* p)
+{
+    Logger::print("EqualExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    Type* t = DtoDType(e1->type);
+    Type* e2t = DtoDType(e2->type);
+    assert(t == e2t);
+
+    llvm::Value* eval = 0;
+
+    if (t->isintegral() || t->ty == Tpointer)
+    {
+        Logger::println("integral or pointer");
+        llvm::ICmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKequal:
+            cmpop = llvm::ICmpInst::ICMP_EQ;
+            break;
+        case TOKnotequal:
+            cmpop = llvm::ICmpInst::ICMP_NE;
+            break;
+        default:
+            assert(0);
+        }
+        eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
+    }
+    else if (t->isfloating())
+    {
+        Logger::println("floating");
+        llvm::FCmpInst::Predicate cmpop;
+        switch(op)
+        {
+        case TOKequal:
+            cmpop = llvm::FCmpInst::FCMP_OEQ;
+            break;
+        case TOKnotequal:
+            cmpop = llvm::FCmpInst::FCMP_UNE;
+            break;
+        default:
+            assert(0);
+        }
+        eval = new llvm::FCmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
+    }
+    else if (t->ty == Tsarray)
+    {
+        Logger::println("static array");
+        eval = DtoStaticArrayCompare(op,l->getRVal(),r->getRVal());
+    }
+    else if (t->ty == Tarray)
+    {
+        Logger::println("dynamic array");
+        eval = DtoDynArrayCompare(op,l->getRVal(),r->getRVal());
+    }
+    else if (t->ty == Tdelegate)
+    {
+        Logger::println("delegate");
+        eval = DtoCompareDelegate(op,l->getRVal(),r->getRVal());
+    }
+    else
+    {
+        assert(0 && "Unsupported EqualExp type");
+    }
+
+    return new DImValue(type, eval);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* PostExp::toElem(IRState* p)
+{
+    Logger::print("PostExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    DValue* r = e2->toElem(p);
+
+    llvm::Value* val = l->getRVal();
+    llvm::Value* post = 0;
+
+    Type* e1type = DtoDType(e1->type);
+    Type* e2type = DtoDType(e2->type);
+
+    if (e1type->isintegral())
+    {
+        assert(e2type->isintegral());
+        llvm::Value* one = llvm::ConstantInt::get(val->getType(), 1, !e2type->isunsigned());
+        if (op == TOKplusplus) {
+            post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb());
+        }
+        else if (op == TOKminusminus) {
+            post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb());
+        }
+    }
+    else if (e1type->ty == Tpointer)
+    {
+        assert(e2type->isintegral());
+        llvm::Constant* minusone = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)-1,true);
+        llvm::Constant* plusone = llvm::ConstantInt::get(DtoSize_t(),(uint64_t)1,false);
+        llvm::Constant* whichone = (op == TOKplusplus) ? plusone : minusone;
+        post = new llvm::GetElementPtrInst(val, whichone, "tmp", p->scopebb());
+    }
+    else if (e1type->isfloating())
+    {
+        assert(e2type->isfloating());
+        llvm::Value* one = llvm::ConstantFP::get(val->getType(), 1.0f);
+        if (op == TOKplusplus) {
+            post = llvm::BinaryOperator::createAdd(val,one,"tmp",p->scopebb());
+        }
+        else if (op == TOKminusminus) {
+            post = llvm::BinaryOperator::createSub(val,one,"tmp",p->scopebb());
+        }
+    }
+    else
+    assert(post);
+
+    DtoStore(post,l->getLVal());
+
+    return new DImValue(type,val,true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* NewExp::toElem(IRState* p)
+{
+    Logger::print("NewExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    assert(!thisexp);
+    assert(!newargs);
+    assert(newtype);
+    assert(!allocator);
+
+    Type* ntype = DtoDType(newtype);
+
+    const llvm::Type* t = DtoType(ntype);
+
+    llvm::Value* emem = 0;
+    bool inplace = true;
+
+    if (onstack) {
+        assert(ntype->ty == Tclass);
+        emem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint());
+    }
+    else {
+        if (ntype->ty == Tclass) {
+            emem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb());
+        }
+        else if (ntype->ty == Tarray) {
+            assert(arguments);
+            if (arguments->dim == 1) {
+                DValue* sz = ((Expression*)arguments->data[0])->toElem(p);
+                llvm::Value* dimval = sz->getRVal();
+                Type* nnt = DtoDType(ntype->next);
+                if (nnt->ty == Tvoid)
+                    nnt = Type::tint8;
+                if (!p->topexp() || p->topexp()->e2 != this) {
+                    const llvm::Type* restype = DtoType(type);
+                    Logger::cout() << "restype = " << *restype << '\n';
+                    emem = new llvm::AllocaInst(restype,"tmp",p->topallocapoint());
+                    DtoNewDynArray(emem, dimval, nnt);
+                    inplace = false;
+                }
+                else if (p->topexp() || p->topexp()->e2 != this) {
+                    assert(p->topexp()->v);
+                    emem = p->topexp()->v->getLVal();
+                    DtoNewDynArray(emem, dimval, nnt);
+                }
+                else
+                assert(0);
+            }
+            else {
+                assert(0);
+            }
+        }
+        else {
+            emem = new llvm::MallocInst(t,"tmp",p->scopebb());
+        }
+    }
+
+    if (ntype->ty == Tclass) {
+        // first apply the static initializer
+        DtoInitClass((TypeClass*)ntype, emem);
+
+        // then call constructor
+        if (arguments) {
+            assert(member);
+            assert(member->llvmValue);
+            llvm::Function* fn = llvm::cast<llvm::Function>(member->llvmValue);
+            TypeFunction* tf = (TypeFunction*)DtoDType(member->type);
+
+            std::vector<llvm::Value*> ctorargs;
+            ctorargs.push_back(emem);
+            for (size_t i=0; i<arguments->dim; ++i)
+            {
+                Expression* ex = (Expression*)arguments->data[i];
+                Argument* fnarg = Argument::getNth(tf->parameters, i);
+                llvm::Value* a = DtoArgument(fn->getFunctionType()->getParamType(i+1), fnarg, ex);
+                ctorargs.push_back(a);
+            }
+            emem = new llvm::CallInst(fn, ctorargs.begin(), ctorargs.end(), "tmp", p->scopebb());
+        }
+    }
+    else if (ntype->ty == Tstruct) {
+        TypeStruct* ts = (TypeStruct*)ntype;
+        if (ts->isZeroInit()) {
+            DtoStructZeroInit(emem);
+        }
+        else {
+            DtoStructCopy(emem,ts->llvmInit);
+        }
+    }
+
+    if (inplace)
+        return new DImValue(type, emem, true);
+
+    return new DVarValue(type, emem, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DeleteExp::toElem(IRState* p)
+{
+    Logger::print("DeleteExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    //assert(e1->type->ty != Tclass);
+
+    DValue* v = e1->toElem(p);
+    llvm::Value* val = v->getRVal();
+    llvm::Value* ldval = 0;
+
+    const llvm::Type* t = val->getType();
+    llvm::Constant* z = llvm::Constant::getNullValue(t);
+
+    Type* e1type = DtoDType(e1->type);
+
+    if (e1type->ty == Tpointer) {
+        Logger::cout() << *z << '\n';
+        Logger::cout() << *val << '\n';
+        new llvm::FreeInst(val, p->scopebb());
+        new llvm::StoreInst(z, v->getLVal(), p->scopebb());
+    }
+    else if (e1type->ty == Tclass) {
+        TypeClass* tc = (TypeClass*)e1type;
+        DtoCallClassDtors(tc, val);
+
+        if (DVarValue* vv = v->isVar()) {
+            if (vv->var && !vv->var->onstack)
+                new llvm::FreeInst(val, p->scopebb());
+        }
+        new llvm::StoreInst(z, v->getLVal(), p->scopebb());
+    }
+    else if (e1type->ty == Tarray) {
+        // must be on the heap (correct?)
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+        llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+        llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb());
+        ptr = new llvm::LoadInst(ptr,"tmp",p->scopebb());
+        new llvm::FreeInst(ptr, p->scopebb());
+        DtoNullArray(val);
+    }
+    else {
+        assert(0);
+    }
+
+    // this expression produces no useful data
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ArrayLengthExp::toElem(IRState* p)
+{
+    Logger::print("ArrayLengthExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+
+    if (p->topexp() && p->topexp()->e1 == this)
+    {
+        return new DArrayLenValue(type, u->getLVal());
+    }
+    else
+    {
+        llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+        llvm::Value* ptr = DtoGEP(u->getRVal(),zero,zero,"tmp",p->scopebb());
+        ptr = new llvm::LoadInst(ptr, "tmp", p->scopebb());
+        return new DImValue(type, ptr);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AssertExp::toElem(IRState* p)
+{
+    Logger::print("AssertExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+    DValue* m = msg ? msg->toElem(p) : NULL;
+
+    llvm::Value* loca = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false);
+    DtoAssert(u->getRVal(), loca, m ? m->getRVal() : NULL);
+
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* NotExp::toElem(IRState* p)
+{
+    Logger::print("NotExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+
+    llvm::Value* b = DtoBoolean(u->getRVal());
+
+    llvm::Constant* zero = llvm::ConstantInt::get(llvm::Type::Int1Ty, 0, true);
+    b = p->ir->CreateICmpEQ(b,zero);
+
+    return new DImValue(type, b);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* AndAndExp::toElem(IRState* p)
+{
+    Logger::print("AndAndExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::Value* resval = 0;
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"andandtmp",p->topallocapoint());
+
+    DValue* u = e1->toElem(p);
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* andand = new llvm::BasicBlock("andand", gIR->topfunc(), oldend);
+    llvm::BasicBlock* andandend = new llvm::BasicBlock("andandend", gIR->topfunc(), oldend);
+
+    llvm::Value* ubool = DtoBoolean(u->getRVal());
+    new llvm::StoreInst(ubool,resval,p->scopebb());
+    new llvm::BranchInst(andand,andandend,ubool,p->scopebb());
+
+    p->scope() = IRScope(andand, andandend);
+    DValue* v = e2->toElem(p);
+
+    llvm::Value* vbool = DtoBoolean(v->getRVal());
+    llvm::Value* uandvbool = llvm::BinaryOperator::create(llvm::BinaryOperator::And, ubool, vbool,"tmp",p->scopebb());
+    new llvm::StoreInst(uandvbool,resval,p->scopebb());
+    new llvm::BranchInst(andandend,p->scopebb());
+
+    p->scope() = IRScope(andandend, oldend);
+
+    resval = new llvm::LoadInst(resval,"tmp",p->scopebb());
+    return new DImValue(type, resval);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* OrOrExp::toElem(IRState* p)
+{
+    Logger::print("OrOrExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::Value* resval = 0;
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    resval = new llvm::AllocaInst(llvm::Type::Int1Ty,"orortmp",p->topallocapoint());
+
+    DValue* u = e1->toElem(p);
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* oror = new llvm::BasicBlock("oror", gIR->topfunc(), oldend);
+    llvm::BasicBlock* ororend = new llvm::BasicBlock("ororend", gIR->topfunc(), oldend);
+
+    llvm::Value* ubool = DtoBoolean(u->getRVal());
+    new llvm::StoreInst(ubool,resval,p->scopebb());
+    new llvm::BranchInst(ororend,oror,ubool,p->scopebb());
+
+    p->scope() = IRScope(oror, ororend);
+    DValue* v = e2->toElem(p);
+
+    llvm::Value* vbool = DtoBoolean(v->getRVal());
+    new llvm::StoreInst(vbool,resval,p->scopebb());
+    new llvm::BranchInst(ororend,p->scopebb());
+
+    p->scope() = IRScope(ororend, oldend);
+
+    resval = new llvm::LoadInst(resval,"tmp",p->scopebb());
+    return new DImValue(type, resval);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define BinBitExp(X,Y) \
+DValue* X##Exp::toElem(IRState* p) \
+{ \
+    Logger::print("%sExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \
+    LOG_SCOPE; \
+    DValue* u = e1->toElem(p); \
+    DValue* v = e2->toElem(p); \
+    llvm::Value* x = llvm::BinaryOperator::create(llvm::Instruction::Y, u->getRVal(), v->getRVal(), "tmp", p->scopebb()); \
+    return new DImValue(type, x); \
+} \
+\
+DValue* X##AssignExp::toElem(IRState* p) \
+{ \
+    Logger::print("%sAssignExp::toElem: %s | %s\n", #X, toChars(), type->toChars()); \
+    LOG_SCOPE; \
+    p->exps.push_back(IRExp(e1,e2,NULL)); \
+    DValue* u = e1->toElem(p); \
+    p->topexp()->v = u; \
+    DValue* v = e2->toElem(p); \
+    p->exps.pop_back(); \
+    llvm::Value* uval = u->getRVal(); \
+    llvm::Value* vval = v->getRVal(); \
+    llvm::Value* tmp = llvm::BinaryOperator::create(llvm::Instruction::Y, uval, vval, "tmp", p->scopebb()); \
+    new llvm::StoreInst(DtoPointedType(u->getLVal(), tmp), u->getLVal(), p->scopebb()); \
+    return u; \
+}
+
+BinBitExp(And,And);
+BinBitExp(Or,Or);
+BinBitExp(Xor,Xor);
+BinBitExp(Shl,Shl);
+BinBitExp(Shr,AShr);
+BinBitExp(Ushr,LShr);
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* HaltExp::toElem(IRState* p)
+{
+    Logger::print("HaltExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    llvm::Value* loca = llvm::ConstantInt::get(llvm::Type::Int32Ty, loc.linnum, false);
+    DtoAssert(llvm::ConstantInt::getFalse(), loca, NULL);
+
+    new llvm::UnreachableInst(p->scopebb());
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DelegateExp::toElem(IRState* p)
+{
+    Logger::print("DelegateExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+
+    llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
+    llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
+
+    const llvm::Type* int8ptrty = llvm::PointerType::get(llvm::Type::Int8Ty);
+
+    assert(p->topexp() && p->topexp()->e2 == this && p->topexp()->v);
+    llvm::Value* lval = p->topexp()->v->getLVal();
+
+    llvm::Value* context = DtoGEP(lval,zero,zero,"tmp",p->scopebb());
+    llvm::Value* castcontext = new llvm::BitCastInst(u->getRVal(),int8ptrty,"tmp",p->scopebb());
+    new llvm::StoreInst(castcontext, context, p->scopebb());
+
+    llvm::Value* fptr = DtoGEP(lval,zero,one,"tmp",p->scopebb());
+
+    assert(func->llvmValue);
+    llvm::Value* castfptr = new llvm::BitCastInst(func->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb());
+    new llvm::StoreInst(castfptr, fptr, p->scopebb());
+
+    return new DImValue(type, u->getRVal(), true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* IdentityExp::toElem(IRState* p)
+{
+    Logger::print("IdentityExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+    DValue* v = e2->toElem(p);
+
+    llvm::Value* l = u->getRVal();
+    llvm::Value* r = v->getRVal();
+
+    Type* t1 = DtoDType(e1->type);
+
+    llvm::Value* eval = 0;
+
+    if (t1->ty == Tarray) {
+        if (v->isNull()) {
+            r = NULL;
+        }
+        else {
+            assert(l->getType() == r->getType());
+        }
+        eval = DtoDynArrayIs(op,l,r);
+    }
+    else {
+        llvm::ICmpInst::Predicate pred = (op == TOKidentity) ? llvm::ICmpInst::ICMP_EQ : llvm::ICmpInst::ICMP_NE;
+        if (t1->ty == Tpointer && v->isNull() && l->getType() != r->getType()) {
+            r = llvm::ConstantPointerNull::get(llvm::cast<llvm::PointerType>(l->getType()));
+        }
+        Logger::cout() << "l = " << *l << " r = " << *r << '\n';
+        eval = new llvm::ICmpInst(pred, l, r, "tmp", p->scopebb());
+    }
+    return new DImValue(type, eval);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CommaExp::toElem(IRState* p)
+{
+    Logger::print("CommaExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+    DValue* v = e2->toElem(p);
+    return v;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CondExp::toElem(IRState* p)
+{
+    Logger::print("CondExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    Type* dtype = DtoDType(type);
+    const llvm::Type* resty = DtoType(dtype);
+
+    // allocate a temporary for the final result. failed to come up with a better way :/
+    llvm::BasicBlock* entryblock = &p->topfunc()->front();
+    llvm::Value* resval = new llvm::AllocaInst(resty,"condtmp",p->topallocapoint());
+    DVarValue* dvv = new DVarValue(type, resval, true);
+
+    llvm::BasicBlock* oldend = p->scopeend();
+    llvm::BasicBlock* condtrue = new llvm::BasicBlock("condtrue", gIR->topfunc(), oldend);
+    llvm::BasicBlock* condfalse = new llvm::BasicBlock("condfalse", gIR->topfunc(), oldend);
+    llvm::BasicBlock* condend = new llvm::BasicBlock("condend", gIR->topfunc(), oldend);
+
+    DValue* c = econd->toElem(p);
+    llvm::Value* cond_val = DtoBoolean(c->getRVal());
+    new llvm::BranchInst(condtrue,condfalse,cond_val,p->scopebb());
+
+    p->scope() = IRScope(condtrue, condfalse);
+    DValue* u = e1->toElem(p);
+    DtoAssign(dvv, u);
+    new llvm::BranchInst(condend,p->scopebb());
+
+    p->scope() = IRScope(condfalse, condend);
+    DValue* v = e2->toElem(p);
+    DtoAssign(dvv, v);
+    new llvm::BranchInst(condend,p->scopebb());
+
+    p->scope() = IRScope(condend, oldend);
+    return dvv;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ComExp::toElem(IRState* p)
+{
+    Logger::print("ComExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* u = e1->toElem(p);
+
+    llvm::Value* value = u->getRVal();
+    llvm::Value* minusone = llvm::ConstantInt::get(value->getType(), -1, true);
+    value = llvm::BinaryOperator::create(llvm::Instruction::Xor, value, minusone, "tmp", p->scopebb());
+
+    return new DImValue(type, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* NegExp::toElem(IRState* p)
+{
+    Logger::print("NegExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+    llvm::Value* val = l->getRVal();
+
+    Type* t = DtoDType(type);
+
+    llvm::Value* zero = 0;
+    if (t->isintegral())
+        zero = llvm::ConstantInt::get(val->getType(), 0, true);
+    else if (t->isfloating()) {
+        if (t->ty == Tfloat32)
+            zero = llvm::ConstantFP::get(val->getType(), float(0));
+        else if (t->ty == Tfloat64 || t->ty == Tfloat80)
+            zero = llvm::ConstantFP::get(val->getType(), double(0));
+        else
+        assert(0);
+    }
+    else
+        assert(0);
+
+    val = llvm::BinaryOperator::createSub(zero,val,"tmp",p->scopebb());
+    return new DImValue(type, val);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CatExp::toElem(IRState* p)
+{
+    Logger::print("CatExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    Type* t = DtoDType(type);
+
+    IRExp* ex = p->topexp();
+    if (ex && ex->e2 == this) {
+        assert(ex->v);
+        DtoCatArrays(ex->v->getLVal(),e1,e2);
+        return new DImValue(type, ex->v->getLVal(), true);
+    }
+    else {
+        assert(t->ty == Tarray);
+        const llvm::Type* arrty = DtoType(t);
+        llvm::Value* dst = new llvm::AllocaInst(arrty, "tmpmem", p->topallocapoint());
+        DtoCatArrays(dst,e1,e2);
+        return new DVarValue(type, dst, true);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* CatAssignExp::toElem(IRState* p)
+{
+    Logger::print("CatAssignExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    DValue* l = e1->toElem(p);
+
+    Type* e1type = DtoDType(e1->type);
+    Type* elemtype = DtoDType(e1type->next);
+    Type* e2type = DtoDType(e2->type);
+
+    if (e2type == elemtype) {
+        DtoCatAssignElement(l->getLVal(),e2);
+    }
+    else if (e1type == e2type) {
+        DtoCatAssignArray(l->getLVal(),e2);
+    }
+    else
+        assert(0 && "only one element at a time right now");
+
+    return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* FuncExp::toElem(IRState* p)
+{
+    Logger::print("FuncExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    assert(fd);
+
+    if (fd->isNested()) Logger::println("nested");
+    Logger::println("kind = %s\n", fd->kind());
+
+    fd->toObjFile();
+
+    llvm::Value* lval = NULL;
+    if (!p->topexp() || p->topexp()->e2 != this) {
+        const llvm::Type* dgty = DtoType(type);
+        Logger::cout() << "delegate without explicit storage:" << '\n' << *dgty << '\n';
+        lval = new llvm::AllocaInst(dgty,"dgstorage",p->topallocapoint());
+    }
+    else if (p->topexp()->e2 == this) {
+        assert(p->topexp()->v);
+        lval = p->topexp()->v->getLVal();;
+    }
+    else
+    assert(0);
+
+    llvm::Value* context = DtoGEPi(lval,0,0,"tmp",p->scopebb());
+    const llvm::PointerType* pty = llvm::cast<llvm::PointerType>(context->getType()->getContainedType(0));
+    llvm::Value* llvmNested = p->func().decl->llvmNested;
+    if (llvmNested == NULL) {
+        llvm::Value* nullcontext = llvm::ConstantPointerNull::get(pty);
+        p->ir->CreateStore(nullcontext, context);
+    }
+    else {
+        llvm::Value* nestedcontext = p->ir->CreateBitCast(llvmNested, pty, "tmp");
+        p->ir->CreateStore(nestedcontext, context);
+    }
+
+    llvm::Value* fptr = DtoGEPi(lval,0,1,"tmp",p->scopebb());
+
+    assert(fd->llvmValue);
+    llvm::Value* castfptr = new llvm::BitCastInst(fd->llvmValue,fptr->getType()->getContainedType(0),"tmp",p->scopebb());
+    new llvm::StoreInst(castfptr, fptr, p->scopebb());
+
+    return new DImValue(type, lval, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* ArrayLiteralExp::toElem(IRState* p)
+{
+    Logger::print("ArrayLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    const llvm::Type* t = DtoType(type);
+    Logger::cout() << "array literal has llvm type: " << *t << '\n';
+
+    llvm::Value* mem = 0;
+    if (!p->topexp() || p->topexp()->e2 != this) {
+        assert(DtoDType(type)->ty == Tsarray);
+        mem = new llvm::AllocaInst(t,"tmparrayliteral",p->topallocapoint());
+    }
+    else if (p->topexp()->e2 == this) {
+        DValue* tlv = p->topexp()->v;
+        if (DSliceValue* sv = tlv->isSlice()) {
+            assert(sv->len == 0);
+            mem = sv->ptr;
+        }
+        else {
+            mem = p->topexp()->v->getLVal();
+        }
+        assert(mem);
+        if (!llvm::isa<llvm::PointerType>(mem->getType()) ||
+            !llvm::isa<llvm::ArrayType>(mem->getType()->getContainedType(0)))
+        {
+            error("TODO array literals can currently only be used to initialise static arrays");
+            fatal();
+        }
+    }
+    else
+    assert(0);
+
+    for (unsigned i=0; i<elements->dim; ++i)
+    {
+        Expression* expr = (Expression*)elements->data[i];
+        llvm::Value* elemAddr = DtoGEPi(mem,0,i,"tmp",p->scopebb());
+        DValue* e = expr->toElem(p);
+        new llvm::StoreInst(e->getRVal(), elemAddr, p->scopebb());
+    }
+
+    return new DImValue(type, mem, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* ArrayLiteralExp::toConstElem(IRState* p)
+{
+    Logger::print("ArrayLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    const llvm::Type* t = DtoType(type);
+    Logger::cout() << "array literal has llvm type: " << *t << '\n';
+    assert(llvm::isa<llvm::ArrayType>(t));
+    const llvm::ArrayType* arrtype = llvm::cast<llvm::ArrayType>(t);
+
+    assert(arrtype->getNumElements() == elements->dim);
+    std::vector<llvm::Constant*> vals(elements->dim, NULL);
+    for (unsigned i=0; i<elements->dim; ++i)
+    {
+        Expression* expr = (Expression*)elements->data[i];
+        vals[i] = expr->toConstElem(p);
+    }
+
+    return llvm::ConstantArray::get(arrtype, vals);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* StructLiteralExp::toElem(IRState* p)
+{
+    Logger::print("StructLiteralExp::toElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    llvm::Value* sptr;
+    const llvm::Type* llt = DtoType(type);
+
+    llvm::Value* mem = 0;
+
+    // temporary struct literal
+    if (!p->topexp() || p->topexp()->e2 != this)
+    {
+        sptr = new llvm::AllocaInst(llt,"tmpstructliteral",p->topallocapoint());
+    }
+    // already has memory
+    else
+    {
+        assert(p->topexp()->e2 == this);
+        sptr = p->topexp()->v->getLVal();
+    }
+
+    // num elements in literal
+    unsigned n = elements->dim;
+
+    // unions might have different types for each literal
+    if (sd->llvmHasUnions) {
+        // build the type of the literal
+        std::vector<const llvm::Type*> tys;
+        for (unsigned i=0; i<n; ++i) {
+            Expression* vx = (Expression*)elements->data[i];
+            if (!vx) continue;
+            tys.push_back(DtoType(vx->type));
+        }
+        const llvm::StructType* t = llvm::StructType::get(tys);
+        if (t != llt) {
+            if (gTargetData->getTypeSize(t) != gTargetData->getTypeSize(llt)) { 
+                Logger::cout() << "got size " << gTargetData->getTypeSize(t) << ", expected " << gTargetData->getTypeSize(llt) << '\n';
+                assert(0 && "type size mismatch");
+            }
+            sptr = p->ir->CreateBitCast(sptr, llvm::PointerType::get(t), "tmp");
+            Logger::cout() << "sptr type is now: " << *t << '\n';
+        }
+    }
+
+    // build
+    unsigned j = 0;
+    for (unsigned i=0; i<n; ++i)
+    {
+        Expression* vx = (Expression*)elements->data[i];
+        if (!vx) continue;
+
+        Logger::cout() << "getting index " << j << " of " << *sptr << '\n';
+        llvm::Value* arrptr = DtoGEPi(sptr,0,j,"tmp",p->scopebb());
+        DValue* darrptr = new DVarValue(vx->type, arrptr, true);
+
+        p->exps.push_back(IRExp(NULL,vx,darrptr));
+        DValue* ve = vx->toElem(p);
+        p->exps.pop_back();
+
+        if (!ve->inPlace())
+            DtoAssign(darrptr, ve);
+
+        j++;
+    }
+
+    return new DImValue(type, sptr, true);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* StructLiteralExp::toConstElem(IRState* p)
+{
+    Logger::print("StructLiteralExp::toConstElem: %s | %s\n", toChars(), type->toChars());
+    LOG_SCOPE;
+
+    unsigned n = elements->dim;
+    std::vector<llvm::Constant*> vals(n, NULL);
+
+    for (unsigned i=0; i<n; ++i)
+    {
+        Expression* vx = (Expression*)elements->data[i];
+        vals[i] = vx->toConstElem(p);
+    }
+
+    assert(DtoDType(type)->ty == Tstruct);
+    const llvm::Type* t = DtoType(type);
+    const llvm::StructType* st = llvm::cast<llvm::StructType>(t);
+    return llvm::ConstantStruct::get(st,vals);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+#define STUB(x) DValue *x::toElem(IRState * p) {error("Exp type "#x" not implemented: %s", toChars()); fatal(); return 0; }
+//STUB(IdentityExp);
+//STUB(CondExp);
+//STUB(EqualExp);
+STUB(InExp);
+//STUB(CmpExp);
+//STUB(AndAndExp);
+//STUB(OrOrExp);
+//STUB(AndExp);
+//STUB(AndAssignExp);
+//STUB(OrExp);
+//STUB(OrAssignExp);
+//STUB(XorExp);
+//STUB(XorAssignExp);
+//STUB(ShrExp);
+//STUB(ShrAssignExp);
+//STUB(ShlExp);
+//STUB(ShlAssignExp);
+//STUB(UshrExp);
+//STUB(UshrAssignExp);
+//STUB(DivExp);
+//STUB(DivAssignExp);
+//STUB(MulExp);
+//STUB(MulAssignExp);
+//STUB(ModExp);
+//STUB(ModAssignExp);
+//STUB(CatExp);
+//STUB(CatAssignExp);
+//STUB(AddExp);
+//STUB(AddAssignExp);
+STUB(Expression);
+//STUB(MinExp);
+//STUB(MinAssignExp);
+//STUB(PostExp);
+//STUB(NullExp);
+//STUB(ThisExp);
+//STUB(CallExp);
+STUB(DotTypeExp);
+STUB(TypeDotIdExp);
+//STUB(DotVarExp);
+//STUB(AssertExp);
+//STUB(FuncExp);
+//STUB(DelegateExp);
+//STUB(VarExp);
+//STUB(DeclarationExp);
+//STUB(NewExp);
+//STUB(SymOffExp);
+STUB(ScopeExp);
+//STUB(AssignExp);
+
+STUB(TypeExp);
+//STUB(RealExp);
+STUB(ComplexExp);
+//STUB(StringExp);
+//STUB(IntegerExp);
+STUB(BoolExp);
+
+//STUB(NotExp);
+//STUB(ComExp);
+//STUB(NegExp);
+//STUB(PtrExp);
+//STUB(AddrExp);
+//STUB(SliceExp);
+//STUB(CastExp);
+//STUB(DeleteExp);
+//STUB(IndexExp);
+//STUB(CommaExp);
+//STUB(ArrayLengthExp);
+//STUB(HaltExp);
+STUB(RemoveExp);
+//STUB(ArrayLiteralExp);
+STUB(AssocArrayLiteralExp);
+//STUB(StructLiteralExp);
+
+#define CONSTSTUB(x) llvm::Constant* x::toConstElem(IRState * p) {error("const Exp type "#x" not implemented: '%s' type: '%s'", toChars(), type->toChars()); assert(0); fatal(); return NULL; }
+CONSTSTUB(Expression);
+//CONSTSTUB(IntegerExp);
+//CONSTSTUB(RealExp);
+//CONSTSTUB(NullExp);
+//CONSTSTUB(StringExp);
+//CONSTSTUB(VarExp);
+//CONSTSTUB(ArrayLiteralExp);
+CONSTSTUB(AssocArrayLiteralExp);
+//CONSTSTUB(StructLiteralExp);
+
+unsigned Type::totym() { return 0; }
+
+type * Type::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * Type::toCParamtype()
+{
+    assert(0);
+    return 0;
+}
+Symbol * Type::toSymbol()
+{
+    assert(0);
+    return 0;
+}
+
+type *
+TypeTypedef::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type *
+TypeTypedef::toCParamtype()
+{
+    assert(0);
+    return 0;
+}
+
+void
+TypedefDeclaration::toDebug()
+{
+    assert(0);
+}
+
+
+type *
+TypeEnum::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type *
+TypeStruct::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+void
+StructDeclaration::toDebug()
+{
+    assert(0);
+}
+
+Symbol * TypeClass::toSymbol()
+{
+    assert(0);
+    return 0;
+}
+
+unsigned TypeFunction::totym()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeFunction::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeSArray::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type *TypeSArray::toCParamtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeDArray::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeAArray::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypePointer::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeDelegate::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+type * TypeClass::toCtype()
+{
+    assert(0);
+    return 0;
+}
+
+void ClassDeclaration::toDebug()
+{
+    assert(0);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void
+EnumDeclaration::toDebug()
+{
+    assert(0);
+}
+
+int Dsymbol::cvMember(unsigned char*)
+{
+    assert(0);
+    return 0;
+}
+int EnumDeclaration::cvMember(unsigned char*)
+{
+    assert(0);
+    return 0;
+}
+int FuncDeclaration::cvMember(unsigned char*)
+{
+    assert(0);
+    return 0;
+}
+int VarDeclaration::cvMember(unsigned char*)
+{
+    assert(0);
+    return 0;
+}
+int TypedefDeclaration::cvMember(unsigned char*)
+{
+    assert(0);
+    return 0;
+}
+
+void obj_includelib(char*){}
+
+AsmStatement::AsmStatement(Loc loc, Token *tokens) :
+    Statement(loc)
+{
+    assert(0);
+}
+Statement *AsmStatement::syntaxCopy()
+{
+    assert(0);
+    return 0;
+}
+
+Statement *AsmStatement::semantic(Scope *sc)
+{
+    return Statement::semantic(sc);
+}
+
+
+void AsmStatement::toCBuffer(OutBuffer *buf, HdrGenState *hgs)
+{
+    Statement::toCBuffer(buf, hgs);
+}
+
+int AsmStatement::comeFrom()
+{
+    assert(0);
+    return FALSE;
+}
+
+void
+backend_init()
+{
+    // now lazily loaded
+    //LLVM_D_InitRuntime();
+}
+
+void
+backend_term()
+{
+    LLVM_D_FreeRuntime();
+}