Mercurial > projects > ldc
comparison gen/statements.cpp @ 319:e9c93739bc4c trunk
[svn r340] Rework exception handling to work with nested tryfinally and trycatch.
author | ChristianK |
---|---|
date | Sat, 05 Jul 2008 10:22:56 +0200 |
parents | a9697749e898 |
children | 04e1b4930975 |
comparison
equal
deleted
inserted
replaced
318:8e570dbe4087 | 319:e9c93739bc4c |
---|---|
25 #include "gen/arrays.h" | 25 #include "gen/arrays.h" |
26 #include "gen/todebug.h" | 26 #include "gen/todebug.h" |
27 #include "gen/dvalue.h" | 27 #include "gen/dvalue.h" |
28 | 28 |
29 #include "ir/irfunction.h" | 29 #include "ir/irfunction.h" |
30 #include "ir/irlandingpad.h" | |
30 | 31 |
31 ////////////////////////////////////////////////////////////////////////////// | 32 ////////////////////////////////////////////////////////////////////////////// |
32 | 33 |
33 void CompoundStatement::toIR(IRState* p) | 34 void CompoundStatement::toIR(IRState* p) |
34 { | 35 { |
495 llvm::BasicBlock* oldend = p->scopeend(); | 496 llvm::BasicBlock* oldend = p->scopeend(); |
496 | 497 |
497 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); | 498 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); |
498 llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend); | 499 llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend); |
499 // the landing pad for statements in the try block | 500 // the landing pad for statements in the try block |
500 // only reached via eh-unwinding, a call to resume unwinding is appended | 501 llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend); |
501 llvm::BasicBlock* unwindfinallybb = llvm::BasicBlock::Create("unwindfinally", p->topfunc(), oldend); | |
502 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend); | 502 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend); |
503 | 503 |
504 // pass the previous BB into this | 504 // pass the previous BB into this |
505 assert(!gIR->scopereturned()); | 505 assert(!gIR->scopereturned()); |
506 llvm::BranchInst::Create(trybb, p->scopebb()); | 506 llvm::BranchInst::Create(trybb, p->scopebb()); |
507 | |
508 // | |
509 // set up the landing pad | |
510 // | |
511 p->scope() = IRScope(landingpadbb, endbb); | |
512 | |
513 gIR->func()->landingPad.addFinally(finalbody); | |
514 gIR->func()->landingPad.push(landingpadbb); | |
507 | 515 |
508 // | 516 // |
509 // do the try block | 517 // do the try block |
510 // | 518 // |
511 p->scope() = IRScope(trybb,finallybb); | 519 p->scope() = IRScope(trybb,finallybb); |
512 p->landingPads.push_back(unwindfinallybb); | |
513 | 520 |
514 assert(body); | 521 assert(body); |
515 body->toIR(p); | 522 body->toIR(p); |
516 | 523 |
517 // terminate try BB | 524 // terminate try BB |
518 if (!p->scopereturned()) | 525 if (!p->scopereturned()) |
519 llvm::BranchInst::Create(finallybb, p->scopebb()); | 526 llvm::BranchInst::Create(finallybb, p->scopebb()); |
520 | 527 |
521 p->landingPads.pop_back(); | 528 gIR->func()->landingPad.pop(); |
522 | 529 |
523 // | 530 // |
524 // do finally block | 531 // do finally block |
525 // | 532 // |
526 p->scope() = IRScope(finallybb,unwindfinallybb); | 533 p->scope() = IRScope(finallybb,landingpadbb); |
527 assert(finalbody); | 534 assert(finalbody); |
528 finalbody->toIR(p); | 535 finalbody->toIR(p); |
529 | 536 |
530 // terminate finally | 537 // terminate finally |
531 //TODO: isn't it an error to have a 'returned' finally block? | 538 //TODO: isn't it an error to have a 'returned' finally block? |
532 if (!gIR->scopereturned()) { | 539 if (!gIR->scopereturned()) { |
533 llvm::BranchInst::Create(endbb, p->scopebb()); | 540 llvm::BranchInst::Create(endbb, p->scopebb()); |
534 } | 541 } |
535 | 542 |
536 // | |
537 // do landing pad | |
538 // | |
539 p->scope() = IRScope(unwindfinallybb,endbb); | |
540 | |
541 // eh_ptr = llvm.eh.exception(); | |
542 llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); | |
543 LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); | |
544 | |
545 // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, 0); | |
546 llvm::Function* eh_selector_fn; | |
547 if (global.params.is64bit) | |
548 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64); | |
549 else | |
550 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32); | |
551 llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); | |
552 LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)); | |
553 LLValue* eh_sel = gIR->ir->CreateCall3(eh_selector_fn, eh_ptr, personality_fn_arg, llvm::ConstantInt::get(LLType::Int32Ty, 0)); | |
554 | |
555 // emit finally code | |
556 finalbody->toIR(p); | |
557 | |
558 // finally code may not be terminated! | |
559 if (gIR->scopereturned()) { | |
560 error("finally blocks may not be terminated", loc.toChars()); | |
561 fatal(); | |
562 } | |
563 | |
564 llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); | |
565 gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); | |
566 | |
567 gIR->ir->CreateUnreachable(); | |
568 | |
569 // rewrite the scope | 543 // rewrite the scope |
570 p->scope() = IRScope(endbb,oldend); | 544 p->scope() = IRScope(endbb,oldend); |
571 } | 545 } |
572 | 546 |
573 ////////////////////////////////////////////////////////////////////////////// | 547 ////////////////////////////////////////////////////////////////////////////// |
591 // pass the previous BB into this | 565 // pass the previous BB into this |
592 assert(!gIR->scopereturned()); | 566 assert(!gIR->scopereturned()); |
593 llvm::BranchInst::Create(trybb, p->scopebb()); | 567 llvm::BranchInst::Create(trybb, p->scopebb()); |
594 | 568 |
595 // | 569 // |
570 // do catches and the landing pad | |
571 // | |
572 assert(catches); | |
573 gIR->scope() = IRScope(landingpadbb, endbb); | |
574 | |
575 for (int i = 0; i < catches->dim; i++) | |
576 { | |
577 Catch *c = (Catch *)catches->data[i]; | |
578 gIR->func()->landingPad.addCatch(c, endbb); | |
579 } | |
580 | |
581 gIR->func()->landingPad.push(landingpadbb); | |
582 | |
583 // | |
596 // do the try block | 584 // do the try block |
597 // | 585 // |
598 p->scope() = IRScope(trybb,landingpadbb); | 586 p->scope() = IRScope(trybb,landingpadbb); |
599 p->landingPads.push_back(landingpadbb); | |
600 | 587 |
601 assert(body); | 588 assert(body); |
602 body->toIR(p); | 589 body->toIR(p); |
603 | 590 |
604 if (!gIR->scopereturned()) | 591 if (!gIR->scopereturned()) |
605 llvm::BranchInst::Create(endbb, p->scopebb()); | 592 llvm::BranchInst::Create(endbb, p->scopebb()); |
606 | 593 |
607 p->landingPads.pop_back(); | 594 gIR->func()->landingPad.pop(); |
608 | |
609 // | |
610 // do catches | |
611 // | |
612 assert(catches); | |
613 | |
614 // get storage for exception var | |
615 const LLType* objectTy = DtoType(ClassDeclaration::object->type); | |
616 llvm::AllocaInst* catch_var = new llvm::AllocaInst(objectTy,"catchvar",p->topallocapoint()); | |
617 | |
618 // for further reference in landing pad | |
619 LLSmallVector<llvm::BasicBlock*,4> catch_bbs; | |
620 | |
621 for (int i = 0; i < catches->dim; i++) | |
622 { | |
623 Catch *c = (Catch *)catches->data[i]; | |
624 | |
625 llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend); | |
626 catch_bbs.push_back(catchbb); | |
627 p->scope() = IRScope(catchbb,oldend); | |
628 | |
629 // assign storage to catch var | |
630 if(c->var) { | |
631 assert(!c->var->ir.irLocal); | |
632 c->var->ir.irLocal = new IrLocal(c->var); | |
633 c->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(c->var->type))); | |
634 } | |
635 | |
636 // emit handler | |
637 assert(c->handler); | |
638 c->handler->toIR(p); | |
639 | |
640 if (!gIR->scopereturned()) | |
641 llvm::BranchInst::Create(endbb, p->scopebb()); | |
642 } | |
643 | |
644 // | |
645 // do landing pad | |
646 // | |
647 p->scope() = IRScope(landingpadbb,endbb); | |
648 | |
649 // eh_ptr = llvm.eh.exception(); | |
650 llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); | |
651 LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); | |
652 | |
653 // store eh_ptr in catch_var | |
654 gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); | |
655 | |
656 // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <classinfos>); | |
657 llvm::Function* eh_selector_fn; | |
658 if (global.params.is64bit) | |
659 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64); | |
660 else | |
661 eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32); | |
662 | |
663 LLSmallVector<LLValue*,4> args; | |
664 args.push_back(eh_ptr); | |
665 llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); | |
666 args.push_back(gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty))); | |
667 for (int i = 0; i < catches->dim; i++) | |
668 { | |
669 Catch *c = (Catch *)catches->data[i]; | |
670 assert(c->type); | |
671 ClassDeclaration* cdecl = c->type->isClassHandle(); | |
672 assert(cdecl); | |
673 assert(cdecl->ir.irStruct); | |
674 args.push_back(cdecl->ir.irStruct->classInfo); | |
675 } | |
676 | |
677 LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, args.begin(), args.end()); | |
678 | |
679 // switch on eh_sel and branch to correct case | |
680 | |
681 // setup default target | |
682 llvm::BasicBlock* defaulttarget = llvm::BasicBlock::Create("default", p->topfunc(), oldend); | |
683 //TODO: Error handling? | |
684 new llvm::UnreachableInst(defaulttarget); | |
685 | |
686 llvm::SwitchInst* sw = p->ir->CreateSwitch(eh_sel, defaulttarget, catch_bbs.size()); | |
687 | |
688 // add all catches as cases | |
689 for(unsigned int c = 0; c < catch_bbs.size(); ++c) | |
690 { | |
691 llvm::BasicBlock* casebb = llvm::BasicBlock::Create("case", p->topfunc(), oldend); | |
692 llvm::BranchInst::Create(catch_bbs[c], casebb); | |
693 sw->addCase(llvm::ConstantInt::get(LLType::Int32Ty, c+1), casebb); | |
694 } | |
695 | 595 |
696 // rewrite the scope | 596 // rewrite the scope |
697 p->scope() = IRScope(endbb,oldend); | 597 p->scope() = IRScope(endbb,oldend); |
698 } | 598 } |
699 | 599 |