diff options
Diffstat (limited to 'lib/CodeGen/RegAllocLinearScan.cpp')
| -rw-r--r-- | lib/CodeGen/RegAllocLinearScan.cpp | 74 | 
1 files changed, 65 insertions, 9 deletions
| diff --git a/lib/CodeGen/RegAllocLinearScan.cpp b/lib/CodeGen/RegAllocLinearScan.cpp index fff50da947c1..4ff512932f8e 100644 --- a/lib/CodeGen/RegAllocLinearScan.cpp +++ b/lib/CodeGen/RegAllocLinearScan.cpp @@ -64,9 +64,31 @@ linearscanRegAlloc("linearscan", "linear scan register allocator",                     createLinearScanRegisterAllocator);  namespace { +  // 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", +                      cl::desc("Number of registers for linearscan to remember to skip."), +                      cl::init(0), +                      cl::Hidden); +     struct RALinScan : public MachineFunctionPass {      static char ID; -    RALinScan() : MachineFunctionPass(&ID) {} +    RALinScan() : MachineFunctionPass(&ID) { +      // Initialize the queue to record recently-used registers. +      if (NumRecentlyUsedRegs > 0) +        RecentRegs.resize(NumRecentlyUsedRegs, 0); +      RecentNext = RecentRegs.begin(); +    }      typedef std::pair<LiveInterval*, LiveInterval::iterator> IntervalPtr;      typedef SmallVector<IntervalPtr, 32> IntervalPtrs; @@ -132,6 +154,20 @@ namespace {      std::auto_ptr<Spiller> spiller_; +    // The queue of recently-used registers. +    SmallVector<unsigned, 4> RecentRegs; +    SmallVector<unsigned, 4>::iterator RecentNext; + +    // Record that we just picked this register. +    void recordRecentlyUsed(unsigned reg) { +      assert(reg != 0 && "Recently used register is NOREG!"); +      if (!RecentRegs.empty()) { +        *RecentNext++ = reg; +        if (RecentNext == RecentRegs.end()) +          RecentNext = RecentRegs.begin(); +      } +    } +    public:      virtual const char* getPassName() const {        return "Linear Scan Register Allocator"; @@ -161,6 +197,12 @@ namespace {      /// runOnMachineFunction - register allocate the whole function      bool runOnMachineFunction(MachineFunction&); +    // Determine if we skip this register due to its being recently used. +    bool isRecentlyUsed(unsigned reg) const { +      return std::find(RecentRegs.begin(), RecentRegs.end(), reg) != +             RecentRegs.end(); +    } +    private:      /// linearScan - the linear scan algorithm      void linearScan(); @@ -436,7 +478,7 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) {    vrm_ = &getAnalysis<VirtRegMap>();    if (!rewriter_.get()) rewriter_.reset(createVirtRegRewriter()); -  spiller_.reset(createSpiller(mf_, li_, ls_, loopInfo, vrm_)); +  spiller_.reset(createSpiller(mf_, li_, loopInfo, vrm_));    initIntervalSets(); @@ -833,9 +875,15 @@ void RALinScan::findIntervalsToSpill(LiveInterval *cur,  namespace {    struct WeightCompare { +  private: +    const RALinScan &Allocator; + +  public: +    WeightCompare(const RALinScan &Alloc) : Allocator(Alloc) {}; +      typedef std::pair<unsigned, float> RegWeightPair;      bool operator()(const RegWeightPair &LHS, const RegWeightPair &RHS) const { -      return LHS.second < RHS.second; +      return LHS.second < RHS.second && !Allocator.isRecentlyUsed(LHS.first);      }    };  } @@ -1079,7 +1127,8 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) {             e = RC->allocation_order_end(*mf_); i != e; ++i) {        unsigned reg = *i;        float regWeight = SpillWeights[reg]; -      if (minWeight > regWeight) +      // Skip recently allocated registers. +      if (minWeight > regWeight && !isRecentlyUsed(reg))          Found = true;        RegsWeights.push_back(std::make_pair(reg, regWeight));      } @@ -1097,7 +1146,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur) {    }    // Sort all potential spill candidates by weight. -  std::sort(RegsWeights.begin(), RegsWeights.end(), WeightCompare()); +  std::sort(RegsWeights.begin(), RegsWeights.end(), WeightCompare(*this));    minReg = RegsWeights[0].first;    minWeight = RegsWeights[0].second;    if (minWeight == HUGE_VALF) { @@ -1360,7 +1409,8 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,      // Ignore "downgraded" registers.      if (SkipDGRegs && DowngradedRegs.count(Reg))        continue; -    if (isRegAvail(Reg)) { +    // Skip recently allocated registers. +    if (isRegAvail(Reg) && !isRecentlyUsed(Reg)) {        FreeReg = Reg;        if (FreeReg < inactiveCounts.size())          FreeRegInactiveCount = inactiveCounts[FreeReg]; @@ -1372,9 +1422,12 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,    // If there are no free regs, or if this reg has the max inactive count,    // return this register. -  if (FreeReg == 0 || FreeRegInactiveCount == MaxInactiveCount) +  if (FreeReg == 0 || FreeRegInactiveCount == MaxInactiveCount) { +    // Remember what register we picked so we can skip it next time. +    if (FreeReg != 0) recordRecentlyUsed(FreeReg);      return FreeReg; -  +  } +    // Continue scanning the registers, looking for the one with the highest    // inactive count.  Alkis found that this reduced register pressure very    // slightly on X86 (in rev 1.94 of this file), though this should probably be @@ -1385,7 +1438,7 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,      if (SkipDGRegs && DowngradedRegs.count(Reg))        continue;      if (isRegAvail(Reg) && Reg < inactiveCounts.size() && -        FreeRegInactiveCount < inactiveCounts[Reg]) { +        FreeRegInactiveCount < inactiveCounts[Reg] && !isRecentlyUsed(Reg)) {        FreeReg = Reg;        FreeRegInactiveCount = inactiveCounts[Reg];        if (FreeRegInactiveCount == MaxInactiveCount) @@ -1393,6 +1446,9 @@ unsigned RALinScan::getFreePhysReg(LiveInterval* cur,      }    } +  // Remember what register we picked so we can skip it next time. +  recordRecentlyUsed(FreeReg); +    return FreeReg;  } | 
