diff options
Diffstat (limited to 'llvm/lib/Transforms/Utils/Debugify.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/Debugify.cpp | 540 |
1 files changed, 494 insertions, 46 deletions
diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index 3e4d53c10dc9..30c3fa521d52 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -1,4 +1,4 @@ -//===- Debugify.cpp - Attach synthetic debug info to everything -----------===// +//===- Debugify.cpp - Check debug info preservation in optimizations ------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,8 +6,10 @@ // //===----------------------------------------------------------------------===// /// -/// \file This pass attaches synthetic debug info to everything. It can be used -/// to create targeted tests for debug info preservation. +/// \file In the `synthetic` mode, the `-debugify` attaches synthetic debug info +/// to everything. It can be used to create targeted tests for debug info +/// preservation. In addition, when using the `original` mode, it can check +/// original debug info preservation. The `synthetic` mode is default one. /// //===----------------------------------------------------------------------===// @@ -23,6 +25,10 @@ #include "llvm/IR/PassInstrumentation.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/JSON.h" + +#define DEBUG_TYPE "debugify" using namespace llvm; @@ -35,6 +41,8 @@ enum class Level { Locations, LocationsAndVariables }; + +// Used for the synthetic mode only. cl::opt<Level> DebugifyLevel( "debugify-level", cl::desc("Kind of debug info to add"), cl::values(clEnumValN(Level::Locations, "locations", "Locations only"), @@ -199,16 +207,33 @@ bool llvm::applyDebugifyMetadata( return true; } -static bool applyDebugify(Function &F) { +static bool +applyDebugify(Function &F, + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef NameOfWrappedPass = "") { Module &M = *F.getParent(); auto FuncIt = F.getIterator(); - return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: ", /*ApplyToMF=*/nullptr); + if (Mode == DebugifyMode::SyntheticDebugInfo) + return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), + "FunctionDebugify: ", /*ApplyToMF*/ nullptr); + assert(DIPreservationMap); + return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap, + "FunctionDebugify (original debuginfo)", + NameOfWrappedPass); } -static bool applyDebugify(Module &M) { - return applyDebugifyMetadata(M, M.functions(), - "ModuleDebugify: ", /*ApplyToMF=*/nullptr); +static bool +applyDebugify(Module &M, + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef NameOfWrappedPass = "") { + if (Mode == DebugifyMode::SyntheticDebugInfo) + return applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); + return collectDebugInfoMetadata(M, M.functions(), *DIPreservationMap, + "ModuleDebugify (original debuginfo)", + NameOfWrappedPass); } bool llvm::stripDebugifyMetadata(Module &M) { @@ -256,6 +281,355 @@ bool llvm::stripDebugifyMetadata(Module &M) { return Changed; } +bool llvm::collectDebugInfoMetadata(Module &M, + iterator_range<Module::iterator> Functions, + DebugInfoPerPassMap &DIPreservationMap, + StringRef Banner, + StringRef NameOfWrappedPass) { + LLVM_DEBUG(dbgs() << Banner << ": (before) " << NameOfWrappedPass << '\n'); + + // Clear the map with the debug info before every single pass. + DIPreservationMap.clear(); + + if (!M.getNamedMetadata("llvm.dbg.cu")) { + dbg() << Banner << ": Skipping module without debug info\n"; + return false; + } + + // Visit each instruction. + for (Function &F : Functions) { + if (isFunctionSkipped(F)) + continue; + + // Collect the DISubprogram. + auto *SP = F.getSubprogram(); + DIPreservationMap[NameOfWrappedPass].DIFunctions.insert({F.getName(), SP}); + if (SP) { + LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast<DILocalVariable>(DN)) { + DIPreservationMap[NameOfWrappedPass].DIVariables[DV] = 0; + } + } + } + + for (BasicBlock &BB : F) { + // Collect debug locations (!dbg) and debug variable intrinsics. + for (Instruction &I : BB) { + // Skip PHIs. + if (isa<PHINode>(I)) + continue; + + // Collect dbg.values and dbg.declares. + if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) { + if (!SP) + continue; + // Skip inlined variables. + if (I.getDebugLoc().getInlinedAt()) + continue; + // Skip undef values. + if (DVI->isUndef()) + continue; + + auto *Var = DVI->getVariable(); + DIPreservationMap[NameOfWrappedPass].DIVariables[Var]++; + continue; + } + + // Skip debug instructions other than dbg.value and dbg.declare. + if (isa<DbgInfoIntrinsic>(&I)) + continue; + + LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n'); + DIPreservationMap[NameOfWrappedPass].InstToDelete.insert({&I, &I}); + + const DILocation *Loc = I.getDebugLoc().get(); + bool HasLoc = Loc != nullptr; + DIPreservationMap[NameOfWrappedPass].DILocations.insert({&I, HasLoc}); + } + } + } + + return true; +} + +// This checks the preservation of original debug info attached to functions. +static bool checkFunctions(const DebugFnMap &DIFunctionsBefore, + const DebugFnMap &DIFunctionsAfter, + StringRef NameOfWrappedPass, + StringRef FileNameFromCU, bool ShouldWriteIntoJSON, + llvm::json::Array &Bugs) { + bool Preserved = true; + for (const auto &F : DIFunctionsAfter) { + if (F.second) + continue; + auto SPIt = DIFunctionsBefore.find(F.first); + if (SPIt == DIFunctionsBefore.end()) { + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, + {"name", F.first}, + {"action", "not-generate"}})); + else + dbg() << "ERROR: " << NameOfWrappedPass + << " did not generate DISubprogram for " << F.first << " from " + << FileNameFromCU << '\n'; + Preserved = false; + } else { + auto SP = SPIt->second; + if (!SP) + continue; + // If the function had the SP attached before the pass, consider it as + // a debug info bug. + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DISubprogram"}, + {"name", F.first}, + {"action", "drop"}})); + else + dbg() << "ERROR: " << NameOfWrappedPass << " dropped DISubprogram of " + << F.first << " from " << FileNameFromCU << '\n'; + Preserved = false; + } + } + + return Preserved; +} + +// This checks the preservation of the original debug info attached to +// instructions. +static bool checkInstructions(const DebugInstMap &DILocsBefore, + const DebugInstMap &DILocsAfter, + const WeakInstValueMap &InstToDelete, + StringRef NameOfWrappedPass, + StringRef FileNameFromCU, + bool ShouldWriteIntoJSON, + llvm::json::Array &Bugs) { + bool Preserved = true; + for (const auto &L : DILocsAfter) { + if (L.second) + continue; + auto Instr = L.first; + + // In order to avoid pointer reuse/recycling, skip the values that might + // have been deleted during a pass. + auto WeakInstrPtr = InstToDelete.find(Instr); + if (WeakInstrPtr != InstToDelete.end() && !WeakInstrPtr->second) + continue; + + auto FnName = Instr->getFunction()->getName(); + auto BB = Instr->getParent(); + auto BBName = BB->hasName() ? BB->getName() : "no-name"; + auto InstName = Instruction::getOpcodeName(Instr->getOpcode()); + + auto InstrIt = DILocsBefore.find(Instr); + if (InstrIt == DILocsBefore.end()) { + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, + {"fn-name", FnName.str()}, + {"bb-name", BBName.str()}, + {"instr", InstName}, + {"action", "not-generate"}})); + else + dbg() << "WARNING: " << NameOfWrappedPass + << " did not generate DILocation for " << *Instr + << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; + Preserved = false; + } else { + if (!InstrIt->second) + continue; + // If the instr had the !dbg attached before the pass, consider it as + // a debug info issue. + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object({{"metadata", "DILocation"}, + {"fn-name", FnName.str()}, + {"bb-name", BBName.str()}, + {"instr", InstName}, + {"action", "drop"}})); + else + dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of " + << *Instr << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; + Preserved = false; + } + } + + return Preserved; +} + +// This checks the preservation of original debug variable intrinsics. +static bool checkVars(const DebugVarMap &DIFunctionsBefore, + const DebugVarMap &DIFunctionsAfter, + StringRef NameOfWrappedPass, StringRef FileNameFromCU, + bool ShouldWriteIntoJSON, llvm::json::Array &Bugs) { + bool Preserved = true; + for (const auto &V : DIFunctionsBefore) { + auto VarIt = DIFunctionsAfter.find(V.first); + if (VarIt == DIFunctionsAfter.end()) + continue; + + unsigned NumOfDbgValsAfter = VarIt->second; + + if (V.second > NumOfDbgValsAfter) { + if (ShouldWriteIntoJSON) + Bugs.push_back(llvm::json::Object( + {{"metadata", "dbg-var-intrinsic"}, + {"name", V.first->getName()}, + {"fn-name", V.first->getScope()->getSubprogram()->getName()}, + {"action", "drop"}})); + else + dbg() << "WARNING: " << NameOfWrappedPass + << " drops dbg.value()/dbg.declare() for " << V.first->getName() + << " from " + << "function " << V.first->getScope()->getSubprogram()->getName() + << " (file " << FileNameFromCU << ")\n"; + Preserved = false; + } + } + + return Preserved; +} + +// Write the json data into the specifed file. +static void writeJSON(StringRef OrigDIVerifyBugsReportFilePath, + StringRef FileNameFromCU, StringRef NameOfWrappedPass, + llvm::json::Array &Bugs) { + std::error_code EC; + raw_fd_ostream OS_FILE{OrigDIVerifyBugsReportFilePath, EC, + sys::fs::OF_Append | sys::fs::OF_TextWithCRLF}; + if (EC) { + errs() << "Could not open file: " << EC.message() << ", " + << OrigDIVerifyBugsReportFilePath << '\n'; + return; + } + + OS_FILE << "{\"file\":\"" << FileNameFromCU << "\", "; + + StringRef PassName = NameOfWrappedPass != "" ? NameOfWrappedPass : "no-name"; + OS_FILE << "\"pass\":\"" << PassName << "\", "; + + llvm::json::Value BugsToPrint{std::move(Bugs)}; + OS_FILE << "\"bugs\": " << BugsToPrint; + + OS_FILE << "}\n"; +} + +bool llvm::checkDebugInfoMetadata(Module &M, + iterator_range<Module::iterator> Functions, + DebugInfoPerPassMap &DIPreservationMap, + StringRef Banner, StringRef NameOfWrappedPass, + StringRef OrigDIVerifyBugsReportFilePath) { + LLVM_DEBUG(dbgs() << Banner << ": (after) " << NameOfWrappedPass << '\n'); + + if (!M.getNamedMetadata("llvm.dbg.cu")) { + dbg() << Banner << ": Skipping module without debug info\n"; + return false; + } + + // Map the debug info holding DIs after a pass. + DebugInfoPerPassMap DIPreservationAfter; + + // Visit each instruction. + for (Function &F : Functions) { + if (isFunctionSkipped(F)) + continue; + + // TODO: Collect metadata other than DISubprograms. + // Collect the DISubprogram. + auto *SP = F.getSubprogram(); + DIPreservationAfter[NameOfWrappedPass].DIFunctions.insert( + {F.getName(), SP}); + + if (SP) { + LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); + for (const DINode *DN : SP->getRetainedNodes()) { + if (const auto *DV = dyn_cast<DILocalVariable>(DN)) { + DIPreservationAfter[NameOfWrappedPass].DIVariables[DV] = 0; + } + } + } + + for (BasicBlock &BB : F) { + // Collect debug locations (!dbg) and debug variable intrinsics. + for (Instruction &I : BB) { + // Skip PHIs. + if (isa<PHINode>(I)) + continue; + + // Collect dbg.values and dbg.declares. + if (auto *DVI = dyn_cast<DbgVariableIntrinsic>(&I)) { + if (!SP) + continue; + // Skip inlined variables. + if (I.getDebugLoc().getInlinedAt()) + continue; + // Skip undef values. + if (DVI->isUndef()) + continue; + + auto *Var = DVI->getVariable(); + DIPreservationAfter[NameOfWrappedPass].DIVariables[Var]++; + continue; + } + + // Skip debug instructions other than dbg.value and dbg.declare. + if (isa<DbgInfoIntrinsic>(&I)) + continue; + + LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n'); + + const DILocation *Loc = I.getDebugLoc().get(); + bool HasLoc = Loc != nullptr; + + DIPreservationAfter[NameOfWrappedPass].DILocations.insert({&I, HasLoc}); + } + } + } + + // TODO: The name of the module could be read better? + StringRef FileNameFromCU = + (cast<DICompileUnit>(M.getNamedMetadata("llvm.dbg.cu")->getOperand(0))) + ->getFilename(); + + auto DIFunctionsBefore = DIPreservationMap[NameOfWrappedPass].DIFunctions; + auto DIFunctionsAfter = DIPreservationAfter[NameOfWrappedPass].DIFunctions; + + auto DILocsBefore = DIPreservationMap[NameOfWrappedPass].DILocations; + auto DILocsAfter = DIPreservationAfter[NameOfWrappedPass].DILocations; + + auto InstToDelete = DIPreservationAfter[NameOfWrappedPass].InstToDelete; + + auto DIVarsBefore = DIPreservationMap[NameOfWrappedPass].DIVariables; + auto DIVarsAfter = DIPreservationAfter[NameOfWrappedPass].DIVariables; + + bool ShouldWriteIntoJSON = !OrigDIVerifyBugsReportFilePath.empty(); + llvm::json::Array Bugs; + + bool ResultForFunc = + checkFunctions(DIFunctionsBefore, DIFunctionsAfter, NameOfWrappedPass, + FileNameFromCU, ShouldWriteIntoJSON, Bugs); + bool ResultForInsts = checkInstructions( + DILocsBefore, DILocsAfter, InstToDelete, NameOfWrappedPass, + FileNameFromCU, ShouldWriteIntoJSON, Bugs); + + bool ResultForVars = checkVars(DIVarsBefore, DIVarsAfter, NameOfWrappedPass, + FileNameFromCU, ShouldWriteIntoJSON, Bugs); + + bool Result = ResultForFunc && ResultForInsts && ResultForVars; + + StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner; + if (ShouldWriteIntoJSON && !Bugs.empty()) + writeJSON(OrigDIVerifyBugsReportFilePath, FileNameFromCU, NameOfWrappedPass, + Bugs); + + if (Result) + dbg() << ResultBanner << ": PASS\n"; + else + dbg() << ResultBanner << ": FAIL\n"; + + LLVM_DEBUG(dbgs() << "\n\n"); + return Result; +} + namespace { /// Return true if a mis-sized diagnostic is issued for \p DVI. bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { @@ -264,15 +638,16 @@ bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { // // TODO: This, along with a check for non-null value operands, should be // promoted to verifier failures. - Value *V = DVI->getValue(); - if (!V) - return false; // For now, don't try to interpret anything more complicated than an empty // DIExpression. Eventually we should try to handle OP_deref and fragments. if (DVI->getExpression()->getNumElements()) return false; + Value *V = DVI->getVariableLocationOp(0); + if (!V) + return false; + Type *Ty = V->getType(); uint64_t ValueOperandSize = getAllocSizeInBits(M, Ty); Optional<uint64_t> DbgVarSize = DVI->getFragmentSizeInBits(); @@ -331,7 +706,7 @@ bool checkDebugifyMetadata(Module &M, // Find missing lines. for (Instruction &I : instructions(F)) { - if (isa<DbgValueInst>(&I) || isa<PHINode>(&I)) + if (isa<DbgValueInst>(&I)) continue; auto DL = I.getDebugLoc(); @@ -340,7 +715,7 @@ bool checkDebugifyMetadata(Module &M, continue; } - if (!DL) { + if (!isa<PHINode>(&I) && !DL) { dbg() << "WARNING: Instruction with empty DebugLoc in function "; dbg() << F.getName() << " --"; I.print(dbg()); @@ -394,43 +769,77 @@ bool checkDebugifyMetadata(Module &M, /// ModulePass for attaching synthetic debug info to everything, used with the /// legacy module pass manager. struct DebugifyModulePass : public ModulePass { - bool runOnModule(Module &M) override { return applyDebugify(M); } + bool runOnModule(Module &M) override { + return applyDebugify(M, Mode, DIPreservationMap, NameOfWrappedPass); + } - DebugifyModulePass() : ModulePass(ID) {} + DebugifyModulePass(enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + StringRef NameOfWrappedPass = "", + DebugInfoPerPassMap *DIPreservationMap = nullptr) + : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), + DIPreservationMap(DIPreservationMap), Mode(Mode) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } static char ID; // Pass identification. + +private: + StringRef NameOfWrappedPass; + DebugInfoPerPassMap *DIPreservationMap; + enum DebugifyMode Mode; }; /// FunctionPass for attaching synthetic debug info to instructions within a /// single function, used with the legacy module pass manager. struct DebugifyFunctionPass : public FunctionPass { - bool runOnFunction(Function &F) override { return applyDebugify(F); } + bool runOnFunction(Function &F) override { + return applyDebugify(F, Mode, DIPreservationMap, NameOfWrappedPass); + } - DebugifyFunctionPass() : FunctionPass(ID) {} + DebugifyFunctionPass( + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + StringRef NameOfWrappedPass = "", + DebugInfoPerPassMap *DIPreservationMap = nullptr) + : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), + DIPreservationMap(DIPreservationMap), Mode(Mode) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); } static char ID; // Pass identification. + +private: + StringRef NameOfWrappedPass; + DebugInfoPerPassMap *DIPreservationMap; + enum DebugifyMode Mode; }; /// ModulePass for checking debug info inserted by -debugify, used with the /// legacy module pass manager. struct CheckDebugifyModulePass : public ModulePass { bool runOnModule(Module &M) override { - return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, - "CheckModuleDebugify", Strip, StatsMap); + if (Mode == DebugifyMode::SyntheticDebugInfo) + return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, + "CheckModuleDebugify", Strip, StatsMap); + return checkDebugInfoMetadata( + M, M.functions(), *DIPreservationMap, + "CheckModuleDebugify (original debuginfo)", NameOfWrappedPass, + OrigDIVerifyBugsReportFilePath); } - CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} + CheckDebugifyModulePass( + bool Strip = false, StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef OrigDIVerifyBugsReportFilePath = "") + : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), + OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), + StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), + Strip(Strip) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -439,9 +848,12 @@ struct CheckDebugifyModulePass : public ModulePass { static char ID; // Pass identification. private: - bool Strip; StringRef NameOfWrappedPass; + StringRef OrigDIVerifyBugsReportFilePath; DebugifyStatsMap *StatsMap; + DebugInfoPerPassMap *DIPreservationMap; + enum DebugifyMode Mode; + bool Strip; }; /// FunctionPass for checking debug info inserted by -debugify-function, used @@ -450,16 +862,26 @@ struct CheckDebugifyFunctionPass : public FunctionPass { bool runOnFunction(Function &F) override { Module &M = *F.getParent(); auto FuncIt = F.getIterator(); - return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - NameOfWrappedPass, "CheckFunctionDebugify", - Strip, StatsMap); + if (Mode == DebugifyMode::SyntheticDebugInfo) + return checkDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), + NameOfWrappedPass, "CheckFunctionDebugify", + Strip, StatsMap); + return checkDebugInfoMetadata( + M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap, + "CheckFunctionDebugify (original debuginfo)", NameOfWrappedPass, + OrigDIVerifyBugsReportFilePath); } - CheckDebugifyFunctionPass(bool Strip = false, - StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} + CheckDebugifyFunctionPass( + bool Strip = false, StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum DebugifyMode Mode = DebugifyMode::SyntheticDebugInfo, + DebugInfoPerPassMap *DIPreservationMap = nullptr, + StringRef OrigDIVerifyBugsReportFilePath = "") + : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), + OrigDIVerifyBugsReportFilePath(OrigDIVerifyBugsReportFilePath), + StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), + Strip(Strip) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -468,9 +890,12 @@ struct CheckDebugifyFunctionPass : public FunctionPass { static char ID; // Pass identification. private: - bool Strip; StringRef NameOfWrappedPass; + StringRef OrigDIVerifyBugsReportFilePath; DebugifyStatsMap *StatsMap; + DebugInfoPerPassMap *DIPreservationMap; + enum DebugifyMode Mode; + bool Strip; }; } // end anonymous namespace @@ -496,12 +921,23 @@ void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) { } } -ModulePass *llvm::createDebugifyModulePass() { - return new DebugifyModulePass(); +ModulePass *createDebugifyModulePass(enum DebugifyMode Mode, + llvm::StringRef NameOfWrappedPass, + DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == DebugifyMode::SyntheticDebugInfo) + return new DebugifyModulePass(); + assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); + return new DebugifyModulePass(Mode, NameOfWrappedPass, DIPreservationMap); } -FunctionPass *llvm::createDebugifyFunctionPass() { - return new DebugifyFunctionPass(); +FunctionPass * +createDebugifyFunctionPass(enum DebugifyMode Mode, + llvm::StringRef NameOfWrappedPass, + DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == DebugifyMode::SyntheticDebugInfo) + return new DebugifyFunctionPass(); + assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); + return new DebugifyFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap); } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { @@ -510,16 +946,28 @@ PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { return PreservedAnalyses::all(); } -ModulePass *llvm::createCheckDebugifyModulePass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); +ModulePass *createCheckDebugifyModulePass( + bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, + enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, + StringRef OrigDIVerifyBugsReportFilePath) { + if (Mode == DebugifyMode::SyntheticDebugInfo) + return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); + assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); + return new CheckDebugifyModulePass(false, NameOfWrappedPass, nullptr, Mode, + DIPreservationMap, + OrigDIVerifyBugsReportFilePath); } -FunctionPass * -llvm::createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); +FunctionPass *createCheckDebugifyFunctionPass( + bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, + enum DebugifyMode Mode, DebugInfoPerPassMap *DIPreservationMap, + StringRef OrigDIVerifyBugsReportFilePath) { + if (Mode == DebugifyMode::SyntheticDebugInfo) + return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); + assert(Mode == DebugifyMode::OriginalDebugInfo && "Must be original mode"); + return new CheckDebugifyFunctionPass(false, NameOfWrappedPass, nullptr, Mode, + DIPreservationMap, + OrigDIVerifyBugsReportFilePath); } PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, |