Mercurial > projects > ldc
comparison gen/statements.cpp @ 314:8d98e42ece93 trunk
[svn r335] The basics of exception handling are in place.
Still need to make sure calls are turned into invokes everywhere. (NewExpression for instance)
Still some rough edges and corner cases to figure out.
Needs testing!
author | ChristianK |
---|---|
date | Wed, 02 Jul 2008 22:20:18 +0200 |
parents | 9967a3270837 |
children | a9697749e898 |
comparison
equal
deleted
inserted
replaced
313:a498b736a0bd | 314:8d98e42ece93 |
---|---|
494 // create basic blocks | 494 // create basic blocks |
495 llvm::BasicBlock* oldend = p->scopeend(); | 495 llvm::BasicBlock* oldend = p->scopeend(); |
496 | 496 |
497 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); | 497 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); |
498 llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend); | 498 llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend); |
499 // 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* unwindfinallybb = llvm::BasicBlock::Create("unwindfinally", p->topfunc(), oldend); | |
499 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend); | 502 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend); |
500 | 503 |
501 // pass the previous BB into this | 504 // pass the previous BB into this |
502 assert(!gIR->scopereturned()); | 505 assert(!gIR->scopereturned()); |
503 llvm::BranchInst::Create(trybb, p->scopebb()); | 506 llvm::BranchInst::Create(trybb, p->scopebb()); |
504 | 507 |
508 // | |
505 // do the try block | 509 // do the try block |
510 // | |
506 p->scope() = IRScope(trybb,finallybb); | 511 p->scope() = IRScope(trybb,finallybb); |
512 p->landingPads.push_back(unwindfinallybb); | |
507 | 513 |
508 assert(body); | 514 assert(body); |
509 body->toIR(p); | 515 body->toIR(p); |
510 | 516 |
511 // terminate try BB | 517 // terminate try BB |
512 if (!p->scopereturned()) | 518 if (!p->scopereturned()) |
513 llvm::BranchInst::Create(finallybb, p->scopebb()); | 519 llvm::BranchInst::Create(finallybb, p->scopebb()); |
514 | 520 |
521 p->landingPads.pop_back(); | |
522 | |
523 // | |
515 // do finally block | 524 // do finally block |
516 p->scope() = IRScope(finallybb,endbb); | 525 // |
526 p->scope() = IRScope(finallybb,unwindfinallybb); | |
517 assert(finalbody); | 527 assert(finalbody); |
518 finalbody->toIR(p); | 528 finalbody->toIR(p); |
519 | 529 |
520 // terminate finally | 530 // terminate finally |
531 //TODO: isn't it an error to have a 'returned' finally block? | |
521 if (!gIR->scopereturned()) { | 532 if (!gIR->scopereturned()) { |
522 llvm::BranchInst::Create(endbb, p->scopebb()); | 533 llvm::BranchInst::Create(endbb, p->scopebb()); |
523 } | 534 } |
524 | 535 |
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 | |
525 // rewrite the scope | 569 // rewrite the scope |
526 p->scope() = IRScope(endbb,oldend); | 570 p->scope() = IRScope(endbb,oldend); |
527 } | 571 } |
528 | 572 |
529 ////////////////////////////////////////////////////////////////////////////// | 573 ////////////////////////////////////////////////////////////////////////////// |
531 void TryCatchStatement::toIR(IRState* p) | 575 void TryCatchStatement::toIR(IRState* p) |
532 { | 576 { |
533 Logger::println("TryCatchStatement::toIR(): %s", loc.toChars()); | 577 Logger::println("TryCatchStatement::toIR(): %s", loc.toChars()); |
534 LOG_SCOPE; | 578 LOG_SCOPE; |
535 | 579 |
536 Logger::attention(loc, "try-catch is not yet fully implemented"); | |
537 | |
538 if (global.params.symdebug) | 580 if (global.params.symdebug) |
539 DtoDwarfStopPoint(loc.linnum); | 581 DtoDwarfStopPoint(loc.linnum); |
540 | 582 |
541 // create basic blocks | 583 // create basic blocks |
542 llvm::BasicBlock* oldend = p->scopeend(); | 584 llvm::BasicBlock* oldend = p->scopeend(); |
543 | 585 |
544 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); | 586 llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend); |
545 llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend); | 587 // the landing pad will be responsible for branching to the correct catch block |
588 llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend); | |
546 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtrycatch", p->topfunc(), oldend); | 589 llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtrycatch", p->topfunc(), oldend); |
547 | 590 |
548 // pass the previous BB into this | 591 // pass the previous BB into this |
549 assert(!gIR->scopereturned()); | 592 assert(!gIR->scopereturned()); |
550 llvm::BranchInst::Create(trybb, p->scopebb()); | 593 llvm::BranchInst::Create(trybb, p->scopebb()); |
551 | 594 |
595 // | |
552 // do the try block | 596 // do the try block |
553 p->scope() = IRScope(trybb,catchbb); | 597 // |
598 p->scope() = IRScope(trybb,landingpadbb); | |
599 p->landingPads.push_back(landingpadbb); | |
600 | |
554 assert(body); | 601 assert(body); |
555 body->toIR(p); | 602 body->toIR(p); |
556 | 603 |
557 if (!gIR->scopereturned()) | 604 if (!gIR->scopereturned()) |
558 llvm::BranchInst::Create(endbb, p->scopebb()); | 605 llvm::BranchInst::Create(endbb, p->scopebb()); |
559 | 606 |
560 // do catch | 607 p->landingPads.pop_back(); |
561 p->scope() = IRScope(catchbb,oldend); | 608 |
562 llvm::BranchInst::Create(endbb, p->scopebb()); | 609 // |
563 /*assert(catches); | 610 // do catches |
564 for(size_t i=0; i<catches->dim; ++i) | 611 // |
565 { | 612 assert(catches); |
566 Catch* c = (Catch*)catches->data[i]; | 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); | |
567 c->handler->toIR(p); | 638 c->handler->toIR(p); |
568 }*/ | 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 } | |
569 | 695 |
570 // rewrite the scope | 696 // rewrite the scope |
571 p->scope() = IRScope(endbb,oldend); | 697 p->scope() = IRScope(endbb,oldend); |
572 } | 698 } |
573 | 699 |
575 | 701 |
576 void ThrowStatement::toIR(IRState* p) | 702 void ThrowStatement::toIR(IRState* p) |
577 { | 703 { |
578 Logger::println("ThrowStatement::toIR(): %s", loc.toChars()); | 704 Logger::println("ThrowStatement::toIR(): %s", loc.toChars()); |
579 LOG_SCOPE; | 705 LOG_SCOPE; |
580 | |
581 Logger::attention(loc, "throw is not yet fully implemented"); | |
582 | 706 |
583 if (global.params.symdebug) | 707 if (global.params.symdebug) |
584 DtoDwarfStopPoint(loc.linnum); | 708 DtoDwarfStopPoint(loc.linnum); |
585 | 709 |
586 assert(exp); | 710 assert(exp); |