The big catch/finally rework, part 2

Now with *almost* working EH codegen. Does not compile Phobos yet
because we run into the "instruction does not dominate all uses"
issue when an r-value result of toElemDtor is used and we need to
run cleanups in between. Should easily be fixed by promoting those
values to allocas.

Most of the changes outside of ir/irfunction.{h, cpp} are just
because CreateCallOrInvoke moved locations. I took the
opportunity to also make use of the different arg count
overloads where possible.
This commit is contained in:
David Nadlinger 2015-08-19 06:58:20 +02:00
parent 4236ae9ce5
commit 4bcae9731a
23 changed files with 441 additions and 212 deletions

View file

@ -19,6 +19,7 @@
#include "gen/logger.h"
#include "gen/runtime.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irmodule.h"
// returns the keytype typeinfo
@ -68,9 +69,9 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
// valuesize param
LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
ret = gIR->CreateCallOrInvoke4(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction();
ret = gIR->CreateCallOrInvoke(func, aaval, keyti, valsize, pkey, "aa.index").getInstruction();
} else {
ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction();
ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index").getInstruction();
}
// cast return value
@ -92,16 +93,12 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
gIR->scope() = IRScope(failbb);
LLValue* args[] = {
// file param
DtoModuleFileName(gIR->func()->decl->getModule(), loc),
// line param
DtoConstUint(loc.linnum)
};
// call
llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arraybounds");
gIR->CreateCallOrInvoke(errorfn, args);
gIR->CreateCallOrInvoke(
errorfn,
DtoModuleFileName(gIR->func()->decl->getModule(), loc),
DtoConstUint(loc.linnum)
);
// the function does not return
gIR->ir->CreateUnreachable();
@ -147,7 +144,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key)
pkey = DtoBitCast(pkey, getVoidPtrType());
// call runtime
LLValue* ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.in").getInstruction();
LLValue* ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.in").getInstruction();
// cast return value
LLType* targettype = DtoType(type);
@ -191,11 +188,8 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key)
LLValue* pkey = makeLValue(loc, key);
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
// build arg vector
LLValue* args[] = { aaval, keyti, pkey };
// call runtime
LLCallSite call = gIR->CreateCallOrInvoke(func, args);
LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
return new DImValue(Type::tbool, call.getInstruction());
}
@ -212,7 +206,7 @@ LLValue* DtoAAEquals(Loc& loc, TOK op, DValue* l, DValue* r)
LLValue* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1));
LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2));
LLValue* aaTypeInfo = DtoTypeInfoOf(t);
LLValue* res = gIR->CreateCallOrInvoke3(func, aaTypeInfo, aaval, abval, "aaEqRes").getInstruction();
LLValue* res = gIR->CreateCallOrInvoke(func, aaTypeInfo, aaval, abval, "aaEqRes").getInstruction();
res = gIR->ir->CreateICmpNE(res, DtoConstInt(0));
if (op == TOKnotequal)
res = gIR->ir->CreateNot(res);

View file

