mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 23:50:43 +03:00
Fix debuginfos for nested ref/out parameters (use llvm.dbg.declare)
llvm.dbg.value() apparently doesn't like GEP + deref, so use llvm.dbg.declare() & GEP.
This commit is contained in:
parent
93decabe6c
commit
8cc5ff6e79
6 changed files with 55 additions and 35 deletions
|
@ -1034,7 +1034,7 @@ void ldc::DIBuilder::EmitValue(llvm::Value *val, VarDeclaration *vd) {
|
||||||
|
|
||||||
void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
|
void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
|
||||||
Type *type, bool isThisPtr,
|
Type *type, bool isThisPtr,
|
||||||
bool forceAsLocal,
|
bool forceAsLocal, bool isRefRVal,
|
||||||
llvm::ArrayRef<int64_t> addr) {
|
llvm::ArrayRef<int64_t> addr) {
|
||||||
if (!mustEmitFullDebugInfo())
|
if (!mustEmitFullDebugInfo())
|
||||||
return;
|
return;
|
||||||
|
@ -1054,16 +1054,21 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
|
||||||
if (static_cast<llvm::MDNode *>(TD) == nullptr)
|
if (static_cast<llvm::MDNode *>(TD) == nullptr)
|
||||||
return; // unsupported
|
return; // unsupported
|
||||||
|
|
||||||
|
const bool isRefOrOut = vd->isRef() || vd->isOut(); // incl. special-ref vars
|
||||||
|
|
||||||
|
// For MSVC x64 targets, declare params rewritten by ExplicitByvalRewrite as
|
||||||
|
// DI references, as if they were ref parameters.
|
||||||
|
const bool isPassedExplicitlyByval =
|
||||||
|
isTargetMSVCx64 && !isRefOrOut && isaArgument(ll) && addr.empty();
|
||||||
|
|
||||||
bool useDbgValueIntrinsic = false;
|
bool useDbgValueIntrinsic = false;
|
||||||
if (vd->isRef() || vd->isOut() ||
|
if (isRefOrOut || isPassedExplicitlyByval) {
|
||||||
// For MSVC x64 targets, declare params rewritten by ExplicitByvalRewrite
|
|
||||||
// as DI references, as if they were ref parameters.
|
|
||||||
(isTargetMSVCx64 && isaArgument(ll) && addr.empty())) {
|
|
||||||
// With the exception of special-ref loop variables, the reference/pointer
|
// With the exception of special-ref loop variables, the reference/pointer
|
||||||
// itself is constant. So we don't have to attach the debug information to a
|
// itself is constant. So we don't have to attach the debug information to a
|
||||||
// memory location and can use llvm.dbg.value to set the constant pointer
|
// memory location and can use llvm.dbg.value to set the constant pointer
|
||||||
// for the DI reference.
|
// for the DI reference.
|
||||||
useDbgValueIntrinsic = !isSpecialRefVar(vd);
|
useDbgValueIntrinsic =
|
||||||
|
isPassedExplicitlyByval || (!isSpecialRefVar(vd) && isRefRVal);
|
||||||
#if LDC_LLVM_VER >= 308
|
#if LDC_LLVM_VER >= 308
|
||||||
// Note: createReferenceType expects the size to be the size of a pointer,
|
// Note: createReferenceType expects the size to be the size of a pointer,
|
||||||
// not the size of the type the reference refers to.
|
// not the size of the type the reference refers to.
|
||||||
|
|
|
@ -116,19 +116,21 @@ public:
|
||||||
/// \brief Emits all things necessary for making debug info for a local
|
/// \brief Emits all things necessary for making debug info for a local
|
||||||
/// variable vd.
|
/// variable vd.
|
||||||
/// \param ll LL value which, in combination with `addr`, yields the
|
/// \param ll LL value which, in combination with `addr`, yields the
|
||||||
/// storage/lvalue of the variable (not treating ref/out params as special
|
/// storage/lvalue of the variable. For special-ref loop variables, specify
|
||||||
/// case; what's needed is the lvalue of the original variable).
|
/// the storage/lvalue of the reference/pointer.
|
||||||
/// For special-ref loop variables, specify the lvalue of the reference/
|
|
||||||
/// pointer.
|
|
||||||
/// \param vd Variable declaration to emit debug info for.
|
/// \param vd Variable declaration to emit debug info for.
|
||||||
/// \param type Type of variable if different from vd->type
|
/// \param type Type of variable if different from vd->type
|
||||||
/// \param isThisPtr Variable is hidden this pointer
|
/// \param isThisPtr Variable is hidden this pointer
|
||||||
/// \param forceAsLocal Emit as local even if the variable is a parameter
|
/// \param forceAsLocal Emit as local even if the variable is a parameter
|
||||||
|
/// \param isRefRVal Only relevant for ref/out parameters: indicates whether
|
||||||
|
/// ll & addr specify the reference's rvalue, i.e., the lvalue of the original
|
||||||
|
/// variable, instead of the reference's lvalue.
|
||||||
/// \param addr An array of complex address operations encoding a DWARF
|
/// \param addr An array of complex address operations encoding a DWARF
|
||||||
/// expression.
|
/// expression.
|
||||||
void
|
void
|
||||||
EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Type *type = nullptr,
|
EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Type *type = nullptr,
|
||||||
bool isThisPtr = false, bool forceAsLocal = false,
|
bool isThisPtr = false, bool forceAsLocal = false,
|
||||||
|
bool isRefRVal = false,
|
||||||
llvm::ArrayRef<int64_t> addr = llvm::ArrayRef<int64_t>());
|
llvm::ArrayRef<int64_t> addr = llvm::ArrayRef<int64_t>());
|
||||||
|
|
||||||
/// \brief Emits all things necessary for making debug info for a global
|
/// \brief Emits all things necessary for making debug info for a global
|
||||||
|
|
|
@ -770,8 +770,12 @@ void defineParameters(IrFuncTy &irFty, VarDeclarations ¶meters) {
|
||||||
|
|
||||||
// The debuginfos for captured params are handled later by
|
// The debuginfos for captured params are handled later by
|
||||||
// DtoCreateNestedContext().
|
// DtoCreateNestedContext().
|
||||||
if (global.params.symdebug && vd->nestedrefs.dim == 0)
|
if (global.params.symdebug && vd->nestedrefs.dim == 0) {
|
||||||
gIR->DBuilder.EmitLocalVariable(irparam->value, vd, paramType);
|
// Reference (ref/out) parameters have no storage themselves as they are
|
||||||
|
// constant pointers, so pass the reference rvalue to EmitLocalVariable().
|
||||||
|
gIR->DBuilder.EmitLocalVariable(irparam->value, vd, paramType, false,
|
||||||
|
false, /*isRefRVal=*/true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -129,15 +129,15 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
||||||
Logger::cout() << "Addr: " << *val << '\n';
|
Logger::cout() << "Addr: " << *val << '\n';
|
||||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||||
}
|
}
|
||||||
|
const bool isRefOrOut = vd->isRef() || vd->isOut();
|
||||||
if (isSpecialRefVar(vd)) {
|
if (isSpecialRefVar(vd)) {
|
||||||
// Handled appropriately by makeVarDValue() and
|
// Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass
|
||||||
// DIBuilder::EmitLocalVariable(), pass storage of pointer (reference
|
// storage of pointer (reference lvalue).
|
||||||
// lvalue).
|
} else if (byref || isRefOrOut) {
|
||||||
} else if (byref || vd->isRef() || vd->isOut()) {
|
|
||||||
// makeVarDValue() and DIBuilder::EmitLocalVariable() expect the original
|
|
||||||
// variable's lvalue for ref/out params too (i.e., the reference rvalue),
|
|
||||||
// so always dereference.
|
|
||||||
val = DtoAlignedLoad(val);
|
val = DtoAlignedLoad(val);
|
||||||
|
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable();
|
||||||
|
// pass the GEP as reference lvalue in that case.
|
||||||
|
if (!isRefOrOut)
|
||||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||||
IF_LOG {
|
IF_LOG {
|
||||||
Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
|
Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
|
||||||
|
@ -146,8 +146,8 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!skipDIDeclaration && global.params.symdebug) {
|
if (!skipDIDeclaration && global.params.symdebug) {
|
||||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, true,
|
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false,
|
||||||
dwarfAddrOps);
|
/*forceAsLocal=*/true, false, dwarfAddrOps);
|
||||||
}
|
}
|
||||||
|
|
||||||
return makeVarDValue(astype, vd, val);
|
return makeVarDValue(astype, vd, val);
|
||||||
|
@ -482,7 +482,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
||||||
if (vd->isRef() || vd->isOut()) {
|
if (vd->isRef() || vd->isOut()) {
|
||||||
Logger::println("Captured by reference, copying pointer to nested frame");
|
Logger::println("Captured by reference, copying pointer to nested frame");
|
||||||
DtoAlignedStore(parm->value, gep);
|
DtoAlignedStore(parm->value, gep);
|
||||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
// pass GEP as reference lvalue to EmitLocalVariable()
|
||||||
} else {
|
} else {
|
||||||
Logger::println("Copying to nested frame");
|
Logger::println("Copying to nested frame");
|
||||||
// The parameter value is an alloca'd stack slot.
|
// The parameter value is an alloca'd stack slot.
|
||||||
|
@ -499,7 +499,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (global.params.symdebug) {
|
if (global.params.symdebug) {
|
||||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false,
|
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false, false,
|
||||||
dwarfAddrOps);
|
dwarfAddrOps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,35 +16,44 @@ void encloser(int arg0, ref int arg1)
|
||||||
// CDB: g
|
// CDB: g
|
||||||
// CDB: dv /t
|
// CDB: dv /t
|
||||||
// CHECK: int arg0 = 0n1
|
// CHECK: int arg0 = 0n1
|
||||||
// arg1 is missing
|
// (cdb displays references as pointers)
|
||||||
|
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||||
// CHECK-NEXT: int enc_n = 0n123
|
// CHECK-NEXT: int enc_n = 0n123
|
||||||
|
// CDB: ?? *arg1
|
||||||
|
// CHECK: int 0n2
|
||||||
enc_n += arg1;
|
enc_n += arg1;
|
||||||
|
|
||||||
void nested(int nes_i)
|
void nested(int nes_i)
|
||||||
{
|
{
|
||||||
int blub = arg0 + arg1 + enc_n;
|
int blub = arg0 + arg1 + enc_n;
|
||||||
// CDB: bp `nested_cdb.d:26`
|
// CDB: bp `nested_cdb.d:29`
|
||||||
// CDB: g
|
// CDB: g
|
||||||
// CDB: dv /t
|
// CDB: dv /t
|
||||||
// CHECK: int arg0 = 0n1
|
// CHECK: int arg0 = 0n1
|
||||||
// arg1 is missing
|
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||||
// CHECK-NEXT: int enc_n = 0n125
|
// CHECK-NEXT: int enc_n = 0n125
|
||||||
|
// CDB: ?? *arg1
|
||||||
|
// CHECK: int 0n2
|
||||||
arg0 = arg1 = enc_n = nes_i;
|
arg0 = arg1 = enc_n = nes_i;
|
||||||
// CDB: bp `nested_cdb.d:33`
|
// CDB: bp `nested_cdb.d:38`
|
||||||
// CDB: g
|
// CDB: g
|
||||||
// CDB: dv /t
|
// CDB: dv /t
|
||||||
// CHECK: int arg0 = 0n456
|
// CHECK: int arg0 = 0n456
|
||||||
// arg1 is missing
|
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||||
// CHECK-NEXT: int enc_n = 0n456
|
// CHECK-NEXT: int enc_n = 0n456
|
||||||
|
// CDB: ?? *arg1
|
||||||
|
// CHECK: int 0n456
|
||||||
}
|
}
|
||||||
|
|
||||||
nested(456);
|
nested(456);
|
||||||
// CDB: bp `nested_cdb.d:42`
|
// CDB: bp `nested_cdb.d:49`
|
||||||
// CDB: g
|
// CDB: g
|
||||||
// CDB: dv /t
|
// CDB: dv /t
|
||||||
// CHECK: int arg0 = 0n456
|
// CHECK: int arg0 = 0n456
|
||||||
// arg1 is missing
|
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||||
// CHECK-NEXT: int enc_n = 0n456
|
// CHECK-NEXT: int enc_n = 0n456
|
||||||
|
// CDB: ?? *arg1
|
||||||
|
// CHECK: int 0n456
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
|
|
|
@ -12,7 +12,7 @@ void encloser(int arg0, ref int arg1)
|
||||||
// GDB: p arg0
|
// GDB: p arg0
|
||||||
// CHECK: $1 = 1
|
// CHECK: $1 = 1
|
||||||
// GDB: p arg1
|
// GDB: p arg1
|
||||||
// no-CHECK: $2 = 2 (<optimized out>)
|
// CHECK: $2 = (int &) @{{0x[0-9a-f]*}}: 2
|
||||||
// GDB: p enc_n
|
// GDB: p enc_n
|
||||||
// CHECK: $3 = 123
|
// CHECK: $3 = 123
|
||||||
enc_n += arg1;
|
enc_n += arg1;
|
||||||
|
@ -25,7 +25,7 @@ void encloser(int arg0, ref int arg1)
|
||||||
// GDB: p arg0
|
// GDB: p arg0
|
||||||
// CHECK: $4 = 1
|
// CHECK: $4 = 1
|
||||||
// GDB: p arg1
|
// GDB: p arg1
|
||||||
// no-CHECK: $5 = 2 (<optimized out>)
|
// CHECK: $5 = (int &) @{{0x[0-9a-f]*}}: 2
|
||||||
// GDB: p enc_n
|
// GDB: p enc_n
|
||||||
// CHECK: $6 = 125
|
// CHECK: $6 = 125
|
||||||
arg0 = arg1 = enc_n = nes_i;
|
arg0 = arg1 = enc_n = nes_i;
|
||||||
|
@ -34,7 +34,7 @@ void encloser(int arg0, ref int arg1)
|
||||||
// GDB: p arg0
|
// GDB: p arg0
|
||||||
// CHECK: $7 = 456
|
// CHECK: $7 = 456
|
||||||
// GDB: p arg1
|
// GDB: p arg1
|
||||||
// no-CHECK: $8 = 456 (<optimized out>)
|
// CHECK: $8 = (int &) @{{0x[0-9a-f]*}}: 456
|
||||||
// GDB: p enc_n
|
// GDB: p enc_n
|
||||||
// CHECK: $9 = 456
|
// CHECK: $9 = 456
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ void encloser(int arg0, ref int arg1)
|
||||||
// GDB: p arg0
|
// GDB: p arg0
|
||||||
// CHECK: $10 = 456
|
// CHECK: $10 = 456
|
||||||
// GDB: p arg1
|
// GDB: p arg1
|
||||||
// no-CHECK: $11 = 456 (<optimized out>)
|
// CHECK: $11 = (int &) @{{0x[0-9a-f]*}}: 456
|
||||||
// GDB: p enc_n
|
// GDB: p enc_n
|
||||||
// CHECK: $12 = 456
|
// CHECK: $12 = 456
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue