diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h --- a/llvm/include/llvm/CodeGen/Passes.h +++ b/llvm/include/llvm/CodeGen/Passes.h @@ -473,6 +473,8 @@ /// Create IR Type Promotion pass. \see TypePromotion.cpp FunctionPass *createTypePromotionPass(); + /// Creates MIR Debugify pass. \see MachineDebugify.cpp + ModulePass *createDebugifyMachineModulePass(); } // End llvm namespace #endif diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -121,6 +121,7 @@ void initializeDataFlowSanitizerPass(PassRegistry&); void initializeDeadInstEliminationPass(PassRegistry&); void initializeDeadMachineInstructionElimPass(PassRegistry&); +void initializeDebugifyMachineModulePass(PassRegistry &); void initializeDelinearizationPass(PassRegistry&); void initializeDemandedBitsWrapperPassPass(PassRegistry&); void initializeDependenceAnalysisPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/Utils/Debugify.h b/llvm/include/llvm/Transforms/Utils/Debugify.h --- a/llvm/include/llvm/Transforms/Utils/Debugify.h +++ b/llvm/include/llvm/Transforms/Utils/Debugify.h @@ -17,6 +17,22 @@ #include "llvm/ADT/MapVector.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); +} // namespace llvm + llvm::ModulePass *createDebugifyModulePass(); llvm::FunctionPass *createDebugifyFunctionPass(); diff --git a/llvm/lib/CodeGen/CMakeLists.txt b/llvm/lib/CodeGen/CMakeLists.txt --- a/llvm/lib/CodeGen/CMakeLists.txt +++ b/llvm/lib/CodeGen/CMakeLists.txt @@ -73,6 +73,7 @@ MachineCombiner.cpp MachineCopyPropagation.cpp MachineCSE.cpp + MachineDebugify.cpp MachineDominanceFrontier.cpp MachineDominators.cpp MachineFrameInfo.cpp diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp --- a/llvm/lib/CodeGen/CodeGen.cpp +++ b/llvm/lib/CodeGen/CodeGen.cpp @@ -27,6 +27,7 @@ initializeCFIInstrInserterPass(Registry); initializeCodeGenPreparePass(Registry); initializeDeadMachineInstructionElimPass(Registry); + initializeDebugifyMachineModulePass(Registry); initializeDetectDeadLanesPass(Registry); initializeDwarfEHPreparePass(Registry); initializeEarlyIfConverterPass(Registry); diff --git a/llvm/lib/CodeGen/MachineDebugify.cpp b/llvm/lib/CodeGen/MachineDebugify.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/MachineDebugify.cpp @@ -0,0 +1,84 @@ +//===- MachineDebugify.cpp - 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 This pass attaches synthetic debug info to everything. It can be used +/// to create targeted tests for debug info preservation. +/// +/// This isn't intended to have feature parity with Debugify. +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DebugInfo.h" +#include "llvm/InitializePasses.h" +#include "llvm/Transforms/Utils/Debugify.h" + +#define DEBUG_TYPE "mir-debugify" + +using namespace llvm; + +namespace { +bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI, + DIBuilder &DIB, Function &F) { + MachineFunction &MF = MMI.getOrCreateMachineFunction(F); + + DISubprogram *SP = F.getSubprogram(); + assert(SP && "IR Debugify just created it?"); + + LLVMContext &Ctx = F.getParent()->getContext(); + unsigned NextLine = SP->getLine(); + + for (MachineBasicBlock &MBB : MF) { + for (MachineInstr &MI : MBB) { + // This will likely emit line numbers beyond the end of the imagined + // source function and into subsequent ones. We don't do anything about + // that as it doesn't really matter to the compiler where the line is in + // the imaginary source code. + MI.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP)); + } + } + + return true; +} + +/// ModulePass for attaching synthetic debug info to everything, used with the +/// legacy module pass manager. +struct DebugifyMachineModule : public ModulePass { + bool runOnModule(Module &M) override { + MachineModuleInfo &MMI = + getAnalysis().getMMI(); + return applyDebugifyMetadata( + M, M.functions(), + "ModuleDebugify: ", [&](DIBuilder &DIB, Function &F) -> bool { + return applyDebugifyMetadataToMachineFunction(MMI, DIB, F); + }); + } + + DebugifyMachineModule() : ModulePass(ID) {} + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addPreserved(); + } + + static char ID; // Pass identification. +}; +char DebugifyMachineModule::ID = 0; + +} // end anonymous namespace + +INITIALIZE_PASS_BEGIN(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) +INITIALIZE_PASS_END(DebugifyMachineModule, DEBUG_TYPE, + "Machine Debugify Module", false, false) + +ModulePass *createDebugifyMachineModulePass() { + return new DebugifyMachineModule(); +} diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -62,10 +62,11 @@ return I; return BB.getTerminator(); } +} // end anonymous namespace -bool applyDebugifyMetadata(Module &M, - iterator_range Functions, - StringRef Banner) { +bool llvm::applyDebugifyMetadata( + Module &M, iterator_range Functions, StringRef Banner, + std::function ApplyToMF) { // Skip modules with debug info. if (M.getNamedMetadata("llvm.dbg.cu")) { dbg() << Banner << "Skipping module with debug info\n"; @@ -149,6 +150,8 @@ InsertBefore); } } + if (ApplyToMF) + ApplyToMF(DIB, F); DIB.finalizeSubprogram(SP); } DIB.finalize(); @@ -173,6 +176,7 @@ return true; } +namespace { /// Return true if a mis-sized diagnostic is issued for \p DVI. bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) { // The size of a dbg.value's value operand should match the size of the @@ -315,7 +319,8 @@ /// legacy module pass manager. struct DebugifyModulePass : public ModulePass { bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + return applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyModulePass() : ModulePass(ID) {} @@ -334,7 +339,7 @@ Module &M = *F.getParent(); auto FuncIt = F.getIterator(); return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: "); + "FunctionDebugify: ", /*ApplyToMF*/ nullptr); } DebugifyFunctionPass() : FunctionPass(ID) {} @@ -409,7 +414,8 @@ } PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { - applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: "); + applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF*/ nullptr); return PreservedAnalyses::all(); } diff --git a/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/Generic/MIRDebugify/locations.mir @@ -0,0 +1,37 @@ +# RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s +# RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s +--- | + ; ModuleID = 'loc-only.ll' + source_filename = "loc-only.ll" + + ; ALL-LABEL: @test + define i32 @test(i32 %a, i32 %b) { + %add = add i32 %a, 2 + ; ALL-NEXT: %add = add i32 %a, 2, !dbg [[L1:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]] + %sub = sub i32 %add, %b + ; ALL-NEXT: %sub = sub i32 %add, %b, !dbg [[L2:![0-9]+]] + ; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]] + ; ALL-NEXT: ret i32 %sub, !dbg [[L3:![0-9]+]] + ret i32 %sub + } + +... +--- +name: test +body: | + bb.1 (%ir-block.0): + %0:_(s32) = IMPLICIT_DEF + %1:_(s32) = IMPLICIT_DEF + %2:_(s32) = G_CONSTANT i32 2 + %3:_(s32) = G_ADD %0, %2 + %4:_(s32) = G_SUB %3, %1 + ; There's no attempt to have the locations make sense as it's an imaginary + ; source file anyway. These first three coincide with IR-level information + ; and therefore use metadata references. + ; ALL: %0:_(s32) = IMPLICIT_DEF debug-location [[L1]] + ; ALL: %1:_(s32) = IMPLICIT_DEF debug-location [[L2]] + ; ALL: %2:_(s32) = G_CONSTANT i32 2, debug-location [[L3]] + ; ALL: %3:_(s32) = G_ADD %0, %2, debug-location !DILocation(line: 4, column: 1, scope: !6) + ; ALL: %4:_(s32) = G_SUB %3, %1, debug-location !DILocation(line: 5, column: 1, scope: !6) +...