Recently there has been renewed interest in improving debug-info for variables that (partially or otherwise) live on the stack in optimised code. At the moment instcombine speculates that stack slots are probably going to be promoted to registers, and prepares the debug-info accordingly. It runs a function called LowerDbgDeclare which converts dbg.declares to a set of dbg.values after loads, and before stores and calls. Sometimes the stack location remains (e.g. for escaped locals). If any dbg.values become undef where the stack location is still valid we end up unnecessarily reducing variable location coverage due to our inability to track multiple locations simultaneously. There is a flag to disable this feature (-instcombine-lower-dbg-declare=0), which prevents this conversion at the cost of sometimes providing incorrect location info in the face of DSE, DCE, GVN, CSE etc. This has been discussed fairly extensively on PR34136. The idea of these tests is to provide examples of situations that we should consider when designing a new system, to aid discussions and eventually help evaluate the implementation. Dexter isn't ideal for observing specific optimisation behaviour. Writing an exaustive test suite would be difficult, and the resultant suite would be fragile. However, I think having some concrete executable examples is useful at least as a reference. Differential Revision: https://reviews.llvm.org/D89543
78 lines
2.7 KiB
C
78 lines
2.7 KiB
C
// XFAIL:*
|
|
//// Suboptimal coverage, see description below.
|
|
|
|
// REQUIRES: lldb
|
|
// UNSUPPORTED: system-windows
|
|
// RUN: %dexter --fail-lt 1.0 -w --debugger lldb \
|
|
// RUN: --builder 'clang-c' --cflags "-O3 -glldb" -- %s
|
|
|
|
//// Adapted from https://bugs.llvm.org/show_bug.cgi?id=34136#c1
|
|
//// LowerDbgDeclare has since been updated to look through bitcasts. We still
|
|
//// get suboptimal coverage at the beginning of 'main' though. For each local,
|
|
//// LowerDbgDeclare inserts a dbg.value and a dbg.value+DW_OP_deref before the
|
|
//// store (after the call to 'getint') and the call to 'alias' respectively.
|
|
//// The first dbg.value describes the result of the 'getint' call, eventually
|
|
//// becoming a register location. The second points back into the stack
|
|
//// home. There is a gap in the coverage between the quickly clobbered register
|
|
//// location and the stack location, even though the stack location is valid
|
|
//// during that gap. For x86 we end up with this code at the start of main:
|
|
//// 00000000004004b0 <main>:
|
|
//// 4004b0: sub rsp,0x18
|
|
//// 4004b4: mov edi,0x5
|
|
//// 4004b9: call 400480 <getint>
|
|
//// 4004be: mov DWORD PTR [rsp+0x14],eax
|
|
//// 4004c2: mov edi,0x5
|
|
//// 4004c7: call 400480 <getint>
|
|
//// 4004cc: mov DWORD PTR [rsp+0x10],eax
|
|
//// 4004d0: mov edi,0x5
|
|
//// 4004d5: call 400480 <getint>
|
|
//// 4004da: mov DWORD PTR [rsp+0xc],eax
|
|
//// ...
|
|
//// With these variable locations:
|
|
//// DW_TAG_variable
|
|
//// DW_AT_location (0x00000000:
|
|
//// [0x00000000004004be, 0x00000000004004cc): DW_OP_reg0 RAX
|
|
//// [0x00000000004004de, 0x0000000000400503): DW_OP_breg7 RSP+20)
|
|
//// DW_AT_name ("x")
|
|
//// ...
|
|
//// DW_TAG_variable
|
|
//// DW_AT_location (0x00000037:
|
|
//// [0x00000000004004cc, 0x00000000004004da): DW_OP_reg0 RAX
|
|
//// [0x00000000004004e8, 0x0000000000400503): DW_OP_breg7 RSP+16)
|
|
//// DW_AT_name ("y")
|
|
//// ...
|
|
//// DW_TAG_variable
|
|
//// DW_AT_location (0x0000006e:
|
|
//// [0x00000000004004da, 0x00000000004004e8): DW_OP_reg0 RAX
|
|
//// [0x00000000004004f2, 0x0000000000400503): DW_OP_breg7 RSP+12)
|
|
//// DW_AT_name ("z")
|
|
//// ...
|
|
|
|
char g = 1;
|
|
int five = 5;
|
|
__attribute__((__noinline__))
|
|
int getint(int x) {
|
|
g = x - 4;
|
|
return x * g;
|
|
}
|
|
|
|
__attribute__((__noinline__))
|
|
void alias(char* c) {
|
|
g = *c;
|
|
*c = (char)five;
|
|
}
|
|
|
|
int main() {
|
|
int x = getint(5);
|
|
int y = getint(5); // DexLabel('s1')
|
|
int z = getint(5); // DexLabel('s2')
|
|
alias((char*)&x); // DexLabel('s3')
|
|
alias((char*)&y);
|
|
alias((char*)&z);
|
|
return 0; // DexLabel('s4')
|
|
}
|
|
|
|
// DexExpectWatchValue('x', '5', from_line='s1', to_line='s4')
|
|
// DexExpectWatchValue('y', '5', from_line='s2', to_line='s4')
|
|
// DexExpectWatchValue('z', '5', from_line='s3', to_line='s4')
|