view 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 source

// 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();
}