view gen/llvmhelpers.cpp @ 454:283d113d4753

Added generation of the llvm 'sret' parameter attribute where applicable. Fixed some wrong argument handling code when setting parameter attributes. Updated the tango unittest script in the tango patch, does not work yet, all modules don't compile...
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sat, 02 Aug 2008 02:54:57 +0200
parents 60332cd85308
children 45a67b6f1310
line wrap: on
line source

#include "gen/llvm.h"
#include "llvm/Target/TargetMachineRegistry.h"

#include "mars.h"
#include "init.h"
#include "id.h"
#include "expression.h"
#include "template.h"

#include "gen/tollvm.h"
#include "gen/llvmhelpers.h"
#include "gen/irstate.h"
#include "gen/runtime.h"
#include "gen/logger.h"
#include "gen/arrays.h"
#include "gen/dvalue.h"
#include "gen/complex.h"
#include "gen/classes.h"
#include "gen/functions.h"
#include "gen/typeinf.h"
#include "gen/todebug.h"

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// DYNAMIC MEMORY HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

LLValue* DtoNew(Type* newtype)
{
    // get runtime function
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_allocmemoryT");
    // get type info
    LLConstant* ti = DtoTypeInfoOf(newtype);
    assert(isaPointer(ti));
    // call runtime allocator
    LLValue* mem = gIR->CreateCallOrInvoke(fn, ti, ".gc_mem")->get();
    // cast
    return DtoBitCast(mem, getPtrToType(DtoType(newtype)), ".gc_mem");
}

void DtoDeleteMemory(LLValue* ptr)
{
    // get runtime function
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delmemory");
    // build args
    LLSmallVector<LLValue*,1> arg;
    arg.push_back(DtoBitCast(ptr, getVoidPtrType(), ".tmp"));
    // call
    gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end());
}

void DtoDeleteClass(LLValue* inst)
{
    // get runtime function
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delclass");
    // build args
    LLSmallVector<LLValue*,1> arg;
    arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp"));
    // call
    gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end());
}

void DtoDeleteInterface(LLValue* inst)
{
    // get runtime function
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delinterface");
    // build args
    LLSmallVector<LLValue*,1> arg;
    arg.push_back(DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp"));
    // call
    gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end());
}

void DtoDeleteArray(DValue* arr)
{
    // get runtime function
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_delarray");
    // build args
    LLSmallVector<LLValue*,2> arg;
    arg.push_back(DtoArrayLen(arr));
    arg.push_back(DtoBitCast(DtoArrayPtr(arr), getVoidPtrType(), ".tmp"));
    // call
    gIR->CreateCallOrInvoke(fn, arg.begin(), arg.end());
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// ASSERT HELPER
////////////////////////////////////////////////////////////////////////////////////////*/

void DtoAssert(Loc* loc, DValue* msg)
{
    std::vector<LLValue*> args;
    LLConstant* c;

    // func
    const char* fname = msg ? "_d_assert_msg" : "_d_assert";
    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);

    // param attrs
    llvm::PAListPtr palist;
    int idx = 1;

    // FIXME: every assert creates a global for the filename !!!
    c = DtoConstString(loc->filename);

    // msg param
    if (msg)
    {
        if (DSliceValue* s = msg->isSlice())
        {
            llvm::AllocaInst* alloc = gIR->func()->msgArg;
            if (!alloc)
            {
                alloc = new llvm::AllocaInst(c->getType(), ".assertmsg", gIR->topallocapoint());
                DtoSetArray(alloc, DtoArrayLen(s), DtoArrayPtr(s));
                gIR->func()->msgArg = alloc;
            }
            args.push_back(alloc);
        }
        else
        {
            args.push_back(msg->getRVal());
        }
        palist = palist.addAttr(idx++, llvm::ParamAttr::ByVal);
    }

    // file param
    llvm::AllocaInst* alloc = gIR->func()->srcfileArg;
    if (!alloc)
    {
        alloc = new llvm::AllocaInst(c->getType(), ".srcfile", gIR->topallocapoint());
        gIR->func()->srcfileArg = alloc;
    }
    LLValue* ptr = DtoGEPi(alloc, 0,0, "tmp");
    DtoStore(c->getOperand(0), ptr);
    ptr = DtoGEPi(alloc, 0,1, "tmp");
    DtoStore(c->getOperand(1), ptr);

    args.push_back(alloc);
    palist = palist.addAttr(idx++, llvm::ParamAttr::ByVal);


    // line param
    c = DtoConstUint(loc->linnum);
    args.push_back(c);

    // call
    CallOrInvoke* call = gIR->CreateCallOrInvoke(fn, args.begin(), args.end());
    call->setParamAttrs(palist);

    // after assert is always unreachable
    gIR->ir->CreateUnreachable();
}


/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// LABEL HELPER
////////////////////////////////////////////////////////////////////////////////////////*/
LabelStatement* DtoLabelStatement(Identifier* ident)
{
    FuncDeclaration* fd = gIR->func()->decl;
    FuncDeclaration::LabelMap::iterator iter = fd->labmap.find(ident->toChars());
    if (iter == fd->labmap.end())
    {
        if (fd->returnLabel && fd->returnLabel->ident->equals(ident))
        {
            assert(fd->returnLabel->statement);
            return fd->returnLabel->statement;
        }
        return NULL;
    }
    return iter->second;
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// GOTO HELPER
////////////////////////////////////////////////////////////////////////////////////////*/
void DtoGoto(Loc* loc, Identifier* target, EnclosingHandler* enclosinghandler, TryFinallyStatement* sourcetf)
{
    assert(!gIR->scopereturned());

    LabelStatement* lblstmt = DtoLabelStatement(target);
    if(!lblstmt) {
        error(*loc, "the label %s does not exist", target->toChars());
        fatal();
    }

    // if the target label is inside inline asm, error
    if(lblstmt->asmLabel) {
        error(*loc, "cannot goto to label %s inside an inline asm block", target->toChars());
        fatal();
    }

    // find target basic block
    std::string labelname = gIR->func()->getScopedLabelName(target->toChars());
    llvm::BasicBlock*& targetBB = gIR->func()->labelToBB[labelname];
    if (targetBB == NULL)
        targetBB = llvm::BasicBlock::Create("label", gIR->topfunc());

    // find finallys between goto and label
    EnclosingHandler* endfinally = enclosinghandler;
    while(endfinally != NULL && endfinally != lblstmt->enclosinghandler) {
        endfinally = endfinally->getEnclosing();
    }

    // error if didn't find tf statement of label
    if(endfinally != lblstmt->enclosinghandler)
        error(*loc, "cannot goto into try block");

    // goto into finally blocks is forbidden by the spec
    // though it should not be problematic to implement
    if(lblstmt->tf != sourcetf) {
        error(*loc, "spec disallows goto into finally block");
        fatal();
    }

    // emit code for finallys between goto and label
    DtoEnclosingHandlers(enclosinghandler, endfinally);

    llvm::BranchInst::Create(targetBB, gIR->scopebb());
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// TRY-FINALLY, VOLATILE AND SYNCHRONIZED HELPER
////////////////////////////////////////////////////////////////////////////////////////*/

void EnclosingSynchro::emitCode(IRState * p)
{
    if (s->exp)
        DtoLeaveMonitor(s->llsync);
    else
        DtoLeaveCritical(s->llsync);
}

EnclosingHandler* EnclosingSynchro::getEnclosing()
{
    return s->enclosinghandler;
}

////////////////////////////////////////////////////////////////////////////////////////

void EnclosingVolatile::emitCode(IRState * p)
{
    // store-load barrier
    DtoMemoryBarrier(false, false, true, false);
}

EnclosingHandler* EnclosingVolatile::getEnclosing()
{
    return v->enclosinghandler;
}

////////////////////////////////////////////////////////////////////////////////////////

void EnclosingTryFinally::emitCode(IRState * p)
{
    assert(tf->finalbody);
    tf->finalbody->toIR(p);
}

EnclosingHandler* EnclosingTryFinally::getEnclosing()
{
    return tf->enclosinghandler;
}

////////////////////////////////////////////////////////////////////////////////////////

void DtoEnclosingHandlers(EnclosingHandler* start, EnclosingHandler* end)
{
    // verify that end encloses start
    EnclosingHandler* endfinally = start;
    while(endfinally != NULL && endfinally != end) {
        endfinally = endfinally->getEnclosing();
    }
    assert(endfinally == end);


    //
    // emit code for finallys between start and end
    //

    // since the labelstatements possibly inside are private
    // and might already exist push a label scope
    gIR->func()->pushUniqueLabelScope("enclosing");
    EnclosingHandler* tf = start;
    while(tf != end) {
        tf->emitCode(gIR);
        tf = tf->getEnclosing();
    }
    gIR->func()->popLabelScope();
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// SYNCHRONIZED SECTION HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

void DtoEnterCritical(LLValue* g)
{
    LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_criticalenter");
    gIR->CreateCallOrInvoke(fn, g);
}

void DtoLeaveCritical(LLValue* g)
{
    LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_criticalexit");
    gIR->CreateCallOrInvoke(fn, g);
}

void DtoEnterMonitor(LLValue* v)
{
    LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_monitorenter");
    v = DtoBitCast(v, fn->getFunctionType()->getParamType(0));
    gIR->CreateCallOrInvoke(fn, v);
}

void DtoLeaveMonitor(LLValue* v)
{
    LLFunction* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_monitorexit");
    v = DtoBitCast(v, fn->getFunctionType()->getParamType(0));
    gIR->CreateCallOrInvoke(fn, v);
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// NESTED VARIABLE HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

static const LLType* get_next_frame_ptr_type(Dsymbol* sc)
{
    assert(sc->isFuncDeclaration() || sc->isClassDeclaration());
    Dsymbol* p = sc->toParent2();
    if (!p->isFuncDeclaration() && !p->isClassDeclaration())
        Logger::println("unexpected parent symbol found while resolving frame pointer - '%s' kind: '%s'", p->toChars(), p->kind());
    assert(p->isFuncDeclaration() || p->isClassDeclaration());
    if (FuncDeclaration* fd = p->isFuncDeclaration())
    {
        LLValue* v = fd->ir.irFunc->nestedVar;
        assert(v);
        return v->getType();
    }
    else if (ClassDeclaration* cd = p->isClassDeclaration())
    {
        return DtoType(cd->type);
    }
    else
    {
        Logger::println("symbol: '%s' kind: '%s'", sc->toChars(), sc->kind());
        assert(0);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

static LLValue* get_frame_ptr_impl(FuncDeclaration* func, Dsymbol* sc, LLValue* v)
{
    LOG_SCOPE;
    if (sc == func)
    {
        return v;
    }
    else if (FuncDeclaration* fd = sc->isFuncDeclaration())
    {
        Logger::println("scope is function: %s", fd->toChars());

        if (fd->toParent2() == func)
        {
            if (!func->ir.irFunc->nestedVar)
                return NULL;
            return DtoBitCast(v, func->ir.irFunc->nestedVar->getType());
        }

        v = DtoBitCast(v, get_next_frame_ptr_type(fd));
        Logger::cout() << "v = " << *v << '\n';

        if (fd->toParent2()->isFuncDeclaration())
        {
            v = DtoGEPi(v, 0,0, "tmp");
            v = DtoLoad(v);
        }
        else if (ClassDeclaration* cd = fd->toParent2()->isClassDeclaration())
        {
            v = DtoGEPi(v,0,2+cd->vthis->ir.irField->index,"tmp");
            v = DtoLoad(v);
        }
        else
        {
            assert(0);
        }
        return get_frame_ptr_impl(func, fd->toParent2(), v);
    }
    else if (ClassDeclaration* cd = sc->isClassDeclaration())
    {
        Logger::println("scope is class: %s", cd->toChars());
        return get_frame_ptr_impl(func, cd->toParent2(), v);
    }
    else
    {
        Logger::println("symbol: '%s'", sc->toPrettyChars());
        assert(0);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

static LLValue* get_frame_ptr(FuncDeclaration* func)
{
    Logger::println("Resolving context pointer for nested function: '%s'", func->toPrettyChars());
    LOG_SCOPE;
    IrFunction* irfunc = gIR->func();

    // in the right scope already
    if (func == irfunc->decl)
        return irfunc->decl->ir.irFunc->nestedVar;

    // use the 'this' pointer
    LLValue* ptr = irfunc->decl->ir.irFunc->thisVar;
    assert(ptr);

    // return the fully resolved frame pointer
    ptr = get_frame_ptr_impl(func, irfunc->decl, ptr);
    if (ptr) Logger::cout() << "Found context!" << *ptr;
    else Logger::cout() << "NULL context!\n";

    return ptr;
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoNestedContext(FuncDeclaration* func)
{
    // resolve frame ptr
    LLValue* ptr = get_frame_ptr(func);
    Logger::cout() << "Nested context ptr = ";
    if (ptr) Logger::cout() << *ptr;
    else Logger::cout() << "NULL";
    Logger::cout() << '\n';
    return ptr;
}

//////////////////////////////////////////////////////////////////////////////////////////

static void print_frame_worker(VarDeclaration* vd, Dsymbol* par)
{
    if (vd->toParent2() == par)
    {
        Logger::println("found: '%s' kind: '%s'", par->toChars(), par->kind());
        return;
    }

    Logger::println("diving into: '%s' kind: '%s'", par->toChars(), par->kind());
    LOG_SCOPE;
    print_frame_worker(vd, par->toParent2());
}

//////////////////////////////////////////////////////////////////////////////////////////

static void print_nested_frame_list(VarDeclaration* vd, Dsymbol* par)
{
    Logger::println("Frame pointer list for nested var: '%s'", vd->toPrettyChars());
    LOG_SCOPE;
    if (vd->toParent2() != par)
        print_frame_worker(vd, par);
    else
        Logger::println("Found at level 0");
    Logger::println("Done");
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoNestedVariable(VarDeclaration* vd)
{
    // log the frame list
    IrFunction* irfunc = gIR->func();
    if (Logger::enabled())
        print_nested_frame_list(vd, irfunc->decl);

    // resolve frame ptr
    FuncDeclaration* func = vd->toParent2()->isFuncDeclaration();
    assert(func);
    LLValue* ptr = DtoNestedContext(func);
    assert(ptr && "nested var, but no context");

    // if there is no nestedVar the context itself is what we're after
    if (!func->ir.irFunc->nestedVar)
    {
        return ptr;
    }

    // handle a "normal" nested variable

    // we must cast here to be sure. nested classes just have a void*
    ptr = DtoBitCast(ptr, func->ir.irFunc->nestedVar->getType());

    // index nested var and load (if necessary)
    LLValue* v = DtoGEPi(ptr, 0, vd->ir.irLocal->nestedIndex, "tmp");
    // references must be loaded, for normal variables this IS already the variable storage!!!
    if (vd->isParameter() && (vd->isRef() || vd->isOut() || DtoIsPassedByRef(vd->type)))
        v = DtoLoad(v);

    // log and return
    Logger::cout() << "Nested var ptr = " << *v << '\n';
    return v;
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
// ASSIGNMENT HELPER (store this in that)
////////////////////////////////////////////////////////////////////////////////////////*/

void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
{
    Logger::cout() << "DtoAssign(...);\n";
    LOG_SCOPE;

    Type* t = DtoDType(lhs->getType());
    Type* t2 = DtoDType(rhs->getType());

    if (t->ty == Tstruct) {
        if (!t->equals(t2)) {
            // TODO: fix this, use 'rhs' for something
            DtoAggrZeroInit(lhs->getLVal());
        }
        else if (!rhs->inPlace()) {
            DtoAggrCopy(lhs->getLVal(), rhs->getRVal());
        }
    }
    else if (t->ty == Tarray) {
        // lhs is slice
        if (DSliceValue* s = lhs->isSlice()) {
            if (DSliceValue* s2 = rhs->isSlice()) {
                DtoArrayCopySlices(s, s2);
            }
            else if (t->next->toBasetype()->equals(t2)) {
                DtoArrayInit(loc, s, rhs);
            }
            else {
                DtoArrayCopyToSlice(s, rhs);
            }
        }
        // rhs is slice
        else if (DSliceValue* s = rhs->isSlice()) {
            assert(s->getType()->toBasetype() == lhs->getType()->toBasetype());
            DtoSetArray(lhs->getLVal(),DtoArrayLen(s),DtoArrayPtr(s));
        }
        // null
        else if (rhs->isNull()) {
            DtoSetArrayToNull(lhs->getLVal());
        }
        // reference assignment
        else {
            DtoArrayAssign(lhs->getLVal(), rhs->getRVal());
        }
    }
    else if (t->ty == Tsarray) {
        if (DtoType(lhs->getType()) == DtoType(rhs->getType())) {
            DtoStaticArrayCopy(lhs->getLVal(), rhs->getRVal());
        }
        else {
            DtoArrayInit(loc, lhs, rhs);
        }
    }
    else if (t->ty == Tdelegate) {
        if (rhs->isNull())
            DtoAggrZeroInit(lhs->getLVal());
        else if (!rhs->inPlace()) {
            LLValue* l = lhs->getLVal();
            LLValue* r = rhs->getRVal();
            Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
            DtoAggrCopy(l, r);
        }
    }
    else if (t->ty == Tclass) {
        assert(t2->ty == Tclass);
        // assignment to this in constructor special case
        if (lhs->isThis()) {
            LLValue* tmp = rhs->getRVal();
            FuncDeclaration* fdecl = gIR->func()->decl;
            // respecify the this param
            if (!llvm::isa<llvm::AllocaInst>(fdecl->ir.irFunc->thisVar))
                fdecl->ir.irFunc->thisVar = new llvm::AllocaInst(tmp->getType(), "newthis", gIR->topallocapoint());
            DtoStore(tmp, fdecl->ir.irFunc->thisVar);
        }
        // regular class ref -> class ref assignment
        else {
            DtoStore(rhs->getRVal(), lhs->getLVal());
        }
    }
    else if (t->iscomplex()) {
        assert(!lhs->isComplex());

        LLValue* dst;
        if (DLRValue* lr = lhs->isLRValue()) {
            dst = lr->getLVal();
            rhs = DtoCastComplex(loc, rhs, lr->getLType());
        }
        else {
            dst = lhs->getRVal();
        }

        if (DComplexValue* cx = rhs->isComplex())
            DtoComplexSet(dst, cx->re, cx->im);
        else
            DtoComplexAssign(dst, rhs->getRVal());
    }
    else {
        LLValue* l = lhs->getLVal();
        LLValue* r = rhs->getRVal();
        Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
        const LLType* lit = l->getType()->getContainedType(0);
        if (r->getType() != lit) {
            // handle lvalue cast assignments
            if (DLRValue* lr = lhs->isLRValue()) {
                Logger::println("lvalue cast!");
                r = DtoCast(loc, rhs, lr->getLType())->getRVal();
            }
            else {
                r = DtoCast(loc, rhs, lhs->getType())->getRVal();
            }
            Logger::cout() << "really assign\nlhs: " << *l << "rhs: " << *r << '\n';
            assert(r->getType() == l->getType()->getContainedType(0));
        }
        gIR->ir->CreateStore(r, l);
    }
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      NULL VALUE HELPER
////////////////////////////////////////////////////////////////////////////////////////*/

DValue* DtoNullValue(Type* type)
{
    Type* basetype = type->toBasetype();
    TY basety = basetype->ty;
    const LLType* lltype = DtoType(basetype);

    // complex, needs to be first since complex are also floating
    if (basetype->iscomplex())
    {
        const LLType* basefp = DtoComplexBaseType(basetype);
        return new DComplexValue(type, LLConstant::getNullValue(basefp), LLConstant::getNullValue(basefp));
    }
    // integer, floating, pointer and class have no special representation
    else if (basetype->isintegral() || basetype->isfloating() || basety == Tpointer || basety == Tclass)
    {
        return new DConstValue(type, LLConstant::getNullValue(lltype));
    }
    // dynamic array
    else if (basety == Tarray)
    {
        LLValue* len = DtoConstSize_t(0);
        LLValue* ptr = getNullPtr(getPtrToType(DtoType(basetype->next)));
        return new DSliceValue(type, len, ptr);
    }
    // delegate
    else if (basety == Tdelegate)
    {
        return new DNullValue(type, LLConstant::getNullValue(lltype));
    }

    // unknown
    std::cout << "unsupported: null value for " << type->toChars() << '\n';
    assert(0);
    return 0;

}


/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      CASTING HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

DValue* DtoCastInt(Loc& loc, DValue* val, Type* _to)
{
    const LLType* tolltype = DtoType(_to);

    Type* to = DtoDType(_to);
    Type* from = DtoDType(val->getType());
    assert(from->isintegral());

    size_t fromsz = from->size();
    size_t tosz = to->size();

    LLValue* rval = val->getRVal();
    if (rval->getType() == tolltype) {
        return new DImValue(_to, rval);
    }

    if (to->isintegral()) {
        if (fromsz < tosz) {
            Logger::cout() << "cast to: " << *tolltype << '\n';
            if (from->isunsigned() || from->ty == Tbool) {
                rval = new llvm::ZExtInst(rval, tolltype, "tmp", gIR->scopebb());
            } else {
                rval = new llvm::SExtInst(rval, tolltype, "tmp", gIR->scopebb());
            }
        }
        else if (fromsz > tosz) {
            rval = new llvm::TruncInst(rval, tolltype, "tmp", gIR->scopebb());
        }
        else {
            rval = DtoBitCast(rval, tolltype);
        }
    }
    else if (to->iscomplex()) {
        return DtoComplex(loc, to, val);
    }
    else if (to->isfloating()) {
        if (from->isunsigned()) {
            rval = new llvm::UIToFPInst(rval, tolltype, "tmp", gIR->scopebb());
        }
        else {
            rval = new llvm::SIToFPInst(rval, tolltype, "tmp", gIR->scopebb());
        }
    }
    else if (to->ty == Tpointer) {
        Logger::cout() << "cast pointer: " << *tolltype << '\n';
        rval = gIR->ir->CreateIntToPtr(rval, tolltype, "tmp");
    }
    else {
        error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), _to->toChars());
        fatal();
    }

    return new DImValue(_to, rval);
}

DValue* DtoCastPtr(Loc& loc, DValue* val, Type* to)
{
    const LLType* tolltype = DtoType(to);

    Type* totype = DtoDType(to);
    Type* fromtype = DtoDType(val->getType());
    assert(fromtype->ty == Tpointer || fromtype->ty == Tfunction);

    LLValue* rval;

    if (totype->ty == Tpointer || totype->ty == Tclass) {
        LLValue* src = val->getRVal();
        Logger::cout() << "src: " << *src << "to type: " << *tolltype << '\n';
        rval = DtoBitCast(src, tolltype);
    }
    else if (totype->isintegral()) {
        rval = new llvm::PtrToIntInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
    }
    else {
        error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
        fatal();
    }

    return new DImValue(to, rval);
}

DValue* DtoCastFloat(Loc& loc, DValue* val, Type* to)
{
    if (val->getType() == to)
        return val;

    const LLType* tolltype = DtoType(to);

    Type* totype = DtoDType(to);
    Type* fromtype = DtoDType(val->getType());
    assert(fromtype->isfloating());

    size_t fromsz = fromtype->size();
    size_t tosz = totype->size();

    LLValue* rval;

    if (totype->iscomplex()) {
        return DtoComplex(loc, to, val);
    }
    else if (totype->isfloating()) {
        if (fromsz == tosz) {
            rval = val->getRVal();
            assert(rval->getType() == tolltype);
        }
        else if (fromsz < tosz) {
            rval = new llvm::FPExtInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
        }
        else if (fromsz > tosz) {
            rval = new llvm::FPTruncInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
        }
        else {
            error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
            fatal();
        }
    }
    else if (totype->isintegral()) {
        if (totype->isunsigned()) {
            rval = new llvm::FPToUIInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
        }
        else {
            rval = new llvm::FPToSIInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
        }
    }
    else {
        error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
        fatal();
    }

    return new DImValue(to, rval);
}

DValue* DtoCastDelegate(Loc& loc, DValue* val, Type* to)
{
    LLValue* res = 0;
    to = to->toBasetype();

    if (to->ty == Tdelegate)
    {
        const LLType* toll = getPtrToType(DtoType(to));
        res = DtoBitCast(val->getRVal(), toll);
    }
    else
    {
        error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
        fatal();
    }

    return new DImValue(to, res);
}

DValue* DtoCast(Loc& loc, DValue* val, Type* to)
{
    Type* fromtype = DtoDType(val->getType());
    Logger::println("Casting from '%s' to '%s'", fromtype->toChars(), to->toChars());
    if (fromtype->isintegral()) {
        return DtoCastInt(loc, val, to);
    }
    else if (fromtype->iscomplex()) {
        return DtoCastComplex(loc, val, to);
    }
    else if (fromtype->isfloating()) {
        return DtoCastFloat(loc, val, to);
    }
    else if (fromtype->ty == Tclass) {
        return DtoCastClass(val, to);
    }
    else if (fromtype->ty == Tarray || fromtype->ty == Tsarray) {
        return DtoCastArray(loc, val, to);
    }
    else if (fromtype->ty == Tpointer || fromtype->ty == Tfunction) {
        return DtoCastPtr(loc, val, to);
    }
    else if (fromtype->ty == Tdelegate) {
        return DtoCastDelegate(loc, val, to);
    }
    else {
        error(loc, "invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
        fatal();
    }
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      TEMPLATE HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

bool DtoIsTemplateInstance(Dsymbol* s)
{
    if (!s) return false;
    if (s->isTemplateInstance() && !s->isTemplateMixin())
        return true;
    else if (s->parent)
        return DtoIsTemplateInstance(s->parent);
    return false;
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      LAZY STATIC INIT HELPER
////////////////////////////////////////////////////////////////////////////////////////*/

void DtoLazyStaticInit(bool istempl, LLValue* gvar, Initializer* init, Type* t)
{
    // create a flag to make sure initialization only happens once
    llvm::GlobalValue::LinkageTypes gflaglink = istempl ? llvm::GlobalValue::WeakLinkage : llvm::GlobalValue::InternalLinkage;
    std::string gflagname(gvar->getName());
    gflagname.append("__initflag");
    llvm::GlobalVariable* gflag = new llvm::GlobalVariable(LLType::Int1Ty,false,gflaglink,DtoConstBool(false),gflagname,gIR->module);

    // check flag and do init if not already done
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* initbb = llvm::BasicBlock::Create("ifnotinit",gIR->topfunc(),oldend);
    llvm::BasicBlock* endinitbb = llvm::BasicBlock::Create("ifnotinitend",gIR->topfunc(),oldend);
    LLValue* cond = gIR->ir->CreateICmpEQ(gIR->ir->CreateLoad(gflag,"tmp"),DtoConstBool(false));
    gIR->ir->CreateCondBr(cond, initbb, endinitbb);
    gIR->scope() = IRScope(initbb,endinitbb);
    DValue* ie = DtoInitializer(init);
    if (!ie->inPlace()) {
        DValue* dst = new DVarValue(t, gvar, true);
        DtoAssign(init->loc, dst, ie);
    }
    gIR->ir->CreateStore(DtoConstBool(true), gflag);
    gIR->ir->CreateBr(endinitbb);
    gIR->scope() = IRScope(endinitbb,oldend);
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      PROCESSING QUEUE HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

void DtoResolveDsymbol(Dsymbol* dsym)
{
    if (StructDeclaration* sd = dsym->isStructDeclaration()) {
        DtoResolveStruct(sd);
    }
    else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
        DtoResolveClass(cd);
    }
    else if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
        DtoResolveFunction(fd);
    }
    else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) {
        DtoResolveTypeInfo(fd);
    }
    else {
    error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
    assert(0 && "unsupported dsymbol for DtoResolveDsymbol");
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoDeclareDsymbol(Dsymbol* dsym)
{
    if (StructDeclaration* sd = dsym->isStructDeclaration()) {
        DtoDeclareStruct(sd);
    }
    else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
        DtoDeclareClass(cd);
    }
    else if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
        DtoDeclareFunction(fd);
    }
    else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) {
        DtoDeclareTypeInfo(fd);
    }
    else {
    error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
    assert(0 && "unsupported dsymbol for DtoDeclareDsymbol");
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoConstInitDsymbol(Dsymbol* dsym)
{
    if (StructDeclaration* sd = dsym->isStructDeclaration()) {
        DtoConstInitStruct(sd);
    }
    else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
        DtoConstInitClass(cd);
    }
    else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) {
        DtoConstInitTypeInfo(fd);
    }
    else if (VarDeclaration* vd = dsym->isVarDeclaration()) {
        DtoConstInitGlobal(vd);
    }
    else {
    error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
    assert(0 && "unsupported dsymbol for DtoConstInitDsymbol");
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoDefineDsymbol(Dsymbol* dsym)
{
    if (StructDeclaration* sd = dsym->isStructDeclaration()) {
        DtoDefineStruct(sd);
    }
    else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
        DtoDefineClass(cd);
    }
    else if (FuncDeclaration* fd = dsym->isFuncDeclaration()) {
        DtoDefineFunc(fd);
    }
    else if (TypeInfoDeclaration* fd = dsym->isTypeInfoDeclaration()) {
        DtoDefineTypeInfo(fd);
    }
    else {
    error(dsym->loc, "unsupported dsymbol: %s", dsym->toChars());
    assert(0 && "unsupported dsymbol for DtoDefineDsymbol");
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoConstInitGlobal(VarDeclaration* vd)
{
    if (vd->ir.initialized) return;
    vd->ir.initialized = gIR->dmodule;

    Logger::println("* DtoConstInitGlobal(%s)", vd->toChars());
    LOG_SCOPE;

    bool emitRTstaticInit = false;

    LLConstant* _init = 0;
    if (vd->parent && vd->parent->isFuncDeclaration() && vd->init && vd->init->isExpInitializer()) {
        _init = DtoConstInitializer(vd->type, NULL);
        emitRTstaticInit = true;
    }
    else {
        _init = DtoConstInitializer(vd->type, vd->init);
    }

    const LLType* _type = DtoType(vd->type);
    Type* t = DtoDType(vd->type);

    //Logger::cout() << "initializer: " << *_init << '\n';
    if (_type != _init->getType()) {
        Logger::cout() << "got type '" << *_init->getType() << "' expected '" << *_type << "'\n";
        // zero initalizer
        if (_init->isNullValue())
            _init = llvm::Constant::getNullValue(_type);
        // pointer to global constant (struct.init)
        else if (llvm::isa<llvm::GlobalVariable>(_init))
        {
            assert(_init->getType()->getContainedType(0) == _type);
            llvm::GlobalVariable* gv = llvm::cast<llvm::GlobalVariable>(_init);
            assert(t->ty == Tstruct);
            TypeStruct* ts = (TypeStruct*)t;
            assert(ts->sym->ir.irStruct->constInit);
            _init = ts->sym->ir.irStruct->constInit;
        }
        // array single value init
        else if (isaArray(_type))
        {
            _init = DtoConstStaticArray(_type, _init);
        }
        else {
            Logger::cout() << "Unexpected initializer type: " << *_type << '\n';
            //assert(0);
        }
    }

    bool istempl = false;
    if ((vd->storage_class & STCcomdat) || (vd->parent && DtoIsTemplateInstance(vd->parent))) {
        istempl = true;
    }

    if (_init && _init->getType() != _type)
        _type = _init->getType();
    llvm::cast<LLOpaqueType>(vd->ir.irGlobal->type.get())->refineAbstractTypeTo(_type);
    _type = vd->ir.irGlobal->type.get();
    //_type->dump();
    assert(!_type->isAbstract());

    llvm::GlobalVariable* gvar = llvm::cast<llvm::GlobalVariable>(vd->ir.irGlobal->value);
    if (!(vd->storage_class & STCextern) && (vd->getModule() == gIR->dmodule || istempl))
    {
        gvar->setInitializer(_init);
        // do debug info
        if (global.params.symdebug)
        {
            LLGlobalVariable* gv = DtoDwarfGlobalVariable(gvar, vd);
            // keep a reference so GDCE doesn't delete it !
            gIR->usedArray.push_back(llvm::ConstantExpr::getBitCast(gv, getVoidPtrType()));
        }
    }

    if (emitRTstaticInit)
        DtoLazyStaticInit(istempl, gvar, vd->init, t);
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoEmptyResolveList()
{
    //Logger::println("DtoEmptyResolveList()");
    Dsymbol* dsym;
    while (!gIR->resolveList.empty()) {
        dsym = gIR->resolveList.front();
        gIR->resolveList.pop_front();
        DtoResolveDsymbol(dsym);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoEmptyDeclareList()
{
    //Logger::println("DtoEmptyDeclareList()");
    Dsymbol* dsym;
    while (!gIR->declareList.empty()) {
        dsym = gIR->declareList.front();
        gIR->declareList.pop_front();
        DtoDeclareDsymbol(dsym);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoEmptyConstInitList()
{
    //Logger::println("DtoEmptyConstInitList()");
    Dsymbol* dsym;
    while (!gIR->constInitList.empty()) {
        dsym = gIR->constInitList.front();
        gIR->constInitList.pop_front();
        DtoConstInitDsymbol(dsym);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoEmptyDefineList()
{
    //Logger::println("DtoEmptyDefineList()");
    Dsymbol* dsym;
    while (!gIR->defineList.empty()) {
        dsym = gIR->defineList.front();
        gIR->defineList.pop_front();
        DtoDefineDsymbol(dsym);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////
void DtoEmptyAllLists()
{
    for(;;)
    {
        Dsymbol* dsym;
        if (!gIR->resolveList.empty()) {
            dsym = gIR->resolveList.front();
            gIR->resolveList.pop_front();
            DtoResolveDsymbol(dsym);
        }
        else if (!gIR->declareList.empty()) {
            dsym = gIR->declareList.front();
            gIR->declareList.pop_front();
            DtoDeclareDsymbol(dsym);
        }
        else if (!gIR->constInitList.empty()) {
            dsym = gIR->constInitList.front();
            gIR->constInitList.pop_front();
            DtoConstInitDsymbol(dsym);
        }
        else if (!gIR->defineList.empty()) {
            dsym = gIR->defineList.front();
            gIR->defineList.pop_front();
            DtoDefineDsymbol(dsym);
        }
        else {
            break;
        }
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoForceDeclareDsymbol(Dsymbol* dsym)
{
    if (dsym->ir.declared) return;
    Logger::println("DtoForceDeclareDsymbol(%s)", dsym->toPrettyChars());
    LOG_SCOPE;
    DtoResolveDsymbol(dsym);

    DtoEmptyResolveList();

    DtoDeclareDsymbol(dsym);
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoForceConstInitDsymbol(Dsymbol* dsym)
{
    if (dsym->ir.initialized) return;
    Logger::println("DtoForceConstInitDsymbol(%s)", dsym->toPrettyChars());
    LOG_SCOPE;
    DtoResolveDsymbol(dsym);

    DtoEmptyResolveList();
    DtoEmptyDeclareList();

    DtoConstInitDsymbol(dsym);
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoForceDefineDsymbol(Dsymbol* dsym)
{
    if (dsym->ir.defined) return;
    Logger::println("DtoForceDefineDsymbol(%s)", dsym->toPrettyChars());
    LOG_SCOPE;
    DtoResolveDsymbol(dsym);

    DtoEmptyResolveList();
    DtoEmptyDeclareList();
    DtoEmptyConstInitList();

    DtoDefineDsymbol(dsym);
}

/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      DECLARATION EXP HELPER
////////////////////////////////////////////////////////////////////////////////////////*/
DValue* DtoDeclarationExp(Dsymbol* declaration)
{
    Logger::print("DtoDeclarationExp: %s\n", declaration->toChars());
    LOG_SCOPE;

    // variable declaration
    if (VarDeclaration* vd = declaration->isVarDeclaration())
    {
        Logger::println("VarDeclaration");

        // static
        if (vd->isDataseg())
        {
            vd->toObjFile(0); // TODO: multiobj
        }
        else
        {
            if (global.params.llvmAnnotate)
                DtoAnnotation(declaration->toChars());

            Logger::println("vdtype = %s", vd->type->toChars());

            // referenced by nested delegate?
            if (vd->nestedref) {
                Logger::println("has nestedref set");
                assert(vd->ir.irLocal);
                vd->ir.irLocal->value = gIR->func()->decl->ir.irFunc->nestedVar;
                assert(vd->ir.irLocal->value);
                assert(vd->ir.irLocal->nestedIndex >= 0);
            }
            // normal stack variable, allocate storage on the stack if it has not already been done
            else if(!vd->ir.irLocal) {
                const LLType* lltype = DtoType(vd->type);

                llvm::Value* allocainst;
                if(gTargetData->getTypeSizeInBits(lltype) == 0) 
                    allocainst = llvm::ConstantPointerNull::get(getPtrToType(lltype));
                else
                    allocainst = new llvm::AllocaInst(lltype, vd->toChars(), gIR->topallocapoint());

                //allocainst->setAlignment(vd->type->alignsize()); // TODO
                vd->ir.irLocal = new IrLocal(vd);
                vd->ir.irLocal->value = allocainst;

                if (global.params.symdebug)
                {
                    DtoDwarfLocalVariable(allocainst, vd);
                }
            }

            Logger::cout() << "llvm value for decl: " << *vd->ir.irLocal->value << '\n';
            DValue* ie = DtoInitializer(vd->init);
        }

        return new DVarValue(vd->type, vd, vd->ir.getIrValue(), true);
    }
    // struct declaration
    else if (StructDeclaration* s = declaration->isStructDeclaration())
    {
        Logger::println("StructDeclaration");
        DtoForceConstInitDsymbol(s);
    }
    // function declaration
    else if (FuncDeclaration* f = declaration->isFuncDeclaration())
    {
        Logger::println("FuncDeclaration");
        DtoForceDeclareDsymbol(f);
    }
    // alias declaration
    else if (AliasDeclaration* a = declaration->isAliasDeclaration())
    {
        Logger::println("AliasDeclaration - no work");
        // do nothing
    }
    // enum
    else if (EnumDeclaration* e = declaration->isEnumDeclaration())
    {
        Logger::println("EnumDeclaration - no work");
        // do nothing
    }
    // class
    else if (ClassDeclaration* e = declaration->isClassDeclaration())
    {
        Logger::println("ClassDeclaration");
        DtoForceConstInitDsymbol(e);
    }
    // typedef
    else if (TypedefDeclaration* tdef = declaration->isTypedefDeclaration())
    {
        Logger::println("TypedefDeclaration");
        DtoTypeInfoOf(tdef->type, false);
    }
    // attribute declaration
    else if (AttribDeclaration* a = declaration->isAttribDeclaration())
    {
        Logger::println("AttribDeclaration");
        for (int i=0; i < a->decl->dim; ++i)
        {
            DtoForceDeclareDsymbol((Dsymbol*)a->decl->data[i]);
        }
    }
    // mixin declaration
    else if (TemplateMixin* m = declaration->isTemplateMixin())
    {
        Logger::println("TemplateMixin");
        for (int i=0; i < m->members->dim; ++i)
        {
            Dsymbol* mdsym = (Dsymbol*)m->members->data[i];
            DtoDeclarationExp(mdsym);
        }
    }
    // unsupported declaration
    else
    {
        error(declaration->loc, "Unimplemented Declaration type for DeclarationExp. kind: %s", declaration->kind());
        assert(0);
    }
    return NULL;
}


/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////
//      INITIALIZER HELPERS
////////////////////////////////////////////////////////////////////////////////////////*/

LLConstant* DtoConstInitializer(Type* type, Initializer* init)
{
    LLConstant* _init = 0; // may return zero
    if (!init)
    {
        Logger::println("const default initializer for %s", type->toChars());

        if(type->ty == Tsarray)
        {
            Logger::println("type is a static array, building constant array initializer");
            TypeSArray* arrtype = (TypeSArray*)type;
            Type* elemtype = type->next;

            integer_t arraydim;
            arraydim = arrtype->dim->toInteger();

            std::vector<LLConstant*> inits(arraydim, elemtype->defaultInit()->toConstElem(gIR));
            const LLArrayType* arrty = LLArrayType::get(DtoType(elemtype),arraydim);
            _init = LLConstantArray::get(arrty, inits);
        }
        else
            _init = type->defaultInit()->toConstElem(gIR);
    }
    else if (ExpInitializer* ex = init->isExpInitializer())
    {
        Logger::println("const expression initializer");
        _init = ex->exp->toConstElem(gIR);
    }
    else if (StructInitializer* si = init->isStructInitializer())
    {
        Logger::println("const struct initializer");
        _init = DtoConstStructInitializer(si);
    }
    else if (ArrayInitializer* ai = init->isArrayInitializer())
    {
        Logger::println("const array initializer");
        _init = DtoConstArrayInitializer(ai);
    }
    else if (init->isVoidInitializer())
    {
        Logger::println("const void initializer");
        const LLType* ty = DtoType(type);
        _init = llvm::Constant::getNullValue(ty);
    }
    else {
        Logger::println("unsupported const initializer: %s", init->toChars());
    }
    return _init;
}

//////////////////////////////////////////////////////////////////////////////////////////

LLConstant* DtoConstFieldInitializer(Type* t, Initializer* init)
{
    Logger::println("DtoConstFieldInitializer");
    LOG_SCOPE;

    const LLType* _type = DtoType(t);

    LLConstant* _init = DtoConstInitializer(t, init);
    assert(_init);
    if (_type != _init->getType())
    {
        Logger::cout() << "field init is: " << *_init << " type should be " << *_type << '\n';
        if (t->ty == Tsarray)
        {
            const LLArrayType* arrty = isaArray(_type);
            uint64_t n = arrty->getNumElements();
            std::vector<LLConstant*> vals(n,_init);
            _init = llvm::ConstantArray::get(arrty, vals);
        }
        else if (t->ty == Tarray)
        {
            assert(isaStruct(_type));
            _init = llvm::ConstantAggregateZero::get(_type);
        }
        else if (t->ty == Tstruct)
        {
            const LLStructType* structty = isaStruct(_type);
            TypeStruct* ts = (TypeStruct*)t;
            assert(ts);
            assert(ts->sym);
            assert(ts->sym->ir.irStruct->constInit);
            _init = ts->sym->ir.irStruct->constInit;
        }
        else if (t->ty == Tclass)
        {
            _init = llvm::Constant::getNullValue(_type);
        }
        else {
            Logger::println("failed for type %s", t->toChars());
            assert(0);
        }
    }

    return _init;
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoInitializer(Initializer* init)
{
    if (!init)
        return 0;
    else if (ExpInitializer* ex = init->isExpInitializer())
    {
        Logger::println("expression initializer");
        assert(ex->exp);
        return ex->exp->toElem(gIR);
    }
    else if (init->isVoidInitializer())
    {
        // do nothing
    }
    else {
        Logger::println("unsupported initializer: %s", init->toChars());
        assert(0);
    }
    return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////

void DtoAnnotation(const char* str)
{
    std::string s("CODE: ");
    s.append(str);
    char* p = &s[0];
    while (*p)
    {
        if (*p == '"')
            *p = '\'';
        ++p;
    }
    // create a noop with the code as the result name!
    gIR->ir->CreateAnd(DtoConstSize_t(0),DtoConstSize_t(0),s.c_str());
}

//////////////////////////////////////////////////////////////////////////////////////////

LLConstant* DtoTypeInfoOf(Type* type, bool base)
{
    type = type->merge(); // needed.. getTypeInfo does the same
    type->getTypeInfo(NULL);
    TypeInfoDeclaration* tidecl = type->vtinfo;
    assert(tidecl);
    DtoForceDeclareDsymbol(tidecl);
    assert(tidecl->ir.irGlobal != NULL);
    LLConstant* c = isaConstant(tidecl->ir.irGlobal->value);
    assert(c != NULL);
    if (base)
        return llvm::ConstantExpr::getBitCast(c, DtoType(Type::typeinfo->type));
    return c;
}

//////////////////////////////////////////////////////////////////////////////////////////

void findDefaultTarget()
{
    std::string err_str;
    const llvm::TargetMachineRegistry::entry* e = llvm::TargetMachineRegistry::getClosestTargetForJIT(err_str);
    if (e == 0)
    {
        error("Failed to find a default target machine: %s", err_str.c_str());
        fatal();
    }
    else
    {
        global.params.llvmArch = const_cast<char*>(e->Name);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoBoolean(Loc& loc, DValue* dval)
{
    Type* dtype = dval->getType()->toBasetype();
    TY ty = dtype->ty;

    // integer
    if (dtype->isintegral())
    {
        LLValue* val = dval->getRVal();
        if (val->getType() == LLType::Int1Ty)
            return val;
        else {
            LLValue* zero = LLConstantInt::get(val->getType(), 0, false);
            return gIR->ir->CreateICmpNE(val, zero, "tmp");
        }
    }
    // complex
    else if (dtype->iscomplex())
    {
        return DtoComplexEquals(loc, TOKnotequal, dval, DtoNullValue(dtype));
    }
    // floating point
    else if (dtype->isfloating())
    {
        LLValue* val = dval->getRVal();
        LLValue* zero = LLConstant::getNullValue(val->getType());
        return gIR->ir->CreateFCmpONE(val, zero, "tmp");
    }
    // pointer/class
    else if (ty == Tpointer || ty == Tclass) {
        LLValue* val = dval->getRVal();
        LLValue* zero = LLConstant::getNullValue(val->getType());
        return gIR->ir->CreateICmpNE(val, zero, "tmp");
    }
    // dynamic array
    else if (ty == Tarray)
    {
        // return (arr.length != 0)
        return gIR->ir->CreateICmpNE(DtoArrayLen(dval), DtoConstSize_t(0), "tmp");
    }
    // delegate
    else if (ty == Tdelegate)
    {
        // return (dg !is null)
        return DtoDelegateEquals(TOKnotequal, dval->getRVal(), NULL);
    }
    // unknown
    std::cout << "unsupported -> bool : " << dtype->toChars() << '\n';
    assert(0);
    return 0;
}