Mercurial > projects > ldc
view gen/statements.cpp @ 305:2b72433d5c8c trunk
[svn r326] Fixed a bunch of issues with printf's that MinGW32 did not support.
Fixed problems with label collisions when using labels inside inline asm. LabelStatement is now easily reached given its
Identifier, which should be useful elsewhere too.
Enabled inline asm for building the lib/compiler/llvmdc runtime code, fixing branches out of asm makes this possible.
author | lindquist |
---|---|
date | Fri, 27 Jun 2008 22:04:35 +0200 |
parents | 3ebc136702dd |
children | 6b62e8cdf970 |
line wrap: on
line source
// Statements: D -> LLVM glue #include <stdio.h> #include <math.h> #include <sstream> #include <fstream> #include <iostream> #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 "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" ////////////////////////////////////////////////////////////////////////////// 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; if (exp) { if (p->topfunc()->getReturnType() == LLType::VoidTy) { IrFunction* f = p->func(); assert(f->type->llvmRetInPtr); 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, true); p->exps.push_back(IRExp(NULL,exp,rvar)); DValue* e = exp->toElem(p); p->exps.pop_back(); if (!e->inPlace()) DtoAssign(rvar, e); DtoFinallyBlocks(enclosingtryfinally, NULL); if (f->inVolatile) { // store-load barrier DtoMemoryBarrier(false, false, true, false); } 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; 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"); Logger::cout() << "return value after cast: " << *v << '\n'; } DtoFinallyBlocks(enclosingtryfinally, NULL); if (gIR->func()->inVolatile) { // store-load barrier DtoMemoryBarrier(false, false, true, false); } if (global.params.symdebug) DtoDwarfFuncEnd(p->func()->decl); llvm::ReturnInst::Create(v, p->scopebb()); } } else { assert(p->topfunc()->getReturnType() == LLType::VoidTy); DtoFinallyBlocks(enclosingtryfinally, NULL); if (gIR->func()->inVolatile) { // store-load barrier DtoMemoryBarrier(false, false, true, false); } 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 = 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) { LLValue* allocainst = new llvm::AllocaInst(DtoType(match->type), "._tmp_if_var", p->topallocapoint()); match->ir.irLocal = new IrLocal(match); match->ir.irLocal->value = allocainst; } DValue* cond_e = condition->toElem(p); LLValue* cond_val = cond_e->getRVal(); delete cond_e; 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) { Logger::cout() << "if conditional: " << *cond_val << '\n'; cond_val = DtoBoolean(cond_val); } 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 = DtoBoolean(cond_e->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,enclosingtryfinally,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* 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,endbb); // do-while body code p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,dowhilebb,endbb)); body->toIR(p); p->loopbbs.pop_back(); // create the condition DValue* cond_e = condition->toElem(p); LLValue* cond_val = DtoBoolean(cond_e->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,enclosingtryfinally,forincbb,endbb)); // replace current scope gIR->scope() = IRScope(forbb,forbodybb); // create the condition DValue* cond_e = condition->toElem(p); LLValue* cond_val = DtoBoolean(cond_e->getRVal()); delete cond_e; // 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()); DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally); // 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 { DtoFinallyBlocks(enclosingtryfinally, p->loopbbs.back().enclosingtryfinally); 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()); DtoFinallyBlocks(enclosingtryfinally, target->enclosingtryfinally); // 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 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()); return; } } assert(0); } else { DtoFinallyBlocks(enclosingtryfinally, gIR->loopbbs.back().enclosingtryfinally); llvm::BranchInst::Create(gIR->loopbbs.back().begin, gIR->scopebb()); } } ////////////////////////////////////////////////////////////////////////////// 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); // 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); 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()); // 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()); // do finally block p->scope() = IRScope(finallybb,endbb); assert(finalbody); finalbody->toIR(p); // terminate finally 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; Logger::attention(loc, "try-catch is not yet fully implemented"); 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); llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", 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 the try block p->scope() = IRScope(trybb,catchbb); assert(body); body->toIR(p); if (!gIR->scopereturned()) llvm::BranchInst::Create(endbb, p->scopebb()); // do catch p->scope() = IRScope(catchbb,oldend); llvm::BranchInst::Create(endbb, p->scopebb()); /*assert(catches); for(size_t i=0; i<catches->dim; ++i) { Catch* c = (Catch*)catches->data[i]; c->handler->toIR(p); }*/ // rewrite the scope p->scope() = IRScope(endbb,oldend); } ////////////////////////////////////////////////////////////////////////////// void ThrowStatement::toIR(IRState* p) { Logger::println("ThrowStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; Logger::attention(loc, "throw is not yet fully implemented"); if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); assert(exp); DValue* e = exp->toElem(p); 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->ir->CreateCall(fn, arg, ""); gIR->ir->CreateUnreachable(); } ////////////////////////////////////////////////////////////////////////////// // 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::GlobalVariable* table, Expression* e) { Type* dt = DtoDType(e->type); Type* dtnext = DtoDType(dt->next); 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); 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; if (DSliceValue* sval = val->isSlice()) { // give storage llval = new llvm::AllocaInst(DtoType(e->type), "tmp", gIR->topallocapoint()); DVarValue* vv = new DVarValue(e->type, llval, true); DtoAssign(vv, val); } else { llval = val->getRVal(); } assert(llval->getType() == fn->getFunctionType()->getParamType(1)); llvm::CallInst* call = gIR->ir->CreateCall2(fn, table, llval, "tmp"); llvm::PAListPtr palist; palist = palist.addAttr(1, llvm::ParamAttr::ByVal); palist = palist.addAttr(2, llvm::ParamAttr::ByVal); call->setParamAttrs(palist); return call; } 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; i<cases->dim; ++i) { CaseStatement* cs = (CaseStatement*)cases->data[i]; cs->bodyBB = NULL; cs->llvmIdx = NULL; } // string switch? llvm::GlobalVariable* 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 = 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<const LLType*> types; types.push_back(DtoSize_t()); types.push_back(elemPtrTy); const llvm::StructType* sTy = llvm::StructType::get(types); std::vector<LLConstant*> sinits; sinits.push_back(DtoConstSize_t(inits.size())); sinits.push_back(arrPtr); LLConstant* sInit = llvm::ConstantStruct::get(sTy, sinits); switchTable = new llvm::GlobalVariable(sTy, true, llvm::GlobalValue::InternalLinkage, sInit, ".string_switch_table", gIR->module); } // 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,enclosingtryfinally,p->scopebb(),endbb)); body->toIR(p); p->loopbbs.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("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 (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* endbb = llvm::BasicBlock::Create("unrolledend", p->topfunc(), oldend); p->scope() = IRScope(p->scopebb(),endbb); p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb)); for (int i=0; i<statements->dim; ++i) { Statement* s = (Statement*)statements->data[i]; s->toIR(p); } p->loopbbs.pop_back(); llvm::BranchInst::Create(endbb, p->scopebb()); 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(body != 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 = new llvm::AllocaInst(keytype, "foreachkey", p->topallocapoint()); if (key) { //key->llvmValue = keyvar; assert(!key->ir.irLocal); key->ir.irLocal = new IrLocal(key); key->ir.irLocal->value = keyvar; } LLValue* zerokey = llvm::ConstantInt::get(keytype,0,false); // value Logger::println("value = %s", value->toPrettyChars()); const LLType* valtype = DtoType(value->type); LLValue* valvar = NULL; if (!value->isRef() && !value->isOut()) valvar = new llvm::AllocaInst(valtype, "foreachval", p->topallocapoint()); if (!value->ir.irLocal) value->ir.irLocal = new IrLocal(value); // what to iterate DValue* aggrval = aggr->toElem(p); Type* aggrtype = DtoDType(aggr->type); // get length and pointer LLValue* val = 0; LLValue* niters = 0; // static array if (aggrtype->ty == Tsarray) { Logger::println("foreach over static array"); val = aggrval->getRVal(); assert(isaPointer(val->getType())); const llvm::ArrayType* arrty = isaArray(val->getType()->getContainedType(0)); assert(arrty); size_t nelems = arrty->getNumElements(); if(nelems == 0) return; niters = llvm::ConstantInt::get(keytype,nelems,false); } // dynamic array else if (aggrtype->ty == Tarray) { if (DSliceValue* slice = aggrval->isSlice()) { Logger::println("foreach over slice"); niters = slice->len; assert(niters); val = slice->ptr; assert(val); } else { Logger::println("foreach over dynamic array"); val = aggrval->getRVal(); niters = DtoGEPi(val,0,0); niters = DtoLoad(niters, "numiterations"); val = DtoGEPi(val,0,1); val = DtoLoad(val, "collection"); } } else { assert(0 && "aggregate type is not Tarray or Tsarray"); } 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 = new llvm::ICmpInst(llvm::ICmpInst::ICMP_ULT, load, niters, "tmp", p->scopebb()); } else if (op == TOKforeach_reverse) { done = new llvm::ICmpInst(llvm::ICmpInst::ICMP_UGT, load, zerokey, "tmp", p->scopebb()); load = llvm::BinaryOperator::createSub(load,llvm::ConstantInt::get(keytype, 1, false),"tmp",p->scopebb()); new llvm::StoreInst(load, keyvar, p->scopebb()); } 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"); if (aggrtype->ty == Tsarray) value->ir.irLocal->value = DtoGEP(val,zero,loadedKey,"tmp"); else if (aggrtype->ty == Tarray) value->ir.irLocal->value = llvm::GetElementPtrInst::Create(val,loadedKey,"tmp",p->scopebb()); if (!value->isRef() && !value->isOut()) { DValue* dst = new DVarValue(value->type, valvar, true); DValue* src = new DVarValue(value->type, value->ir.irLocal->value, true); DtoAssign(dst, src); value->ir.irLocal->value = valvar; } // emit body p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,nextbb,endbb)); 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); } ////////////////////////////////////////////////////////////////////////////// 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 { assert(tf == NULL); llvm::BasicBlock* oldend = gIR->scopeend(); if (llvmBB) llvmBB->moveBefore(oldend); else llvmBB = llvm::BasicBlock::Create("label", p->topfunc(), oldend); if (!p->scopereturned()) llvm::BranchInst::Create(llvmBB, p->scopebb()); p->scope() = IRScope(llvmBB,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); assert(tf == NULL); llvm::BasicBlock* oldend = gIR->scopeend(); llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergoto", p->topfunc(), oldend); DtoGoto(&loc, label->ident, enclosingtryfinally); 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); DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally); 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()); } DtoFinallyBlocks(enclosingtryfinally, sw->enclosingtryfinally); 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); assert(!wthis->ir.isSet()); wthis->ir.irLocal = new IrLocal(wthis); wthis->ir.irLocal->value = e->getRVal(); body->toIR(p); } ////////////////////////////////////////////////////////////////////////////// void SynchronizedStatement::toIR(IRState* p) { Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; Logger::attention(loc, "synchronized is currently ignored. only the body will be emitted"); if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); body->toIR(p); } ////////////////////////////////////////////////////////////////////////////// /* this has moved to asmstmt.cpp void AsmStatement::toIR(IRState* p) { Logger::println("AsmStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; // error("%s: inline asm is not yet implemented", loc.toChars()); // fatal(); assert(!asmcode && !asmalign && !refparam && !naked && !regs); Token* t = tokens; assert(t); std::string asmstr; do { Logger::println("token: %s", t->toChars()); asmstr.append(t->toChars()); asmstr.append(" "); } while (t = t->next); Logger::println("asm expr = '%s'", asmstr.c_str()); // create function type std::vector<const LLType*> args; const llvm::FunctionType* fty = llvm::FunctionType::get(DtoSize_t(), args, false); // create inline asm callee llvm::InlineAsm* inasm = llvm::InlineAsm::get(fty, asmstr, "r,r", false); assert(0); } */ ////////////////////////////////////////////////////////////////////////////// void VolatileStatement::toIR(IRState* p) { Logger::println("VolatileStatement::toIR(): %s", loc.toChars()); LOG_SCOPE; if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum); // mark in-volatile bool old = gIR->func()->inVolatile; gIR->func()->inVolatile = true; // 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 should 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 gIR->func()->inVolatile = old; } ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// #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);