llvm.org GIT mirror llvm / 2a5fda9
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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240867 91177308-0d34-0410-b5e6-96231b3b80d8 Duncan P. N. Exon Smith 4 years ago
5 changed file(s) with 118 addition(s) and 10 deletion(s). Raw diff Collapse all Expand all
123123 ///
124124 /// If \c M is provided, metadata nodes will be numbered canonically;
125125 /// otherwise, pointer addresses are substituted.
126 /// @{
126127 void print(raw_ostream &OS, const Module *M = nullptr) const;
128 void print(raw_ostream &OS, ModuleSlotTracker &MST,
129 const Module *M = nullptr) const;
130 /// @}
127131
128132 /// \brief Print as operand.
129133 ///
199199 void dump() const;
200200
201201 /// \brief Implement operator<< on Value.
202 /// @{
202203 void print(raw_ostream &O) const;
204 void print(raw_ostream &O, ModuleSlotTracker &MST) const;
205 /// @}
203206
204207 /// \brief Print the name of this Value out to the specified raw_ostream.
205208 ///
31923192 }
31933193
31943194 void Value::print(raw_ostream &ROS) const {
3195 bool ShouldInitializeAllMetadata = false;
3196 if (auto *I = dyn_cast(this))
3197 ShouldInitializeAllMetadata = isReferencingMDNode(*I);
3198 else if (isa(this) || isa(this))
3199 ShouldInitializeAllMetadata = true;
3200
3201 ModuleSlotTracker MST(getModuleFromVal(this), ShouldInitializeAllMetadata);
3202 print(ROS, MST);
3203 }
3204
3205 void Value::print(raw_ostream &ROS, ModuleSlotTracker &MST) const {
31953206 formatted_raw_ostream OS(ROS);
3207 SlotTracker EmptySlotTable(static_cast(nullptr));
3208 SlotTracker &SlotTable =
3209 MST.getMachine() ? *MST.getMachine() : EmptySlotTable;
3210 auto incorporateFunction = [&](const Function *F) {
3211 if (F)
3212 MST.incorporateFunction(*F);
3213 };
3214
31963215 if (const Instruction *I = dyn_cast(this)) {
3197 const Function *F = I->getParent() ? I->getParent()->getParent() : nullptr;
3198 SlotTracker SlotTable(
3199 F,
3200 /* ShouldInitializeAllMetadata */ isReferencingMDNode(*I));
3216 incorporateFunction(I->getParent() ? I->getParent()->getParent() : nullptr);
32013217 AssemblyWriter W(OS, SlotTable, getModuleFromVal(I), nullptr);
32023218 W.printInstruction(*I);
32033219 } else if (const BasicBlock *BB = dyn_cast(this)) {
3204 SlotTracker SlotTable(BB->getParent());
3220 incorporateFunction(BB->getParent());
32053221 AssemblyWriter W(OS, SlotTable, getModuleFromVal(BB), nullptr);
32063222 W.printBasicBlock(BB);
32073223 } else if (const GlobalValue *GV = dyn_cast(this)) {
3208 SlotTracker SlotTable(GV->getParent(),
3209 /* ShouldInitializeAllMetadata */ isa(GV));
32103224 AssemblyWriter W(OS, SlotTable, GV->getParent(), nullptr);
32113225 if (const GlobalVariable *V = dyn_cast(GV))
32123226 W.printGlobal(V);
32153229 else
32163230 W.printAlias(cast(GV));
32173231 } else if (const MetadataAsValue *V = dyn_cast(this)) {
3218 V->getMetadata()->print(ROS, getModuleFromVal(V));
3232 V->getMetadata()->print(ROS, MST, getModuleFromVal(V));
32193233 } else if (const Constant *C = dyn_cast(this)) {
32203234 TypePrinting TypePrinter;
32213235 TypePrinter.print(C->getType(), OS);
32223236 OS << ' ';
3223 WriteConstantInternal(OS, C, TypePrinter, nullptr, nullptr);
3237 WriteConstantInternal(OS, C, TypePrinter, MST.getMachine(), nullptr);
32243238 } else if (isa(this) || isa(this)) {
3225 this->printAsOperand(OS);
3239 this->printAsOperand(OS, /* PrintType */ true, MST);
32263240 } else {
32273241 llvm_unreachable("Unknown value to print out!");
32283242 }
33143328 printMetadataImpl(OS, *this, MST, M, /* OnlyAsOperand */ false);
33153329 }
33163330
3331 void Metadata::print(raw_ostream &OS, ModuleSlotTracker &MST,
3332 const Module *M) const {
3333 printMetadataImpl(OS, *this, MST, M, /* OnlyAsOperand */ false);
3334 }
3335
33173336 // Value::dump - allow easy printing of Values from the debugger.
33183337 LLVM_DUMP_METHOD
33193338 void Value::dump() const { print(dbgs()); dbgs() << '\n'; }
1515 #include "llvm/IR/LLVMContext.h"
1616 #include "llvm/IR/Metadata.h"
1717 #include "llvm/IR/Module.h"
18 #include "llvm/IR/ModuleSlotTracker.h"
1819 #include "llvm/IR/Type.h"
1920 #include "llvm/IR/Verifier.h"
2021 #include "llvm/Support/raw_ostream.h"
355356
356357 EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, &M));
357358 EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, &M));
359
360 ModuleSlotTracker MST(&M);
361 EXPECT_PRINTER_EQ("!0 = distinct !{}", N0->print(OS, MST));
362 EXPECT_PRINTER_EQ("!1 = distinct !{}", N1->print(OS, MST));
358363 }
359364
360365 TEST_F(MDNodeTest, PrintFromMetadataAsValue) {
383388 EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false));
384389 EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true));
385390 EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true));
391
392 ModuleSlotTracker MST(&M);
393 EXPECT_PRINTER_EQ("!0 = distinct !{}", MAV0->print(OS, MST));
394 EXPECT_PRINTER_EQ("!1 = distinct !{}", MAV1->print(OS, MST));
395 EXPECT_PRINTER_EQ("!0", MAV0->printAsOperand(OS, false, MST));
396 EXPECT_PRINTER_EQ("!1", MAV1->printAsOperand(OS, false, MST));
397 EXPECT_PRINTER_EQ("metadata !0", MAV0->printAsOperand(OS, true, MST));
398 EXPECT_PRINTER_EQ("metadata !1", MAV1->printAsOperand(OS, true, MST));
386399 }
387400 #undef EXPECT_PRINTER_EQ
388401
1010 #include "llvm/IR/Function.h"
1111 #include "llvm/IR/LLVMContext.h"
1212 #include "llvm/IR/Module.h"
13 #include "llvm/IR/ModuleSlotTracker.h"
1314 #include "llvm/IR/Value.h"
1415 #include "llvm/Support/SourceMgr.h"
1516 #include "gtest/gtest.h"
105106 #endif
106107 #endif
107108
109 TEST(ValueTest, printSlots) {
110 // Check that Value::print() and Value::printAsOperand() work with and
111 // without a slot tracker.
112 LLVMContext C;
113
114 const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
115 "entry:\n"
116 " %0 = add i32 %y, 1\n"
117 " %1 = add i32 %y, 1\n"
118 " ret void\n"
119 "}\n";
120 SMDiagnostic Err;
121 std::unique_ptr M = parseAssemblyString(ModuleString, Err, C);
122
123 Function *F = M->getFunction("f");
124 ASSERT_TRUE(F);
125 ASSERT_FALSE(F->empty());
126 BasicBlock &BB = F->getEntryBlock();
127 ASSERT_EQ(3u, BB.size());
128
129 Instruction *I0 = BB.begin();
130 ASSERT_TRUE(I0);
131 Instruction *I1 = ++BB.begin();
132 ASSERT_TRUE(I1);
133
134 ModuleSlotTracker MST(M.get());
135
136 #define CHECK_PRINT(INST, STR) \
137 do { \
138 { \
139 std::string S; \
140 raw_string_ostream OS(S); \
141 INST->print(OS); \
142 EXPECT_EQ(STR, OS.str()); \
143 } \
144 { \
145 std::string S; \
146 raw_string_ostream OS(S); \
147 INST->print(OS, MST); \
148 EXPECT_EQ(STR, OS.str()); \
149 } \
150 } while (false)
151 CHECK_PRINT(I0, " %0 = add i32 %y, 1");
152 CHECK_PRINT(I1, " %1 = add i32 %y, 1");
153 #undef CHECK_PRINT
154
155 #define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \
156 do { \
157 { \
158 std::string S; \
159 raw_string_ostream OS(S); \
160 INST->printAsOperand(OS, TYPE); \
161 EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
162 } \
163 { \
164 std::string S; \
165 raw_string_ostream OS(S); \
166 INST->printAsOperand(OS, TYPE, MST); \
167 EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
168 } \
169 } while (false)
170 CHECK_PRINT_AS_OPERAND(I0, false, "%0");
171 CHECK_PRINT_AS_OPERAND(I1, false, "%1");
172 CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0");
173 CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1");
174 #undef CHECK_PRINT_AS_OPERAND
175 }
176
108177 } // end anonymous namespace