@ -22,6 +22,7 @@
#include "gen/logger.h"
#include "gen/runtime.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irmodule.h"
static void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr);
@ -206,7 +207,7 @@ static void copySlice(Loc& loc, LLValue* dstarr, LLValue* sz1, LLValue* srcarr,
if (checksEnabled && !knownInBounds)
{
LLValue* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
gIR->CreateCallOrInvoke4(fn, dstarr, sz1, srcarr, sz2);
gIR->CreateCallOrInvoke(fn, dstarr, sz1, srcarr, sz2);
}
else
{
@ -295,12 +296,12 @@ void DtoArrayAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPost
else if (isConstructing)
{
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayctor");
LLValue* args[] = {
LLCallSite call = gIR->CreateCallOrInvoke(
fn,
DtoTypeInfoOf(elemType),
DtoSlice(rhsPtr, rhsLength),
DtoSlice(lhsPtr, lhsLength)
};
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
);
call.setCallingConv(llvm::CallingConv::C);
}
else // assigning
@ -308,13 +309,13 @@ void DtoArrayAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPost
LLValue* tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
LLValue* args[] = {
LLCallSite call = gIR->CreateCallOrInvoke(
fn,
DtoTypeInfoOf(elemType),
DtoSlice(rhsPtr, rhsLength),
DtoSlice(lhsPtr, lhsLength),
DtoBitCast(tmpSwap, getVoidPtrType())
};
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
);
call.setCallingConv(llvm::CallingConv::C);
}
}
@ -338,13 +339,13 @@ void DtoArrayAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPost
{
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
isConstructing ? "_d_arraysetctor" : "_d_arraysetassign");
LLValue* args[] = {
LLCallSite call = gIR->CreateCallOrInvoke(
fn,
lhsPtr,
DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
gIR->ir->CreateTruncOrBitCast(lhsLength, LLType::getInt32Ty(gIR->context())),
DtoTypeInfoOf(stripModifiers(t2))
};
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
);
call.setCallingConv(llvm::CallingConv::C);
}
}
@ -648,7 +649,7 @@ DSliceValue* DtoNewDynArray(Loc& loc, Type* arrayType, DValue* dim, bool default
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, fnname);
// call allocator
LLValue* newArray = gIR->CreateCallOrInvoke2(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction();
LLValue* newArray = gIR->CreateCallOrInvoke(fn, arrayTypeInfo, arrayLen, ".gc_mem").getInstruction();
return getSlice(arrayType, newArray);
}
@ -709,13 +710,12 @@ DSliceValue* DtoNewMulDimDynArray(Loc& loc, Type* arrayType, DValue** dims, size
DtoStore(DtoConstSize_t(ndims), DtoGEPi(darray, 0, 0, ".len"));
DtoStore(DtoBitCast(array, getPtrToType(DtoSize_t())), DtoGEPi(darray, 0, 1, ".ptr"));
llvm::Value* args[] = {
arrayTypeInfo,
DtoLoad(darray)
};
// call allocator
LLValue* newptr = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction();
LLValue* newptr = gIR->CreateCallOrInvoke(fn,
arrayTypeInfo,
DtoLoad(darray),
".gc_mem"
).getInstruction();
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
@ -739,12 +739,13 @@ DSliceValue* DtoResizeDynArray(Loc& loc, Type* arrayType, DValue* array, LLValue
// call runtime
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT" : "_d_arraysetlengthiT" );
LLValue* args[] = {
LLValue* newArray = gIR->CreateCallOrInvoke(
fn,
DtoTypeInfoOf(arrayType),
newdim,
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2))
};
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction();
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2)),
".gc_mem")
.getInstruction();
return getSlice(arrayType, newArray);
}
@ -765,13 +766,13 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e
DValue *expVal = toElem(exp);
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendcTX");
LLValue* args[] = {
LLValue* appendedArray = gIR->CreateCallOrInvoke(
fn,
DtoTypeInfoOf(arrayType),
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(1)),
DtoConstSize_t(1)
};
LLValue* appendedArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
DtoConstSize_t(1),
".appendedArray"
).getInstruction();
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
LLValue* val = DtoArrayPtr(array);
@ -788,20 +789,15 @@ DSliceValue* DtoCatAssignArray(Loc& loc, DValue* arr, Expression* exp)
LOG_SCOPE;
Type *arrayType = arr->getType();
// Prepare arguments
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
LLSmallVector<LLValue*,3> args;
// TypeInfo ti
args.push_back(DtoTypeInfoOf(arrayType));
// byte[] *px
args.push_back(DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(1)));
// byte[] y
LLValue *y = DtoSlice(toElem(exp));
y = DtoAggrPaint(y, fn->getFunctionType()->getParamType(2));
args.push_back(y);
// Call _d_arrayappendT
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
LLValue* newArray = gIR->CreateCallOrInvoke(
fn,
DtoTypeInfoOf(arrayType),
DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(1)),
DtoAggrPaint(DtoSlice(toElem(exp)), fn->getFunctionType()->getParamType(2)),
".appendedArray"
).getInstruction();
return getSlice(arrayType, newArray);
}
@ -873,7 +869,7 @@ DSliceValue* DtoCatArrays(Loc& loc, Type* arrayType, Expression* exp1, Expressio
args.push_back(val);
}
LLValue *newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
LLValue *newArray = gIR->func()->scopes->callOrInvoke(fn, args, ".appendedArray").getInstruction();
return getSlice(arrayType, newArray);
}
@ -886,15 +882,13 @@ DSliceValue* DtoAppendDChar(Loc& loc, DValue* arr, Expression* exp, const char *
// Prepare arguments
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, func);
LLValue* args[] = {
// ref string x
DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(0)),
// dchar c
DtoBitCast(valueToAppend->getRVal(), fn->getFunctionType()->getParamType(1))
};
// Call function
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
// Call function (ref string x, dchar c)
LLValue* newArray = gIR->CreateCallOrInvoke(fn,
DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(0)),
DtoBitCast(valueToAppend->getRVal(), fn->getFunctionType()->getParamType(1)),
".appendedArray"
).getInstruction();
return getSlice(arrayType, newArray);
}
@ -946,9 +940,7 @@ static LLValue* DtoArrayEqCmp_impl(Loc& loc, const char* func, DValue* l, DValue
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
}
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
return call.getInstruction();
return gIR->func()->scopes->callOrInvoke(fn, args).getInstruction();
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -998,14 +990,13 @@ LLValue* DtoArrayCastLength(Loc& loc, LLValue* len, LLType* elemty, LLType* newe
if (esz == nsz)
return len;
LLValue* args[] = {
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
return gIR->CreateCallOrInvoke(
fn,
len,
LLConstantInt::get(DtoSize_t(), esz, false),
LLConstantInt::get(DtoSize_t(), nsz, false)
};
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
return gIR->CreateCallOrInvoke(fn, args).getInstruction();
).getInstruction();
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -1241,19 +1232,12 @@ void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBoun
gIR->scope() = IRScope(failbb);
std::vector<LLValue*> args;
// file param
Module* funcmodule = gIR->func()->decl->getModule();
args.push_back(DtoModuleFileName(funcmodule, loc));
// line param
LLConstant* c = DtoConstUint(loc.linnum);
args.push_back(c);
// call
llvm::Function* errorfn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arraybounds");
gIR->CreateCallOrInvoke(errorfn, args);
gIR->CreateCallOrInvoke(
errorfn,
DtoModuleFileName(gIR->func()->decl->getModule(), loc),
DtoConstUint(loc.linnum)
);
// the function does not return
gIR->ir->CreateUnreachable();

View file

@ -37,6 +37,7 @@
#include "gen/logger.h"
#include "gen/llvmhelpers.h"
#include "gen/functions.h"
#include "ir/irfunction.h"
typedef enum {
Arg_Integer,

View file

@ -26,6 +26,7 @@
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "ir/iraggr.h"
#include "ir/irfunction.h"
#include "ir/irtypeclass.h"
//////////////////////////////////////////////////////////////////////////////////////////
@ -193,12 +194,9 @@ void DtoFinalizeClass(Loc& loc, LLValue* inst)
{
// get runtime function
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_callfinalizer");
// build args
LLValue* arg[] = {
DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")
};
// call
gIR->CreateCallOrInvoke(fn, arg, "");
gIR->CreateCallOrInvoke(fn,
DtoBitCast(inst, fn->getFunctionType()->getParamType(0)), "");
}
//////////////////////////////////////////////////////////////////////////////////////////
@ -352,7 +350,7 @@ DValue* DtoDynamicCastObject(Loc& loc, DValue* val, Type* _to)
assert(funcTy->getParamType(1) == cinfo->getType());
// call it
LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo).getInstruction();
LLValue* ret = gIR->CreateCallOrInvoke(func, obj, cinfo).getInstruction();
// cast return value
ret = DtoBitCast(ret, DtoType(_to));
@ -412,7 +410,7 @@ DValue* DtoDynamicCastInterface(Loc& loc, DValue* val, Type* _to)
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
// call it
LLValue* ret = gIR->CreateCallOrInvoke2(func, ptr, cinfo).getInstruction();
LLValue* ret = gIR->CreateCallOrInvoke(func, ptr, cinfo).getInstruction();
// cast return value
ret = DtoBitCast(ret, DtoType(_to));

View file

@ -15,6 +15,7 @@
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "gen/optimizer.h"
#include "ir/irfunction.h"
#include "ir/irtypeaggr.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/FileSystem.h"

View file

@ -32,6 +32,7 @@
#include "gen/pragma.h"
#include "gen/runtime.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irmodule.h"
#if LDC_LLVM_VER >= 303
#include "llvm/IR/Intrinsics.h"

View file

@ -13,6 +13,7 @@
#include "statement.h"
#include "gen/llvm.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include <cstdarg>
IRState* gIR = 0;
@ -94,31 +95,31 @@ bool IRState::scopereturned()
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name)
{
LLSmallVector<LLValue*, 1> args;
return CreateCallOrInvoke(Callee, args, Name);
return func()->scopes->callOrInvoke(Callee, args, Name);
}
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name)
{
LLValue* args[] = { Arg1 };
return CreateCallOrInvoke(Callee, args, Name);
return func()->scopes->callOrInvoke(Callee, args, Name);
}
LLCallSite IRState::CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name)
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name)
{
LLValue* args[] = { Arg1, Arg2 };
return CreateCallOrInvoke(Callee, args, Name);
return func()->scopes->callOrInvoke(Callee, args, Name);
}
LLCallSite IRState::CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name)
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name)
{
LLValue* args[] = { Arg1, Arg2, Arg3 };
return CreateCallOrInvoke(Callee, args, Name);
return func()->scopes->callOrInvoke(Callee, args, Name);
}
LLCallSite IRState::CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name)
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name)
{
LLValue* args[] = { Arg1, Arg2, Arg3, Arg4 };
return CreateCallOrInvoke(Callee, args, Name);
return func()->scopes->callOrInvoke(Callee, args, Name);
}
bool IRState::emitArrayBoundsChecks()

