// Statements: D -> LLVM glue #include #include #include #include #include #include "gen/llvm.h" #include "llvm/InlineAsm.h" #include "llvm/Support/CFG.h" #include "mars.h" #include "total.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 "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; idim; 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; if (exp) { if (p->topfunc()->getReturnType() == LLType::VoidTy) { IrFunction* f = p->func(); assert(f->type->retInPtr); assert(f->decl->ir.irFunc->retArg); if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg); DValue* e = exp->toElem(p); DtoAssign(loc, rvar, e); DtoEnclosingHandlers(enclosinghandler, NULL); if (global.params.symdebug) DtoDwarfFuncEnd(f->decl); llvm::ReturnInst::Create(p->scopebb()); } else { if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); DValue* e = exp->toElem(p); LLValue* v = e->getRVal(); delete e; if (Logger::enabled()) Logger::cout() << "return value is '" <<*v << "'\n"; // can happen for classes if (v->getType() != p->topfunc()->getReturnType()) { v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp"); if (Logger::enabled()) Logger::cout() << "return value after cast: " << *v << '\n'; } DtoEnclosingHandlers(enclosinghandler, NULL); if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl); llvm::ReturnInst::Create(v, p->scopebb()); } } else { assert(p->topfunc()->getReturnType() == LLType::VoidTy); DtoEnclosingHandlers(enclosinghandler, NULL); if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl); llvm::ReturnInst::Create(p->scopebb()); } // the return terminated this basicblock, start a new one llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterreturn", p->topfunc(), oldend); p->scope() = IRScope(bb,oldend); } ////////////////////////////////////////////////////////////////////////////// void ExpStatement::toIR(IRState* p) { Logger::println("ExpStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); 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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); 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("if", gIR->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endif", gIR->topfunc(), oldend); llvm::BasicBlock* elsebb = elsebody ? llvm::BasicBlock::Create("else", gIR->topfunc(), endbb) : endbb; if (cond_val->getType() != LLType::Int1Ty) { 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("scope", p->topfunc(), oldend); if (!p->scopereturned()) llvm::BranchInst::Create(beginbb, bb); } llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // create while blocks llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* whilebb = llvm::BasicBlock::Create("whilecond", gIR->topfunc(), oldend); llvm::BasicBlock* whilebodybb = llvm::BasicBlock::Create("whilebody", gIR->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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->loopbbs.push_back(IRLoopScope(this,enclosinghandler,whilebb,endbb)); body->toIR(p); p->loopbbs.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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // create while blocks llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* dowhilebb = llvm::BasicBlock::Create("dowhile", gIR->topfunc(), oldend); llvm::BasicBlock* condbb = llvm::BasicBlock::Create("dowhilecond", gIR->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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->loopbbs.push_back(IRLoopScope(this,enclosinghandler,condbb,endbb)); body->toIR(p); p->loopbbs.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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // create for blocks llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* forbb = llvm::BasicBlock::Create("forcond", gIR->topfunc(), oldend); llvm::BasicBlock* forbodybb = llvm::BasicBlock::Create("forbody", gIR->topfunc(), oldend); llvm::BasicBlock* forincbb = llvm::BasicBlock::Create("forinc", gIR->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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->loopbbs.push_back(IRLoopScope(this,enclosinghandler,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 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->loopbbs.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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); if (ident != 0) { Logger::println("ident = %s", ident->toChars()); DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler); // 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; IRState::LoopScopeVec::reverse_iterator it; for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) { if(it->s == targetLoopStatement) { llvm::BranchInst::Create(it->end, p->scopebb()); found = true; break; } } assert(found); } else { DtoEnclosingHandlers(enclosinghandler, p->loopbbs.back().enclosinghandler); llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb()); } // the break terminated this basicblock, start a new one llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("afterbreak", p->topfunc(), oldend); p->scope() = IRScope(bb,oldend); } ////////////////////////////////////////////////////////////////////////////// void ContinueStatement::toIR(IRState* p) { Logger::println("ContinueStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); if (ident != 0) { Logger::println("ident = %s", ident->toChars()); DtoEnclosingHandlers(enclosinghandler, target->enclosinghandler); // 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; IRState::LoopScopeVec::reverse_iterator it; for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) { if(it->s == targetLoopStatement) { llvm::BranchInst::Create(it->begin, gIR->scopebb()); found = true; break; } } assert(found); } else { // can't 'continue' within switch, so omit them IRState::LoopScopeVec::reverse_iterator it; for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) { if(!it->isSwitch) { break; } } DtoEnclosingHandlers(enclosinghandler, it->enclosinghandler); llvm::BranchInst::Create(it->begin, gIR->scopebb()); } // the continue terminated this basicblock, start a new one llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // 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("try", p->topfunc(), oldend); llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend); // the landing pad for statements in the try block llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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); gIR->func()->landingPad.addFinally(finalbody); gIR->func()->landingPad.push(landingpadbb); // // 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()); gIR->func()->landingPad.pop(); // // 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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // create basic blocks llvm::BasicBlock* oldend = p->scopeend(); llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); // the landing pad will be responsible for branching to the correct catch block llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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); for (int i = 0; i < catches->dim; i++) { Catch *c = (Catch *)catches->data[i]; gIR->func()->landingPad.addCatch(c, endbb); } gIR->func()->landingPad.push(landingpadbb); // // do the try block // p->scope() = IRScope(trybb,landingpadbb); assert(body); body->toIR(p); if (!gIR->scopereturned()) llvm::BranchInst::Create(endbb, p->scopebb()); gIR->func()->landingPad.pop(); // rewrite the scope p->scope() = IRScope(endbb,oldend); } ////////////////////////////////////////////////////////////////////////////// void ThrowStatement::toIR(IRState* p) { Logger::println("ThrowStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); assert(exp); DValue* e = exp->toElem(p); if (global.params.symdebug) DtoDwarfFuncEnd(gIR->func()->decl); 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("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)); CallOrInvoke* call = gIR->CreateCallOrInvoke2(fn, table, llval, "tmp"); return call->get(); } void SwitchStatement::toIR(IRState* p) { Logger::println("SwitchStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); llvm::BasicBlock* oldend = gIR->scopeend(); // clear data from previous passes... :/ for (int i=0; idim; ++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; idim; ++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 inits(caseArray.dim); for (size_t i=0; idata[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 = llvm::ConstantArray::get(arrTy, inits); llvm::GlobalVariable* arr = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, ".string_switch_table_data", gIR->module); const LLType* elemPtrTy = getPtrToType(elemTy); LLConstant* arrPtr = llvm::ConstantExpr::getBitCast(arr, elemPtrTy); // build the static table std::vector types; types.push_back(DtoSize_t()); types.push_back(elemPtrTy); const llvm::StructType* sTy = llvm::StructType::get(types); std::vector 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("switchbody", p->topfunc(), oldend); // default llvm::BasicBlock* defbb = 0; if (sdefault) { Logger::println("has default"); defbb = llvm::BasicBlock::Create("default", p->topfunc(), oldend); sdefault->bodyBB = defbb; } // end (break point) llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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->loopbbs.push_back(IRLoopScope(this,enclosinghandler,p->scopebb(),endbb,true)); body->toIR(p); p->loopbbs.pop_back(); if (!p->scopereturned()) llvm::BranchInst::Create(endbb, p->scopebb()); // add the cases for (int i=0; idim; ++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("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("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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // 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 blocks(nstmt, NULL); for (size_t i=0; itopfunc(), oldend); } // create end block llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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; iscope() = IRScope(thisbb,nextbb); // push loop scope // continue goes to next statement, break goes to end p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); // do statement s->toIR(p); // pop loop scope p->loopbbs.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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); //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 = DtoAlloca(keytype, "foreachkey"); LLValue* zerokey = llvm::ConstantInt::get(keytype,0,false); // value Logger::println("value = %s", value->toPrettyChars()); DtoRawVarDeclaration(value); const LLType* valtype = DtoType(value->type); LLValue* valvar = NULL; if (!value->isRef() && !value->isOut()) 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("foreachcond", p->topfunc(), oldend); llvm::BasicBlock* bodybb = llvm::BasicBlock::Create("foreachbody", p->topfunc(), oldend); llvm::BasicBlock* nextbb = llvm::BasicBlock::Create("foreachnext", p->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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, llvm::ConstantInt::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 = llvm::ConstantInt::get(keytype,0,false); LLValue* loadedKey = p->ir->CreateLoad(keyvar,"tmp"); value->ir.irLocal->value = DtoGEP1(val,loadedKey); if (!value->isRef() && !value->isOut()) { DVarValue dst(value->type, valvar); DVarValue src(value->type, value->ir.irLocal->value); DtoAssign(loc, &dst, &src); value->ir.irLocal->value = valvar; } // emit body p->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); if(body) body->toIR(p); p->loopbbs.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, llvm::ConstantInt::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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // 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("foreachrange_cond", p->topfunc(), oldend); llvm::BasicBlock* bodybb = llvm::BasicBlock::Create("foreachrange_body", p->topfunc(), oldend); llvm::BasicBlock* nextbb = llvm::BasicBlock::Create("foreachrange_next", p->topfunc(), oldend); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("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->loopbbs.push_back(IRLoopScope(this,enclosinghandler,nextbb,endbb)); if (body) body->toIR(p); p->loopbbs.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); } else { std::string labelname = p->func()->getScopedLabelName(ident->toChars()); llvm::BasicBlock*& labelBB = p->func()->labelToBB[labelname]; llvm::BasicBlock* oldend = gIR->scopeend(); if (labelBB != NULL) { labelBB->moveBefore(oldend); } else { labelBB = llvm::BasicBlock::Create("label", p->topfunc(), oldend); } if (!p->scopereturned()) llvm::BranchInst::Create(labelBB, p->scopebb()); p->scope() = IRScope(labelBB,oldend); } if (statement) statement->toIR(p); } ////////////////////////////////////////////////////////////////////////////// void GotoStatement::toIR(IRState* p) { Logger::println("GotoStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend); DtoGoto(&loc, label->ident, enclosinghandler, tf); p->scope() = IRScope(bb,oldend); } ////////////////////////////////////////////////////////////////////////////// void GotoDefaultStatement::toIR(IRState* p) { Logger::println("GotoDefaultStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotodefault", p->topfunc(), oldend); assert(!p->scopereturned()); assert(sw->sdefault->bodyBB); DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler); 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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotocase", p->topfunc(), oldend); assert(!p->scopereturned()); if (!cs->bodyBB) { cs->bodyBB = llvm::BasicBlock::Create("goto_case", p->topfunc(), p->scopeend()); } DtoEnclosingHandlers(enclosinghandler, sw->enclosinghandler); 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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); assert(exp); assert(body); 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(Mty, false, llvm::GlobalValue::InternalLinkage, LLConstant::getNullValue(Mty), ".uniqueCS", gIR->module); } void SynchronizedStatement::toIR(IRState* p) { Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // enter lock if (exp) { llsync = exp->toElem(p)->getRVal(); DtoEnterMonitor(llsync); } else { llsync = generate_unique_critical_section(); DtoEnterCritical(llsync); } // emit body body->toIR(p); // 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; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // mark in-volatile // FIXME // has statement if (statement != NULL) { // load-store DtoMemoryBarrier(false, true, false, false); // do statement statement->toIR(p); // no point in a unreachable barrier, terminating statements must insert this themselves. if (statement->fallOffEnd()) { // 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 args; // file param args.push_back(DtoLoad(gIR->dmodule->ir.irModule->fileName)); // line param LLConstant* c = DtoConstUint(loc.linnum); args.push_back(c); // call CallOrInvoke* 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