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