view gen/statements.cpp @ 1650:40bd4a0d4870

Update to work with LLVM 2.7. Removed use of dyn_cast, llvm no compiles without exceptions and rtti by default. We do need exceptions for the libconfig stuff, but rtti isn't necessary (anymore). Debug info needs to be rewritten, as in LLVM 2.7 the format has completely changed. To have something to look at while rewriting, the old code has been wrapped inside #ifndef DISABLE_DEBUG_INFO , this means that you have to define this to compile at the moment. Updated tango 0.99.9 patch to include updated EH runtime code, which is needed for LLVM 2.7 as well.
author Tomas Lindquist Olsen
date Wed, 19 May 2010 12:42:32 +0200
parents 638a823ace45
children
line wrap: on
line source

// Statements: D -> LLVM glue

#include <stdio.h>
#include <math.h>
#include <fstream>

#include "gen/llvm.h"
#include "llvm/InlineAsm.h"
#include "llvm/Support/CFG.h"

#include "mars.h"
#include "init.h"
#include "mtype.h"
#include "hdrgen.h"
#include "port.h"
#include "module.h"

#include "gen/irstate.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/llvmhelpers.h"
#include "gen/runtime.h"
#include "gen/arrays.h"
#include "gen/todebug.h"
#include "gen/dvalue.h"
#include "gen/abi.h"

#include "ir/irfunction.h"
#include "ir/irmodule.h"
#include "ir/irlandingpad.h"

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

void CompoundStatement::toIR(IRState* p)
{
    Logger::println("CompoundStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    for (int i=0; i<statements->dim; i++)
    {
        Statement* s = (Statement*)statements->data[i];
        if (s) {
            s->toIR(p);
        }
    }
}


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

void ReturnStatement::toIR(IRState* p)
{
    Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // is there a return value expression?
    if (exp || (!exp && (p->topfunc() == p->mainFunc)) )
    {
        // if the functions return type is void this means that
        // we are returning through a pointer argument
        if (p->topfunc()->getReturnType() == LLType::getVoidTy(gIR->context()))
        {
            // sanity check
            IrFunction* f = p->func();
            assert(f->decl->ir.irFunc->retArg);

            // FIXME: is there ever a case where a sret return needs to be rewritten for the ABI?

            // get return pointer
            DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg);
            DValue* e = exp->toElem(p);
            // store return value
            DtoAssign(loc, rvar, e);

            // emit scopes
            DtoEnclosingHandlers(loc, NULL);

            #ifndef DISABLE_DEBUG_INFO
            // emit dbg end function
            if (global.params.symdebug) DtoDwarfFuncEnd(f->decl);
            #endif

            // emit ret
            llvm::ReturnInst::Create(gIR->context(), p->scopebb());

        }
        // the return type is not void, so this is a normal "register" return
        else
        {
            LLValue* v;
            if (!exp && (p->topfunc() == p->mainFunc))
                v = LLConstant::getNullValue(p->mainFunc->getReturnType());
            else
                // do abi specific transformations on the return value
                v = p->func()->type->fty.putRet(exp->type, exp->toElem(p));

            if (Logger::enabled())
                Logger::cout() << "return value is '" <<*v << "'\n";

            IrFunction* f = p->func();
            // Hack around LDC assuming structs are in memory:
            // If the function returns a struct, and the return value is a
            // pointer to a struct, load from it before returning.
            if (f->type->next->ty == Tstruct && isaPointer(v->getType())) {
                Logger::println("Loading struct type for return");
                v = DtoLoad(v);
            }

            // can happen for classes and void main
            if (v->getType() != p->topfunc()->getReturnType())
            {
                // for the main function this only happens if it is declared as void
                // and then contains a return (exp); statement. Since the actual
                // return type remains i32, we just throw away the exp value
                // and return 0 instead
                // if we're not in main, just bitcast
                if (p->topfunc() == p->mainFunc)
                    v = LLConstant::getNullValue(p->mainFunc->getReturnType());
                else
                    v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp");

                if (Logger::enabled())
                    Logger::cout() << "return value after cast: " << *v << '\n';
            }

            DtoEnclosingHandlers(loc, NULL);

            #ifndef DISABLE_DEBUG_INFO
            if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
            #endif
            llvm::ReturnInst::Create(gIR->context(), v, p->scopebb());
        }
    }
    // no return value expression means it's a void function
    else
    {
        assert(p->topfunc()->getReturnType() == LLType::getVoidTy(gIR->context()));
        DtoEnclosingHandlers(loc, NULL);

        #ifndef DISABLE_DEBUG_INFO
        if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl);
        #endif
        llvm::ReturnInst::Create(gIR->context(), p->scopebb());
    }

    // the return terminated this basicblock, start a new one
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "afterreturn", p->topfunc(), oldend);
    p->scope() = IRScope(bb,oldend);
}

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

void ExpStatement::toIR(IRState* p)
{
    Logger::println("ExpStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    if (exp) {
        if (global.params.llvmAnnotate)
            DtoAnnotation(exp->toChars());
        elem* e;
        // a cast(void) around the expression is allowed, but doesn't require any code
        if(exp->op == TOKcast && exp->type == Type::tvoid) {
            CastExp* cexp = (CastExp*)exp;
            e = cexp->e1->toElem(p);
        }
        else
            e = exp->toElem(p);
        delete e;
    }
    /*elem* e = exp->toElem(p);
    p->buf.printf("%s", e->toChars());
    delete e;
    p->buf.writenl();*/
}

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

void IfStatement::toIR(IRState* p)
{
    Logger::println("IfStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    if (match)
        DtoRawVarDeclaration(match);

    DValue* cond_e = condition->toElem(p);
    LLValue* cond_val = cond_e->getRVal();

    llvm::BasicBlock* oldend = gIR->scopeend();

    llvm::BasicBlock* ifbb = llvm::BasicBlock::Create(gIR->context(), "if", gIR->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endif", gIR->topfunc(), oldend);
    llvm::BasicBlock* elsebb = elsebody ? llvm::BasicBlock::Create(gIR->context(), "else", gIR->topfunc(), endbb) : endbb;

    if (cond_val->getType() != LLType::getInt1Ty(gIR->context())) {
        if (Logger::enabled())
            Logger::cout() << "if conditional: " << *cond_val << '\n';
        cond_val = DtoCast(loc, cond_e, Type::tbool)->getRVal();
    }
    LLValue* ifgoback = llvm::BranchInst::Create(ifbb, elsebb, cond_val, gIR->scopebb());

    // replace current scope
    gIR->scope() = IRScope(ifbb,elsebb);

    // do scoped statements
    if (ifbody)
        ifbody->toIR(p);
    if (!gIR->scopereturned()) {
        llvm::BranchInst::Create(endbb,gIR->scopebb());
    }

    if (elsebody) {
        //assert(0);
        gIR->scope() = IRScope(elsebb,endbb);
        elsebody->toIR(p);
        if (!gIR->scopereturned()) {
            llvm::BranchInst::Create(endbb,gIR->scopebb());
        }
    }

    // rewrite the scope
    gIR->scope() = IRScope(endbb,oldend);
}

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

void ScopeStatement::toIR(IRState* p)
{
    Logger::println("ScopeStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    /*llvm::BasicBlock* oldend = p->scopeend();

    llvm::BasicBlock* beginbb = 0;

    // remove useless branches by clearing and reusing the current basicblock
    llvm::BasicBlock* bb = p->scopebb();
    if (bb->empty()) {
        beginbb = bb;
    }
    else {
        beginbb = llvm::BasicBlock::Create(gIR->context(), "scope", p->topfunc(), oldend);
        if (!p->scopereturned())
            llvm::BranchInst::Create(beginbb, bb);
    }

    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endscope", p->topfunc(), oldend);
    if (beginbb != bb)
        p->scope() = IRScope(beginbb, endbb);
    else
        p->scope().end = endbb;*/

    if (statement)
        statement->toIR(p);

    /*p->scope().end = oldend;
    Logger::println("Erasing scope endbb");
    endbb->eraseFromParent();*/
}

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

void WhileStatement::toIR(IRState* p)
{
    Logger::println("WhileStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // create while blocks
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* whilebb = llvm::BasicBlock::Create(gIR->context(), "whilecond", gIR->topfunc(), oldend);
    llvm::BasicBlock* whilebodybb = llvm::BasicBlock::Create(gIR->context(), "whilebody", gIR->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endwhile", gIR->topfunc(), oldend);

    // move into the while block
    p->ir->CreateBr(whilebb);
    //llvm::BranchInst::Create(whilebb, gIR->scopebb());

    // replace current scope
    gIR->scope() = IRScope(whilebb,endbb);

    // create the condition
    DValue* cond_e = condition->toElem(p);
    LLValue* cond_val = DtoCast(loc, cond_e, Type::tbool)->getRVal();
    delete cond_e;

    // conditional branch
    LLValue* ifbreak = llvm::BranchInst::Create(whilebodybb, endbb, cond_val, p->scopebb());

    // rewrite scope
    gIR->scope() = IRScope(whilebodybb,endbb);

    // while body code
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,whilebb,endbb));
    if (body)
        body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    // loop
    if (!gIR->scopereturned())
        llvm::BranchInst::Create(whilebb, gIR->scopebb());

    // rewrite the scope
    gIR->scope() = IRScope(endbb,oldend);
}

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

void DoStatement::toIR(IRState* p)
{
    Logger::println("DoStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // create while blocks
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* dowhilebb = llvm::BasicBlock::Create(gIR->context(), "dowhile", gIR->topfunc(), oldend);
    llvm::BasicBlock* condbb = llvm::BasicBlock::Create(gIR->context(), "dowhilecond", gIR->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "enddowhile", gIR->topfunc(), oldend);

    // move into the while block
    assert(!gIR->scopereturned());
    llvm::BranchInst::Create(dowhilebb, gIR->scopebb());

    // replace current scope
    gIR->scope() = IRScope(dowhilebb,condbb);

    // do-while body code
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,condbb,endbb));
    if (body)
        body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    // branch to condition block
    llvm::BranchInst::Create(condbb, gIR->scopebb());
    gIR->scope() = IRScope(condbb,endbb);

    // create the condition
    DValue* cond_e = condition->toElem(p);
    LLValue* cond_val = DtoCast(loc, cond_e, Type::tbool)->getRVal();
    delete cond_e;

    // conditional branch
    LLValue* ifbreak = llvm::BranchInst::Create(dowhilebb, endbb, cond_val, gIR->scopebb());

    // rewrite the scope
    gIR->scope() = IRScope(endbb,oldend);
}

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

void ForStatement::toIR(IRState* p)
{
    Logger::println("ForStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // create for blocks
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* forbb = llvm::BasicBlock::Create(gIR->context(), "forcond", gIR->topfunc(), oldend);
    llvm::BasicBlock* forbodybb = llvm::BasicBlock::Create(gIR->context(), "forbody", gIR->topfunc(), oldend);
    llvm::BasicBlock* forincbb = llvm::BasicBlock::Create(gIR->context(), "forinc", gIR->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endfor", gIR->topfunc(), oldend);

    // init
    if (init != 0)
    init->toIR(p);

    // move into the for condition block, ie. start the loop
    assert(!gIR->scopereturned());
    llvm::BranchInst::Create(forbb, gIR->scopebb());

    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,forincbb,endbb));

    // replace current scope
    gIR->scope() = IRScope(forbb,forbodybb);

    // create the condition
    LLValue* cond_val;
    if (condition)
    {
        DValue* cond_e = condition->toElem(p);
        cond_val = DtoCast(loc, cond_e, Type::tbool)->getRVal();
        delete cond_e;
    }
    else
    {
        cond_val = DtoConstBool(true);
    }

    // conditional branch
    assert(!gIR->scopereturned());
    llvm::BranchInst::Create(forbodybb, endbb, cond_val, gIR->scopebb());

    // rewrite scope
    gIR->scope() = IRScope(forbodybb,forincbb);

    // do for body code
    if (body)
        body->toIR(p);

    // move into the for increment block
    if (!gIR->scopereturned())
        llvm::BranchInst::Create(forincbb, gIR->scopebb());
    gIR->scope() = IRScope(forincbb, endbb);

    // increment
    if (increment) {
        DValue* inc = increment->toElem(p);
        delete inc;
    }

    // loop
    if (!gIR->scopereturned())
        llvm::BranchInst::Create(forbb, gIR->scopebb());

    p->func()->gen->targetScopes.pop_back();

    // rewrite the scope
    gIR->scope() = IRScope(endbb,oldend);
}

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

void BreakStatement::toIR(IRState* p)
{
    Logger::println("BreakStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    // don't emit two terminators in a row
    // happens just before DMD generated default statements if the last case terminates
    if (p->scopereturned())
        return;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    if (ident != 0) {
        Logger::println("ident = %s", ident->toChars());

        DtoEnclosingHandlers(loc, target);

        // get the loop statement the label refers to
        Statement* targetLoopStatement = target->statement;
        ScopeStatement* tmp;
        while(tmp = targetLoopStatement->isScopeStatement())
            targetLoopStatement = tmp->statement;

        // find the right break block and jump there
        bool found = false;
        FuncGen::TargetScopeVec::reverse_iterator it = p->func()->gen->targetScopes.rbegin();
        FuncGen::TargetScopeVec::reverse_iterator it_end = p->func()->gen->targetScopes.rend();
        while(it != it_end) {
            if(it->s == targetLoopStatement) {
                llvm::BranchInst::Create(it->breakTarget, p->scopebb());
                found = true;
                break;
            }
            ++it;
        }
        assert(found);
    }
    else {
        // find closest scope with a break target
        FuncGen::TargetScopeVec::reverse_iterator it = p->func()->gen->targetScopes.rbegin();
        FuncGen::TargetScopeVec::reverse_iterator it_end = p->func()->gen->targetScopes.rend();
        while(it != it_end) {
            if(it->breakTarget) {
                break;
            }
            ++it;
        }
        DtoEnclosingHandlers(loc, it->s);
        llvm::BranchInst::Create(it->breakTarget, gIR->scopebb());
    }

    // the break terminated this basicblock, start a new one
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "afterbreak", p->topfunc(), oldend);
    p->scope() = IRScope(bb,oldend);
}

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

void ContinueStatement::toIR(IRState* p)
{
    Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    if (ident != 0) {
        Logger::println("ident = %s", ident->toChars());

        DtoEnclosingHandlers(loc, target);

        // get the loop statement the label refers to
        Statement* targetLoopStatement = target->statement;
        ScopeStatement* tmp;
        while(tmp = targetLoopStatement->isScopeStatement())
            targetLoopStatement = tmp->statement;

        // find the right continue block and jump there
        bool found = false;
        FuncGen::TargetScopeVec::reverse_iterator it = p->func()->gen->targetScopes.rbegin();
        FuncGen::TargetScopeVec::reverse_iterator it_end = p->func()->gen->targetScopes.rend();
        while(it != it_end) {
            if(it->s == targetLoopStatement) {
                llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
                found = true;
                break;
            }
            ++it;
        }
        assert(found);
    }
    else {
        // find closest scope with a continue target
        FuncGen::TargetScopeVec::reverse_iterator it = p->func()->gen->targetScopes.rbegin();
        FuncGen::TargetScopeVec::reverse_iterator it_end = p->func()->gen->targetScopes.rend();
        while(it != it_end) {
            if(it->continueTarget) {
                break;
            }
            ++it;
        }
        DtoEnclosingHandlers(loc, it->s);
        llvm::BranchInst::Create(it->continueTarget, gIR->scopebb());
    }

    // the continue terminated this basicblock, start a new one
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftercontinue", p->topfunc(), oldend);
    p->scope() = IRScope(bb,oldend);
}

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

void OnScopeStatement::toIR(IRState* p)
{
    Logger::println("OnScopeStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    assert(statement);
    //statement->toIR(p); // this seems to be redundant
}

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

void TryFinallyStatement::toIR(IRState* p)
{
    Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // if there's no finalbody or no body, things are simple
    if (!finalbody) {
        if (body)
            body->toIR(p);
        return;
    }
    if (!body) {
        finalbody->toIR(p);
        return;
    }

    // create basic blocks
    llvm::BasicBlock* oldend = p->scopeend();

    llvm::BasicBlock* trybb = llvm::BasicBlock::Create(gIR->context(), "try", p->topfunc(), oldend);
    llvm::BasicBlock* finallybb = llvm::BasicBlock::Create(gIR->context(), "finally", p->topfunc(), oldend);
    // the landing pad for statements in the try block
    llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(gIR->context(), "landingpad", p->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endtryfinally", p->topfunc(), oldend);

    // pass the previous BB into this
    assert(!gIR->scopereturned());
    llvm::BranchInst::Create(trybb, p->scopebb());

    //
    // set up the landing pad
    //
    p->scope() = IRScope(landingpadbb, endbb);

    assert(finalbody);
    IRLandingPad& pad = gIR->func()->gen->landingPadInfo;
    pad.addFinally(finalbody);
    pad.push(landingpadbb);
    gIR->func()->gen->targetScopes.push_back(IRTargetScope(this,new EnclosingTryFinally(this,gIR->func()->gen->landingPad),NULL,NULL));
    gIR->func()->gen->landingPad = pad.get();

    //
    // do the try block
    //
    p->scope() = IRScope(trybb,finallybb);

    assert(body);
    body->toIR(p);

    // terminate try BB
    if (!p->scopereturned())
        llvm::BranchInst::Create(finallybb, p->scopebb());

    pad.pop();
    gIR->func()->gen->landingPad = pad.get();
    gIR->func()->gen->targetScopes.pop_back();

    //
    // do finally block
    //
    p->scope() = IRScope(finallybb,landingpadbb);
    finalbody->toIR(p);

    // terminate finally
    //TODO: isn't it an error to have a 'returned' finally block?
    if (!gIR->scopereturned()) {
        llvm::BranchInst::Create(endbb, p->scopebb());
    }

    // rewrite the scope
    p->scope() = IRScope(endbb,oldend);
}

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

void TryCatchStatement::toIR(IRState* p)
{
    Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // create basic blocks
    llvm::BasicBlock* oldend = p->scopeend();

    llvm::BasicBlock* trybb = llvm::BasicBlock::Create(gIR->context(), "try", p->topfunc(), oldend);
    // the landing pad will be responsible for branching to the correct catch block
    llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create(gIR->context(), "landingpad", p->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "endtrycatch", p->topfunc(), oldend);

    // pass the previous BB into this
    assert(!gIR->scopereturned());
    llvm::BranchInst::Create(trybb, p->scopebb());

    //
    // do catches and the landing pad
    //
    assert(catches);
    gIR->scope() = IRScope(landingpadbb, endbb);

    IRLandingPad& pad = gIR->func()->gen->landingPadInfo;
    for (int i = 0; i < catches->dim; i++)
    {
        Catch *c = (Catch *)catches->data[i];
        pad.addCatch(c, endbb);
    }

    pad.push(landingpadbb);
    gIR->func()->gen->landingPad = pad.get();

    //
    // do the try block
    //
    p->scope() = IRScope(trybb,landingpadbb);

    assert(body);
    body->toIR(p);

    if (!gIR->scopereturned())
        llvm::BranchInst::Create(endbb, p->scopebb());

    pad.pop();
    gIR->func()->gen->landingPad = pad.get();

    // rewrite the scope
    p->scope() = IRScope(endbb,oldend);
}

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

void ThrowStatement::toIR(IRState* p)
{
    Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    assert(exp);
    DValue* e = exp->toElem(p);

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug) DtoDwarfFuncEnd(gIR->func()->decl);
    #endif

    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_throw_exception");
    //Logger::cout() << "calling: " << *fn << '\n';
    LLValue* arg = DtoBitCast(e->getRVal(), fn->getFunctionType()->getParamType(0));
    //Logger::cout() << "arg: " << *arg << '\n';
    gIR->CreateCallOrInvoke(fn, arg);
    gIR->ir->CreateUnreachable();

    // need a block after the throw for now
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "afterthrow", p->topfunc(), oldend);
    p->scope() = IRScope(bb,oldend);
}

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

// used to build the sorted list of cases
struct Case : Object
{
    StringExp* str;
    size_t index;

    Case(StringExp* s, size_t i) {
        str = s;
        index = i;
    }

    int compare(Object *obj) {
        Case* c2 = (Case*)obj;
        return str->compare(c2->str);
    }
};

static LLValue* call_string_switch_runtime(llvm::Value* table, Expression* e)
{
    Type* dt = e->type->toBasetype();
    Type* dtnext = dt->nextOf()->toBasetype();
    TY ty = dtnext->ty;
    const char* fname;
    if (ty == Tchar) {
        fname = "_d_switch_string";
    }
    else if (ty == Twchar) {
        fname = "_d_switch_ustring";
    }
    else if (ty == Tdchar) {
        fname = "_d_switch_dstring";
    }
    else {
        assert(0 && "not char/wchar/dchar");
    }

    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname);

    if (Logger::enabled())
    {
        Logger::cout() << *table->getType() << '\n';
        Logger::cout() << *fn->getFunctionType()->getParamType(0) << '\n';
    }
    assert(table->getType() == fn->getFunctionType()->getParamType(0));

    DValue* val = e->toElem(gIR);
    LLValue* llval = val->getRVal();
    assert(llval->getType() == fn->getFunctionType()->getParamType(1));

    LLCallSite call = gIR->CreateCallOrInvoke2(fn, table, llval, "tmp");

    return call.getInstruction();
}

void SwitchStatement::toIR(IRState* p)
{
    Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    llvm::BasicBlock* oldend = gIR->scopeend();

    // clear data from previous passes... :/
    for (int i=0; i<cases->dim; ++i)
    {
        CaseStatement* cs = (CaseStatement*)cases->data[i];
        cs->bodyBB = NULL;
        cs->llvmIdx = NULL;
    }

    // string switch?
    llvm::Value* switchTable = 0;
    Array caseArray;
    if (!condition->type->isintegral())
    {
        Logger::println("is string switch");
        // build array of the stringexpS
        caseArray.reserve(cases->dim);
        for (int i=0; i<cases->dim; ++i)
        {
            CaseStatement* cs = (CaseStatement*)cases->data[i];

            assert(cs->exp->op == TOKstring);
            caseArray.push(new Case((StringExp*)cs->exp, i));
        }
        // first sort it
        caseArray.sort();
        // iterate and add indices to cases
        std::vector<LLConstant*> inits(caseArray.dim);
        for (size_t i=0; i<caseArray.dim; ++i)
        {
            Case* c = (Case*)caseArray.data[i];
            CaseStatement* cs = (CaseStatement*)cases->data[c->index];
            cs->llvmIdx = DtoConstUint(i);
            inits[i] = c->str->toConstElem(p);
        }
        // build static array for ptr or final array
        const LLType* elemTy = DtoType(condition->type);
        const llvm::ArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size());
        LLConstant* arrInit = LLConstantArray::get(arrTy, inits);
        llvm::GlobalVariable* arr = new llvm::GlobalVariable(*gIR->module, arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, ".string_switch_table_data");

        const LLType* elemPtrTy = getPtrToType(elemTy);
        LLConstant* arrPtr = llvm::ConstantExpr::getBitCast(arr, elemPtrTy);

        // build the static table
        std::vector<const LLType*> types;
        types.push_back(DtoSize_t());
        types.push_back(elemPtrTy);
        const llvm::StructType* sTy = llvm::StructType::get(gIR->context(), types);
        std::vector<LLConstant*> sinits;
        sinits.push_back(DtoConstSize_t(inits.size()));
        sinits.push_back(arrPtr);
        switchTable = llvm::ConstantStruct::get(sTy, sinits);
    }

    // body block
    llvm::BasicBlock* bodybb = llvm::BasicBlock::Create(gIR->context(), "switchbody", p->topfunc(), oldend);

    // default
    llvm::BasicBlock* defbb = 0;
    if (sdefault) {
        Logger::println("has default");
        defbb = llvm::BasicBlock::Create(gIR->context(), "default", p->topfunc(), oldend);
        sdefault->bodyBB = defbb;
    }

    // end (break point)
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "switchend", p->topfunc(), oldend);

    // condition var
    LLValue* condVal;
    // integral switch
    if (condition->type->isintegral()) {
        DValue* cond = condition->toElem(p);
        condVal = cond->getRVal();
    }
    // string switch
    else {
        condVal = call_string_switch_runtime(switchTable, condition);
    }
    llvm::SwitchInst* si = llvm::SwitchInst::Create(condVal, defbb ? defbb : endbb, cases->dim, p->scopebb());

    // do switch body
    assert(body);

    p->scope() = IRScope(bodybb, endbb);
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,NULL,endbb));
    body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    if (!p->scopereturned())
        llvm::BranchInst::Create(endbb, p->scopebb());

    // add the cases
    for (int i=0; i<cases->dim; ++i)
    {
        CaseStatement* cs = (CaseStatement*)cases->data[i];
        si->addCase(cs->llvmIdx, cs->bodyBB);
    }

    gIR->scope() = IRScope(endbb,oldend);
}

