/// Create IR Type Promotion pass. \see TypePromotion.cpp
FunctionPass *createTypePromotionPass();
+ /// Creates MIR Debugify pass. \see MachineDebugify.cpp
+ ModulePass *createDebugifyMachineModulePass();
} // End llvm namespace
#endif
void initializeDataFlowSanitizerPass(PassRegistry&);
void initializeDeadInstEliminationPass(PassRegistry&);
void initializeDeadMachineInstructionElimPass(PassRegistry&);
+void initializeDebugifyMachineModulePass(PassRegistry &);
void initializeDelinearizationPass(PassRegistry&);
void initializeDemandedBitsWrapperPassPass(PassRegistry&);
void initializeDependenceAnalysisPass(PassRegistry&);
#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<Module::iterator> Functions, StringRef Banner,
+ std::function<bool(DIBuilder &, Function &)> ApplyToMF);
+} // namespace llvm
+
llvm::ModulePass *createDebugifyModulePass();
llvm::FunctionPass *createDebugifyFunctionPass();
MachineCombiner.cpp
MachineCopyPropagation.cpp
MachineCSE.cpp
+ MachineDebugify.cpp
MachineDominanceFrontier.cpp
MachineDominators.cpp
MachineFrameInfo.cpp
initializeCFIInstrInserterPass(Registry);
initializeCodeGenPreparePass(Registry);
initializeDeadMachineInstructionElimPass(Registry);
+ initializeDebugifyMachineModulePass(Registry);
initializeDetectDeadLanesPass(Registry);
initializeDwarfEHPreparePass(Registry);
initializeEarlyIfConverterPass(Registry);
--- /dev/null
+//===- 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<MachineModuleInfoWrapperPass>().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<MachineModuleInfoWrapperPass>();
+ AU.addPreserved<MachineModuleInfoWrapperPass>();
+ }
+
+ 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();
+}
return I;
return BB.getTerminator();
}
+} // end anonymous namespace
-bool applyDebugifyMetadata(Module &M,
- iterator_range<Module::iterator> Functions,
- StringRef Banner) {
+bool llvm::applyDebugifyMetadata(
+ Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
+ std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) {
// Skip modules with debug info.
if (M.getNamedMetadata("llvm.dbg.cu")) {
dbg() << Banner << "Skipping module with debug info\n";
InsertBefore);
}
}
+ if (ApplyToMF)
+ ApplyToMF(DIB, F);
DIB.finalizeSubprogram(SP);
}
DIB.finalize();
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
/// 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) {}
Module &M = *F.getParent();
auto FuncIt = F.getIterator();
return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
- "FunctionDebugify: ");
+ "FunctionDebugify: ", /*ApplyToMF*/ nullptr);
}
DebugifyFunctionPass() : FunctionPass(ID) {}
}
PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
- applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
+ applyDebugifyMetadata(M, M.functions(),
+ "ModuleDebugify: ", /*ApplyToMF*/ nullptr);
return PreservedAnalyses::all();
}
--- /dev/null
+# 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)
+...