Mercurial > projects > ldc
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; }