mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30: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,
|
||||
Type *type, bool isThisPtr,
|
||||
bool forceAsLocal,
|
||||
bool forceAsLocal, bool isRefRVal,
|
||||
llvm::ArrayRef<int64_t> addr) {
|
||||
if (!mustEmitFullDebugInfo())
|
||||
return;
|
||||
|
@ -1054,16 +1054,21 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd,
|
|||
if (static_cast<llvm::MDNode *>(TD) == nullptr)
|
||||
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;
|
||||
if (vd->isRef() || vd->isOut() ||
|
||||
// For MSVC x64 targets, declare params rewritten by ExplicitByvalRewrite
|
||||
// as DI references, as if they were ref parameters.
|
||||
(isTargetMSVCx64 && isaArgument(ll) && addr.empty())) {
|
||||
if (isRefOrOut || isPassedExplicitlyByval) {
|
||||
// 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
|
||||
// memory location and can use llvm.dbg.value to set the constant pointer
|
||||
// for the DI reference.
|
||||
useDbgValueIntrinsic = !isSpecialRefVar(vd);
|
||||
useDbgValueIntrinsic =
|
||||
isPassedExplicitlyByval || (!isSpecialRefVar(vd) && isRefRVal);
|
||||
#if LDC_LLVM_VER >= 308
|
||||
// Note: createReferenceType expects the size to be the size of a pointer,
|
||||
// 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
|
||||
/// variable vd.
|
||||
/// \param ll LL value which, in combination with `addr`, yields the
|
||||
/// storage/lvalue of the variable (not treating ref/out params as special
|
||||
/// case; what's needed is the lvalue of the original variable).
|
||||
/// For special-ref loop variables, specify the lvalue of the reference/
|
||||
/// pointer.
|
||||
/// storage/lvalue of the variable. For special-ref loop variables, specify
|
||||
/// the storage/lvalue of the reference/pointer.
|
||||
/// \param vd Variable declaration to emit debug info for.
|
||||
/// \param type Type of variable if different from vd->type
|
||||
/// \param isThisPtr Variable is hidden this pointer
|
||||
/// \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
|
||||
/// expression.
|
||||
void
|
||||
EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, Type *type = nullptr,
|
||||
bool isThisPtr = false, bool forceAsLocal = false,
|
||||
bool isRefRVal = false,
|
||||
llvm::ArrayRef<int64_t> addr = llvm::ArrayRef<int64_t>());
|
||||
|
||||
/// \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
|
||||
// DtoCreateNestedContext().
|
||||
if (global.params.symdebug && vd->nestedrefs.dim == 0)
|
||||
gIR->DBuilder.EmitLocalVariable(irparam->value, vd, paramType);
|
||||
if (global.params.symdebug && vd->nestedrefs.dim == 0) {
|
||||
// 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,16 +129,16 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
Logger::cout() << "Addr: " << *val << '\n';
|
||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||
}
|
||||
const bool isRefOrOut = vd->isRef() || vd->isOut();
|
||||
if (isSpecialRefVar(vd)) {
|
||||
// Handled appropriately by makeVarDValue() and
|
||||
// DIBuilder::EmitLocalVariable(), pass storage of pointer (reference
|
||||
// lvalue).
|
||||
} 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.
|
||||
// Handled appropriately by makeVarDValue() and EmitLocalVariable(), pass
|
||||
// storage of pointer (reference lvalue).
|
||||
} else if (byref || isRefOrOut) {
|
||||
val = DtoAlignedLoad(val);
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
// 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);
|
||||
IF_LOG {
|
||||
Logger::cout() << "Was byref, now: " << *irLocal->value << '\n';
|
||||
Logger::cout() << "of type: " << *irLocal->value->getType() << '\n';
|
||||
|
@ -146,8 +146,8 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
}
|
||||
|
||||
if (!skipDIDeclaration && global.params.symdebug) {
|
||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, true,
|
||||
dwarfAddrOps);
|
||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false,
|
||||
/*forceAsLocal=*/true, false, dwarfAddrOps);
|
||||
}
|
||||
|
||||
return makeVarDValue(astype, vd, val);
|
||||
|
@ -482,7 +482,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
|||
if (vd->isRef() || vd->isOut()) {
|
||||
Logger::println("Captured by reference, copying pointer to nested frame");
|
||||
DtoAlignedStore(parm->value, gep);
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
// pass GEP as reference lvalue to EmitLocalVariable()
|
||||
} else {
|
||||
Logger::println("Copying to nested frame");
|
||||
// The parameter value is an alloca'd stack slot.
|
||||
|
@ -499,7 +499,7 @@ void DtoCreateNestedContext(FuncGenState &funcGen) {
|
|||
}
|
||||
|
||||
if (global.params.symdebug) {
|
||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false,
|
||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false, false, false,
|
||||
dwarfAddrOps);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,35 +16,44 @@ void encloser(int arg0, ref int arg1)
|
|||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// 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
|
||||
// CDB: ?? *arg1
|
||||
// CHECK: int 0n2
|
||||
enc_n += arg1;
|
||||
|
||||
void nested(int nes_i)
|
||||
{
|
||||
int blub = arg0 + arg1 + enc_n;
|
||||
// CDB: bp `nested_cdb.d:26`
|
||||
// CDB: bp `nested_cdb.d:29`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n1
|
||||
// arg1 is missing
|
||||
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||
// CHECK-NEXT: int enc_n = 0n125
|
||||
// CDB: ?? *arg1
|
||||
// CHECK: int 0n2
|
||||
arg0 = arg1 = enc_n = nes_i;
|
||||
// CDB: bp `nested_cdb.d:33`
|
||||
// CDB: bp `nested_cdb.d:38`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n456
|
||||
// arg1 is missing
|
||||
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||
// CHECK-NEXT: int enc_n = 0n456
|
||||
// CDB: ?? *arg1
|
||||
// CHECK: int 0n456
|
||||
}
|
||||
|
||||
nested(456);
|
||||
// CDB: bp `nested_cdb.d:42`
|
||||
// CDB: bp `nested_cdb.d:49`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n456
|
||||
// arg1 is missing
|
||||
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||
// CHECK-NEXT: int enc_n = 0n456
|
||||
// CDB: ?? *arg1
|
||||
// CHECK: int 0n456
|
||||
}
|
||||
|
||||
void main()
|
||||
|
|
|
@ -12,7 +12,7 @@ void encloser(int arg0, ref int arg1)
|
|||
// GDB: p arg0
|
||||
// CHECK: $1 = 1
|
||||
// GDB: p arg1
|
||||
// no-CHECK: $2 = 2 (<optimized out>)
|
||||
// CHECK: $2 = (int &) @{{0x[0-9a-f]*}}: 2
|
||||
// GDB: p enc_n
|
||||
// CHECK: $3 = 123
|
||||
enc_n += arg1;
|
||||
|
@ -25,7 +25,7 @@ void encloser(int arg0, ref int arg1)
|
|||
// GDB: p arg0
|
||||
// CHECK: $4 = 1
|
||||
// GDB: p arg1
|
||||
// no-CHECK: $5 = 2 (<optimized out>)
|
||||
// CHECK: $5 = (int &) @{{0x[0-9a-f]*}}: 2
|
||||
// GDB: p enc_n
|
||||
// CHECK: $6 = 125
|
||||
arg0 = arg1 = enc_n = nes_i;
|
||||
|
@ -34,7 +34,7 @@ void encloser(int arg0, ref int arg1)
|
|||
// GDB: p arg0
|
||||
// CHECK: $7 = 456
|
||||
// GDB: p arg1
|
||||
// no-CHECK: $8 = 456 (<optimized out>)
|
||||
// CHECK: $8 = (int &) @{{0x[0-9a-f]*}}: 456
|
||||
// GDB: p enc_n
|
||||
// CHECK: $9 = 456
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ void encloser(int arg0, ref int arg1)
|
|||
// GDB: p arg0
|
||||
// CHECK: $10 = 456
|
||||
// GDB: p arg1
|
||||
// no-CHECK: $11 = 456 (<optimized out>)
|
||||
// CHECK: $11 = (int &) @{{0x[0-9a-f]*}}: 456
|
||||
// GDB: p enc_n
|
||||
// CHECK: $12 = 456
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue