mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +00:00 
			
		
		
		
	The spillers can pluck the analyses they need from the pass reference. Switch some never-null pointers to references. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108969 91177308-0d34-0410-b5e6-96231b3b80d8
		
			
				
	
	
		
			279 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			279 lines
		
	
	
		
			9.7 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //===---------- SplitKit.cpp - Toolkit for splitting live ranges ----------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This file contains the SplitAnalysis class as well as mutator functions for
 | |
| // live range splitting.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #define DEBUG_TYPE "splitter"
 | |
| #include "SplitKit.h"
 | |
| #include "llvm/CodeGen/LiveIntervalAnalysis.h"
 | |
| #include "llvm/CodeGen/MachineFunctionPass.h"
 | |
| #include "llvm/CodeGen/MachineLoopInfo.h"
 | |
| #include "llvm/CodeGen/MachineRegisterInfo.h"
 | |
| #include "llvm/Support/CommandLine.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| #include "llvm/Target/TargetInstrInfo.h"
 | |
| #include "llvm/Target/TargetMachine.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| static cl::opt<bool>
 | |
| AllowSplit("spiller-splits-edges",
 | |
|            cl::desc("Allow critical edge splitting during spilling"));
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| //                                 Split Analysis
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| SplitAnalysis::SplitAnalysis(const MachineFunction &mf,
 | |
|                              const LiveIntervals &lis,
 | |
|                              const MachineLoopInfo &mli)
 | |
|   : mf_(mf),
 | |
|     lis_(lis),
 | |
|     loops_(mli),
 | |
|     tii_(*mf.getTarget().getInstrInfo()),
 | |
|     curli_(0) {}
 | |
| 
 | |
| void SplitAnalysis::clear() {
 | |
|   usingInstrs_.clear();
 | |
|   usingBlocks_.clear();
 | |
|   usingLoops_.clear();
 | |
| }
 | |
| 
 | |
| bool SplitAnalysis::canAnalyzeBranch(const MachineBasicBlock *MBB) {
 | |
|   MachineBasicBlock *T, *F;
 | |
|   SmallVector<MachineOperand, 4> Cond;
 | |
|   return !tii_.AnalyzeBranch(const_cast<MachineBasicBlock&>(*MBB), T, F, Cond);
 | |
| }
 | |
| 
 | |
| /// analyzeUses - Count instructions, basic blocks, and loops using curli.
 | |
| void SplitAnalysis::analyzeUses() {
 | |
|   const MachineRegisterInfo &MRI = mf_.getRegInfo();
 | |
|   for (MachineRegisterInfo::reg_iterator I = MRI.reg_begin(curli_->reg);
 | |
|        MachineInstr *MI = I.skipInstruction();) {
 | |
|     if (MI->isDebugValue() || !usingInstrs_.insert(MI))
 | |
|       continue;
 | |
|     MachineBasicBlock *MBB = MI->getParent();
 | |
|     if (usingBlocks_[MBB]++)
 | |
|       continue;
 | |
|     if (MachineLoop *Loop = loops_.getLoopFor(MBB))
 | |
|       usingLoops_.insert(Loop);
 | |
|   }
 | |
|   DEBUG(dbgs() << "Counted "
 | |
|                << usingInstrs_.size() << " instrs, "
 | |
|                << usingBlocks_.size() << " blocks, "
 | |
|                << usingLoops_.size()  << " loops in "
 | |
|                << *curli_ << "\n");
 | |
| }
 | |
| 
 | |
| // Get three sets of basic blocks surrounding a loop: Blocks inside the loop,
 | |
| // predecessor blocks, and exit blocks.
 | |
