llvm.org GIT mirror llvm / 2ef1575
[AddDiscriminators] Assign discriminators to MemIntrinsic calls. Before this patch, pass AddDiscriminators always avoided to assign discriminators to intrinsic calls. This was done mainly for two reasons: 1) We wanted to minimize the number of based discriminators used. 2) We wanted to avoid non-deterministic discriminator assignment for different debug levels. Unfortunately, that approach was problematic for MemIntrinsic calls. MemIntrinsic calls can be split by SROA into loads and stores, and each new load/store instruction would obtain the debug location from the original intrinsic call. If we don't assign a discriminator to MemIntrinsic calls, then we cannot correctly set the discriminator for the newly created loads and stores. This may have a negative impact on the basic block weight computation performed by the SampleLoader. This patch fixes the issue by letting MemIntrinsic calls have a discriminator. Differential Revision: https://reviews.llvm.org/D31900 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@299972 91177308-0d34-0410-b5e6-96231b3b80d8 Andrea Di Biagio 2 years ago
2 changed file(s) with 119 addition(s) and 1 deletion(s). Raw diff Collapse all Expand all
101101 return new AddDiscriminatorsLegacyPass();
102102 }
103103
104 static bool shouldHaveDiscriminator(const Instruction *I) {
105 return !isa(I) || isa(I);
106 }
107
104108 /// \brief Assign DWARF discriminators.
105109 ///
106110 /// To assign discriminators, we examine the boundaries of every
175179 // discriminator for this instruction.
176180 for (BasicBlock &B : F) {
177181 for (auto &I : B.getInstList()) {
178 if (isa(&I))
182 // Not all intrinsic calls should have a discriminator.
183 // We want to avoid a non-deterministic assignment of discriminators at
184 // different debug levels. We still allow discriminators on memory
185 // intrinsic calls because those can be early expanded by SROA into
186 // pairs of loads and stores, and the expanded load/store instructions
187 // should have a valid discriminator.
188 if (!shouldHaveDiscriminator(&I))
179189 continue;
180190 const DILocation *DIL = I.getDebugLoc();
181191 if (!DIL)
206216 LocationSet CallLocations;
207217 for (auto &I : B.getInstList()) {
208218 CallInst *Current = dyn_cast(&I);
219 // We bypass intrinsic calls for the following two reasons:
220 // 1) We want to avoid a non-deterministic assigment of
221 // discriminators.
222 // 2) We want to minimize the number of base discriminators used.
209223 if (!Current || isa(&I))
210224 continue;
211225
0 ; RUN: opt < %s -add-discriminators -sroa -S | FileCheck %s
1
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3
4 ; Test case obtained from the following C code:
5
6 ; struct A {
7 ; int field1;
8 ; short field2;
9 ; };
10 ;
11 ; struct B {
12 ; struct A field1;
13 ; int field2;
14 ; };
15 ;
16 ;
17 ; extern struct B g_b;
18 ; extern int bar(struct B b, int c);
19 ;
20 ; int foo(int cond) {
21 ; int result = cond ? bar(g_b, 33) : 42;
22 ; return result;
23 ; }
24
25 ; In this test, global variable g_b is passed by copy to function bar. That
26 ; copy is located on the stack (see alloca %g_b.coerce), and it is initialized
27 ; by a memcpy call.
28 ;
29 ; SROA would split alloca %g_b.coerce into two (smaller disjoint) slices:
30 ; slice [0,8) and slice [8, 12). Users of the original alloca are rewritten
31 ; as users of the new alloca slices.
32 ; In particular, the memcpy is rewritten by SROA as two load/store pairs.
33 ;
34 ; Later on, mem2reg successfully promotes the new alloca slices to registers,
35 ; and loads %3 and %5 are made redundant by the loads obtained from the memcpy
36 ; intrinsic expansion.
37 ;
38 ; If pass AddDiscriminators doesn't assign a discriminator to the intrinsic
39 ; memcpy call, then the loads obtained from the memcpy expansion would not have
40 ; a correct discriminator.
41 ;
42 ; This test checks that the two new loads inserted by SROA in %cond.true
43 ; correctly reference a debug location with a non-zero discriminator. This test
44 ; also checks that the same discriminator is used by all instructions from
45 ; basic block %cond.true.
46
47 %struct.B = type { %struct.A, i32 }
48 %struct.A = type { i32, i16 }
49
50 @g_b = external global %struct.B, align 4
51
52 define i32 @foo(i32 %cond) #0 !dbg !5 {
53 entry:
54 %g_b.coerce = alloca { i64, i32 }, align 4
55 %tobool = icmp ne i32 %cond, 0, !dbg !7
56 br i1 %tobool, label %cond.true, label %cond.end, !dbg !7
57
58 cond.true:
59 ; CHECK-LABEL: cond.true:
60 ; CHECK: load i64, {{.*}}, !dbg ![[LOC:[0-9]+]]
61 ; CHECK-NEXT: load i32, {{.*}}, !dbg ![[LOC]]
62 ; CHECK-NEXT: %call = call i32 @bar({{.*}}), !dbg ![[LOC]]
63 ; CHECK-NEXT: br label %cond.end, !dbg ![[BR_LOC:[0-9]+]]
64
65 ; CHECK-DAG: ![[LOC]] = !DILocation(line: 16, column: 23, scope: ![[SCOPE:[0-9]+]])
66 ; CHECK-DAG: ![[SCOPE]] = !DILexicalBlockFile({{.*}}, discriminator: 2)
67 ; CHECK-DAG: ![[BR_LOC]] = !DILocation(line: 16, column: 16, scope: ![[SCOPE]])
68
69 %0 = bitcast { i64, i32 }* %g_b.coerce to i8*, !dbg !8
70 %1 = bitcast %struct.B* @g_b to i8*, !dbg !8
71 call void @llvm.memcpy.p0i8.p0i8.i64(i8* %0, i8* %1, i64 12, i32 4, i1 false), !dbg !8
72 %2 = getelementptr inbounds { i64, i32 }, { i64, i32 }* %g_b.coerce, i32 0, i32 0, !dbg !8
73 %3 = load i64, i64* %2, align 4, !dbg !8
74 %4 = getelementptr inbounds { i64, i32 }, { i64, i32 }* %g_b.coerce, i32 0, i32 1, !dbg !8
75 %5 = load i32, i32* %4, align 4, !dbg !8
76 %call = call i32 @bar(i64 %3, i32 %5, i32 33), !dbg !8
77 br label %cond.end, !dbg !7
78
79 cond.end: ; preds = %entry, %cond.true
80 %cond1 = phi i32 [ %call, %cond.true ], [ 42, %entry ], !dbg !7
81 ret i32 %cond1, !dbg !9
82 }
83
84 declare i32 @bar(i64, i32, i32)
85
86 declare void @llvm.memcpy.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32, i1) #1
87
88 attributes #0 = { noinline nounwind uwtable }
89 attributes #1 = { argmemonly nounwind }
90
91 !llvm.dbg.cu = !{!0}
92 !llvm.module.flags = !{!3, !4}
93
94 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: LineTablesOnly, enums: !2)
95 !1 = !DIFile(filename: "test.c", directory: ".")
96 !2 = !{}
97 !3 = !{i32 2, !"Dwarf Version", i32 4}
98 !4 = !{i32 2, !"Debug Info Version", i32 3}
99 !5 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 15, type: !6, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2)
100 !6 = !DISubroutineType(types: !2)
101 !7 = !DILocation(line: 16, column: 16, scope: !5)
102 !8 = !DILocation(line: 16, column: 23, scope: !5)
103 !9 = !DILocation(line: 17, column: 3, scope: !5)