Skip to content
RegAllocLinearScan.cpp 55.1 KiB
Newer Older
//===-- RegAllocLinearScan.cpp - Linear Scan register allocator -----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a linear scan register allocator.
//
//===----------------------------------------------------------------------===//
#include "Spiller.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
David Greene's avatar
 
David Greene committed
#include "llvm/CodeGen/RegisterCoalescer.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/SmallSet.h"
Reid Spencer's avatar
Reid Spencer committed
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
Duraid Madina's avatar
Duraid Madina committed
#include <memory>
Jeff Cohen's avatar
Jeff Cohen committed
#include <cmath>
STATISTIC(NumIters     , "Number of iterations performed");
STATISTIC(NumBacktracks, "Number of times we had to backtrack");
STATISTIC(NumCoalesce,   "Number of copies coalesced");
STATISTIC(NumDowngrade,  "Number of registers downgraded");
static cl::opt<bool>
NewHeuristic("new-spilling-heuristic",
             cl::desc("Use new spilling heuristic"),
             cl::init(false), cl::Hidden);

static cl::opt<bool>
PreSplitIntervals("pre-alloc-split",
                  cl::desc("Pre-register allocation live interval splitting"),
                  cl::init(false), cl::Hidden);

static cl::opt<bool>
TrivCoalesceEnds("trivial-coalesce-ends",
                  cl::desc("Attempt trivial coalescing of interval ends"),
                  cl::init(false), cl::Hidden);

static RegisterRegAlloc
linearscanRegAlloc("linearscan", "linear scan register allocator",
                   createLinearScanRegisterAllocator);
namespace {
David Greene's avatar
 
David Greene committed
  // When we allocate a register, add it to a fixed-size queue of
  // registers to skip in subsequent allocations. This trades a small
  // amount of register pressure and increased spills for flexibility in
  // the post-pass scheduler.
  //
  // Note that in a the number of registers used for reloading spills
  // will be one greater than the value of this option.
  //
  // One big limitation of this is that it doesn't differentiate between
  // different register classes. So on x86-64, if there is xmm register
  // pressure, it can caused fewer GPRs to be held in the queue.
  static cl::opt<unsigned>
  NumRecentlyUsedRegs("linearscan-skip-count",
Eric Christopher's avatar
Eric Christopher committed
                      cl::desc("Number of registers for linearscan to remember"
                               "to skip."),
David Greene's avatar
 
David Greene committed
                      cl::init(0),
                      cl::Hidden);
  struct RALinScan : public MachineFunctionPass {
Devang Patel's avatar
Devang Patel committed
    static char ID;
    RALinScan() : MachineFunctionPass(ID) {
      initializeLiveIntervalsPass(*PassRegistry::getPassRegistry());
      initializeStrongPHIEliminationPass(*PassRegistry::getPassRegistry());
      initializeRegisterCoalescerAnalysisGroup(
        *PassRegistry::getPassRegistry());
      initializeCalculateSpillWeightsPass(*PassRegistry::getPassRegistry());
      initializePreAllocSplittingPass(*PassRegistry::getPassRegistry());
      initializeLiveStacksPass(*PassRegistry::getPassRegistry());
      initializeMachineLoopInfoPass(*PassRegistry::getPassRegistry());
      initializeVirtRegMapPass(*PassRegistry::getPassRegistry());
      initializeMachineDominatorTreePass(*PassRegistry::getPassRegistry());
      
David Greene's avatar
 
David Greene committed
      // Initialize the queue to record recently-used registers.
      if (NumRecentlyUsedRegs > 0)
        RecentRegs.resize(NumRecentlyUsedRegs, 0);
David Greene's avatar
 
David Greene committed
      RecentNext = RecentRegs.begin();
David Greene's avatar
 
David Greene committed
    }
    typedef std::pair<LiveInterval*, LiveInterval::iterator> IntervalPtr;
    typedef SmallVector<IntervalPtr, 32> IntervalPtrs;
    /// RelatedRegClasses - This structure is built the first time a function is
    /// compiled, and keeps track of which register classes have registers that
    /// belong to multiple classes or have aliases that are in other classes.
    EquivalenceClasses<const TargetRegisterClass*> RelatedRegClasses;
    DenseMap<unsigned, const TargetRegisterClass*> OneClassForEachPhysReg;
    // NextReloadMap - For each register in the map, it maps to the another
    // register which is defined by a reload from the same stack slot and
    // both reloads are in the same basic block.
    DenseMap<unsigned, unsigned> NextReloadMap;

    // DowngradedRegs - A set of registers which are being "downgraded", i.e.
    // un-favored for allocation.
    SmallSet<unsigned, 8> DowngradedRegs;

    // DowngradeMap - A map from virtual registers to physical registers being
    // downgraded for the virtual registers.
    DenseMap<unsigned, unsigned> DowngradeMap;

    MachineFunction* mf_;
    const TargetMachine* tm_;
    const TargetRegisterInfo* tri_;
    const TargetInstrInfo* tii_;
    BitVector allocatableRegs_;
    LiveIntervals* li_;

    /// handled_ - Intervals are added to the handled_ set in the order of their
    /// start value.  This is uses for backtracking.
    std::vector<LiveInterval*> handled_;

    /// fixed_ - Intervals that correspond to machine registers.
    ///
    IntervalPtrs fixed_;

    /// active_ - Intervals that are currently being processed, and which have a
    /// live range active for the current point.
    IntervalPtrs active_;

    /// inactive_ - Intervals that are currently being processed, but which have
    /// a hold at the current point.
    IntervalPtrs inactive_;

    typedef std::priority_queue<LiveInterval*,
                                greater_ptr<LiveInterval> > IntervalHeap;
    IntervalHeap unhandled_;

    /// regUse_ - Tracks register usage.
    SmallVector<unsigned, 32> regUse_;
    SmallVector<unsigned, 32> regUseBackUp_;

    /// vrm_ - Tracks register assignments.
    VirtRegMap* vrm_;
    std::auto_ptr<VirtRegRewriter> rewriter_;
    std::auto_ptr<Spiller> spiller_;

David Greene's avatar
 
David Greene committed
    // The queue of recently-used registers.
David Greene's avatar
 
David Greene committed
    SmallVector<unsigned, 4> RecentRegs;
    SmallVector<unsigned, 4>::iterator RecentNext;
David Greene's avatar
 
David Greene committed

    // Record that we just picked this register.
    void recordRecentlyUsed(unsigned reg) {
      assert(reg != 0 && "Recently used register is NOREG!");
      if (!RecentRegs.empty()) {
David Greene's avatar
 
David Greene committed
        *RecentNext++ = reg;
        if (RecentNext == RecentRegs.end())
          RecentNext = RecentRegs.begin();
David Greene's avatar
 
David Greene committed
      }
    }

  public:
    virtual const char* getPassName() const {
      return "Linear Scan Register Allocator";
    }
    virtual void getAnalysisUsage(AnalysisUsage &AU) const {
      AU.addRequired<LiveIntervals>();
Lang Hames's avatar
Lang Hames committed
      AU.addPreserved<SlotIndexes>();
      if (StrongPHIElim)
        AU.addRequiredID(StrongPHIEliminationID);
David Greene's avatar
 
David Greene committed
      // Make sure PassManager knows which analyses to make available
      // to coalescing and which analyses coalescing invalidates.
Loading
Loading full blame...