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
This commit is contained in:
Duncan P. N. Exon Smith
2015-06-27 00:38:26 +00:00
parent e92934e078
commit 2a5fda92b4
5 changed files with 118 additions and 10 deletions

View File

@@ -11,6 +11,7 @@
#include "llvm/IR/Function.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/IR/Value.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
@@ -106,4 +107,72 @@ TEST(GlobalTest, AlignDeath) {
#endif
#endif
TEST(ValueTest, printSlots) {
// Check that Value::print() and Value::printAsOperand() work with and
// without a slot tracker.
LLVMContext C;
const char *ModuleString = "define void @f(i32 %x, i32 %y) {\n"
"entry:\n"
" %0 = add i32 %y, 1\n"
" %1 = add i32 %y, 1\n"
" ret void\n"
"}\n";
SMDiagnostic Err;
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, C);
Function *F = M->getFunction("f");
ASSERT_TRUE(F);
ASSERT_FALSE(F->empty());
BasicBlock &BB = F->getEntryBlock();
ASSERT_EQ(3u, BB.size());
Instruction *I0 = BB.begin();
ASSERT_TRUE(I0);
Instruction *I1 = ++BB.begin();
ASSERT_TRUE(I1);
ModuleSlotTracker MST(M.get());
#define CHECK_PRINT(INST, STR) \
do { \
{ \
std::string S; \
raw_string_ostream OS(S); \
INST->print(OS); \
EXPECT_EQ(STR, OS.str()); \
} \
{ \
std::string S; \
raw_string_ostream OS(S); \
INST->print(OS, MST); \
EXPECT_EQ(STR, OS.str()); \
} \
} while (false)
CHECK_PRINT(I0, " %0 = add i32 %y, 1");
CHECK_PRINT(I1, " %1 = add i32 %y, 1");
#undef CHECK_PRINT
#define CHECK_PRINT_AS_OPERAND(INST, TYPE, STR) \
do { \
{ \
std::string S; \
raw_string_ostream OS(S); \
INST->printAsOperand(OS, TYPE); \
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
} \
{ \
std::string S; \
raw_string_ostream OS(S); \
INST->printAsOperand(OS, TYPE, MST); \
EXPECT_EQ(StringRef(STR), StringRef(OS.str())); \
} \
} while (false)
CHECK_PRINT_AS_OPERAND(I0, false, "%0");
CHECK_PRINT_AS_OPERAND(I1, false, "%1");
CHECK_PRINT_AS_OPERAND(I0, true, "i32 %0");
CHECK_PRINT_AS_OPERAND(I1, true, "i32 %1");
#undef CHECK_PRINT_AS_OPERAND
}
} // end anonymous namespace