diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index 6df613d22f..e63733a973 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -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 addr) { if (!mustEmitFullDebugInfo()) return; @@ -1054,16 +1054,21 @@ void ldc::DIBuilder::EmitLocalVariable(llvm::Value *ll, VarDeclaration *vd, if (static_cast(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. diff --git a/gen/dibuilder.h b/gen/dibuilder.h index f52536d4b4..31c6482fcf 100644 --- a/gen/dibuilder.h +++ b/gen/dibuilder.h @@ -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 addr = llvm::ArrayRef()); /// \brief Emits all things necessary for making debug info for a global diff --git a/gen/functions.cpp b/gen/functions.cpp index 094f8e567a..1d91333d68 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -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); + } } } diff --git a/gen/nested.cpp b/gen/nested.cpp index 205b7d30b3..e502c00f30 100644 --- a/gen/nested.cpp +++ b/gen/nested.cpp @@ -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); } } diff --git a/tests/debuginfo/nested_cdb.d b/tests/debuginfo/nested_cdb.d index eb66527604..1af5adef5b 100644 --- a/tests/debuginfo/nested_cdb.d +++ b/tests/debuginfo/nested_cdb.d @@ -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() diff --git a/tests/debuginfo/nested_gdb.d b/tests/debuginfo/nested_gdb.d index d63452c7ff..e392bdd69a 100644 --- a/tests/debuginfo/nested_gdb.d +++ b/tests/debuginfo/nested_gdb.d @@ -12,7 +12,7 @@ void encloser(int arg0, ref int arg1) // GDB: p arg0 // CHECK: $1 = 1 // GDB: p arg1 -// no-CHECK: $2 = 2 () +// 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 () +// 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 () +// 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 () +// CHECK: $11 = (int &) @{{0x[0-9a-f]*}}: 456 // GDB: p enc_n // CHECK: $12 = 456 }