Skip to content

Commit 1f8a99a

Browse files
committed
IR: Expose ModuleSlotTracker in Value::print()
Allow callers of `Value::print()` and `Metadata::print()` to pass in a `ModuleSlotTracker`. This allows them to pay only once for calculating module-level slots (such as Metadata). This is related to PR23865, where there was a huge cost for `MachineFunction::print()`. Although I don't have a *particular* user in mind for this new code, I have hit big slowdowns before when running `opt -debug`, and I think this will be useful. Going forward, if someone hits a big slowdown with `print()` statements, they can create a `ModuleSlotTracker` and send it through. Similarly, adding support to `Value::dump()` and `Metadata::dump()` should be trivial. I added unit tests to be sure the `print()` functions actually behave the same way with and without the slot tracker. llvm-svn: 240867
1 parent ba4c8b5 commit 1f8a99a

File tree

5 files changed

+118
-10
lines changed

5 files changed

+118
-10
lines changed

llvm/include/llvm/IR/Metadata.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ class Metadata {
124124
///
125125
/// If \c M is provided, metadata nodes will be numbered canonically;
126126
/// otherwise, pointer addresses are substituted.
127+
/// @{
127128
void print(raw_ostream &OS, const Module *M = nullptr) const;
129+
void print(raw_ostream &OS, ModuleSlotTracker &MST,
130+
const Module *M = nullptr) const;
131+
/// @}
128132

129133
/// \brief Print as operand.
130134
///

llvm/include/llvm/IR/Value.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,10 @@ class Value {
200200
void dump() const;
201201

202202
/// \brief Implement operator<< on Value.
203+
/// @{
203204
void print(raw_ostream &O) const;
205+
void print(raw_ostream &O, ModuleSlotTracker &MST) const;
206+
/// @}
204207

205208
/// \brief Print the name of this Value out to the specified raw_ostream.
206209
///

llvm/lib/IR/AsmWriter.cpp

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3193,21 +3193,35 @@ static bool isReferencingMDNode(const Instruction &I) {
31933193
}
31943194

31953195
void Value::print(raw_ostream &ROS) const {
3196+
bool ShouldInitializeAllMetadata = false;
3197+
if (auto *I = dyn_cast<Instruction>(this))
3198+
ShouldInitializeAllMetadata = isReferencingMDNode(*I);
3199+
else if (isa<Function>(this) || isa<MetadataAsValue>(this))
3200+
ShouldInitializeAllMetadata = true;
3201+
3202+
ModuleSlotTracker MST(getModuleFromVal(this), ShouldInitializeAllMetadata);
3203+
print(ROS, MST);
3204+
}
3205+
3206+
void Value::print(raw_ostream &ROS, ModuleSlotTracker &MST) const {
31963207
formatted_raw_ostream OS(ROS);
3208+
SlotTracker EmptySlotTable(static_cast<const Module *>(nullptr));
3209+
SlotTracker &SlotTable =
3210+
MST.getMachine() ? *MST.getMachine() : EmptySlotTable;
3211+
auto incorporateFunction = [&](const Function *F) {
3212+
if (F)
3213+
MST.incorporateFunction(*F);
3214+
};
3215+
31973216
if (const Instruction *I = dyn_cast<Instruction>(this)) {
3198-
const Function *F = I->getParent() ? I->getParent()->getParent() : nullptr;
3199-
SlotTracker SlotTable(
3200-
F,
3201-
/* ShouldInitializeAllMetadata */ isReferencingMDNode(*I));
3217+
incorporateFunction(I->getParent() ? I->getParent()->getParent() : nullptr);
32023218
AssemblyWriter W(OS, SlotTable, getModuleFromVal(I), nullptr);
32033219
W.printInstruction(*I);
32043220
} else if (const BasicBlock *BB = dyn_cast<BasicBlock>(this)) {
3205-
SlotTracker SlotTable(BB->getParent());
3221+
incorporateFunction(BB->getParent());
32063222
AssemblyWriter W(OS, SlotTable, getModuleFromVal(BB), nullptr);
32073223
W.printBasicBlock(BB);
32083224
} else if (const GlobalValue *GV = dyn_cast<GlobalValue>(this)) {
3209-
SlotTracker SlotTable(GV->getParent(),
3210-
/* ShouldInitializeAllMetadata */ isa<Function>(GV));
32113225
AssemblyWriter W(OS, SlotTable, GV->getParent(), nullptr);
32123226
if (const GlobalVariable *V = dyn_cast<GlobalVariable>(GV))
32133227
W.printGlobal(V);
@@ -3216,14 +3230,14 @@ void Value::print(raw_ostream &ROS) const {
32163230
else
32173231
W.printAlias(cast<GlobalAlias>(GV));
32183232
} else if (const MetadataAsValue *V = dyn_cast<MetadataAsValue>(this)) {
3219-
V->getMetadata()->print(ROS, getModuleFromVal(V));
3233+
V->getMetadata()->print(ROS, MST, getModuleFromVal(V));
32203234
} else if (const Constant *C = dyn_cast<Constant>(this)) {
32213235
TypePrinting TypePrinter;
32223236
TypePrinter.print(C->getType(), OS);
32233237
OS << ' ';
3224-
WriteConstantInternal(OS, C, TypePrinter, nullptr, nullptr);
3238+
WriteConstantInternal(OS, C, TypePrinter, MST.getMachine(), nullptr);
32253239
} else if (isa<InlineAsm>(this) || isa<Argument>(this)) {
3226-
this->printAsOperand(OS);
3240+
this->printAsOperand(OS, /* PrintType */ true, MST);
32273241
} else {
32283242
llvm_unreachable("Unknown value to print out!");
32293243
}
@@ -3315,6 +3329,11 @@ void Metadata::print(raw_ostream &OS, const Module *M) const {
33153329
printMetadataImpl(OS, *this, MST, M, /* OnlyAsOperand */ false);
33163330
}
33173331

3332+
void Metadata::print(raw_ostream &OS, ModuleSlotTracker &MST,
3333+
const Module *M) const {
3334+
printMetadataImpl(OS, *this, MST, M, /* OnlyAsOperand */ false);
3335+
}
3336+
33183337
// Value::dump - allow easy printing of Values from the debugger.
33193338
LLVM_DUMP_METHOD
33203339
void Value::dump() const { print(dbgs()); dbgs() << '\n'; }

llvm/unittests/IR/MetadataTest.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "llvm/IR/LLVMContext.h"
1717
#include "llvm/IR/Metadata.h"
1818
#include "llvm/IR/Module.h"
19+
#include "llvm/IR/ModuleSlotTracker.h"
1920
#include "llvm/IR/Type.h"
2021
#include "llvm/IR/Verifier.h"
2122
#include "llvm/Support/raw_ostream.h"
@@ -356,6 +357,10 @@ TEST_F(MDNodeTest, PrintFromFunction) {
356357

357358
EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, &M));
358359
EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, &M));
360+
361+
ModuleSlotTracker MST(&M);
362+
EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, MST));
363+
EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, MST));
359364
}
360365