//////////////////////////////////////////////////////////////////////////////
void CaseStatement::toIR(IRState* p)
{
    Logger::println("CaseStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    llvm::BasicBlock* nbb = llvm::BasicBlock::Create(gIR->context(), "case", p->topfunc(), p->scopeend());

    if (bodyBB && !bodyBB->getTerminator())
    {
        llvm::BranchInst::Create(nbb, bodyBB);
    }
    bodyBB = nbb;

    if (llvmIdx == NULL) {
        LLConstant* c = exp->toConstElem(p);
        llvmIdx = isaConstantInt(c);
    }

    if (!p->scopereturned())
        llvm::BranchInst::Create(bodyBB, p->scopebb());

    p->scope() = IRScope(bodyBB, p->scopeend());

    assert(statement);
    statement->toIR(p);
}

//////////////////////////////////////////////////////////////////////////////
void DefaultStatement::toIR(IRState* p)
{
    Logger::println("DefaultStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    assert(bodyBB);

    llvm::BasicBlock* nbb = llvm::BasicBlock::Create(gIR->context(), "default", p->topfunc(), p->scopeend());

    if (!bodyBB->getTerminator())
    {
        llvm::BranchInst::Create(nbb, bodyBB);
    }
    bodyBB = nbb;

    if (!p->scopereturned())
        llvm::BranchInst::Create(bodyBB, p->scopebb());

    p->scope() = IRScope(bodyBB, p->scopeend());

    assert(statement);
    statement->toIR(p);
}

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

void UnrolledLoopStatement::toIR(IRState* p)
{
    Logger::println("UnrolledLoopStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    // if no statements, there's nothing to do
    if (!statements || !statements->dim)
        return;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // DMD doesn't fold stuff like continue/break, and since this isn't really a loop
    // we have to keep track of each statement and jump to the next/end on continue/break

    llvm::BasicBlock* oldend = gIR->scopeend();

    // create a block for each statement
    size_t nstmt = statements->dim;
    LLSmallVector<llvm::BasicBlock*, 4> blocks(nstmt, NULL);

    for (size_t i=0; i<nstmt; i++)
    {
        blocks[i] = llvm::BasicBlock::Create(gIR->context(), "unrolledstmt", p->topfunc(), oldend);
    }

    // create end block
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "unrolledend", p->topfunc(), oldend);

    // enter first stmt
    if (!p->scopereturned())
        p->ir->CreateBr(blocks[0]);

    // do statements
    Statement** stmts = (Statement**)statements->data;

    for (int i=0; i<nstmt; i++)
    {
        Statement* s = stmts[i];

        // get blocks
        llvm::BasicBlock* thisbb = blocks[i];
        llvm::BasicBlock* nextbb = (i+1 == nstmt) ? endbb : blocks[i+1];

        // update scope
        p->scope() = IRScope(thisbb,nextbb);

        // push loop scope
        // continue goes to next statement, break goes to end
        p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));

        // do statement
        s->toIR(p);

        // pop loop scope
        p->func()->gen->targetScopes.pop_back();

        // next stmt
        if (!p->scopereturned())
            p->ir->CreateBr(nextbb);
    }

    // finish scope
    if (!p->scopereturned())
        p->ir->CreateBr(endbb);
    p->scope() = IRScope(endbb,oldend);
}

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

