1 //===- DebugifyTest.cpp - Debugify unit tests -----------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/SmallVector.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/DebugInfoMetadata.h"
12 #include "llvm/IR/IntrinsicInst.h"
13 #include "llvm/IR/LegacyPassManager.h"
14 #include "llvm/Support/SourceMgr.h"
15 #include "llvm/Transforms/Utils/Debugify.h"
16 #include "gtest/gtest.h"
20 static std::unique_ptr
<Module
> parseIR(LLVMContext
&C
, const char *IR
) {
22 std::unique_ptr
<Module
> Mod
= parseAssemblyString(IR
, Err
, C
);
24 Err
.print("DebugifyTest", errs());
29 void initializeDebugInfoDropPass(PassRegistry
&);
30 void initializeDebugInfoDummyAnalysisPass(PassRegistry
&);
33 struct DebugInfoDrop
: public FunctionPass
{
35 bool runOnFunction(Function
&F
) override
{
37 F
.setSubprogram(nullptr);
38 for (BasicBlock
&BB
: F
) {
39 // Remove debug locations.
40 for (Instruction
&I
: BB
)
41 I
.setDebugLoc(DebugLoc());
47 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
51 DebugInfoDrop() : FunctionPass(ID
) {}
54 struct DebugValueDrop
: public FunctionPass
{
56 bool runOnFunction(Function
&F
) override
{
57 SmallVector
<DbgVariableIntrinsic
*, 4> Dbgs
;
58 for (BasicBlock
&BB
: F
) {
59 // Remove dbg var intrinsics.
60 for (Instruction
&I
: BB
) {
61 if (auto *DVI
= dyn_cast
<DbgVariableIntrinsic
>(&I
))
72 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
76 DebugValueDrop() : FunctionPass(ID
) {}
79 struct DebugInfoDummyAnalysis
: public FunctionPass
{
81 bool runOnFunction(Function
&F
) override
{
82 // Do nothing, so debug info stays untouched.
85 void getAnalysisUsage(AnalysisUsage
&AU
) const override
{
89 DebugInfoDummyAnalysis() : FunctionPass(ID
) {}
93 char DebugInfoDrop::ID
= 0;
94 char DebugValueDrop::ID
= 0;
95 char DebugInfoDummyAnalysis::ID
= 0;
97 TEST(DebugInfoDrop
, DropOriginalDebugInfo
) {
99 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
100 define i16 @f(i16 %a) !dbg !6 {
101 %b = add i16 %a, 1, !dbg !11
102 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
105 declare void @llvm.dbg.value(metadata, metadata, metadata)
108 !llvm.module.flags = !{!5}
110 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
111 !1 = !DIFile(filename: "t
.ll
", directory: "/")
113 !5 = !{i32 2, !"Debug Info Version
", i32 3}
114 !6 = distinct !DISubprogram(name: "f
", linkageName: "f
", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
115 !7 = !DISubroutineType(types: !2)
117 !9 = !DILocalVariable(name: "b
", scope: !6, file: !1, line: 1, type: !10)
118 !10 = !DIBasicType(name: "ty16
", size: 16, encoding: DW_ATE_unsigned)
119 !11 = !DILocation(line: 1, column: 1, scope: !6)
122 DebugInfoDrop
*P
= new DebugInfoDrop();
124 DebugInfoPerPass DIBeforePass
;
125 DebugifyCustomPassManager Passes
;
126 Passes
.setDebugInfoBeforePass(DIBeforePass
);
127 Passes
.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo
, "",
128 &(Passes
.getDebugInfoPerPass())));
130 Passes
.add(createCheckDebugifyModulePass(false, "", nullptr,
131 DebugifyMode::OriginalDebugInfo
,
132 &(Passes
.getDebugInfoPerPass())));
134 testing::internal::CaptureStderr();
137 std::string StdOut
= testing::internal::GetCapturedStderr();
139 std::string ErrorForSP
= "ERROR: dropped DISubprogram of";
140 std::string WarningForLoc
= "WARNING: dropped DILocation of";
141 std::string FinalResult
= "CheckModuleDebugify (original debuginfo): FAIL";
143 EXPECT_TRUE(StdOut
.find(ErrorForSP
) != std::string::npos
);
144 EXPECT_TRUE(StdOut
.find(WarningForLoc
) != std::string::npos
);
145 EXPECT_TRUE(StdOut
.find(FinalResult
) != std::string::npos
);
148 TEST(DebugValueDrop
, DropOriginalDebugValues
) {
150 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
151 define i16 @f(i16 %a) !dbg !6 {
152 %b = add i16 %a, 1, !dbg !11
153 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
156 declare void @llvm.dbg.value(metadata, metadata, metadata)
159 !llvm.module.flags = !{!5}
161 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
162 !1 = !DIFile(filename: "t
.ll
", directory: "/")
164 !5 = !{i32 2, !"Debug Info Version
", i32 3}
165 !6 = distinct !DISubprogram(name: "f
", linkageName: "f
", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
166 !7 = !DISubroutineType(types: !2)
168 !9 = !DILocalVariable(name: "b
", scope: !6, file: !1, line: 1, type: !10)
169 !10 = !DIBasicType(name: "ty16
", size: 16, encoding: DW_ATE_unsigned)
170 !11 = !DILocation(line: 1, column: 1, scope: !6)
173 DebugValueDrop
*P
= new DebugValueDrop();
175 DebugInfoPerPass DIBeforePass
;
176 DebugifyCustomPassManager Passes
;
177 Passes
.setDebugInfoBeforePass(DIBeforePass
);
178 Passes
.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo
, "",
179 &(Passes
.getDebugInfoPerPass())));
181 Passes
.add(createCheckDebugifyModulePass(false, "", nullptr,
182 DebugifyMode::OriginalDebugInfo
,
183 &(Passes
.getDebugInfoPerPass())));
185 testing::internal::CaptureStderr();
188 std::string StdOut
= testing::internal::GetCapturedStderr();
190 std::string ErrorForSP
= "ERROR: dropped DISubprogram of";
191 std::string WarningForLoc
= "WARNING: dropped DILocation of";
192 std::string WarningForVars
= "WARNING: drops dbg.value()/dbg.declare() for";
193 std::string FinalResult
= "CheckModuleDebugify (original debuginfo): FAIL";
195 EXPECT_TRUE(StdOut
.find(ErrorForSP
) == std::string::npos
);
196 EXPECT_TRUE(StdOut
.find(WarningForLoc
) == std::string::npos
);
197 EXPECT_TRUE(StdOut
.find(WarningForVars
) != std::string::npos
);
198 EXPECT_TRUE(StdOut
.find(FinalResult
) != std::string::npos
);
201 TEST(DebugInfoDummyAnalysis
, PreserveOriginalDebugInfo
) {
203 std::unique_ptr
<Module
> M
= parseIR(C
, R
"(
204 define i32 @g(i32 %b) !dbg !6 {
205 %c = add i32 %b, 1, !dbg !11
206 call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11
209 declare void @llvm.dbg.value(metadata, metadata, metadata)
212 !llvm.module.flags = !{!5}
214 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify
", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
215 !1 = !DIFile(filename: "test
.ll
", directory: "/")
217 !5 = !{i32 2, !"Debug Info Version
", i32 3}
218 !6 = distinct !DISubprogram(name: "f
", linkageName: "f
", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
219 !7 = !DISubroutineType(types: !2)
221 !9 = !DILocalVariable(name: "c
", scope: !6, file: !1, line: 1, type: !10)
222 !10 = !DIBasicType(name: "ty32
", size: 32, encoding: DW_ATE_unsigned)
223 !11 = !DILocation(line: 1, column: 1, scope: !6)
226 DebugInfoDummyAnalysis
*P
= new DebugInfoDummyAnalysis();
228 DebugInfoPerPass DIBeforePass
;
229 DebugifyCustomPassManager Passes
;
230 Passes
.setDebugInfoBeforePass(DIBeforePass
);
231 Passes
.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo
, "",
232 &(Passes
.getDebugInfoPerPass())));
234 Passes
.add(createCheckDebugifyModulePass(false, "", nullptr,
235 DebugifyMode::OriginalDebugInfo
,
236 &(Passes
.getDebugInfoPerPass())));
238 testing::internal::CaptureStderr();
241 std::string StdOut
= testing::internal::GetCapturedStderr();
243 std::string ErrorForSP
= "ERROR: dropped DISubprogram of";
244 std::string WarningForLoc
= "WARNING: dropped DILocation of";
245 std::string WarningForVars
= "WARNING: drops dbg.value()/dbg.declare() for";
246 std::string FinalResult
= "CheckModuleDebugify (original debuginfo): PASS";
248 EXPECT_TRUE(StdOut
.find(ErrorForSP
) == std::string::npos
);
249 EXPECT_TRUE(StdOut
.find(WarningForLoc
) == std::string::npos
);
250 EXPECT_TRUE(StdOut
.find(WarningForVars
) == std::string::npos
);
251 EXPECT_TRUE(StdOut
.find(FinalResult
) != std::string::npos
);
254 } // end namespace llvm
256 INITIALIZE_PASS_BEGIN(DebugInfoDrop
, "debuginfodroppass", "debuginfodroppass",
258 INITIALIZE_PASS_END(DebugInfoDrop
, "debuginfodroppass", "debuginfodroppass", false,
261 INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis
, "debuginfodummyanalysispass",
262 "debuginfodummyanalysispass", false, false)
263 INITIALIZE_PASS_END(DebugInfoDummyAnalysis
, "debuginfodummyanalysispass",
264 "debuginfodummyanalysispass", false, false)