mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-09-04 09:30:13 +00:00
When computing a trace, all the candidates for pred/succ must have been visited. Filter out back-edges first, though. The PO traversal ignores them. Thanks to Andy for spotting this in review. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@160995 91177308-0d34-0410-b5e6-96231b3b80d8
536 lines
19 KiB
C++
536 lines
19 KiB
C++
//===- lib/CodeGen/MachineTraceMetrics.cpp ----------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "early-ifcvt"
|
|
#include "MachineTraceMetrics.h"
|
|
#include "llvm/CodeGen/MachineBasicBlock.h"
|
|
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
|
#include "llvm/CodeGen/MachineLoopInfo.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/Passes.h"
|
|
#include "llvm/Target/TargetInstrInfo.h"
|
|
#include "llvm/Target/TargetRegisterInfo.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/ADT/PostOrderIterator.h"
|
|
|
|
using namespace llvm;
|
|
|
|
char MachineTraceMetrics::ID = 0;
|
|
char &llvm::MachineTraceMetricsID = MachineTraceMetrics::ID;
|
|
|
|
INITIALIZE_PASS_BEGIN(MachineTraceMetrics,
|
|
"machine-trace-metrics", "Machine Trace Metrics", false, true)
|
|
INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
|
|
INITIALIZE_PASS_DEPENDENCY(MachineLoopInfo)
|
|
INITIALIZE_PASS_END(MachineTraceMetrics,
|
|
"machine-trace-metrics", "Machine Trace Metrics", false, true)
|
|
|
|
MachineTraceMetrics::MachineTraceMetrics()
|
|
: MachineFunctionPass(ID), TII(0), TRI(0), MRI(0), Loops(0) {
|
|
std::fill(Ensembles, array_endof(Ensembles), (Ensemble*)0);
|
|
}
|
|
|
|
void MachineTraceMetrics::getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.setPreservesAll();
|
|
AU.addRequired<MachineBranchProbabilityInfo>();
|
|
AU.addRequired<MachineLoopInfo>();
|
|
MachineFunctionPass::getAnalysisUsage(AU);
|
|
}
|
|
|
|
bool MachineTraceMetrics::runOnMachineFunction(MachineFunction &Func) {
|
|
MF = &Func;
|
|
TII = MF->getTarget().getInstrInfo();
|
|
TRI = MF->getTarget().getRegisterInfo();
|
|
MRI = &MF->getRegInfo();
|
|
Loops = &getAnalysis<MachineLoopInfo>();
|
|
BlockInfo.resize(MF->getNumBlockIDs());
|
|
return false;
|
|
}
|
|
|
|
void MachineTraceMetrics::releaseMemory() {
|
|
BlockInfo.clear();
|
|
for (unsigned i = 0; i != TS_NumStrategies; ++i) {
|
|
delete Ensembles[i];
|
|
Ensembles[i] = 0;
|
|
}
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Fixed block information
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The number of instructions in a basic block and the CPU resources used by
|
|
// those instructions don't depend on any given trace strategy.
|
|
|
|
/// Compute the resource usage in basic block MBB.
|
|
const MachineTraceMetrics::FixedBlockInfo*
|
|
MachineTraceMetrics::getResources(const MachineBasicBlock *MBB) {
|
|
assert(MBB && "No basic block");
|
|
FixedBlockInfo *FBI = &BlockInfo[MBB->getNumber()];
|
|
if (FBI->hasResources())
|
|
return FBI;
|
|
|
|
// Compute resource usage in the block.
|
|
// FIXME: Compute per-functional unit counts.
|
|
FBI->HasCalls = false;
|
|
unsigned InstrCount = 0;
|
|
for (MachineBasicBlock::const_iterator I = MBB->begin(), E = MBB->end();
|
|
I != E; ++I) {
|
|
const MachineInstr *MI = I;
|
|
if (MI->isTransient())
|
|
continue;
|
|
++InstrCount;
|
|
if (MI->isCall())
|
|
FBI->HasCalls = true;
|
|
}
|
|
FBI->InstrCount = InstrCount;
|
|
return FBI;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Ensemble utility functions
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
MachineTraceMetrics::Ensemble::Ensemble(MachineTraceMetrics *ct)
|
|
: CT(*ct) {
|
|
BlockInfo.resize(CT.BlockInfo.size());
|
|
}
|
|
|
|
// Virtual destructor serves as an anchor.
|
|
MachineTraceMetrics::Ensemble::~Ensemble() {}
|
|
|
|
const MachineLoop*
|
|
MachineTraceMetrics::Ensemble::getLoopFor(const MachineBasicBlock *MBB) const {
|
|
return CT.Loops->getLoopFor(MBB);
|
|
}
|
|
|
|
// Update resource-related information in the TraceBlockInfo for MBB.
|
|
// Only update resources related to the trace above MBB.
|
|
void MachineTraceMetrics::Ensemble::
|
|
computeDepthResources(const MachineBasicBlock *MBB) {
|
|
TraceBlockInfo *TBI = &BlockInfo[MBB->getNumber()];
|
|
|
|
// Compute resources from trace above. The top block is simple.
|
|
if (!TBI->Pred) {
|
|
TBI->InstrDepth = 0;
|
|
TBI->Head = MBB->getNumber();
|
|
return;
|
|
}
|
|
|
|
// Compute from the block above. A post-order traversal ensures the
|
|
// predecessor is always computed first.
|
|
TraceBlockInfo *PredTBI = &BlockInfo[TBI->Pred->getNumber()];
|
|
assert(PredTBI->hasValidDepth() && "Trace above has not been computed yet");
|
|
const FixedBlockInfo *PredFBI = CT.getResources(TBI->Pred);
|
|
TBI->InstrDepth = PredTBI->InstrDepth + PredFBI->InstrCount;
|
|
TBI->Head = PredTBI->Head;
|
|
}
|
|
|
|
// Update resource-related information in the TraceBlockInfo for MBB.
|
|
// Only update resources related to the trace below MBB.
|
|
void MachineTraceMetrics::Ensemble::
|
|
computeHeightResources(const MachineBasicBlock *MBB) {
|
|
TraceBlockInfo *TBI = &BlockInfo[MBB->getNumber()];
|
|
|
|
// Compute resources for the current block.
|
|
TBI->InstrHeight = CT.getResources(MBB)->InstrCount;
|
|
|
|
// The trace tail is done.
|
|
if (!TBI->Succ) {
|
|
TBI->Tail = MBB->getNumber();
|
|
return;
|
|
}
|
|
|
|
// Compute from the block below. A post-order traversal ensures the
|
|
// predecessor is always computed first.
|
|
TraceBlockInfo *SuccTBI = &BlockInfo[TBI->Succ->getNumber()];
|
|
assert(SuccTBI->hasValidHeight() && "Trace below has not been computed yet");
|
|
TBI->InstrHeight += SuccTBI->InstrHeight;
|
|
TBI->Tail = SuccTBI->Tail;
|
|
}
|
|
|
|
// Check if depth resources for MBB are valid and return the TBI.
|
|
// Return NULL if the resources have been invalidated.
|
|
const MachineTraceMetrics::TraceBlockInfo*
|
|
MachineTraceMetrics::Ensemble::
|
|
getDepthResources(const MachineBasicBlock *MBB) const {
|
|
const TraceBlockInfo *TBI = &BlockInfo[MBB->getNumber()];
|
|
return TBI->hasValidDepth() ? TBI : 0;
|
|
}
|
|
|
|
// Check if height resources for MBB are valid and return the TBI.
|
|
// Return NULL if the resources have been invalidated.
|
|
const MachineTraceMetrics::TraceBlockInfo*
|
|
MachineTraceMetrics::Ensemble::
|
|
getHeightResources(const MachineBasicBlock *MBB) const {
|
|
const TraceBlockInfo *TBI = &BlockInfo[MBB->getNumber()];
|
|
return TBI->hasValidHeight() ? TBI : 0;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Trace Selection Strategies
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// A trace selection strategy is implemented as a sub-class of Ensemble. The
|
|
// trace through a block B is computed by two DFS traversals of the CFG
|
|
// starting from B. One upwards, and one downwards. During the upwards DFS,
|
|
// pickTracePred() is called on the post-ordered blocks. During the downwards
|
|
// DFS, pickTraceSucc() is called in a post-order.
|
|
//
|
|
|
|
// MinInstrCountEnsemble - Pick the trace that executes the least number of
|
|
// instructions.
|
|
namespace {
|
|
class MinInstrCountEnsemble : public MachineTraceMetrics::Ensemble {
|
|
const char *getName() const { return "MinInstr"; }
|
|
const MachineBasicBlock *pickTracePred(const MachineBasicBlock*);
|
|
const MachineBasicBlock *pickTraceSucc(const MachineBasicBlock*);
|
|
|
|
public:
|
|
MinInstrCountEnsemble(MachineTraceMetrics *ct)
|
|
: MachineTraceMetrics::Ensemble(ct) {}
|
|
};
|
|
}
|
|
|
|
// Select the preferred predecessor for MBB.
|
|
const MachineBasicBlock*
|
|
MinInstrCountEnsemble::pickTracePred(const MachineBasicBlock *MBB) {
|
|
if (MBB->pred_empty())
|
|
return 0;
|
|
const MachineLoop *CurLoop = getLoopFor(MBB);
|
|
// Don't leave loops, and never follow back-edges.
|
|
if (CurLoop && MBB == CurLoop->getHeader())
|
|
return 0;
|
|
unsigned CurCount = CT.getResources(MBB)->InstrCount;
|
|
const MachineBasicBlock *Best = 0;
|
|
unsigned BestDepth = 0;
|
|
for (MachineBasicBlock::const_pred_iterator
|
|
I = MBB->pred_begin(), E = MBB->pred_end(); I != E; ++I) {
|
|
const MachineBasicBlock *Pred = *I;
|
|
// Don't consider predecessors in other loops.
|
|
if (getLoopFor(Pred) != CurLoop)
|
|
continue;
|
|
const MachineTraceMetrics::TraceBlockInfo *PredTBI =
|
|
getDepthResources(Pred);
|
|
assert(PredTBI && "Predecessor must be visited first");
|
|
// Pick the predecessor that would give this block the smallest InstrDepth.
|
|
unsigned Depth = PredTBI->InstrDepth + CurCount;
|
|
if (!Best || Depth < BestDepth)
|
|
Best = Pred, BestDepth = Depth;
|
|
}
|
|
return Best;
|
|
}
|
|
|
|
// Select the preferred successor for MBB.
|
|
const MachineBasicBlock*
|
|
MinInstrCountEnsemble::pickTraceSucc(const MachineBasicBlock *MBB) {
|
|
if (MBB->pred_empty())
|
|
return 0;
|
|
const MachineLoop *CurLoop = getLoopFor(MBB);
|
|
const MachineBasicBlock *Best = 0;
|
|
unsigned BestHeight = 0;
|
|
for (MachineBasicBlock::const_succ_iterator
|
|
I = MBB->succ_begin(), E = MBB->succ_end(); I != E; ++I) {
|
|
const MachineBasicBlock *Succ = *I;
|
|
// Don't consider back-edges.
|
|
if (CurLoop && Succ == CurLoop->getHeader())
|
|
continue;
|
|
// Don't consider successors in other loops.
|
|
if (getLoopFor(Succ) != CurLoop)
|
|
continue;
|
|
const MachineTraceMetrics::TraceBlockInfo *SuccTBI =
|
|
getHeightResources(Succ);
|
|
assert(SuccTBI && "Successor must be visited first");
|
|
// Pick the successor that would give this block the smallest InstrHeight.
|
|
unsigned Height = SuccTBI->InstrHeight;
|
|
if (!Best || Height < BestHeight)
|
|
Best = Succ, BestHeight = Height;
|
|
}
|
|
return Best;
|
|
}
|
|
|
|
// Get an Ensemble sub-class for the requested trace strategy.
|
|
MachineTraceMetrics::Ensemble *
|
|
MachineTraceMetrics::getEnsemble(MachineTraceMetrics::Strategy strategy) {
|
|
assert(strategy < TS_NumStrategies && "Invalid trace strategy enum");
|
|
Ensemble *&E = Ensembles[strategy];
|
|
if (E)
|
|
return E;
|
|
|
|
// Allocate new Ensemble on demand.
|
|
switch (strategy) {
|
|
case TS_MinInstrCount: return (E = new MinInstrCountEnsemble(this));
|
|
default: llvm_unreachable("Invalid trace strategy enum");
|
|
}
|
|
}
|
|
|
|
void MachineTraceMetrics::invalidate(const MachineBasicBlock *MBB) {
|
|
DEBUG(dbgs() << "Invalidate traces through BB#" << MBB->getNumber() << '\n');
|
|
BlockInfo[MBB->getNumber()].invalidate();
|
|
for (unsigned i = 0; i != TS_NumStrategies; ++i)
|
|
if (Ensembles[i])
|
|
Ensembles[i]->invalidate(MBB);
|
|
}
|
|
|
|
void MachineTraceMetrics::verifyAnalysis() const {
|
|
#ifndef NDEBUG
|
|
assert(BlockInfo.size() == MF->getNumBlockIDs() && "Outdated BlockInfo size");
|
|
for (unsigned i = 0; i != TS_NumStrategies; ++i)
|
|
if (Ensembles[i])
|
|
Ensembles[i]->verify();
|
|
#endif
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Trace building
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Traces are built by two CFG traversals. To avoid recomputing too much, use a
|
|
// set abstraction that confines the search to the current loop, and doesn't
|
|
// revisit blocks.
|
|
|
|
namespace {
|
|
struct LoopBounds {
|
|
MutableArrayRef<MachineTraceMetrics::TraceBlockInfo> Blocks;
|
|
const MachineLoopInfo *Loops;
|
|
const MachineLoop *CurLoop;
|
|
bool Downward;
|
|
LoopBounds(MutableArrayRef<MachineTraceMetrics::TraceBlockInfo> blocks,
|
|
const MachineLoopInfo *loops, const MachineLoop *curloop)
|
|
: Blocks(blocks), Loops(loops), CurLoop(curloop), Downward(false) {}
|
|
};
|
|
}
|
|
|
|
// Specialize po_iterator_storage in order to prune the post-order traversal so
|
|
// it is limited to the current loop and doesn't traverse the loop back edges.
|
|
namespace llvm {
|
|
template<>
|
|
class po_iterator_storage<LoopBounds, true> {
|
|
LoopBounds &LB;
|
|
public:
|
|
po_iterator_storage(LoopBounds &lb) : LB(lb) {}
|
|
void finishPostorder(const MachineBasicBlock*) {}
|
|
|
|
bool insertEdge(const MachineBasicBlock *From, const MachineBasicBlock *To) {
|
|
// Skip already visited To blocks.
|
|
MachineTraceMetrics::TraceBlockInfo &TBI = LB.Blocks[To->getNumber()];
|
|
if (LB.Downward ? TBI.hasValidHeight() : TBI.hasValidDepth())
|
|
return false;
|
|
// Don't follow CurLoop backedges.
|
|
if (LB.CurLoop && (LB.Downward ? To : From) == LB.CurLoop->getHeader())
|
|
return false;
|
|
// Don't leave CurLoop.
|
|
if (LB.Loops->getLoopFor(To) != LB.CurLoop)
|
|
return false;
|
|
// This is a new block. The PO traversal will compute height/depth
|
|
// resources, causing us to reject new edges to To. This only works because
|
|
// we reject back-edges, so the CFG is cycle-free.
|
|
return true;
|
|
}
|
|
};
|
|
}
|
|
|
|
/// Compute the trace through MBB.
|
|
void MachineTraceMetrics::Ensemble::computeTrace(const MachineBasicBlock *MBB) {
|
|
DEBUG(dbgs() << "Computing " << getName() << " trace through BB#"
|
|
<< MBB->getNumber() << '\n');
|
|
// Set up loop bounds for the backwards post-order traversal.
|
|
LoopBounds Bounds(BlockInfo, CT.Loops, getLoopFor(MBB));
|
|
|
|
// Run an upwards post-order search for the trace start.
|
|
Bounds.Downward = false;
|
|
typedef ipo_ext_iterator<const MachineBasicBlock*, LoopBounds> UpwardPO;
|
|
for (UpwardPO I = ipo_ext_begin(MBB, Bounds), E = ipo_ext_end(MBB, Bounds);
|
|
I != E; ++I) {
|
|
DEBUG(dbgs() << " pred for BB#" << I->getNumber() << ": ");
|
|
TraceBlockInfo &TBI = BlockInfo[I->getNumber()];
|
|
// All the predecessors have been visited, pick the preferred one.
|
|
TBI.Pred = pickTracePred(*I);
|
|
DEBUG({
|
|
if (TBI.Pred)
|
|
dbgs() << "BB#" << TBI.Pred->getNumber() << '\n';
|
|
else
|
|
dbgs() << "null\n";
|
|
});
|
|
// The trace leading to I is now known, compute the depth resources.
|
|
computeDepthResources(*I);
|
|
}
|
|
|
|
// Run a downwards post-order search for the trace end.
|
|
Bounds.Downward = true;
|
|
typedef po_ext_iterator<const MachineBasicBlock*, LoopBounds> DownwardPO;
|
|
for (DownwardPO I = po_ext_begin(MBB, Bounds), E = po_ext_end(MBB, Bounds);
|
|
I != E; ++I) {
|
|
DEBUG(dbgs() << " succ for BB#" << I->getNumber() << ": ");
|
|
TraceBlockInfo &TBI = BlockInfo[I->getNumber()];
|
|
// All the successors have been visited, pick the preferred one.
|
|
TBI.Succ = pickTraceSucc(*I);
|
|
DEBUG({
|
|
if (TBI.Pred)
|
|
dbgs() << "BB#" << TBI.Succ->getNumber() << '\n';
|
|
else
|
|
dbgs() << "null\n";
|
|
});
|
|
// The trace leaving I is now known, compute the height resources.
|
|
computeHeightResources(*I);
|
|
}
|
|
}
|
|
|
|
/// Invalidate traces through BadMBB.
|
|
void
|
|
MachineTraceMetrics::Ensemble::invalidate(const MachineBasicBlock *BadMBB) {
|
|
SmallVector<const MachineBasicBlock*, 16> WorkList;
|
|
TraceBlockInfo &BadTBI = BlockInfo[BadMBB->getNumber()];
|
|
|
|
// Invalidate height resources of blocks above MBB.
|
|
if (BadTBI.hasValidHeight()) {
|
|
BadTBI.invalidateHeight();
|
|
WorkList.push_back(BadMBB);
|
|
do {
|
|
const MachineBasicBlock *MBB = WorkList.pop_back_val();
|
|
DEBUG(dbgs() << "Invalidate BB#" << MBB->getNumber() << ' ' << getName()
|
|
<< " height.\n");
|
|
// Find any MBB predecessors that have MBB as their preferred successor.
|
|
// They are the only ones that need to be invalidated.
|
|
for (MachineBasicBlock::const_pred_iterator
|
|
I = MBB->pred_begin(), E = MBB->pred_end(); I != E; ++I) {
|
|
TraceBlockInfo &TBI = BlockInfo[(*I)->getNumber()];
|
|
if (!TBI.hasValidHeight())
|
|
continue;
|
|
if (TBI.Succ == MBB) {
|
|
TBI.invalidateHeight();
|
|
WorkList.push_back(*I);
|
|
continue;
|
|
}
|
|
// Verify that TBI.Succ is actually a *I successor.
|
|
assert((!TBI.Succ || (*I)->isSuccessor(TBI.Succ)) && "CFG changed");
|
|
}
|
|
} while (!WorkList.empty());
|
|
}
|
|
|
|
// Invalidate depth resources of blocks below MBB.
|
|
if (BadTBI.hasValidDepth()) {
|
|
BadTBI.invalidateDepth();
|
|
WorkList.push_back(BadMBB);
|
|
do {
|
|
const MachineBasicBlock *MBB = WorkList.pop_back_val();
|
|
DEBUG(dbgs() << "Invalidate BB#" << MBB->getNumber() << ' ' << getName()
|
|
<< " depth.\n");
|
|
// Find any MBB successors that have MBB as their preferred predecessor.
|
|
// They are the only ones that need to be invalidated.
|
|
for (MachineBasicBlock::const_succ_iterator
|
|
I = MBB->succ_begin(), E = MBB->succ_end(); I != E; ++I) {
|
|
TraceBlockInfo &TBI = BlockInfo[(*I)->getNumber()];
|
|
if (!TBI.hasValidDepth())
|
|
continue;
|
|
if (TBI.Pred == MBB) {
|
|
TBI.invalidateDepth();
|
|
WorkList.push_back(*I);
|
|
continue;
|
|
}
|
|
// Verify that TBI.Pred is actually a *I predecessor.
|
|
assert((!TBI.Pred || (*I)->isPredecessor(TBI.Pred)) && "CFG changed");
|
|
}
|
|
} while (!WorkList.empty());
|
|
}
|
|
}
|
|
|
|
void MachineTraceMetrics::Ensemble::verify() const {
|
|
#ifndef NDEBUG
|
|
assert(BlockInfo.size() == CT.MF->getNumBlockIDs() &&
|
|
"Outdated BlockInfo size");
|
|
for (unsigned Num = 0, e = BlockInfo.size(); Num != e; ++Num) {
|
|
const TraceBlockInfo &TBI = BlockInfo[Num];
|
|
if (TBI.hasValidDepth() && TBI.Pred) {
|
|
const MachineBasicBlock *MBB = CT.MF->getBlockNumbered(Num);
|
|
assert(MBB->isPredecessor(TBI.Pred) && "CFG doesn't match trace");
|
|
assert(BlockInfo[TBI.Pred->getNumber()].hasValidDepth() &&
|
|
"Trace is broken, depth should have been invalidated.");
|
|
const MachineLoop *Loop = getLoopFor(MBB);
|
|
assert(!(Loop && MBB == Loop->getHeader()) && "Trace contains backedge");
|
|
}
|
|
if (TBI.hasValidHeight() && TBI.Succ) {
|
|
const MachineBasicBlock *MBB = CT.MF->getBlockNumbered(Num);
|
|
assert(MBB->isSuccessor(TBI.Succ) && "CFG doesn't match trace");
|
|
assert(BlockInfo[TBI.Succ->getNumber()].hasValidHeight() &&
|
|
"Trace is broken, height should have been invalidated.");
|
|
const MachineLoop *Loop = getLoopFor(MBB);
|
|
const MachineLoop *SuccLoop = getLoopFor(TBI.Succ);
|
|
assert(!(Loop && Loop == SuccLoop && TBI.Succ == Loop->getHeader()) &&
|
|
"Trace contains backedge");
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
MachineTraceMetrics::Trace
|
|
MachineTraceMetrics::Ensemble::getTrace(const MachineBasicBlock *MBB) {
|
|
// FIXME: Check cache tags, recompute as needed.
|
|
computeTrace(MBB);
|
|
return Trace(*this, BlockInfo[MBB->getNumber()]);
|
|
}
|
|
|
|
void MachineTraceMetrics::Ensemble::print(raw_ostream &OS) const {
|
|
OS << getName() << " ensemble:\n";
|
|
for (unsigned i = 0, e = BlockInfo.size(); i != e; ++i) {
|
|
OS << " BB#" << i << '\t';
|
|
BlockInfo[i].print(OS);
|
|
OS << '\n';
|
|
}
|
|
}
|
|
|
|
void MachineTraceMetrics::TraceBlockInfo::print(raw_ostream &OS) const {
|
|
if (hasValidDepth()) {
|
|
OS << "depth=" << InstrDepth;
|
|
if (Pred)
|
|
OS << " pred=BB#" << Pred->getNumber();
|
|
else
|
|
OS << " pred=null";
|
|
OS << " head=BB#" << Head;
|
|
} else
|
|
OS << "depth invalid";
|
|
OS << ", ";
|
|
if (hasValidHeight()) {
|
|
OS << "height=" << InstrHeight;
|
|
if (Succ)
|
|
OS << " succ=BB#" << Succ->getNumber();
|
|
else
|
|
OS << " succ=null";
|
|
OS << " tail=BB#" << Tail;
|
|
} else
|
|
OS << "height invalid";
|
|
}
|
|
|
|
void MachineTraceMetrics::Trace::print(raw_ostream &OS) const {
|
|
unsigned MBBNum = &TBI - &TE.BlockInfo[0];
|
|
|
|
OS << TE.getName() << " trace BB#" << TBI.Head << " --> BB#" << MBBNum
|
|
<< " --> BB#" << TBI.Tail << ':';
|
|
if (TBI.hasValidHeight() && TBI.hasValidDepth())
|
|
OS << ' ' << getInstrCount() << " instrs.";
|
|
|
|
const MachineTraceMetrics::TraceBlockInfo *Block = &TBI;
|
|
OS << "\nBB#" << MBBNum;
|
|
while (Block->hasValidDepth() && Block->Pred) {
|
|
unsigned Num = Block->Pred->getNumber();
|
|
OS << " <- BB#" << Num;
|
|
Block = &TE.BlockInfo[Num];
|
|
}
|
|
|
|
Block = &TBI;
|
|
OS << "\n ";
|
|
while (Block->hasValidHeight() && Block->Succ) {
|
|
unsigned Num = Block->Succ->getNumber();
|
|
OS << " -> BB#" << Num;
|
|
Block = &TE.BlockInfo[Num];
|
|
}
|
|
OS << '\n';
|
|
}
|