void ForeachStatement::toIR(IRState* p)
{
    Logger::println("ForeachStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    //assert(arguments->dim == 1);
    assert(value != 0);
    assert(aggr != 0);
    assert(func != 0);

    //Argument* arg = (Argument*)arguments->data[0];
    //Logger::println("Argument is %s", arg->toChars());

    Logger::println("aggr = %s", aggr->toChars());

    // key
    const LLType* keytype = key ? DtoType(key->type) : DtoSize_t();
    LLValue* keyvar;
    if (key)
        keyvar = DtoRawVarDeclaration(key);
    else
        keyvar = DtoRawAlloca(keytype, 0, "foreachkey"); // FIXME: align?
    LLValue* zerokey = LLConstantInt::get(keytype,0,false);

    // value
    Logger::println("value = %s", value->toPrettyChars());
    LLValue* valvar = NULL;
    if (!value->isRef() && !value->isOut()) {
        // Create a local variable to serve as the value.
        DtoRawVarDeclaration(value);
        valvar = value->ir.irLocal->value;
    }

    // what to iterate
    DValue* aggrval = aggr->toElem(p);
    Type* aggrtype = aggr->type->toBasetype();

    // get length and pointer
    LLValue* niters = DtoArrayLen(aggrval);
    LLValue* val = DtoArrayPtr(aggrval);

    if (niters->getType() != keytype)
    {
        size_t sz1 = getTypeBitSize(niters->getType());
        size_t sz2 = getTypeBitSize(keytype);
        if (sz1 < sz2)
            niters = gIR->ir->CreateZExt(niters, keytype, "foreachtrunckey");
        else if (sz1 > sz2)
            niters = gIR->ir->CreateTrunc(niters, keytype, "foreachtrunckey");
        else
            niters = gIR->ir->CreateBitCast(niters, keytype, "foreachtrunckey");
    }

    LLConstant* delta = 0;
    if (op == TOKforeach) {
        new llvm::StoreInst(zerokey, keyvar, p->scopebb());
    }
    else {
        new llvm::StoreInst(niters, keyvar, p->scopebb());
    }

    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* condbb = llvm::BasicBlock::Create(gIR->context(), "foreachcond", p->topfunc(), oldend);
    llvm::BasicBlock* bodybb = llvm::BasicBlock::Create(gIR->context(), "foreachbody", p->topfunc(), oldend);
    llvm::BasicBlock* nextbb = llvm::BasicBlock::Create(gIR->context(), "foreachnext", p->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "foreachend", p->topfunc(), oldend);

    llvm::BranchInst::Create(condbb, p->scopebb());

    // condition
    p->scope() = IRScope(condbb,bodybb);

    LLValue* done = 0;
    LLValue* load = DtoLoad(keyvar);
    if (op == TOKforeach) {
        done = p->ir->CreateICmpULT(load, niters, "tmp");
    }
    else if (op == TOKforeach_reverse) {
        done = p->ir->CreateICmpUGT(load, zerokey, "tmp");
        load = p->ir->CreateSub(load, LLConstantInt::get(keytype, 1, false), "tmp");
        DtoStore(load, keyvar);
    }
    llvm::BranchInst::Create(bodybb, endbb, done, p->scopebb());

    // init body
    p->scope() = IRScope(bodybb,nextbb);

    // get value for this iteration
    LLConstant* zero = LLConstantInt::get(keytype,0,false);
    LLValue* loadedKey = p->ir->CreateLoad(keyvar,"tmp");
    LLValue* gep = DtoGEP1(val,loadedKey);

    if (!value->isRef() && !value->isOut()) {
        // Copy value to local variable, and use it as the value variable.
        DVarValue dst(value->type, valvar);
        DVarValue src(value->type, gep);
        DtoAssign(loc, &dst, &src);
        value->ir.irLocal->value = valvar;
    } else {
        // Use the GEP as the address of the value variable.
        DtoRawVarDeclaration(value, gep);
    }

    // emit body
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
    if(body)
        body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    if (!p->scopereturned())
        llvm::BranchInst::Create(nextbb, p->scopebb());

    // next
    p->scope() = IRScope(nextbb,endbb);
    if (op == TOKforeach) {
        LLValue* load = DtoLoad(keyvar);
        load = p->ir->CreateAdd(load, LLConstantInt::get(keytype, 1, false), "tmp");
        DtoStore(load, keyvar);
    }
    llvm::BranchInst::Create(condbb, p->scopebb());

    // end
    p->scope() = IRScope(endbb,oldend);
}

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

#if DMDV2

void ForeachRangeStatement::toIR(IRState* p)
{
    Logger::println("ForeachRangeStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // evaluate lwr/upr
    assert(lwr->type->isintegral());
    LLValue* lower = lwr->toElem(p)->getRVal();
    assert(upr->type->isintegral());
    LLValue* upper = upr->toElem(p)->getRVal();

    // handle key
    assert(key->type->isintegral());
    LLValue* keyval = DtoRawVarDeclaration(key);

    // store initial value in key
    if (op == TOKforeach)
        DtoStore(lower, keyval);
    else
        DtoStore(upper, keyval);

    // set up the block we'll need
    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* condbb = llvm::BasicBlock::Create(gIR->context(), "foreachrange_cond", p->topfunc(), oldend);
    llvm::BasicBlock* bodybb = llvm::BasicBlock::Create(gIR->context(), "foreachrange_body", p->topfunc(), oldend);
    llvm::BasicBlock* nextbb = llvm::BasicBlock::Create(gIR->context(), "foreachrange_next", p->topfunc(), oldend);
    llvm::BasicBlock* endbb = llvm::BasicBlock::Create(gIR->context(), "foreachrange_end", p->topfunc(), oldend);

    // jump to condition
    llvm::BranchInst::Create(condbb, p->scopebb());

    // CONDITION
    p->scope() = IRScope(condbb,bodybb);

    // first we test that lwr < upr
    lower = DtoLoad(keyval);
    assert(lower->getType() == upper->getType());
    llvm::ICmpInst::Predicate cmpop;
    if (key->type->isunsigned())
    {
        cmpop = (op == TOKforeach)
        ? llvm::ICmpInst::ICMP_ULT
        : llvm::ICmpInst::ICMP_UGT;
    }
    else
    {
        cmpop = (op == TOKforeach)
        ? llvm::ICmpInst::ICMP_SLT
        : llvm::ICmpInst::ICMP_SGT;
    }
    LLValue* cond = p->ir->CreateICmp(cmpop, lower, upper);

    // jump to the body if range is ok, to the end if not
    llvm::BranchInst::Create(bodybb, endbb, cond, p->scopebb());

    // BODY
    p->scope() = IRScope(bodybb,nextbb);

    // reverse foreach decrements here
    if (op == TOKforeach_reverse)
    {
        LLValue* v = DtoLoad(keyval);
        LLValue* one = LLConstantInt::get(v->getType(), 1, false);
        v = p->ir->CreateSub(v, one);
        DtoStore(v, keyval);
    }

    // emit body
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,nextbb,endbb));
    if (body)
        body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    // jump to next iteration
    if (!p->scopereturned())
        llvm::BranchInst::Create(nextbb, p->scopebb());

    // NEXT
    p->scope() = IRScope(nextbb,endbb);

    // forward foreach increments here
    if (op == TOKforeach)
    {
        LLValue* v = DtoLoad(keyval);
        LLValue* one = LLConstantInt::get(v->getType(), 1, false);
        v = p->ir->CreateAdd(v, one);
        DtoStore(v, keyval);
    }

    // jump to condition
    llvm::BranchInst::Create(condbb, p->scopebb());

    // END
    p->scope() = IRScope(endbb,oldend);
}

