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 {