View file

@ -17,7 +17,6 @@
#include "aggregate.h"
#include "root.h"
#include "ir/irfunction.h"
#include "ir/iraggr.h"
#include "ir/irvar.h"
#include "gen/dibuilder.h"
@ -60,6 +59,7 @@ class TypeStruct;
struct BaseClass;
class AnonDeclaration;
struct IrFunction;
struct IrModule;
// represents a scope
@ -148,14 +148,11 @@ struct IRState
bool scopereturned();
// create a call or invoke, depending on the landing pad info
// the template function is defined further down in this file
template <typename T>
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const T& args, const char* Name="");
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, const char* Name="");
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name="");
llvm::CallSite CreateCallOrInvoke2(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name="");
llvm::CallSite CreateCallOrInvoke3(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name="");
llvm::CallSite CreateCallOrInvoke4(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name="");
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, const char* Name="");
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, const char* Name="");
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, LLValue* Arg2, LLValue* Arg3, LLValue* Arg4, const char* Name="");
// this holds the array being indexed or sliced so $ will work
// might be a better way but it works. problem is I only get a
@ -198,40 +195,6 @@ struct IRState
#endif
};
template <typename T>
llvm::CallSite IRState::CreateCallOrInvoke(LLValue* Callee, const T &args, const char* Name)
{
//ScopeStack& funcGen = *func()->scopes;
LLFunction* fn = llvm::dyn_cast<LLFunction>(Callee);
/*const bool hasTemporaries = funcGen.hasTemporariesToDestruct();
// intrinsics don't support invoking and 'nounwind' functions don't need it.
const bool doesNotThrow = (fn && (fn->isIntrinsic() || fn->doesNotThrow()));
if (doesNotThrow || (!hasTemporaries && funcGen.landingPad == NULL))
{*/
llvm::CallInst* call = ir->CreateCall(Callee, args, Name);
if (fn)
call->setAttributes(fn->getAttributes());
return call;
/*}
if (hasTemporaries)
funcGen.prepareToDestructAllTemporariesOnThrow(this);
llvm::BasicBlock* landingPad = funcGen.landingPad;
llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(context(), "postinvoke", topfunc(), landingPad);
llvm::InvokeInst* invoke = ir->CreateInvoke(Callee, postinvoke, landingPad, args, Name);
if (fn)
invoke->setAttributes(fn->getAttributes());
if (hasTemporaries)
funcGen.landingPadInfo.pop();
scope() = IRScope(postinvoke);
return invoke;*/
}
void Statement_toIR(Statement *s, IRState *irs);
#endif // LDC_GEN_IRSTATE_H