361366
TEST_F(MDNodeTest, PrintFromMetadataAsValue) {
@@ -384,6 +389,14 @@ TEST_F(MDNodeTest, PrintFromMetadataAsValue) {
384389
EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false));
385390
EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true));
386391
EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true));
392+
393+
ModuleSlotTracker MST(&M);
394+
EXPECT_PRINTER_EQ("!0 = distinct !{}", MAV0->print(OS, MST));
395+
EXPECT_PRINTER_EQ("!1 = distinct !{}", MAV1->print(OS, MST));
396+
EXPECT_PRINTER_EQ("!0", MAV0->printAsOperand(OS, false, MST));
397+
EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false, MST));
398+
EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true, MST));
399+
EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true, MST));
387400
}
388401
#undef EXPECT_PRINTER_EQ
389402

llvm/unittests/IR/ValueTest.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include "llvm/IR/Function.h"
1212
#include "llvm/IR/LLVMContext.h"
1313
#include "llvm/IR/Module.h"
14+
#include "llvm/IR/ModuleSlotTracker.h"
1415
#include "llvm/IR/Value.h"
1516
#include "llvm/Support/SourceMgr.h"
1617
#include "gtest/gtest.h"
@@ -106,4 +107,72 @@ TEST(GlobalTest, AlignDeath) {
106107
#endif
107108
#endif
108109

110+
TEST(ValueTest, printSlots) {
111+
// Check that Value::print() and Value::printAsOperand() work with and
112+
// without a slot tracker.
113+
LLVMContext C;
114+
115+
const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
116+
"entry:\n"
117+
" %0 = add i32 %y, 1\n"
118+
" %1 = add i32 %y, 1\n"
119+
" ret void\n"
120+
"}\n";
121+
SMDiagnostic Err;
122+
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
123+
124+
Function *F = M->getFunction("f");
125+
ASSERT_TRUE(F);
126+
ASSERT_FALSE(F->empty());
127+
BasicBlock &BB = F->getEntryBlock();
128+
ASSERT_EQ(3u, BB.size());
129+
130+
Instruction *I0 = BB.begin();
131+
ASSERT_TRUE(I0);
132+
Instruction *I1 = ++BB.begin();
133+
ASSERT_TRUE(I1);
134+
135+
ModuleSlotTracker MST(M.get());
136+
137+
#define CHECK_PRINT(INST, STR) \
138+
do { \
139+
{ \
140+
std::string S; \
141+
raw_string_ostream OS(S); \
142+
INST->print(OS); \
143+
EXPECT_EQ(STR, OS.str()); \
144+
} \
145+
{ \
146+
std::string S; \
147+
raw_string_ostream OS(S); \
148+
INST->print(OS, MST); \
149+
EXPECT_EQ(STR, OS.str()); \
150+
} \
151+
} while (false)
152+
CHECK_PRINT(I0, " %0 = add i32 %y, 1");
153+
CHECK_PRINT(I1, " %1 = add i32 %y, 1");
154+
#undef CHECK_PRINT
155+
156+
#define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \
157+
do { \
158+
{ \
159+
std::string S; \
160+
raw_string_ostream OS(S); \
161+
INST->printAsOperand(OS, TYPE); \
162+
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
163+
} \
164+
{ \
165+
std::string S; \
166+
raw_string_ostream OS(S); \
167+
INST->printAsOperand(OS, TYPE, MST); \
168+
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
169+
} \
170+
} while (false)
171+
CHECK_PRINT_AS_OPERAND(I0, false, "%0");
172+
CHECK_PRINT_AS_OPERAND(I1, false, "%1");
173+
CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0");
174+
CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1");
175+
#undef CHECK_PRINT_AS_OPERAND
176+
}
177+
109178
} // end anonymous namespace

0 commit comments

Comments
 (0)