260 lines · cpp
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-exception6//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 18using namespace llvm;19 20static 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 28namespace llvm {29void initializeDebugInfoDropPass(PassRegistry &);30void initializeDebugInfoDummyAnalysisPass(PassRegistry &);31 32namespace {33struct DebugInfoDrop : public FunctionPass {34 static char ID;35 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 47 void getAnalysisUsage(AnalysisUsage &AU) const override {48 AU.setPreservesCFG();49 }50 51 DebugInfoDrop() : FunctionPass(ID) {}52};53 54struct DebugValueDrop : public FunctionPass {55 static char ID;56 bool runOnFunction(Function &F) override {57 for (BasicBlock &BB : F) {58 for (Instruction &I : BB) {59 // If there are any debug records, drop them.60 I.dropDbgRecords();61 }62 }63 64 return true;65 }66 67 void getAnalysisUsage(AnalysisUsage &AU) const override {68 AU.setPreservesCFG();69 }70 71 DebugValueDrop() : FunctionPass(ID) {}72};73 74struct DebugInfoDummyAnalysis : public FunctionPass {75 static char ID;76 bool runOnFunction(Function &F) override {77 // Do nothing, so debug info stays untouched.78 return false;79 }80 void getAnalysisUsage(AnalysisUsage &AU) const override {81 AU.setPreservesAll();82 }83 84 DebugInfoDummyAnalysis() : FunctionPass(ID) {}85};86}87 88char DebugInfoDrop::ID = 0;89char DebugValueDrop::ID = 0;90char DebugInfoDummyAnalysis::ID = 0;91 92TEST(DebugInfoDrop, DropOriginalDebugInfo) {93 LLVMContext C;94 std::unique_ptr<Module> M = parseIR(C, R"(95 define i16 @f(i16 %a) !dbg !6 {96 %b = add i16 %a, 1, !dbg !1197 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !1198 ret i16 0, !dbg !1199 }100 declare void @llvm.dbg.value(metadata, metadata, metadata)101 102 !llvm.dbg.cu = !{!0}103 !llvm.module.flags = !{!5}104 105 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)106 !1 = !DIFile(filename: "t.ll", directory: "/")107 !2 = !{}108 !5 = !{i32 2, !"Debug Info Version", i32 3}109 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)110 !7 = !DISubroutineType(types: !2)111 !8 = !{!9}112 !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)113 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)114 !11 = !DILocation(line: 1, column: 1, scope: !6)115 )");116 117 DebugInfoDrop *P = new DebugInfoDrop();118 119 DebugInfoPerPass DIBeforePass;120 DebugifyCustomPassManager Passes;121 Passes.setDebugInfoBeforePass(DIBeforePass);122 Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",123 &(Passes.getDebugInfoPerPass())));124 Passes.add(P);125 Passes.add(createCheckDebugifyModulePass(false, "", nullptr,126 DebugifyMode::OriginalDebugInfo,127 &(Passes.getDebugInfoPerPass())));128 129 testing::internal::CaptureStderr();130 Passes.run(*M);131 132 std::string StdOut = testing::internal::GetCapturedStderr();133 134 std::string ErrorForSP = "ERROR: dropped DISubprogram of";135 std::string WarningForLoc = "WARNING: dropped DILocation of";136 std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";137 138 EXPECT_TRUE(StdOut.find(ErrorForSP) != std::string::npos);139 EXPECT_TRUE(StdOut.find(WarningForLoc) != std::string::npos);140 EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);141}142 143TEST(DebugValueDrop, DropOriginalDebugValues) {144 LLVMContext C;145 std::unique_ptr<Module> M = parseIR(C, R"(146 define i16 @f(i16 %a) !dbg !6 {147 %b = add i16 %a, 1, !dbg !11148 call void @llvm.dbg.value(metadata i16 %b, metadata !9, metadata !DIExpression()), !dbg !11149 ret i16 0, !dbg !11150 }151 declare void @llvm.dbg.value(metadata, metadata, metadata)152 153 !llvm.dbg.cu = !{!0}154 !llvm.module.flags = !{!5}155 156 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)157 !1 = !DIFile(filename: "t.ll", directory: "/")158 !2 = !{}159 !5 = !{i32 2, !"Debug Info Version", i32 3}160 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)161 !7 = !DISubroutineType(types: !2)162 !8 = !{!9}163 !9 = !DILocalVariable(name: "b", scope: !6, file: !1, line: 1, type: !10)164 !10 = !DIBasicType(name: "ty16", size: 16, encoding: DW_ATE_unsigned)165 !11 = !DILocation(line: 1, column: 1, scope: !6)166 )");167 168 DebugValueDrop *P = new DebugValueDrop();169 170 DebugInfoPerPass DIBeforePass;171 DebugifyCustomPassManager Passes;172 Passes.setDebugInfoBeforePass(DIBeforePass);173 Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",174 &(Passes.getDebugInfoPerPass())));175 Passes.add(P);176 Passes.add(createCheckDebugifyModulePass(false, "", nullptr,177 DebugifyMode::OriginalDebugInfo,178 &(Passes.getDebugInfoPerPass())));179 180 testing::internal::CaptureStderr();181 Passes.run(*M);182 183 std::string StdOut = testing::internal::GetCapturedStderr();184 185 std::string ErrorForSP = "ERROR: dropped DISubprogram of";186 std::string WarningForLoc = "WARNING: dropped DILocation of";187 std::string WarningForVars = "WARNING: drops dbg.value()/dbg.declare() for";188 std::string FinalResult = "CheckModuleDebugify (original debuginfo): FAIL";189 190 EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);191 EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);192 EXPECT_TRUE(StdOut.find(WarningForVars) != std::string::npos);193 EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);194}195 196TEST(DebugInfoDummyAnalysis, PreserveOriginalDebugInfo) {197 LLVMContext C;198 std::unique_ptr<Module> M = parseIR(C, R"(199 define i32 @g(i32 %b) !dbg !6 {200 %c = add i32 %b, 1, !dbg !11201 call void @llvm.dbg.value(metadata i32 %c, metadata !9, metadata !DIExpression()), !dbg !11202 ret i32 1, !dbg !11203 }204 declare void @llvm.dbg.value(metadata, metadata, metadata)205 206 !llvm.dbg.cu = !{!0}207 !llvm.module.flags = !{!5}208 209 !0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1, producer: "debugify", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)210 !1 = !DIFile(filename: "test.ll", directory: "/")211 !2 = !{}212 !5 = !{i32 2, !"Debug Info Version", i32 3}213 !6 = distinct !DISubprogram(name: "f", linkageName: "f", scope: null, file: !1, line: 1, type: !7, scopeLine: 1, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !8)214 !7 = !DISubroutineType(types: !2)215 !8 = !{!9}216 !9 = !DILocalVariable(name: "c", scope: !6, file: !1, line: 1, type: !10)217 !10 = !DIBasicType(name: "ty32", size: 32, encoding: DW_ATE_unsigned)218 !11 = !DILocation(line: 1, column: 1, scope: !6)219 )");220 221 DebugInfoDummyAnalysis *P = new DebugInfoDummyAnalysis();222 223 DebugInfoPerPass DIBeforePass;224 DebugifyCustomPassManager Passes;225 Passes.setDebugInfoBeforePass(DIBeforePass);226 Passes.add(createDebugifyModulePass(DebugifyMode::OriginalDebugInfo, "",227 &(Passes.getDebugInfoPerPass())));228 Passes.add(P);229 Passes.add(createCheckDebugifyModulePass(false, "", nullptr,230 DebugifyMode::OriginalDebugInfo,231 &(Passes.getDebugInfoPerPass())));232 233 testing::internal::CaptureStderr();234 Passes.run(*M);235 236 std::string StdOut = testing::internal::GetCapturedStderr();237 238 std::string ErrorForSP = "ERROR: dropped DISubprogram of";239 std::string WarningForLoc = "WARNING: dropped DILocation of";240 std::string WarningForVars = "WARNING: drops dbg.value()/dbg.declare() for";241 std::string FinalResult = "CheckModuleDebugify (original debuginfo): PASS";242 243 EXPECT_TRUE(StdOut.find(ErrorForSP) == std::string::npos);244 EXPECT_TRUE(StdOut.find(WarningForLoc) == std::string::npos);245 EXPECT_TRUE(StdOut.find(WarningForVars) == std::string::npos);246 EXPECT_TRUE(StdOut.find(FinalResult) != std::string::npos);247}248 249} // end namespace llvm250 251INITIALIZE_PASS_BEGIN(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass",252 false, false)253INITIALIZE_PASS_END(DebugInfoDrop, "debuginfodroppass", "debuginfodroppass", false,254 false)255 256INITIALIZE_PASS_BEGIN(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",257 "debuginfodummyanalysispass", false, false)258INITIALIZE_PASS_END(DebugInfoDummyAnalysis, "debuginfodummyanalysispass",259 "debuginfodummyanalysispass", false, false)260