1 //===- unittests/IR/DroppedVariableStatsTest.cpp - TimePassesHandler tests
4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5 // See https://llvm.org/LICENSE.txt for license information.
6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
8 //===----------------------------------------------------------------------===//
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Function.h"
12 #include "llvm/IR/InstIterator.h"
13 #include "llvm/IR/LegacyPassManager.h"
14 #include "llvm/IR/Module.h"
15 #include "llvm/Pass.h"
16 #include "llvm/PassRegistry.h"
17 #include "llvm/Passes/StandardInstrumentations.h"
18 #include "llvm/Support/SourceMgr.h"
19 #include "gtest/gtest.h"
20 #include <gtest/gtest.h>
21 #include <llvm/ADT/SmallString.h>
22 #include <llvm/IR/LLVMContext.h>
23 #include <llvm/IR/Module.h>
24 #include <llvm/IR/PassInstrumentation.h>
25 #include <llvm/IR/PassManager.h>
26 #include <llvm/IR/PassTimingInfo.h>
27 #include <llvm/Support/raw_ostream.h>
31 void initializePassTest1Pass(PassRegistry
&);
33 static std::unique_ptr
<Module
> parseIR(LLVMContext
&C
, const char *IR
) {
35 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
37 Err
.print("AbstractCallSiteTests", errs());
44 // This test ensures that if a #dbg_value and an instruction that exists in the
45 // same scope as that #dbg_value are both deleted as a result of an optimization
46 // pass, debug information is considered not dropped.
47 TEST(DroppedVariableStats
, BothDeleted
) {
48 PassInstrumentationCallbacks PIC
;
49 PassInstrumentation
PI(&PIC
);
55 ; Function Attrs: mustprogress nounwind ssp uwtable(sync)
56 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
58 #dbg_value(i32 %x, !15, !DIExpression(), !16)
59 %add = add nsw i32 %x, 1, !dbg !17
63 !llvm.module.flags = !{!3}
65 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
66 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
67 !3 = !{i32 2, !"Debug Info Version
", i32 3}
69 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
70 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
71 !11 = !DISubroutineType(types: !12)
73 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
75 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
76 !16 = !DILocation(line: 0, scope: !9)
77 !17 = !DILocation(line: 2, column: 11, scope: !9))";
79 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
82 DroppedVariableStats
Stats(true);
83 Stats
.runBeforePass("Test",
84 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
86 // This loop simulates an IR pass that drops debug information.
88 for (auto &I
: instructions(&F
)) {
96 Stats
.runAfterPass("Test",
97 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
98 ASSERT_EQ(Stats
.getPassDroppedVariables(), false);
101 // This test ensures that if a #dbg_value is dropped after an optimization pass,
102 // but an instruction that shares the same scope as the #dbg_value still exists,
103 // debug information is conisdered dropped.
104 TEST(DroppedVariableStats
, DbgValLost
) {
105 PassInstrumentationCallbacks PIC
;
106 PassInstrumentation
PI(&PIC
);
112 ; Function Attrs: mustprogress nounwind ssp uwtable(sync)
113 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
115 #dbg_value(i32 %x, !15, !DIExpression(), !16)
116 %add = add nsw i32 %x, 1, !dbg !17
120 !llvm.module.flags = !{!3}
122 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
123 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
124 !3 = !{i32 2, !"Debug Info Version
", i32 3}
126 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
127 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
128 !11 = !DISubroutineType(types: !12)
130 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
132 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
133 !16 = !DILocation(line: 0, scope: !9)
134 !17 = !DILocation(line: 2, column: 11, scope: !9))";
136 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
139 DroppedVariableStats
Stats(true);
140 Stats
.runBeforePass("Test",
141 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
143 // This loop simulates an IR pass that drops debug information.
145 for (auto &I
: instructions(&F
)) {
151 PreservedAnalyses PA
;
152 Stats
.runAfterPass("Test",
153 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
154 ASSERT_EQ(Stats
.getPassDroppedVariables(), true);
157 // This test ensures that if a #dbg_value is dropped after an optimization pass,
158 // but an instruction that has an unrelated scope as the #dbg_value still
159 // exists, debug information is conisdered not dropped.
160 TEST(DroppedVariableStats
, UnrelatedScopes
) {
161 PassInstrumentationCallbacks PIC
;
162 PassInstrumentation
PI(&PIC
);
168 ; Function Attrs: mustprogress nounwind ssp uwtable(sync)
169 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
171 #dbg_value(i32 %x, !15, !DIExpression(), !16)
172 %add = add nsw i32 %x, 1, !dbg !17
176 !llvm.module.flags = !{!3}
178 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
179 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
180 !3 = !{i32 2, !"Debug Info Version
", i32 3}
182 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
183 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
184 !11 = !DISubroutineType(types: !12)
186 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
188 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
189 !16 = !DILocation(line: 0, scope: !9)
190 !17 = !DILocation(line: 2, column: 11, scope: !18)
191 !18 = distinct !DISubprogram(name: "bar
", linkageName: "_Z3bari
", scope: !10, file: !10, line: 11, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14))";
193 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
196 DroppedVariableStats
Stats(true);
197 Stats
.runBeforePass("Test",
198 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
200 // This loop simulates an IR pass that drops debug information.
202 for (auto &I
: instructions(&F
)) {
208 PreservedAnalyses PA
;
209 Stats
.runAfterPass("Test",
210 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
211 ASSERT_EQ(Stats
.getPassDroppedVariables(), false);
214 // This test ensures that if a #dbg_value is dropped after an optimization pass,
215 // but an instruction that has a scope which is a child of the #dbg_value scope
216 // still exists, debug information is conisdered dropped.
217 TEST(DroppedVariableStats
, ChildScopes
) {
218 PassInstrumentationCallbacks PIC
;
219 PassInstrumentation
PI(&PIC
);
225 ; Function Attrs: mustprogress nounwind ssp uwtable(sync)
226 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
228 #dbg_value(i32 %x, !15, !DIExpression(), !16)
229 %add = add nsw i32 %x, 1, !dbg !17
233 !llvm.module.flags = !{!3}
235 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
236 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
237 !3 = !{i32 2, !"Debug Info Version
", i32 3}
239 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
240 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
241 !11 = !DISubroutineType(types: !12)
243 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
245 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
246 !16 = !DILocation(line: 0, scope: !9)
247 !17 = !DILocation(line: 2, column: 11, scope: !18)
248 !18 = distinct !DILexicalBlock(scope: !9, file: !10, line: 10, column: 28))";
250 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
253 DroppedVariableStats
Stats(true);
254 Stats
.runBeforePass("Test",
255 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
257 // This loop simulates an IR pass that drops debug information.
259 for (auto &I
: instructions(&F
)) {
265 PreservedAnalyses PA
;
266 Stats
.runAfterPass("Test",
267 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
268 ASSERT_EQ(Stats
.getPassDroppedVariables(), true);
271 // This test ensures that if a #dbg_value is dropped after an optimization pass,
272 // but an instruction that has a scope which is a child of the #dbg_value scope
273 // still exists, and the #dbg_value is inlined at another location, debug
274 // information is conisdered not dropped.
275 TEST(DroppedVariableStats
, InlinedAt
) {
276 PassInstrumentationCallbacks PIC
;
277 PassInstrumentation
PI(&PIC
);
282 R
"(; Function Attrs: mustprogress nounwind ssp uwtable(sync)
283 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
285 #dbg_value(i32 %x, !15, !DIExpression(), !16)
286 %add = add nsw i32 %x, 1, !dbg !17
290 !llvm.module.flags = !{!3}
292 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
293 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
294 !3 = !{i32 2, !"Debug Info Version
", i32 3}
296 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
297 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
298 !11 = !DISubroutineType(types: !12)
300 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
302 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
303 !16 = !DILocation(line: 0, scope: !9, inlinedAt: !19)
304 !17 = !DILocation(line: 2, column: 11, scope: !18)
305 !18 = distinct !DILexicalBlock(scope: !9, file: !10, line: 10, column: 28)
306 !19 = !DILocation(line: 3, column: 2, scope: !9))";
308 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
311 DroppedVariableStats
Stats(true);
312 Stats
.runBeforePass("Test",
313 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
315 // This loop simulates an IR pass that drops debug information.
317 for (auto &I
: instructions(&F
)) {
323 PreservedAnalyses PA
;
324 Stats
.runAfterPass("Test",
325 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
326 ASSERT_EQ(Stats
.getPassDroppedVariables(), false);
329 // This test ensures that if a #dbg_value is dropped after an optimization pass,
330 // but an instruction that has a scope which is a child of the #dbg_value scope
331 // still exists, and the #dbg_value and the instruction are inlined at another
332 // location, debug information is conisdered dropped.
333 TEST(DroppedVariableStats
, InlinedAtShared
) {
334 PassInstrumentationCallbacks PIC
;
335 PassInstrumentation
PI(&PIC
);
340 R
"(; Function Attrs: mustprogress nounwind ssp uwtable(sync)
341 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
343 #dbg_value(i32 %x, !15, !DIExpression(), !16)
344 %add = add nsw i32 %x, 1, !dbg !17
348 !llvm.module.flags = !{!3}
350 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
351 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
352 !3 = !{i32 2, !"Debug Info Version
", i32 3}
354 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
355 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
356 !11 = !DISubroutineType(types: !12)
358 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
360 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
361 !16 = !DILocation(line: 0, scope: !9, inlinedAt: !19)
362 !17 = !DILocation(line: 2, column: 11, scope: !18, inlinedAt: !19)
363 !18 = distinct !DILexicalBlock(scope: !9, file: !10, line: 10, column: 28)
364 !19 = !DILocation(line: 3, column: 2, scope: !9))";
366 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
369 DroppedVariableStats
Stats(true);
370 Stats
.runBeforePass("Test",
371 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
373 // This loop simulates an IR pass that drops debug information.
375 for (auto &I
: instructions(&F
)) {
381 PreservedAnalyses PA
;
382 Stats
.runAfterPass("Test",
383 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
384 ASSERT_EQ(Stats
.getPassDroppedVariables(), true);
387 // This test ensures that if a #dbg_value is dropped after an optimization pass,
388 // but an instruction that has a scope which is a child of the #dbg_value scope
389 // still exists, and the instruction is inlined at a location that is the
390 // #dbg_value's inlined at location, debug information is conisdered dropped.
391 TEST(DroppedVariableStats
, InlinedAtChild
) {
392 PassInstrumentationCallbacks PIC
;
393 PassInstrumentation
PI(&PIC
);
398 R
"(; Function Attrs: mustprogress nounwind ssp uwtable(sync)
399 define noundef range(i32 -2147483647, -2147483648) i32 @_Z3fooi(i32 noundef %x) local_unnamed_addr #0 !dbg !9 {
401 #dbg_value(i32 %x, !15, !DIExpression(), !16)
402 %add = add nsw i32 %x, 1, !dbg !17
406 !llvm.module.flags = !{!3}
408 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, producer: "clang
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: Apple, sysroot: "/")
409 !1 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "/")
410 !3 = !{i32 2, !"Debug Info Version
", i32 3}
412 !9 = distinct !DISubprogram(name: "foo
", linkageName: "_Z3fooi
", scope: !10, file: !10, line: 1, type: !11, scopeLine: 1, unit: !0, retainedNodes: !14)
413 !10 = !DIFile(filename: "/tmp
/code
.cpp
", directory: "")
414 !11 = !DISubroutineType(types: !12)
416 !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
418 !15 = !DILocalVariable(name: "x
", arg: 1, scope: !9, file: !10, line: 1, type: !13)
419 !16 = !DILocation(line: 0, scope: !9, inlinedAt: !19)
420 !17 = !DILocation(line: 2, column: 11, scope: !18, inlinedAt: !20)
421 !18 = distinct !DILexicalBlock(scope: !9, file: !10, line: 10, column: 28)
422 !19 = !DILocation(line: 3, column: 2, scope: !9);
423 !20 = !DILocation(line: 4, column: 5, scope: !18, inlinedAt: !19))";
425 std::unique_ptr
<llvm::Module
> M
= parseIR(C
, IR
);
428 DroppedVariableStats
Stats(true);
429 Stats
.runBeforePass("Test",
430 llvm::Any(const_cast<const llvm::Module
*>(M
.get())));
432 // This loop simulates an IR pass that drops debug information.
434 for (auto &I
: instructions(&F
)) {
440 PreservedAnalyses PA
;
441 Stats
.runAfterPass("Test",
442 llvm::Any(const_cast<const llvm::Module
*>(M
.get())), PA
);
443 ASSERT_EQ(Stats
.getPassDroppedVariables(), true);
446 } // end anonymous namespace