Mercurial > projects > ldc
view ir/irlandingpad.cpp @ 650:aa6a0b7968f7
Added test case for bug #100
Removed dubious check for not emitting static private global in other modules without access. This should be handled properly somewhere else, it's causing unresolved global errors for stuff that should work (in MiniD)
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Sun, 05 Oct 2008 17:28:15 +0200 |
parents | d97b017a8aef |
children | 5761d7e6f628 |
line wrap: on
line source
#include "gen/llvm.h" #include "gen/tollvm.h" #include "gen/irstate.h" #include "gen/runtime.h" #include "gen/logger.h" #include "gen/classes.h" #include "gen/llvmhelpers.h" #include "ir/irlandingpad.h" IRLandingPadInfo::IRLandingPadInfo(Catch* catchstmt, llvm::BasicBlock* end) : finallyBody(NULL) { target = llvm::BasicBlock::Create("catch", gIR->topfunc(), end); gIR->scope() = IRScope(target,end); // assign storage to catch var if(catchstmt->var) { assert(!catchstmt->var->ir.irLocal); catchstmt->var->ir.irLocal = new IrLocal(catchstmt->var); LLValue* catch_var = gIR->func()->landingPad.getExceptionStorage(); catchstmt->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(catchstmt->var->type))); } // emit handler, if there is one // handler is zero for instance for 'catch { debug foo(); }' if(catchstmt->handler) catchstmt->handler->toIR(gIR); if (!gIR->scopereturned()) gIR->ir->CreateBr(end); assert(catchstmt->type); catchType = catchstmt->type->toBasetype()->isClassHandle(); assert(catchType); DtoForceDeclareDsymbol(catchType); } IRLandingPadInfo::IRLandingPadInfo(Statement* finallystmt) : target(NULL), finallyBody(finallystmt), catchType(NULL) { } void IRLandingPad::addCatch(Catch* catchstmt, llvm::BasicBlock* end) { unpushed_infos.push_front(IRLandingPadInfo(catchstmt, end)); } void IRLandingPad::addFinally(Statement* finallystmt) { unpushed_infos.push_front(IRLandingPadInfo(finallystmt)); } void IRLandingPad::push(llvm::BasicBlock* inBB) { // store infos such that matches are right to left nInfos.push(infos.size()); infos.insert(infos.end(), unpushed_infos.begin(), unpushed_infos.end()); unpushed_infos.clear(); constructLandingPad(inBB); // store as invoke target padBBs.push(inBB); } void IRLandingPad::pop() { padBBs.pop(); size_t n = nInfos.top(); infos.resize(n); nInfos.pop(); } llvm::BasicBlock* IRLandingPad::get() { if(padBBs.size() == 0) return NULL; else return padBBs.top(); } void IRLandingPad::constructLandingPad(llvm::BasicBlock* inBB) { // save and rewrite scope IRScope savedscope = gIR->scope(); gIR->scope() = IRScope(inBB,savedscope.end); // eh_ptr = llvm.eh.exception(); llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception); LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn); // build selector arguments LLSmallVector<LLValue*, 6> selectorargs; // put in classinfos in the right order bool hasFinally = false; std::deque<IRLandingPadInfo>::iterator it = infos.begin(), end = infos.end(); for(; it != end; ++it) { if(it->finallyBody) hasFinally = true; else { if(catchToInt.find(it->catchType) == catchToInt.end()) { int newval = 1 + catchToInt.size(); catchToInt[it->catchType] = newval; } assert(it->catchType); assert(it->catchType->ir.irStruct); selectorargs.insert(selectorargs.begin(), it->catchType->ir.irStruct->classInfo); } } // if there's a finally, the eh table has to have a 0 action if(hasFinally) selectorargs.push_back(llvm::ConstantInt::get(LLType::Int32Ty, 0)); // personality fn llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality"); LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)); selectorargs.insert(selectorargs.begin(), personality_fn_arg); // eh storage target selectorargs.insert(selectorargs.begin(), eh_ptr); // if there is a catch and some catch allocated storage, store exception object if(catchToInt.size() && catch_var) { const LLType* objectTy = DtoType(ClassDeclaration::object->type); gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var); } // eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <selectorargs>); llvm::Function* eh_selector_fn; if (global.params.is64bit) eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i64); else eh_selector_fn = GET_INTRINSIC_DECL(eh_selector_i32); LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, selectorargs.begin(), selectorargs.end()); // emit finallys and switches that branch to catches until there are no more catches // then simply branch to the finally chain llvm::SwitchInst* switchinst = NULL; std::deque<IRLandingPadInfo>::reverse_iterator rit, rend = infos.rend(); for(rit = infos.rbegin(); rit != rend; ++rit) { // if it's a finally, emit its code if(rit->finallyBody) { if(switchinst) switchinst = NULL; // since this may be emitted multiple times // give the labels a new scope gIR->func()->pushUniqueLabelScope("finally"); rit->finallyBody->toIR(gIR); gIR->func()->popLabelScope(); } // otherwise it's a catch and we'll add a switch case else { if(!switchinst) { switchinst = gIR->ir->CreateSwitch(eh_sel, llvm::BasicBlock::Create("switchdefault", gIR->topfunc(), gIR->scopeend()), infos.size()); gIR->scope() = IRScope(switchinst->getDefaultDest(), gIR->scopeend()); } // dubious comment // catches matched first get the largest switchval, so do size - unique int llvm::ConstantInt* switchval = llvm::ConstantInt::get(DtoSize_t(), catchToInt[rit->catchType]); // and make sure we don't add the same switchval twice, may happen with nested trys if(!switchinst->findCaseValue(switchval)) switchinst->addCase(switchval, rit->target); } } // no catch matched and all finallys executed - resume unwind llvm::Function* unwind_resume_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_resume_unwind"); gIR->ir->CreateCall(unwind_resume_fn, eh_ptr); gIR->ir->CreateUnreachable(); gIR->scope() = savedscope; } LLValue* IRLandingPad::getExceptionStorage() { if(!catch_var) { Logger::println("Making new catch var"); const LLType* objectTy = DtoType(ClassDeclaration::object->type); catch_var = DtoAlloca(objectTy,"catchvar"); } return catch_var; }