Mercurial > projects > ldc
comparison gen/statements.cpp @ 122:36ab367572df trunk
[svn r126] String switch is now implemented.
A few other fixes.
author | lindquist |
---|---|
date | Tue, 27 Nov 2007 09:19:07 +0100 |
parents | 9c79b61fb638 |
children | 7f9a0a58394b |
comparison
equal
deleted
inserted
replaced
121:9c79b61fb638 | 122:36ab367572df |
---|---|
524 */ | 524 */ |
525 } | 525 } |
526 | 526 |
527 ////////////////////////////////////////////////////////////////////////////// | 527 ////////////////////////////////////////////////////////////////////////////// |
528 | 528 |
529 // used to build the sorted list of cases | |
530 struct Case : Object | |
531 { | |
532 StringExp* str; | |
533 size_t index; | |
534 | |
535 Case(StringExp* s, size_t i) { | |
536 str = s; | |
537 index = i; | |
538 } | |
539 | |
540 int compare(Object *obj) { | |
541 Case* c2 = (Case*)obj; | |
542 return str->compare(c2->str); | |
543 } | |
544 }; | |
545 | |
546 static llvm::Value* call_string_switch_runtime(llvm::GlobalVariable* table, Expression* e) | |
547 { | |
548 Type* dt = DtoDType(e->type); | |
549 Type* dtnext = DtoDType(dt->next); | |
550 TY ty = dtnext->ty; | |
551 const char* fname; | |
552 if (ty == Tchar) { | |
553 fname = "_d_switch_string"; | |
554 } | |
555 else if (ty == Twchar) { | |
556 fname = "_d_switch_ustring"; | |
557 } | |
558 else if (ty == Tdchar) { | |
559 fname = "_d_switch_dstring"; | |
560 } | |
561 else { | |
562 assert(0 && "not char/wchar/dchar"); | |
563 } | |
564 | |
565 llvm::Function* fn = LLVM_D_GetRuntimeFunction(gIR->module, fname); | |
566 std::vector<llvm::Value*> args; | |
567 args.push_back(table); | |
568 args.push_back(e->toElem(gIR)->getRVal()); | |
569 return gIR->ir->CreateCall(fn, args.begin(), args.end(), "tmp"); | |
570 } | |
571 | |
529 void SwitchStatement::toIR(IRState* p) | 572 void SwitchStatement::toIR(IRState* p) |
530 { | 573 { |
531 Logger::println("SwitchStatement::toIR(): %s", toChars()); | 574 Logger::println("SwitchStatement::toIR()"); |
532 LOG_SCOPE; | 575 LOG_SCOPE; |
533 | 576 |
534 llvm::BasicBlock* oldend = gIR->scopeend(); | 577 llvm::BasicBlock* oldend = gIR->scopeend(); |
535 | 578 |
536 // collect the needed cases | 579 // collect the needed cases |
537 typedef std::pair<llvm::BasicBlock*, std::vector<llvm::ConstantInt*> > CasePair; | 580 typedef std::pair<llvm::BasicBlock*, std::vector<llvm::ConstantInt*> > CasePair; |
538 std::vector<CasePair> vcases; | 581 std::vector<CasePair> vcases; |
539 std::vector<Statement*> vbodies; | 582 std::vector<Statement*> vbodies; |
583 Array caseArray; | |
540 for (int i=0; i<cases->dim; ++i) | 584 for (int i=0; i<cases->dim; ++i) |
541 { | 585 { |
542 CaseStatement* cs = (CaseStatement*)cases->data[i]; | 586 CaseStatement* cs = (CaseStatement*)cases->data[i]; |
543 | 587 |
544 // create the case bb with a nice label | 588 std::string lblname("case"); |
545 std::string lblname("case"+std::string(cs->exp->toChars())); | |
546 llvm::BasicBlock* bb = new llvm::BasicBlock(lblname, p->topfunc(), oldend); | 589 llvm::BasicBlock* bb = new llvm::BasicBlock(lblname, p->topfunc(), oldend); |
547 | 590 |
548 std::vector<llvm::ConstantInt*> tmp; | 591 std::vector<llvm::ConstantInt*> tmp; |
549 CaseStatement* last; | 592 CaseStatement* last; |
593 bool first = true; | |
550 do { | 594 do { |
551 // get the case value | 595 // integral case |
552 DValue* e = cs->exp->toElem(p); | 596 if (cs->exp->type->isintegral()) { |
553 DConstValue* ce = e->isConst(); | 597 llvm::Constant* c = cs->exp->toConstElem(p); |
554 assert(ce); | 598 tmp.push_back(isaConstantInt(c)); |
555 llvm::ConstantInt* ec = isaConstantInt(ce->c); | 599 } |
556 assert(ec); | 600 // string case |
557 tmp.push_back(ec); | 601 else { |
602 assert(cs->exp->op == TOKstring); | |
603 // for string switches this is unfortunately necessary or there will be duplicates in the list | |
604 if (first) { | |
605 caseArray.push(new Case((StringExp*)cs->exp, i)); | |
606 first = false; | |
607 } | |
608 } | |
558 last = cs; | 609 last = cs; |
559 } | 610 } |
560 while (cs = cs->statement->isCaseStatement()); | 611 while (cs = cs->statement->isCaseStatement()); |
561 | 612 |
562 vcases.push_back(CasePair(bb, tmp)); | 613 vcases.push_back(CasePair(bb, tmp)); |
563 vbodies.push_back(last->statement); | 614 vbodies.push_back(last->statement); |
615 } | |
616 | |
617 // string switch? | |
618 llvm::GlobalVariable* switchTable = 0; | |
619 if (!condition->type->isintegral()) | |
620 { | |
621 // first sort it | |
622 caseArray.sort(); | |
623 // iterate and add indices to cases | |
624 std::vector<llvm::Constant*> inits; | |
625 for (size_t i=0; i<caseArray.dim; ++i) | |
626 { | |
627 Case* c = (Case*)caseArray.data[i]; | |
628 vcases[c->index].second.push_back(DtoConstUint(i)); | |
629 inits.push_back(c->str->toConstElem(p)); | |
630 } | |
631 // build static array for ptr or final array | |
632 const llvm::Type* elemTy = DtoType(condition->type); | |
633 const llvm::ArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size()); | |
634 llvm::Constant* arrInit = llvm::ConstantArray::get(arrTy, inits); | |
635 llvm::GlobalVariable* arr = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, "string_switch_table_data", gIR->module); | |
636 | |
637 const llvm::Type* elemPtrTy = llvm::PointerType::get(elemTy); | |
638 llvm::Constant* arrPtr = llvm::ConstantExpr::getBitCast(arr, elemPtrTy); | |
639 | |
640 // build the static table | |
641 std::vector<const llvm::Type*> types; | |
642 types.push_back(DtoSize_t()); | |
643 types.push_back(elemPtrTy); | |
644 const llvm::StructType* sTy = llvm::StructType::get(types); | |
645 std::vector<llvm::Constant*> sinits; | |
646 sinits.push_back(DtoConstSize_t(inits.size())); | |
647 sinits.push_back(arrPtr); | |
648 llvm::Constant* sInit = llvm::ConstantStruct::get(sTy, sinits); | |
649 | |
650 switchTable = new llvm::GlobalVariable(sTy, true, llvm::GlobalValue::InternalLinkage, sInit, "string_switch_table", gIR->module); | |
564 } | 651 } |
565 | 652 |
566 // default | 653 // default |
567 llvm::BasicBlock* defbb = 0; | 654 llvm::BasicBlock* defbb = 0; |
568 if (!hasNoDefault) { | 655 if (!hasNoDefault) { |
571 | 658 |
572 // end (break point) | 659 // end (break point) |
573 llvm::BasicBlock* endbb = new llvm::BasicBlock("switchend", p->topfunc(), oldend); | 660 llvm::BasicBlock* endbb = new llvm::BasicBlock("switchend", p->topfunc(), oldend); |
574 | 661 |
575 // condition var | 662 // condition var |
576 DValue* cond = condition->toElem(p); | 663 llvm::Value* condVal; |
577 llvm::SwitchInst* si = new llvm::SwitchInst(cond->getRVal(), defbb ? defbb : endbb, cases->dim, p->scopebb()); | 664 // integral switch |
578 delete cond; | 665 if (condition->type->isintegral()) { |
666 DValue* cond = condition->toElem(p); | |
667 condVal = cond->getRVal(); | |
668 } | |
669 // string switch | |
670 else { | |
671 condVal = call_string_switch_runtime(switchTable, condition); | |
672 } | |
673 llvm::SwitchInst* si = new llvm::SwitchInst(condVal, defbb ? defbb : endbb, cases->dim, p->scopebb()); | |
579 | 674 |
580 // add the cases | 675 // add the cases |
581 size_t n = vcases.size(); | 676 size_t n = vcases.size(); |
582 for (size_t i=0; i<n; ++i) | 677 for (size_t i=0; i<n; ++i) |
583 { | 678 { |