mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-01 07:30:43 +03:00
Debuginfo: Fix nested variables (primarily for CodeView) (#2909)
We've been going back and forth between GEPs and complex DWARF expressions based on the context pointer; this goes back to the latter, as that fixes simple nested variables for CodeView with LLVM >= 6. I guess it also helps for debuginfos of nested vars with enabled optimizations.
This commit is contained in:
parent
78d6fb3bb8
commit
32b6e49a65
4 changed files with 34 additions and 54 deletions
|
@ -206,7 +206,11 @@ public:
|
|||
|
||||
uint64_t offset =
|
||||
gDataLayout->getStructLayout(type)->getElementOffset(index);
|
||||
#if LDC_LLVM_VER >= 500
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus_uconst);
|
||||
#else
|
||||
addr.push_back(llvm::dwarf::DW_OP_plus);
|
||||
#endif
|
||||
addr.push_back(offset);
|
||||
}
|
||||
|
||||
|
|
|
@ -93,6 +93,21 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
IF_LOG { Logger::cout() << "casting to: " << *irfunc->frameType << '\n'; }
|
||||
LLValue *val = DtoBitCast(ctx, frameType);
|
||||
|
||||
// Make the DWARF variable address relative to the context pointer (ctx);
|
||||
// register all ops (offsetting, dereferencing) required to get there in the
|
||||
// following list.
|
||||
LLSmallVector<int64_t, 4> dwarfAddrOps;
|
||||
|
||||
const auto offsetToNthField = [&val, &dwarfAddrOps](unsigned fieldIndex,
|
||||
const char *name = "") {
|
||||
gIR->DBuilder.OpOffset(dwarfAddrOps, val, fieldIndex);
|
||||
val = DtoGEPi(val, 0, fieldIndex, name);
|
||||
};
|
||||
const auto dereference = [&val, &dwarfAddrOps](const char *name = "") {
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
val = DtoAlignedLoad(val, name);
|
||||
};
|
||||
|
||||
IrLocal *const irLocal = getIrLocal(vd);
|
||||
const auto vardepth = irLocal->nestedDepth;
|
||||
const auto funcdepth = irfunc->depth;
|
||||
|
@ -111,20 +126,16 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
} else {
|
||||
// Load frame pointer and index that...
|
||||
IF_LOG Logger::println("Lower depth");
|
||||
val = DtoGEPi(val, 0, vardepth);
|
||||
offsetToNthField(vardepth);
|
||||
IF_LOG Logger::cout() << "Frame index: " << *val << '\n';
|
||||
val = DtoAlignedLoad(
|
||||
val, (std::string(".frame.") + vdparent->toChars()).c_str());
|
||||
dereference((std::string(".frame.") + vdparent->toChars()).c_str());
|
||||
IF_LOG Logger::cout() << "Frame: " << *val << '\n';
|
||||
}
|
||||
|
||||
const auto idx = irLocal->nestedIndex;
|
||||
assert(idx != -1 && "Nested context not yet resolved for variable.");
|
||||
|
||||
LLSmallVector<int64_t, 2> dwarfAddrOps;
|
||||
|
||||
LLValue *gep = DtoGEPi(val, 0, idx, vd->toChars());
|
||||
val = gep;
|
||||
offsetToNthField(idx, vd->toChars());
|
||||
IF_LOG {
|
||||
Logger::cout() << "Addr: " << *val << '\n';
|
||||
Logger::cout() << "of type: " << *val->getType() << '\n';
|
||||
|
@ -135,8 +146,8 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
// storage of pointer (reference lvalue).
|
||||
} else if (byref || isRefOrOut) {
|
||||
val = DtoAlignedLoad(val);
|
||||
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable();
|
||||
// pass the GEP as reference lvalue in that case.
|
||||
// ref/out variables get a reference-debuginfo-type in EmitLocalVariable()
|
||||
// => don't dereference, use reference lvalue as address
|
||||
if (!isRefOrOut)
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
IF_LOG {
|
||||
|
@ -147,11 +158,9 @@ DValue *DtoNestedVariable(Loc &loc, Type *astype, VarDeclaration *vd,
|
|||
|
||||
if (!skipDIDeclaration && global.params.symdebug) {
|
||||
#if LDC_LLVM_VER < 500
|
||||
// Because we are passing a GEP instead of an alloca to
|
||||
// llvm.dbg.declare, we have to make the address dereference explicit.
|
||||
gIR->DBuilder.OpDeref(dwarfAddrOps);
|
||||
#endif
|
||||
gIR->DBuilder.EmitLocalVariable(gep, vd, nullptr, false,
|
||||
gIR->DBuilder.EmitLocalVariable(ctx, vd, nullptr, false,
|
||||
/*forceAsLocal=*/true, false, dwarfAddrOps);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
// Tests debug info generation for nested functions
|
||||
// RUN: %ldc -g -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
|
||||
|
||||
// CHECK: define {{.*}} @{{.*}}_D6nested8encloserFiiZv
|
||||
// CHECK-SAME: !dbg
|
||||
void encloser(int arg0, int arg1)
|
||||
{
|
||||
// CHECK: @llvm.dbg.declare{{.*}}%enc_n{{.*}}enc_n
|
||||
int enc_n;
|
||||
|
||||
// CHECK-LABEL: define {{.*}}_D6nested8encloserFiiZQuMFNaNbNiNfiZv
|
||||
void nested(int nes_i)
|
||||
{
|
||||
// CHECK: %arg0 = getelementptr inbounds %nest.encloser
|
||||
// CHECK: @llvm.dbg.declare{{.*}}%arg0
|
||||
// CHECK: %arg1 = getelementptr inbounds %nest.encloser
|
||||
// CHECK: @llvm.dbg.declare{{.*}}%arg1
|
||||
// CHECK: %enc_n = getelementptr inbounds %nest.encloser
|
||||
// CHECK: @llvm.dbg.declare{{.*}}%enc_n
|
||||
arg0 = arg1 = enc_n = nes_i; // accessing arg0, arg1 and enc_n from a nested function turns them into closure variables
|
||||
|
||||
// nes_i and arg1 have the same parameter index in the generated IR, if both get declared as
|
||||
// function parameters this triggers off an assert in LLVM >=3.8 (see Github PR #1598)
|
||||
}
|
||||
}
|
||||
|
||||
// CHECK-LABEL: !DISubprogram(name:{{.*}}nested"
|
||||
// CHECK: !DILocalVariable{{.*}}nes_i
|
||||
// CHECK: !DILocalVariable{{.*}}arg1
|
||||
// CHECK-NOT: arg:
|
||||
// CHECK-SAME: ){{$}}
|
|
@ -1,11 +1,10 @@
|
|||
// REQUIRES: atleast_llvm500
|
||||
// REQUIRES: atmost_llvm501
|
||||
// REQUIRES: Windows
|
||||
// REQUIRES: cdb
|
||||
// RUN: %ldc -g -of=%t.exe %s
|
||||
// RUN: sed -e "/^\\/\\/ CDB:/!d" -e "s,// CDB:,," %s \
|
||||
// RUN: | %cdb -snul -lines -y . %t.exe >%t.out
|
||||
// RUN: FileCheck %s -check-prefix=CHECK -check-prefix=%arch < %t.out
|
||||
// RUN: FileCheck %s < %t.out
|
||||
|
||||
// CDB: ld /f nested_cdb*
|
||||
// enable case sensitive symbol lookup
|
||||
|
@ -14,7 +13,7 @@
|
|||
void encloser(int arg0, ref int arg1)
|
||||
{
|
||||
int enc_n = 123;
|
||||
// CDB: bp `nested_cdb.d:17`
|
||||
// CDB: bp `nested_cdb.d:16`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n1
|
||||
|
@ -28,7 +27,7 @@ void encloser(int arg0, ref int arg1)
|
|||
void nested(int nes_i)
|
||||
{
|
||||
int blub = arg0 + arg1 + enc_n;
|
||||
// CDB: bp `nested_cdb.d:31`
|
||||
// CDB: bp `nested_cdb.d:30`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n1
|
||||
|
@ -37,7 +36,7 @@ void encloser(int arg0, ref int arg1)
|
|||
// CDB: ?? *arg1
|
||||
// CHECK: int 0n2
|
||||
arg0 = arg1 = enc_n = nes_i;
|
||||
// CDB: bp `nested_cdb.d:40`
|
||||
// CDB: bp `nested_cdb.d:39`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// CHECK: int arg0 = 0n456
|
||||
|
@ -48,15 +47,14 @@ void encloser(int arg0, ref int arg1)
|
|||
}
|
||||
|
||||
nested(456);
|
||||
// CDB: bp `nested_cdb.d:51`
|
||||
// CDB: bp `nested_cdb.d:50`
|
||||
// CDB: g
|
||||
// CDB: dv /t
|
||||
// the following values are garbage on Win32...
|
||||
// x64: int arg0 = 0n456
|
||||
// x64-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||
// x64-NEXT: int enc_n = 0n456
|
||||
// CHECK: int arg0 = 0n456
|
||||
// CHECK-NEXT: int * arg1 = {{0x[0-9a-f`]*}}
|
||||
// CHECK-NEXT: int enc_n = 0n456
|
||||
// CDB: ?? *arg1
|
||||
// x64: int 0n456
|
||||
// CHECK: int 0n456
|
||||
}
|
||||
|
||||
void main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue