Skip to content

Commit 1adeeab

Browse files
committed
Add MIR-level debugify with only locations support for now
Summary: Re-used the IR-level debugify for the most part. The MIR-level code then adds locations to the MachineInstrs afterwards based on the LLVM-IR debug info. It's worth mentioning that the resulting locations make little sense as the range of line numbers used in a Function at the MIR level exceeds that of the equivelent IR level function. As such, MachineInstrs can appear to originate from outside the subprogram scope (and from other subprogram scopes). However, it doesn't seem worth worrying about as the source is imaginary anyway. There's a few high level goals this pass works towards: * We should be able to debugify our .ll/.mir in the lit tests without changing the checks and still pass them. I.e. Debug info should not change codegen. Combining this with a strip-debug pass should enable this. The main issue I ran into without the strip-debug pass was instructions with MMO's and checks on both the instruction and the MMO as the debug-___location is between them. I currently have a simple hack in the MIRPrinter to resolve that but the more general solution is a proper strip-debug pass. * We should be able to test that GlobalISel does not lose debug info. I recently found that the legalizer can be unexpectedly lossy in seemingly simple cases (e.g. expanding one instr into many). I have a verifier (will be posted separately) that can be integrated with passes that use the observer interface and will catch ___location loss (it does not verify correctness, just that there's zero lossage). It is a little conservative as the line-0 locations that arise from conflicts do not track the conflicting locations but it can still catch a fair bit. Depends on D77439, D77438 Reviewers: aprantl, bogner, vsk Subscribers: mgorny, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D77446
1 parent 624654f commit 1adeeab

File tree

8 files changed

+154
-6
lines changed

8 files changed

+154
-6
lines changed

llvm/include/llvm/CodeGen/Passes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,8 @@ namespace llvm {
473473
/// Create IR Type Promotion pass. \see TypePromotion.cpp
474474
FunctionPass *createTypePromotionPass();
475475

476+
/// Creates MIR Debugify pass. \see MachineDebugify.cpp
477+
ModulePass *createDebugifyMachineModulePass();
476478
} // End llvm namespace
477479

478480
#endif

llvm/include/llvm/InitializePasses.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ void initializeDSELegacyPassPass(PassRegistry&);
121121
void initializeDataFlowSanitizerPass(PassRegistry&);
122122
void initializeDeadInstEliminationPass(PassRegistry&);
123123
void initializeDeadMachineInstructionElimPass(PassRegistry&);
124+
void initializeDebugifyMachineModulePass(PassRegistry &);
124125
void initializeDelinearizationPass(PassRegistry&);
125126
void initializeDemandedBitsWrapperPassPass(PassRegistry&);
126127
void initializeDependenceAnalysisPass(PassRegistry&);

llvm/include/llvm/Transforms/Utils/Debugify.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@
1717
#include "llvm/ADT/MapVector.h"
1818
#include "llvm/IR/PassManager.h"
1919

20+
namespace llvm {
21+
class DIBuilder;
22+
23+
/// Add synthesized debug information to a module.
24+
///
25+
/// \param M The module to add debug information to.
26+
/// \param Functions A range of functions to add debug information to.
27+
/// \param Banner A prefix string to add to debug/error messages.
28+
/// \param ApplyToMF A call back that will add debug information to the
29+
/// MachineFunction for a Function. If nullptr, then the
30+
/// MachineFunction (if any) will not be modified.
31+
bool applyDebugifyMetadata(
32+
Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
33+
std::function<bool(DIBuilder &, Function &)> ApplyToMF);
34+
} // namespace llvm
35+
2036
llvm::ModulePass *createDebugifyModulePass();
2137
llvm::FunctionPass *createDebugifyFunctionPass();
2238

llvm/lib/CodeGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ add_llvm_component_library(LLVMCodeGen
7373
MachineCombiner.cpp
7474
MachineCopyPropagation.cpp
7575
MachineCSE.cpp
76+
MachineDebugify.cpp
7677
MachineDominanceFrontier.cpp
7778
MachineDominators.cpp
7879
MachineFrameInfo.cpp

llvm/lib/CodeGen/CodeGen.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
2727
initializeCFIInstrInserterPass(Registry);
2828
initializeCodeGenPreparePass(Registry);
2929
initializeDeadMachineInstructionElimPass(Registry);
30+
initializeDebugifyMachineModulePass(Registry);
3031
initializeDetectDeadLanesPass(Registry);
3132
initializeDwarfEHPreparePass(Registry);
3233
initializeEarlyIfConverterPass(Registry);

llvm/lib/CodeGen/MachineDebugify.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
//===- MachineDebugify.cpp - Attach synthetic debug info to everything ----===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
///
9+
/// \file This pass attaches synthetic debug info to everything. It can be used
10+
/// to create targeted tests for debug info preservation.
11+
///
12+
/// This isn't intended to have feature parity with Debugify.
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "llvm/CodeGen/MachineFunctionPass.h"
16+
#include "llvm/CodeGen/MachineModuleInfo.h"
17+
#include "llvm/CodeGen/Passes.h"
18+
#include "llvm/IR/DIBuilder.h"
19+
#include "llvm/IR/DebugInfo.h"
20+
#include "llvm/InitializePasses.h"
21+
#include "llvm/Transforms/Utils/Debugify.h"
22+
23+
#define DEBUG_TYPE "mir-debugify"
24+
25+
using namespace llvm;
26+
27+
namespace {
28+
bool applyDebugifyMetadataToMachineFunction(MachineModuleInfo &MMI,
29+
DIBuilder &DIB, Function &F) {
30+
MachineFunction &MF = MMI.getOrCreateMachineFunction(F);
31+
32+
DISubprogram *SP = F.getSubprogram();
33+
assert(SP && "IR Debugify just created it?");
34+
35+
LLVMContext &Ctx = F.getParent()->getContext();
36+
unsigned NextLine = SP->getLine();
37+
38+
for (MachineBasicBlock &MBB : MF) {
39+
for (MachineInstr &MI : MBB) {
40+
// This will likely emit line numbers beyond the end of the imagined
41+
// source function and into subsequent ones. We don't do anything about
42+
// that as it doesn't really matter to the compiler where the line is in
43+
// the imaginary source code.
44+
MI.setDebugLoc(DILocation::get(Ctx, NextLine++, 1, SP));
45+
}
46+
}
47+
48+
return true;
49+
}
50+
51+
/// ModulePass for attaching synthetic debug info to everything, used with the
52+
/// legacy module pass manager.
53+
struct DebugifyMachineModule : public ModulePass {
54+
bool runOnModule(Module &M) override {
55+
MachineModuleInfo &MMI =
56+
getAnalysis<MachineModuleInfoWrapperPass>().getMMI();
57+
return applyDebugifyMetadata(
58+
M, M.functions(),
59+
"ModuleDebugify: ", [&](DIBuilder &DIB, Function &F) -> bool {
60+
return applyDebugifyMetadataToMachineFunction(MMI, DIB, F);
61+
});
62+
}
63+
64+
DebugifyMachineModule() : ModulePass(ID) {}
65+
66+
void getAnalysisUsage(AnalysisUsage &AU) const override {
67+
AU.addRequired<MachineModuleInfoWrapperPass>();
68+
AU.addPreserved<MachineModuleInfoWrapperPass>();
69+
}
70+
71+
static char ID; // Pass identification.
72+
};
73+
char DebugifyMachineModule::ID = 0;
74+
75+
} // end anonymous namespace
76+
77+
INITIALIZE_PASS_BEGIN(DebugifyMachineModule, DEBUG_TYPE,
78+
"Machine Debugify Module", false, false)
79+
INITIALIZE_PASS_END(DebugifyMachineModule, DEBUG_TYPE,
80+
"Machine Debugify Module", false, false)
81+
82+
ModulePass *createDebugifyMachineModulePass() {
83+
return new DebugifyMachineModule();
84+
}

llvm/lib/Transforms/Utils/Debugify.cpp

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,11 @@ Instruction *findTerminatingInstruction(BasicBlock &BB) {
6262
return I;
6363
return BB.getTerminator();
6464
}
65+
} // end anonymous namespace
6566

66-
bool applyDebugifyMetadata(Module &M,
67-
iterator_range<Module::iterator> Functions,
68-
StringRef Banner) {
67+
bool llvm::applyDebugifyMetadata(
68+
Module &M, iterator_range<Module::iterator> Functions, StringRef Banner,
69+
std::function<bool(DIBuilder &DIB, Function &F)> ApplyToMF) {
6970
// Skip modules with debug info.
7071
if (M.getNamedMetadata("llvm.dbg.cu")) {
7172
dbg() << Banner << "Skipping module with debug info\n";
@@ -149,6 +150,8 @@ bool applyDebugifyMetadata(Module &M,
149150
InsertBefore);
150151
}
151152
}
153+
if (ApplyToMF)
154+
ApplyToMF(DIB, F);
152155
DIB.finalizeSubprogram(SP);
153156
}
154157
DIB.finalize();
@@ -173,6 +176,7 @@ bool applyDebugifyMetadata(Module &M,
173176
return true;
174177
}
175178

179+
namespace {
176180
/// Return true if a mis-sized diagnostic is issued for \p DVI.
177181
bool diagnoseMisSizedDbgValue(Module &M, DbgValueInst *DVI) {
178182
// The size of a dbg.value's value operand should match the size of the
@@ -315,7 +319,8 @@ bool checkDebugifyMetadata(Module &M,
315319
/// legacy module pass manager.
316320
struct DebugifyModulePass : public ModulePass {
317321
bool runOnModule(Module &M) override {
318-
return applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
322+
return applyDebugifyMetadata(M, M.functions(),
323+
"ModuleDebugify: ", /*ApplyToMF*/ nullptr);
319324
}
320325

321326
DebugifyModulePass() : ModulePass(ID) {}
@@ -334,7 +339,7 @@ struct DebugifyFunctionPass : public FunctionPass {
334339
Module &M = *F.getParent();
335340
auto FuncIt = F.getIterator();
336341
return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)),
337-
"FunctionDebugify: ");
342+
"FunctionDebugify: ", /*ApplyToMF*/ nullptr);
338343
}
339344

340345
DebugifyFunctionPass() : FunctionPass(ID) {}
@@ -409,7 +414,8 @@ FunctionPass *createDebugifyFunctionPass() {
409414
}
410415

411416
PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) {
412-
applyDebugifyMetadata(M, M.functions(), "ModuleDebugify: ");
417+
applyDebugifyMetadata(M, M.functions(),
418+
"ModuleDebugify: ", /*ApplyToMF*/ nullptr);
413419
return PreservedAnalyses::all();
414420
}
415421

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# RUN: llc -run-pass=mir-debugify -o - %s | FileCheck --check-prefixes=ALL,VALUE %s
2+
# RUN: llc -run-pass=mir-debugify -debugify-level=locations -o - %s | FileCheck --check-prefixes=ALL --implicit-check-not=dbg.value %s
3+
--- |
4+
; ModuleID = 'loc-only.ll'
5+
source_filename = "loc-only.ll"
6+
7+
; ALL-LABEL: @test
8+
define i32 @test(i32 %a, i32 %b) {
9+
%add = add i32 %a, 2
10+
; ALL-NEXT: %add = add i32 %a, 2, !dbg [[L1:![0-9]+]]
11+
; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %add, metadata [[add:![0-9]+]], metadata !DIExpression()), !dbg [[L1]]
12+
%sub = sub i32 %add, %b
13+
; ALL-NEXT: %sub = sub i32 %add, %b, !dbg [[L2:![0-9]+]]
14+
; VALUE-NEXT: call void @llvm.dbg.value(metadata i32 %sub, metadata [[sub:![0-9]+]], metadata !DIExpression()), !dbg [[L2]]
15+
; ALL-NEXT: ret i32 %sub, !dbg [[L3:![0-9]+]]
16+
ret i32 %sub
17+
}
18+
19+
...
20+
---
21+
name: test
22+
body: |
23+
bb.1 (%ir-block.0):
24+
%0:_(s32) = IMPLICIT_DEF
25+
%1:_(s32) = IMPLICIT_DEF
26+
%2:_(s32) = G_CONSTANT i32 2
27+
%3:_(s32) = G_ADD %0, %2
28+
%4:_(s32) = G_SUB %3, %1
29+
; There's no attempt to have the locations make sense as it's an imaginary
30+
; source file anyway. These first three coincide with IR-level information
31+
; and therefore use metadata references.
32+
; ALL: %0:_(s32) = IMPLICIT_DEF debug-___location [[L1]]
33+
; ALL: %1:_(s32) = IMPLICIT_DEF debug-___location [[L2]]
34+
; ALL: %2:_(s32) = G_CONSTANT i32 2, debug-___location [[L3]]
35+
; ALL: %3:_(s32) = G_ADD %0, %2, debug-___location !DILocation(line: 4, column: 1, scope: !6)
36+
; ALL: %4:_(s32) = G_SUB %3, %1, debug-___location !DILocation(line: 5, column: 1, scope: !6)
37+
...

0 commit comments

Comments
 (0)