Skip to content

Commit 986e88d

Browse files
authored
Merge pull request #2022 from vedantk/eng/PR-66592859
[InstCombine] Remove dbg.values describing contents of dead allocas
2 parents 3635cb0 + 6e091c1 commit 986e88d

File tree

2 files changed

+106
-6
lines changed

2 files changed

+106
-6
lines changed

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2526,10 +2526,10 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
25262526

25272527
// If we are removing an alloca with a dbg.declare, insert dbg.value calls
25282528
// before each store.
2529-
TinyPtrVector<DbgVariableIntrinsic *> DIIs;
2529+
SmallVector<DbgVariableIntrinsic *, 8> DVIs;
25302530
std::unique_ptr<DIBuilder> DIB;
25312531
if (isa<AllocaInst>(MI)) {
2532-
DIIs = FindDbgAddrUses(&MI);
2532+
findDbgUsers(DVIs, &MI);
25332533
DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false));
25342534
}
25352535

@@ -2563,8 +2563,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
25632563
ConstantInt::get(Type::getInt1Ty(C->getContext()),
25642564
C->isFalseWhenEqual()));
25652565
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
2566-
for (auto *DII : DIIs)
2567-
ConvertDebugDeclareToDebugValue(DII, SI, *DIB);
2566+
for (auto *DVI : DVIs)
2567+
if (DVI->isAddressOfVariable())
2568+
ConvertDebugDeclareToDebugValue(DVI, SI, *DIB);
25682569
} else {
25692570
// Casts, GEP, or anything else: we're about to delete this instruction,
25702571
// so it can not have any valid uses.
@@ -2581,8 +2582,31 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) {
25812582
None, "", II->getParent());
25822583
}
25832584

2584-
for (auto *DII : DIIs)
2585-
eraseInstFromFunction(*DII);
2585+
// Remove debug intrinsics which describe the value contained within the
2586+
// alloca. In addition to removing dbg.{declare,addr} which simply point to
2587+
// the alloca, remove dbg.value(<alloca>, ..., DW_OP_deref)'s as well, e.g.:
2588+
//
2589+
// ```
2590+
// define void @foo(i32 %0) {
2591+
// %a = alloca i32 ; Deleted.
2592+
// store i32 %0, i32* %a
2593+
// dbg.value(i32 %0, "arg0") ; Not deleted.
2594+
// dbg.value(i32* %a, "arg0", DW_OP_deref) ; Deleted.
2595+
// call void @trivially_inlinable_no_op(i32* %a)
2596+
// ret void
2597+
// }
2598+
// ```
2599+
//
2600+
// This may not be required if we stop describing the contents of allocas
2601+
// using dbg.value(<alloca>, ..., DW_OP_deref), but we currently do this in
2602+
// the LowerDbgDeclare utility.
2603+
//
2604+
// If there is a dead store to `%a` in @trivially_inlinable_no_op, the
2605+
// "arg0" dbg.value may be stale after the call. However, failing to remove
2606+
// the DW_OP_deref dbg.value causes large gaps in location coverage.
2607+
for (auto *DVI : DVIs)
2608+
if (DVI->isAddressOfVariable() || DVI->getExpression()->startsWithDeref())
2609+
DVI->eraseFromParent();
25862610

