mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
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:
parent
4236ae9ce5
commit
4bcae9731a
23 changed files with 441 additions and 212 deletions
28
gen/aa.cpp
28
gen/aa.cpp
|
@ -19,6 +19,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
|
|
||||||
// returns the keytype typeinfo
|
// returns the keytype typeinfo
|
||||||
|
@ -68,9 +69,9 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
|
||||||
// valuesize param
|
// valuesize param
|
||||||
LLValue* valsize = DtoConstSize_t(getTypePaddedSize(DtoType(type)));
|
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 {
|
} else {
|
||||||
ret = gIR->CreateCallOrInvoke3(func, aaval, keyti, pkey, "aa.index").getInstruction();
|
ret = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey, "aa.index").getInstruction();
|
||||||
}
|
}
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
|
@ -92,16 +93,12 @@ DValue* DtoAAIndex(Loc& loc, Type* type, DValue* aa, DValue* key, bool lvalue)
|
||||||
|
|
||||||
gIR->scope() = IRScope(failbb);
|
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");
|
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
|
// the function does not return
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
|
@ -147,7 +144,7 @@ DValue* DtoAAIn(Loc& loc, Type* type, DValue* aa, DValue* key)
|
||||||
pkey = DtoBitCast(pkey, getVoidPtrType());
|
pkey = DtoBitCast(pkey, getVoidPtrType());
|
||||||
|
|
||||||
// call runtime
|
// 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
|
// cast return value
|
||||||
LLType* targettype = DtoType(type);
|
LLType* targettype = DtoType(type);
|
||||||
|
@ -191,11 +188,8 @@ DValue *DtoAARemove(Loc& loc, DValue* aa, DValue* key)
|
||||||
LLValue* pkey = makeLValue(loc, key);
|
LLValue* pkey = makeLValue(loc, key);
|
||||||
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
|
pkey = DtoBitCast(pkey, funcTy->getParamType(2));
|
||||||
|
|
||||||
// build arg vector
|
|
||||||
LLValue* args[] = { aaval, keyti, pkey };
|
|
||||||
|
|
||||||
// call runtime
|
// call runtime
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(func, args);
|
LLCallSite call = gIR->CreateCallOrInvoke(func, aaval, keyti, pkey);
|
||||||
|
|
||||||
return new DImValue(Type::tbool, call.getInstruction());
|
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* aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1));
|
||||||
LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2));
|
LLValue* abval = DtoBitCast(r->getRVal(), funcTy->getParamType(2));
|
||||||
LLValue* aaTypeInfo = DtoTypeInfoOf(t);
|
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));
|
res = gIR->ir->CreateICmpNE(res, DtoConstInt(0));
|
||||||
if (op == TOKnotequal)
|
if (op == TOKnotequal)
|
||||||
res = gIR->ir->CreateNot(res);
|
res = gIR->ir->CreateNot(res);
|
||||||
|
|
120
gen/arrays.cpp
120
gen/arrays.cpp
|
@ -22,6 +22,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
|
|
||||||
static void DtoSetArray(DValue* array, LLValue* dim, LLValue* ptr);
|
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)
|
if (checksEnabled && !knownInBounds)
|
||||||
{
|
{
|
||||||
LLValue* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -295,12 +296,12 @@ void DtoArrayAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPost
|
||||||
else if (isConstructing)
|
else if (isConstructing)
|
||||||
{
|
{
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||||
LLValue* args[] = {
|
LLCallSite call = gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoTypeInfoOf(elemType),
|
DtoTypeInfoOf(elemType),
|
||||||
DtoSlice(rhsPtr, rhsLength),
|
DtoSlice(rhsPtr, rhsLength),
|
||||||
DtoSlice(lhsPtr, lhsLength)
|
DtoSlice(lhsPtr, lhsLength)
|
||||||
};
|
);
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
|
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
call.setCallingConv(llvm::CallingConv::C);
|
||||||
}
|
}
|
||||||
else // assigning
|
else // assigning
|
||||||
|
@ -308,13 +309,13 @@ void DtoArrayAssign(Loc& loc, DValue* lhs, DValue* rhs, int op, bool canSkipPost
|
||||||
LLValue* tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
LLValue* tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
|
||||||
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
||||||
LLValue* args[] = {
|
LLCallSite call = gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoTypeInfoOf(elemType),
|
DtoTypeInfoOf(elemType),
|
||||||
DtoSlice(rhsPtr, rhsLength),
|
DtoSlice(rhsPtr, rhsLength),
|
||||||
DtoSlice(lhsPtr, lhsLength),
|
DtoSlice(lhsPtr, lhsLength),
|
||||||
DtoBitCast(tmpSwap, getVoidPtrType())
|
DtoBitCast(tmpSwap, getVoidPtrType())
|
||||||
};
|
);
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
|
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
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,
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
|
||||||
isConstructing ? "_d_arraysetctor" : "_d_arraysetassign");
|
isConstructing ? "_d_arraysetctor" : "_d_arraysetassign");
|
||||||
LLValue* args[] = {
|
LLCallSite call = gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
lhsPtr,
|
lhsPtr,
|
||||||
DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
|
DtoBitCast(makeLValue(loc, rhs), getVoidPtrType()),
|
||||||
gIR->ir->CreateTruncOrBitCast(lhsLength, LLType::getInt32Ty(gIR->context())),
|
gIR->ir->CreateTruncOrBitCast(lhsLength, LLType::getInt32Ty(gIR->context())),
|
||||||
DtoTypeInfoOf(stripModifiers(t2))
|
DtoTypeInfoOf(stripModifiers(t2))
|
||||||
};
|
);
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
|
|
||||||
call.setCallingConv(llvm::CallingConv::C);
|
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);
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, fnname);
|
||||||
|
|
||||||
// call allocator
|
// 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);
|
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(DtoConstSize_t(ndims), DtoGEPi(darray, 0, 0, ".len"));
|
||||||
DtoStore(DtoBitCast(array, getPtrToType(DtoSize_t())), DtoGEPi(darray, 0, 1, ".ptr"));
|
DtoStore(DtoBitCast(array, getPtrToType(DtoSize_t())), DtoGEPi(darray, 0, 1, ".ptr"));
|
||||||
|
|
||||||
llvm::Value* args[] = {
|
|
||||||
arrayTypeInfo,
|
|
||||||
DtoLoad(darray)
|
|
||||||
};
|
|
||||||
|
|
||||||
// call allocator
|
// 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';
|
IF_LOG Logger::cout() << "final ptr = " << *newptr << '\n';
|
||||||
|
|
||||||
|
@ -739,12 +739,13 @@ DSliceValue* DtoResizeDynArray(Loc& loc, Type* arrayType, DValue* array, LLValue
|
||||||
// call runtime
|
// call runtime
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT" : "_d_arraysetlengthiT" );
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, zeroInit ? "_d_arraysetlengthT" : "_d_arraysetlengthiT" );
|
||||||
|
|
||||||
LLValue* args[] = {
|
LLValue* newArray = gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoTypeInfoOf(arrayType),
|
DtoTypeInfoOf(arrayType),
|
||||||
newdim,
|
newdim,
|
||||||
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2))
|
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(2)),
|
||||||
};
|
".gc_mem")
|
||||||
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".gc_mem").getInstruction();
|
.getInstruction();
|
||||||
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
@ -765,13 +766,13 @@ void DtoCatAssignElement(Loc& loc, Type* arrayType, DValue* array, Expression* e
|
||||||
DValue *expVal = toElem(exp);
|
DValue *expVal = toElem(exp);
|
||||||
|
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendcTX");
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendcTX");
|
||||||
LLValue* args[] = {
|
LLValue* appendedArray = gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoTypeInfoOf(arrayType),
|
DtoTypeInfoOf(arrayType),
|
||||||
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(1)),
|
DtoBitCast(array->getLVal(), fn->getFunctionType()->getParamType(1)),
|
||||||
DtoConstSize_t(1)
|
DtoConstSize_t(1),
|
||||||
};
|
".appendedArray"
|
||||||
|
).getInstruction();
|
||||||
LLValue* appendedArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
|
|
||||||
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
|
appendedArray = DtoAggrPaint(appendedArray, DtoType(arrayType));
|
||||||
|
|
||||||
LLValue* val = DtoArrayPtr(array);
|
LLValue* val = DtoArrayPtr(array);
|
||||||
|
@ -788,20 +789,15 @@ DSliceValue* DtoCatAssignArray(Loc& loc, DValue* arr, Expression* exp)
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
Type *arrayType = arr->getType();
|
Type *arrayType = arr->getType();
|
||||||
|
|
||||||
// Prepare arguments
|
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
||||||
LLSmallVector<LLValue*,3> args;
|
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
|
||||||
// TypeInfo ti
|
LLValue* newArray = gIR->CreateCallOrInvoke(
|
||||||
args.push_back(DtoTypeInfoOf(arrayType));
|
fn,
|
||||||
// byte[] *px
|
DtoTypeInfoOf(arrayType),
|
||||||
args.push_back(DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(1)));
|
DtoBitCast(arr->getLVal(), fn->getFunctionType()->getParamType(1)),
|
||||||
// byte[] y
|
DtoAggrPaint(DtoSlice(toElem(exp)), fn->getFunctionType()->getParamType(2)),
|
||||||
LLValue *y = DtoSlice(toElem(exp));
|
".appendedArray"
|
||||||
y = DtoAggrPaint(y, fn->getFunctionType()->getParamType(2));
|
).getInstruction();
|
||||||
args.push_back(y);
|
|
||||||
|
|
||||||
// Call _d_arrayappendT
|
|
||||||
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
|
|
||||||
|
|
||||||
return getSlice(arrayType, newArray);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
@ -873,7 +869,7 @@ DSliceValue* DtoCatArrays(Loc& loc, Type* arrayType, Expression* exp1, Expressio
|
||||||
args.push_back(val);
|
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);
|
return getSlice(arrayType, newArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -886,15 +882,13 @@ DSliceValue* DtoAppendDChar(Loc& loc, DValue* arr, Expression* exp, const char *
|
||||||
|
|
||||||
// Prepare arguments
|
// Prepare arguments
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, func);
|
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
|
// Call function (ref string x, dchar c)
|
||||||
LLValue* newArray = gIR->CreateCallOrInvoke(fn, args, ".appendedArray").getInstruction();
|
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);
|
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)));
|
args.push_back(DtoBitCast(tival, fn->getFunctionType()->getParamType(2)));
|
||||||
}
|
}
|
||||||
|
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, args);
|
return gIR->func()->scopes->callOrInvoke(fn, args).getInstruction();
|
||||||
|
|
||||||
return call.getInstruction();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -998,14 +990,13 @@ LLValue* DtoArrayCastLength(Loc& loc, LLValue* len, LLType* elemty, LLType* newe
|
||||||
if (esz == nsz)
|
if (esz == nsz)
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
LLValue* args[] = {
|
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
|
||||||
|
return gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
len,
|
len,
|
||||||
LLConstantInt::get(DtoSize_t(), esz, false),
|
LLConstantInt::get(DtoSize_t(), esz, false),
|
||||||
LLConstantInt::get(DtoSize_t(), nsz, false)
|
LLConstantInt::get(DtoSize_t(), nsz, false)
|
||||||
};
|
).getInstruction();
|
||||||
|
|
||||||
LLFunction* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
|
|
||||||
return gIR->CreateCallOrInvoke(fn, args).getInstruction();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -1241,19 +1232,12 @@ void DtoArrayBoundsCheck(Loc& loc, DValue* arr, DValue* index, DValue* lowerBoun
|
||||||
|
|
||||||
gIR->scope() = IRScope(failbb);
|
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");
|
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
|
// the function does not return
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/functions.h"
|
#include "gen/functions.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
Arg_Integer,
|
Arg_Integer,
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "gen/structs.h"
|
#include "gen/structs.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/iraggr.h"
|
#include "ir/iraggr.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtypeclass.h"
|
#include "ir/irtypeclass.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -193,12 +194,9 @@ void DtoFinalizeClass(Loc& loc, LLValue* inst)
|
||||||
{
|
{
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_callfinalizer");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_callfinalizer");
|
||||||
// build args
|
|
||||||
LLValue* arg[] = {
|
gIR->CreateCallOrInvoke(fn,
|
||||||
DtoBitCast(inst, fn->getFunctionType()->getParamType(0), ".tmp")
|
DtoBitCast(inst, fn->getFunctionType()->getParamType(0)), "");
|
||||||
};
|
|
||||||
// call
|
|
||||||
gIR->CreateCallOrInvoke(fn, arg, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -352,7 +350,7 @@ DValue* DtoDynamicCastObject(Loc& loc, DValue* val, Type* _to)
|
||||||
assert(funcTy->getParamType(1) == cinfo->getType());
|
assert(funcTy->getParamType(1) == cinfo->getType());
|
||||||
|
|
||||||
// call it
|
// call it
|
||||||
LLValue* ret = gIR->CreateCallOrInvoke2(func, obj, cinfo).getInstruction();
|
LLValue* ret = gIR->CreateCallOrInvoke(func, obj, cinfo).getInstruction();
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
ret = DtoBitCast(ret, DtoType(_to));
|
ret = DtoBitCast(ret, DtoType(_to));
|
||||||
|
@ -412,7 +410,7 @@ DValue* DtoDynamicCastInterface(Loc& loc, DValue* val, Type* _to)
|
||||||
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
|
cinfo = DtoBitCast(cinfo, funcTy->getParamType(1));
|
||||||
|
|
||||||
// call it
|
// call it
|
||||||
LLValue* ret = gIR->CreateCallOrInvoke2(func, ptr, cinfo).getInstruction();
|
LLValue* ret = gIR->CreateCallOrInvoke(func, ptr, cinfo).getInstruction();
|
||||||
|
|
||||||
// cast return value
|
// cast return value
|
||||||
ret = DtoBitCast(ret, DtoType(_to));
|
ret = DtoBitCast(ret, DtoType(_to));
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/optimizer.h"
|
#include "gen/optimizer.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtypeaggr.h"
|
#include "ir/irtypeaggr.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/Support/FileSystem.h"
|
#include "llvm/Support/FileSystem.h"
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "gen/pragma.h"
|
#include "gen/pragma.h"
|
||||||
#include "gen/runtime.h"
|
#include "gen/runtime.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
#if LDC_LLVM_VER >= 303
|
#if LDC_LLVM_VER >= 303
|
||||||
#include "llvm/IR/Intrinsics.h"
|
#include "llvm/IR/Intrinsics.h"
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "statement.h"
|
#include "statement.h"
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
|
|
||||||
IRState* gIR = 0;
|
IRState* gIR = 0;
|
||||||
|
@ -94,31 +95,31 @@ bool IRState::scopereturned()
|
||||||
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name)
|
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, const char* Name)
|
||||||
{
|
{
|
||||||
LLSmallVector<LLValue*, 1> args;
|
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)
|
LLCallSite IRState::CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, const char* Name)
|
||||||
{
|
{
|
||||||
LLValue* args[] = { Arg1 };
|
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 };
|
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 };
|
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 };
|
LLValue* args[] = { Arg1, Arg2, Arg3, Arg4 };
|
||||||
return CreateCallOrInvoke(Callee, args, Name);
|
return func()->scopes->callOrInvoke(Callee, args, Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IRState::emitArrayBoundsChecks()
|
bool IRState::emitArrayBoundsChecks()
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
|
|
||||||
#include "aggregate.h"
|
#include "aggregate.h"
|
||||||
#include "root.h"
|
#include "root.h"
|
||||||
#include "ir/irfunction.h"
|
|
||||||
#include "ir/iraggr.h"
|
#include "ir/iraggr.h"
|
||||||
#include "ir/irvar.h"
|
#include "ir/irvar.h"
|
||||||
#include "gen/dibuilder.h"
|
#include "gen/dibuilder.h"
|
||||||
|
@ -60,6 +59,7 @@ class TypeStruct;
|
||||||
struct BaseClass;
|
struct BaseClass;
|
||||||
class AnonDeclaration;
|
class AnonDeclaration;
|
||||||
|
|
||||||
|
struct IrFunction;
|
||||||
struct IrModule;
|
struct IrModule;
|
||||||
|
|
||||||
// represents a scope
|
// represents a scope
|
||||||
|
@ -148,14 +148,11 @@ struct IRState
|
||||||
bool scopereturned();
|
bool scopereturned();
|
||||||
|
|
||||||
// create a call or invoke, depending on the landing pad info
|
// 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, const char* Name="");
|
||||||
llvm::CallSite CreateCallOrInvoke(LLValue* Callee, LLValue* Arg1, 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 CreateCallOrInvoke(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 CreateCallOrInvoke(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, LLValue* Arg3, LLValue* Arg4, const char* Name="");
|
||||||
|
|
||||||
// this holds the array being indexed or sliced so $ will work
|
// 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
|
// might be a better way but it works. problem is I only get a
|
||||||
|
@ -198,40 +195,6 @@ struct IRState
|
||||||
#endif
|
#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);
|
void Statement_toIR(Statement *s, IRState *irs);
|
||||||
|
|
||||||
#endif // LDC_GEN_IRSTATE_H
|
#endif // LDC_GEN_IRSTATE_H
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/typeinf.h"
|
#include "gen/typeinf.h"
|
||||||
#include "gen/abi.h"
|
#include "gen/abi.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
#include "ir/irtypeaggr.h"
|
#include "ir/irtypeaggr.h"
|
||||||
#include "llvm/MC/MCAsmInfo.h"
|
#include "llvm/MC/MCAsmInfo.h"
|
||||||
|
@ -85,40 +86,34 @@ LLValue* DtoNewStruct(Loc& loc, TypeStruct* newtype)
|
||||||
|
|
||||||
void DtoDeleteMemory(Loc& loc, DValue* ptr)
|
void DtoDeleteMemory(Loc& loc, DValue* ptr)
|
||||||
{
|
{
|
||||||
// get runtime function
|
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
||||||
// build args
|
|
||||||
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
|
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
// call
|
|
||||||
gIR->CreateCallOrInvoke(fn, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteStruct(Loc& loc, DValue* ptr)
|
void DtoDeleteStruct(Loc& loc, DValue* ptr)
|
||||||
{
|
{
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
||||||
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue* lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
LLValue* arg[] = {
|
gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
||||||
DtoBitCast(DtoTypeInfoOf(ptr->type->nextOf()), fn->getFunctionType()->getParamType(1))
|
DtoBitCast(DtoTypeInfoOf(ptr->type->nextOf()), fn->getFunctionType()->getParamType(1))
|
||||||
};
|
);
|
||||||
gIR->CreateCallOrInvoke(fn, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteClass(Loc& loc, DValue* inst)
|
void DtoDeleteClass(Loc& loc, DValue* inst)
|
||||||
{
|
{
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delclass");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delclass");
|
||||||
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
|
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
gIR->CreateCallOrInvoke(fn, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteInterface(Loc& loc, DValue* inst)
|
void DtoDeleteInterface(Loc& loc, DValue* inst)
|
||||||
{
|
{
|
||||||
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
llvm::Function* fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
||||||
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue* lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
LLValue* arg[] = { DtoBitCast(lval, fn->getFunctionType()->getParamType(0)) };
|
gIR->CreateCallOrInvoke(fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
gIR->CreateCallOrInvoke(fn, arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DtoDeleteArray(Loc& loc, DValue* arr)
|
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* typeInfo = (!hasDtor ? getNullPtr(fty->getParamType(1)) : DtoTypeInfoOf(elementType));
|
||||||
|
|
||||||
LLValue* lval = (arr->isLVal() ? arr->getLVal() : makeLValue(loc, arr));
|
LLValue* lval = (arr->isLVal() ? arr->getLVal() : makeLValue(loc, arr));
|
||||||
LLValue* arg[] = {
|
gIR->CreateCallOrInvoke(
|
||||||
|
fn,
|
||||||
DtoBitCast(lval, fty->getParamType(0)),
|
DtoBitCast(lval, fty->getParamType(0)),
|
||||||
DtoBitCast(typeInfo, fty->getParamType(1))
|
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));
|
args.push_back(DtoConstUint(loc.linnum));
|
||||||
|
|
||||||
// call
|
// call
|
||||||
gIR->CreateCallOrInvoke(fn, args);
|
gIR->func()->scopes->callOrInvoke(fn, args);
|
||||||
|
|
||||||
// after assert is always unreachable
|
// after assert is always unreachable
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "gen/structs.h"
|
#include "gen/structs.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/irdsymbol.h"
|
#include "ir/irdsymbol.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irmodule.h"
|
||||||
#include "ir/irtype.h"
|
#include "ir/irtype.h"
|
||||||
#include "ir/irvar.h"
|
#include "ir/irvar.h"
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#if LDC_LLVM_VER >= 303
|
#if LDC_LLVM_VER >= 303
|
||||||
#include "llvm/IR/InlineAsm.h"
|
#include "llvm/IR/InlineAsm.h"
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -15,9 +15,8 @@
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "llvm/Analysis/ValueTracking.h"
|
#include "llvm/Analysis/ValueTracking.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
|
||||||
namespace cl = llvm::cl;
|
|
||||||
|
|
||||||
/****************************************************************************************/
|
/****************************************************************************************/
|
||||||
/*////////////////////////////////////////////////////////////////////////////////////////
|
/*////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/iraggr.h"
|
#include "ir/iraggr.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
|
|
||||||
RTTIBuilder::RTTIBuilder(AggregateDeclaration* base_class)
|
RTTIBuilder::RTTIBuilder(AggregateDeclaration* base_class)
|
||||||
{
|
{
|
||||||
|
|
|
@ -98,7 +98,7 @@ static LLValue* call_string_switch_runtime(llvm::Value* table, Expression* e)
|
||||||
LLValue* llval = val->getRVal();
|
LLValue* llval = val->getRVal();
|
||||||
assert(llval->getType() == fn->getFunctionType()->getParamType(1));
|
assert(llval->getType() == fn->getFunctionType()->getParamType(1));
|
||||||
|
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke2(fn, table, llval);
|
LLCallSite call = gIR->CreateCallOrInvoke(fn, table, llval);
|
||||||
|
|
||||||
return call.getInstruction();
|
return call.getInstruction();
|
||||||
}
|
}
|
||||||
|
@ -734,11 +734,35 @@ public:
|
||||||
// For catches that use the Throwable object, create storage for it.
|
// For catches that use the Throwable object, create storage for it.
|
||||||
// We will set it in the code that branches from the landing pads
|
// We will set it in the code that branches from the landing pads
|
||||||
// (there might be more than one) to catchBlock.
|
// (there might be more than one) to catchBlock.
|
||||||
llvm::Value* exceptionVar = 0;
|
|
||||||
if ((*it)->var) {
|
if ((*it)->var) {
|
||||||
DtoDeclarationExp((*it)->var);
|
llvm::Value* ehPtr = irs->func()->getOrCreateEhPtrSlot();
|
||||||
IrLocal* irLocal = getIrLocal((*it)->var);
|
|
||||||
exceptionVar = irLocal->value;
|
#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);
|
||||||
|
|
||||||
|
// 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
|
// emit handler, if there is one
|
||||||
|
@ -758,8 +782,7 @@ public:
|
||||||
DtoResolveClass(catchType);
|
DtoResolveClass(catchType);
|
||||||
|
|
||||||
irs->func()->scopes->pushCatch(
|
irs->func()->scopes->pushCatch(
|
||||||
getIrAggr(catchType)->getClassInfoSymbol(), exceptionVar,
|
getIrAggr(catchType)->getClassInfoSymbol(), catchBlock);
|
||||||
catchBlock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit the try block.
|
// Emit the try block.
|
||||||
|
@ -895,7 +918,7 @@ public:
|
||||||
inits[i] = toConstElem(c->str, irs);
|
inits[i] = toConstElem(c->str, irs);
|
||||||
}
|
}
|
||||||
// build static array for ptr or final array
|
// 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());
|
LLArrayType* arrTy = llvm::ArrayType::get(elemTy, inits.size());
|
||||||
LLConstant* arrInit = LLConstantArray::get(arrTy, inits);
|
LLConstant* arrInit = LLConstantArray::get(arrTy, inits);
|
||||||
LLGlobalVariable* arr = new llvm::GlobalVariable(irs->module, arrTy, true, llvm::GlobalValue::InternalLinkage, arrInit, ".string_switch_table_data");
|
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();
|
LLValue *moduleInfoSymbol = getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
|
||||||
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
|
LLType *moduleInfoType = DtoType(Module::moduleinfo->type);
|
||||||
|
|
||||||
LLValue* args[] = {
|
LLCallSite call = irs->CreateCallOrInvoke(
|
||||||
// module param
|
fn,
|
||||||
DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType)),
|
DtoBitCast(moduleInfoSymbol, getPtrToType(moduleInfoType)),
|
||||||
// line param
|
|
||||||
DtoConstUint(stmt->loc.linnum)
|
DtoConstUint(stmt->loc.linnum)
|
||||||
};
|
);
|
||||||
|
|
||||||
// call
|
|
||||||
LLCallSite call = irs->CreateCallOrInvoke(fn, args);
|
|
||||||
call.setDoesNotReturn();
|
call.setDoesNotReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/nested.h"
|
#include "gen/nested.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtype.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);
|
addExplicitArguments(args, attrs, irFty, callableTy, argvals, numFormalParams);
|
||||||
|
|
||||||
// call the function
|
// call the function
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(callable, args);
|
LLCallSite call = gIR->func()->scopes->callOrInvoke(callable, args);
|
||||||
|
|
||||||
// get return value
|
// get return value
|
||||||
LLValue* retllval = (retinptr) ? args[0] : call.getInstruction();
|
LLValue* retllval = (retinptr) ? args[0] : call.getInstruction();
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include "gen/logger.h"
|
#include "gen/logger.h"
|
||||||
#include "gen/structs.h"
|
#include "gen/structs.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtypeclass.h"
|
#include "ir/irtypeclass.h"
|
||||||
#include "ir/irtypestruct.h"
|
#include "ir/irtypestruct.h"
|
||||||
|
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "gen/typeinf.h"
|
#include "gen/typeinf.h"
|
||||||
#include "gen/warnings.h"
|
#include "gen/warnings.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtypeclass.h"
|
#include "ir/irtypeclass.h"
|
||||||
#include "ir/irtypestruct.h"
|
#include "ir/irtypestruct.h"
|
||||||
#include "llvm/Support/CommandLine.h"
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
@ -3005,7 +3006,7 @@ public:
|
||||||
slice = DtoConstSlice(DtoConstSize_t(e->keys->dim), slice);
|
slice = DtoConstSlice(DtoConstSize_t(e->keys->dim), slice);
|
||||||
LLValue* valuesArray = DtoAggrPaint(slice, funcTy->getParamType(2));
|
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) {
|
if (basetype->ty != Taarray) {
|
||||||
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
|
LLValue *tmp = DtoAlloca(e->type, "aaliteral");
|
||||||
DtoStore(aa, DtoGEPi(tmp, 0, 0));
|
DtoStore(aa, DtoGEPi(tmp, 0, 0));
|
||||||
|
|
37
ir/iraggr.h
37
ir/iraggr.h
|
@ -22,6 +22,11 @@
|
||||||
// DMD forward declarations
|
// DMD forward declarations
|
||||||
class StructInitializer;
|
class StructInitializer;
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
class Constant;
|
||||||
|
class StructType;
|
||||||
|
}
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// represents a struct or class
|
// represents a struct or class
|
||||||
|
@ -44,22 +49,22 @@ struct IrAggr
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
/// Create the __initZ symbol lazily.
|
/// Create the __initZ symbol lazily.
|
||||||
LLGlobalVariable* getInitSymbol();
|
llvm::GlobalVariable* getInitSymbol();
|
||||||
/// Builds the __initZ initializer constant lazily.
|
/// Builds the __initZ initializer constant lazily.
|
||||||
LLConstant* getDefaultInit();
|
llvm::Constant* getDefaultInit();
|
||||||
|
|
||||||
/// Create the __vtblZ symbol lazily.
|
/// Create the __vtblZ symbol lazily.
|
||||||
LLGlobalVariable* getVtblSymbol();
|
llvm::GlobalVariable* getVtblSymbol();
|
||||||
/// Builds the __vtblZ initializer constant lazily.
|
/// Builds the __vtblZ initializer constant lazily.
|
||||||
LLConstant* getVtblInit();
|
llvm::Constant* getVtblInit();
|
||||||
|
|
||||||
/// Create the __ClassZ/__InterfaceZ symbol lazily.
|
/// Create the __ClassZ/__InterfaceZ symbol lazily.
|
||||||
LLGlobalVariable* getClassInfoSymbol();
|
llvm::GlobalVariable* getClassInfoSymbol();
|
||||||
/// Builds the __ClassZ/__InterfaceZ initializer constant lazily.
|
/// Builds the __ClassZ/__InterfaceZ initializer constant lazily.
|
||||||
LLConstant* getClassInfoInit();
|
llvm::Constant* getClassInfoInit();
|
||||||
|
|
||||||
/// Create the __interfaceInfos symbol lazily.
|
/// Create the __interfaceInfos symbol lazily.
|
||||||
LLGlobalVariable* getInterfaceArraySymbol();
|
llvm::GlobalVariable* getInterfaceArraySymbol();
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
@ -87,21 +92,21 @@ struct IrAggr
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/// Static default initializer global.
|
/// Static default initializer global.
|
||||||
LLGlobalVariable* init;
|
llvm::GlobalVariable* init;
|
||||||
/// Static default initializer constant.
|
/// Static default initializer constant.
|
||||||
LLConstant* constInit;
|
llvm::Constant* constInit;
|
||||||
/// Static default initialier type.
|
/// Static default initialier type.
|
||||||
LLStructType* init_type;
|
llvm::StructType* init_type;
|
||||||
|
|
||||||
/// Vtbl global.
|
/// Vtbl global.
|
||||||
LLGlobalVariable* vtbl;
|
llvm::GlobalVariable* vtbl;
|
||||||
/// Vtbl initializer constant.
|
/// Vtbl initializer constant.
|
||||||
LLConstant* constVtbl;
|
llvm::Constant* constVtbl;
|
||||||
|
|
||||||
/// ClassInfo global.
|
/// ClassInfo global.
|
||||||
LLGlobalVariable* classInfo;
|
llvm::GlobalVariable* classInfo;
|
||||||
/// ClassInfo initializer constant.
|
/// ClassInfo initializer constant.
|
||||||
LLConstant* constClassInfo;
|
llvm::Constant* constClassInfo;
|
||||||
|
|
||||||
/// Map for mapping ClassDeclaration* to LLVM GlobalVariable.
|
/// Map for mapping ClassDeclaration* to LLVM GlobalVariable.
|
||||||
typedef std::map<ClassDeclaration*, llvm::GlobalVariable*> ClassGlobalMap;
|
typedef std::map<ClassDeclaration*, llvm::GlobalVariable*> ClassGlobalMap;
|
||||||
|
@ -130,10 +135,10 @@ protected:
|
||||||
size_t interfaces_index);
|
size_t interfaces_index);
|
||||||
|
|
||||||
// FIXME make this a member instead
|
// FIXME make this a member instead
|
||||||
friend LLConstant* DtoDefineClassInfo(ClassDeclaration* cd);
|
friend llvm::Constant* DtoDefineClassInfo(ClassDeclaration* cd);
|
||||||
|
|
||||||
/// Create the Interface[] interfaces ClassInfo field initializer.
|
/// 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
|
/// Returns true, if the LLVM struct type for the aggregate is declared as packed
|
||||||
bool isPacked() const;
|
bool isPacked() const;
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "gen/functions.h"
|
#include "gen/functions.h"
|
||||||
|
|
||||||
#include "ir/iraggr.h"
|
#include "ir/iraggr.h"
|
||||||
|
#include "ir/irfunction.h"
|
||||||
#include "ir/irtypeclass.h"
|
#include "ir/irtypeclass.h"
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
#include "gen/llvmhelpers.h"
|
#include "gen/llvmhelpers.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
|
#include "gen/runtime.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/irdsymbol.h"
|
#include "ir/irdsymbol.h"
|
||||||
#include "ir/irfunction.h"
|
#include "ir/irfunction.h"
|
||||||
|
@ -32,7 +33,7 @@ void executeCleanup(IRState *irs, CleanupScope& scope,
|
||||||
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
|
scope.exitTargets.push_back(CleanupExitTarget(continueWith));
|
||||||
llvm::BranchInst::Create(continueWith, scope.endBlock);
|
llvm::BranchInst::Create(continueWith, scope.endBlock);
|
||||||
}
|
}
|
||||||
scope.exitTargets.front().sourceBlocks.push_back(sourceBlock);
|
scope.exitTargets.front().sourceBlocks.push_back(sourceBlock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,15 +121,17 @@ void ScopeStack::pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* end
|
||||||
cleanupScopes.push_back(CleanupScope(beginBlock, endBlock));
|
cleanupScopes.push_back(CleanupScope(beginBlock, endBlock));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScopeStack::runCleanups(CleanupCursor targetScope,
|
void ScopeStack::runCleanups(
|
||||||
|
CleanupCursor sourceScope,
|
||||||
|
CleanupCursor targetScope,
|
||||||
llvm::BasicBlock* continueWith
|
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.
|
// No cleanups to run, just branch to the next block.
|
||||||
llvm::BranchInst::Create(continueWith, irs->scopebb());
|
llvm::BranchInst::Create(continueWith, irs->scopebb());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert the unconditional branch to the first cleanup block.
|
// Insert the unconditional branch to the first cleanup block.
|
||||||
|
@ -136,7 +139,7 @@ void ScopeStack::runCleanups(CleanupCursor targetScope,
|
||||||
|
|
||||||
// Update all the control flow in the cleanups to make sure we end up where
|
// Update all the control flow in the cleanups to make sure we end up where
|
||||||
// we want.
|
// we want.
|
||||||
for (CleanupCursor i = currentCleanupScope(); i-- > targetScope;) {
|
for (CleanupCursor i = sourceScope; i-- > targetScope;) {
|
||||||
llvm::BasicBlock *nextBlock = (i > targetScope) ?
|
llvm::BasicBlock *nextBlock = (i > targetScope) ?
|
||||||
cleanupScopes[i - 1].beginBlock : continueWith;
|
cleanupScopes[i - 1].beginBlock : continueWith;
|
||||||
executeCleanup(irs, cleanupScopes[i], irs->scopebb(), nextBlock);
|
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,
|
void ScopeStack::pushLoopTarget(Statement* loopStatement, llvm::BasicBlock* continueTarget,
|
||||||
llvm::BasicBlock* breakTarget
|
llvm::BasicBlock* breakTarget
|
||||||
) {
|
) {
|
||||||
|
@ -258,8 +273,129 @@ void ScopeStack::jumpToClosest(std::vector<JumpTarget>& targets) {
|
||||||
std::vector<GotoJump>& ScopeStack::currentUnresolvedGotos() {
|
std::vector<GotoJump>& ScopeStack::currentUnresolvedGotos() {
|
||||||
return cleanupScopes.empty() ?
|
return cleanupScopes.empty() ?
|
||||||
topLevelUnresolvedGotos :
|
topLevelUnresolvedGotos :
|
||||||
cleanupScopes.back().unresolvedGotos;
|
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)
|
IrFunction::IrFunction(FuncDeclaration* fd)
|
||||||
{
|
{
|
||||||
|
@ -288,6 +424,10 @@ IrFunction::IrFunction(FuncDeclaration* fd)
|
||||||
|
|
||||||
retValSlot = NULL;
|
retValSlot = NULL;
|
||||||
retBlock = NULL;
|
retBlock = NULL;
|
||||||
|
|
||||||
|
ehPtrSlot = NULL;
|
||||||
|
resumeUnwindBlock = NULL;
|
||||||
|
ehSelectorSlot = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void IrFunction::setNeverInline()
|
void IrFunction::setNeverInline()
|
||||||
|
@ -318,6 +458,13 @@ void IrFunction::setAlwaysInline()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
llvm::AllocaInst* IrFunction::getOrCreateEhPtrSlot() {
|
||||||
|
if (!ehPtrSlot) {
|
||||||
|
ehPtrSlot = DtoRawAlloca(getVoidPtrType(), 0, "eh.ptr");
|
||||||
|
}
|
||||||
|
return ehPtrSlot;
|
||||||
|
}
|
||||||
|
|
||||||
IrFunction *getIrFunc(FuncDeclaration *decl, bool create)
|
IrFunction *getIrFunc(FuncDeclaration *decl, bool create)
|
||||||
{
|
{
|
||||||
if (!isIrFuncCreated(decl) && create)
|
if (!isIrFuncCreated(decl) && create)
|
||||||
|
|
129
ir/irfunction.h
129
ir/irfunction.h
|
@ -19,6 +19,7 @@
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
#include "llvm/ADT/DenseMapInfo.h"
|
#include "llvm/ADT/DenseMapInfo.h"
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
|
#include "gen/irstate.h"
|
||||||
#include "ir/irfuncty.h"
|
#include "ir/irfuncty.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <stack>
|
#include <stack>
|
||||||
|
@ -26,7 +27,6 @@
|
||||||
|
|
||||||
class Identifier;
|
class Identifier;
|
||||||
class Statement;
|
class Statement;
|
||||||
struct IRState;
|
|
||||||
|
|
||||||
/// Represents a position on the stack of currently active cleanup scopes.
|
/// Represents a position on the stack of currently active cleanup scopes.
|
||||||
///
|
///
|
||||||
|
@ -105,7 +105,7 @@ public:
|
||||||
beginBlock(beginBlock), endBlock(endBlock), branchSelector(0) {}
|
beginBlock(beginBlock), endBlock(endBlock), branchSelector(0) {}
|
||||||
|
|
||||||
/// The basic block to branch to for running the cleanup.
|
/// 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
|
/// The basic block that contains the end of the cleanuip code (is different
|
||||||
/// from beginBlock if the cleanup contains control flow).
|
/// 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
|
/// have not found the label yet (because it occurs lexically later in the
|
||||||
/// function).
|
/// function).
|
||||||
std::vector<GotoJump> unresolvedGotos;
|
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
|
/// Contains transitory information about the current scope, etc. while
|
||||||
|
@ -140,20 +158,24 @@ public:
|
||||||
void pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* endBlock);
|
void pushCleanup(llvm::BasicBlock* beginBlock, llvm::BasicBlock* endBlock);
|
||||||
|
|
||||||
/// Terminates the current IRScope with a branch to the cleanups needed for
|
/// 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.
|
/// stack level.
|
||||||
///
|
///
|
||||||
/// After running them, execution will branch to the given basic block.
|
/// 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.
|
/// Like #runCleanups(), but runs all of them.
|
||||||
void runAllCleanups(llvm::BasicBlock* continueWith);
|
void runAllCleanups(llvm::BasicBlock* continueWith);
|
||||||
|
|
||||||
/// Pops all the cleanups between the current scope and the target cursor.
|
/// 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);
|
void popCleanups(CleanupCursor targetScope);
|
||||||
|
|
||||||
/// Returns a cursor that identifies the curernt cleanup scope, to be later
|
/// 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
|
/// Note that this cursor is only valid as long as the current scope is not
|
||||||
/// popped.
|
/// popped.
|
||||||
|
@ -166,11 +188,16 @@ public:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
///
|
///
|
||||||
void pushCatch(llvm::Value* classInfoPtr, llvm::Value* exceptionVar,
|
void pushCatch(llvm::Constant* classInfoPtr, llvm::BasicBlock* bodyBlock);
|
||||||
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,
|
void pushLoopTarget(Statement* loopStatement, llvm::BasicBlock* continueTarget,
|
||||||
|
@ -213,12 +240,26 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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<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);
|
void jumpToStatement(std::vector<JumpTarget>& targets, Statement* loopOrSwitchStatement);
|
||||||
|
|
||||||
|
/// Unified implementation for unlabeled break/continue.
|
||||||
void jumpToClosest(std::vector<JumpTarget>& targets);
|
void jumpToClosest(std::vector<JumpTarget>& targets);
|
||||||
|
|
||||||
|
/// The ambient IRState. For legacy reasons, there is currently a cyclic
|
||||||
|
/// dependency between the two.
|
||||||
IRState *irs;
|
IRState *irs;
|
||||||
|
|
||||||
typedef llvm::DenseMap<Identifier*, JumpTarget> LabelTargetMap;
|
typedef llvm::DenseMap<Identifier*, JumpTarget> LabelTargetMap;
|
||||||
|
@ -235,12 +276,20 @@ private:
|
||||||
///
|
///
|
||||||
std::vector<CleanupScope> cleanupScopes;
|
std::vector<CleanupScope> cleanupScopes;
|
||||||
|
|
||||||
|
///
|
||||||
|
std::vector<CatchScope> catchScopes;
|
||||||
|
|
||||||
/// Gotos which we were not able to resolve to any cleanup scope, but which
|
/// 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
|
/// 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
|
/// any left on function exit, it is an error (e.g. because the user tried
|
||||||
/// to goto into a finally block, etc.).
|
/// to goto into a finally block, etc.).
|
||||||
std::vector<GotoJump> topLevelUnresolvedGotos;
|
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
|
#if 0
|
||||||
/// To be able to handle the broken AST the frontend produces in some cases
|
/// 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
|
/// for temporary constructor calls, we need to be able to temporarily
|
||||||
|
@ -251,6 +300,49 @@ private:
|
||||||
#endif
|
#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
|
// represents a function
|
||||||
struct IrFunction {
|
struct IrFunction {
|
||||||
// constructor
|
// constructor
|
||||||
|
@ -260,6 +352,8 @@ struct IrFunction {
|
||||||
void setNeverInline();
|
void setNeverInline();
|
||||||
void setAlwaysInline();
|
void setAlwaysInline();
|
||||||
|
|
||||||
|
llvm::AllocaInst* getOrCreateEhPtrSlot();
|
||||||
|
|
||||||
llvm::Function* func;
|
llvm::Function* func;
|
||||||
llvm::Instruction* allocapoint;
|
llvm::Instruction* allocapoint;
|
||||||
FuncDeclaration* decl;
|
FuncDeclaration* decl;
|
||||||
|
@ -284,11 +378,26 @@ struct IrFunction {
|
||||||
llvm::Value* _arguments;
|
llvm::Value* _arguments;
|
||||||
llvm::Value* _argptr;
|
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;
|
llvm::AllocaInst* retValSlot;
|
||||||
// The basic block with the return instruction.
|
/// The basic block with the return instruction.
|
||||||
llvm::BasicBlock* retBlock;
|
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
|
#if LDC_LLVM_VER >= 307
|
||||||
llvm::DISubprogram* diSubprogram = nullptr;
|
llvm::DISubprogram* diSubprogram = nullptr;
|
||||||
std::stack<llvm::DILexicalBlock*> diLexicalBlocks;
|
std::stack<llvm::DILexicalBlock*> diLexicalBlocks;
|
||||||
|
|
|
@ -7,12 +7,13 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "ir/irmodule.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include "gen/llvm.h"
|
#include "gen/llvm.h"
|
||||||
#include "gen/irstate.h"
|
#include "gen/irstate.h"
|
||||||
#include "gen/tollvm.h"
|
#include "gen/tollvm.h"
|
||||||
#include "ir/irdsymbol.h"
|
#include "ir/irdsymbol.h"
|
||||||
#include "ir/irmodule.h"
|
#include "ir/irfunction.h"
|
||||||
|
|
||||||
IrModule::IrModule(Module *module, const char *srcfilename)
|
IrModule::IrModule(Module *module, const char *srcfilename)
|
||||||
: M(module), moduleInfoVar_(0) {}
|
: M(module), moduleInfoVar_(0) {}
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#ifndef LDC_IR_IRMODULE_H
|
#ifndef LDC_IR_IRMODULE_H
|
||||||
#define LDC_IR_IRMODULE_H
|
#define LDC_IR_IRMODULE_H
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
|
||||||
|
class FuncDeclaration;
|
||||||
|
class VarDeclaration;
|
||||||
class Module;
|
class Module;
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class GlobalVariable;
|
class GlobalVariable;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue