Index: llvm/docs/HowToUpdateDebugInfo.rst =================================================================== --- llvm/docs/HowToUpdateDebugInfo.rst +++ llvm/docs/HowToUpdateDebugInfo.rst @@ -218,11 +218,20 @@ mutated to test debug info handling within that transformation. This is a simple way to test for proper debug info handling. -The ``debugify`` utility -^^^^^^^^^^^^^^^^^^^^^^^^ +The ``VerifyDIPreserve`` utility passes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The ``debugify`` testing utility is just a pair of passes: ``debugify`` and -``check-debugify``. +The ``VerifyDIPreserve`` testing utility is just a pair of passes: +``prepare-debuginfo-for-verify`` and ``check-debuginfo``. It works in two modes: + +* `debugify` - attaches synthetic debug info to everything and tests its + preservation (default mode) + +* `original-di-check` - collects and checks the preservation of real debug info + metadata + +The ``debugify`` mode +********************* The first applies synthetic debug information to every instruction of the module, and the second checks that this DI is still available after an @@ -244,7 +253,7 @@ ret void } -and after running ``opt -debugify``: +and after running ``opt -prepare-debuginfo-for-verify``: .. code-block:: llvm @@ -281,50 +290,68 @@ !15 = !DILocation(line: 4, column: 1, scope: !6) !16 = !DILocation(line: 5, column: 1, scope: !6) -Using ``debugify`` -^^^^^^^^^^^^^^^^^^ +The ``original-di-check`` mode +****************************** + +The ``VerifyDIPreserve`` utility can operate in the `original-di-check` mode +when it checks the preservation of the original/real Debug Info metadata in +optimizations. Before a pass it collects the metadata, and after the pass it +checks if it preserved the Debug Info metadata. It could be run as follows: + +.. code-block:: bash + + $ opt -verify-debuginfo-preserve -pass-to-test sample.ll + +Using ``VerifyDIPreserve`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ -A simple way to use ``debugify`` is as follows: +A simple way to use ``VerifyDIPreserve`` in ``debugify`` mode is as follows: .. code-block:: bash - $ opt -debugify -pass-to-test -check-debugify sample.ll + $ opt -prepare-debuginfo-for-verify -pass-to-test -check-debuginfo sample.ll This will inject synthetic DI to ``sample.ll`` run the ``pass-to-test`` and -then check for missing DI. The ``-check-debugify`` step can of course be +then check for missing DI. The ``-check-debuginfo`` step can of course be omitted in favor of more customizable FileCheck directives. -Some other ways to run debugify are available: +Some other ways to run the verifier are available: .. code-block:: bash # Same as the above example. $ opt -enable-debugify -pass-to-test sample.ll + # Run the pass in original-di-check mode. + $ opt -verify-debuginfo-preserve -pass-to-test sample.ll + # Suppresses verbose debugify output. $ opt -enable-debugify -debugify-quiet -pass-to-test sample.ll - # Prepend -debugify before and append -check-debugify -strip after - # each pass on the pipeline (similar to -verify-each). + # Prepend -prepare-debuginfo-for-verify before and append -check-debuginfo + # -strip after each pass on the pipeline (similar to -verify-each). $ opt -debugify-each -O2 sample.ll -In order for ``check-debugify`` to work, the DI must be coming from -``debugify``. Thus, modules with existing DI will be skipped. + # Check the preservation of original Debug Info after each pass. + $ opt -verify-each-debuginfo-preserve -O2 sample.ll + +In order for ``check-debuginfo`` in `debugify` mode to work, the DI must be +coming from ``debugify``. Thus, modules with existing DI will be skipped. -``debugify`` can be used to test a backend, e.g: +``debugify`` mode can be used to test a backend, e.g: .. code-block:: bash - $ opt -debugify < sample.ll | llc -o - + $ opt -prepare-debuginfo-for-verify < sample.ll | llc -o - There is also a MIR-level debugify pass that can be run before each backend pass, see: :ref:`Mutation testing for MIR-level transformations`. -``debugify`` in regression tests -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +``debugify`` mode in regression tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -The output of the ``debugify`` pass must be stable enough to use in regression +The output of the ``debugify`` must be stable enough to use in regression tests. Changes to this pass are not allowed to break existing tests. .. note:: Index: llvm/include/llvm/Transforms/Utils/Debugify.h =================================================================== --- llvm/include/llvm/Transforms/Utils/Debugify.h +++ /dev/null @@ -1,146 +0,0 @@ -//===- Debugify.h - Attach synthetic debug info to everything -------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file Interface to the `debugify` synthetic debug info testing utility. -/// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_TRANSFORM_UTILS_DEBUGIFY_H -#define LLVM_TRANSFORM_UTILS_DEBUGIFY_H - -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Bitcode/BitcodeWriterPass.h" -#include "llvm/IR/IRPrintingPasses.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/PassManager.h" - -namespace llvm { -class DIBuilder; - -/// Add synthesized debug information to a module. -/// -/// \param M The module to add debug information to. -/// \param Functions A range of functions to add debug information to. -/// \param Banner A prefix string to add to debug/error messages. -/// \param ApplyToMF A call back that will add debug information to the -/// MachineFunction for a Function. If nullptr, then the -/// MachineFunction (if any) will not be modified. -bool applyDebugifyMetadata( - Module &M, iterator_range Functions, StringRef Banner, - std::function ApplyToMF); - -/// Strip out all of the metadata and debug info inserted by debugify. If no -/// llvm.debugify module-level named metadata is present, this is a no-op. -/// Returns true if any change was made. -bool stripDebugifyMetadata(Module &M); - -} // namespace llvm - -llvm::ModulePass *createDebugifyModulePass(); -llvm::FunctionPass *createDebugifyFunctionPass(); - -struct NewPMDebugifyPass : public llvm::PassInfoMixin { - llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -/// Track how much `debugify` information has been lost. -struct DebugifyStatistics { - /// Number of missing dbg.values. - unsigned NumDbgValuesMissing = 0; - - /// Number of dbg.values expected. - unsigned NumDbgValuesExpected = 0; - - /// Number of instructions with empty debug locations. - unsigned NumDbgLocsMissing = 0; - - /// Number of instructions expected to have debug locations. - unsigned NumDbgLocsExpected = 0; - - /// Get the ratio of missing/expected dbg.values. - float getMissingValueRatio() const { - return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); - } - - /// Get the ratio of missing/expected instructions with locations. - float getEmptyLocationRatio() const { - return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); - } -}; - -/// Map pass names to a per-pass DebugifyStatistics instance. -using DebugifyStatsMap = llvm::MapVector; - -llvm::ModulePass * -createCheckDebugifyModulePass(bool Strip = false, - llvm::StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr); - -llvm::FunctionPass * -createCheckDebugifyFunctionPass(bool Strip = false, - llvm::StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr); - -struct NewPMCheckDebugifyPass - : public llvm::PassInfoMixin { - llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); -}; - -namespace llvm { -/// DebugifyCustomPassManager wraps each pass with the debugify passes if -/// needed. -/// NOTE: We support legacy custom pass manager only. -/// TODO: Add New PM support for custom pass manager. -class DebugifyCustomPassManager : public legacy::PassManager { - DebugifyStatsMap DIStatsMap; - bool EnableDebugifyEach = false; - -public: - using super = legacy::PassManager; - - void add(Pass *P) override { - // Wrap each pass with (-check)-debugify passes if requested, making - // exceptions for passes which shouldn't see -debugify instrumentation. - bool WrapWithDebugify = EnableDebugifyEach && !P->getAsImmutablePass() && - !isIRPrintingPass(P) && !isBitcodeWriterPass(P); - if (!WrapWithDebugify) { - super::add(P); - return; - } - - // Apply -debugify/-check-debugify before/after each pass and collect - // debug info loss statistics. - PassKind Kind = P->getPassKind(); - StringRef Name = P->getPassName(); - - // TODO: Implement Debugify for LoopPass. - switch (Kind) { - case PT_Function: - super::add(createDebugifyFunctionPass()); - super::add(P); - super::add(createCheckDebugifyFunctionPass(true, Name, &DIStatsMap)); - break; - case PT_Module: - super::add(createDebugifyModulePass()); - super::add(P); - super::add(createCheckDebugifyModulePass(true, Name, &DIStatsMap)); - break; - default: - super::add(P); - break; - } - } - - void enableDebugifyEach() { EnableDebugifyEach = true; } - - const DebugifyStatsMap &getDebugifyStatsMap() const { return DIStatsMap; } -}; -} // namespace llvm - -#endif // LLVM_TRANSFORM_UTILS_DEBUGIFY_H Index: llvm/include/llvm/Transforms/Utils/VerifyDIPreserve.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Utils/VerifyDIPreserve.h @@ -0,0 +1,222 @@ +//===- VerifyDIPreserve.h - Check debug info preservation -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file Interface to the debug info testing utility pass. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORM_UTILS_VDIP_H +#define LLVM_TRANSFORM_UTILS_VDIP_H + +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Bitcode/BitcodeWriterPass.h" +#include "llvm/IR/IRPrintingPasses.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/PassManager.h" + +using DebugFnMap = llvm::DenseMap; +using DebugInstMap = llvm::DenseMap; + +/// Used to track the Debug Info Metadata information. +struct DebugInfoPerPass { + // This maps a function name to its associated DISubprogram. + DebugFnMap DIFunctions; + // This maps an instruction and the info about whether it has !dbg attached. + DebugInstMap DILocations; +}; + +/// Map pass names to a per-pass DebugInfoPerPass instance. +using DebugInfoPerPassMap = llvm::MapVector; + +namespace llvm { +class DIBuilder; + +/// Add synthesized debug information to a module. +/// +/// \param M The module to add debug information to. +/// \param Functions A range of functions to add debug information to. +/// \param Banner A prefix string to add to debug/error messages. +/// \param ApplyToMF A call back that will add debug information to the +/// MachineFunction for a Function. If nullptr, then the +/// MachineFunction (if any) will not be modified. +bool applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF); + +/// Strip out all of the metadata and debug info inserted by debugify. If no +/// llvm.debugify module-level named metadata is present, this is a no-op. +/// Returns true if any change was made. +bool stripDebugifyMetadata(Module &M); + +/// Collect original debug information before a pass. +/// +/// \param M The module to collect debug information from. +/// \param Functions A range of functions to collect debug information from. +/// \param DIPreservationMap A map to collect the DI metadata. +/// \param Banner A prefix string to add to debug/error messages. +/// \param NameOfWrappedPass A name of a pass to add to debug/error messages. +bool collectDebugInfoMetadata(Module &M, + iterator_range Functions, + DebugInfoPerPassMap &DIPreservationMap, + StringRef Banner, StringRef NameOfWrappedPass); + +/// Check original debug information after a pass. +/// +/// \param M The module to collect debug information from. +/// \param Functions A range of functions to collect debug information from. +/// \param DIPreservationMap A map used to check collected the DI metadata. +/// \param Banner A prefix string to add to debug/error messages. +/// \param NameOfWrappedPass A name of a pass to add to debug/error messages. +bool checkDebugInfoMetadata(Module &M, + iterator_range Functions, + DebugInfoPerPassMap &DIPreservationMap, + StringRef Banner, StringRef NameOfWrappedPass); +} // namespace llvm + +/// Used to check whether we track synthetic or original debug info. +enum class VerifyDIPreserveMode { + NoVerify, + Debugify, + OriginalDebugInfo +}; + +llvm::ModulePass *createPrepareDIModulePass( + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + llvm::StringRef NameOfWrappedPass = "", + DebugInfoPerPassMap *DIPreservationMap = nullptr); +llvm::FunctionPass *createPrepareDIFunctionPass( + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + llvm::StringRef NameOfWrappedPass = "", + DebugInfoPerPassMap *DIPreservationMap = nullptr); + +struct NewPMDebugifyPass : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); +}; + +/// Track how much `debugify` information has been lost. +struct DebugifyStatistics { + /// Number of missing dbg.values. + unsigned NumDbgValuesMissing = 0; + + /// Number of dbg.values expected. + unsigned NumDbgValuesExpected = 0; + + /// Number of instructions with empty debug locations. + unsigned NumDbgLocsMissing = 0; + + /// Number of instructions expected to have debug locations. + unsigned NumDbgLocsExpected = 0; + + /// Get the ratio of missing/expected dbg.values. + float getMissingValueRatio() const { + return float(NumDbgValuesMissing) / float(NumDbgLocsExpected); + } + + /// Get the ratio of missing/expected instructions with locations. + float getEmptyLocationRatio() const { + return float(NumDbgLocsMissing) / float(NumDbgLocsExpected); + } +}; + +/// Map pass names to a per-pass DebugifyStatistics instance. +using DebugifyStatsMap = llvm::MapVector; + +llvm::ModulePass *createCheckDIModulePass( + bool Strip = false, llvm::StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + DebugInfoPerPassMap *DIPreservationMap = nullptr); + +llvm::FunctionPass *createCheckDIFunctionPass( + bool Strip = false, llvm::StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + DebugInfoPerPassMap *DIPreservationMap = nullptr); + +struct NewPMCheckDebugifyPass + : public llvm::PassInfoMixin { + llvm::PreservedAnalyses run(llvm::Module &M, llvm::ModuleAnalysisManager &AM); +}; + +namespace llvm { +/// VerifyDIPreserveCustomPassManager wraps each pass with +/// the verify-di-preservation passes if needed. +/// NOTE: We support legacy custom pass manager only. +/// TODO: Add New PM support for custom pass manager. +class VerifyDIPreserveCustomPassManager : public legacy::PassManager { + DebugifyStatsMap *DIStatsMap = nullptr; + DebugInfoPerPassMap *DIPreservationMap = nullptr; + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::NoVerify; + +public: + using super = legacy::PassManager; + + void add(Pass *P) override { + // Wrap each pass with the debugify passes if requested, making + // exceptions for passes which shouldn't see the debugify instrumentation. + bool WrapWithVerifyDIPreservation = + (Mode == VerifyDIPreserveMode::Debugify || + Mode == VerifyDIPreserveMode::OriginalDebugInfo) && + !P->getAsImmutablePass() && !isIRPrintingPass(P) && + !isBitcodeWriterPass(P); + if (!WrapWithVerifyDIPreservation) { + super::add(P); + return; + } + + // Either apply the debugify before/after each pass and collect debug info + // loss statistics, or collect and check original debug info in the + // optimizations. + PassKind Kind = P->getPassKind(); + StringRef Name = P->getPassName(); + + // TODO: Implement the debug info verifiers for LoopPass. + switch (Kind) { + case PT_Function: + super::add(createPrepareDIFunctionPass(Mode, Name, DIPreservationMap)); + super::add(P); + super::add(createCheckDIFunctionPass(isDebugify(), Name, DIStatsMap, Mode, + DIPreservationMap)); + break; + case PT_Module: + super::add(createPrepareDIModulePass(Mode, Name, DIPreservationMap)); + super::add(P); + super::add(createCheckDIModulePass(isDebugify(), Name, DIStatsMap, Mode, + DIPreservationMap)); + break; + default: + super::add(P); + break; + } + } + + // Used within Debugify mode. + void setDIStatsMap(DebugifyStatsMap &StatMap) { + DIStatsMap = &StatMap; + } + // Used within original di preservation checking mode. + void setDIPreservationMap(DebugInfoPerPassMap &PerPassMap) { + DIPreservationMap = &PerPassMap; + } + void setVerifyDIPreserveMode(enum VerifyDIPreserveMode M) { + Mode = M; + } + + bool isDebugify() const { return Mode == VerifyDIPreserveMode::Debugify; } + bool isOriginalDebugInfoPreserveVerify() const { + return Mode == VerifyDIPreserveMode::OriginalDebugInfo; + } + + const DebugifyStatsMap &getDebugifyStatsMap() const { return *DIStatsMap; } + DebugInfoPerPassMap &getDebugInfoPerPassMap() { return *DIPreservationMap; } +}; +} // namespace llvm + +#endif // LLVM_TRANSFORM_UTILS_VDIP_H Index: llvm/lib/CodeGen/MachineDebugify.cpp =================================================================== --- llvm/lib/CodeGen/MachineDebugify.cpp +++ llvm/lib/CodeGen/MachineDebugify.cpp @@ -25,7 +25,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/InitializePasses.h" -#include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/VerifyDIPreserve.h" #define DEBUG_TYPE "mir-debugify" Index: llvm/lib/CodeGen/MachineStripDebug.cpp =================================================================== --- llvm/lib/CodeGen/MachineStripDebug.cpp +++ llvm/lib/CodeGen/MachineStripDebug.cpp @@ -16,7 +16,7 @@ #include "llvm/IR/DebugInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" -#include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/VerifyDIPreserve.h" #define DEBUG_TYPE "mir-strip-debug" Index: llvm/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Utils/CMakeLists.txt +++ llvm/lib/Transforms/Utils/CMakeLists.txt @@ -16,7 +16,6 @@ CodeExtractor.cpp CodeMoverUtils.cpp CtorUtils.cpp - Debugify.cpp DemoteRegToStack.cpp EntryExitInstrumenter.cpp EscapeEnumerator.cpp @@ -71,6 +70,7 @@ UniqueInternalLinkageNames.cpp Utils.cpp ValueMapper.cpp + VerifyDIPreserve.cpp VNCoercion.cpp ADDITIONAL_HEADER_DIRS Index: llvm/lib/Transforms/Utils/VerifyDIPreserve.cpp =================================================================== --- llvm/lib/Transforms/Utils/VerifyDIPreserve.cpp +++ llvm/lib/Transforms/Utils/VerifyDIPreserve.cpp @@ -1,4 +1,4 @@ -//===- Debugify.cpp - Attach synthetic debug info to everything -----------===// +//===- VerifyDIPreserve.cpp - Check debug info preservation ---------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,17 @@ // //===----------------------------------------------------------------------===// /// -/// \file This pass attaches synthetic debug info to everything. It can be used +/// \file Verify Debug Info Preserve contains two modes: +/// 1) debugify - works with synthetic debug info +/// 2) original-di-check - works with original debug info +/// The debugify attaches synthetic debug info to everything. It can be used /// to create targeted tests for debug info preservation. +/// The original-di-check mode checks original debug info (-g +/// generated) preservation. /// //===----------------------------------------------------------------------===// -#include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/VerifyDIPreserve.h" #include "llvm/ADT/BitVector.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DIBuilder.h" @@ -23,6 +28,8 @@ #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" +#define DEBUG_TYPE "verify-di-preserve" + using namespace llvm; namespace { @@ -245,6 +252,202 @@ return Changed; } +bool llvm::collectDebugInfoMetadata(Module &M, + iterator_range 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 (BasicBlock &BB : F) { + // Collect debug locations (!dbg). + // TODO: Collect dbg.values. + for (Instruction &I : BB) { + // Skip PHIs. + if (isa(I)) + continue; + + // Skip debug instructions. + if (isa(&I)) + continue; + + LLVM_DEBUG(dbgs() << " Collecting info for inst: " << I << '\n'); + + 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 Preserved = true; + for (const auto &F : DIFunctionsAfter) { + if (F.second) + continue; + auto SPIt = DIFunctionsBefore.find(F.first); + if (SPIt == DIFunctionsBefore.end()) { + 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 attacched before the pass, consider it as + // a debug info bug. + 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, + StringRef NameOfWrappedPass, + StringRef FileNameFromCU) { + bool Preserved = true; + for (const auto &L : DILocsAfter) { + if (L.second) + continue; + auto Instr = L.first; + auto FnName = Instr->getFunction()->getName(); + auto BB = Instr->getParent(); + auto BBName = BB->hasName() ? BB->getName() : "no-name"; + + auto InstrIt = DILocsBefore.find(Instr); + if (InstrIt == DILocsBefore.end()) { + dbg() << "WARNING: " << NameOfWrappedPass + << " did not generate DILocation for " << *Instr + << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; + Preserved = false; + } else { + auto hadLoc = InstrIt->second; + if (!hadLoc) + continue; + // If the instr had the !dbg attacched before the pass, consider it as + // a debug info issue. + dbg() << "WARNING: " << NameOfWrappedPass << " dropped DILocation of " + << *Instr << " (BB: " << BBName << ", Fn: " << FnName + << ", File: " << FileNameFromCU << ")\n"; + Preserved = false; + } + } + + return Preserved; +} + +bool llvm::checkDebugInfoMetadata(Module &M, + iterator_range Functions, + DebugInfoPerPassMap &DIPreservationMap, + StringRef Banner, + StringRef NameOfWrappedPass) { + 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(); + DIPreservationMap[NameOfWrappedPass].DIFunctions.insert( + {F.getName(), SP}); + if (SP) + LLVM_DEBUG(dbgs() << " Collecting subprogram: " << *SP << '\n'); + + for (BasicBlock &BB : F) { + // Collect debug locations (!dbg attachments). + // TODO: Collect dbg.values. + for (Instruction &I : BB) { + // Skip PHIs. + if (isa(I)) + continue; + + // Skip debug instructions. + if (isa(&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(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; + + bool Result = checkFunctions(DIFunctionsBefore, DIFunctionsAfter, + NameOfWrappedPass, FileNameFromCU) && + checkInstructions(DILocsBefore, DILocsAfter, NameOfWrappedPass, + FileNameFromCU); + + StringRef ResultBanner = NameOfWrappedPass != "" ? NameOfWrappedPass : Banner; + 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) { @@ -381,53 +584,95 @@ } /// ModulePass for attaching synthetic debug info to everything, used with the -/// legacy module pass manager. -struct DebugifyModulePass : public ModulePass { +/// legacy module pass manager, if the mode is set to Debugify. If the mode is +/// set to OriginalDebugInfo, it just collects debug info before a pass. +struct PrepareDIModulePass : public ModulePass { bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), - "ModuleDebugify: ", /*ApplyToMF*/ nullptr); + if (Mode == VerifyDIPreserveMode::Debugify) + return applyDebugifyMetadata( + M, M.functions(), "ModuleVerifyDIPreserve: ", /*ApplyToMF*/ nullptr); + return collectDebugInfoMetadata( + M, M.functions(), *DIPreservationMap, + "ModuleVerifyDIPreserve(original-di-check): ", NameOfWrappedPass); } - DebugifyModulePass() : ModulePass(ID) {} + PrepareDIModulePass( + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + 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 VerifyDIPreserveMode Mode; }; /// FunctionPass for attaching synthetic debug info to instructions within a -/// single function, used with the legacy module pass manager. -struct DebugifyFunctionPass : public FunctionPass { +/// single function, used with the legacy module pass manager, if the mode is +/// set to Debugify. If the mode is set to OriginalDebugInfo, it just +/// collects debug info before a pass. +struct PrepareDIFunctionPass : public FunctionPass { bool runOnFunction(Function &F) override { Module &M = *F.getParent(); auto FuncIt = F.getIterator(); - return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: ", /*ApplyToMF*/ nullptr); + if (Mode == VerifyDIPreserveMode::Debugify) + return applyDebugifyMetadata( + M, make_range(FuncIt, std::next(FuncIt)), + "FunctionVerifyDIPreserve: ", /*ApplyToMF*/ nullptr); + return collectDebugInfoMetadata( + M, M.functions(), *DIPreservationMap, + "FunctionVerifyDIPreserve(original-di-check): ", NameOfWrappedPass); } - DebugifyFunctionPass() : FunctionPass(ID) {} + PrepareDIFunctionPass( + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + 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 VerifyDIPreserveMode Mode; }; -/// ModulePass for checking debug info inserted by -debugify, used with the -/// legacy module pass manager. -struct CheckDebugifyModulePass : public ModulePass { +/// ModulePass for checking debug info inserted by debugify, used with the +/// legacy module pass manager. In the case of the di-preservation-verify, +/// it just checks if a pass preserved the debug info. +struct CheckDIModulePass : public ModulePass { bool runOnModule(Module &M) override { - return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, - "CheckModuleDebugify", Strip, StatsMap); + if (Mode == VerifyDIPreserveMode::Debugify) + return checkDebugifyMetadata(M, M.functions(), NameOfWrappedPass, + "CheckModuleVerifyDIPreserve", Strip, + StatsMap); + return checkDebugInfoMetadata( + M, M.functions(), *DIPreservationMap, + "CheckModuleVerifyDIPreserve(original-di-check): ", NameOfWrappedPass); } - CheckDebugifyModulePass(bool Strip = false, StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : ModulePass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} + CheckDIModulePass( + bool Strip = false, StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + DebugInfoPerPassMap *DIPreservationMap = nullptr) + : ModulePass(ID), NameOfWrappedPass(NameOfWrappedPass), + StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), + Strip(Strip) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -436,27 +681,39 @@ static char ID; // Pass identification. private: - bool Strip; StringRef NameOfWrappedPass; DebugifyStatsMap *StatsMap; + DebugInfoPerPassMap *DIPreservationMap; + enum VerifyDIPreserveMode Mode; + bool Strip; }; -/// FunctionPass for checking debug info inserted by -debugify-function, used -/// with the legacy module pass manager. -struct CheckDebugifyFunctionPass : public FunctionPass { +/// FunctionPass for checking debug info inserted by debugify-function, used +/// with the legacy module pass manager. In the case of the +/// di-preservation-verify, it just checks if a pass preserved the debug +/// info. +struct CheckDIFunctionPass : 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 == VerifyDIPreserveMode::Debugify) + return checkDebugifyMetadata( + M, make_range(FuncIt, std::next(FuncIt)), NameOfWrappedPass, + "CheckFunctionVerifyDIPreserve", Strip, StatsMap); + return checkDebugInfoMetadata( + M, make_range(FuncIt, std::next(FuncIt)), *DIPreservationMap, + "CheckFunctionVerifyDIPreserve(original-di-check): ", + NameOfWrappedPass); } - CheckDebugifyFunctionPass(bool Strip = false, - StringRef NameOfWrappedPass = "", - DebugifyStatsMap *StatsMap = nullptr) - : FunctionPass(ID), Strip(Strip), NameOfWrappedPass(NameOfWrappedPass), - StatsMap(StatsMap) {} + CheckDIFunctionPass( + bool Strip = false, StringRef NameOfWrappedPass = "", + DebugifyStatsMap *StatsMap = nullptr, + enum VerifyDIPreserveMode Mode = VerifyDIPreserveMode::Debugify, + DebugInfoPerPassMap *DIPreservationMap = nullptr) + : FunctionPass(ID), NameOfWrappedPass(NameOfWrappedPass), + StatsMap(StatsMap), DIPreservationMap(DIPreservationMap), Mode(Mode), + Strip(Strip) {} void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesAll(); @@ -465,56 +722,86 @@ static char ID; // Pass identification. private: - bool Strip; StringRef NameOfWrappedPass; DebugifyStatsMap *StatsMap; + DebugInfoPerPassMap *DIPreservationMap; + enum VerifyDIPreserveMode Mode; + bool Strip; }; } // end anonymous namespace -ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); } +ModulePass *createPrepareDIModulePass(enum VerifyDIPreserveMode Mode, + llvm::StringRef NameOfWrappedPass, + DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == VerifyDIPreserveMode::Debugify) + return new PrepareDIModulePass(); + assert(Mode == VerifyDIPreserveMode::OriginalDebugInfo && + "Must be original-di-check mode"); + return new PrepareDIModulePass(Mode, NameOfWrappedPass, DIPreservationMap); +} -FunctionPass *createDebugifyFunctionPass() { - return new DebugifyFunctionPass(); +FunctionPass * +createPrepareDIFunctionPass(enum VerifyDIPreserveMode Mode, + llvm::StringRef NameOfWrappedPass, + DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == VerifyDIPreserveMode::Debugify) + return new PrepareDIFunctionPass(); + assert(Mode == VerifyDIPreserveMode::OriginalDebugInfo && + "Must be original-di-check mode"); + return new PrepareDIFunctionPass(Mode, NameOfWrappedPass, DIPreservationMap); } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { applyDebugifyMetadata(M, M.functions(), - "ModuleDebugify: ", /*ApplyToMF*/ nullptr); + "ModuleVerifyDIPreserve: ", /*ApplyToMF*/ nullptr); return PreservedAnalyses::all(); } -ModulePass *createCheckDebugifyModulePass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); +ModulePass *createCheckDIModulePass(bool Strip, StringRef NameOfWrappedPass, + DebugifyStatsMap *StatsMap, + enum VerifyDIPreserveMode Mode, + DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == VerifyDIPreserveMode::Debugify) + return new CheckDIModulePass(Strip, NameOfWrappedPass, StatsMap); + assert(Mode == VerifyDIPreserveMode::OriginalDebugInfo && + "Must be original-di-check mode"); + return new CheckDIModulePass(false, NameOfWrappedPass, nullptr, Mode, + DIPreservationMap); } -FunctionPass *createCheckDebugifyFunctionPass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { - return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); +FunctionPass *createCheckDIFunctionPass( + bool Strip, StringRef NameOfWrappedPass, DebugifyStatsMap *StatsMap, + enum VerifyDIPreserveMode Mode, DebugInfoPerPassMap *DIPreservationMap) { + if (Mode == VerifyDIPreserveMode::Debugify) + return new CheckDIFunctionPass(Strip, NameOfWrappedPass, StatsMap); + assert(Mode == VerifyDIPreserveMode::OriginalDebugInfo && + "Must be original-di-check mode"); + return new CheckDIFunctionPass(false, NameOfWrappedPass, nullptr, Mode, + DIPreservationMap); } PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - checkDebugifyMetadata(M, M.functions(), "", "CheckModuleDebugify", false, - nullptr); + checkDebugifyMetadata(M, M.functions(), "", "CheckModuleVerifyDIPreserve", + false, nullptr); return PreservedAnalyses::all(); } -char DebugifyModulePass::ID = 0; -static RegisterPass DM("debugify", - "Attach debug info to everything"); +char PrepareDIModulePass::ID = 0; +static RegisterPass + DM("prepare-debuginfo-for-verify", "Prepare debug info for the analysis"); -char CheckDebugifyModulePass::ID = 0; -static RegisterPass - CDM("check-debugify", "Check debug info from -debugify"); +char CheckDIModulePass::ID = 0; +static RegisterPass + CDM("check-debuginfo", "Check debug info from -prepare-debuginfo"); -char DebugifyFunctionPass::ID = 0; -static RegisterPass DF("debugify-function", - "Attach debug info to a function"); +char PrepareDIFunctionPass::ID = 0; +static RegisterPass + DF("prepare-debuginfo-for-verify-function", + "Prepare a function debug info for the analysis"); -char CheckDebugifyFunctionPass::ID = 0; -static RegisterPass - CDF("check-debugify-function", "Check debug info from -debugify-function"); +char CheckDIFunctionPass::ID = 0; +static RegisterPass + CDF("check-debuginfo-function", + "Check debug info from -prepare-debuginfo-function"); Index: llvm/test/CodeGen/X86/block-placement.ll =================================================================== --- llvm/test/CodeGen/X86/block-placement.ll +++ llvm/test/CodeGen/X86/block-placement.ll @@ -1,5 +1,5 @@ ; RUN: llc -mtriple=i686-linux -pre-RA-sched=source < %s | FileCheck %s -; RUN: opt -disable-output -debugify < %s +; RUN: opt -disable-output -prepare-debuginfo-for-verify < %s declare void @error(i32 %i, i32 %a, i32 %b) Index: llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll =================================================================== --- llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll +++ llvm/test/CodeGen/X86/deopt-intrinsic-cconv.ll @@ -1,6 +1,6 @@ ; RUN: llc < %s | FileCheck %s ; RUN: llc -debug-only=stackmaps < %s 2>&1 | FileCheck --check-prefix=STACKMAPS %s -; RUN: opt -disable-output -debugify < %s +; RUN: opt -disable-output -prepare-debuginfo-for-verify < %s ; REQUIRES: asserts target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128" Index: llvm/test/DebugInfo/X86/bitcast-di.ll =================================================================== --- llvm/test/DebugInfo/X86/bitcast-di.ll +++ llvm/test/DebugInfo/X86/bitcast-di.ll @@ -1,4 +1,4 @@ -; RUN: opt -mtriple=x86_64-unknown-linux-gnu -S -debugify -codegenprepare < %s | FileCheck %s +; RUN: opt -mtriple=x86_64-unknown-linux-gnu -S -prepare-debuginfo-for-verify -codegenprepare < %s | FileCheck %s target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128" target triple = "x86_64-unknown-linux-gnu" Index: llvm/test/DebugInfo/debugify-bogus-dbg-value.ll =================================================================== --- llvm/test/DebugInfo/debugify-bogus-dbg-value.ll +++ llvm/test/DebugInfo/debugify-bogus-dbg-value.ll @@ -1,4 +1,4 @@ -; RUN: opt -check-debugify < %s 2>&1 | FileCheck %s +; RUN: opt -check-debuginfo < %s 2>&1 | FileCheck %s define <2 x i64> @test-fun(<2 x i64> %A) !dbg !6 { %and = and <2 x i64> %A, , !dbg !14 @@ -22,7 +22,7 @@ ret <2 x i64> %and, !dbg !16 } -; CHECK: CheckModuleDebugify: FAIL +; CHECK: CheckModuleVerifyDIPreserve: FAIL ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.value(metadata, metadata, metadata) #0 Index: llvm/test/DebugInfo/debugify-each.ll =================================================================== --- llvm/test/DebugInfo/debugify-each.ll +++ llvm/test/DebugInfo/debugify-each.ll @@ -38,10 +38,10 @@ ; Verify that the module & function (check-)debugify passes run at least twice. -; MODULE-PASS: CheckModuleDebugify [{{.*}}] -; MODULE-PASS: CheckModuleDebugify [{{.*}}] +; MODULE-PASS: CheckModuleVerifyDIPreserve [{{.*}}] +; MODULE-PASS: CheckModuleVerifyDIPreserve [{{.*}}] -; FUNCTION-PASS: CheckFunctionDebugify [{{.*}}] -; FUNCTION-PASS: CheckFunctionDebugify [{{.*}}] -; FUNCTION-PASS: CheckFunctionDebugify [{{.*}}] -; FUNCTION-PASS: CheckFunctionDebugify [{{.*}}] +; FUNCTION-PASS: CheckFunctionVerifyDIPreserve [{{.*}}] +; FUNCTION-PASS: CheckFunctionVerifyDIPreserve [{{.*}}] +; FUNCTION-PASS: CheckFunctionVerifyDIPreserve [{{.*}}] +; FUNCTION-PASS: CheckFunctionVerifyDIPreserve [{{.*}}] Index: llvm/test/DebugInfo/debugify-report-missing-locs-only.ll =================================================================== --- llvm/test/DebugInfo/debugify-report-missing-locs-only.ll +++ llvm/test/DebugInfo/debugify-report-missing-locs-only.ll @@ -1,4 +1,4 @@ -; RUN: opt -check-debugify < %s -S -o - 2>&1 | FileCheck %s -implicit-check-not "WARNING: Instruction with empty DebugLoc in function bar" +; RUN: opt -check-debuginfo < %s -S -o - 2>&1 | FileCheck %s -implicit-check-not "WARNING: Instruction with empty DebugLoc in function bar" ; CHECK: WARNING: Instruction with empty DebugLoc in function foo -- ret void define void @foo() !dbg !6 { Index: llvm/test/DebugInfo/debugify.ll =================================================================== --- llvm/test/DebugInfo/debugify.ll +++ llvm/test/DebugInfo/debugify.ll @@ -1,19 +1,19 @@ -; RUN: opt -debugify -S -o - < %s | FileCheck %s -; RUN: opt -passes=debugify -S -o - < %s | FileCheck %s +; RUN: opt -prepare-debuginfo-for-verify -S -o - < %s | FileCheck %s +; RUN: opt -passes=prepare-debuginfo-for-verify -S -o - < %s | FileCheck %s -; RUN: opt -debugify -debugify -S -o - < %s 2>&1 | \ +; RUN: opt -prepare-debuginfo-for-verify -prepare-debuginfo-for-verify -S -o - < %s 2>&1 | \ ; RUN: FileCheck %s -check-prefix=CHECK-REPEAT -; RUN: opt -passes=debugify,debugify -S -o - < %s 2>&1 | \ +; RUN: opt -passes=prepare-debuginfo-for-verify,prepare-debuginfo-for-verify -S -o - < %s 2>&1 | \ ; RUN: FileCheck %s -check-prefix=CHECK-REPEAT -; RUN: opt -debugify -check-debugify -S -o - < %s | \ -; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL" -; RUN: opt -passes=debugify,check-debugify -S -o - < %s | \ -; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL" +; RUN: opt -prepare-debuginfo-for-verify -check-debuginfo -S -o - < %s | \ +; RUN: FileCheck %s -implicit-check-not="CheckModuleVerifyDIPreserve: FAIL" +; RUN: opt -passes=prepare-debuginfo-for-verify,check-debuginfo -S -o - < %s | \ +; RUN: FileCheck %s -implicit-check-not="CheckModuleVerifyDIPreserve: FAIL" ; RUN: opt -enable-debugify -passes=verify -S -o - < %s | \ -; RUN: FileCheck %s -implicit-check-not="CheckModuleDebugify: FAIL" +; RUN: FileCheck %s -implicit-check-not="CheckModuleVerifyDIPreserve: FAIL" -; RUN: opt -debugify -strip -check-debugify -S -o - < %s 2>&1 | \ +; RUN: opt -prepare-debuginfo-for-verify -strip -check-debuginfo -S -o - < %s 2>&1 | \ ; RUN: FileCheck %s -check-prefix=CHECK-WARN ; RUN: opt -enable-debugify -strip -S -o - < %s 2>&1 | \ @@ -23,7 +23,7 @@ ; Verify that debugify can be safely used with piping ; RUN: opt -enable-debugify -O1 < %s | opt -O2 -o /dev/null -; RUN: opt -debugify -mem2reg -check-debugify < %s | opt -O2 -o /dev/null +; RUN: opt -prepare-debuginfo-for-verify -mem2reg -check-debuginfo < %s | opt -O2 -o /dev/null ; CHECK-LABEL: define void @foo define void @foo() { @@ -85,7 +85,7 @@ ; CHECK-DAG: ![[NUM_VARS]] = !{i32 3} ; --- Repeat case -; CHECK-REPEAT: ModuleDebugify: Skipping module with debug info +; CHECK-REPEAT: ModuleVerifyDIPreserve: Skipping module with debug info ; --- Failure case ; CHECK-WARN: WARNING: Instruction with empty DebugLoc in function foo -- ret void @@ -97,6 +97,6 @@ ; CHECK-WARN: WARNING: Missing line 3 ; CHECK-WARN: WARNING: Missing line 4 ; CHECK-WARN: WARNING: Missing variable 1 -; CHECK-WARN: CheckModuleDebugify: PASS +; CHECK-WARN: CheckModuleVerifyDIPreserve: PASS -; PASS: CheckModuleDebugify: PASS +; PASS: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/DebugInfo/di-preserve-verify-no-dbg-info.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/di-preserve-verify-no-dbg-info.ll @@ -0,0 +1,23 @@ +; RUN: opt -verify-debuginfo-preserve -instcombine -S -o - < %s 2>&1 | FileCheck %s + +; CHECK: ModuleVerifyDIPreserve(original-di-check): Skipping module without debug info +; CHECK-NEXT: CheckModuleVerifyDIPreserve(original-di-check): Skipping module without debug info + +; ModuleID = 'no-dbg-info.c' +source_filename = "no-dbg-info.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define dso_local i32 @fn() { + %1 = call i32 (...) @fn2() + ret i32 %1 +} + +declare dso_local i32 @fn2(...) + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"wchar_size", i32 4} +!1 = !{!"clang version 11.0.0"} Index: llvm/test/DebugInfo/di-preserve-verify.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/di-preserve-verify.ll @@ -0,0 +1,73 @@ +; Check the preservation of original debug info. + +; RUN: opt -verify-debuginfo-preserve -instcombine -S -o - < %s 2>&1 | FileCheck %s + +; CHECK: CheckModuleVerifyDIPreserve(original-di-check): : PASS + +; ModuleID = 'test' +source_filename = "test.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: norecurse nounwind readnone uwtable +define dso_local i32 @fn1(i32 %0) local_unnamed_addr !dbg !12 { + call void @llvm.dbg.value(metadata i32 %0, metadata !16, metadata !DIExpression()), !dbg !17 + %2 = and i32 %0, 1, !dbg !18 + %.0 = add nsw i32 %2, %0, !dbg !20 + ret i32 %.0, !dbg !21 +} + +; Function Attrs: nounwind uwtable +define dso_local i32 @fn2() local_unnamed_addr !dbg !22 { + %1 = tail call i32 (...) @fn3(), !dbg !27 + call void @llvm.dbg.value(metadata i32 %1, metadata !26, metadata !DIExpression()), !dbg !28 + call void @llvm.dbg.value(metadata i32 %1, metadata !16, metadata !DIExpression()), !dbg !29 + %2 = and i32 %1, 1, !dbg !31 + %reass.add = shl i32 %1, 1 + %3 = or i32 %2, %reass.add + call void @llvm.dbg.value(metadata i32 %3, metadata !26, metadata !DIExpression()), !dbg !28 + ret i32 %3, !dbg !32 +} + +declare !dbg !4 dso_local i32 @fn3(...) local_unnamed_addr + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.value(metadata, metadata, metadata) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "fn3", scope: !1, file: !1, line: 1, type: !5, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, null} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 2, type: !13, scopeLine: 2, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7, !7} +!15 = !{!16} +!16 = !DILocalVariable(name: "arg1", arg: 1, scope: !12, file: !1, line: 2, type: !7) +!17 = !DILocation(line: 0, scope: !12) +!18 = !DILocation(line: 3, column: 12, scope: !19) +!19 = distinct !DILexicalBlock(scope: !12, file: !1, line: 3, column: 7) +!20 = !DILocation(line: 3, column: 7, scope: !12) +!21 = !DILocation(line: 6, column: 1, scope: !12) +!22 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 7, type: !23, scopeLine: 7, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !25) +!23 = !DISubroutineType(types: !24) +!24 = !{!7} +!25 = !{!26} +!26 = !DILocalVariable(name: "local1", scope: !22, file: !1, line: 8, type: !7) +!27 = !DILocation(line: 8, column: 16, scope: !22) +!28 = !DILocation(line: 0, scope: !22) +!29 = !DILocation(line: 0, scope: !12, inlinedAt: !30) +!30 = distinct !DILocation(line: 9, column: 13, scope: !22) +!31 = !DILocation(line: 3, column: 12, scope: !19, inlinedAt: !30) +!32 = !DILocation(line: 10, column: 3, scope: !22) Index: llvm/test/DebugInfo/orig-di-preserve-verify-each-dbginfo.ll =================================================================== --- /dev/null +++ llvm/test/DebugInfo/orig-di-preserve-verify-each-dbginfo.ll @@ -0,0 +1,96 @@ +; Check the preservation of original debug info. + +; RUN: opt -O2 -verify-each-debuginfo-preserve -S -o - < %s 2>&1 | FileCheck %s + +; CHECK: WARNING: Combine redundant instructions {{.*}} +; CHECK-NEXT: Combine redundant instructions: FAIL + +; ModuleID = 'simple.c' +source_filename = "simple.c" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: nounwind uwtable +define dso_local i32 @fn1(i32 %arg1) !dbg !12 { +entry: + %retval = alloca i32, align 4 + %arg1.addr = alloca i32, align 4 + store i32 %arg1, i32* %arg1.addr, align 4 + call void @llvm.dbg.declare(metadata i32* %arg1.addr, metadata !16, metadata !DIExpression()), !dbg !21 + %0 = load i32, i32* %arg1.addr, align 4, !dbg !22 + %rem = srem i32 %0, 2, !dbg !24 + %tobool = icmp ne i32 %rem, 0, !dbg !24 + br i1 %tobool, label %if.then, label %if.end, !dbg !25 + +if.then: ; preds = %entry + %1 = load i32, i32* %arg1.addr, align 4, !dbg !24 + %inc = add nsw i32 %1, 1, !dbg !24 + store i32 %inc, i32* %arg1.addr, align 4, !dbg !24 + store i32 %inc, i32* %retval, align 4, !dbg !24 + br label %return, !dbg !24 + +if.end: ; preds = %entry + %2 = load i32, i32* %arg1.addr, align 4, !dbg !25 + store i32 %2, i32* %retval, align 4, !dbg !25 + br label %return, !dbg !25 + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, align 4, !dbg !25 + ret i32 %3, !dbg !25 +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) + +; Function Attrs: nounwind uwtable +define dso_local i32 @fn2() !dbg !31 { +entry: + %local1 = alloca i32, align 4 + %0 = bitcast i32* %local1 to i8*, !dbg !36 + call void @llvm.dbg.declare(metadata i32* %local1, metadata !35, metadata !DIExpression()), !dbg !36 + %call = call i32 (...) @fn3(), !dbg !36 + store i32 %call, i32* %local1, align 4, !dbg !36 + %1 = load i32, i32* %local1, align 4, !dbg !36 + %call1 = call i32 @fn1(i32 %1), !dbg !36 + %2 = load i32, i32* %local1, align 4 + %add = add nsw i32 %2, %call1 + store i32 %add, i32* %local1, align 4 + %3 = load i32, i32* %local1, align 4, !dbg !36 + %4 = bitcast i32* %local1 to i8*, !dbg !36 + ret i32 %3, !dbg !36 +} + +declare !dbg !4 dso_local i32 @fn3(...) + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!8, !9, !10} +!llvm.ident = !{!11} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 11.0.0", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, retainedTypes: !3, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "simple.c", directory: "/dir") +!2 = !{} +!3 = !{!4} +!4 = !DISubprogram(name: "fn3", scope: !1, file: !1, line: 1, type: !5, spFlags: DISPFlagOptimized, retainedNodes: !2) +!5 = !DISubroutineType(types: !6) +!6 = !{!7, null} +!7 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!8 = !{i32 7, !"Dwarf Version", i32 4} +!9 = !{i32 2, !"Debug Info Version", i32 3} +!10 = !{i32 1, !"wchar_size", i32 4} +!11 = !{!"clang version 11.0.0"} +!12 = distinct !DISubprogram(name: "fn1", scope: !1, file: !1, line: 3, type: !13, scopeLine: 3, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !15) +!13 = !DISubroutineType(types: !14) +!14 = !{!7, !7} +!15 = !{!16} +!16 = !DILocalVariable(name: "arg1", arg: 1, scope: !12, file: !1, line: 3, type: !7) +!21 = !DILocation(line: 3, column: 13, scope: !12) +!22 = !DILocation(line: 4, column: 7, scope: !23) +!23 = distinct !DILexicalBlock(scope: !12, file: !1, line: 4, column: 7) +!24 = !DILocation(line: 4, column: 12, scope: !23) +!25 = !DILocation(line: 4, column: 7, scope: !12) +!31 = distinct !DISubprogram(name: "fn2", scope: !1, file: !1, line: 10, type: !32, scopeLine: 10, flags: DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !34) +!32 = !DISubroutineType(types: !33) +!33 = !{!7} +!34 = !{!35} +!35 = !DILocalVariable(name: "local1", scope: !31, file: !1, line: 11, type: !7) +!36 = !DILocation(line: 11, column: 3, scope: !31) Index: llvm/test/DebugInfo/pr37964.ll =================================================================== --- llvm/test/DebugInfo/pr37964.ll +++ llvm/test/DebugInfo/pr37964.ll @@ -1,7 +1,7 @@ ; RUN: opt -disable-output -debugify-each -gvn < %s 2>&1 | FileCheck %s ; CHECK-NOT: ERROR: Instruction with empty DebugLoc in function _Z3bazv -- {{%.*}} = phi -; CHECK: CheckFunctionDebugify [Global Value Numbering]: PASS +; CHECK: CheckFunctionVerifyDIPreserve [Global Value Numbering]: PASS @foo = dso_local local_unnamed_addr global i32 0, align 4 @x = global i8 17 Index: llvm/test/DebugInfo/salvage-cast-debug-info.ll =================================================================== --- llvm/test/DebugInfo/salvage-cast-debug-info.ll +++ llvm/test/DebugInfo/salvage-cast-debug-info.ll @@ -1,4 +1,4 @@ -; RUN: opt %s -debugify -early-cse -earlycse-debug-hash -S | FileCheck %s +; RUN: opt %s -prepare-debuginfo-for-verify -early-cse -earlycse-debug-hash -S | FileCheck %s define i32 @foo(i64 %nose, i32 %more) { ; CHECK-LABEL: @foo( ; CHECK: call void @llvm.dbg.value(metadata i64 %nose, metadata [[V1:![0-9]+]], metadata !DIExpression(DW_OP_LLVM_convert, 64, DW_ATE_unsigned, DW_OP_LLVM_convert, 32, DW_ATE_unsigned Index: llvm/test/Transforms/ArgumentPromotion/pr27568.ll =================================================================== --- llvm/test/Transforms/ArgumentPromotion/pr27568.ll +++ llvm/test/Transforms/ArgumentPromotion/pr27568.ll @@ -1,7 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes ; RUN: opt -S -argpromotion < %s | FileCheck %s ; RUN: opt -S -passes=argpromotion < %s | FileCheck %s -; RUN: opt -S -debugify -o /dev/null < %s +; RUN: opt -S -prepare-debuginfo-for-verify -o /dev/null < %s target triple = "x86_64-pc-windows-msvc" define internal void @callee(i8*) { Index: llvm/test/Transforms/BDCE/basic.ll =================================================================== --- llvm/test/Transforms/BDCE/basic.ll +++ llvm/test/Transforms/BDCE/basic.ll @@ -1,6 +1,6 @@ ; RUN: opt -S -bdce -instsimplify < %s | FileCheck %s ; RUN: opt -S -instsimplify < %s | FileCheck %s -check-prefix=CHECK-IO -; RUN: opt -S -debugify -bdce < %s | FileCheck %s -check-prefix=DEBUGIFY +; RUN: opt -S -prepare-debuginfo-for-verify -bdce < %s | FileCheck %s -check-prefix=DEBUGIFY target datalayout = "E-m:e-i64:64-n32:64" target triple = "powerpc64-unknown-linux-gnu" Index: llvm/test/Transforms/CodeExtractor/LoopExtractor_alloca.ll =================================================================== --- llvm/test/Transforms/CodeExtractor/LoopExtractor_alloca.ll +++ llvm/test/Transforms/CodeExtractor/LoopExtractor_alloca.ll @@ -1,4 +1,4 @@ -; RUN: opt -debugify -loop-extract -S < %s | FileCheck %s +; RUN: opt -prepare-debuginfo-for-verify -loop-extract -S < %s | FileCheck %s ; This tests 2 cases: ; 1. loop1 should be extracted into a function, without extracting %v1 alloca. Index: llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll +++ llvm/test/Transforms/CodeGenPrepare/AArch64/overflow-intrinsics.ll @@ -168,4 +168,4 @@ } ; Check that every instruction inserted by -codegenprepare has a debug location. -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll +++ llvm/test/Transforms/CodeGenPrepare/SPARC/overflow-intrinsics.ll @@ -120,4 +120,4 @@ } ; Check that every instruction inserted by -codegenprepare has a debug location. -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll +++ llvm/test/Transforms/CodeGenPrepare/X86/overflow-intrinsics.ll @@ -637,5 +637,5 @@ } ; Check that every instruction inserted by -codegenprepare has a debug location. -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/Transforms/CodeGenPrepare/X86/select.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/X86/select.ll +++ llvm/test/Transforms/CodeGenPrepare/X86/select.ll @@ -1,6 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -codegenprepare -S < %s | FileCheck %s -; RUN: opt -debugify -codegenprepare -S < %s | FileCheck %s -check-prefix=DEBUG +; RUN: opt -prepare-debuginfo-for-verify -codegenprepare -S < %s | FileCheck %s -check-prefix=DEBUG target triple = "x86_64-unknown-unknown" Index: llvm/test/Transforms/CodeGenPrepare/X86/vec-shift.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/X86/vec-shift.ll +++ llvm/test/Transforms/CodeGenPrepare/X86/vec-shift.ll @@ -403,4 +403,4 @@ declare <8 x i32> @llvm.fshl.v8i32(<8 x i32>, <8 x i32>, <8 x i32>) #1 ; Check that every instruction inserted by -codegenprepare has a debug location. -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/Transforms/CodeGenPrepare/X86/widen_switch.ll =================================================================== --- llvm/test/Transforms/CodeGenPrepare/X86/widen_switch.ll +++ llvm/test/Transforms/CodeGenPrepare/X86/widen_switch.ll @@ -1,7 +1,7 @@ ;; x86 is chosen to show the transform when 8-bit and 16-bit registers are available. ; RUN: opt < %s -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=X86 -; RUN: opt < %s -debugify -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=DEBUG +; RUN: opt < %s -prepare-debuginfo-for-verify -codegenprepare -S -mtriple=x86_64-unknown-unknown | FileCheck %s --check-prefix=DEBUG ; No change for x86 because 16-bit registers are part of the architecture. Index: llvm/test/Transforms/CorrelatedValuePropagation/ashr.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/ashr.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/ashr.ll @@ -4,7 +4,7 @@ ; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors ; RUN: opt < %s -enable-debugify -correlated-propagation -S 2>&1 | \ ; RUN: FileCheck %s -check-prefix=DEBUG -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS ; CHECK-LABEL: @test1 define void @test1(i32 %n) { Index: llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/overflows.ll @@ -5,7 +5,7 @@ ; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors ; RUN: opt < %s -enable-debugify -correlated-propagation -S 2>&1 | \ ; RUN: FileCheck %s -check-prefix=DEBUG -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS declare { i32, i1 } @llvm.sadd.with.overflow.i32(i32, i32) Index: llvm/test/Transforms/CorrelatedValuePropagation/sext.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/sext.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/sext.ll @@ -5,7 +5,7 @@ ; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors ; RUN: opt < %s -enable-debugify -correlated-propagation -S 2>&1 | \ ; RUN: FileCheck %s -check-prefix=DEBUG -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS declare void @use64(i64) Index: llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/udiv.ll @@ -4,7 +4,7 @@ ; https://llvm.org/docs/SourceLevelDebugging.html#fixing-errors ; RUN: opt < %s -enable-debugify -correlated-propagation -S 2>&1 | \ ; RUN: FileCheck %s -check-prefix=DEBUG -; DEBUG: CheckModuleDebugify: PASS +; DEBUG: CheckModuleVerifyDIPreserve: PASS ; CHECK-LABEL: @test_nop define void @test_nop(i32 %n) { Index: llvm/test/Transforms/DCE/basic.ll =================================================================== --- llvm/test/Transforms/DCE/basic.ll +++ llvm/test/Transforms/DCE/basic.ll @@ -1,5 +1,5 @@ -; RUN: opt -debugify -dce -S < %s | FileCheck %s -; RUN: opt -passes='module(debugify),function(dce)' -S < %s | FileCheck %s +; RUN: opt -prepare-debuginfo-for-verify -dce -S < %s | FileCheck %s +; RUN: opt -passes='module(prepare-debuginfo-for-verify),function(dce)' -S < %s | FileCheck %s ; CHECK-LABEL: @test define void @test() { Index: llvm/test/Transforms/DeadStoreElimination/MSSA/debuginfo.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MSSA/debuginfo.ll +++ llvm/test/Transforms/DeadStoreElimination/MSSA/debuginfo.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -basic-aa -dse -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -basic-aa -dse -S | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" Index: llvm/test/Transforms/DeadStoreElimination/MemDepAnalysis/debuginfo.ll =================================================================== --- llvm/test/Transforms/DeadStoreElimination/MemDepAnalysis/debuginfo.ll +++ llvm/test/Transforms/DeadStoreElimination/MemDepAnalysis/debuginfo.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -basic-aa -dse -enable-dse-memoryssa=false -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -basic-aa -dse -enable-dse-memoryssa=false -S | FileCheck %s target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128" Index: llvm/test/Transforms/GVN/PRE/phi-translate-2.ll =================================================================== --- llvm/test/Transforms/GVN/PRE/phi-translate-2.ll +++ llvm/test/Transforms/GVN/PRE/phi-translate-2.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -gvn -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -gvn -S | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" @a = common global [100 x i64] zeroinitializer, align 16 Index: llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll =================================================================== --- llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll +++ llvm/test/Transforms/GlobalOpt/shrink-global-to-bool-check-debug.ll @@ -1,4 +1,4 @@ -;RUN: opt -S -debugify -globalopt -f %s | FileCheck %s +;RUN: opt -S -prepare-debuginfo-for-verify -globalopt -f %s | FileCheck %s @foo = internal global i32 0, align 4 Index: llvm/test/Transforms/InstCombine/cast-mul-select.ll =================================================================== --- llvm/test/Transforms/InstCombine/cast-mul-select.ll +++ llvm/test/Transforms/InstCombine/cast-mul-select.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -instcombine -S | FileCheck %s -; RUN: opt -debugify -instcombine -S < %s | FileCheck %s -check-prefix DBGINFO +; RUN: opt -prepare-debuginfo-for-verify -instcombine -S < %s | FileCheck %s -check-prefix DBGINFO target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32" Index: llvm/test/Transforms/InstCombine/debuginfo-variables.ll =================================================================== --- llvm/test/Transforms/InstCombine/debuginfo-variables.ll +++ llvm/test/Transforms/InstCombine/debuginfo-variables.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -instcombine -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -instcombine -S | FileCheck %s declare void @escape32(i32) Index: llvm/test/Transforms/InstCombine/double-float-shrink-2.ll =================================================================== --- llvm/test/Transforms/InstCombine/double-float-shrink-2.ll +++ llvm/test/Transforms/InstCombine/double-float-shrink-2.ll @@ -737,4 +737,4 @@ ret float %F } -; DBG-VALID: CheckModuleDebugify: PASS +; DBG-VALID: CheckModuleVerifyDIPreserve: PASS Index: llvm/test/Transforms/InstCombine/storemerge-dbg.ll =================================================================== --- llvm/test/Transforms/InstCombine/storemerge-dbg.ll +++ llvm/test/Transforms/InstCombine/storemerge-dbg.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -instcombine -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -instcombine -S | FileCheck %s declare i32 @escape(i32) Index: llvm/test/Transforms/InstMerge/st_sink_check_debug.ll =================================================================== --- llvm/test/Transforms/InstMerge/st_sink_check_debug.ll +++ llvm/test/Transforms/InstMerge/st_sink_check_debug.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -S -debugify -mldst-motion -o - | FileCheck %s +; RUN: opt < %s -S -prepare-debuginfo-for-verify -mldst-motion -o - | FileCheck %s %struct.S = type { i32 } Index: llvm/test/Transforms/JumpThreading/branch-debug-info.ll =================================================================== --- llvm/test/Transforms/JumpThreading/branch-debug-info.ll +++ llvm/test/Transforms/JumpThreading/branch-debug-info.ll @@ -1,4 +1,4 @@ -; RUN: opt %s -debugify -jump-threading -S | FileCheck %s +; RUN: opt %s -prepare-debuginfo-for-verify -jump-threading -S | FileCheck %s ; Tests Bug 37966 define void @test0(i32 %i) { Index: llvm/test/Transforms/LCSSA/avoid-intrinsics-in-catchswitch.ll =================================================================== --- llvm/test/Transforms/LCSSA/avoid-intrinsics-in-catchswitch.ll +++ llvm/test/Transforms/LCSSA/avoid-intrinsics-in-catchswitch.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -licm -S -o /dev/null +; RUN: opt < %s -prepare-debuginfo-for-verify -licm -S -o /dev/null ; ; The following test is from https://bugs.llvm.org/show_bug.cgi?id=36238 ; This test should pass (not assert or fault). The error that originally Index: llvm/test/Transforms/LCSSA/basictest.ll =================================================================== --- llvm/test/Transforms/LCSSA/basictest.ll +++ llvm/test/Transforms/LCSSA/basictest.ll @@ -1,6 +1,6 @@ ; RUN: opt < %s -lcssa -S | FileCheck %s ; RUN: opt < %s -passes=lcssa -S | FileCheck %s -; RUN: opt < %s -debugify -lcssa -S | FileCheck -check-prefix=DEBUGIFY %s +; RUN: opt < %s -prepare-debuginfo-for-verify -lcssa -S | FileCheck -check-prefix=DEBUGIFY %s define void @lcssa(i1 %S2) { ; CHECK-LABEL: @lcssa Index: llvm/test/Transforms/LICM/sinking.ll =================================================================== --- llvm/test/Transforms/LICM/sinking.ll +++ llvm/test/Transforms/LICM/sinking.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -basic-aa -licm -S | FileCheck %s -; RUN: opt < %s -debugify -basic-aa -licm -S | FileCheck %s -check-prefix=DEBUGIFY +; RUN: opt < %s -prepare-debuginfo-for-verify -basic-aa -licm -S | FileCheck %s -check-prefix=DEBUGIFY ; RUN: opt < %s -basic-aa -licm -S -enable-mssa-loop-dependency=true -verify-memoryssa | FileCheck %s Index: llvm/test/Transforms/LoopIdiom/memcpy-debugify-remarks.ll =================================================================== --- llvm/test/Transforms/LoopIdiom/memcpy-debugify-remarks.ll +++ llvm/test/Transforms/LoopIdiom/memcpy-debugify-remarks.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -basic-aa -debugify -loop-idiom -pass-remarks=loop-idiom -pass-remarks-analysis=loop-idiom -verify -verify-each -verify-dom-info -verify-loop-info < %s -S 2>&1 | FileCheck %s +; RUN: opt -basic-aa -prepare-debuginfo-for-verify -loop-idiom -pass-remarks=loop-idiom -pass-remarks-analysis=loop-idiom -verify -verify-each -verify-dom-info -verify-loop-info < %s -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" Index: llvm/test/Transforms/LoopIdiom/memset-debugify-remarks.ll =================================================================== --- llvm/test/Transforms/LoopIdiom/memset-debugify-remarks.ll +++ llvm/test/Transforms/LoopIdiom/memset-debugify-remarks.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -basic-aa -debugify -loop-idiom -pass-remarks=loop-idiom -pass-remarks-analysis=loop-idiom -verify -verify-each -verify-dom-info -verify-loop-info < %s -S 2>&1 | FileCheck %s +; RUN: opt -basic-aa -prepare-debuginfo-for-verify -loop-idiom -pass-remarks=loop-idiom -pass-remarks-analysis=loop-idiom -verify -verify-each -verify-dom-info -verify-loop-info < %s -S 2>&1 | FileCheck %s target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-unknown-linux-gnu" Index: llvm/test/Transforms/LoopVectorize/i8-induction.ll =================================================================== --- llvm/test/Transforms/LoopVectorize/i8-induction.ll +++ llvm/test/Transforms/LoopVectorize/i8-induction.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -loop-vectorize -force-vector-interleave=1 -force-vector-width=4 -dce -instcombine -S -; RUN: opt < %s -debugify -loop-vectorize -S | FileCheck %s --check-prefix=DEBUGLOC +; RUN: opt < %s -prepare-debuginfo-for-verify -loop-vectorize -S | FileCheck %s --check-prefix=DEBUGLOC target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" Index: llvm/test/Transforms/LoopVectorize/preserve-dbg-loc-and-loop-metadata.ll =================================================================== --- llvm/test/Transforms/LoopVectorize/preserve-dbg-loc-and-loop-metadata.ll +++ llvm/test/Transforms/LoopVectorize/preserve-dbg-loc-and-loop-metadata.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -loop-vectorize -S 2>&1 | FileCheck %s -; RUN: opt < %s -debugify -loop-vectorize -S | FileCheck %s -check-prefix DEBUGLOC +; RUN: opt < %s -prepare-debuginfo-for-verify -loop-vectorize -S | FileCheck %s -check-prefix DEBUGLOC target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" ; This test makes sure we don't duplicate the loop vectorizer's metadata Index: llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll =================================================================== --- llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll +++ llvm/test/Transforms/Mem2Reg/PromoteMemToRegister.ll @@ -1,8 +1,8 @@ ; Simple sanity check testcase. Both alloca's should be eliminated. -; RUN: opt < %s -debugify -mem2reg -check-debugify -S 2>&1 | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -mem2reg -check-debuginfo -S 2>&1 | FileCheck %s ; CHECK-NOT: alloca -; CHECK: CheckModuleDebugify: PASS +; CHECK: CheckModuleVerifyDIPreserve: PASS define double @testfunc(i32 %i, double %j) { %I = alloca i32 ; [#uses=4] Index: llvm/test/Transforms/MemCpyOpt/pr37967.ll =================================================================== --- llvm/test/Transforms/MemCpyOpt/pr37967.ll +++ llvm/test/Transforms/MemCpyOpt/pr37967.ll @@ -1,6 +1,6 @@ -; RUN: opt -debugify -memcpyopt -check-debugify -S < %s 2>&1 | FileCheck %s +; RUN: opt -prepare-debuginfo-for-verify -memcpyopt -check-debuginfo -S < %s 2>&1 | FileCheck %s -; CHECK: CheckModuleDebugify: PASS +; CHECK: CheckModuleVerifyDIPreserve: PASS ; CHECK-LABEL: define {{.*}} @_Z3bar3Foo ; CHECK: [[target:%.*]] = load i8*, i8** bitcast (%struct.Foo** @a to i8**), align 8, !dbg Index: llvm/test/Transforms/SCCP/loadtest.ll =================================================================== --- llvm/test/Transforms/SCCP/loadtest.ll +++ llvm/test/Transforms/SCCP/loadtest.ll @@ -1,8 +1,8 @@ ; This test makes sure that these instructions are properly constant propagated. -; RUN: opt < %s -data-layout="e-p:32:32" -debugify -sccp -S | FileCheck %s -; RUN: opt < %s -data-layout="E-p:32:32" -debugify -sccp -S | FileCheck %s -; RUN: opt < %s -data-layout="E-p:32:32" -debugify -ipsccp -S | FileCheck %s +; RUN: opt < %s -data-layout="e-p:32:32" -prepare-debuginfo-for-verify -sccp -S | FileCheck %s +; RUN: opt < %s -data-layout="E-p:32:32" -prepare-debuginfo-for-verify -sccp -S | FileCheck %s +; RUN: opt < %s -data-layout="E-p:32:32" -prepare-debuginfo-for-verify -ipsccp -S | FileCheck %s @X = constant i32 42 ; [#uses=1] @Y = constant [2 x { i32, float }] [ { i32, float } { i32 12, float 1.000000e+00 }, { i32, float } { i32 37, float 0x3FF3B2FEC0000000 } ] ; <[2 x { i32, float }]*> [#uses=2] Index: llvm/test/Transforms/SROA/alignment.ll =================================================================== --- llvm/test/Transforms/SROA/alignment.ll +++ llvm/test/Transforms/SROA/alignment.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -sroa -S | FileCheck %s -; RUN: opt -debugify -sroa -S < %s | FileCheck %s -check-prefix DEBUGLOC +; RUN: opt -prepare-debuginfo-for-verify -sroa -S < %s | FileCheck %s -check-prefix DEBUGLOC target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" Index: llvm/test/Transforms/SimplifyCFG/debug-info-thread-phi.ll =================================================================== --- llvm/test/Transforms/SimplifyCFG/debug-info-thread-phi.ll +++ llvm/test/Transforms/SimplifyCFG/debug-info-thread-phi.ll @@ -1,4 +1,4 @@ -; RUN: opt %s -debugify -simplifycfg -S | FileCheck %s +; RUN: opt %s -prepare-debuginfo-for-verify -simplifycfg -S | FileCheck %s ; Tests Bug 37966 define void @bar(i32 %aa) { Index: llvm/test/Transforms/TailCallElim/debugloc.ll =================================================================== --- llvm/test/Transforms/TailCallElim/debugloc.ll +++ llvm/test/Transforms/TailCallElim/debugloc.ll @@ -1,4 +1,4 @@ -; RUN: opt < %s -debugify -tailcallelim -S | FileCheck %s +; RUN: opt < %s -prepare-debuginfo-for-verify -tailcallelim -S | FileCheck %s define void @foo() { entry: Index: llvm/test/Transforms/Util/Debugify/loc-only.ll =================================================================== --- llvm/test/Transforms/Util/Debugify/loc-only.ll +++ llvm/test/Transforms/Util/Debugify/loc-only.ll @@ -1,5 +1,5 @@ -; RUN: opt -debugify -S < %s | FileCheck --check-prefixes=ALL,VALUE %s -; RUN: opt -debugify -debugify-level=locations -S < %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +; RUN: opt -prepare-debuginfo-for-verify -S < %s | FileCheck --check-prefixes=ALL,VALUE %s +; RUN: opt -prepare-debuginfo-for-verify -debugify-level=locations -S < %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s ; ALL-LABEL: @test define void @test() { Index: llvm/tools/opt/NewPMDriver.cpp =================================================================== --- llvm/tools/opt/NewPMDriver.cpp +++ llvm/tools/opt/NewPMDriver.cpp @@ -36,7 +36,7 @@ #include "llvm/Transforms/IPO/ThinLTOBitcodeWriter.h" #include "llvm/Transforms/Instrumentation/AddressSanitizer.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" -#include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/VerifyDIPreserve.h" using namespace llvm; using namespace opt_tool; @@ -290,10 +290,10 @@ PB.registerPipelineParsingCallback( [](StringRef Name, ModulePassManager &MPM, ArrayRef) { - if (Name == "debugify") { + if (Name == "prepare-debuginfo-for-verify") { MPM.addPass(NewPMDebugifyPass()); return true; - } else if (Name == "check-debugify") { + } else if (Name == "check-debuginfo") { MPM.addPass(NewPMCheckDebugifyPass()); return true; } Index: llvm/tools/opt/opt.cpp =================================================================== --- llvm/tools/opt/opt.cpp +++ llvm/tools/opt/opt.cpp @@ -55,7 +55,7 @@ #include "llvm/Transforms/IPO/PassManagerBuilder.h" #include "llvm/Transforms/IPO/WholeProgramDevirt.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/Debugify.h" +#include "llvm/Transforms/Utils/VerifyDIPreserve.h" #include #include using namespace llvm; @@ -207,16 +207,26 @@ static cl::opt EnableDebugify( "enable-debugify", cl::desc( - "Start the pipeline with debugify and end it with check-debugify")); + "Start the pipeline with debugify and end it with check-debugify.")); + +static cl::opt VerifyDebugInfoPreserve( + "verify-debuginfo-preserve", + cl::desc("Start the pipeline with collecting and end it with checking of " + "debug info preservation.")); static cl::opt DebugifyEach( "debugify-each", - cl::desc( - "Start each pass with debugify and end it with check-debugify")); + cl::desc("Start each pass with debugify and end it with check-debugify.")); + +static cl::opt VerifyEachDebugInfoPreserve( + "verify-each-debuginfo-preserve", + cl::desc("Start each pass with collecting and end it with checking of " + "debug info preservation.")); static cl::opt DebugifyExport("debugify-export", - cl::desc("Export per-pass debugify statistics to this file"), + cl::desc("Export per-pass debugify (in synthetic mode) " + "statistics to this file"), cl::value_desc("filename"), cl::init("")); static cl::opt @@ -780,12 +790,22 @@ // Create a PassManager to hold and optimize the collection of passes we are // about to build. If the -debugify-each option is set, wrap each pass with - // the (-check)-debugify passes. - DebugifyCustomPassManager Passes; - if (DebugifyEach) - Passes.enableDebugifyEach(); + // the debugify passes. It also applies to -verify-each-debuginfo-preserve + // as well, which performs the analysis on original debug info. + VerifyDIPreserveCustomPassManager Passes; + DebugifyStatsMap DIStatsMap; + DebugInfoPerPassMap DIPreservationMap; + if (DebugifyEach) { + Passes.setVerifyDIPreserveMode(VerifyDIPreserveMode::Debugify); + Passes.setDIStatsMap(DIStatsMap); + } else if (VerifyEachDebugInfoPreserve) { + Passes.setVerifyDIPreserveMode(VerifyDIPreserveMode::OriginalDebugInfo); + Passes.setDIPreservationMap(DIPreservationMap); + } - bool AddOneTimeDebugifyPasses = EnableDebugify && !DebugifyEach; + bool AddOneTimeDebugifyPasses = + (EnableDebugify && !DebugifyEach) || + (VerifyDebugInfoPreserve && !VerifyEachDebugInfoPreserve); // Add an appropriate TargetLibraryInfo pass for the module's triple. TargetLibraryInfoImpl TLII(ModuleTriple); @@ -812,8 +832,17 @@ Passes.add(createTargetTransformInfoWrapperPass(TM ? TM->getTargetIRAnalysis() : TargetIRAnalysis())); - if (AddOneTimeDebugifyPasses) - Passes.add(createDebugifyModulePass()); + if (AddOneTimeDebugifyPasses) { + if (EnableDebugify) { + Passes.setDIStatsMap(DIStatsMap); + Passes.add(createPrepareDIModulePass()); + } else if (VerifyDebugInfoPreserve) { + Passes.setDIPreservationMap(DIPreservationMap); + Passes.add(createPrepareDIModulePass( + VerifyDIPreserveMode::OriginalDebugInfo, "", + &(Passes.getDebugInfoPerPassMap()))); + } + } std::unique_ptr FPasses; if (OptLevelO0 || OptLevelO1 || OptLevelO2 || OptLevelOs || OptLevelOz || @@ -957,8 +986,14 @@ if (!NoVerify && !VerifyEach) Passes.add(createVerifierPass()); - if (AddOneTimeDebugifyPasses) - Passes.add(createCheckDebugifyModulePass(false)); + if (AddOneTimeDebugifyPasses) { + if (EnableDebugify) + Passes.add(createCheckDIModulePass(false)); + else if (VerifyDebugInfoPreserve) + Passes.add(createCheckDIModulePass( + false, "", nullptr, VerifyDIPreserveMode::OriginalDebugInfo, + &(Passes.getDebugInfoPerPassMap()))); + } // In run twice mode, we want to make sure the output is bit-by-bit // equivalent if we run the pass manager again, so setup two buffers and