| void SplitAnalysis::getLoopBlocks(const MachineLoop *Loop, LoopBlocks &Blocks) {
 | |
|   Blocks.clear();
 | |
| 
 | |
|   // Blocks in the loop.
 | |
|   Blocks.Loop.insert(Loop->block_begin(), Loop->block_end());
 | |
| 
 | |
|   // Predecessor blocks.
 | |
|   const MachineBasicBlock *Header = Loop->getHeader();
 | |
|   for (MachineBasicBlock::const_pred_iterator I = Header->pred_begin(),
 | |
|        E = Header->pred_end(); I != E; ++I)
 | |
|     if (!Blocks.Loop.count(*I))
 | |
|       Blocks.Preds.insert(*I);
 | |
| 
 | |
|   // Exit blocks.
 | |
|   for (MachineLoop::block_iterator I = Loop->block_begin(),
 | |
|        E = Loop->block_end(); I != E; ++I) {
 | |
|     const MachineBasicBlock *MBB = *I;
 | |
|     for (MachineBasicBlock::const_succ_iterator SI = MBB->succ_begin(),
 | |
|        SE = MBB->succ_end(); SI != SE; ++SI)
 | |
|       if (!Blocks.Loop.count(*SI))
 | |
|         Blocks.Exits.insert(*SI);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in
 | |
| /// and around the Loop.
 | |
| SplitAnalysis::LoopPeripheralUse SplitAnalysis::
 | |
| analyzeLoopPeripheralUse(const SplitAnalysis::LoopBlocks &Blocks) {
 | |
|   LoopPeripheralUse use = ContainedInLoop;
 | |
|   for (BlockCountMap::iterator I = usingBlocks_.begin(), E = usingBlocks_.end();
 | |
|        I != E; ++I) {
 | |
|     const MachineBasicBlock *MBB = I->first;
 | |
|     // Is this a peripheral block?
 | |
|     if (use < MultiPeripheral &&
 | |
|         (Blocks.Preds.count(MBB) || Blocks.Exits.count(MBB))) {
 | |
|       if (I->second > 1) use = MultiPeripheral;
 | |
|       else               use = SinglePeripheral;
 | |
|       continue;
 | |
|     }
 | |
|     // Is it a loop block?
 | |
|     if (Blocks.Loop.count(MBB))
 | |
|       continue;
 | |
|     // It must be an unrelated block.
 | |
|     return OutsideLoop;
 | |
|   }
 | |
|   return use;
 | |
| }
 | |
| 
 | |
| /// getCriticalExits - It may be necessary to partially break critical edges
 | |
| /// leaving the loop if an exit block has phi uses of curli. Collect the exit
 | |
| /// blocks that need special treatment into CriticalExits.
 | |
| void SplitAnalysis::getCriticalExits(const SplitAnalysis::LoopBlocks &Blocks,
 | |
|                                      BlockPtrSet &CriticalExits) {
 | |
|   CriticalExits.clear();
 | |
| 
 | |
|   // A critical exit block contains a phi def of curli, and has a predecessor
 | |
|   // that is not in the loop nor a loop predecessor.
 | |
|   // For such an exit block, the edges carrying the new variable must be moved
 | |
|   // to a new pre-exit block.
 | |
|   for (BlockPtrSet::iterator I = Blocks.Exits.begin(), E = Blocks.Exits.end();
 | |
|        I != E; ++I) {
 | |
|     const MachineBasicBlock *Succ = *I;
 | |
|     SlotIndex SuccIdx = lis_.getMBBStartIdx(Succ);
 | |
|     VNInfo *SuccVNI = curli_->getVNInfoAt(SuccIdx);
 | |
|     // This exit may not have curli live in at all. No need to split.
 | |
|     if (!SuccVNI)
 | |
|       continue;
 | |
|     // If this is not a PHI def, it is either using a value from before the
 | |
|     // loop, or a value defined inside the loop. Both are safe.
 | |
|     if (!SuccVNI->isPHIDef() || SuccVNI->def.getBaseIndex() != SuccIdx)
 | |
|       continue;
 | |
|     // This exit block does have a PHI. Does it also have a predecessor that is
 | |
|     // not a loop block or loop predecessor?
 | |
|     for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(),
 | |
|          PE = Succ->pred_end(); PI != PE; ++PI) {
 | |
|       const MachineBasicBlock *Pred = *PI;
 | |
|       if (Blocks.Loop.count(Pred) || Blocks.Preds.count(Pred))
 | |
|         continue;
 | |
|       // This is a critical exit block, and we need to split the exit edge.
 | |
|       CriticalExits.insert(Succ);
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /// canSplitCriticalExits - Return true if it is possible to insert new exit
 | |
| /// blocks before the blocks in CriticalExits.
 | |
| bool
 | |
| SplitAnalysis::canSplitCriticalExits(const SplitAnalysis::LoopBlocks &Blocks,
 | |
|                                      BlockPtrSet &CriticalExits) {
 | |
|   // If we don't allow critical edge splitting, require no critical exits.
 | |
|   if (!AllowSplit)
 | |
|     return CriticalExits.empty();
 | |
| 
 | |
|   for (BlockPtrSet::iterator I = CriticalExits.begin(), E = CriticalExits.end();
 | |
|        I != E; ++I) {
 | |
|     const MachineBasicBlock *Succ = *I;
 | |
|     // We want to insert a new pre-exit MBB before Succ, and change all the
 | |
|     // in-loop blocks to branch to the pre-exit instead of Succ.
 | |
|     // Check that all the in-loop predecessors can be changed.
 | |
|     for (MachineBasicBlock::const_pred_iterator PI = Succ->pred_begin(),
 | |
|          PE = Succ->pred_end(); PI != PE; ++PI) {
 | |
|       const MachineBasicBlock *Pred = *PI;
 | |
|       // The external predecessors won't be altered.
 | |
|       if (!Blocks.Loop.count(Pred) && !Blocks.Preds.count(Pred))
 | |
|         continue;
 | |
|       if (!canAnalyzeBranch(Pred))
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     // If Succ's layout predecessor falls through, that too must be analyzable.
 | |
|     // We need to insert the pre-exit block in the gap.
 | |
|     MachineFunction::const_iterator MFI = Succ;
 | |
|     if (MFI == mf_.begin())
 | |
|       continue;
 | |
|     if (!canAnalyzeBranch(--MFI))
 | |
|       return false;
 | |
|   }
 | |
|   // No problems found.
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void SplitAnalysis::analyze(const LiveInterval *li) {
 | |
|   clear();
 | |
|   curli_ = li;
 | |
|   analyzeUses();
 | |
| }
 | |
| 
 | |
| const MachineLoop *SplitAnalysis::getBestSplitLoop() {
 | |
|   assert(curli_ && "Call analyze() before getBestSplitLoop");
 | |
|   if (usingLoops_.empty())
 | |
|     return 0;
 | |
| 
 | |
|   LoopPtrSet Loops, SecondLoops;
 | |
|   LoopBlocks Blocks;
 | |
|   BlockPtrSet CriticalExits;
 | |
| 
 | |
|   // Find first-class and second class candidate loops.
 | |
|   // We prefer to split around loops where curli is used outside the periphery.
 | |
|   for (LoopPtrSet::const_iterator I = usingLoops_.begin(),
 | |
|        E = usingLoops_.end(); I != E; ++I) {
 | |
|     getLoopBlocks(*I, Blocks);
 | |
|     LoopPtrSet *LPS = 0;
 | |
|     switch(analyzeLoopPeripheralUse(Blocks)) {
 | |
|     case OutsideLoop:
 | |
|       LPS = &Loops;
 | |
|       break;
 | |
|     case MultiPeripheral:
 | |
|       LPS = &SecondLoops;
 | |
|       break;
 | |
|     case ContainedInLoop:
 | |
|       DEBUG(dbgs() << "ContainedInLoop: " << **I);
 | |
|       continue;
 | |
|     case SinglePeripheral:
 | |
|       DEBUG(dbgs() << "SinglePeripheral: " << **I);
 | |
|       continue;
 | |
|     }
 | |
|     // Will it be possible to split around this loop?
 | |
|     getCriticalExits(Blocks, CriticalExits);
 | |
|     DEBUG(dbgs() << CriticalExits.size() << " critical exits: " << **I);
 | |
|     if (!canSplitCriticalExits(Blocks, CriticalExits))
 | |
|       continue;
 | |
|     // This is a possible split.
 | |
|     assert(LPS);
 | |
|     LPS->insert(*I);
 | |
|   }
 | |
| 
 | |
|   DEBUG(dbgs() << "Got " << Loops.size() << " + " << SecondLoops.size()
 | |
|                << " candidate loops\n");
 | |
| 
 | |
|   // If there are no first class loops available, look at second class loops.
 | |
|   if (Loops.empty())
 | |
|     Loops = SecondLoops;
 | |
| 
 | |
|   if (Loops.empty())
 | |
|     return 0;
 | |
| 
 | |
|   // Pick the earliest loop.
 | |
|   // FIXME: Are there other heuristics to consider?
 | |
|   const MachineLoop *Best = 0;
 | |
|   SlotIndex BestIdx;
 | |
|   for (LoopPtrSet::const_iterator I = Loops.begin(), E = Loops.end(); I != E;
 | |
|        ++I) {
 | |
|     SlotIndex Idx = lis_.getMBBStartIdx((*I)->getHeader());
 | |
|     if (!Best || Idx < BestIdx)
 | |
|       Best = *I, BestIdx = Idx;
 | |
|   }
 | |
|   DEBUG(dbgs() << "Best: " << *Best);
 | |
|   return Best;
 | |
| }
 | |
| 
 | |
| //===----------------------------------------------------------------------===//
 | |
| //                               Loop Splitting
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| bool llvm::splitAroundLoop(SplitAnalysis &sa, const MachineLoop *loop) {
 | |
|   return false;
 | |
| }
 | |
| 
 |