mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-07-19 21:55:21 +02:00
[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!
This commit is contained in:
@@ -136,8 +136,11 @@ struct IRState
|
||||
llvm::BasicBlock* scopeend();
|
||||
bool scopereturned();
|
||||
|
||||
// landing pads for try statements
|
||||
typedef std::vector<llvm::BasicBlock*> BBVec;
|
||||
BBVec landingPads;
|
||||
|
||||
// loop blocks
|
||||
typedef std::vector<IRScope> BBVec;
|
||||
typedef std::vector<IRLoopScope> LoopScopeVec;
|
||||
LoopScopeVec loopbbs;
|
||||
|
||||
|
||||
@@ -880,4 +880,30 @@ static void LLVM_D_BuildRuntimeModule()
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// int _d_eh_personality(int ver, int actions, ulong eh_class, ptr eh_info, ptr context)
|
||||
{
|
||||
std::string fname("_d_eh_personality");
|
||||
std::vector<const LLType*> types;
|
||||
types.push_back(intTy);
|
||||
types.push_back(intTy);
|
||||
types.push_back(longTy);
|
||||
types.push_back(voidPtrTy);
|
||||
types.push_back(voidPtrTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
|
||||
// void _d_eh_resume_unwind(ptr exc_struct)
|
||||
{
|
||||
std::string fname("_d_eh_resume_unwind");
|
||||
std::vector<const LLType*> types;
|
||||
types.push_back(voidPtrTy);
|
||||
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
|
||||
llvm::Function::Create(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -496,14 +496,20 @@ void TryFinallyStatement::toIR(IRState* p)
|
||||
|
||||
llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend);
|
||||
llvm::BasicBlock* finallybb = llvm::BasicBlock::Create("finally", p->topfunc(), oldend);
|
||||
// the landing pad for statements in the try block
|
||||
// only reached via eh-unwinding, a call to resume unwinding is appended
|
||||
llvm::BasicBlock* unwindfinallybb = llvm::BasicBlock::Create("unwindfinally", p->topfunc(), oldend);
|
||||
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtryfinally", p->topfunc(), oldend);
|
||||
|
||||
// pass the previous BB into this
|
||||
assert(!gIR->scopereturned());
|
||||
llvm::BranchInst::Create(trybb, p->scopebb());
|
||||
|
||||
//
|
||||
// do the try block
|
||||
//
|
||||
p->scope() = IRScope(trybb,finallybb);
|
||||
p->landingPads.push_back(unwindfinallybb);
|
||||
|
||||
assert(body);
|
||||
body->toIR(p);
|
||||
@@ -512,16 +518,54 @@ void TryFinallyStatement::toIR(IRState* p)
|
||||
if (!p->scopereturned())
|
||||
llvm::BranchInst::Create(finallybb, p->scopebb());
|
||||
|
||||
p->landingPads.pop_back();
|
||||
|
||||
//
|
||||
// do finally block
|
||||
p->scope() = IRScope(finallybb,endbb);
|
||||
//
|
||||
p->scope() = IRScope(finallybb,unwindfinallybb);
|
||||
assert(finalbody);
|
||||
finalbody->toIR(p);
|
||||
|
||||
// terminate finally
|
||||
//TODO: isn't it an error to have a 'returned' finally block?
|
||||
if (!gIR->scopereturned()) {
|
||||
llvm::BranchInst::Create(endbb, p->scopebb());
|
||||
}
|
||||
|
||||
//
|
||||
// do landing pad
|
||||
//
|
||||
p->scope() = IRScope(unwindfinallybb,endbb);
|
||||
|
||||
// eh_ptr = llvm.eh.exception();
|
||||
llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
|
||||
LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);
|
||||
|
||||
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, 0);
|
||||
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);
|
||||
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
|
||||
LLValue* personality_fn_arg = gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty));
|
||||
LLValue* eh_sel = gIR->ir->CreateCall3(eh_selector_fn, eh_ptr, personality_fn_arg, llvm::ConstantInt::get(LLType::Int32Ty, 0));
|
||||
|
||||
// emit finally code
|
||||
finalbody->toIR(p);
|
||||
|
||||
// finally code may not be terminated!
|
||||
if (gIR->scopereturned()) {
|
||||
error("finally blocks may not be terminated", loc.toChars());
|
||||
fatal();
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
// rewrite the scope
|
||||
p->scope() = IRScope(endbb,oldend);
|
||||
}
|
||||
@@ -533,8 +577,6 @@ void TryCatchStatement::toIR(IRState* p)
|
||||
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
Logger::attention(loc, "try-catch is not yet fully implemented");
|
||||
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
@@ -542,30 +584,114 @@ void TryCatchStatement::toIR(IRState* p)
|
||||
llvm::BasicBlock* oldend = p->scopeend();
|
||||
|
||||
llvm::BasicBlock* trybb = llvm::BasicBlock::Create("try", p->topfunc(), oldend);
|
||||
llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend);
|
||||
// the landing pad will be responsible for branching to the correct catch block
|
||||
llvm::BasicBlock* landingpadbb = llvm::BasicBlock::Create("landingpad", p->topfunc(), oldend);
|
||||
llvm::BasicBlock* endbb = llvm::BasicBlock::Create("endtrycatch", p->topfunc(), oldend);
|
||||
|
||||
// pass the previous BB into this
|
||||
assert(!gIR->scopereturned());
|
||||
llvm::BranchInst::Create(trybb, p->scopebb());
|
||||
|
||||
//
|
||||
// do the try block
|
||||
p->scope() = IRScope(trybb,catchbb);
|
||||
//
|
||||
p->scope() = IRScope(trybb,landingpadbb);
|
||||
p->landingPads.push_back(landingpadbb);
|
||||
|
||||
assert(body);
|
||||
body->toIR(p);
|
||||
|
||||
if (!gIR->scopereturned())
|
||||
llvm::BranchInst::Create(endbb, p->scopebb());
|
||||
|
||||
// do catch
|
||||
p->scope() = IRScope(catchbb,oldend);
|
||||
llvm::BranchInst::Create(endbb, p->scopebb());
|
||||
/*assert(catches);
|
||||
for(size_t i=0; i<catches->dim; ++i)
|
||||
p->landingPads.pop_back();
|
||||
|
||||
//
|
||||
// do catches
|
||||
//
|
||||
assert(catches);
|
||||
|
||||
// get storage for exception var
|
||||
const LLType* objectTy = DtoType(ClassDeclaration::object->type);
|
||||
llvm::AllocaInst* catch_var = new llvm::AllocaInst(objectTy,"catchvar",p->topallocapoint());
|
||||
|
||||
// for further reference in landing pad
|
||||
LLSmallVector<llvm::BasicBlock*,4> catch_bbs;
|
||||
|
||||
for (int i = 0; i < catches->dim; i++)
|
||||
{
|
||||
Catch* c = (Catch*)catches->data[i];
|
||||
Catch *c = (Catch *)catches->data[i];
|
||||
|
||||
llvm::BasicBlock* catchbb = llvm::BasicBlock::Create("catch", p->topfunc(), oldend);
|
||||
catch_bbs.push_back(catchbb);
|
||||
p->scope() = IRScope(catchbb,oldend);
|
||||
|
||||
// assign storage to catch var
|
||||
if(c->var) {
|
||||
assert(!c->var->ir.irLocal);
|
||||
c->var->ir.irLocal = new IrLocal(c->var);
|
||||
c->var->ir.irLocal->value = gIR->ir->CreateBitCast(catch_var, getPtrToType(DtoType(c->var->type)));
|
||||
}
|
||||
|
||||
// emit handler
|
||||
assert(c->handler);
|
||||
c->handler->toIR(p);
|
||||
}*/
|
||||
|
||||
if (!gIR->scopereturned())
|
||||
llvm::BranchInst::Create(endbb, p->scopebb());
|
||||
}
|
||||
|
||||
//
|
||||
// do landing pad
|
||||
//
|
||||
p->scope() = IRScope(landingpadbb,endbb);
|
||||
|
||||
// eh_ptr = llvm.eh.exception();
|
||||
llvm::Function* eh_exception_fn = GET_INTRINSIC_DECL(eh_exception);
|
||||
LLValue* eh_ptr = gIR->ir->CreateCall(eh_exception_fn);
|
||||
|
||||
// store eh_ptr in catch_var
|
||||
gIR->ir->CreateStore(gIR->ir->CreateBitCast(eh_ptr, objectTy), catch_var);
|
||||
|
||||
// eh_sel = llvm.eh.selector(eh_ptr, cast(byte*)&_d_eh_personality, <classinfos>);
|
||||
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);
|
||||
|
||||
LLSmallVector<LLValue*,4> args;
|
||||
args.push_back(eh_ptr);
|
||||
llvm::Function* personality_fn = LLVM_D_GetRuntimeFunction(gIR->module, "_d_eh_personality");
|
||||
args.push_back(gIR->ir->CreateBitCast(personality_fn, getPtrToType(LLType::Int8Ty)));
|
||||
for (int i = 0; i < catches->dim; i++)
|
||||
{
|
||||
Catch *c = (Catch *)catches->data[i];
|
||||
assert(c->type);
|
||||
ClassDeclaration* cdecl = c->type->isClassHandle();
|
||||
assert(cdecl);
|
||||
assert(cdecl->ir.irStruct);
|
||||
args.push_back(cdecl->ir.irStruct->classInfo);
|
||||
}
|
||||
|
||||
LLValue* eh_sel = gIR->ir->CreateCall(eh_selector_fn, args.begin(), args.end());
|
||||
|
||||
// switch on eh_sel and branch to correct case
|
||||
|
||||
// setup default target
|
||||
llvm::BasicBlock* defaulttarget = llvm::BasicBlock::Create("default", p->topfunc(), oldend);
|
||||
//TODO: Error handling?
|
||||
new llvm::UnreachableInst(defaulttarget);
|
||||
|
||||
llvm::SwitchInst* sw = p->ir->CreateSwitch(eh_sel, defaulttarget, catch_bbs.size());
|
||||
|
||||
// add all catches as cases
|
||||
for(unsigned int c = 0; c < catch_bbs.size(); ++c)
|
||||
{
|
||||
llvm::BasicBlock* casebb = llvm::BasicBlock::Create("case", p->topfunc(), oldend);
|
||||
llvm::BranchInst::Create(catch_bbs[c], casebb);
|
||||
sw->addCase(llvm::ConstantInt::get(LLType::Int32Ty, c+1), casebb);
|
||||
}
|
||||
|
||||
// rewrite the scope
|
||||
p->scope() = IRScope(endbb,oldend);
|
||||
@@ -578,8 +704,6 @@ void ThrowStatement::toIR(IRState* p)
|
||||
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
|
||||
LOG_SCOPE;
|
||||
|
||||
Logger::attention(loc, "throw is not yet fully implemented");
|
||||
|
||||
if (global.params.symdebug)
|
||||
DtoDwarfStopPoint(loc.linnum);
|
||||
|
||||
|
||||
94
gen/toir.cpp
94
gen/toir.cpp
@@ -1246,37 +1246,81 @@ DValue* CallExp::toElem(IRState* p)
|
||||
//Logger::cout() << "Calling: " << *funcval << '\n';
|
||||
|
||||
// call the function
|
||||
llvm::CallInst* call = llvm::CallInst::Create(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
|
||||
LLValue* retllval = (retinptr) ? llargs[0] : call;
|
||||
LLValue* retllval;
|
||||
if(p->landingPads.empty())
|
||||
{
|
||||
llvm::CallInst* call = llvm::CallInst::Create(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
|
||||
|
||||
if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) {
|
||||
const LLType* rettype = getPtrToType(DtoType(type));
|
||||
if (retllval->getType() != rettype) {
|
||||
Logger::println("llvmRunTimeHack==true - force casting return value");
|
||||
Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n';
|
||||
retllval = DtoBitCast(retllval, rettype);
|
||||
retllval = (retinptr) ? llargs[0] : call;
|
||||
|
||||
if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) {
|
||||
const LLType* rettype = getPtrToType(DtoType(type));
|
||||
if (retllval->getType() != rettype) {
|
||||
Logger::println("llvmRunTimeHack==true - force casting return value");
|
||||
Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n';
|
||||
retllval = DtoBitCast(retllval, rettype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set calling convention
|
||||
if (dfn && dfn->func) {
|
||||
int li = dfn->func->llvmInternal;
|
||||
if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) {
|
||||
// set calling convention
|
||||
if (dfn && dfn->func) {
|
||||
int li = dfn->func->llvmInternal;
|
||||
if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
}
|
||||
/*else if (delegateCall) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}*/
|
||||
else if (dfn && dfn->cc != (unsigned)-1) {
|
||||
call->setCallingConv(dfn->cc);
|
||||
}
|
||||
else {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
}
|
||||
/*else if (delegateCall) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}*/
|
||||
else if (dfn && dfn->cc != (unsigned)-1) {
|
||||
call->setCallingConv(dfn->cc);
|
||||
}
|
||||
else {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
|
||||
// param attrs
|
||||
call->setParamAttrs(palist);
|
||||
// param attrs
|
||||
call->setParamAttrs(palist);
|
||||
}
|
||||
else
|
||||
{
|
||||
llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create("postinvoke", p->topfunc(), p->scopeend());
|
||||
llvm::InvokeInst* call = llvm::InvokeInst::Create(funcval, postinvoke, *p->landingPads.rbegin(), llargs.begin(), llargs.end(), varname, p->scopebb());
|
||||
p->scope() = IRScope(postinvoke, p->scopeend());
|
||||
|
||||
|
||||
//FIXME: Code duplication!
|
||||
retllval = (retinptr) ? llargs[0] : call;
|
||||
|
||||
if (retinptr && dfn && dfn->func && dfn->func->runTimeHack) {
|
||||
const LLType* rettype = getPtrToType(DtoType(type));
|
||||
if (retllval->getType() != rettype) {
|
||||
Logger::println("llvmRunTimeHack==true - force casting return value");
|
||||
Logger::cout() << "from: " << *retllval->getType() << " to: " << *rettype << '\n';
|
||||
retllval = DtoBitCast(retllval, rettype);
|
||||
}
|
||||
}
|
||||
|
||||
// set calling convention
|
||||
if (dfn && dfn->func) {
|
||||
int li = dfn->func->llvmInternal;
|
||||
if (li != LLVMintrinsic && li != LLVMva_start && li != LLVMva_intrinsic) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
}
|
||||
/*else if (delegateCall) {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}*/
|
||||
else if (dfn && dfn->cc != (unsigned)-1) {
|
||||
call->setCallingConv(dfn->cc);
|
||||
}
|
||||
else {
|
||||
call->setCallingConv(DtoCallingConv(dlink));
|
||||
}
|
||||
|
||||
// param attrs
|
||||
call->setParamAttrs(palist);
|
||||
}
|
||||
|
||||
return new DImValue(type, retllval, isInPlace);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user