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:
Martin Kinkelin 2018-11-20 20:44:47 +01:00 committed by GitHub
parent 78d6fb3bb8
commit 32b6e49a65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 34 additions and 54 deletions

View file

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

View file

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

View file

@ -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: ){{$}}

View file

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