25872611
return eraseInstFromFunction(MI);
25882612
}
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
; RUN: opt -S -instcombine %s | FileCheck %s -check-prefix=RUN-ONCE
2+
3+
; This example was reduced from a test case in which InstCombine ran at least
4+
; twice:
5+
; - The first InstCombine run converted dbg.declares to dbg.values using the
6+
; LowerDbgDeclare utility. This produced a dbg.value(i32* %2, DW_OP_deref)
7+
; (this happens when the contents of an alloca are passed by-value), and a
8+
; dbg.value(i32 %0) (due to the store of %0 into the alloca).
9+
; - The second InstCombine run deleted the alloca (%2).
10+
; Check that the DW_OP_deref dbg.value is deleted, just like a dbg.declare would
11+
; be.
12+
;
13+
; RUN-ONCE-LABEL: @t1(
14+
; RUN-ONCE-NEXT: llvm.dbg.value(metadata i32 %0, metadata [[t1_arg0:![0-9]+]], metadata !DIExpression())
15+
; RUN-ONCE-NEXT: llvm.dbg.value(metadata i32* undef, metadata [[t1_fake_ptr:![0-9]+]], metadata !DIExpression())
16+
; RUN-ONCE-NEXT: ret void
17+
define void @t1(i32) !dbg !9 {
18+
%2 = alloca i32, align 4
19+
store i32 %0, i32* %2, align 4
20+
call void @llvm.dbg.value(metadata i32 %0, metadata !14, metadata !DIExpression()), !dbg !15
21+
call void @llvm.dbg.value(metadata i32* %2, metadata !14, metadata !DIExpression(DW_OP_deref)), !dbg !15
22+
call void @llvm.dbg.value(metadata i32* %2, metadata !20, metadata !DIExpression()), !dbg !15
23+
ret void
24+
}
25+
26+
; This example is closer to an end-to-end test: the IR looks like it could have
27+
; been produced by a frontend compiling at -O0.
28+
;
29+
; Here's what happens:
30+
; 1) We run InstCombine. This puts a dbg.value(i32* %x.addr, DW_OP_deref)
31+
; before the call to @use, and a dbg.value(i32 %x) after the store.
32+
; 2) We inline @use.
33+
; 3) We run InstCombine again. The alloca %x.addr is erased. We should just get
34+
; dbg.value(i32 %x). There should be no leftover dbg.value(metadata i32*
35+
; undef).
36+
;
37+
;;; define void @use(i32* %addr) alwaysinline { ret void }
38+
;;; define void @t2(i32 %x) !dbg !17 {
39+
;;; %x.addr = alloca i32, align 4
40+
;;; store i32 %x, i32* %x.addr, align 4
41+
;;; call void @llvm.dbg.declare(metadata i32* %x.addr, metadata !18, metadata !DIExpression()), !dbg !19
42+
;;; call void @use(i32* %x.addr)
43+
;;; ret void
44+
;;; }
45+
46+
declare void @llvm.dbg.value(metadata, metadata, metadata)
47+
declare void @llvm.dbg.declare(metadata, metadata, metadata)
48+
49+
!llvm.module.flags = !{!0, !1, !2, !3, !4}
50+
!llvm.dbg.cu = !{!5}
51+
!llvm.ident = !{!8}
52+
53+
; RUN-ONCE: [[t1_arg0]] = !DILocalVariable(name: "a"
54+
; RUN-ONCE: [[t1_fake_ptr]] = !DILocalVariable(name: "fake_ptr"
55+
56+
!0 = !{i32 2, !"SDK Version", [2 x i32] [i32 10, i32 14]}
57+
!1 = !{i32 2, !"Dwarf Version", i32 4}
58+
!2 = !{i32 2, !"Debug Info Version", i32 3}
59+
!3 = !{i32 1, !"wchar_size", i32 4}
60+
!4 = !{i32 7, !"PIC Level", i32 2}
61+
!5 = distinct !DICompileUnit(language: DW_LANG_C99, file: !6, producer: "", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !7, nameTableKind: GNU)
62+
!6 = !DIFile(filename: "-", directory: "/")
63+
!7 = !{}
64+
!8 = !{!""}
65+
!9 = distinct !DISubprogram(name: "t1", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !7)
66+
!10 = !DIFile(filename: "<stdin>", directory: "/")
67+
!11 = !DISubroutineType(types: !12)
68+
!12 = !{null, !13}
69+
!13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
70+
!14 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 1, type: !13)
71+
!15 = !DILocation(line: 1, column: 13, scope: !9)
72+
!16 = !DILocation(line: 1, column: 17, scope: !9)
73+
!17 = distinct !DISubprogram(name: "t2", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !5, retainedNodes: !7)
74+
!18 = !DILocalVariable(name: "x", arg: 1, scope: !17, file: !10, line: 1, type: !13)
75+
!19 = !DILocation(line: 1, column: 1, scope: !17)
76+
!20 = !DILocalVariable(name: "fake_ptr", scope: !9, file: !10, line: 1, type: !13)

0 commit comments

Comments
 (0)