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:
Martin 2017-09-07 23:12:07 +02:00
parent 93decabe6c
commit 8cc5ff6e79
6 changed files with 55 additions and 35 deletions

View file

@ -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.

View file

@ -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

View file

@ -770,8 +770,12 @@ void defineParameters(IrFuncTy &irFty, VarDeclarations &parameters) {
// 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);
}
} }
} }

View file

@ -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);
} }
} }

View file

@ -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()

View file

@ -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
} }