CodeGen: Use a single SlotTracker in MachineFunction::print()

Expose enough of the IR-level `SlotTracker` so that
`MachineFunction::print()` can use a single one for printing
`BasicBlock`s.  Next step would be to lift this through a few more APIs
so that we can make other print methods faster.

Fixes PR23865, changing the runtime of `llc -print-machineinstrs` from
many minutes (killed after 3 minutes, but it wasn't very close) to
13 seconds for a 502185 line dump.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@240842 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan P. N. Exon Smith 2015-06-26 22:04:20 +00:00
parent 0be7d0cf17
commit 9a61a42713
6 changed files with 162 additions and 22 deletions

View File

@ -660,6 +660,8 @@ public:
// Debugging methods.
void dump() const;
void print(raw_ostream &OS, SlotIndexes* = nullptr) const;
void print(raw_ostream &OS, ModuleSlotTracker &MST,
SlotIndexes * = nullptr) const;
// Printing method used by LoopInfo.
void printAsOperand(raw_ostream &OS, bool PrintType = true) const;

View File

@ -0,0 +1,63 @@
//===-- llvm/IR/ModuleSlotTracker.h -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_IR_MODULESLOTTRACKER_H
#define LLVM_IR_MODULESLOTTRACKER_H
#include <memory>
namespace llvm {
class Module;
class Function;
class SlotTracker;
/// Manage lifetime of a slot tracker for printing IR.
///
/// Wrapper around the \a SlotTracker used internally by \a AsmWriter. This
/// class allows callers to share the cost of incorporating the metadata in a
/// module or a function.
///
/// If the IR changes from underneath \a ModuleSlotTracker, strings like
/// "<badref>" will be printed, or, worse, the wrong slots entirely.
class ModuleSlotTracker {
/// Storage for a slot tracker.
std::unique_ptr<SlotTracker> MachineStorage;
const Module *M = nullptr;
const Function *F = nullptr;
SlotTracker *Machine = nullptr;
public:
/// Wrap a preinitialized SlotTracker.
ModuleSlotTracker(SlotTracker &Machine, const Module *M,
const Function *F = nullptr);
/// Construct a slot tracker from a module.
///
/// If \a M is \c nullptr, uses a null slot tracker.
explicit ModuleSlotTracker(const Module *M);
/// Destructor to clean up storage.
~ModuleSlotTracker();
SlotTracker *getMachine() const { return Machine; }
const Module *getModule() const { return M; }
const Function *getCurrentFunction() const { return F; }
/// Incorporate the given function.
///
/// Purge the currently incorporated function and incorporate \c F. If \c F
/// is currently incorporated, this is a no-op.
void incorporateFunction(const Function &F);
};
} // end namespace llvm
#endif

View File

@ -38,6 +38,7 @@ class InlineAsm;
class Instruction;
class LLVMContext;
class Module;
class ModuleSlotTracker;
class StringRef;
class Twine;
class Type;
@ -207,8 +208,12 @@ public:
/// instruction that generated it. If you specify a Module for context, then
/// even constanst get pretty-printed; for example, the type of a null
/// pointer is printed symbolically.
/// @{
void printAsOperand(raw_ostream &O, bool PrintType = true,
const Module *M = nullptr) const;
void printAsOperand(raw_ostream &O, bool PrintType,
ModuleSlotTracker &MST) const;
/// @}
/// \brief All values are typed, get the type of this value.
Type *getType() const { return VTy; }

View File

@ -24,6 +24,7 @@
#include "llvm/CodeGen/SlotIndexes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/Debug.h"
@ -244,6 +245,20 @@ void MachineBasicBlock::print(raw_ostream &OS, SlotIndexes *Indexes) const {
<< " is null\n";
return;
}
const Function *F = MF->getFunction();
const Module *M = F ? F->getParent() : nullptr;
ModuleSlotTracker MST(M);
print(OS, MST, Indexes);
}
void MachineBasicBlock::print(raw_ostream &OS, ModuleSlotTracker &MST,
SlotIndexes *Indexes) const {
const MachineFunction *MF = getParent();
if (!MF) {
OS << "Can't print out MachineBasicBlock because parent MachineFunction"
<< " is null\n";
return;
}
if (Indexes)
OS << Indexes->getMBBStartIdx(this) << '\t';
@ -253,7 +268,7 @@ void MachineBasicBlock::print(raw_ostream &OS, SlotIndexes *Indexes) const {
const char *Comma = "";
if (const BasicBlock *LBB = getBasicBlock()) {
OS << Comma << "derived from LLVM BB ";
LBB->printAsOperand(OS, /*PrintType=*/false);
LBB->printAsOperand(OS, /*PrintType=*/false, MST);
Comma = ", ";
}
if (isLandingPad()) { OS << Comma << "EH LANDING PAD"; Comma = ", "; }

View File

@ -29,6 +29,7 @@
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugInfo.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/Debug.h"
@ -361,9 +362,11 @@ void MachineFunction::print(raw_ostream &OS, SlotIndexes *Indexes) const {
OS << '\n';
}
ModuleSlotTracker MST(getFunction()->getParent());
MST.incorporateFunction(*getFunction());
for (const auto &BB : *this) {
OS << '\n';
BB.print(OS, Indexes);
BB.print(OS, MST, Indexes);
}
OS << "\n# End machine code for function " << getName() << ".\n\n";

View File

@ -30,6 +30,7 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/ModuleSlotTracker.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/Statepoint.h"
#include "llvm/IR/TypeFinder.h"
@ -544,7 +545,7 @@ void TypePrinting::printStructBody(StructType *STy, raw_ostream &OS) {
OS << '>';
}
namespace {
namespace llvm {
//===----------------------------------------------------------------------===//
// SlotTracker Class: Enumerate slot numbers for unnamed values
//===----------------------------------------------------------------------===//
@ -663,7 +664,32 @@ private:
SlotTracker(const SlotTracker &) = delete;
void operator=(const SlotTracker &) = delete;
};
} // namespace
} // namespace llvm
ModuleSlotTracker::ModuleSlotTracker(SlotTracker &Machine, const Module *M,
const Function *F)
: M(M), F(F), Machine(&Machine) {}
ModuleSlotTracker::ModuleSlotTracker(const Module *M)
: MachineStorage(
M ? new SlotTracker(M, /* ShouldInitializeAllMetadata */ true)
: nullptr),
M(M), Machine(MachineStorage.get()) {}
ModuleSlotTracker::~ModuleSlotTracker() {}
void ModuleSlotTracker::incorporateFunction(const Function &F) {
if (!Machine)
return;
// Nothing to do if this is the right function already.
if (this->F == &F)
return;
if (this->F)
Machine->purgeFunction();
Machine->incorporateFunction(&F);
this->F = &F;
}
static SlotTracker *createSlotTracker(const Module *M) {
return new SlotTracker(M);
@ -1948,7 +1974,7 @@ namespace {
class AssemblyWriter {
formatted_raw_ostream &Out;
const Module *TheModule;
std::unique_ptr<SlotTracker> ModuleSlotTracker;
std::unique_ptr<SlotTracker> SlotTrackerStorage;
SlotTracker &Machine;
TypePrinting TypePrinter;
AssemblyAnnotationWriter *AnnotationWriter;
@ -2038,8 +2064,8 @@ AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, SlotTracker &Mac,
AssemblyWriter::AssemblyWriter(formatted_raw_ostream &o, const Module *M,
AssemblyAnnotationWriter *AAW,
bool ShouldPreserveUseListOrder)
: Out(o), TheModule(M), ModuleSlotTracker(createSlotTracker(M)),
Machine(*ModuleSlotTracker), AnnotationWriter(AAW),
: Out(o), TheModule(M), SlotTrackerStorage(createSlotTracker(M)),
Machine(*SlotTrackerStorage), AnnotationWriter(AAW),
ShouldPreserveUseListOrder(ShouldPreserveUseListOrder) {
init();
}
@ -3200,29 +3226,55 @@ void Value::print(raw_ostream &ROS) const {
}
}
void Value::printAsOperand(raw_ostream &O, bool PrintType, const Module *M) const {
// Fast path: Don't construct and populate a TypePrinting object if we
// won't be needing any types printed.
bool IsMetadata = isa<MetadataAsValue>(this);
if (!PrintType && ((!isa<Constant>(this) && !IsMetadata) || hasName() ||
isa<GlobalValue>(this))) {
WriteAsOperandInternal(O, this, nullptr, nullptr, M);
return;
/// Print without a type, skipping the TypePrinting object.
///
/// \return \c true iff printing was succesful.
static bool printWithoutType(const Value &V, raw_ostream &O,
SlotTracker *Machine, const Module *M) {
if (V.hasName() || isa<GlobalValue>(V) ||
(!isa<Constant>(V) && !isa<MetadataAsValue>(V))) {
WriteAsOperandInternal(O, &V, nullptr, Machine, M);
return true;
}
return false;
}
if (!M)
M = getModuleFromVal(this);
static void printAsOperandImpl(const Value &V, raw_ostream &O, bool PrintType,
ModuleSlotTracker &MST) {
TypePrinting TypePrinter;
if (M)
if (const Module *M = MST.getModule())
TypePrinter.incorporateTypes(*M);
if (PrintType) {
TypePrinter.print(getType(), O);
TypePrinter.print(V.getType(), O);
O << ' ';
}
SlotTracker Machine(M, /* ShouldInitializeAllMetadata */ IsMetadata);
WriteAsOperandInternal(O, this, &TypePrinter, &Machine, M);
WriteAsOperandInternal(O, &V, &TypePrinter, MST.getMachine(),
MST.getModule());
}
void Value::printAsOperand(raw_ostream &O, bool PrintType,
const Module *M) const {
if (!M)
M = getModuleFromVal(this);
if (!PrintType)
if (printWithoutType(*this, O, nullptr, M))
return;
SlotTracker Machine(
M, /* ShouldInitializeAllMetadata */ isa<MetadataAsValue>(this));
ModuleSlotTracker MST(Machine, M);
printAsOperandImpl(*this, O, PrintType, MST);
}
void Value::printAsOperand(raw_ostream &O, bool PrintType,
ModuleSlotTracker &MST) const {
if (!PrintType)
if (printWithoutType(*this, O, MST.getMachine(), MST.getModule()))
return;
printAsOperandImpl(*this, O, PrintType, MST);
}
static void printMetadataImpl(raw_ostream &ROS, const Metadata &MD,