mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-08-15 06:29:05 +00:00
Beginning SplitKit - utility classes for live range splitting.
This is a work in progress. So far we have some basic loop analysis to help determine where it is useful to split a live range around a loop. The actual loop splitting code from Splitter.cpp is also going to move in here. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@108842 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -68,6 +68,7 @@ add_llvm_library(LLVMCodeGen
|
|||||||
SjLjEHPrepare.cpp
|
SjLjEHPrepare.cpp
|
||||||
SlotIndexes.cpp
|
SlotIndexes.cpp
|
||||||
Spiller.cpp
|
Spiller.cpp
|
||||||
|
SplitKit.cpp
|
||||||
Splitter.cpp
|
Splitter.cpp
|
||||||
StackProtector.cpp
|
StackProtector.cpp
|
||||||
StackSlotColoring.cpp
|
StackSlotColoring.cpp
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#define DEBUG_TYPE "spiller"
|
#define DEBUG_TYPE "spiller"
|
||||||
#include "Spiller.h"
|
#include "Spiller.h"
|
||||||
|
#include "SplitKit.h"
|
||||||
#include "VirtRegMap.h"
|
#include "VirtRegMap.h"
|
||||||
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
|
||||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||||
@@ -39,6 +40,8 @@ class InlineSpiller : public Spiller {
|
|||||||
const TargetRegisterInfo &tri_;
|
const TargetRegisterInfo &tri_;
|
||||||
const BitVector reserved_;
|
const BitVector reserved_;
|
||||||
|
|
||||||
|
SplitAnalysis splitAnalysis_;
|
||||||
|
|
||||||
// Variables that are valid during spill(), but used by multiple methods.
|
// Variables that are valid during spill(), but used by multiple methods.
|
||||||
LiveInterval *li_;
|
LiveInterval *li_;
|
||||||
std::vector<LiveInterval*> *newIntervals_;
|
std::vector<LiveInterval*> *newIntervals_;
|
||||||
@@ -62,7 +65,8 @@ public:
|
|||||||
mri_(mf->getRegInfo()),
|
mri_(mf->getRegInfo()),
|
||||||
tii_(*mf->getTarget().getInstrInfo()),
|
tii_(*mf->getTarget().getInstrInfo()),
|
||||||
tri_(*mf->getTarget().getRegisterInfo()),
|
tri_(*mf->getTarget().getRegisterInfo()),
|
||||||
reserved_(tri_.getReservedRegs(mf_)) {}
|
reserved_(tri_.getReservedRegs(mf_)),
|
||||||
|
splitAnalysis_(mf, lis, mli) {}
|
||||||
|
|
||||||
void spill(LiveInterval *li,
|
void spill(LiveInterval *li,
|
||||||
std::vector<LiveInterval*> &newIntervals,
|
std::vector<LiveInterval*> &newIntervals,
|
||||||
@@ -70,6 +74,8 @@ public:
|
|||||||
SlotIndex *earliestIndex);
|
SlotIndex *earliestIndex);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool split();
|
||||||
|
|
||||||
bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx,
|
bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx,
|
||||||
SlotIndex UseIdx);
|
SlotIndex UseIdx);
|
||||||
bool reMaterializeFor(MachineBasicBlock::iterator MI);
|
bool reMaterializeFor(MachineBasicBlock::iterator MI);
|
||||||
@@ -91,6 +97,22 @@ Spiller *createInlineSpiller(MachineFunction *mf,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// split - try splitting the current interval into pieces that may allocate
|
||||||
|
/// separately. Return true if successful.
|
||||||
|
bool InlineSpiller::split() {
|
||||||
|
// FIXME: Add intra-MBB splitting.
|
||||||
|
if (lis_.intervalIsInOneMBB(*li_))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
splitAnalysis_.analyze(li_);
|
||||||
|
|
||||||
|
if (const MachineLoop *loop = splitAnalysis_.getBestSplitLoop()) {
|
||||||
|
if (splitAroundLoop(splitAnalysis_, loop))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// allUsesAvailableAt - Return true if all registers used by OrigMI at
|
/// allUsesAvailableAt - Return true if all registers used by OrigMI at
|
||||||
/// OrigIdx are also available with the same value at UseIdx.
|
/// OrigIdx are also available with the same value at UseIdx.
|
||||||
bool InlineSpiller::allUsesAvailableAt(const MachineInstr *OrigMI,
|
bool InlineSpiller::allUsesAvailableAt(const MachineInstr *OrigMI,
|
||||||
@@ -338,6 +360,9 @@ void InlineSpiller::spill(LiveInterval *li,
|
|||||||
rc_ = mri_.getRegClass(li->reg);
|
rc_ = mri_.getRegClass(li->reg);
|
||||||
spillIs_ = &spillIs;
|
spillIs_ = &spillIs;
|
||||||
|
|
||||||
|
if (split())
|
||||||
|
return;
|
||||||
|
|
||||||
reMaterializeAll();
|
reMaterializeAll();
|
||||||
|
|
||||||
// Remat may handle everything.
|
// Remat may handle everything.
|
||||||
|
148
lib/CodeGen/SplitKit.cpp
Normal file
148
lib/CodeGen/SplitKit.cpp
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
//===---------- 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/Debug.h"
|
||||||
|
#include "llvm/Support/raw_ostream.h"
|
||||||
|
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Split Analysis
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
SplitAnalysis::SplitAnalysis(const MachineFunction *mf,
|
||||||
|
const LiveIntervals *lis,
|
||||||
|
const MachineLoopInfo *mli)
|
||||||
|
: mf_(*mf),
|
||||||
|
lis_(*lis),
|
||||||
|
loops_(*mli),
|
||||||
|
curli_(0) {}
|
||||||
|
|
||||||
|
void SplitAnalysis::clear() {
|
||||||
|
usingInstrs_.clear();
|
||||||
|
usingBlocks_.clear();
|
||||||
|
usingLoops_.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// analyseUses - Count instructions, basic blocks, and loops using curli.
|
||||||
|
void SplitAnalysis::analyseUses() {
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
SplitAnalysis::LoopPeripheralUse
|
||||||
|
SplitAnalysis::analyzeLoopPeripheralUse(const MachineLoop *Loop) {
|
||||||
|
// Peripheral blocks.
|
||||||
|
SmallVector<MachineBasicBlock*, 16> Peri;
|
||||||
|
Loop->getExitBlocks(Peri);
|
||||||
|
if (MachineBasicBlock *PredBB = Loop->getLoopPredecessor())
|
||||||
|
Peri.push_back(PredBB);
|
||||||
|
array_pod_sort(Peri.begin(), Peri.end());
|
||||||
|
Peri.erase(std::unique(Peri.begin(), Peri.end()), Peri.end());
|
||||||
|
|
||||||
|
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 &&
|
||||||
|
std::binary_search(Peri.begin(), Peri.end(), MBB)) {
|
||||||
|
if (I->second > 1) use = MultiPeripheral;
|
||||||
|
else use = SinglePeripheral;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Is it a loop block?
|
||||||
|
if (Loop->contains(MBB))
|
||||||
|
continue;
|
||||||
|
// It must be an unrelated block.
|
||||||
|
return OutsideLoop;
|
||||||
|
}
|
||||||
|
return use;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SplitAnalysis::analyze(const LiveInterval *li) {
|
||||||
|
clear();
|
||||||
|
curli_ = li;
|
||||||
|
analyseUses();
|
||||||
|
}
|
||||||
|
|
||||||
|
const MachineLoop *SplitAnalysis::getBestSplitLoop() {
|
||||||
|
LoopPtrSet Loops, SecondLoops;
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
switch(analyzeLoopPeripheralUse(*I)) {
|
||||||
|
case OutsideLoop:
|
||||||
|
Loops.insert(*I);
|
||||||
|
break;
|
||||||
|
case MultiPeripheral:
|
||||||
|
SecondLoops.insert(*I);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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?
|
||||||
|
// - avoid breaking critical edges.
|
||||||
|
// - avoid impossible loops.
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
return Best;
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Loop Splitting
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
bool llvm::splitAroundLoop(SplitAnalysis &sa, const MachineLoop *loop) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
86
lib/CodeGen/SplitKit.h
Normal file
86
lib/CodeGen/SplitKit.h
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
//===---------- 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.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||||||
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
|
||||||
|
namespace llvm {
|
||||||
|
|
||||||
|
class LiveInterval;
|
||||||
|
class LiveIntervals;
|
||||||
|
class MachineBasicBlock;
|
||||||
|
class MachineInstr;
|
||||||
|
class MachineFunction;
|
||||||
|
class MachineFunctionPass;
|
||||||
|
class MachineLoop;
|
||||||
|
class MachineLoopInfo;
|
||||||
|
|
||||||
|
class SplitAnalysis {
|
||||||
|
const MachineFunction &mf_;
|
||||||
|
const LiveIntervals &lis_;
|
||||||
|
const MachineLoopInfo &loops_;
|
||||||
|
|
||||||
|
// Current live interval.
|
||||||
|
const LiveInterval *curli_;
|
||||||
|
|
||||||
|
// Instructions using the the current register.
|
||||||
|
typedef SmallPtrSet<const MachineInstr*, 16> InstrPtrSet;
|
||||||
|
InstrPtrSet usingInstrs_;
|
||||||
|
|
||||||
|
// The number of instructions using curli in each basic block.
|
||||||
|
typedef DenseMap<const MachineBasicBlock*, unsigned> BlockCountMap;
|
||||||
|
BlockCountMap usingBlocks_;
|
||||||
|
|
||||||
|
// Loops where the curent interval is used.
|
||||||
|
typedef SmallPtrSet<const MachineLoop*, 16> LoopPtrSet;
|
||||||
|
LoopPtrSet usingLoops_;
|
||||||
|
|
||||||
|
// Sumarize statistics by counting instructions using curli_.
|
||||||
|
void analyseUses();
|
||||||
|
|
||||||
|
public:
|
||||||
|
SplitAnalysis(const MachineFunction *mf, const LiveIntervals *lis,
|
||||||
|
const MachineLoopInfo *mli);
|
||||||
|
|
||||||
|
/// analyze - set curli to the specified interval, and analyze how it may be
|
||||||
|
/// split.
|
||||||
|
void analyze(const LiveInterval *li);
|
||||||
|
|
||||||
|
/// clear - clear all data structures so SplitAnalysis is ready to analyze a
|
||||||
|
/// new interval.
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
/// LoopPeripheralUse - how is a variable used in and around a loop?
|
||||||
|
/// Peripheral blocks are the loop predecessors and exit blocks.
|
||||||
|
enum LoopPeripheralUse {
|
||||||
|
ContainedInLoop, // All uses are inside the loop.
|
||||||
|
SinglePeripheral, // At most one instruction per peripheral block.
|
||||||
|
MultiPeripheral, // Multiple instructions in some peripheral blocks.
|
||||||
|
OutsideLoop // Uses outside loop periphery.
|
||||||
|
};
|
||||||
|
|
||||||
|
/// analyzeLoopPeripheralUse - Return an enum describing how curli_ is used in
|
||||||
|
/// and around the Loop.
|
||||||
|
LoopPeripheralUse analyzeLoopPeripheralUse(const MachineLoop*);
|
||||||
|
|
||||||
|
/// getBestSplitLoop - Return the loop where curli may best be split to a
|
||||||
|
/// separate register, or NULL.
|
||||||
|
const MachineLoop *getBestSplitLoop();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// splitAroundLoop - Try to split curli into a separate live interval inside
|
||||||
|
/// the loop. Retun true on success.
|
||||||
|
bool splitAroundLoop(SplitAnalysis&, const MachineLoop*);
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user