xref: /llvm-project/llvm/unittests/Transforms/Utils/DebugifyTest.cpp (revision 360da83858655ad8297f3c0467c8c97ebedab5ed)
1 //===- DebugifyTest.cpp - Debugify unit tests -----------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
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"
17 
18 using namespace llvm;
19 
parseIR(LLVMContext & C,const char * IR)20 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
21   SMDiagnostic Err;
22   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
23   if (!Mod)
24     Err.print("DebugifyTest", errs());
25   return Mod;
26 }
27 
28 namespace llvm {
29 void initializeDebugInfoDropPass(PassRegistry &);
30 void initializeDebugInfoDummyAnalysisPass(PassRegistry &);
31 
32 namespace {
33 struct DebugInfoDrop : public FunctionPass {
34   static char ID;
runOnFunctionllvm::__anonf5b6608c0111::DebugInfoDrop35   bool runOnFunction(Function &F) override {
36     // Drop DISubprogram.
37     F.setSubprogram(nullptr);
38     for (BasicBlock &BB : F) {
39       // Remove debug locations.
40       for (Instruction &I : BB)
41         I.setDebugLoc(DebugLoc());
42     }
43 
44     return false;
45   }
46 
getAnalysisUsagellvm::__anonf5b6608c0111::DebugInfoDrop47   void getAnalysisUsage(AnalysisUsage &AU) const override {
48     AU.setPreservesCFG();
49   }
50 
DebugInfoDropllvm::__anonf5b6608c0111::DebugInfoDrop51   DebugInfoDrop() : FunctionPass(ID) {}
52 };
53 
54 struct DebugValueDrop : public FunctionPass {
55   static char ID;
runOnFunctionllvm::__anonf5b6608c0111::DebugValueDrop56   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))
62           Dbgs.push_back(DVI);
63         // If there are any non-intrinsic records (DbgRecords), drop those too.
64         I.dropDbgRecords();
65       }
66     }
67 
68     for (auto &I : Dbgs)
69       I->eraseFromParent();
70 
71     return true;
72   }
73 
getAnalysisUsagellvm::__anonf5b6608c0111::DebugValueDrop74   void getAnalysisUsage(AnalysisUsage &AU) const override {
75     AU.setPreservesCFG();
76   }
77 
DebugValueDropllvm::__anonf5b6608c0111::DebugValueDrop78   DebugValueDrop() : FunctionPass(ID) {}
79 };
80 
81 struct DebugInfoDummyAnalysis : public FunctionPass {
82   static char ID;
runOnFunctionllvm::__anonf5b6608c0111::DebugInfoDummyAnalysis83   bool runOnFunction(Function &F) override {
84     // Do nothing, so debug info stays untouched.
85     return false;
86   }
getAnalysisUsagellvm::__anonf5b6608c0111::DebugInfoDummyAnalysis87   void getAnalysisUsage(AnalysisUsage &AU) const override {
88     AU.setPreservesAll();
89   }
90 
DebugInfoDummyAnalysisllvm::__anonf5b6608c0111::DebugInfoDummyAnalysis91   DebugInfoDummyAnalysis() : FunctionPass(ID) {}
92 };
93 }
94 
95 char DebugInfoDrop::ID = 0;
96 char DebugValueDrop::ID = 0;
97 char DebugInfoDummyAnalysis::ID = 0;
98 
TEST(DebugInfoDrop,DropOriginalDebugInfo)99 TEST(DebugInfoDrop, DropOriginalDebugInfo) {
100   LLVMContext C;
101   std::unique_ptr<Module> M = parseIR(C, R"(
102     define i16 @f(i16 %a) !dbg !6 {
103       %b = add i16 %a, 1, !dbg !11
104       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
105       ret i16 0, !dbg !11
106     }
107     declare void @llvm.dbg.value(metadata, metadata, metadata)
108 
109     !llvm.dbg.cu = !{!0}
110     !llvm.module.flags = !{!5}
111 
112     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
113     !1 = !DIFile(filename: "t.ll", directory: "/")
114     !2 = !{}
115     !5 = !{i32 2, !"Debug Info Version", i32 3}
116     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
117     !7 = !DISubroutineType(types: !2)
118     !8 = !{!9}
119     !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
120     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
121     !11 = !DILocation(line: 1, column: 1, scope: !6)
122   )");
123 
124   DebugInfoDrop *P = new DebugInfoDrop();
125 
126   DebugInfoPerPass DIBeforePass;
127   DebugifyCustomPassManager Passes;
128   Passes.setDebugInfoBeforePass(DIBeforePass);
129   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
130                                       &(Passes.getDebugInfoPerPass())));
131   Passes.add(P);
132   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
133                                            DebugifyMode::OriginalDebugInfo,
134                                            &(Passes.getDebugInfoPerPass())));
135 
136   testing::internal::CaptureStderr();
137   Passes.run(*M);
138 
139   std::string StdOut = testing::internal::GetCapturedStderr();
140 
141   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
142   std::string WarningForLoc = "WARNING:  dropped DILocation of";
143   std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
144 
145   EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos);
146   EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos);
147   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
148 }
149 
TEST(DebugValueDrop,DropOriginalDebugValues)150 TEST(DebugValueDrop, DropOriginalDebugValues) {
151   LLVMContext C;
152   std::unique_ptr<Module> M = parseIR(C, R"(
153     define i16 @f(i16 %a) !dbg !6 {
154       %b = add i16 %a, 1, !dbg !11
155       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
156       ret i16 0, !dbg !11
157     }
158     declare void @llvm.dbg.value(metadata, metadata, metadata)
159 
160     !llvm.dbg.cu = !{!0}
161     !llvm.module.flags = !{!5}
162 
163     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
164     !1 = !DIFile(filename: "t.ll", directory: "/")
165     !2 = !{}
166     !5 = !{i32 2, !"Debug Info Version", i32 3}
167     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
168     !7 = !DISubroutineType(types: !2)
169     !8 = !{!9}
170     !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
171     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
172     !11 = !DILocation(line: 1, column: 1, scope: !6)
173   )");
174 
175   DebugValueDrop *P = new DebugValueDrop();
176 
177   DebugInfoPerPass DIBeforePass;
178   DebugifyCustomPassManager Passes;
179   Passes.setDebugInfoBeforePass(DIBeforePass);
180   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
181                                       &(Passes.getDebugInfoPerPass())));
182   Passes.add(P);
183   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
184                                            DebugifyMode::OriginalDebugInfo,
185                                            &(Passes.getDebugInfoPerPass())));
186 
187   testing::internal::CaptureStderr();
188   Passes.run(*M);
189 
190   std::string StdOut = testing::internal::GetCapturedStderr();
191 
192   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
193   std::string WarningForLoc = "WARNING:  dropped DILocation of";
194   std::string WarningForVars = "WARNING:  drops dbg.value()/dbg.declare() for";
195   std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
196 
197   EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
198   EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
199   EXPECT_TRUE(StdOut.find(WarningForVars) != std::string::npos);
200   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
201 }
202 
TEST(DebugInfoDummyAnalysis,PreserveOriginalDebugInfo)203 TEST(DebugInfoDummyAnalysis, PreserveOriginalDebugInfo) {
204   LLVMContext C;
205   std::unique_ptr<Module> M = parseIR(C, R"(
206     define i32 @g(i32 %b) !dbg !6 {
207       %c = add i32 %b, 1, !dbg !11
208       call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11
209       ret i32 1, !dbg !11
210     }
211     declare void @llvm.dbg.value(metadata, metadata, metadata)
212 
213     !llvm.dbg.cu = !{!0}
214     !llvm.module.flags = !{!5}
215 
216     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
217     !1 = !DIFile(filename: "test.ll", directory: "/")
218     !2 = !{}
219     !5 = !{i32 2, !"Debug Info Version", i32 3}
220     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
221     !7 = !DISubroutineType(types: !2)
222     !8 = !{!9}
223     !9 = !DILocalVariable(name: "c", scope: !6, file: !1, line: 1, type: !10)
224     !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
225     !11 = !DILocation(line: 1, column: 1, scope: !6)
226   )");
227 
228   DebugInfoDummyAnalysis *P = new DebugInfoDummyAnalysis();
229 
230   DebugInfoPerPass DIBeforePass;
231   DebugifyCustomPassManager Passes;
232   Passes.setDebugInfoBeforePass(DIBeforePass);
233   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
234                                       &(Passes.getDebugInfoPerPass())));
235   Passes.add(P);
236   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
237                                            DebugifyMode::OriginalDebugInfo,
238                                            &(Passes.getDebugInfoPerPass())));
239 
240   testing::internal::CaptureStderr();
241   Passes.run(*M);
242 
243   std::string StdOut = testing::internal::GetCapturedStderr();
244 
245   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
246   std::string WarningForLoc = "WARNING:  dropped DILocation of";
247   std::string WarningForVars = "WARNING:  drops dbg.value()/dbg.declare() for";
248   std::string FinalResult = "CheckModuleDebugify (original debuginfo): PASS";
249 
250   EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
251   EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
252   EXPECT_TRUE(StdOut.find(WarningForVars) == std::string::npos);
253   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
254 }
255 
256 } // end namespace llvm
257 
258 INITIALIZE_PASS_BEGIN(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass",
259                       false, false)
260 INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false,
261                     false)
262 
263 INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
264                       "debuginfodummyanalysispass", false, false)
265 INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
266                     "debuginfodummyanalysispass", false, false)
267