11a2b3536SDjordje Todorovic //===- DebugifyTest.cpp - Debugify unit tests -----------------------------===//
21a2b3536SDjordje Todorovic //
31a2b3536SDjordje Todorovic // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41a2b3536SDjordje Todorovic // See https://llvm.org/LICENSE.txt for license information.
51a2b3536SDjordje Todorovic // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61a2b3536SDjordje Todorovic //
71a2b3536SDjordje Todorovic //===----------------------------------------------------------------------===//
81a2b3536SDjordje Todorovic 
9b9076d11SDjordje Todorovic #include "llvm/ADT/SmallVector.h"
101a2b3536SDjordje Todorovic #include "llvm/AsmParser/Parser.h"
111a2b3536SDjordje Todorovic #include "llvm/IR/DebugInfoMetadata.h"
12b9076d11SDjordje Todorovic #include "llvm/IR/IntrinsicInst.h"
131a2b3536SDjordje Todorovic #include "llvm/IR/LegacyPassManager.h"
141a2b3536SDjordje Todorovic #include "llvm/Support/SourceMgr.h"
151a2b3536SDjordje Todorovic #include "llvm/Transforms/Utils/Debugify.h"
161a2b3536SDjordje Todorovic #include "gtest/gtest.h"
171a2b3536SDjordje Todorovic 
181a2b3536SDjordje Todorovic using namespace llvm;
191a2b3536SDjordje Todorovic 
parseIR(LLVMContext & C,const char * IR)201a2b3536SDjordje Todorovic static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
211a2b3536SDjordje Todorovic   SMDiagnostic Err;
221a2b3536SDjordje Todorovic   std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
231a2b3536SDjordje Todorovic   if (!Mod)
241a2b3536SDjordje Todorovic     Err.print("DebugifyTest", errs());
251a2b3536SDjordje Todorovic   return Mod;
261a2b3536SDjordje Todorovic }
271a2b3536SDjordje Todorovic 
281a2b3536SDjordje Todorovic namespace llvm {
291a2b3536SDjordje Todorovic void initializeDebugInfoDropPass(PassRegistry &);
301a2b3536SDjordje Todorovic void initializeDebugInfoDummyAnalysisPass(PassRegistry &);
311a2b3536SDjordje Todorovic 
321a2b3536SDjordje Todorovic namespace {
331a2b3536SDjordje Todorovic struct DebugInfoDrop : public FunctionPass {
341a2b3536SDjordje Todorovic   static char ID;
runOnFunctionllvm::__anoneaed2e690111::DebugInfoDrop351a2b3536SDjordje Todorovic   bool runOnFunction(Function &F) override {
361a2b3536SDjordje Todorovic     // Drop DISubprogram.
371a2b3536SDjordje Todorovic     F.setSubprogram(nullptr);
381a2b3536SDjordje Todorovic     for (BasicBlock &BB : F) {
391a2b3536SDjordje Todorovic       // Remove debug locations.
401a2b3536SDjordje Todorovic       for (Instruction &I : BB)
411a2b3536SDjordje Todorovic         I.setDebugLoc(DebugLoc());
421a2b3536SDjordje Todorovic     }
431a2b3536SDjordje Todorovic 
441a2b3536SDjordje Todorovic     return false;
451a2b3536SDjordje Todorovic   }
46b9076d11SDjordje Todorovic 
getAnalysisUsagellvm::__anoneaed2e690111::DebugInfoDrop471a2b3536SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
481a2b3536SDjordje Todorovic     AU.setPreservesCFG();
491a2b3536SDjordje Todorovic   }
501a2b3536SDjordje Todorovic 
DebugInfoDropllvm::__anoneaed2e690111::DebugInfoDrop511a2b3536SDjordje Todorovic   DebugInfoDrop() : FunctionPass(ID) {}
521a2b3536SDjordje Todorovic };
531a2b3536SDjordje Todorovic 
54b9076d11SDjordje Todorovic struct DebugValueDrop : public FunctionPass {
55b9076d11SDjordje Todorovic   static char ID;
runOnFunctionllvm::__anoneaed2e690111::DebugValueDrop56b9076d11SDjordje Todorovic   bool runOnFunction(Function &F) override {
57b9076d11SDjordje Todorovic     SmallVector<DbgVariableIntrinsic *, 4> Dbgs;
58b9076d11SDjordje Todorovic     for (BasicBlock &BB : F) {
59b9076d11SDjordje Todorovic       // Remove dbg var intrinsics.
60b9076d11SDjordje Todorovic       for (Instruction &I : BB) {
61b9076d11SDjordje Todorovic         if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I))
62b9076d11SDjordje Todorovic           Dbgs.push_back(DVI);
63b9076d11SDjordje Todorovic       }
64b9076d11SDjordje Todorovic     }
65b9076d11SDjordje Todorovic 
66b9076d11SDjordje Todorovic     for (auto &I : Dbgs)
67b9076d11SDjordje Todorovic       I->eraseFromParent();
68b9076d11SDjordje Todorovic 
69b9076d11SDjordje Todorovic     return true;
70b9076d11SDjordje Todorovic   }
71b9076d11SDjordje Todorovic 
getAnalysisUsagellvm::__anoneaed2e690111::DebugValueDrop72b9076d11SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
73b9076d11SDjordje Todorovic     AU.setPreservesCFG();
74b9076d11SDjordje Todorovic   }
75b9076d11SDjordje Todorovic 
DebugValueDropllvm::__anoneaed2e690111::DebugValueDrop76b9076d11SDjordje Todorovic   DebugValueDrop() : FunctionPass(ID) {}
77b9076d11SDjordje Todorovic };
78b9076d11SDjordje Todorovic 
791a2b3536SDjordje Todorovic struct DebugInfoDummyAnalysis : public FunctionPass {
801a2b3536SDjordje Todorovic   static char ID;
runOnFunctionllvm::__anoneaed2e690111::DebugInfoDummyAnalysis811a2b3536SDjordje Todorovic   bool runOnFunction(Function &F) override {
821a2b3536SDjordje Todorovic     // Do nothing, so debug info stays untouched.
831a2b3536SDjordje Todorovic     return false;
841a2b3536SDjordje Todorovic   }
getAnalysisUsagellvm::__anoneaed2e690111::DebugInfoDummyAnalysis851a2b3536SDjordje Todorovic   void getAnalysisUsage(AnalysisUsage &AU) const override {
861a2b3536SDjordje Todorovic     AU.setPreservesAll();
871a2b3536SDjordje Todorovic   }
881a2b3536SDjordje Todorovic 
DebugInfoDummyAnalysisllvm::__anoneaed2e690111::DebugInfoDummyAnalysis891a2b3536SDjordje Todorovic   DebugInfoDummyAnalysis() : FunctionPass(ID) {}
901a2b3536SDjordje Todorovic };
911a2b3536SDjordje Todorovic }
921a2b3536SDjordje Todorovic 
931a2b3536SDjordje Todorovic char DebugInfoDrop::ID = 0;
94b9076d11SDjordje Todorovic char DebugValueDrop::ID = 0;
951a2b3536SDjordje Todorovic char DebugInfoDummyAnalysis::ID = 0;
961a2b3536SDjordje Todorovic 
TEST(DebugInfoDrop,DropOriginalDebugInfo)971a2b3536SDjordje Todorovic TEST(DebugInfoDrop, DropOriginalDebugInfo) {
981a2b3536SDjordje Todorovic   LLVMContext C;
991a2b3536SDjordje Todorovic   std::unique_ptr<Module> M = parseIR(C, R"(
1001a2b3536SDjordje Todorovic     define i16 @f(i16 %a) !dbg !6 {
1011a2b3536SDjordje Todorovic       %b = add i16 %a, 1, !dbg !11
1021a2b3536SDjordje Todorovic       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
1031a2b3536SDjordje Todorovic       ret i16 0, !dbg !11
1041a2b3536SDjordje Todorovic     }
1051a2b3536SDjordje Todorovic     declare void @llvm.dbg.value(metadata, metadata, metadata)
1061a2b3536SDjordje Todorovic 
1071a2b3536SDjordje Todorovic     !llvm.dbg.cu = !{!0}
1081a2b3536SDjordje Todorovic     !llvm.module.flags = !{!5}
1091a2b3536SDjordje Todorovic 
1101a2b3536SDjordje Todorovic     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
1111a2b3536SDjordje Todorovic     !1 = !DIFile(filename: "t.ll", directory: "/")
1121a2b3536SDjordje Todorovic     !2 = !{}
1131a2b3536SDjordje Todorovic     !5 = !{i32 2, !"Debug Info Version", i32 3}
1141a2b3536SDjordje Todorovic     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
1151a2b3536SDjordje Todorovic     !7 = !DISubroutineType(types: !2)
1161a2b3536SDjordje Todorovic     !8 = !{!9}
1171a2b3536SDjordje Todorovic     !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
1181a2b3536SDjordje Todorovic     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
1191a2b3536SDjordje Todorovic     !11 = !DILocation(line: 1, column: 1, scope: !6)
1201a2b3536SDjordje Todorovic   )");
1211a2b3536SDjordje Todorovic 
1221a2b3536SDjordje Todorovic   DebugInfoDrop *P = new DebugInfoDrop();
1231a2b3536SDjordje Todorovic 
124*73777b4cSDjordje Todorovic   DebugInfoPerPass DIBeforePass;
1251a2b3536SDjordje Todorovic   DebugifyCustomPassManager Passes;
126*73777b4cSDjordje Todorovic   Passes.setDebugInfoBeforePass(DIBeforePass);
1271a2b3536SDjordje Todorovic   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
128*73777b4cSDjordje Todorovic                                       &(Passes.getDebugInfoPerPass())));
1291a2b3536SDjordje Todorovic   Passes.add(P);
1301a2b3536SDjordje Todorovic   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
1311a2b3536SDjordje Todorovic                                            DebugifyMode::OriginalDebugInfo,
132*73777b4cSDjordje Todorovic                                            &(Passes.getDebugInfoPerPass())));
1331a2b3536SDjordje Todorovic 
1341a2b3536SDjordje Todorovic   testing::internal::CaptureStderr();
1351a2b3536SDjordje Todorovic   Passes.run(*M);
1361a2b3536SDjordje Todorovic 
1371a2b3536SDjordje Todorovic   std::string StdOut = testing::internal::GetCapturedStderr();
1381a2b3536SDjordje Todorovic 
1391a2b3536SDjordje Todorovic   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
1401a2b3536SDjordje Todorovic   std::string WarningForLoc = "WARNING:  dropped DILocation of";
1411a2b3536SDjordje Todorovic   std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
1421a2b3536SDjordje Todorovic 
1431a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos);
1441a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos);
1451a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
1461a2b3536SDjordje Todorovic }
1471a2b3536SDjordje Todorovic 
TEST(DebugValueDrop,DropOriginalDebugValues)148b9076d11SDjordje Todorovic TEST(DebugValueDrop, DropOriginalDebugValues) {
149b9076d11SDjordje Todorovic   LLVMContext C;
150b9076d11SDjordje Todorovic   std::unique_ptr<Module> M = parseIR(C, R"(
151b9076d11SDjordje Todorovic     define i16 @f(i16 %a) !dbg !6 {
152b9076d11SDjordje Todorovic       %b = add i16 %a, 1, !dbg !11
153b9076d11SDjordje Todorovic       call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11
154b9076d11SDjordje Todorovic       ret i16 0, !dbg !11
155b9076d11SDjordje Todorovic     }
156b9076d11SDjordje Todorovic     declare void @llvm.dbg.value(metadata, metadata, metadata)
157b9076d11SDjordje Todorovic 
158b9076d11SDjordje Todorovic     !llvm.dbg.cu = !{!0}
159b9076d11SDjordje Todorovic     !llvm.module.flags = !{!5}
160b9076d11SDjordje Todorovic 
161b9076d11SDjordje Todorovic     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
162b9076d11SDjordje Todorovic     !1 = !DIFile(filename: "t.ll", directory: "/")
163b9076d11SDjordje Todorovic     !2 = !{}
164b9076d11SDjordje Todorovic     !5 = !{i32 2, !"Debug Info Version", i32 3}
165b9076d11SDjordje Todorovic     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
166b9076d11SDjordje Todorovic     !7 = !DISubroutineType(types: !2)
167b9076d11SDjordje Todorovic     !8 = !{!9}
168b9076d11SDjordje Todorovic     !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)
169b9076d11SDjordje Todorovic     !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)
170b9076d11SDjordje Todorovic     !11 = !DILocation(line: 1, column: 1, scope: !6)
171b9076d11SDjordje Todorovic   )");
172b9076d11SDjordje Todorovic 
173b9076d11SDjordje Todorovic   DebugValueDrop *P = new DebugValueDrop();
174b9076d11SDjordje Todorovic 
175*73777b4cSDjordje Todorovic   DebugInfoPerPass DIBeforePass;
176b9076d11SDjordje Todorovic   DebugifyCustomPassManager Passes;
177*73777b4cSDjordje Todorovic   Passes.setDebugInfoBeforePass(DIBeforePass);
178b9076d11SDjordje Todorovic   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
179*73777b4cSDjordje Todorovic                                       &(Passes.getDebugInfoPerPass())));
180b9076d11SDjordje Todorovic   Passes.add(P);
181b9076d11SDjordje Todorovic   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
182b9076d11SDjordje Todorovic                                            DebugifyMode::OriginalDebugInfo,
183*73777b4cSDjordje Todorovic                                            &(Passes.getDebugInfoPerPass())));
184b9076d11SDjordje Todorovic 
185b9076d11SDjordje Todorovic   testing::internal::CaptureStderr();
186b9076d11SDjordje Todorovic   Passes.run(*M);
187b9076d11SDjordje Todorovic 
188b9076d11SDjordje Todorovic   std::string StdOut = testing::internal::GetCapturedStderr();
189b9076d11SDjordje Todorovic 
190b9076d11SDjordje Todorovic   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
191b9076d11SDjordje Todorovic   std::string WarningForLoc = "WARNING:  dropped DILocation of";
192b9076d11SDjordje Todorovic   std::string WarningForVars = "WARNING:  drops dbg.value()/dbg.declare() for";
193b9076d11SDjordje Todorovic   std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";
194b9076d11SDjordje Todorovic 
195b9076d11SDjordje Todorovic   EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
196b9076d11SDjordje Todorovic   EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
197b9076d11SDjordje Todorovic   EXPECT_TRUE(StdOut.find(WarningForVars) != std::string::npos);
198b9076d11SDjordje Todorovic   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
199b9076d11SDjordje Todorovic }
200b9076d11SDjordje Todorovic 
TEST(DebugInfoDummyAnalysis,PreserveOriginalDebugInfo)2011a2b3536SDjordje Todorovic TEST(DebugInfoDummyAnalysis, PreserveOriginalDebugInfo) {
2021a2b3536SDjordje Todorovic   LLVMContext C;
2031a2b3536SDjordje Todorovic   std::unique_ptr<Module> M = parseIR(C, R"(
2041a2b3536SDjordje Todorovic     define i32 @g(i32 %b) !dbg !6 {
2051a2b3536SDjordje Todorovic       %c = add i32 %b, 1, !dbg !11
2061a2b3536SDjordje Todorovic       call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11
2071a2b3536SDjordje Todorovic       ret i32 1, !dbg !11
2081a2b3536SDjordje Todorovic     }
2091a2b3536SDjordje Todorovic     declare void @llvm.dbg.value(metadata, metadata, metadata)
2101a2b3536SDjordje Todorovic 
2111a2b3536SDjordje Todorovic     !llvm.dbg.cu = !{!0}
2121a2b3536SDjordje Todorovic     !llvm.module.flags = !{!5}
2131a2b3536SDjordje Todorovic 
2141a2b3536SDjordje Todorovic     !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
2151a2b3536SDjordje Todorovic     !1 = !DIFile(filename: "test.ll", directory: "/")
2161a2b3536SDjordje Todorovic     !2 = !{}
2171a2b3536SDjordje Todorovic     !5 = !{i32 2, !"Debug Info Version", i32 3}
2181a2b3536SDjordje Todorovic     !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)
2191a2b3536SDjordje Todorovic     !7 = !DISubroutineType(types: !2)
2201a2b3536SDjordje Todorovic     !8 = !{!9}
2211a2b3536SDjordje Todorovic     !9 = !DILocalVariable(name: "c", scope: !6, file: !1, line: 1, type: !10)
2221a2b3536SDjordje Todorovic     !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)
2231a2b3536SDjordje Todorovic     !11 = !DILocation(line: 1, column: 1, scope: !6)
2241a2b3536SDjordje Todorovic   )");
2251a2b3536SDjordje Todorovic 
2261a2b3536SDjordje Todorovic   DebugInfoDummyAnalysis *P = new DebugInfoDummyAnalysis();
2271a2b3536SDjordje Todorovic 
228*73777b4cSDjordje Todorovic   DebugInfoPerPass DIBeforePass;
2291a2b3536SDjordje Todorovic   DebugifyCustomPassManager Passes;
230*73777b4cSDjordje Todorovic   Passes.setDebugInfoBeforePass(DIBeforePass);
2311a2b3536SDjordje Todorovic   Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",
232*73777b4cSDjordje Todorovic                                       &(Passes.getDebugInfoPerPass())));
2331a2b3536SDjordje Todorovic   Passes.add(P);
2341a2b3536SDjordje Todorovic   Passes.add(createCheckDebugifyModulePass(false, "", nullptr,
2351a2b3536SDjordje Todorovic                                            DebugifyMode::OriginalDebugInfo,
236*73777b4cSDjordje Todorovic                                            &(Passes.getDebugInfoPerPass())));
2371a2b3536SDjordje Todorovic 
2381a2b3536SDjordje Todorovic   testing::internal::CaptureStderr();
2391a2b3536SDjordje Todorovic   Passes.run(*M);
2401a2b3536SDjordje Todorovic 
2411a2b3536SDjordje Todorovic   std::string StdOut = testing::internal::GetCapturedStderr();
2421a2b3536SDjordje Todorovic 
2431a2b3536SDjordje Todorovic   std::string ErrorForSP = "ERROR:  dropped DISubprogram of";
2441a2b3536SDjordje Todorovic   std::string WarningForLoc = "WARNING:  dropped DILocation of";
245b9076d11SDjordje Todorovic   std::string WarningForVars = "WARNING:  drops dbg.value()/dbg.declare() for";
2461a2b3536SDjordje Todorovic   std::string FinalResult = "CheckModuleDebugify (original debuginfo): PASS";
2471a2b3536SDjordje Todorovic 
2481a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);
2491a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);
250b9076d11SDjordje Todorovic   EXPECT_TRUE(StdOut.find(WarningForVars) == std::string::npos);
2511a2b3536SDjordje Todorovic   EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);
2521a2b3536SDjordje Todorovic }
2531a2b3536SDjordje Todorovic 
2541a2b3536SDjordje Todorovic } // end namespace llvm
2551a2b3536SDjordje Todorovic 
2561a2b3536SDjordje Todorovic INITIALIZE_PASS_BEGIN(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass",
2571a2b3536SDjordje Todorovic                       false, false)
2581a2b3536SDjordje Todorovic INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false,
2591a2b3536SDjordje Todorovic                     false)
2601a2b3536SDjordje Todorovic 
2611a2b3536SDjordje Todorovic INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
2621a2b3536SDjordje Todorovic                       "debuginfodummyanalysispass", false, false)
2631a2b3536SDjordje Todorovic INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",
2641a2b3536SDjordje Todorovic                     "debuginfodummyanalysispass", false, false)
265