Mercurial > projects > ldc
comparison gen/statements.cpp @ 262:88252a1af660 trunk
[svn r280] Fixed a bunch of issues with switch statements. Ended up a bit far reaching...
author | lindquist |
---|---|
date | Sat, 14 Jun 2008 05:13:49 +0200 |
parents | a95056b3c996 |
children | 2be09ee06bc7 |
comparison
equal
deleted
inserted
replaced
261:5723b7385c25 | 262:88252a1af660 |
---|---|
221 void ScopeStatement::toIR(IRState* p) | 221 void ScopeStatement::toIR(IRState* p) |
222 { | 222 { |
223 Logger::println("ScopeStatement::toIR(): %s", loc.toChars()); | 223 Logger::println("ScopeStatement::toIR(): %s", loc.toChars()); |
224 LOG_SCOPE; | 224 LOG_SCOPE; |
225 | 225 |
226 llvm::BasicBlock* oldend = p->scopeend(); | 226 /*llvm::BasicBlock* oldend = p->scopeend(); |
227 | 227 |
228 llvm::BasicBlock* beginbb = 0; | 228 llvm::BasicBlock* beginbb = 0; |
229 | 229 |
230 // remove useless branches by clearing and reusing the current basicblock | 230 // remove useless branches by clearing and reusing the current basicblock |
231 llvm::BasicBlock* bb = p->scopebb(); | 231 llvm::BasicBlock* bb = p->scopebb(); |
232 if (bb->empty()) { | 232 if (bb->empty()) { |
233 beginbb = bb; | 233 beginbb = bb; |
234 } | 234 } |
235 else { | 235 else { |
236 assert(!p->scopereturned()); | |
237 beginbb = llvm::BasicBlock::Create("scope", p->topfunc(), oldend); | 236 beginbb = llvm::BasicBlock::Create("scope", p->topfunc(), oldend); |
238 llvm::BranchInst::Create(beginbb, p->scopebb()); | 237 if (!p->scopereturned()) |
239 } | 238 llvm::BranchInst::Create(beginbb, bb); |
239 } | |
240 | |
240 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endscope", p->topfunc(), oldend); | 241 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endscope", p->topfunc(), oldend); |
241 | 242 if (beginbb != bb) |
242 gIR->scope() = IRScope(beginbb, endbb); | 243 p->scope() = IRScope(beginbb, endbb); |
244 else | |
245 p->scope().end = endbb;*/ | |
243 | 246 |
244 if (statement) | 247 if (statement) |
245 statement->toIR(p); | 248 statement->toIR(p); |
246 | 249 |
247 p->scope() = IRScope(p->scopebb(),oldend); | 250 /*p->scope().end = oldend; |
248 endbb->eraseFromParent(); | 251 Logger::println("Erasing scope endbb"); |
252 endbb->eraseFromParent();*/ | |
249 } | 253 } |
250 | 254 |
251 ////////////////////////////////////////////////////////////////////////////// | 255 ////////////////////////////////////////////////////////////////////////////// |
252 | 256 |
253 void WhileStatement::toIR(IRState* p) | 257 void WhileStatement::toIR(IRState* p) |
396 void BreakStatement::toIR(IRState* p) | 400 void BreakStatement::toIR(IRState* p) |
397 { | 401 { |
398 Logger::println("BreakStatement::toIR(): %s", loc.toChars()); | 402 Logger::println("BreakStatement::toIR(): %s", loc.toChars()); |
399 LOG_SCOPE; | 403 LOG_SCOPE; |
400 | 404 |
405 // don't emit two terminators in a row | |
406 // happens just before DMD generated default statements if the last case terminates | |
407 if (p->scopereturned()) | |
408 return; | |
409 | |
401 if (ident != 0) { | 410 if (ident != 0) { |
402 Logger::println("ident = %s", ident->toChars()); | 411 Logger::println("ident = %s", ident->toChars()); |
403 | 412 |
404 emit_finallyblocks(p, enclosingtryfinally, target->enclosingtryfinally); | 413 emit_finallyblocks(p, enclosingtryfinally, target->enclosingtryfinally); |
405 | 414 |
409 while(tmp = targetLoopStatement->isScopeStatement()) | 418 while(tmp = targetLoopStatement->isScopeStatement()) |
410 targetLoopStatement = tmp->statement; | 419 targetLoopStatement = tmp->statement; |
411 | 420 |
412 // find the right break block and jump there | 421 // find the right break block and jump there |
413 IRState::LoopScopeVec::reverse_iterator it; | 422 IRState::LoopScopeVec::reverse_iterator it; |
414 for(it = gIR->loopbbs.rbegin(); it != gIR->loopbbs.rend(); ++it) { | 423 for(it = p->loopbbs.rbegin(); it != p->loopbbs.rend(); ++it) { |
415 if(it->s == targetLoopStatement) { | 424 if(it->s == targetLoopStatement) { |
416 llvm::BranchInst::Create(it->end, gIR->scopebb()); | 425 llvm::BranchInst::Create(it->end, p->scopebb()); |
417 return; | 426 return; |
418 } | 427 } |
419 } | 428 } |
420 assert(0); | 429 assert(0); |
421 } | 430 } |
422 else { | 431 else { |
423 emit_finallyblocks(p, enclosingtryfinally, gIR->loopbbs.back().enclosingtryfinally); | 432 emit_finallyblocks(p, enclosingtryfinally, p->loopbbs.back().enclosingtryfinally); |
424 llvm::BranchInst::Create(gIR->loopbbs.back().end, gIR->scopebb()); | 433 llvm::BranchInst::Create(p->loopbbs.back().end, p->scopebb()); |
425 } | 434 } |
426 } | 435 } |
427 | 436 |
428 ////////////////////////////////////////////////////////////////////////////// | 437 ////////////////////////////////////////////////////////////////////////////// |
429 | 438 |
640 Logger::println("SwitchStatement::toIR(): %s", loc.toChars()); | 649 Logger::println("SwitchStatement::toIR(): %s", loc.toChars()); |
641 LOG_SCOPE; | 650 LOG_SCOPE; |
642 | 651 |
643 llvm::BasicBlock* oldend = gIR->scopeend(); | 652 llvm::BasicBlock* oldend = gIR->scopeend(); |
644 | 653 |
645 // collect the needed cases | |
646 typedef std::pair<llvm::BasicBlock*, std::vector<llvm::ConstantInt*> > CasePair; | |
647 std::vector<CasePair> vcases; | |
648 std::vector<Statement*> vbodies; | |
649 Array caseArray; | |
650 for (int i=0; i<cases->dim; ++i) | |
651 { | |
652 CaseStatement* cs = (CaseStatement*)cases->data[i]; | |
653 | |
654 std::string lblname("case"); | |
655 llvm::BasicBlock* bb = llvm::BasicBlock::Create(lblname, p->topfunc(), oldend); | |
656 cs->bodyBB = bb; | |
657 | |
658 std::vector<llvm::ConstantInt*> tmp; | |
659 CaseStatement* last; | |
660 bool first = true; | |
661 do { | |
662 // integral case | |
663 if (cs->exp->type->isintegral()) { | |
664 LLConstant* c = cs->exp->toConstElem(p); | |
665 tmp.push_back(isaConstantInt(c)); | |
666 } | |
667 // string case | |
668 else { | |
669 assert(cs->exp->op == TOKstring); | |
670 // for string switches this is unfortunately necessary or there will be duplicates in the list | |
671 if (first) { | |
672 caseArray.push(new Case((StringExp*)cs->exp, i)); | |
673 first = false; | |
674 } | |
675 } | |
676 last = cs; | |
677 } | |
678 while (cs = cs->statement->isCaseStatement()); | |
679 | |
680 vcases.push_back(CasePair(bb, tmp)); | |
681 vbodies.push_back(last->statement); | |
682 } | |
683 | |
684 // string switch? | 654 // string switch? |
685 llvm::GlobalVariable* switchTable = 0; | 655 llvm::GlobalVariable* switchTable = 0; |
656 Array caseArray; | |
686 if (!condition->type->isintegral()) | 657 if (!condition->type->isintegral()) |
687 { | 658 { |
659 Logger::println("is string switch"); | |
660 // build array of the stringexpS | |
661 for (int i=0; i<cases->dim; ++i) | |
662 { | |
663 CaseStatement* cs = (CaseStatement*)cases->data[i]; | |
664 | |
665 assert(cs->exp->op == TOKstring); | |
666 caseArray.push(new Case((StringExp*)cs->exp, i)); | |
667 } | |
688 // first sort it | 668 // first sort it |
689 caseArray.sort(); | 669 caseArray.sort(); |
690 // iterate and add indices to cases | 670 // iterate and add indices to cases |
691 std::vector<LLConstant*> inits; | 671 std::vector<LLConstant*> inits; |
692 for (size_t i=0; i<caseArray.dim; ++i) | 672 for (size_t i=0; i<caseArray.dim; ++i) |
693 { | 673 { |
674 CaseStatement* cs = (CaseStatement*)cases->data[i]; | |
675 cs->llvmIdx = DtoConstUint(i); | |
694 Case* c = (Case*)caseArray.data[i]; | 676 Case* c = (Case*)caseArray.data[i]; |
695 vcases[c->index].second.push_back(DtoConstUint(i)); | |
696 inits.push_back(c->str->toConstElem(p)); | 677 inits.push_back(c->str->toConstElem(p)); |
697 } | 678 } |
698 // build static array for ptr or final array | 679 // build static array for ptr or final array |
699 const LLType* elemTy = DtoType(condition->type); | 680 const LLType* elemTy = DtoType(condition->type); |
700 const llvm::ArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size()); | 681 const llvm::ArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size()); |
715 LLConstant* sInit = llvm::ConstantStruct::get(sTy, sinits); | 696 LLConstant* sInit = llvm::ConstantStruct::get(sTy, sinits); |
716 | 697 |
717 switchTable = new llvm::GlobalVariable(sTy, true, llvm::GlobalValue::InternalLinkage, sInit, "string_switch_table", gIR->module); | 698 switchTable = new llvm::GlobalVariable(sTy, true, llvm::GlobalValue::InternalLinkage, sInit, "string_switch_table", gIR->module); |
718 } | 699 } |
719 | 700 |
701 // body block | |
702 llvm::BasicBlock* bodybb = llvm::BasicBlock::Create("switchbody", p->topfunc(), oldend); | |
703 | |
720 // default | 704 // default |
721 llvm::BasicBlock* defbb = 0; | 705 llvm::BasicBlock* defbb = 0; |
722 if (!hasNoDefault) { | 706 if (sdefault) { |
707 Logger::println("has default"); | |
723 defbb = llvm::BasicBlock::Create("default", p->topfunc(), oldend); | 708 defbb = llvm::BasicBlock::Create("default", p->topfunc(), oldend); |
724 sdefault->bodyBB = defbb; | 709 sdefault->bodyBB = defbb; |
725 } | 710 } |
726 | 711 |
727 // end (break point) | 712 // end (break point) |
738 else { | 723 else { |
739 condVal = call_string_switch_runtime(switchTable, condition); | 724 condVal = call_string_switch_runtime(switchTable, condition); |
740 } | 725 } |
741 llvm::SwitchInst* si = llvm::SwitchInst::Create(condVal, defbb ? defbb : endbb, cases->dim, p->scopebb()); | 726 llvm::SwitchInst* si = llvm::SwitchInst::Create(condVal, defbb ? defbb : endbb, cases->dim, p->scopebb()); |
742 | 727 |
728 // do switch body | |
729 assert(body); | |
730 | |
731 p->scope() = IRScope(bodybb, endbb); | |
732 p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb)); | |
733 body->toIR(p); | |
734 p->loopbbs.pop_back(); | |
735 | |
736 if (!p->scopereturned()) | |
737 llvm::BranchInst::Create(endbb, p->scopebb()); | |
738 | |
743 // add the cases | 739 // add the cases |
744 size_t n = vcases.size(); | 740 for (int i=0; i<cases->dim; ++i) |
745 for (size_t i=0; i<n; ++i) | 741 { |
746 { | 742 CaseStatement* cs = (CaseStatement*)cases->data[i]; |
747 size_t nc = vcases[i].second.size(); | 743 si->addCase(cs->llvmIdx, cs->bodyBB); |
748 for (size_t j=0; j<nc; ++j) | |
749 { | |
750 si->addCase(vcases[i].second[j], vcases[i].first); | |
751 } | |
752 } | |
753 | |
754 // insert case statements | |
755 for (size_t i=0; i<n; ++i) | |
756 { | |
757 llvm::BasicBlock* nextbb = (i == n-1) ? (defbb ? defbb : endbb) : vcases[i+1].first; | |
758 p->scope() = IRScope(vcases[i].first,nextbb); | |
759 p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb)); | |
760 vbodies[i]->toIR(p); | |
761 p->loopbbs.pop_back(); | |
762 | |
763 llvm::BasicBlock* curbb = p->scopebb(); | |
764 if (curbb->empty() || !curbb->back().isTerminator()) | |
765 { | |
766 llvm::BranchInst::Create(nextbb, curbb); | |
767 } | |
768 } | |
769 | |
770 // default statement | |
771 if (defbb) | |
772 { | |
773 p->scope() = IRScope(defbb,endbb); | |
774 p->loopbbs.push_back(IRLoopScope(this,enclosingtryfinally,p->scopebb(),endbb)); | |
775 Logger::println("doing default statement"); | |
776 sdefault->statement->toIR(p); | |
777 p->loopbbs.pop_back(); | |
778 | |
779 llvm::BasicBlock* curbb = p->scopebb(); | |
780 if (curbb->empty() || !curbb->back().isTerminator()) | |
781 { | |
782 llvm::BranchInst::Create(endbb, curbb); | |
783 } | |
784 } | 744 } |
785 | 745 |
786 gIR->scope() = IRScope(endbb,oldend); | 746 gIR->scope() = IRScope(endbb,oldend); |
787 } | 747 } |
788 | 748 |
790 void CaseStatement::toIR(IRState* p) | 750 void CaseStatement::toIR(IRState* p) |
791 { | 751 { |
792 Logger::println("CaseStatement::toIR(): %s", loc.toChars()); | 752 Logger::println("CaseStatement::toIR(): %s", loc.toChars()); |
793 LOG_SCOPE; | 753 LOG_SCOPE; |
794 | 754 |
795 assert(0); | 755 if (!bodyBB) |
756 { | |
757 bodyBB = llvm::BasicBlock::Create("case", p->topfunc(), p->scopeend()); | |
758 } | |
759 else | |
760 { | |
761 bodyBB->moveAfter(p->scopebb()); | |
762 } | |
763 | |
764 if (exp->type->isintegral()) { | |
765 assert(!llvmIdx); | |
766 LLConstant* c = exp->toConstElem(p); | |
767 llvmIdx = isaConstantInt(c); | |
768 } | |
769 else { | |
770 assert(llvmIdx); | |
771 } | |
772 | |
773 if (!p->scopereturned()) | |
774 llvm::BranchInst::Create(bodyBB, p->scopebb()); | |
775 | |
776 p->scope() = IRScope(bodyBB, p->scopeend()); | |
777 | |
778 assert(statement); | |
779 statement->toIR(p); | |
780 } | |
781 | |
782 ////////////////////////////////////////////////////////////////////////////// | |
783 void DefaultStatement::toIR(IRState* p) | |
784 { | |
785 Logger::println("DefaultStatement::toIR(): %s", loc.toChars()); | |
786 LOG_SCOPE; | |
787 | |
788 assert(bodyBB); | |
789 | |
790 bodyBB->moveAfter(p->scopebb()); | |
791 | |
792 if (!p->scopereturned()) | |
793 llvm::BranchInst::Create(bodyBB, p->scopebb()); | |
794 | |
795 p->scope() = IRScope(bodyBB, p->scopeend()); | |
796 | |
797 assert(statement); | |
798 statement->toIR(p); | |
796 } | 799 } |
797 | 800 |
798 ////////////////////////////////////////////////////////////////////////////// | 801 ////////////////////////////////////////////////////////////////////////////// |
799 | 802 |
800 void UnrolledLoopStatement::toIR(IRState* p) | 803 void UnrolledLoopStatement::toIR(IRState* p) |
1081 | 1084 |
1082 llvm::BasicBlock* oldend = gIR->scopeend(); | 1085 llvm::BasicBlock* oldend = gIR->scopeend(); |
1083 llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotocase", p->topfunc(), oldend); | 1086 llvm::BasicBlock* bb = llvm::BasicBlock::Create("aftergotocase", p->topfunc(), oldend); |
1084 | 1087 |
1085 assert(!p->scopereturned()); | 1088 assert(!p->scopereturned()); |
1086 assert(cs->bodyBB); | 1089 if (!cs->bodyBB) |
1090 { | |
1091 cs->bodyBB = llvm::BasicBlock::Create("case", p->topfunc(), p->scopeend()); | |
1092 } | |
1087 | 1093 |
1088 emit_finallyblocks(p, enclosingtryfinally, sw->enclosingtryfinally); | 1094 emit_finallyblocks(p, enclosingtryfinally, sw->enclosingtryfinally); |
1089 | 1095 |
1090 llvm::BranchInst::Create(cs->bodyBB, p->scopebb()); | 1096 llvm::BranchInst::Create(cs->bodyBB, p->scopebb()); |
1091 p->scope() = IRScope(bb,oldend); | 1097 p->scope() = IRScope(bb,oldend); |
1203 //STUBST(ForStatement); | 1209 //STUBST(ForStatement); |
1204 //STUBST(WithStatement); | 1210 //STUBST(WithStatement); |
1205 //STUBST(SynchronizedStatement); | 1211 //STUBST(SynchronizedStatement); |
1206 //STUBST(ReturnStatement); | 1212 //STUBST(ReturnStatement); |
1207 //STUBST(ContinueStatement); | 1213 //STUBST(ContinueStatement); |
1208 STUBST(DefaultStatement); | 1214 //STUBST(DefaultStatement); |
1209 //STUBST(CaseStatement); | 1215 //STUBST(CaseStatement); |
1210 //STUBST(SwitchStatement); | 1216 //STUBST(SwitchStatement); |
1211 STUBST(SwitchErrorStatement); | 1217 STUBST(SwitchErrorStatement); |
1212 STUBST(Statement); | 1218 STUBST(Statement); |
1213 //STUBST(IfStatement); | 1219 //STUBST(IfStatement); |