mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-12 22:14:54 +03:00
Cleanup runtime fwd decls and use ABI functiontype rewriting
This commit is contained in:
parent
417e3d242d
commit
70a6e73188
15 changed files with 347 additions and 594 deletions
|
@ -1279,7 +1279,7 @@ int main(int argc, char **argv) {
|
||||||
emitJson(modules);
|
emitJson(modules);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVM_D_FreeRuntime();
|
freeRuntime();
|
||||||
llvm::llvm_shutdown();
|
llvm::llvm_shutdown();
|
||||||
|
|
||||||
if (global.errors) {
|
if (global.errors) {
|
||||||
|
|
10
gen/aa.cpp
10
gen/aa.cpp
|
@ -41,7 +41,7 @@ DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
|
||||||
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
||||||
|
|
||||||
// first get the runtime function
|
// first get the runtime function
|
||||||
llvm::Function *func = LLVM_D_GetRuntimeFunction(
|
llvm::Function *func = getRuntimeFunction(
|
||||||
loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
loc, gIR->module, lvalue ? "_aaGetY" : "_aaInX");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ DValue *DtoAAIndex(Loc &loc, Type *type, DValue *aa, DValue *key, bool lvalue) {
|
||||||
gIR->scope() = IRScope(failbb);
|
gIR->scope() = IRScope(failbb);
|
||||||
|
|
||||||
llvm::Function *errorfn =
|
llvm::Function *errorfn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arraybounds");
|
getRuntimeFunction(loc, gIR->module, "_d_arraybounds");
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc),
|
errorfn, DtoModuleFileName(gIR->func()->decl->getModule(), loc),
|
||||||
DtoConstUint(loc.linnum));
|
DtoConstUint(loc.linnum));
|
||||||
|
@ -118,7 +118,7 @@ DValue *DtoAAIn(Loc &loc, Type *type, DValue *aa, DValue *key) {
|
||||||
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
// extern(C) void* _aaInX(AA aa*, TypeInfo keyti, void* pkey)
|
||||||
|
|
||||||
// first get the runtime function
|
// first get the runtime function
|
||||||
llvm::Function *func = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_aaInX");
|
llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaInX");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "_aaIn = " << *func << '\n';
|
IF_LOG Logger::cout() << "_aaIn = " << *func << '\n';
|
||||||
|
@ -164,7 +164,7 @@ DValue *DtoAARemove(Loc &loc, DValue *aa, DValue *key) {
|
||||||
// extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey)
|
// extern(C) bool _aaDelX(AA aa, TypeInfo keyti, void* pkey)
|
||||||
|
|
||||||
// first get the runtime function
|
// first get the runtime function
|
||||||
llvm::Function *func = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_aaDelX");
|
llvm::Function *func = getRuntimeFunction(loc, gIR->module, "_aaDelX");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
IF_LOG Logger::cout() << "_aaDel = " << *func << '\n';
|
IF_LOG Logger::cout() << "_aaDel = " << *func << '\n';
|
||||||
|
@ -198,7 +198,7 @@ LLValue *DtoAAEquals(Loc &loc, TOK op, DValue *l, DValue *r) {
|
||||||
assert(t == r->getType()->toBasetype() &&
|
assert(t == r->getType()->toBasetype() &&
|
||||||
"aa equality is only defined for aas of same type");
|
"aa equality is only defined for aas of same type");
|
||||||
llvm::Function *func =
|
llvm::Function *func =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_aaEqual");
|
getRuntimeFunction(loc, gIR->module, "_aaEqual");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
LLValue *aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1));
|
LLValue *aaval = DtoBitCast(l->getRVal(), funcTy->getParamType(1));
|
||||||
|
|
|
@ -200,7 +200,7 @@ static void copySlice(Loc &loc, LLValue *dstarr, LLValue *sz1, LLValue *srcarr,
|
||||||
global.params.useAssert || gIR->emitArrayBoundsChecks();
|
global.params.useAssert || gIR->emitArrayBoundsChecks();
|
||||||
if (checksEnabled && !knownInBounds) {
|
if (checksEnabled && !knownInBounds) {
|
||||||
LLValue *fn =
|
LLValue *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
getRuntimeFunction(loc, gIR->module, "_d_array_slice_copy");
|
||||||
gIR->CreateCallOrInvoke(fn, dstarr, sz1, srcarr, sz2);
|
gIR->CreateCallOrInvoke(fn, dstarr, sz1, srcarr, sz2);
|
||||||
} else {
|
} else {
|
||||||
// We might have dstarr == srcarr at compile time, but as long as
|
// We might have dstarr == srcarr at compile time, but as long as
|
||||||
|
@ -285,7 +285,7 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
}
|
}
|
||||||
} else if (isConstructing) {
|
} else if (isConstructing) {
|
||||||
LLFunction *fn =
|
LLFunction *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
getRuntimeFunction(loc, gIR->module, "_d_arrayctor");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
|
LLCallSite call = gIR->CreateCallOrInvoke(fn, DtoTypeInfoOf(elemType),
|
||||||
DtoSlice(rhsPtr, rhsLength),
|
DtoSlice(rhsPtr, rhsLength),
|
||||||
DtoSlice(lhsPtr, lhsLength));
|
DtoSlice(lhsPtr, lhsLength));
|
||||||
|
@ -293,7 +293,7 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
} else // assigning
|
} else // assigning
|
||||||
{
|
{
|
||||||
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
LLValue *tmpSwap = DtoAlloca(elemType, "arrayAssign.tmpSwap");
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(
|
LLFunction *fn = getRuntimeFunction(
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
!canSkipPostblit ? "_d_arrayassign_l" : "_d_arrayassign_r");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(
|
LLCallSite call = gIR->CreateCallOrInvoke(
|
||||||
|
@ -316,7 +316,7 @@ void DtoArrayAssign(Loc &loc, DValue *lhs, DValue *rhs, int op,
|
||||||
LLValue *actualLength = gIR->ir->CreateExactUDiv(lhsSize, rhsSize);
|
LLValue *actualLength = gIR->ir->CreateExactUDiv(lhsSize, rhsSize);
|
||||||
DtoArrayInit(loc, actualPtr, actualLength, rhs, op);
|
DtoArrayInit(loc, actualPtr, actualLength, rhs, op);
|
||||||
} else {
|
} else {
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(
|
LLFunction *fn = getRuntimeFunction(
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
isConstructing ? "_d_arraysetctor" : "_d_arraysetassign");
|
isConstructing ? "_d_arraysetctor" : "_d_arraysetassign");
|
||||||
LLCallSite call = gIR->CreateCallOrInvoke(
|
LLCallSite call = gIR->CreateCallOrInvoke(
|
||||||
|
@ -625,7 +625,7 @@ DSliceValue *DtoNewDynArray(Loc &loc, Type *arrayType, DValue *dim,
|
||||||
const char *fnname = defaultInit
|
const char *fnname = defaultInit
|
||||||
? (zeroInit ? "_d_newarrayT" : "_d_newarrayiT")
|
? (zeroInit ? "_d_newarrayT" : "_d_newarrayiT")
|
||||||
: "_d_newarrayU";
|
: "_d_newarrayU";
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, fnname);
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, fnname);
|
||||||
|
|
||||||
// call allocator
|
// call allocator
|
||||||
LLValue *newArray =
|
LLValue *newArray =
|
||||||
|
@ -653,7 +653,7 @@ DSliceValue *DtoNewMulDimDynArray(Loc &loc, Type *arrayType, DValue **dims,
|
||||||
// get runtime function
|
// get runtime function
|
||||||
const char *fnname =
|
const char *fnname =
|
||||||
vtype->isZeroInit() ? "_d_newarraymTX" : "_d_newarraymiTX";
|
vtype->isZeroInit() ? "_d_newarraymTX" : "_d_newarraymiTX";
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, fnname);
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, fnname);
|
||||||
|
|
||||||
// Check if constant
|
// Check if constant
|
||||||
bool allDimsConst = true;
|
bool allDimsConst = true;
|
||||||
|
@ -720,7 +720,7 @@ DSliceValue *DtoResizeDynArray(Loc &loc, Type *arrayType, DValue *array,
|
||||||
bool zeroInit = arrayType->toBasetype()->nextOf()->isZeroInit();
|
bool zeroInit = arrayType->toBasetype()->nextOf()->isZeroInit();
|
||||||
|
|
||||||
// call runtime
|
// call runtime
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module,
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module,
|
||||||
zeroInit ? "_d_arraysetlengthT"
|
zeroInit ? "_d_arraysetlengthT"
|
||||||
: "_d_arraysetlengthiT");
|
: "_d_arraysetlengthiT");
|
||||||
|
|
||||||
|
@ -750,7 +750,7 @@ void DtoCatAssignElement(Loc &loc, Type *arrayType, DValue *array,
|
||||||
DValue *expVal = toElem(exp);
|
DValue *expVal = toElem(exp);
|
||||||
|
|
||||||
LLFunction *fn =
|
LLFunction *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendcTX");
|
getRuntimeFunction(loc, gIR->module, "_d_arrayappendcTX");
|
||||||
LLValue *appendedArray =
|
LLValue *appendedArray =
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoTypeInfoOf(arrayType),
|
fn, DtoTypeInfoOf(arrayType),
|
||||||
|
@ -774,7 +774,7 @@ DSliceValue *DtoCatAssignArray(Loc &loc, DValue *arr, Expression *exp) {
|
||||||
Type *arrayType = arr->getType();
|
Type *arrayType = arr->getType();
|
||||||
|
|
||||||
LLFunction *fn =
|
LLFunction *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
getRuntimeFunction(loc, gIR->module, "_d_arrayappendT");
|
||||||
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
|
// Call _d_arrayappendT(TypeInfo ti, byte[] *px, byte[] y)
|
||||||
LLValue *newArray =
|
LLValue *newArray =
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
|
@ -799,7 +799,7 @@ DSliceValue *DtoCatArrays(Loc &loc, Type *arrayType, Expression *exp1,
|
||||||
LLFunction *fn = nullptr;
|
LLFunction *fn = nullptr;
|
||||||
|
|
||||||
if (exp1->op == TOKcat) { // handle multiple concat
|
if (exp1->op == TOKcat) { // handle multiple concat
|
||||||
fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arraycatnTX");
|
fn = getRuntimeFunction(loc, gIR->module, "_d_arraycatnTX");
|
||||||
|
|
||||||
// Create array of slices
|
// Create array of slices
|
||||||
typedef llvm::SmallVector<llvm::Value *, 16> ArgVector;
|
typedef llvm::SmallVector<llvm::Value *, 16> ArgVector;
|
||||||
|
@ -839,7 +839,7 @@ DSliceValue *DtoCatArrays(Loc &loc, Type *arrayType, Expression *exp1,
|
||||||
// byte[][] arrs
|
// byte[][] arrs
|
||||||
args.push_back(val);
|
args.push_back(val);
|
||||||
} else {
|
} else {
|
||||||
fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_arraycatT");
|
fn = getRuntimeFunction(loc, gIR->module, "_d_arraycatT");
|
||||||
|
|
||||||
// TypeInfo ti
|
// TypeInfo ti
|
||||||
args.push_back(DtoTypeInfoOf(arrayType));
|
args.push_back(DtoTypeInfoOf(arrayType));
|
||||||
|
@ -867,7 +867,7 @@ DSliceValue *DtoAppendDChar(Loc &loc, DValue *arr, Expression *exp,
|
||||||
DValue *valueToAppend = toElem(exp);
|
DValue *valueToAppend = toElem(exp);
|
||||||
|
|
||||||
// Prepare arguments
|
// Prepare arguments
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, func);
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, func);
|
||||||
|
|
||||||
// Call function (ref string x, dchar c)
|
// Call function (ref string x, dchar c)
|
||||||
LLValue *newArray =
|
LLValue *newArray =
|
||||||
|
@ -904,7 +904,7 @@ DSliceValue *DtoAppendDCharToUnicodeString(Loc &loc, DValue *arr,
|
||||||
static LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
|
static LLValue *DtoArrayEqCmp_impl(Loc &loc, const char *func, DValue *l,
|
||||||
DValue *r, bool useti) {
|
DValue *r, bool useti) {
|
||||||
IF_LOG Logger::println("comparing arrays");
|
IF_LOG Logger::println("comparing arrays");
|
||||||
LLFunction *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, func);
|
LLFunction *fn = getRuntimeFunction(loc, gIR->module, func);
|
||||||
assert(fn);
|
assert(fn);
|
||||||
|
|
||||||
// find common dynamic array type
|
// find common dynamic array type
|
||||||
|
@ -981,7 +981,7 @@ LLValue *DtoArrayCastLength(Loc &loc, LLValue *len, LLType *elemty,
|
||||||
}
|
}
|
||||||
|
|
||||||
LLFunction *fn =
|
LLFunction *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
|
getRuntimeFunction(loc, gIR->module, "_d_array_cast_len");
|
||||||
return gIR->CreateCallOrInvoke(fn, len,
|
return gIR->CreateCallOrInvoke(fn, 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))
|
||||||
|
@ -1213,7 +1213,7 @@ void DtoIndexBoundsCheck(Loc &loc, DValue *arr, DValue *index) {
|
||||||
|
|
||||||
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
void DtoBoundsCheckFailCall(IRState *irs, Loc &loc) {
|
||||||
llvm::Function *errorfn =
|
llvm::Function *errorfn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, irs->module, "_d_arraybounds");
|
getRuntimeFunction(loc, irs->module, "_d_arraybounds");
|
||||||
irs->CreateCallOrInvoke(
|
irs->CreateCallOrInvoke(
|
||||||
errorfn, DtoModuleFileName(irs->func()->decl->getModule(), loc),
|
errorfn, DtoModuleFileName(irs->func()->decl->getModule(), loc),
|
||||||
DtoConstUint(loc.linnum));
|
DtoConstUint(loc.linnum));
|
||||||
|
|
|
@ -97,7 +97,7 @@ DValue *DtoNewClass(Loc &loc, TypeClass *tc, NewExp *newexp) {
|
||||||
// default allocator
|
// default allocator
|
||||||
else {
|
else {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_newclass");
|
getRuntimeFunction(loc, gIR->module, "_d_newclass");
|
||||||
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
|
LLConstant *ci = DtoBitCast(getIrAggr(tc->sym)->getClassInfoSymbol(),
|
||||||
DtoType(Type::typeinfoclass->type));
|
DtoType(Type::typeinfoclass->type));
|
||||||
mem =
|
mem =
|
||||||
|
@ -186,7 +186,7 @@ void DtoInitClass(TypeClass *tc, LLValue *dst) {
|
||||||
void DtoFinalizeClass(Loc &loc, LLValue *inst) {
|
void DtoFinalizeClass(Loc &loc, LLValue *inst) {
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_callfinalizer");
|
getRuntimeFunction(loc, gIR->module, "_d_callfinalizer");
|
||||||
|
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(inst, fn->getFunctionType()->getParamType(0)), "");
|
fn, DtoBitCast(inst, fn->getFunctionType()->getParamType(0)), "");
|
||||||
|
@ -330,7 +330,7 @@ DValue *DtoDynamicCastObject(Loc &loc, DValue *val, Type *_to) {
|
||||||
DtoResolveClass(Type::typeinfoclass);
|
DtoResolveClass(Type::typeinfoclass);
|
||||||
|
|
||||||
llvm::Function *func =
|
llvm::Function *func =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_dynamic_cast");
|
getRuntimeFunction(loc, gIR->module, "_d_dynamic_cast");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
// Object o
|
// Object o
|
||||||
|
@ -368,7 +368,7 @@ DValue *DtoDynamicCastInterface(Loc &loc, DValue *val, Type *_to) {
|
||||||
DtoResolveClass(Type::typeinfoclass);
|
DtoResolveClass(Type::typeinfoclass);
|
||||||
|
|
||||||
llvm::Function *func =
|
llvm::Function *func =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_interface_cast");
|
getRuntimeFunction(loc, gIR->module, "_d_interface_cast");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
|
|
||||||
// void* p
|
// void* p
|
||||||
|
|
|
@ -378,43 +378,10 @@ void DtoResolveFunction(FuncDeclaration *fdecl) {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
static void set_param_attrs(TypeFunction *f, llvm::Function *func,
|
void applyParamAttrsToLLFunc(TypeFunction *f, IrFuncTy &irFty,
|
||||||
FuncDeclaration *fdecl) {
|
llvm::Function *func) {
|
||||||
IrFuncTy &irFty = getIrFunc(fdecl)->irFty;
|
|
||||||
AttrSet newAttrs = AttrSet::extractFunctionAndReturnAttributes(func);
|
AttrSet newAttrs = AttrSet::extractFunctionAndReturnAttributes(func);
|
||||||
|
newAttrs.merge(irFty.getParamAttrs(gABI->passThisBeforeSret(f)));
|
||||||
int idx = 0;
|
|
||||||
|
|
||||||
// handle implicit args
|
|
||||||
#define ADD_PA(X) \
|
|
||||||
if (irFty.X) { \
|
|
||||||
newAttrs.add(idx, irFty.X->attrs); \
|
|
||||||
idx++; \
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_PA(ret)
|
|
||||||
|
|
||||||
if (irFty.arg_sret && irFty.arg_this && gABI->passThisBeforeSret(f)) {
|
|
||||||
ADD_PA(arg_this)
|
|
||||||
ADD_PA(arg_sret)
|
|
||||||
} else {
|
|
||||||
ADD_PA(arg_sret)
|
|
||||||
ADD_PA(arg_this)
|
|
||||||
}
|
|
||||||
|
|
||||||
ADD_PA(arg_nest)
|
|
||||||
ADD_PA(arg_arguments)
|
|
||||||
|
|
||||||
#undef ADD_PA
|
|
||||||
|
|
||||||
// Set attributes on the explicit parameters.
|
|
||||||
const size_t n = irFty.args.size();
|
|
||||||
for (size_t k = 0; k < n; k++) {
|
|
||||||
const size_t i = idx + (irFty.reverseParams ? (n - k - 1) : k);
|
|
||||||
newAttrs.add(i, irFty.args[k]->attrs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store the final attribute set
|
|
||||||
func->setAttributes(newAttrs);
|
func->setAttributes(newAttrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +466,7 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) {
|
||||||
|
|
||||||
// parameter attributes
|
// parameter attributes
|
||||||
if (!DtoIsIntrinsic(fdecl)) {
|
if (!DtoIsIntrinsic(fdecl)) {
|
||||||
set_param_attrs(f, func, fdecl);
|
applyParamAttrsToLLFunc(f, getIrFunc(fdecl)->irFty, func);
|
||||||
if (global.params.disableRedZone) {
|
if (global.params.disableRedZone) {
|
||||||
func->addFnAttr(LLAttribute::NoRedZone);
|
func->addFnAttr(LLAttribute::NoRedZone);
|
||||||
}
|
}
|
||||||
|
@ -928,8 +895,7 @@ void DtoDefineFunction(FuncDeclaration *fd) {
|
||||||
bb->eraseFromParent();
|
bb->eraseFromParent();
|
||||||
} else if (!gIR->scopereturned()) {
|
} else if (!gIR->scopereturned()) {
|
||||||
// llvm requires all basic blocks to end with a TerminatorInst but DMD does
|
// llvm requires all basic blocks to end with a TerminatorInst but DMD does
|
||||||
// not put a return statement
|
// not put a return statement in automatically, so we do it here.
|
||||||
// in automatically, so we do it here.
|
|
||||||
|
|
||||||
// pass the previous block into this block
|
// pass the previous block into this block
|
||||||
gIR->DBuilder.EmitStopPoint(fd->endloc);
|
gIR->DBuilder.EmitStopPoint(fd->endloc);
|
||||||
|
|
|
@ -25,7 +25,6 @@ class Parameter;
|
||||||
class Type;
|
class Type;
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
class FunctionType;
|
class FunctionType;
|
||||||
class Value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::FunctionType *DtoFunctionType(Type *t, IrFuncTy &irFty, Type *thistype,
|
llvm::FunctionType *DtoFunctionType(Type *t, IrFuncTy &irFty, Type *thistype,
|
||||||
|
|
|
@ -63,7 +63,7 @@ Type *getTypeInfoType(Type *t, Scope *sc);
|
||||||
LLValue *DtoNew(Loc &loc, Type *newtype) {
|
LLValue *DtoNew(Loc &loc, Type *newtype) {
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
|
getRuntimeFunction(loc, gIR->module, "_d_allocmemoryT");
|
||||||
// get type info
|
// get type info
|
||||||
LLConstant *ti = DtoTypeInfoOf(newtype);
|
LLConstant *ti = DtoTypeInfoOf(newtype);
|
||||||
assert(isaPointer(ti));
|
assert(isaPointer(ti));
|
||||||
|
@ -74,7 +74,7 @@ LLValue *DtoNew(Loc &loc, Type *newtype) {
|
||||||
}
|
}
|
||||||
|
|
||||||
LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
|
LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
|
||||||
llvm::Function *fn = LLVM_D_GetRuntimeFunction(
|
llvm::Function *fn = getRuntimeFunction(
|
||||||
loc, gIR->module,
|
loc, gIR->module,
|
||||||
newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT");
|
newtype->isZeroInit(newtype->sym->loc) ? "_d_newitemT" : "_d_newitemiT");
|
||||||
LLConstant *ti = DtoTypeInfoOf(newtype);
|
LLConstant *ti = DtoTypeInfoOf(newtype);
|
||||||
|
@ -84,7 +84,7 @@ LLValue *DtoNewStruct(Loc &loc, TypeStruct *newtype) {
|
||||||
|
|
||||||
void DtoDeleteMemory(Loc &loc, DValue *ptr) {
|
void DtoDeleteMemory(Loc &loc, DValue *ptr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
getRuntimeFunction(loc, gIR->module, "_d_delmemory");
|
||||||
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
|
@ -92,7 +92,7 @@ void DtoDeleteMemory(Loc &loc, DValue *ptr) {
|
||||||
|
|
||||||
void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
getRuntimeFunction(loc, gIR->module, "_d_delstruct");
|
||||||
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
LLValue *lval = (ptr->isLVal() ? ptr->getLVal() : makeLValue(loc, ptr));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)),
|
||||||
|
@ -102,7 +102,7 @@ void DtoDeleteStruct(Loc &loc, DValue *ptr) {
|
||||||
|
|
||||||
void DtoDeleteClass(Loc &loc, DValue *inst) {
|
void DtoDeleteClass(Loc &loc, DValue *inst) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delclass");
|
getRuntimeFunction(loc, gIR->module, "_d_delclass");
|
||||||
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
|
@ -110,7 +110,7 @@ void DtoDeleteClass(Loc &loc, DValue *inst) {
|
||||||
|
|
||||||
void DtoDeleteInterface(Loc &loc, DValue *inst) {
|
void DtoDeleteInterface(Loc &loc, DValue *inst) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
getRuntimeFunction(loc, gIR->module, "_d_delinterface");
|
||||||
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
LLValue *lval = (inst->isLVal() ? inst->getLVal() : makeLValue(loc, inst));
|
||||||
gIR->CreateCallOrInvoke(
|
gIR->CreateCallOrInvoke(
|
||||||
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
fn, DtoBitCast(lval, fn->getFunctionType()->getParamType(0)));
|
||||||
|
@ -118,7 +118,7 @@ void DtoDeleteInterface(Loc &loc, DValue *inst) {
|
||||||
|
|
||||||
void DtoDeleteArray(Loc &loc, DValue *arr) {
|
void DtoDeleteArray(Loc &loc, DValue *arr) {
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_delarray_t");
|
getRuntimeFunction(loc, gIR->module, "_d_delarray_t");
|
||||||
llvm::FunctionType *fty = fn->getFunctionType();
|
llvm::FunctionType *fty = fn->getFunctionType();
|
||||||
|
|
||||||
// the TypeInfo argument must be null if the type has no dtor
|
// the TypeInfo argument must be null if the type has no dtor
|
||||||
|
@ -183,7 +183,7 @@ llvm::AllocaInst *DtoRawAlloca(LLType *lltype, size_t alignment,
|
||||||
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name) {
|
LLValue *DtoGcMalloc(Loc &loc, LLType *lltype, const char *name) {
|
||||||
// get runtime function
|
// get runtime function
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(loc, gIR->module, "_d_allocmemory");
|
getRuntimeFunction(loc, gIR->module, "_d_allocmemory");
|
||||||
// parameters
|
// parameters
|
||||||
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
LLValue *size = DtoConstSize_t(getTypeAllocSize(lltype));
|
||||||
// call runtime allocator
|
// call runtime allocator
|
||||||
|
@ -232,7 +232,7 @@ LLValue *DtoAllocaDump(LLValue *val, LLType *asType, int alignment,
|
||||||
void DtoAssert(Module *M, Loc &loc, DValue *msg) {
|
void DtoAssert(Module *M, Loc &loc, DValue *msg) {
|
||||||
// func
|
// func
|
||||||
const char *fname = msg ? "_d_assert_msg" : "_d_assert";
|
const char *fname = msg ? "_d_assert_msg" : "_d_assert";
|
||||||
llvm::Function *fn = LLVM_D_GetRuntimeFunction(loc, gIR->module, fname);
|
llvm::Function *fn = getRuntimeFunction(loc, gIR->module, fname);
|
||||||
|
|
||||||
// Arguments
|
// Arguments
|
||||||
llvm::SmallVector<LLValue *, 3> args;
|
llvm::SmallVector<LLValue *, 3> args;
|
||||||
|
|
|
@ -378,7 +378,7 @@ static void build_dso_ctor_dtor_body(
|
||||||
llvm::Value *dsoSlot, llvm::Value *minfoBeg, llvm::Value *minfoEnd,
|
llvm::Value *dsoSlot, llvm::Value *minfoBeg, llvm::Value *minfoEnd,
|
||||||
llvm::Value *minfoUsedPointer, bool executeWhenInitialized) {
|
llvm::Value *minfoUsedPointer, bool executeWhenInitialized) {
|
||||||
llvm::Function *const dsoRegistry =
|
llvm::Function *const dsoRegistry =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), gIR->module, "_d_dso_registry");
|
getRuntimeFunction(Loc(), gIR->module, "_d_dso_registry");
|
||||||
llvm::Type *const recordPtrTy =
|
llvm::Type *const recordPtrTy =
|
||||||
dsoRegistry->getFunctionType()->getContainedType(1);
|
dsoRegistry->getFunctionType()->getContainedType(1);
|
||||||
|
|
||||||
|
@ -670,7 +670,7 @@ static void addCoverageAnalysis(Module *m) {
|
||||||
|
|
||||||
// Set up call to _d_cover_register2
|
// Set up call to _d_cover_register2
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), gIR->module, "_d_cover_register2");
|
getRuntimeFunction(Loc(), gIR->module, "_d_cover_register2");
|
||||||
LLValue *args[] = {DtoConstString(m->srcfile->name->toChars()),
|
LLValue *args[] = {DtoConstString(m->srcfile->name->toChars()),
|
||||||
d_cover_valid_slice, d_cover_data_slice,
|
d_cover_valid_slice, d_cover_data_slice,
|
||||||
DtoConstUbyte(global.params.covPercent)};
|
DtoConstUbyte(global.params.covPercent)};
|
||||||
|
@ -723,7 +723,7 @@ void codegenModule(IRState *irs, Module *m, bool emitFullModuleInfo) {
|
||||||
assert(!gIR && "gIR not null, codegen already in progress?!");
|
assert(!gIR && "gIR not null, codegen already in progress?!");
|
||||||
gIR = irs;
|
gIR = irs;
|
||||||
|
|
||||||
LLVM_D_InitRuntime();
|
initRuntime();
|
||||||
|
|
||||||
// Skip pseudo-modules for coverage analysis
|
// Skip pseudo-modules for coverage analysis
|
||||||
std::string name = m->toChars();
|
std::string name = m->toChars();
|
||||||
|
|
756
gen/runtime.cpp
756
gen/runtime.cpp
File diff suppressed because it is too large
Load diff
|
@ -23,14 +23,13 @@ class Module;
|
||||||
struct Loc;
|
struct Loc;
|
||||||
|
|
||||||
// D runtime support helpers
|
// D runtime support helpers
|
||||||
|
bool initRuntime();
|
||||||
|
void freeRuntime();
|
||||||
|
|
||||||
bool LLVM_D_InitRuntime();
|
llvm::Function *getRuntimeFunction(const Loc &loc, llvm::Module &target,
|
||||||
void LLVM_D_FreeRuntime();
|
|
||||||
|
|
||||||
llvm::Function *LLVM_D_GetRuntimeFunction(const Loc &loc, llvm::Module &target,
|
|
||||||
const char *name);
|
const char *name);
|
||||||
|
|
||||||
llvm::GlobalVariable *
|
llvm::GlobalVariable *
|
||||||
LLVM_D_GetRuntimeGlobal(const Loc &loc, llvm::Module &target, const char *name);
|
getRuntimeGlobal(const Loc &loc, llvm::Module &target, const char *name);
|
||||||
|
|
||||||
#endif // LDC_GEN_RUNTIME_H
|
#endif // LDC_GEN_RUNTIME_H
|
||||||
|
|
|
@ -73,7 +73,7 @@ static LLValue *call_string_switch_runtime(llvm::Value *table, Expression *e) {
|
||||||
llvm_unreachable("not char/wchar/dchar");
|
llvm_unreachable("not char/wchar/dchar");
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Function *fn = LLVM_D_GetRuntimeFunction(e->loc, gIR->module, fname);
|
llvm::Function *fn = getRuntimeFunction(e->loc, gIR->module, fname);
|
||||||
|
|
||||||
IF_LOG {
|
IF_LOG {
|
||||||
Logger::cout() << *table->getType() << '\n';
|
Logger::cout() << *table->getType() << '\n';
|
||||||
|
@ -745,7 +745,7 @@ public:
|
||||||
irs->DBuilder.EmitBlockStart((*it)->loc);
|
irs->DBuilder.EmitBlockStart((*it)->loc);
|
||||||
|
|
||||||
const auto enterCatchFn =
|
const auto enterCatchFn =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_enter_catch");
|
getRuntimeFunction(Loc(), irs->module, "_d_eh_enter_catch");
|
||||||
auto exceptionStruct = DtoLoad(irs->func()->getOrCreateEhPtrSlot());
|
auto exceptionStruct = DtoLoad(irs->func()->getOrCreateEhPtrSlot());
|
||||||
auto throwableObj = irs->ir->CreateCall(enterCatchFn, exceptionStruct);
|
auto throwableObj = irs->ir->CreateCall(enterCatchFn, exceptionStruct);
|
||||||
|
|
||||||
|
@ -825,7 +825,7 @@ public:
|
||||||
DValue *e = toElemDtor(stmt->exp);
|
DValue *e = toElemDtor(stmt->exp);
|
||||||
|
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(stmt->loc, irs->module, "_d_throw_exception");
|
getRuntimeFunction(stmt->loc, irs->module, "_d_throw_exception");
|
||||||
LLValue *arg =
|
LLValue *arg =
|
||||||
DtoBitCast(e->getRVal(), fn->getFunctionType()->getParamType(0));
|
DtoBitCast(e->getRVal(), fn->getFunctionType()->getParamType(0));
|
||||||
;
|
;
|
||||||
|
@ -1507,7 +1507,7 @@ public:
|
||||||
LOG_SCOPE;
|
LOG_SCOPE;
|
||||||
|
|
||||||
llvm::Function *fn =
|
llvm::Function *fn =
|
||||||
LLVM_D_GetRuntimeFunction(stmt->loc, irs->module, "_d_switch_error");
|
getRuntimeFunction(stmt->loc, irs->module, "_d_switch_error");
|
||||||
|
|
||||||
LLValue *moduleInfoSymbol =
|
LLValue *moduleInfoSymbol =
|
||||||
getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
|
getIrModule(irs->func()->decl->getModule())->moduleInfoSymbol();
|
||||||
|
|
|
@ -1912,7 +1912,7 @@ public:
|
||||||
!(static_cast<TypeClass *>(condty)->sym->isInterfaceDeclaration()) &&
|
!(static_cast<TypeClass *>(condty)->sym->isInterfaceDeclaration()) &&
|
||||||
!(static_cast<TypeClass *>(condty)->sym->isCPPclass())) {
|
!(static_cast<TypeClass *>(condty)->sym->isCPPclass())) {
|
||||||
Logger::println("calling class invariant");
|
Logger::println("calling class invariant");
|
||||||
llvm::Function *fn = LLVM_D_GetRuntimeFunction(
|
llvm::Function *fn = getRuntimeFunction(
|
||||||
e->loc, gIR->module,
|
e->loc, gIR->module,
|
||||||
gABI->mangleForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)
|
gABI->mangleForLLVM("_D9invariant12_d_invariantFC6ObjectZv", LINKd)
|
||||||
.c_str());
|
.c_str());
|
||||||
|
@ -2668,7 +2668,7 @@ public:
|
||||||
Type *indexType = static_cast<TypeAArray *>(aatype)->index;
|
Type *indexType = static_cast<TypeAArray *>(aatype)->index;
|
||||||
assert(indexType && vtype);
|
assert(indexType && vtype);
|
||||||
|
|
||||||
llvm::Function *func = LLVM_D_GetRuntimeFunction(
|
llvm::Function *func = getRuntimeFunction(
|
||||||
e->loc, gIR->module, "_d_assocarrayliteralTX");
|
e->loc, gIR->module, "_d_assocarrayliteralTX");
|
||||||
LLFunctionType *funcTy = func->getFunctionType();
|
LLFunctionType *funcTy = func->getFunctionType();
|
||||||
LLValue *aaTypeInfo =
|
LLValue *aaTypeInfo =
|
||||||
|
|
|
@ -291,13 +291,13 @@ llvm::LandingPadInst *createLandingPadInst(IRState *irs) {
|
||||||
LLFunction *currentFunction = irs->func()->func;
|
LLFunction *currentFunction = irs->func()->func;
|
||||||
if (!currentFunction->hasPersonalityFn()) {
|
if (!currentFunction->hasPersonalityFn()) {
|
||||||
LLFunction *personalityFn =
|
LLFunction *personalityFn =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
|
getRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
|
||||||
currentFunction->setPersonalityFn(personalityFn);
|
currentFunction->setPersonalityFn(personalityFn);
|
||||||
}
|
}
|
||||||
return irs->ir->CreateLandingPad(retType, 0);
|
return irs->ir->CreateLandingPad(retType, 0);
|
||||||
#else
|
#else
|
||||||
LLFunction *personalityFn =
|
LLFunction *personalityFn =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
|
getRuntimeFunction(Loc(), irs->module, "_d_eh_personality");
|
||||||
return irs->ir->CreateLandingPad(retType, personalityFn, 0);
|
return irs->ir->CreateLandingPad(retType, personalityFn, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -424,7 +424,7 @@ llvm::BasicBlock *IrFunction::getOrCreateResumeUnwindBlock() {
|
||||||
gIR->scope() = IRScope(resumeUnwindBlock);
|
gIR->scope() = IRScope(resumeUnwindBlock);
|
||||||
|
|
||||||
llvm::Function *resumeFn =
|
llvm::Function *resumeFn =
|
||||||
LLVM_D_GetRuntimeFunction(Loc(), gIR->module, "_d_eh_resume_unwind");
|
getRuntimeFunction(Loc(), gIR->module, "_d_eh_resume_unwind");
|
||||||
gIR->ir->CreateCall(resumeFn, gIR->ir->CreateLoad(getOrCreateEhPtrSlot()));
|
gIR->ir->CreateCall(resumeFn, gIR->ir->CreateLoad(getOrCreateEhPtrSlot()));
|
||||||
gIR->ir->CreateUnreachable();
|
gIR->ir->CreateUnreachable();
|
||||||
|
|
||||||
|
|
|
@ -90,3 +90,40 @@ void IrFuncTy::getParam(Type *dty, size_t idx, LLValue *val, LLValue *address) {
|
||||||
|
|
||||||
DtoStoreZextI8(val, address);
|
DtoStoreZextI8(val, address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AttrSet IrFuncTy::getParamAttrs(bool passThisBeforeSret) {
|
||||||
|
AttrSet newAttrs;
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
|
||||||
|
// handle implicit args
|
||||||
|
#define ADD_PA(X) \
|
||||||
|
if (X) { \
|
||||||
|
newAttrs.add(idx, X->attrs); \
|
||||||
|
idx++; \
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_PA(ret)
|
||||||
|
|
||||||
|
if (arg_sret && arg_this && passThisBeforeSret) {
|
||||||
|
ADD_PA(arg_this)
|
||||||
|
ADD_PA(arg_sret)
|
||||||
|
} else {
|
||||||
|
ADD_PA(arg_sret)
|
||||||
|
ADD_PA(arg_this)
|
||||||
|
}
|
||||||
|
|
||||||
|
ADD_PA(arg_nest)
|
||||||
|
ADD_PA(arg_arguments)
|
||||||
|
|
||||||
|
#undef ADD_PA
|
||||||
|
|
||||||
|
// Set attributes on the explicit parameters.
|
||||||
|
const size_t n = args.size();
|
||||||
|
for (size_t k = 0; k < n; k++) {
|
||||||
|
const size_t i = idx + (reverseParams ? (n - k - 1) : k);
|
||||||
|
newAttrs.add(i, args[k]->attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return newAttrs;
|
||||||
|
}
|
||||||
|
|
|
@ -116,6 +116,8 @@ struct IrFuncTy {
|
||||||
llvm::Value *putParam(size_t idx, DValue *dval);
|
llvm::Value *putParam(size_t idx, DValue *dval);
|
||||||
llvm::Value *putParam(const IrFuncTyArg &arg, DValue *dval);
|
llvm::Value *putParam(const IrFuncTyArg &arg, DValue *dval);
|
||||||
void getParam(Type *dty, size_t idx, llvm::Value *val, llvm::Value *address);
|
void getParam(Type *dty, size_t idx, llvm::Value *val, llvm::Value *address);
|
||||||
|
|
||||||
|
AttrSet getParamAttrs(bool passThisBeforeSret);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue