Skip to content

Commit 0b39825

Browse files
authored
[RemoveDIs] Print non-intrinsic debug info in textual IR output (#79281)
This patch adds support for printing the proposed non-instruction debug info ("RemoveDIs") out to textual IR. This patch does not add any bitcode support, parsing support, or documentation. Printing of the new format is controlled by a flag added in this patch, `--write-experimental-debuginfo`, which defaults to false. The new format will be printed *iff* this flag is true, so whether we use the IR format is completely independent of whether we use non-instruction debug info during LLVM passes (which is controlled by the `--try-experimental-debuginfo-iterators` flag). Even with the flag disabled, some existing tests need to be updated, as this patch causes debug intrinsic declarations to be changed in a round trip, such that they always appear at the end of a module and have no attributes (this has no functional change on the module). The design of this new IR format was proposed previously on Discourse, and any further discussion about the design can still be contributed there: https://discourse.llvm.org/t/rfc-debuginfo-proposed-changes-to-the-textual-ir-representation-for-debug-values/73491
1 parent 3aec947 commit 0b39825

20 files changed

+272
-146
lines changed

Diff for: llvm/include/llvm/IR/Module.h

+14
Original file line numberDiff line numberDiff line change
@@ -218,11 +218,18 @@ class LLVM_EXTERNAL_VISIBILITY Module {
218218
/// \ref BasicBlock.
219219
bool IsNewDbgInfoFormat;
220220

221+
/// Used when converting this module to the new debug info format; removes all
222+
/// declarations of debug intrinsics that are replaced by non-intrinsic
223+
/// records in the new format.
224+
void removeDebugIntrinsicDeclarations();
225+
221226
/// \see BasicBlock::convertToNewDbgValues.
222227
void convertToNewDbgValues() {
223228
for (auto &F : *this) {
224229
F.convertToNewDbgValues();
225230
}
231+
// Remove the declarations of the old debug intrinsics, if any exist.
232+
removeDebugIntrinsicDeclarations();
226233
IsNewDbgInfoFormat = true;
227234
}
228235

@@ -234,6 +241,13 @@ class LLVM_EXTERNAL_VISIBILITY Module {
234241
IsNewDbgInfoFormat = false;
235242
}
236243

244+
void setIsNewDbgInfoFormat(bool UseNewFormat) {
245+
if (UseNewFormat && !IsNewDbgInfoFormat)
246+
convertToNewDbgValues();
247+
else if (!UseNewFormat && IsNewDbgInfoFormat)
248+
convertFromNewDbgValues();
249+
}
250+
237251
/// The Module constructor. Note that there is no default constructor. You
238252
/// must provide a name for the module upon construction.
239253
explicit Module(StringRef ModuleID, LLVMContext& C);

Diff for: llvm/include/llvm/IR/PrintPasses.h

+19
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,25 @@ std::string doSystemDiff(StringRef Before, StringRef After,
7878
StringRef OldLineFormat, StringRef NewLineFormat,
7979
StringRef UnchangedLineFormat);
8080

81+
/// Used to temporarily set the debug info format of a function, module, or
82+
/// basic block for the duration of this object's lifetime, after which the
83+
/// prior state will be restored.
84+
template <typename T> class ScopedDbgInfoFormatSetter {
85+
T &Obj;
86+
bool OldState;
87+
88+
public:
89+
ScopedDbgInfoFormatSetter(T &Obj, bool NewState)
90+
: Obj(Obj), OldState(Obj.IsNewDbgInfoFormat) {
91+
Obj.setIsNewDbgInfoFormat(NewState);
92+
}
93+
~ScopedDbgInfoFormatSetter() { Obj.setIsNewDbgInfoFormat(OldState); }
94+
};
95+
96+
template <typename T>
97+
ScopedDbgInfoFormatSetter(T &Obj, bool NewState)
98+
-> ScopedDbgInfoFormatSetter<T>;
99+
81100
} // namespace llvm
82101

83102
#endif // LLVM_IR_PRINTPASSES_H

Diff for: llvm/lib/IR/AsmWriter.cpp

+32-43
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ class SlotTracker : public AbstractSlotTrackerStorage {
861861
/// Add all of the metadata from an instruction.
862862
void processInstructionMetadata(const Instruction &I);
863863

864-
/// Add all of the metadata from an instruction.
864+
/// Add all of the metadata from a DbgRecord.
865865
void processDbgRecordMetadata(const DbgRecord &DPV);
866866
};
867867

@@ -1140,6 +1140,9 @@ void SlotTracker::processFunctionMetadata(const Function &F) {
11401140

11411141
void SlotTracker::processDbgRecordMetadata(const DbgRecord &DR) {
11421142
if (const DPValue *DPV = dyn_cast<const DPValue>(&DR)) {
1143+
// Process metadata used by DbgRecords; we only specifically care about the
1144+
// DILocalVariable, DILocation, and DIAssignID fields, as the Value and
1145+
// Expression fields should only be printed inline and so do not use a slot.
11431146
CreateMetadataSlot(DPV->getVariable());
11441147
if (DPV->isDbgAssign())
11451148
CreateMetadataSlot(DPV->getAssignID());
@@ -2703,6 +2706,7 @@ class AssemblyWriter {
27032706
void printDPValue(const DPValue &DPI);
27042707
void printDPLabel(const DPLabel &DPL);
27052708
void printDbgRecord(const DbgRecord &DPI);
2709+
void printDbgRecordLine(const DbgRecord &DPI);
27062710

27072711
void printUseListOrder(const Value *V, const std::vector<unsigned> &Shuffle);
27082712
void printUseLists(const Function *F);
@@ -3885,9 +3889,6 @@ void AssemblyWriter::printTypeIdentities() {
38853889

38863890
/// printFunction - Print all aspects of a function.
38873891
void AssemblyWriter::printFunction(const Function *F) {
3888-
bool ConvertBack = F->IsNewDbgInfoFormat;
3889-
if (ConvertBack)
3890-
const_cast<Function *>(F)->convertFromNewDbgValues();
38913892
if (AnnotationWriter) AnnotationWriter->emitFunctionAnnot(F, Out);
38923893

38933894
if (F->isMaterializable())
@@ -4030,8 +4031,6 @@ void AssemblyWriter::printFunction(const Function *F) {
40304031
Out << "}\n";
40314032
}
40324033

4033-
if (ConvertBack)
4034-
const_cast<Function *>(F)->convertToNewDbgValues();
40354034
Machine.purgeFunction();
40364035
}
40374036

@@ -4098,6 +4097,8 @@ void AssemblyWriter::printBasicBlock(const BasicBlock *BB) {
40984097

40994098
// Output all of the instructions in the basic block...
41004099
for (const Instruction &I : *BB) {
4100+
for (const DbgRecord &DR : I.getDbgValueRange())
4101+
printDbgRecordLine(DR);
41014102
printInstructionLine(I);
41024103
}
41034104

@@ -4611,12 +4612,10 @@ void AssemblyWriter::printDbgRecord(const DbgRecord &DR) {
46114612
llvm_unreachable("Unexpected DbgRecord kind");
46124613
}
46134614

4614-
void AssemblyWriter::printDPValue(const DPValue &Value) {
4615-
// There's no formal representation of a DPValue -- print purely as a
4616-
// debugging aid.
4617-
Out << " DPValue ";
4618-
4619-
switch (Value.getType()) {
4615+
void AssemblyWriter::printDPValue(const DPValue &DPV) {
4616+
auto WriterCtx = getContext();
4617+
Out << "#dbg_";
4618+
switch (DPV.getType()) {
46204619
case DPValue::LocationType::Value:
46214620
Out << "value";
46224621
break;
@@ -4629,35 +4628,39 @@ void AssemblyWriter::printDPValue(const DPValue &Value) {
46294628
default:
46304629
llvm_unreachable("Tried to print a DPValue with an invalid LocationType!");
46314630
}
4632-
Out << " { ";
4633-
auto WriterCtx = getContext();
4634-
WriteAsOperandInternal(Out, Value.getRawLocation(), WriterCtx, true);
4631+
Out << "(";
4632+
WriteAsOperandInternal(Out, DPV.getRawLocation(), WriterCtx, true);
46354633
Out << ", ";
4636-
WriteAsOperandInternal(Out, Value.getVariable(), WriterCtx, true);
4634+
WriteAsOperandInternal(Out, DPV.getVariable(), WriterCtx, true);
46374635
Out << ", ";
4638-
WriteAsOperandInternal(Out, Value.getExpression(), WriterCtx, true);
4636+
WriteAsOperandInternal(Out, DPV.getExpression(), WriterCtx, true);
46394637
Out << ", ";
4640-
if (Value.isDbgAssign()) {
4641-
WriteAsOperandInternal(Out, Value.getAssignID(), WriterCtx, true);
4638+
if (DPV.isDbgAssign()) {
4639+
WriteAsOperandInternal(Out, DPV.getAssignID(), WriterCtx, true);
46424640
Out << ", ";
4643-
WriteAsOperandInternal(Out, Value.getRawAddress(), WriterCtx, true);
4641+
WriteAsOperandInternal(Out, DPV.getRawAddress(), WriterCtx, true);
46444642
Out << ", ";
4645-
WriteAsOperandInternal(Out, Value.getAddressExpression(), WriterCtx, true);
4643+
WriteAsOperandInternal(Out, DPV.getAddressExpression(), WriterCtx, true);
46464644
Out << ", ";
46474645
}
4648-
WriteAsOperandInternal(Out, Value.getDebugLoc().get(), WriterCtx, true);
4649-
Out << " marker @" << Value.getMarker();
4650-
Out << " }";
4646+
WriteAsOperandInternal(Out, DPV.getDebugLoc().getAsMDNode(), WriterCtx, true);
4647+
Out << ")";
4648+
}
4649+
4650+
/// printDbgRecordLine - Print a DbgRecord with indentation and a newline
4651+
/// character.
4652+
void AssemblyWriter::printDbgRecordLine(const DbgRecord &DR) {
4653+
// Print lengthier indentation to bring out-of-line with instructions.
4654+
Out << " ";
4655+
printDbgRecord(DR);
4656+
Out << '\n';
46514657
}
46524658

46534659
void AssemblyWriter::printDPLabel(const DPLabel &Label) {
4654-
// There's no formal representation of a DPLabel -- print purely as
4655-
// a debugging aid.
4656-
Out << " DPLabel { ";
46574660
auto WriterCtx = getContext();
4661+
Out << "#dbg_label(";
46584662
WriteAsOperandInternal(Out, Label.getLabel(), WriterCtx, true);
4659-
Out << " marker @" << Label.getMarker();
4660-
Out << " }";
4663+
Out << ")";
46614664
}
46624665

46634666
void AssemblyWriter::printMetadataAttachments(
@@ -4805,19 +4808,11 @@ void BasicBlock::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW,
48054808

48064809
void Module::print(raw_ostream &ROS, AssemblyAnnotationWriter *AAW,
48074810
bool ShouldPreserveUseListOrder, bool IsForDebug) const {
4808-
// RemoveDIs: always print with debug-info in intrinsic format.
4809-
bool ConvertAfter = IsNewDbgInfoFormat;
4810-
if (IsNewDbgInfoFormat)
4811-
const_cast<Module *>(this)->convertFromNewDbgValues();
4812-
48134811
SlotTracker SlotTable(this);
48144812
formatted_raw_ostream OS(ROS);
48154813
AssemblyWriter W(OS, SlotTable, this, AAW, IsForDebug,
48164814
ShouldPreserveUseListOrder);
48174815
W.printModule(this);
4818-
4819-
if (ConvertAfter)
4820-
const_cast<Module *>(this)->convertToNewDbgValues();
48214816
}
48224817

48234818
void NamedMDNode::print(raw_ostream &ROS, bool IsForDebug) const {
@@ -4908,8 +4903,6 @@ void DPValue::print(raw_ostream &ROS, bool IsForDebug) const {
49084903

49094904
void DPMarker::print(raw_ostream &ROS, ModuleSlotTracker &MST,
49104905
bool IsForDebug) const {
4911-
// There's no formal representation of a DPMarker -- print purely as a
4912-
// debugging aid.
49134906
formatted_raw_ostream OS(ROS);
49144907
SlotTracker EmptySlotTable(static_cast<const Module *>(nullptr));
49154908
SlotTracker &SlotTable =
@@ -4931,8 +4924,6 @@ void DPLabel::print(raw_ostream &ROS, bool IsForDebug) const {
49314924

49324925
void DPValue::print(raw_ostream &ROS, ModuleSlotTracker &MST,
49334926
bool IsForDebug) const {
4934-
// There's no formal representation of a DPValue -- print purely as a
4935-
// debugging aid.
49364927
formatted_raw_ostream OS(ROS);
49374928
SlotTracker EmptySlotTable(static_cast<const Module *>(nullptr));
49384929
SlotTracker &SlotTable =
@@ -4950,8 +4941,6 @@ void DPValue::print(raw_ostream &ROS, ModuleSlotTracker &MST,
49504941

49514942
void DPLabel::print(raw_ostream &ROS, ModuleSlotTracker &MST,
49524943
bool IsForDebug) const {
4953-
// There's no formal representation of a DbgLabelRecord -- print purely as
4954-
// a debugging aid.
49554944
formatted_raw_ostream OS(ROS);
49564945
SlotTracker EmptySlotTable(static_cast<const Module *>(nullptr));
49574946
SlotTracker &SlotTable =

Diff for: llvm/lib/IR/BasicBlock.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,6 @@ DPMarker *BasicBlock::createMarker(InstListType::iterator It) {
6161
}
6262

6363
void BasicBlock::convertToNewDbgValues() {
64-
// Is the command line option set?
65-
if (!UseNewDbgInfoFormat)
66-
return;
67-
6864
IsNewDbgInfoFormat = true;
6965

7066
// Iterate over all instructions in the instruction list, collecting dbg.value

Diff for: llvm/lib/IR/IRPrintingPasses.cpp

+8-16
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323

2424
using namespace llvm;
2525

26+
extern cl::opt<bool> WriteNewDbgInfoFormat;
27+
2628
namespace {
2729

2830
class PrintModulePassWrapper : public ModulePass {
@@ -39,11 +41,9 @@ class PrintModulePassWrapper : public ModulePass {
3941
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {}
4042

4143
bool runOnModule(Module &M) override {
42-
// RemoveDIs: there's no textual representation of the DPValue debug-info,
43-
// convert to dbg.values before writing out.
44-
bool IsNewDbgInfoFormat = M.IsNewDbgInfoFormat;
45-
if (IsNewDbgInfoFormat)
46-
M.convertFromNewDbgValues();
44+
// RemoveDIs: Regardless of the format we've processed this module in, use
45+
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
46+
ScopedDbgInfoFormatSetter FormatSetter(M, WriteNewDbgInfoFormat);
4747

4848
if (llvm::isFunctionInPrintList("*")) {
4949
if (!Banner.empty())
@@ -62,9 +62,6 @@ class PrintModulePassWrapper : public ModulePass {
6262
}
6363
}
6464

65-
if (IsNewDbgInfoFormat)
66-
M.convertToNewDbgValues();
67-
6865
return false;
6966
}
7067

@@ -87,11 +84,9 @@ class PrintFunctionPassWrapper : public FunctionPass {
8784

8885
// This pass just prints a banner followed by the function as it's processed.
8986
bool runOnFunction(Function &F) override {
90-
// RemoveDIs: there's no textual representation of the DPValue debug-info,
91-
// convert to dbg.values before writing out.
92-
bool IsNewDbgInfoFormat = F.IsNewDbgInfoFormat;
93-
if (IsNewDbgInfoFormat)
94-
F.convertFromNewDbgValues();
87+
// RemoveDIs: Regardless of the format we've processed this function in, use
88+
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
89+
ScopedDbgInfoFormatSetter FormatSetter(F, WriteNewDbgInfoFormat);
9590

9691
if (isFunctionInPrintList(F.getName())) {
9792
if (forcePrintModuleIR())
@@ -101,9 +96,6 @@ class PrintFunctionPassWrapper : public FunctionPass {
10196
OS << Banner << '\n' << static_cast<Value &>(F);
10297
}
10398

104-
if (IsNewDbgInfoFormat)
105-
F.convertToNewDbgValues();
106-
10799
return false;
108100
}
109101

Diff for: llvm/lib/IR/Module.cpp

+22
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,28 @@ Module::~Module() {
8585
IFuncList.clear();
8686
}
8787

88+
void Module::removeDebugIntrinsicDeclarations() {
89+
auto *DeclareIntrinsicFn =
90+
Intrinsic::getDeclaration(this, Intrinsic::dbg_declare);
91+
assert((!isMaterialized() || DeclareIntrinsicFn->hasZeroLiveUses()) &&
92+
"Debug declare intrinsic should have had uses removed.");
93+
DeclareIntrinsicFn->eraseFromParent();
94+
auto *ValueIntrinsicFn =
95+
Intrinsic::getDeclaration(this, Intrinsic::dbg_value);
96+
assert((!isMaterialized() || ValueIntrinsicFn->hasZeroLiveUses()) &&
97+
"Debug value intrinsic should have had uses removed.");
98+
ValueIntrinsicFn->eraseFromParent();
99+
auto *AssignIntrinsicFn =
100+
Intrinsic::getDeclaration(this, Intrinsic::dbg_assign);
101+
assert((!isMaterialized() || AssignIntrinsicFn->hasZeroLiveUses()) &&
102+
"Debug assign intrinsic should have had uses removed.");
103+
AssignIntrinsicFn->eraseFromParent();
104+
auto *LabelntrinsicFn = Intrinsic::getDeclaration(this, Intrinsic::dbg_label);
105+
assert((!isMaterialized() || LabelntrinsicFn->hasZeroLiveUses()) &&
106+
"Debug label intrinsic should have had uses removed.");
107+
LabelntrinsicFn->eraseFromParent();
108+
}
109+
88110
std::unique_ptr<RandomNumberGenerator>
89111
Module::createRNG(const StringRef Name) const {
90112
SmallString<32> Salt(Name);

Diff for: llvm/lib/IRPrinter/IRPrintingPasses.cpp

+11-16
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@
2222

2323
using namespace llvm;
2424

25+
cl::opt<bool> WriteNewDbgInfoFormat(
26+
"write-experimental-debuginfo",
27+
cl::desc("Write debug info in the new non-intrinsic format"),
28+
cl::init(false));
29+
2530
PrintModulePass::PrintModulePass() : OS(dbgs()) {}
2631
PrintModulePass::PrintModulePass(raw_ostream &OS, const std::string &Banner,
2732
bool ShouldPreserveUseListOrder,
@@ -31,11 +36,9 @@ PrintModulePass::PrintModulePass(raw_ostream &OS, const std::string &Banner,
3136
EmitSummaryIndex(EmitSummaryIndex) {}
3237

3338
PreservedAnalyses PrintModulePass::run(Module &M, ModuleAnalysisManager &AM) {
34-
// RemoveDIs: there's no textual representation of the DPValue debug-info,
35-
// convert to dbg.values before writing out.
36-
bool ShouldConvert = M.IsNewDbgInfoFormat;
37-
if (ShouldConvert)
38-
M.convertFromNewDbgValues();
39+
// RemoveDIs: Regardless of the format we've processed this module in, use
40+
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
41+
ScopedDbgInfoFormatSetter FormatSetter(M, WriteNewDbgInfoFormat);
3942

4043
if (llvm::isFunctionInPrintList("*")) {
4144
if (!Banner.empty())
@@ -63,9 +66,6 @@ PreservedAnalyses PrintModulePass::run(Module &M, ModuleAnalysisManager &AM) {
6366
Index->print(OS);
6467
}
6568

66-
if (ShouldConvert)
67-
M.convertToNewDbgValues();
68-
6969
return PreservedAnalyses::all();
7070
}
7171

@@ -75,11 +75,9 @@ PrintFunctionPass::PrintFunctionPass(raw_ostream &OS, const std::string &Banner)
7575

7676
PreservedAnalyses PrintFunctionPass::run(Function &F,
7777
FunctionAnalysisManager &) {
78-
// RemoveDIs: there's no textual representation of the DPValue debug-info,
79-
// convert to dbg.values before writing out.
80-
bool ShouldConvert = F.IsNewDbgInfoFormat;
81-
if (ShouldConvert)
82-
F.convertFromNewDbgValues();
78+
// RemoveDIs: Regardless of the format we've processed this function in, use
79+
// `WriteNewDbgInfoFormat` to determine which format we use to write it.
80+
ScopedDbgInfoFormatSetter FormatSetter(F, WriteNewDbgInfoFormat);
8381

8482
if (isFunctionInPrintList(F.getName())) {
8583
if (forcePrintModuleIR())
@@ -88,8 +86,5 @@ PreservedAnalyses PrintFunctionPass::run(Function &F,
8886
OS << Banner << '\n' << static_cast<Value &>(F);
8987
}
9088

91-
if (ShouldConvert)
92-
F.convertToNewDbgValues();
93-
9489
return PreservedAnalyses::all();
9590
}

0 commit comments

Comments
 (0)