Skip to content
This repository was archived by the owner on Apr 23, 2020. It is now read-only.

Commit b835e6e

Browse files
committed
Teach LiveDebugValues about lexical scopes.
This addresses PR26055 LiveDebugValues is very slow. Contrary to the old LiveDebugVariables pass LiveDebugValues currently doesn't look at the lexical scopes before inserting a DBG_VALUE intrinsic. This means that we often propagate DBG_VALUEs much further down than necessary. This is especially noticeable in large C++ functions with many inlined method calls that all use the same "this"-pointer. For example, in the following code it makes no sense to propagate the inlined variable a from the first inlined call to f() into any of the subsequent basic blocks, because the variable will always be out of scope: void sink(int a); void __attribute((always_inline)) f(int a) { sink(a); } void foo(int i) { f(i); if (i) f(i); f(i); } This patch reuses the LexicalScopes infrastructure we have for LiveDebugVariables to take this into account. The effect on compile time and memory consumption is quite noticeable: I tested a benchmark that is a large C++ source with an enormous amount of inlined "this"-pointers that would previously eat >24GiB (most of them for DBG_VALUE intrinsics) and whose compile time was dominated by LiveDebugValues. With this patch applied the memory consumption is 1GiB and 1.7% of the time is spent in LiveDebugValues. https://reviews.llvm.org/D24994 Thanks to Daniel Berlin and Keith Walker for reviewing! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@282611 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 89584ae commit b835e6e

File tree

5 files changed

+278
-16
lines changed

5 files changed

+278
-16
lines changed

lib/CodeGen/LiveDebugValues.cpp

+43-8
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/ADT/SparseBitVector.h"
2424
#include "llvm/ADT/Statistic.h"
2525
#include "llvm/ADT/UniqueVector.h"
26+
#include "llvm/CodeGen/LexicalScopes.h"
2627
#include "llvm/CodeGen/MachineFunction.h"
2728
#include "llvm/CodeGen/MachineFunctionPass.h"
2829
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -60,6 +61,26 @@ class LiveDebugValues : public MachineFunctionPass {
6061
private:
6162
const TargetRegisterInfo *TRI;
6263
const TargetInstrInfo *TII;
64+
LexicalScopes LS;
65+
66+
/// Keeps track of lexical scopes associated with a user value's source
67+
/// location.
68+
class UserValueScopes {
69+
DebugLoc DL;
70+
LexicalScopes &LS;
71+
SmallPtrSet<const MachineBasicBlock *, 4> LBlocks;
72+
73+
public:
74+
UserValueScopes(DebugLoc D, LexicalScopes &L) : DL(std::move(D)), LS(L) {}
75+
76+
/// Return true if current scope dominates at least one machine
77+
/// instruction in a given machine basic block.
78+
bool dominates(MachineBasicBlock *MBB) {
79+
if (LBlocks.empty())
80+
LS.getMachineBasicBlocks(DL, LBlocks);
81+
return LBlocks.count(MBB) != 0 || LS.dominates(DL, MBB);
82+
}
83+
};
6384

6485
/// Based on std::pair so it can be used as an index into a DenseMap.
6586
typedef std::pair<const DILocalVariable *, const DILocation *>
@@ -83,7 +104,7 @@ class LiveDebugValues : public MachineFunctionPass {
83104
struct VarLoc {
84105
const DebugVariable Var;
85106
const MachineInstr &MI; ///< Only used for cloning a new DBG_VALUE.
86-
107+
mutable UserValueScopes UVS;
87108
enum { InvalidKind = 0, RegisterKind } Kind;
88109

89110
/// The value location. Stored separately to avoid repeatedly
@@ -96,9 +117,9 @@ class LiveDebugValues : public MachineFunctionPass {
96117
uint64_t Hash;
97118
} Loc;
98119

99-
VarLoc(const MachineInstr &MI)
120+
VarLoc(const MachineInstr &MI, LexicalScopes &LS)
100121
: Var(MI.getDebugVariable(), MI.getDebugLoc()->getInlinedAt()), MI(MI),
101-
Kind(InvalidKind) {
122+
UVS(MI.getDebugLoc(), LS), Kind(InvalidKind) {
102123
static_assert((sizeof(Loc) == sizeof(uint64_t)),
103124
"hash does not cover all members of Loc");
104125
assert(MI.isDebugValue() && "not a DBG_VALUE");
@@ -125,6 +146,10 @@ class LiveDebugValues : public MachineFunctionPass {
125146
return 0;
126147
}
127148

149+
/// Determine whether the lexical scope of this value's debug location
150+
/// dominates MBB.
151+
bool dominates(MachineBasicBlock &MBB) const { return UVS.dominates(&MBB); }
152+
128153
void dump() const { MI.dump(); }
129154

130155
bool operator==(const VarLoc &Other) const {
@@ -229,6 +254,7 @@ class LiveDebugValues : public MachineFunctionPass {
229254
/// Calculate the liveness information for the given machine function.
230255
bool runOnMachineFunction(MachineFunction &MF) override;
231256
};
257+
232258
} // namespace
233259

234260
//===----------------------------------------------------------------------===//
@@ -295,7 +321,7 @@ void LiveDebugValues::transferDebugValue(const MachineInstr &MI,
295321
// Add the VarLoc to OpenRanges from this DBG_VALUE.
296322
// TODO: Currently handles DBG_VALUE which has only reg as location.
297323
if (isDbgValueDescribedByReg(MI)) {
298-
VarLoc VL(MI);
324+
VarLoc VL(MI, LS);
299325
unsigned ID = VarLocIDs.insert(VL);
300326
OpenRanges.insert(ID, VL.Var);
301327
}
@@ -399,6 +425,13 @@ bool LiveDebugValues::join(MachineBasicBlock &MBB, VarLocInMBB &OutLocs,
399425
NumVisited++;
400426
}
401427

428+
// Filter out DBG_VALUES that are out of scope.
429+
VarLocSet KillSet;
430+
for (auto ID : InLocsT)
431+
if (!VarLocIDs[ID].dominates(MBB))
432+
KillSet.set(ID);
433+
InLocsT.intersectWithComplement(KillSet);
434+
402435
// As we are processing blocks in reverse post-order we
403436
// should have processed at least one predecessor, unless it
404437
// is the entry block which has no predecessor.
@@ -520,12 +553,14 @@ bool LiveDebugValues::ExtendRanges(MachineFunction &MF) {
520553
}
521554

522555
bool LiveDebugValues::runOnMachineFunction(MachineFunction &MF) {
556+
if (!MF.getFunction()->getSubprogram())
557+
// LiveDebugValues will already have removed all DBG_VALUEs.
558+
return false;
559+
523560
TRI = MF.getSubtarget().getRegisterInfo();
524561
TII = MF.getSubtarget().getInstrInfo();
562+
LS.initialize(MF);
525563

526-
bool Changed = false;
527-
528-
Changed |= ExtendRanges(MF);
529-
564+
bool Changed = ExtendRanges(MF);
530565
return Changed;
531566
}

test/CodeGen/ARM/dbg-range-extension.mir

-1
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
# CHECK: DBG_VALUE debug-use [[REG_I]], debug-use _, [[VAR_I]]
4848

4949
# CHECK: bb.4.for.cond.cleanup
50-
# CHECK: DBG_VALUE debug-use [[REG_I]], debug-use _, [[VAR_I]]
5150
# CHECK: DBG_VALUE debug-use [[REG_C]], debug-use _, [[VAR_C]]
5251
# CHECK: DBG_VALUE debug-use [[REG_B]], debug-use _, [[VAR_B]]
5352
# CHECK: DBG_VALUE debug-use [[REG_A]], debug-use _, [[VAR_A]]

test/DebugInfo/COFF/register-variables.ll

+4-4
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
; ASM: #DEBUG_VALUE: c <- %EAX
3838
; ASM: testl %esi, %esi
3939
; ASM: je .LBB0_2
40+
; ASM: [[after_je:\.Ltmp.*]]:
4041
; ASM: # BB#1: # %if.then
41-
; ASM-DAG: #DEBUG_VALUE: c <- %EAX
4242
; ASM-DAG: #DEBUG_VALUE: inlineinc:a <- %EAX
4343
; ASM-DAG: #DEBUG_VALUE: a <- %EAX
4444
; ASM-DAG: #DEBUG_VALUE: f:p <- %ESI
@@ -65,7 +65,7 @@
6565
; ASM: .cv_def_range [[after_getint]] [[after_inc_eax]], "A\021\021\000\000\000"
6666
; ASM: .short 4414 # Record kind: S_LOCAL
6767
; ASM: .asciz "c"
68-
; ASM: .cv_def_range [[after_getint]] [[after_inc_eax]], "A\021\021\000\000\000"
68+
; ASM: .cv_def_range [[after_getint]] [[after_je]], "A\021\021\000\000\000"
6969
; ASM: .short 4414 # Record kind: S_LOCAL
7070
; ASM: .asciz "b"
7171
; ASM: .cv_def_range [[after_inc_eax]] [[after_if]], "A\021\021\000\000\000"
@@ -132,7 +132,7 @@
132132
; OBJ: LocalVariableAddrRange {
133133
; OBJ: OffsetStart: .text+0xC
134134
; OBJ: ISectStart: 0x0
135-
; OBJ: Range: 0x6
135+
; OBJ: Range: 0x4
136136
; OBJ: }
137137
; OBJ: }
138138
; OBJ: Local {
@@ -143,7 +143,7 @@
143143
; OBJ: }
144144
; OBJ: DefRangeRegister {
145145
; OBJ: Register: 17
146-
; OBJ: LocalVariableAddrRange {
146+
; OBJ: MayHaveNoName: 0
147147
; OBJ: OffsetStart: .text+0x12
148148
; OBJ: ISectStart: 0x0
149149
; OBJ: Range: 0x6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
--- |
2+
; RUN: llc -run-pass=livedebugvalues -march=x86-64 -o - %s | FileCheck %s
3+
; Created from:
4+
; void sink(int a);
5+
; void __attribute((always_inline)) f(int a) { sink(a); }
6+
; void foo(int i) {
7+
; f(i);
8+
; if (i)
9+
; f(i);
10+
; f(i);
11+
; }
12+
;
13+
; This test verifies that LiveDebugValues doesn't propagate DBG_VALUEs into
14+
; basic blocks that are beyond the scope of the source variable.
15+
;
16+
; CHECK: bb.1.if.then:
17+
; CHECK: DBG_VALUE debug-use %ebx, debug-use _, !19, !13, debug-location !20
18+
; CHECK-NOT: DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !21
19+
; CHECK: DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !27
20+
; CHECK: bb.2.if.end:
21+
; CHECK: DBG_VALUE debug-use %ebx, debug-use _, !19, !13, debug-location !20
22+
; CHECK-NOT: DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !21
23+
; CHECK: DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !31
24+
;
25+
; ModuleID = 'livedebugvalues-limit.ll'
26+
source_filename = "livedebugvalues-limit.c"
27+
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
28+
target triple = "x86_64-apple-macosx"
29+
30+
; Function Attrs: alwaysinline nounwind ssp uwtable
31+
define void @f(i32 %a) local_unnamed_addr #0 !dbg !7 {
32+
entry:
33+
tail call void @llvm.dbg.value(metadata i32 %a, i64 0, metadata !12, metadata !13), !dbg !14
34+
tail call void @sink(i32 %a) #4, !dbg !15
35+
ret void, !dbg !16
36+
}
37+
38+
declare void @sink(i32) local_unnamed_addr
39+
40+
; Function Attrs: nounwind ssp uwtable
41+
define void @foo(i32 %i) local_unnamed_addr #2 !dbg !17 {
42+
entry:
43+
tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !19, metadata !13), !dbg !20
44+
tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !12, metadata !13) #4, !dbg !21
45+
tail call void @sink(i32 %i) #4, !dbg !23
46+
%tobool = icmp eq i32 %i, 0, !dbg !24
47+
br i1 %tobool, label %if.end, label %if.then, !dbg !26
48+
49+
if.then: ; preds = %entry
50+
tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !12, metadata !13) #4, !dbg !27
51+
tail call void @sink(i32 %i) #4, !dbg !29
52+
br label %if.end, !dbg !30
53+
54+
if.end: ; preds = %if.then, %entry
55+
tail call void @llvm.dbg.value(metadata i32 %i, i64 0, metadata !12, metadata !13) #4, !dbg !31
56+
tail call void @sink(i32 %i) #4, !dbg !33
57+
ret void, !dbg !34
58+
}
59+
60+
; Function Attrs: nounwind readnone
61+
declare void @llvm.dbg.value(metadata, i64, metadata, metadata) #3
62+
63+
; Function Attrs: nounwind
64+
declare void @llvm.stackprotector(i8*, i8**) #4
65+
66+
attributes #0 = { alwaysinline nounwind ssp uwtable }
67+
attributes #2 = { nounwind ssp uwtable }
68+
attributes #3 = { nounwind readnone }
69+
attributes #4 = { nounwind }
70+
71+
!llvm.dbg.cu = !{!0}
72+
!llvm.module.flags = !{!3, !4, !5}
73+
!llvm.ident = !{!6}
74+
75+
!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 4.0.0 (trunk 281923) (llvm/trunk 281916)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
76+
!1 = !DIFile(filename: "livedebugvalues-limit.c", directory: "/Volumes/Fusion/Data/llvm")
77+
!2 = !{}
78+
!3 = !{i32 2, !"Dwarf Version", i32 4}
79+
!4 = !{i32 2, !"Debug Info Version", i32 3}
80+
!5 = !{i32 1, !"PIC Level", i32 2}
81+
!6 = !{!"clang version 4.0.0 (trunk 281923) (llvm/trunk 281916)"}
82+
!7 = distinct !DISubprogram(name: "f", scope: !1, file: !1, line: 3, type: !8, isLocal: false, isDefinition: true, scopeLine: 3, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !11)
83+
!8 = !DISubroutineType(types: !9)
84+
!9 = !{null, !10}
85+
!10 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed)
86+
!11 = !{!12}
87+
!12 = !DILocalVariable(name: "a", arg: 1, scope: !7, file: !1, line: 3, type: !10)
88+
!13 = !DIExpression()
89+
!14 = !DILocation(line: 3, column: 41, scope: !7)
90+
!15 = !DILocation(line: 3, column: 46, scope: !7)
91+
!16 = !DILocation(line: 3, column: 55, scope: !7)
92+
!17 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !8, isLocal: false, isDefinition: true, scopeLine: 4, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !18)
93+
!18 = !{!19}
94+
!19 = !DILocalVariable(name: "i", arg: 1, scope: !17, file: !1, line: 4, type: !10)
95+
!20 = !DILocation(line: 4, column: 14, scope: !17)
96+
!21 = !DILocation(line: 3, column: 41, scope: !7, inlinedAt: !22)
97+
!22 = distinct !DILocation(line: 5, column: 3, scope: !17)
98+
!23 = !DILocation(line: 3, column: 46, scope: !7, inlinedAt: !22)
99+
!24 = !DILocation(line: 6, column: 7, scope: !25)
100+
!25 = distinct !DILexicalBlock(scope: !17, file: !1, line: 6, column: 7)
101+
!26 = !DILocation(line: 6, column: 7, scope: !17)
102+
!27 = !DILocation(line: 3, column: 41, scope: !7, inlinedAt: !28)
103+
!28 = distinct !DILocation(line: 7, column: 5, scope: !25)
104+
!29 = !DILocation(line: 3, column: 46, scope: !7, inlinedAt: !28)
105+
!30 = !DILocation(line: 7, column: 5, scope: !25)
106+
!31 = !DILocation(line: 3, column: 41, scope: !7, inlinedAt: !32)
107+
!32 = distinct !DILocation(line: 8, column: 3, scope: !17)
108+
!33 = !DILocation(line: 3, column: 46, scope: !7, inlinedAt: !32)
109+
!34 = !DILocation(line: 9, column: 1, scope: !17)
110+
111+
...
112+
---
113+
name: f
114+
alignment: 4
115+
exposesReturnsTwice: false
116+
legalized: false
117+
regBankSelected: false
118+
selected: false
119+
tracksRegLiveness: true
120+
liveins:
121+
- { reg: '%edi' }
122+
calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
123+
'%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
124+
'%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
125+
'%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
126+
frameInfo:
127+
isFrameAddressTaken: false
128+
isReturnAddressTaken: false
129+
hasStackMap: false
130+
hasPatchPoint: false
131+
stackSize: 8
132+
offsetAdjustment: 0
133+
maxAlignment: 0
134+
adjustsStack: false
135+
hasCalls: false
136+
maxCallFrameSize: 0
137+
hasOpaqueSPAdjustment: false
138+
hasVAStart: false
139+
hasMustTailInVarArgFunc: false
140+
fixedStack:
141+
- { id: 0, type: spill-slot, offset: -16, size: 8, alignment: 16 }
142+
body: |
143+
bb.0.entry:
144+
liveins: %edi, %rbp
145+
146+
frame-setup PUSH64r killed %rbp, implicit-def %rsp, implicit %rsp
147+
CFI_INSTRUCTION def_cfa_offset 16
148+
CFI_INSTRUCTION offset %rbp, -16
149+
%rbp = frame-setup MOV64rr %rsp
150+
CFI_INSTRUCTION def_cfa_register %rbp
151+
DBG_VALUE debug-use %edi, debug-use _, !12, !13, debug-location !14
152+
%rbp = POP64r implicit-def %rsp, implicit %rsp, debug-location !15
153+
TAILJMPd64 @sink, csr_64, implicit %rsp, implicit %rsp, implicit %edi, debug-location !15
154+
155+
...
156+
---
157+
name: foo
158+
alignment: 4
159+
exposesReturnsTwice: false
160+
legalized: false
161+
regBankSelected: false
162+
selected: false
163+
tracksRegLiveness: true
164+
liveins:
165+
- { reg: '%edi' }
166+
calleeSavedRegisters: [ '%bh', '%bl', '%bp', '%bpl', '%bx', '%ebp', '%ebx',
167+
'%rbp', '%rbx', '%r12', '%r13', '%r14', '%r15',
168+
'%r12b', '%r13b', '%r14b', '%r15b', '%r12d', '%r13d',
169+
'%r14d', '%r15d', '%r12w', '%r13w', '%r14w', '%r15w' ]
170+
frameInfo:
171+
isFrameAddressTaken: false
172+
isReturnAddressTaken: false
173+
hasStackMap: false
174+
hasPatchPoint: false
175+
stackSize: 24
176+
offsetAdjustment: -8
177+
maxAlignment: 0
178+
adjustsStack: true
179+
hasCalls: true
180+
maxCallFrameSize: 0
181+
hasOpaqueSPAdjustment: false
182+
hasVAStart: false
183+
hasMustTailInVarArgFunc: false
184+
fixedStack:
185+
- { id: 0, type: spill-slot, offset: -24, size: 8, alignment: 8, callee-saved-register: '%rbx' }
186+
- { id: 1, type: spill-slot, offset: -16, size: 8, alignment: 16 }
187+
body: |
188+
bb.0.entry:
189+
successors: %bb.2.if.end, %bb.1.if.then
190+
liveins: %edi, %rbx, %rbp
191+
192+
frame-setup PUSH64r killed %rbp, implicit-def %rsp, implicit %rsp
193+
CFI_INSTRUCTION def_cfa_offset 16
194+
CFI_INSTRUCTION offset %rbp, -16
195+
%rbp = frame-setup MOV64rr %rsp
196+
CFI_INSTRUCTION def_cfa_register %rbp
197+
frame-setup PUSH64r killed %rbx, implicit-def %rsp, implicit %rsp
198+
frame-setup PUSH64r undef %rax, implicit-def %rsp, implicit %rsp
199+
CFI_INSTRUCTION offset %rbx, -24
200+
DBG_VALUE debug-use %edi, debug-use _, !19, !13, debug-location !20
201+
%ebx = MOV32rr %edi
202+
DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !21
203+
DBG_VALUE debug-use %ebx, debug-use _, !19, !13, debug-location !20
204+
CALL64pcrel32 @sink, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, debug-location !23
205+
TEST32rr %ebx, %ebx, implicit-def %eflags, debug-location !24
206+
JE_1 %bb.2.if.end, implicit %eflags
207+
208+
bb.1.if.then:
209+
successors: %bb.2.if.end
210+
liveins: %ebx, %rbp
211+
212+
DBG_VALUE debug-use %ebx, debug-use _, !19, !13, debug-location !20
213+
DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !27
214+
%edi = MOV32rr %ebx, debug-location !29
215+
CALL64pcrel32 @sink, csr_64, implicit %rsp, implicit %edi, implicit-def %rsp, debug-location !29
216+
217+
bb.2.if.end:
218+
liveins: %ebx, %rbp
219+
220+
DBG_VALUE debug-use %ebx, debug-use _, !19, !13, debug-location !20
221+
%edi = MOV32rr killed %ebx, debug-location !33
222+
%rsp = ADD64ri8 %rsp, 8, implicit-def dead %eflags, debug-location !33
223+
DBG_VALUE debug-use %ebx, debug-use _, !12, !13, debug-location !31
224+
%rbx = POP64r implicit-def %rsp, implicit %rsp, debug-location !33
225+
%rbp = POP64r implicit-def %rsp, implicit %rsp, debug-location !33
226+
TAILJMPd64 @sink, csr_64, implicit %rsp, implicit %rsp, implicit %edi, debug-location !33
227+
228+
...

0 commit comments

Comments
 (0)