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/AsmParser/Parser.h" 10 #include "llvm/IR/DebugInfoMetadata.h" 11 #include "llvm/IR/LegacyPassManager.h" 12 #include "llvm/Support/SourceMgr.h" 13 #include "llvm/Transforms/Utils/Debugify.h" 14 #include "gtest/gtest.h" 15 16 using namespace llvm; 17 18 static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) { 19 SMDiagnostic Err; 20 std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C); 21 if (!Mod) 22 Err.print("DebugifyTest", errs()); 23 return Mod; 24 } 25 26 namespace llvm { 27 void initializeDebugInfoDropPass(PassRegistry &); 28 void initializeDebugInfoDummyAnalysisPass(PassRegistry &); 29 30 namespace { 31 struct DebugInfoDrop : public FunctionPass { 32 static char ID; 33 bool runOnFunction(Function &F) override { 34 // Drop DISubprogram. 35 F.setSubprogram(nullptr); 36 for (BasicBlock &BB : F) { 37 // Remove debug locations. 38 for (Instruction &I : BB) 39 I.setDebugLoc(DebugLoc()); 40 } 41 42 return false; 43 } 44 void getAnalysisUsage(AnalysisUsage &AU) const override { 45 AU.setPreservesCFG(); 46 } 47 48 DebugInfoDrop() : FunctionPass(ID) {} 49 }; 50 51 struct DebugInfoDummyAnalysis : public FunctionPass { 52 static char ID; 53 bool runOnFunction(Function &F) override { 54 // Do nothing, so debug info stays untouched. 55 return false; 56 } 57 void getAnalysisUsage(AnalysisUsage &AU) const override { 58 AU.setPreservesAll(); 59 } 60 61 DebugInfoDummyAnalysis() : FunctionPass(ID) {} 62 }; 63 } 64 65 char DebugInfoDrop::ID = 0; 66 char DebugInfoDummyAnalysis::ID = 0; 67 68 TEST(DebugInfoDrop, DropOriginalDebugInfo) { 69 LLVMContext C; 70 std::unique_ptr<Module> M = parseIR(C, R"( 71 define i16 @f(i16 %a) !dbg !6 { 72 %b = add i16 %a, 1, !dbg !11 73 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11 74 ret i16 0, !dbg !11 75 } 76 declare void @llvm.dbg.value(metadata, metadata, metadata) 77 78 !llvm.dbg.cu = !{!0} 79 !llvm.module.flags = !{!5} 80 81 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 82 !1 = !DIFile(filename: "t.ll", directory: "/") 83 !2 = !{} 84 !5 = !{i32 2, !"Debug Info Version", i32 3} 85 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) 86 !7 = !DISubroutineType(types: !2) 87 !8 = !{!9} 88 !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10) 89 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned) 90 !11 = !DILocation(line: 1, column: 1, scope: !6) 91 )"); 92 93 DebugInfoDrop *P = new DebugInfoDrop(); 94 95 DebugInfoPerPassMap DIPreservationMap; 96 DebugifyCustomPassManager Passes; 97 Passes.setDIPreservationMap(DIPreservationMap); 98 Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "", 99 &(Passes.getDebugInfoPerPassMap()))); 100 Passes.add(P); 101 Passes.add(createCheckDebugifyModulePass(false, "", nullptr, 102 DebugifyMode::OriginalDebugInfo, 103 &(Passes.getDebugInfoPerPassMap()))); 104 105 testing::internal::CaptureStderr(); 106 Passes.run(*M); 107 108 std::string StdOut = testing::internal::GetCapturedStderr(); 109 110 std::string ErrorForSP = "ERROR: dropped DISubprogram of"; 111 std::string WarningForLoc = "WARNING: dropped DILocation of"; 112 std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL"; 113 114 EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos); 115 EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos); 116 EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos); 117 } 118 119 TEST(DebugInfoDummyAnalysis, PreserveOriginalDebugInfo) { 120 LLVMContext C; 121 std::unique_ptr<Module> M = parseIR(C, R"( 122 define i32 @g(i32 %b) !dbg !6 { 123 %c = add i32 %b, 1, !dbg !11 124 call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11 125 ret i32 1, !dbg !11 126 } 127 declare void @llvm.dbg.value(metadata, metadata, metadata) 128 129 !llvm.dbg.cu = !{!0} 130 !llvm.module.flags = !{!5} 131 132 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) 133 !1 = !DIFile(filename: "test.ll", directory: "/") 134 !2 = !{} 135 !5 = !{i32 2, !"Debug Info Version", i32 3} 136 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8) 137 !7 = !DISubroutineType(types: !2) 138 !8 = !{!9} 139 !9 = !DILocalVariable(name: "c", scope: !6, file: !1, line: 1, type: !10) 140 !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned) 141 !11 = !DILocation(line: 1, column: 1, scope: !6) 142 )"); 143 144 DebugInfoDummyAnalysis *P = new DebugInfoDummyAnalysis(); 145 146 DebugInfoPerPassMap DIPreservationMap; 147 DebugifyCustomPassManager Passes; 148 Passes.setDIPreservationMap(DIPreservationMap); 149 Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "", 150 &(Passes.getDebugInfoPerPassMap()))); 151 Passes.add(P); 152 Passes.add(createCheckDebugifyModulePass(false, "", nullptr, 153 DebugifyMode::OriginalDebugInfo, 154 &(Passes.getDebugInfoPerPassMap()))); 155 156 testing::internal::CaptureStderr(); 157 Passes.run(*M); 158 159 std::string StdOut = testing::internal::GetCapturedStderr(); 160 161 std::string ErrorForSP = "ERROR: dropped DISubprogram of"; 162 std::string WarningForLoc = "WARNING: dropped DILocation of"; 163 std::string FinalResult = "CheckModuleDebugify (original debuginfo): PASS"; 164 165 EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos); 166 EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos); 167 EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos); 168 } 169 170 } // end namespace llvm 171 172 INITIALIZE_PASS_BEGIN(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", 173 false, false) 174 INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false, 175 false) 176 177 INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass", 178 "debuginfodummyanalysispass", false, false) 179 INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass", 180 "debuginfodummyanalysispass", false, false) 181