View file

@ -29,6 +29,7 @@
#include "gen/tollvm.h"
#include "gen/typeinf.h"
#include "gen/abi.h"
#include "ir/irfunction.h"
#include "ir/irmodule.h"
#include "ir/irtypeaggr.h"
#include "llvm/MC/MCAsmInfo.h"
@ -85,40 +86,34 @@ LLValue* DtoNewStruct(Loc& loc, TypeStruct* newtype)
void DtoDeleteMemory(Loc& loc, DValue* ptr)
{
// get runtime function
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delmemory");
// build args
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
// call
gIR->CreateCallOrInvoke(fn, arg);
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteStruct(Loc& loc, DValue* ptr)
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delstruct");
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
LLValue* arg[] = {
gIR->CreateCallOrInvoke(
fn,
DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
DtoBitCast(DtoTypeInfoOf(ptr->type->nextOf()), fn->getFunctionType()->getParamType(1))
};
gIR->CreateCallOrInvoke(fn, arg);
);
}
void DtoDeleteClass(Loc& loc, DValue* inst)
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delclass");
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
gIR->CreateCallOrInvoke(fn, arg);
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteInterface(Loc& loc, DValue* inst)
{
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delinterface");
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
gIR->CreateCallOrInvoke(fn, arg);
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
}
void DtoDeleteArray(Loc& loc, DValue* arr)
@ -132,11 +127,11 @@ void DtoDeleteArray(Loc& loc, DValue* arr)
LLValue* typeInfo = (!hasDtor ? getNullPtr(fty->getParamType(1)) : DtoTypeInfoOf(elementType));
LLValue* lval = (arr->isLVal() ? arr->getLVal() : makeLValue(loc, arr));
LLValue* arg[] = {
gIR->CreateCallOrInvoke(
fn,
DtoBitCast(lval, fty->getParamType(0)),
DtoBitCast(typeInfo, fty->getParamType(1))
};
gIR->CreateCallOrInvoke(fn, arg);
);
}
/****************************************************************************************/
@ -206,7 +201,7 @@ void DtoAssert(Module* M, Loc& loc, DValue* msg)
args.push_back(DtoConstUint(loc.linnum));
// call
gIR->CreateCallOrInvoke(fn, args);
gIR->func()->scopes->callOrInvoke(fn, args);
// after assert is always unreachable
gIR->ir->CreateUnreachable();

View file

@ -36,6 +36,7 @@
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "ir/irdsymbol.h"
#include "ir/irfunction.h"
#include "ir/irmodule.h"
#include "ir/irtype.h"
#include "ir/irvar.h"

View file

@ -17,6 +17,7 @@
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#if LDC_LLVM_VER >= 303
#include "llvm/IR/InlineAsm.h"
#else

View file

