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);