#endif // D2

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

void LabelStatement::toIR(IRState* p)
{
    Logger::println("LabelStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    // if it's an inline asm label, we don't create a basicblock, just emit it in the asm
    if (p->asmBlock)
    {
        IRAsmStmt* a = new IRAsmStmt;
        a->code += p->func()->decl->mangle();
        a->code += "_";
        a->code += ident->toChars();
        a->code += ":";
        p->asmBlock->s.push_back(a);
        p->asmBlock->internalLabels.push_back(ident);

        // disable inlining
        gIR->func()->setNeverInline();
    }
    else
    {
        std::string labelname = p->func()->gen->getScopedLabelName(ident->toChars());
        llvm::BasicBlock*& labelBB = p->func()->gen->labelToBB[labelname];

        llvm::BasicBlock* oldend = gIR->scopeend();
        if (labelBB != NULL) {
            labelBB->moveBefore(oldend);
        } else {
            labelBB = llvm::BasicBlock::Create(gIR->context(), "label_" + labelname, p->topfunc(), oldend);
        }

        if (!p->scopereturned())
            llvm::BranchInst::Create(labelBB, p->scopebb());

        p->scope() = IRScope(labelBB,oldend);
    }

    if (statement) {
        p->func()->gen->targetScopes.push_back(IRTargetScope(this,NULL,NULL,NULL));
        statement->toIR(p);
        p->func()->gen->targetScopes.pop_back();
    }
}

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

void GotoStatement::toIR(IRState* p)
{
    Logger::println("GotoStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergoto", p->topfunc(), oldend);

    DtoGoto(loc, label->ident, enclosingFinally);

    p->scope() = IRScope(bb,oldend);
}

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

void GotoDefaultStatement::toIR(IRState* p)
{
    Logger::println("GotoDefaultStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotodefault", p->topfunc(), oldend);

    assert(!p->scopereturned());
    assert(sw->sdefault->bodyBB);

    DtoEnclosingHandlers(loc, sw);

    llvm::BranchInst::Create(sw->sdefault->bodyBB, p->scopebb());
    p->scope() = IRScope(bb,oldend);
}

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

void GotoCaseStatement::toIR(IRState* p)
{
    Logger::println("GotoCaseStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    llvm::BasicBlock* oldend = gIR->scopeend();
    llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "aftergotocase", p->topfunc(), oldend);

    assert(!p->scopereturned());
    if (!cs->bodyBB)
    {
        cs->bodyBB = llvm::BasicBlock::Create(gIR->context(), "goto_case", p->topfunc(), p->scopeend());
    }

    DtoEnclosingHandlers(loc, sw);

    llvm::BranchInst::Create(cs->bodyBB, p->scopebb());
    p->scope() = IRScope(bb,oldend);
}

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

void WithStatement::toIR(IRState* p)
{
    Logger::println("WithStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    assert(exp);
    assert(body);

    // with(..) can either be used with expressions or with symbols
    // wthis == null indicates the symbol form
    if (wthis) {
        DValue* e = exp->toElem(p);
        LLValue* mem = DtoRawVarDeclaration(wthis);
        DtoStore(e->getRVal(), mem);
    }

    body->toIR(p);
}

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

static LLConstant* generate_unique_critical_section()
{
    const LLType* Mty = DtoMutexType();
    return new llvm::GlobalVariable(*gIR->module, Mty, false, llvm::GlobalValue::InternalLinkage, LLConstant::getNullValue(Mty), ".uniqueCS");
}

void SynchronizedStatement::toIR(IRState* p)
{
    Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // enter lock
    if (exp)
    {
        llsync = exp->toElem(p)->getRVal();
        DtoEnterMonitor(llsync);
    }
    else
    {
        llsync = generate_unique_critical_section();
        DtoEnterCritical(llsync);
    }

    // emit body
    p->func()->gen->targetScopes.push_back(IRTargetScope(this,new EnclosingSynchro(this),NULL,NULL));
    body->toIR(p);
    p->func()->gen->targetScopes.pop_back();

    // exit lock
    // no point in a unreachable unlock, terminating statements must insert this themselves.
    if (p->scopereturned())
        return;
    else if (exp)
        DtoLeaveMonitor(llsync);
    else
        DtoLeaveCritical(llsync);
}

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

void VolatileStatement::toIR(IRState* p)
{
    Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    #ifndef DISABLE_DEBUG_INFO
    if (global.params.symdebug)
        DtoDwarfStopPoint(loc.linnum);
    #endif

    // mark in-volatile
    // FIXME

    // has statement
    if (statement != NULL)
    {
        // load-store
        DtoMemoryBarrier(false, true, false, false);

        // do statement
	p->func()->gen->targetScopes.push_back(IRTargetScope(this,new EnclosingVolatile(this),NULL,NULL));
        statement->toIR(p);
	p->func()->gen->targetScopes.pop_back();

        // no point in a unreachable barrier, terminating statements must insert this themselves.
        if (statement->blockExit() & BEfallthru)
        {
            // store-load
            DtoMemoryBarrier(false, false, true, false);
        }
    }
    // barrier only
    else
    {
        // load-store & store-load
        DtoMemoryBarrier(false, true, true, false);
    }

    // restore volatile state
    // FIXME
}

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

void SwitchErrorStatement::toIR(IRState* p)
{
    Logger::println("SwitchErrorStatement::toIR(): %s", loc.toChars());
    LOG_SCOPE;

    llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_switch_error");

    std::vector<LLValue*> args;

    // file param
    IrModule* irmod = getIrModule(NULL);
    args.push_back(DtoLoad(irmod->fileName));

    // line param
    LLConstant* c = DtoConstUint(loc.linnum);
    args.push_back(c);

    // call
    gIR->CreateCallOrInvoke(fn, args.begin(), args.end());

    gIR->ir->CreateUnreachable();
}

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

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

#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
//STUBST(BreakStatement);
//STUBST(ForStatement);
//STUBST(WithStatement);
//STUBST(SynchronizedStatement);
//STUBST(ReturnStatement);
//STUBST(ContinueStatement);
//STUBST(DefaultStatement);
//STUBST(CaseStatement);
//STUBST(SwitchStatement);
//STUBST(SwitchErrorStatement);
STUBST(Statement);
//STUBST(IfStatement);
//STUBST(ForeachStatement);
//STUBST(DoStatement);
//STUBST(WhileStatement);
//STUBST(ExpStatement);
//STUBST(CompoundStatement);
//STUBST(ScopeStatement);
//STUBST(AsmStatement);
//STUBST(TryCatchStatement);
//STUBST(TryFinallyStatement);
//STUBST(VolatileStatement);
//STUBST(LabelStatement);
//STUBST(ThrowStatement);
//STUBST(GotoCaseStatement);
//STUBST(GotoDefaultStatement);
//STUBST(GotoStatement);
//STUBST(UnrolledLoopStatement);
//STUBST(OnScopeStatement);

#if DMDV2
STUBST(PragmaStatement);
#endif

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

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

AsmBlockStatement* Statement::endsWithAsm()
{
    // does not end with inline asm
    return NULL;
}

AsmBlockStatement* CompoundStatement::endsWithAsm()
{
    // make the last inner statement decide
    if (statements && statements->dim)
    {
        unsigned last = statements->dim - 1;
        Statement* s = (Statement*)statements->data[last];
        if (s) return s->endsWithAsm();
    }
    return NULL;
}

AsmBlockStatement* AsmBlockStatement::endsWithAsm()
{
    // yes this is inline asm
    return this;
}