@ -15,9 +15,8 @@
#include "gen/llvmhelpers.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Support/CommandLine.h"
namespace cl = llvm::cl;
/****************************************************************************************/
/*////////////////////////////////////////////////////////////////////////////////////////

View file

@ -18,6 +18,7 @@
#include "gen/llvmhelpers.h"
#include "gen/tollvm.h"
#include "ir/iraggr.h"
#include "ir/irfunction.h"
RTTIBuilder::RTTIBuilder(AggregateDeclaration* base_class)
{

View file

@ -98,7 +98,7 @@ static LLValue* call_string_switch_runtime(llvm::Value* table, Expression* e)
LLValue* llval = val->getRVal();
assert(llval->getType() == fn->getFunctionType()->getParamType(1));
LLCallSite call = gIR->CreateCallOrInvoke2(fn, table, llval);
LLCallSite call = gIR->CreateCallOrInvoke(fn, table, llval);
return call.getInstruction();
}
@ -734,11 +734,35 @@ public:
// For catches that use the Throwable object, create storage for it.
// We will set it in the code that branches from the landing pads
// (there might be more than one) to catchBlock.
llvm::Value* exceptionVar = 0;
if ((*it)->var) {
llvm::Value* ehPtr = irs->func()->getOrCreateEhPtrSlot();
#if LDC_LLVM_VER >= 305
if (!global.params.targetTriple.isWindowsMSVCEnvironment())
#endif
{
// ehPtr is a pointer to _d_exception, which has a reference
// to the Throwable object at offset 0.
ehPtr = irs->ir->CreateLoad(ehPtr);
}
llvm::Type* llCatchVarType = DtoType((*it)->var->type); // e.g., Throwable*
// Use the same storage for all exceptions that are not accessed in
// nested functions
if (!(*it)->var->nestedrefs.dim) {
assert(!isIrLocalCreated((*it)->var));
IrLocal* irLocal = getIrLocal((*it)->var, true);
irLocal->value = DtoBitCast(ehPtr, getPtrToType(llCatchVarType));
} else {
// This will alloca if we haven't already and take care of nested refs
DtoDeclarationExp((*it)->var);
IrLocal* irLocal = getIrLocal((*it)->var);
exceptionVar = irLocal->value;
// Copy the exception reference over from ehPtr
llvm::Value* exc = DtoLoad(DtoBitCast(ehPtr, llCatchVarType->getPointerTo()));
DtoStore(exc, irLocal->value);
}
}
// emit handler, if there is one
@ -758,8 +782,7 @@ public:
DtoResolveClass(catchType);
irs->func()->scopes->pushCatch(
getIrAggr(catchType)->getClassInfoSymbol(), exceptionVar,
catchBlock);
getIrAggr(catchType)->getClassInfoSymbol(), catchBlock);
}
// Emit the try block.
@ -895,7 +918,7 @@ public:
inits[i] = toConstElem(c->str, irs);
}
// build static array for ptr or final array
LLType* elemTy = DtoType(stmt->condition->type);
llvm::Type* elemTy = DtoType(stmt->condition->type);
LLArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size());
LLConstant* arrInit = LLConstantArray::get(arrTy, inits);
LLGlobalVariable* arr = new llvm::GlobalVariable(irs->module, arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, ".string_switch_table_data");
@ -1464,15 +1487,11 @@ public:
LLValue *moduleInfoSymbol = getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
LLValue* args[] = {
// module param
LLCallSite call = irs->CreateCallOrInvoke(
fn,
DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType)),
// line param
DtoConstUint(stmt->loc.linnum)
};
// call
LLCallSite call = irs->CreateCallOrInvoke(fn, args);
);
call.setDoesNotReturn();
}

View file

@ -21,6 +21,7 @@
#include "gen/logger.h"
#include "gen/nested.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irtype.h"
//////////////////////////////////////////////////////////////////////////////////////////
@ -426,7 +427,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
addExplicitArguments(args, attrs, irFty, callableTy, argvals, numFormalParams);
// call the function
LLCallSite call = gIR->CreateCallOrInvoke(callable, args);
LLCallSite call = gIR->func()->scopes->callOrInvoke(callable, args);
// get return value
LLValue* retllval = (retinptr) ? args[0] : call.getInstruction();

View file

@ -16,6 +16,7 @@
#include "gen/logger.h"
#include "gen/structs.h"
#include "gen/tollvm.h"
#include "ir/irfunction.h"
#include "ir/irtypeclass.h"
#include "ir/irtypestruct.h"

View file

@ -37,6 +37,7 @@
#include "gen/tollvm.h"
#include "gen/typeinf.h"
#include "gen/warnings.h"
#include "ir/irfunction.h"
#include "ir/irtypeclass.h"
#include "ir/irtypestruct.h"
#include "llvm/Support/CommandLine.h"
@ -3005,7 +3006,7 @@ public:
slice = DtoConstSlice(DtoConstSize_t(e->keys->dim), slice);
LLValue* valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
LLValue* aa = gIR->CreateCallOrInvoke3(func, aaTypeInfo, keysArray, valuesArray, "aa").getInstruction();
LLValue* aa = gIR->CreateCallOrInvoke(func, aaTypeInfo, keysArray, valuesArray, "aa").getInstruction();
if (basetype->ty != Taarray) {
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
DtoStore(aa, DtoGEPi(tmp, 0, 0));

View file

@ -22,6 +22,11 @@
// DMD forward declarations
class StructInitializer;
namespace llvm {
class Constant;
class StructType;
}
//////////////////////////////////////////////////////////////////////////////
// represents a struct or class
@ -44,22 +49,22 @@ struct IrAggr
//////////////////////////////////////////////////////////////////////////
/// Create the __initZ symbol lazily.
LLGlobalVariable* getInitSymbol();
llvm::GlobalVariable* getInitSymbol();
/// Builds the __initZ initializer constant lazily.
LLConstant* getDefaultInit();
llvm::Constant* getDefaultInit();
/// Create the __vtblZ symbol lazily.
LLGlobalVariable* getVtblSymbol();
llvm::GlobalVariable* getVtblSymbol();
/// Builds the __vtblZ initializer constant lazily.
LLConstant* getVtblInit();
llvm::Constant* getVtblInit();
/// Create the __ClassZ/__InterfaceZ symbol lazily.
LLGlobalVariable* getClassInfoSymbol();
llvm::GlobalVariable* getClassInfoSymbol();
/// Builds the __ClassZ/__InterfaceZ initializer constant lazily.
LLConstant* getClassInfoInit();
llvm::Constant* getClassInfoInit();
/// Create the __interfaceInfos symbol lazily.
LLGlobalVariable* getInterfaceArraySymbol();
llvm::GlobalVariable* getInterfaceArraySymbol();
//////////////////////////////////////////////////////////////////////////
@ -87,21 +92,21 @@ struct IrAggr
protected:
/// Static default initializer global.
LLGlobalVariable* init;
llvm::GlobalVariable* init;
/// Static default initializer constant.
LLConstant* constInit;
llvm::Constant* constInit;
/// Static default initialier type.
LLStructType* init_type;
llvm::StructType* init_type;
/// Vtbl global.
LLGlobalVariable* vtbl;
llvm::GlobalVariable* vtbl;
/// Vtbl initializer constant.
LLConstant* constVtbl;
llvm::Constant* constVtbl;
/// ClassInfo global.
LLGlobalVariable* classInfo;
llvm::GlobalVariable* classInfo;
/// ClassInfo initializer constant.
LLConstant* constClassInfo;
llvm::Constant* constClassInfo;
/// Map for mapping ClassDeclaration* to LLVM GlobalVariable.
typedef std::map<ClassDeclaration*, llvm::GlobalVariable*> ClassGlobalMap;
@ -130,10 +135,10 @@ protected:
size_t interfaces_index);
// FIXME make this a member instead
friend LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
friend llvm::Constant* DtoDefineClassInfo(ClassDeclaration* cd);
/// Create the Interface[] interfaces ClassInfo field initializer.
LLConstant* getClassInfoInterfaces();
llvm::Constant* getClassInfoInterfaces();
/// Returns true, if the LLVM struct type for the aggregate is declared as packed
bool isPacked() const;

View file

@ -35,6 +35,7 @@
#include "gen/functions.h"
#include "ir/iraggr.h"
#include "ir/irfunction.h"
#include "ir/irtypeclass.h"
//////////////////////////////////////////////////////////////////////////////

View file

@ -10,6 +10,7 @@
#include "gen/llvm.h"
#include "gen/llvmhelpers.h"
#include "gen/irstate.h"
#include "gen/runtime.h"
#include "gen/tollvm.h"
#include "ir/irdsymbol.h"
#include "ir/irfunction.h"
@ -120,12 +121,14 @@ void ScopeStack::pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* end
cleanupScopes.push_back(CleanupScope(beginBlock, endBlock));
}
void ScopeStack::runCleanups(CleanupCursor targetScope,
void ScopeStack::runCleanups(
CleanupCursor sourceScope,
CleanupCursor targetScope,
llvm::BasicBlock* continueWith
) {
assert(targetScope <= currentCleanupScope());
assert(targetScope <= sourceScope);
if (targetScope == currentCleanupScope()) {
if (targetScope == sourceScope) {
// No cleanups to run, just branch to the next block.
llvm::BranchInst::Create(continueWith, irs->scopebb());
return;
@ -136,7 +139,7 @@ void ScopeStack::runCleanups(CleanupCursor targetScope,
// Update all the control flow in the cleanups to make sure we end up where
// we want.
for (CleanupCursor i = currentCleanupScope(); i-- > targetScope;) {
for (CleanupCursor i = sourceScope; i-- > targetScope;) {
llvm::BasicBlock *nextBlock = (i > targetScope) ?
cleanupScopes[i - 1].beginBlock : continueWith;
executeCleanup(irs, cleanupScopes[i], irs->scopebb(), nextBlock);
@ -177,6 +180,18 @@ void ScopeStack::popCleanups(CleanupCursor targetScope) {
}
}
void ScopeStack::pushCatch(llvm::Constant* classInfoPtr,
llvm::BasicBlock* bodyBlock
) {
catchScopes.push_back({classInfoPtr, bodyBlock, currentCleanupScope()});
currentLandingPads().push_back(0);
}
void ScopeStack::popCatch() {
catchScopes.pop_back();
currentLandingPads().pop_back();
}
void ScopeStack::pushLoopTarget(Statement* loopStatement, llvm::BasicBlock* continueTarget,
llvm::BasicBlock* breakTarget
) {
@ -261,6 +276,127 @@ std::vector<GotoJump>& ScopeStack::currentUnresolvedGotos() {
cleanupScopes.back().unresolvedGotos;
}
std::vector<llvm::BasicBlock*>& ScopeStack::currentLandingPads() {
return cleanupScopes.empty() ?
topLevelLandingPads :
cleanupScopes.back().landingPads;
}
namespace {
llvm::LandingPadInst* createLandingPadInst(IRState *irs) {
LLType* retType = LLStructType::get(LLType::getInt8PtrTy(irs->context()),
LLType::getInt32Ty(irs->context()),
NULL);
#if LDC_LLVM_VER >= 307
LLFunction* currentFunction = irs->func()->func;
if (!currentFunction->hasPersonalityFn()) {
LLFunction* personalityFn = LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
currentFunction->setPersonalityFn(personalityFn);
}
return irs->ir->CreateLandingPad(retType, 0);
#else
LLFunction* personalityFn = LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
return irs->ir->CreateLandingPad(retType, personalityFn, 0);
#endif
}
}
llvm::BasicBlock* ScopeStack::emitLandingPad() {
// save and rewrite scope
IRScope savedIRScope = irs->scope();
llvm::BasicBlock *beginBB = llvm::BasicBlock::Create(irs->context(),
"landingPad", irs->topfunc());
irs->scope() = IRScope(beginBB);
llvm::LandingPadInst *landingPad = createLandingPadInst(irs);
// Stash away the exception object pointer and selector value into their
// stack slots.
llvm::Value* ehPtr = DtoExtractValue(landingPad, 0);
if (!irs->func()->resumeUnwindBlock) {
irs->func()->resumeUnwindBlock = llvm::BasicBlock::Create(
irs->context(),
"unwind.resume",
irs->topfunc()
);
llvm::BasicBlock *oldBB = irs->scopebb();
irs->scope() = IRScope(irs->func()->resumeUnwindBlock);
llvm::Function* resumeFn = LLVM_D_GetRuntimeFunction(Loc(),
irs->module, "_d_eh_resume_unwind");
irs->ir->CreateCall(resumeFn,
irs->ir->CreateLoad(irs->func()->getOrCreateEhPtrSlot()));
irs->ir->CreateUnreachable();
irs->scope() = IRScope(oldBB);
}
irs->ir->CreateStore(ehPtr, irs->func()->getOrCreateEhPtrSlot());
llvm::Value* ehSelector = DtoExtractValue(landingPad, 1);
if (!irs->func()->ehSelectorSlot) {
irs->func()->ehSelectorSlot =
DtoRawAlloca(ehSelector->getType(), 0, "eh.selector");
}
irs->ir->CreateStore(ehSelector, irs->func()->ehSelectorSlot);
// Add landingpad clauses, emit finallys and 'if' chain to catch the exception,
CleanupCursor lastCleanup = currentCleanupScope();
for (std::vector<CatchScope>::reverse_iterator it = catchScopes.rbegin(),
end = catchScopes.rend();
it != end; ++it
) {
// Insert any cleanups in between the last catch we ran and this one.
if (lastCleanup > it->cleanupScope) {
landingPad->setCleanup(true);
llvm::BasicBlock* afterCleanupBB = llvm::BasicBlock::Create(
irs->context(),
beginBB->getName() + llvm::Twine(".after.cleanup"),
irs->topfunc()
);
runCleanups(lastCleanup, it->cleanupScope, afterCleanupBB);
irs->scope() = IRScope(afterCleanupBB);
lastCleanup = it->cleanupScope;
}
// Add the ClassInfo reference to the landingpad instruction so it is
// emitted to the EH tables.
landingPad->addClause(it->classInfoPtr);
llvm::BasicBlock *mismatchBB = llvm::BasicBlock::Create(
irs->context(),
beginBB->getName() + llvm::Twine(".mismatch"),
irs->topfunc()
);
// "Call" llvm.eh.typeid.for, which gives us the eh selector value to compare with
llvm::Value *ehTypeId = irs->ir->CreateCall(GET_INTRINSIC_DECL(eh_typeid_for),
DtoBitCast(it->classInfoPtr, getVoidPtrType()));
// Compare the selector value from the unwinder against the expected
// one and branch accordingly.
irs->ir->CreateCondBr(
irs->ir->CreateICmpEQ(
irs->ir->CreateLoad(irs->func()->ehSelectorSlot), ehTypeId),
it->bodyBlock,
mismatchBB
);
irs->scope() = IRScope(mismatchBB);
}
// No catch matched. Execute all finallys and resume unwinding.
if (lastCleanup > 0) {
landingPad->setCleanup(true);
runCleanups(lastCleanup, 0, irs->func()->resumeUnwindBlock);
} else {
irs->ir->CreateBr(irs->func()->resumeUnwindBlock);
}
irs->scope() = savedIRScope;
return beginBB;
}
IrFunction::IrFunction(FuncDeclaration* fd)
{
decl = fd;
@ -288,6 +424,10 @@ IrFunction::IrFunction(FuncDeclaration* fd)
retValSlot = NULL;
retBlock = NULL;
ehPtrSlot = NULL;
resumeUnwindBlock = NULL;
ehSelectorSlot = NULL;
}
void IrFunction::setNeverInline()
@ -318,6 +458,13 @@ void IrFunction::setAlwaysInline()
#endif
}
llvm::AllocaInst* IrFunction::getOrCreateEhPtrSlot() {
if (!ehPtrSlot) {
ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
}
return ehPtrSlot;
}
IrFunction *getIrFunc(FuncDeclaration *decl, bool create)
{
if (!isIrFuncCreated(decl) && create)

View file

@ -19,6 +19,7 @@
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DenseMapInfo.h"
#include "gen/llvm.h"
#include "gen/irstate.h"
#include "ir/irfuncty.h"
#include <map>
#include <stack>
@ -26,7 +27,6 @@
class Identifier;
class Statement;
struct IRState;
/// Represents a position on the stack of currently active cleanup scopes.
///
@ -105,7 +105,7 @@ public:
beginBlock(beginBlock), endBlock(endBlock), branchSelector(0) {}
/// The basic block to branch to for running the cleanup.
llvm::BasicBlock* beginBlock;
llvm::BasicBlock* const beginBlock;
/// The basic block that contains the end of the cleanuip code (is different
/// from beginBlock if the cleanup contains control flow).
@ -123,6 +123,24 @@ public:
/// have not found the label yet (because it occurs lexically later in the
/// function).
std::vector<GotoJump> unresolvedGotos;
/// Caches landing pads generated for catches at this cleanup scope level
/// (null if not yet emitted, one element is pushed to/popped from the back
/// on entering/leaving a catch block).
std::vector<llvm::BasicBlock*> landingPads;
};
///
struct CatchScope {
/// The ClassInfo reference corresponding to the type to match the
/// exception object against.
llvm::Constant* classInfoPtr;
/// The block to branch to if the exception type matches.
llvm::BasicBlock* bodyBlock;
/// The cleanup scope level corresponding to this catch.
CleanupCursor cleanupScope;
};
/// Contains transitory information about the current scope, etc. while
@ -140,20 +158,24 @@ public:
void pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* endBlock);
/// Terminates the current IRScope with a branch to the cleanups needed for
/// leaving the given scope and continuing execution at the target scope
/// leaving the current scope and continuing execution at the target scope
/// stack level.
///
/// After running them, execution will branch to the given basic block.
void runCleanups(CleanupCursor targetScope, llvm::BasicBlock* continueWith);
void runCleanups(CleanupCursor targetScope, llvm::BasicBlock* continueWith) {
runCleanups(currentCleanupScope(), targetScope, continueWith);
}
/// Like #runCleanups(), but runs all of them.
void runAllCleanups(llvm::BasicBlock* continueWith);
/// Pops all the cleanups between the current scope and the target cursor.
///
/// This does not insert any cleanup calls, use #runCleanups() beforehand.
void popCleanups(CleanupCursor targetScope);
/// Returns a cursor that identifies the curernt cleanup scope, to be later
/// userd with #popCleanups() et al.
/// userd with #runCleanups() et al.
///
/// Note that this cursor is only valid as long as the current scope is not
/// popped.
@ -166,11 +188,16 @@ public:
#endif
///
void pushCatch(llvm::Value* classInfoPtr, llvm::Value* exceptionVar,
llvm::BasicBlock* bodyBlock) {}
void pushCatch(llvm::Constant* classInfoPtr, llvm::BasicBlock* bodyBlock);
///
void popCatch() {}
void popCatch();
/// Emits a call or invoke to the given callee, depending on whether there
/// are catches/cleanups active or not.
template <typename T>
llvm::CallSite callOrInvoke(llvm::Value* callee, const T &args,
const char* name = "");
///
void pushLoopTarget(Statement* loopStatement, llvm::BasicBlock* continueTarget,
@ -213,12 +240,26 @@ public:
}
private:
/// Internal version that allows specifying the scope at which to start
/// emitting the cleanups.
void runCleanups(CleanupCursor sourceScope, CleanupCursor targetScope,
llvm::BasicBlock* continueWith);
std::vector<GotoJump>& currentUnresolvedGotos();
std::vector<llvm::BasicBlock*>& currentLandingPads();
/// Emits a landing pad to honor all the active cleanups and catches.
llvm::BasicBlock* emitLandingPad();
/// Unified implementation for labeled break/continue.
void jumpToStatement(std::vector<JumpTarget>& targets, Statement* loopOrSwitchStatement);
/// Unified implementation for unlabeled break/continue.
void jumpToClosest(std::vector<JumpTarget>& targets);
/// The ambient IRState. For legacy reasons, there is currently a cyclic
/// dependency between the two.
IRState *irs;
typedef llvm::DenseMap<Identifier*, JumpTarget> LabelTargetMap;
@ -235,12 +276,20 @@ private:
///
std::vector<CleanupScope> cleanupScopes;
///
std::vector<CatchScope> catchScopes;
/// Gotos which we were not able to resolve to any cleanup scope, but which
/// might still be defined later in the function at top level. If there are
/// any left on function exit, it is an error (e.g. because the user tried
/// to goto into a finally block, etc.).
std::vector<GotoJump> topLevelUnresolvedGotos;
/// Caches landing pads generated for catches without any cleanups to run
/// (null if not yet emitted, one element is pushed to/popped from the back
/// on entering/leaving a catch block).
std::vector<llvm::BasicBlock*> topLevelLandingPads;
#if 0
/// To be able to handle the broken AST the frontend produces in some cases
/// for temporary constructor calls, we need to be able to temporarily
@ -251,6 +300,49 @@ private:
#endif
};
template <typename T>
llvm::CallSite ScopeStack::callOrInvoke(llvm::Value* callee, const T &args,
const char* name
) {
// If this is a direct call, we might be able to use the callee attributes
// to our advantage.
llvm::Function* calleeFn = llvm::dyn_cast<llvm::Function>(callee);
// Intrinsics don't support invoking and 'nounwind' functions don't need it.
const bool doesNotThrow = calleeFn &&
(calleeFn->isIntrinsic() || calleeFn->doesNotThrow());
if (doesNotThrow || (cleanupScopes.empty() && catchScopes.empty())) {
llvm::CallInst* call = irs->ir->CreateCall(callee, args, name);
if (calleeFn) {
call->setAttributes(calleeFn->getAttributes());
}
return call;
}
if (currentLandingPads().empty()) {
// Have not encountered.
currentLandingPads().push_back(0);
}
llvm::BasicBlock*& landingPad = currentLandingPads().back();
if (!landingPad) {
landingPad = emitLandingPad();
}
llvm::BasicBlock* postinvoke = llvm::BasicBlock::Create(irs->context(),
"postinvoke", irs->topfunc(), landingPad);
llvm::InvokeInst* invoke = irs->ir->CreateInvoke(callee, postinvoke,
landingPad, args, name);
if (calleeFn) {
invoke->setAttributes(calleeFn->getAttributes());
}
irs->scope() = IRScope(postinvoke);
return invoke;
}
// represents a function
struct IrFunction {
// constructor
@ -260,6 +352,8 @@ struct IrFunction {
void setNeverInline();
void setAlwaysInline();
llvm::AllocaInst* getOrCreateEhPtrSlot();
llvm::Function* func;
llvm::Instruction* allocapoint;
FuncDeclaration* decl;
@ -284,11 +378,26 @@ struct IrFunction {
llvm::Value* _arguments;
llvm::Value* _argptr;
// A stack slot containing the return value, for functions that return by value.
/// A stack slot containing the return value, for functions that return by value.
llvm::AllocaInst* retValSlot;
// The basic block with the return instruction.
/// The basic block with the return instruction.
llvm::BasicBlock* retBlock;
/// A stack slot containing the exception object pointer while a landing pad
/// is active. Need this because the instruction must dominate all uses as a
/// _d_eh_resume_unwind parameter, but if we take a select at the end on a
/// cleanup on the way there, it also must dominate all other precedessors
/// of the cleanup. Thus, we just create an alloca at the start of the
/// function.
llvm::AllocaInst* ehPtrSlot;
/// The basic block with the return instruction. Because of
/// ehPtrSlot, we do not need more than one, so might as well
/// cache it.
llvm::BasicBlock* resumeUnwindBlock;
/// Similar story to ehPtrSlot, but for the selector value.
llvm::AllocaInst* ehSelectorSlot;
#if LDC_LLVM_VER >= 307
llvm::DISubprogram* diSubprogram = nullptr;
std::stack<llvm::DILexicalBlock*> diLexicalBlocks;

View file

@ -7,12 +7,13 @@
//
//===----------------------------------------------------------------------===//
#include "ir/irmodule.h"
#include "module.h"
#include "gen/llvm.h"
#include "gen/irstate.h"
#include "gen/tollvm.h"
#include "ir/irdsymbol.h"
#include "ir/irmodule.h"
#include "ir/irfunction.h"
IrModule::IrModule(Module *module, const char *srcfilename)
: M(module), moduleInfoVar_(0) {}

View file

@ -14,6 +14,10 @@
#ifndef LDC_IR_IRMODULE_H
#define LDC_IR_IRMODULE_H
#include <list>
class FuncDeclaration;
class VarDeclaration;
class Module;
namespace llvm {
class GlobalVariable;