[llvm-commits] [llvm] r160796 - in /llvm/trunk: include/llvm/CodeGen/Passes.h include/llvm/InitializePasses.h lib/CodeGen/CMakeLists.txt lib/CodeGen/EarlyIfConversion.cpp lib/CodeGen/MachineTraceMetrics.cpp lib/CodeGen/MachineTraceMetrics.h

David Blaikie dblaikie at gmail.com
Thu Jul 26 11:57:05 PDT 2012


On Thu, Jul 26, 2012 at 11:38 AM, Jakob Stoklund Olesen <stoklund at 2pi.dk> wrote:
> Author: stoklund
> Date: Thu Jul 26 13:38:11 2012
> New Revision: 160796
>
> URL: http://llvm.org/viewvc/llvm-project?rev=160796&view=rev
> Log:
> Start scaffolding for a MachineTraceMetrics analysis pass.
>
> This is still a work in progress.
>
> Out-of-order CPUs usually execute instructions from multiple basic
> blocks simultaneously, so it is necessary to look at longer traces when
> estimating the performance effects of code transformations.
>
> The MachineTraceMetrics analysis will pick a typical trace through a
> given basic block and provide performance metrics for the trace. Metrics
> will include:
>
> - Instruction count through the trace.
> - Issue count per functional unit.
> - Critical path length, and per-instruction 'slack'.
>
> These metrics can be used to determine the performance limiting factor
> when executing the trace, and how it will be affected by a code
> transformation.
>
> Initially, this will be used by the early if-conversion pass.
>
> Added:
>     llvm/trunk/lib/CodeGen/MachineTraceMetrics.cpp
>     llvm/trunk/lib/CodeGen/MachineTraceMetrics.h
> Modified:
>     llvm/trunk/include/llvm/CodeGen/Passes.h
>     llvm/trunk/include/llvm/InitializePasses.h
>     llvm/trunk/lib/CodeGen/CMakeLists.txt
>     llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp
>
> Modified: llvm/trunk/include/llvm/CodeGen/Passes.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/Passes.h?rev=160796&r1=160795&r2=160796&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/CodeGen/Passes.h (original)
> +++ llvm/trunk/include/llvm/CodeGen/Passes.h Thu Jul 26 13:38:11 2012
> @@ -392,6 +392,10 @@
>    /// into tails of their predecessors.
>    extern char &TailDuplicateID;
>
> +  /// MachineTraceMetrics - This pass computes critical path and CPU resource
> +  /// usage in an ensemble of traces.
> +  extern char &MachineTraceMetricsID;
> +
>    /// EarlyIfConverter - This pass performs if-conversion on SSA form by
>    /// inserting cmov instructions.
>    extern char &EarlyIfConverterID;
>
> Modified: llvm/trunk/include/llvm/InitializePasses.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/InitializePasses.h?rev=160796&r1=160795&r2=160796&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/InitializePasses.h (original)
> +++ llvm/trunk/include/llvm/InitializePasses.h Thu Jul 26 13:38:11 2012
> @@ -172,6 +172,7 @@
>  void initializeMachineModuleInfoPass(PassRegistry&);
>  void initializeMachineSchedulerPass(PassRegistry&);
>  void initializeMachineSinkingPass(PassRegistry&);
> +void initializeMachineTraceMetricsPass(PassRegistry&);
>  void initializeMachineVerifierPassPass(PassRegistry&);
>  void initializeMemCpyOptPass(PassRegistry&);
>  void initializeMemDepPrinterPass(PassRegistry&);
>
> Modified: llvm/trunk/lib/CodeGen/CMakeLists.txt
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/CMakeLists.txt?rev=160796&r1=160795&r2=160796&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/CMakeLists.txt (original)
> +++ llvm/trunk/lib/CodeGen/CMakeLists.txt Thu Jul 26 13:38:11 2012
> @@ -61,6 +61,7 @@
>    MachineSSAUpdater.cpp
>    MachineScheduler.cpp
>    MachineSink.cpp
> +  MachineTraceMetrics.cpp
>    MachineVerifier.cpp
>    OcamlGC.cpp
>    OptimizePHIs.cpp
>
> Modified: llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp?rev=160796&r1=160795&r2=160796&view=diff
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp (original)
> +++ llvm/trunk/lib/CodeGen/EarlyIfConversion.cpp Thu Jul 26 13:38:11 2012
> @@ -17,6 +17,7 @@
>  //===----------------------------------------------------------------------===//
>
>  #define DEBUG_TYPE "early-ifcvt"
> +#include "MachineTraceMetrics.h"
>  #include "llvm/Function.h"
>  #include "llvm/ADT/BitVector.h"
>  #include "llvm/ADT/PostOrderIterator.h"
> @@ -515,6 +516,8 @@
>    MachineRegisterInfo *MRI;
>    MachineDominatorTree *DomTree;
>    MachineLoopInfo *Loops;
> +  MachineTraceMetrics *Traces;
> +  MachineTraceMetrics::Ensemble *MinInstr;
>    SSAIfConv IfConv;
>
>  public:
> @@ -527,6 +530,8 @@
>    bool tryConvertIf(MachineBasicBlock*);
>    void updateDomTree(ArrayRef<MachineBasicBlock*> Removed);
>    void updateLoops(ArrayRef<MachineBasicBlock*> Removed);
> +  void invalidateTraces();
> +  bool shouldConvertIf();
>  };
>  } // end anonymous namespace
>
> @@ -537,6 +542,7 @@
>                        "early-ifcvt", "Early If Converter", false, false)
>  INITIALIZE_PASS_DEPENDENCY(MachineBranchProbabilityInfo)
>  INITIALIZE_PASS_DEPENDENCY(MachineDominatorTree)
> +INITIALIZE_PASS_DEPENDENCY(MachineTraceMetrics)
>  INITIALIZE_PASS_END(EarlyIfConverter,
>                        "early-ifcvt", "Early If Converter", false, false)
>
> @@ -546,6 +552,8 @@
>    AU.addPreserved<MachineDominatorTree>();
>    AU.addRequired<MachineLoopInfo>();
>    AU.addPreserved<MachineLoopInfo>();
> +  AU.addRequired<MachineTraceMetrics>();
> +  AU.addPreserved<MachineTraceMetrics>();
>    MachineFunctionPass::getAnalysisUsage(AU);
>  }
>
> @@ -576,12 +584,31 @@
>      Loops->removeBlock(Removed[i]);
>  }
>
> +/// Invalidate MachineTraceMetrics before if-conversion.
> +void EarlyIfConverter::invalidateTraces() {
> +  Traces->invalidate(IfConv.Head);
> +  Traces->invalidate(IfConv.Tail);
> +  Traces->invalidate(IfConv.TBB);
> +  Traces->invalidate(IfConv.FBB);
> +}
> +
> +/// Apply cost model and heuristics to the if-conversion in IfConv.
> +/// Return true if the conversion is a good idea.
> +///
> +bool EarlyIfConverter::shouldConvertIf() {
> +  if (!MinInstr)
> +    MinInstr = Traces->getEnsemble(MachineTraceMetrics::TS_MinInstrCount);
> +  DEBUG(dbgs() << MinInstr->getTrace(IfConv.Head));
> +  return true;
> +}
> +
>  /// Attempt repeated if-conversion on MBB, return true if successful.
>  ///
>  bool EarlyIfConverter::tryConvertIf(MachineBasicBlock *MBB) {
>    bool Changed = false;
> -  while (IfConv.canConvertIf(MBB)) {
> +  while (IfConv.canConvertIf(MBB) && shouldConvertIf()) {
>      // If-convert MBB and update analyses.
> +    invalidateTraces();
>      SmallVector<MachineBasicBlock*, 4> RemovedBlocks;
>      IfConv.convertIf(RemovedBlocks);
>      Changed = true;
> @@ -600,6 +627,8 @@
>    MRI = &MF.getRegInfo();
>    DomTree = &getAnalysis<MachineDominatorTree>();
>    Loops = getAnalysisIfAvailable<MachineLoopInfo>();
> +  Traces = &getAnalysis<MachineTraceMetrics>();
> +  MinInstr = 0;
>
>    bool Changed = false;
>    IfConv.runOnMachineFunction(MF);
>
> Added: llvm/trunk/lib/CodeGen/MachineTraceMetrics.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineTraceMetrics.cpp?rev=160796&view=auto
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/MachineTraceMetrics.cpp (added)
> +++ llvm/trunk/lib/CodeGen/MachineTraceMetrics.cpp Thu Jul 26 13:38:11 2012
> @@ -0,0 +1,477 @@
> +//===- 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 &MF) {
> +  TII = MF.getTarget().getInstrInfo();
> +  TRI = MF.getTarget().getRegisterInfo();
> +  MRI = &MF.getRegInfo();
> +  Loops = &getAnalysis<MachineLoopInfo>();
> +  unsigned NumBlocks = MF.getNumBlockIDs();
> +  BlockInfo.resize(NumBlocks);
> +  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.
> +
> +/// Is MI an instruction that should be considered free because it will likely
> +/// be eliminated by later passes?
> +static bool isFree(const MachineInstr *MI) {
> +  switch(MI->getOpcode()) {
> +  default: return false;
> +  case TargetOpcode::PHI:
> +  case TargetOpcode::PROLOG_LABEL:
> +  case TargetOpcode::EH_LABEL:
> +  case TargetOpcode::GC_LABEL:
> +  case TargetOpcode::KILL:
> +  case TargetOpcode::EXTRACT_SUBREG:
> +  case TargetOpcode::INSERT_SUBREG:
> +  case TargetOpcode::IMPLICIT_DEF:
> +  case TargetOpcode::SUBREG_TO_REG:
> +  case TargetOpcode::COPY_TO_REGCLASS:
> +  case TargetOpcode::DBG_VALUE:
> +  case TargetOpcode::REG_SEQUENCE:
> +  case TargetOpcode::COPY:
> +    return true;
> +  }
> +}
> +
> +/// 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 (isFree(MI))
> +      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() {}
> +
> +MachineLoop*
> +MachineTraceMetrics::Ensemble::getLoopFor(const MachineBasicBlock *MBB) {
> +  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;
> +    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;
> +}
> +
> +// 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)
> +    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;
> +}
> +
> +// 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() { 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;
> +  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;
> +    const MachineTraceMetrics::TraceBlockInfo *PredTBI =
> +      getDepthResources(Pred);
> +    // Ignore invalidated predecessors. This never happens on the first scan,
> +    // but if we rejected this predecessor earlier, it won't be revalidated.
> +    if (!PredTBI)
> +      continue;
> +    // Don't consider predecessors in other loops.
> +    if (getLoopFor(Pred) != CurLoop)
> +      continue;
> +    // 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;
> +  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;
> +    const MachineTraceMetrics::TraceBlockInfo *SuccTBI =
> +      getHeightResources(Succ);
> +    // Ignore invalidated successors.
> +    if (!SuccTBI)
> +      continue;
> +    // Don't consider back-edges.
> +    if (CurLoop && Succ == CurLoop->getHeader())
> +      continue;
> +    // Don't consider successors in other loops.
> +    if (getLoopFor(Succ) != CurLoop)
> +      continue;
> +    // 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);
> +}
> +
> +//===----------------------------------------------------------------------===//
> +//                               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()];

This variable is unused in release builds.

> +    // All the successors have been visited, pick the preferred one.
> +    BlockInfo[I->getNumber()].Succ = pickTraceSucc(*I);

Did you intend to use it here? (TBI.Succ = ...)

> +    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() && TBI.Succ == MBB) {
> +          TBI.invalidateHeight();
> +          WorkList.push_back(*I);
> +        }
> +      }
> +    } 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() && TBI.Pred == MBB) {
> +          TBI.invalidateDepth();
> +          WorkList.push_back(*I);
> +        }
> +      }
> +    } while (!WorkList.empty());
> +  }
> +}
> +
> +
> +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::Trace::print(raw_ostream &OS) const {
> +  OS << TE.getName() << " trace:";
> +  if (TBI.hasValidHeight() && TBI.hasValidDepth())
> +    OS << ' ' << getInstrCount() << " instrs.";
> +
> +  const MachineTraceMetrics::TraceBlockInfo *Block = &TBI;
> +  OS << "\n *";
> +  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';
> +}
>
> Added: llvm/trunk/lib/CodeGen/MachineTraceMetrics.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/MachineTraceMetrics.h?rev=160796&view=auto
> ==============================================================================
> --- llvm/trunk/lib/CodeGen/MachineTraceMetrics.h (added)
> +++ llvm/trunk/lib/CodeGen/MachineTraceMetrics.h Thu Jul 26 13:38:11 2012
> @@ -0,0 +1,218 @@
> +//===- lib/CodeGen/MachineTraceMetrics.h - Super-scalar metrics -*- C++ -*-===//
> +//
> +//                     The LLVM Compiler Infrastructure
> +//
> +// This file is distributed under the University of Illinois Open Source
> +// License. See LICENSE.TXT for details.
> +//
> +//===----------------------------------------------------------------------===//
> +//
> +// This file defines the interface for the MachineTraceMetrics analysis pass
> +// that estimates CPU resource usage and critical data dependency paths through
> +// preferred traces. This is useful for super-scalar CPUs where execution speed
> +// can be limited both by data dependencies and by limited execution resources.
> +//
> +// Out-of-order CPUs will often be executing instructions from multiple basic
> +// blocks at the same time. This makes it difficult to estimate the resource
> +// usage accurately in a single basic block. Resources can be estimated better
> +// by looking at a trace through the current basic block.
> +//
> +// For every block, the MachineTraceMetrics pass will pick a preferred trace
> +// that passes through the block. The trace is chosen based on loop structure,
> +// branch probabilities, and resource usage. The intention is to pick likely
> +// traces that would be the most affected by code transformations.
> +//
> +// It is expensive to compute a full arbitrary trace for every block, so to
> +// save some computations, traces are chosen to be convergent. This means that
> +// if the traces through basic blocks A and B ever cross when moving away from
> +// A and B, they never diverge again. This applies in both directions - If the
> +// traces meet above A and B, they won't diverge when going further back.
> +//
> +// Traces tend to align with loops. The trace through a block in an inner loop
> +// will begin at the loop entry block and end at a back edge. If there are
> +// nested loops, the trace may begin and end at those instead.
> +//
> +// For each trace, we compute the critical path length, which is the number of
> +// cycles required to execute the trace when execution is limited by data
> +// dependencies only. We also compute the resource height, which is the number
> +// of cycles required to execute all instructions in the trace when ignoring
> +// data dependencies.
> +//
> +// Every instruction in the current block has a slack - the number of cycles
> +// execution of the instruction can be delayed without extending the critical
> +// path.
> +//
> +//===----------------------------------------------------------------------===//
> +
> +#ifndef LLVM_CODEGEN_MACHINE_TRACE_METRICS_H
> +#define LLVM_CODEGEN_MACHINE_TRACE_METRICS_H
> +
> +#include "llvm/ADT/SmallVector.h"
> +#include "llvm/CodeGen/MachineFunctionPass.h"
> +
> +namespace llvm {
> +
> +class TargetInstrInfo;
> +class TargetRegisterInfo;
> +class MachineBasicBlock;
> +class MachineRegisterInfo;
> +class MachineLoopInfo;
> +class MachineLoop;
> +class raw_ostream;
> +
> +class MachineTraceMetrics : public MachineFunctionPass {
> +  const TargetInstrInfo *TII;
> +  const TargetRegisterInfo *TRI;
> +  const MachineRegisterInfo *MRI;
> +  const MachineLoopInfo *Loops;
> +
> +public:
> +  class Ensemble;
> +  class Trace;
> +  static char ID;
> +  MachineTraceMetrics();
> +  void getAnalysisUsage(AnalysisUsage&) const;
> +  bool runOnMachineFunction(MachineFunction&);
> +  void releaseMemory();
> +
> +  friend class Ensemble;
> +  friend class Trace;
> +
> +  /// Per-basic block information that doesn't depend on the trace through the
> +  /// block.
> +  struct FixedBlockInfo {
> +    /// The number of non-trivial instructions in the block.
> +    /// Doesn't count PHI and COPY instructions that are likely to be removed.
> +    unsigned InstrCount;
> +
> +    /// True when the block contains calls.
> +    bool HasCalls;
> +
> +    FixedBlockInfo() : InstrCount(~0u), HasCalls(false) {}
> +
> +    /// Returns true when resource information for this block has been computed.
> +    bool hasResources() const { return InstrCount != ~0u; }
> +
> +    /// Invalidate resource information.
> +    void invalidate() { InstrCount = ~0u; }
> +  };
> +
> +  /// Get the fixed resource information about MBB. Compute it on demand.
> +  const FixedBlockInfo *getResources(const MachineBasicBlock*);
> +
> +  /// Per-basic block information that relates to a specific trace through the
> +  /// block. Convergent traces means that only one of these is required per
> +  /// block in a trace ensemble.
> +  struct TraceBlockInfo {
> +    /// Trace predecessor, or NULL for the first block in the trace.
> +    const MachineBasicBlock *Pred;
> +
> +    /// Trace successor, or NULL for the last block in the trace.
> +    const MachineBasicBlock *Succ;
> +
> +    /// Accumulated number of instructions in the trace above this block.
> +    /// Does not include instructions in this block.
> +    unsigned InstrDepth;
> +
> +    /// Accumulated number of instructions in the trace below this block.
> +    /// Includes instructions in this block.
> +    unsigned InstrHeight;
> +
> +    TraceBlockInfo() : Pred(0), Succ(0), InstrDepth(~0u), InstrHeight(~0u) {}
> +
> +    /// Returns true if the depth resources have been computed from the trace
> +    /// above this block.
> +    bool hasValidDepth() const { return InstrDepth != ~0u; }
> +
> +    /// Returns true if the height resources have been computed from the trace
> +    /// below this block.
> +    bool hasValidHeight() const { return InstrHeight != ~0u; }
> +
> +    /// Invalidate depth resources when some block above this one has changed.
> +    void invalidateDepth() { InstrDepth = ~0u; }
> +
> +    /// Invalidate height resources when a block below this one has changed.
> +    void invalidateHeight() { InstrHeight = ~0u; }
> +  };
> +
> +  /// A trace represents a plausible sequence of executed basic blocks that
> +  /// passes through the current basic block one. The Trace class serves as a
> +  /// handle to internal cached data structures.
> +  class Trace {
> +    Ensemble &TE;
> +    TraceBlockInfo &TBI;
> +
> +  public:
> +    explicit Trace(Ensemble &te, TraceBlockInfo &tbi) : TE(te), TBI(tbi) {}
> +    void print(raw_ostream&) const;
> +
> +    /// Compute the total number of instructions in the trace.
> +    unsigned getInstrCount() const {
> +      return TBI.InstrDepth + TBI.InstrHeight;
> +    }
> +  };
> +
> +  /// A trace ensemble is a collection of traces selected using the same
> +  /// strategy, for example 'minimum resource height'. There is one trace for
> +  /// every block in the function.
> +  class Ensemble {
> +    SmallVector<TraceBlockInfo, 4> BlockInfo;
> +    friend class Trace;
> +
> +    void computeTrace(const MachineBasicBlock*);
> +    void computeDepthResources(const MachineBasicBlock*);
> +    void computeHeightResources(const MachineBasicBlock*);
> +
> +  protected:
> +    MachineTraceMetrics &CT;
> +    virtual const MachineBasicBlock *pickTracePred(const MachineBasicBlock*) =0;
> +    virtual const MachineBasicBlock *pickTraceSucc(const MachineBasicBlock*) =0;
> +    explicit Ensemble(MachineTraceMetrics*);
> +    MachineLoop *getLoopFor(const MachineBasicBlock*);
> +    const TraceBlockInfo *getDepthResources(const MachineBasicBlock*) const;
> +    const TraceBlockInfo *getHeightResources(const MachineBasicBlock*) const;
> +
> +  public:
> +    virtual ~Ensemble();
> +    virtual const char *getName() =0;
> +    void invalidate(const MachineBasicBlock *MBB);
> +
> +    /// Get the trace that passes through MBB.
> +    /// The trace is computed on demand.
> +    Trace getTrace(const MachineBasicBlock *MBB);
> +  };
> +
> +  /// Strategies for selecting traces.
> +  enum Strategy {
> +    /// Select the trace through a block that has the fewest instructions.
> +    TS_MinInstrCount,
> +
> +    TS_NumStrategies
> +  };
> +
> +  /// Get the trace ensemble representing the given trace selection strategy.
> +  /// The returned Ensemble object is owned by the MachineTraceMetrics analysis,
> +  /// and valid for the lifetime of the analysis pass.
> +  Ensemble *getEnsemble(Strategy);
> +
> +  /// Invalidate cached information about MBB. This must be called *before* MBB
> +  /// is erased, or the CFG is otherwise changed.
> +  void invalidate(const MachineBasicBlock *MBB);
> +
> +private:
> +  // One entry per basic block, indexed by block number.
> +  SmallVector<FixedBlockInfo, 4> BlockInfo;
> +
> +  // One ensemble per strategy.
> +  Ensemble* Ensembles[TS_NumStrategies];
> +};
> +
> +inline raw_ostream &operator<<(raw_ostream &OS,
> +                               const MachineTraceMetrics::Trace &Tr) {
> +  Tr.print(OS);
> +  return OS;
> +}
> +
> +} // end namespace llvm
> +
> +#endif
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits



More information about the llvm-commits mailing list