Add a stack slot coloring pass. Not yet enabled.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51934 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng
2008-06-04 09:18:41 +00:00
parent d8a46e3a74
commit 3f32d65912
10 changed files with 523 additions and 47 deletions

View File

@@ -38,12 +38,13 @@ static cl::opt<bool>
EnableSinking("enable-sinking", cl::init(false), cl::Hidden,
cl::desc("Perform sinking on machine code"));
static cl::opt<bool>
AlignLoops("align-loops", cl::init(true), cl::Hidden,
cl::desc("Align loop headers"));
EnableStackColoring("stack-coloring",
cl::init(true), cl::Hidden,
cl::desc("Perform stack slot coloring"));
static cl::opt<bool>
PerformLICM("machine-licm",
cl::init(false), cl::Hidden,
cl::desc("Perform loop-invariant code motion on machine code"));
EnableLICM("machine-licm",
cl::init(false), cl::Hidden,
cl::desc("Perform loop-invariant code motion on machine code"));
// When this works it will be on by default.
static cl::opt<bool>
@@ -88,7 +89,7 @@ LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
if (PerformLICM)
if (EnableLICM)
PM.add(createMachineLICMPass());
if (EnableSinking)
@@ -101,21 +102,28 @@ LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
// Perform register allocation to convert to a concrete x86 representation
PM.add(createRegisterAllocator());
if (PrintMachineCode)
// Perform stack slot coloring.
if (EnableStackColoring)
PM.add(createStackSlotColoringPass());
if (PrintMachineCode) // Print the register-allocated code
PM.add(createMachineFunctionPrinterPass(cerr));
// Run post-ra passes.
if (addPostRegAlloc(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
PM.add(createLowerSubregsPass());
if (PrintMachineCode) // Print the subreg lowered code
PM.add(createMachineFunctionPrinterPass(cerr));
// Run post-ra passes.
if (addPostRegAlloc(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Insert prolog/epilog code. Eliminate abstract frame index references...
PM.add(createPrologEpilogCodeInserter());
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Second pass scheduler.
if (!Fast && !DisablePostRAScheduler)
PM.add(createPostRAScheduler());
@@ -140,7 +148,7 @@ LLVMTargetMachine::addPassesToEmitFile(PassManagerBase &PM,
if (addPreEmitPass(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
if (AlignLoops && !Fast && !OptimizeForSize)
if (!Fast && !OptimizeForSize)
PM.add(createLoopAlignerPass());
switch (FileType) {
@@ -218,7 +226,7 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM,
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
if (PerformLICM)
if (EnableLICM)
PM.add(createMachineLICMPass());
if (EnableSinking)
@@ -228,25 +236,32 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM,
if (addPreRegAlloc(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Perform register allocation to convert to a concrete x86 representation
// Perform register allocation.
PM.add(createRegisterAllocator());
// Perform stack slot coloring.
if (EnableStackColoring)
PM.add(createStackSlotColoringPass());
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Run post-ra passes.
if (addPostRegAlloc(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
if (PrintMachineCode) // Print the register-allocated code
PM.add(createMachineFunctionPrinterPass(cerr));
PM.add(createLowerSubregsPass());
if (PrintMachineCode) // Print the subreg lowered code
PM.add(createMachineFunctionPrinterPass(cerr));
// Run post-ra passes.
if (addPostRegAlloc(PM, Fast) && PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Insert prolog/epilog code. Eliminate abstract frame index references...
PM.add(createPrologEpilogCodeInserter());
if (PrintMachineCode) // Print the register-allocated code
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));
// Second pass scheduler.
@@ -258,6 +273,7 @@ bool LLVMTargetMachine::addPassesToEmitMachineCode(PassManagerBase &PM,
PM.add(createBranchFoldingPass(getEnableTailMergeDefault()));
PM.add(createGCMachineCodeAnalysisPass());
if (PrintMachineCode)
PM.add(createMachineFunctionPrinterPass(cerr));

View File

@@ -358,6 +358,20 @@ LiveInterval::FindLiveRangeContaining(unsigned Idx) {
return end();
}
/// findDefinedVNInfo - Find the VNInfo that's defined at the specified index
/// (register interval) or defined by the specified register (stack inteval).
VNInfo *LiveInterval::findDefinedVNInfo(unsigned DefIdxOrReg) const {
VNInfo *VNI = NULL;
for (LiveInterval::const_vni_iterator i = vni_begin(), e = vni_end();
i != e; ++i)
if ((*i)->def == DefIdxOrReg) {
VNI = *i;
break;
}
return VNI;
}
/// join - Join two live intervals (this, and other) together. This applies
/// mappings to the value numbers in the LHS/RHS intervals as specified. If
/// the intervals are not joinable, this aborts.
@@ -664,7 +678,9 @@ void LiveRange::dump() const {
void LiveInterval::print(std::ostream &OS,
const TargetRegisterInfo *TRI) const {
if (TRI && TargetRegisterInfo::isPhysicalRegister(reg))
if (isSS)
OS << "SS#" << reg;
else if (TRI && TargetRegisterInfo::isPhysicalRegister(reg))
OS << TRI->getName(reg);
else
OS << "%reg" << reg;
@@ -672,7 +688,7 @@ void LiveInterval::print(std::ostream &OS,
OS << ',' << weight;
if (empty())
OS << "EMPTY";
OS << " EMPTY";
else {
OS << " = ";
for (LiveInterval::Ranges::const_iterator I = ranges.begin(),

View File

@@ -65,6 +65,7 @@ void LiveIntervals::getAnalysisUsage(AnalysisUsage &AU) const {
}
void LiveIntervals::releaseMemory() {
MBB2IdxMap.clear();
Idx2MBBMap.clear();
mi2iMap_.clear();
i2miMap_.clear();
@@ -229,8 +230,8 @@ bool LiveIntervals::runOnMachineFunction(MachineFunction &fn) {
void LiveIntervals::print(std::ostream &O, const Module* ) const {
O << "********** INTERVALS **********\n";
for (const_iterator I = begin(), E = end(); I != E; ++I) {
I->second.print(DOUT, tri_);
DOUT << "\n";
I->second.print(O, tri_);
O << "\n";
}
O << "********** MACHINEINSTRS **********\n";
@@ -1160,17 +1161,6 @@ bool LiveIntervals::anyKillInMBBAfterIdx(const LiveInterval &li,
return false;
}
static const VNInfo *findDefinedVNInfo(const LiveInterval &li, unsigned DefIdx) {
const VNInfo *VNI = NULL;
for (LiveInterval::const_vni_iterator i = li.vni_begin(),
e = li.vni_end(); i != e; ++i)
if ((*i)->def == DefIdx) {
VNI = *i;
break;
}
return VNI;
}
/// RewriteInfo - Keep track of machine instrs that will be rewritten
/// during spilling.
namespace {
@@ -1318,7 +1308,7 @@ rewriteInstructionsForSpills(const LiveInterval &li, bool TrySplit,
HasKill = anyKillInMBBAfterIdx(li, I->valno, MBB, getDefIndex(index));
else {
// If this is a two-address code, then this index starts a new VNInfo.
const VNInfo *VNI = findDefinedVNInfo(li, getDefIndex(index));
const VNInfo *VNI = li.findDefinedVNInfo(getDefIndex(index));
if (VNI)
HasKill = anyKillInMBBAfterIdx(li, VNI, MBB, getDefIndex(index));
}

View File

@@ -0,0 +1,50 @@
//===-- LiveStackAnalysis.cpp - Live Stack Slot Analysis ------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the live stack slot analysis pass. It is analogous to
// live interval analysis except it's analyzing liveness of stack slots rather
// than registers.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "livestacks"
#include "llvm/CodeGen/LiveStackAnalysis.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
using namespace llvm;
char LiveStacks::ID = 0;
static RegisterPass<LiveStacks> X("livestacks", "Live Stack Slot Analysis");
void LiveStacks::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
}
void LiveStacks::releaseMemory() {
// Release VNInfo memroy regions after all VNInfo objects are dtor'd.
VNInfoAllocator.Reset();
s2iMap.clear();
}
bool LiveStacks::runOnMachineFunction(MachineFunction &) {
// FIXME: No analysis is being done right now. We are relying on the
// register allocators to provide the information.
return false;
}
/// print - Implement the dump method.
void LiveStacks::print(std::ostream &O, const Module* ) const {
O << "********** INTERVALS **********\n";
for (const_iterator I = begin(), E = end(); I != E; ++I) {
I->second.print(O);
O << "\n";
}
}

View File

@@ -12,10 +12,11 @@
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "regalloc"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "PhysRegTracker.h"
#include "VirtRegMap.h"
#include "llvm/Function.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
#include "llvm/CodeGen/LiveStackAnalysis.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
@@ -67,6 +68,7 @@ namespace {
MachineRegisterInfo *reginfo_;
BitVector allocatableRegs_;
LiveIntervals* li_;
LiveStacks* ls_;
const MachineLoopInfo *loopInfo;
/// handled_ - Intervals are added to the handled_ set in the order of their
@@ -103,6 +105,8 @@ namespace {
// Make sure PassManager knows which analyses to make available
// to coalescing and which analyses coalescing invalidates.
AU.addRequiredTransitive<RegisterCoalescer>();
AU.addRequired<LiveStacks>();
AU.addPreserved<LiveStacks>();
AU.addRequired<MachineLoopInfo>();
AU.addPreserved<MachineLoopInfo>();
AU.addPreservedID(MachineDominatorsID);
@@ -171,6 +175,9 @@ namespace {
char RALinScan::ID = 0;
}
static RegisterPass<RALinScan>
X("linearscan-regalloc", "Linear Scan Register Allocator");
void RALinScan::ComputeRelatedRegClasses() {
const TargetRegisterInfo &TRI = *tri_;
@@ -258,6 +265,7 @@ bool RALinScan::runOnMachineFunction(MachineFunction &fn) {
reginfo_ = &mf_->getRegInfo();
allocatableRegs_ = tri_->getAllocatableSet(fn);
li_ = &getAnalysis<LiveIntervals>();
ls_ = &getAnalysis<LiveStacks>();
loopInfo = &getAnalysis<MachineLoopInfo>();
// We don't run the coalescer here because we have no reason to
@@ -504,6 +512,26 @@ static void RevertVectorIteratorsTo(RALinScan::IntervalPtrs &V, unsigned Point){
}
}
/// addStackInterval - Create a LiveInterval for stack if the specified live
/// interval has been spilled.
static void addStackInterval(LiveInterval *cur, LiveStacks *ls_,
LiveIntervals *li_, VirtRegMap &vrm_) {
int SS = vrm_.getStackSlot(cur->reg);
if (SS == VirtRegMap::NO_STACK_SLOT)
return;
LiveInterval &SI = ls_->getOrCreateInterval(SS);
VNInfo *VNI;
if (SI.getNumValNums())
VNI = SI.getValNumInfo(0);
else
VNI = SI.getNextValue(~0U, 0, ls_->getVNInfoAllocator());
LiveInterval &RI = li_->getInterval(cur->reg);
// FIXME: This may be overly conservative.
SI.MergeRangesInAsValue(RI, VNI);
SI.weight += RI.weight;
}
/// assignRegOrStackSlotAtInterval - assign a register if one is available, or
/// spill.
void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
@@ -717,6 +745,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
DOUT << "\t\t\tspilling(c): " << *cur << '\n';
std::vector<LiveInterval*> added =
li_->addIntervalsForSpills(*cur, loopInfo, *vrm_);
addStackInterval(cur, ls_, li_, *vrm_);
if (added.empty())
return; // Early exit if all spills were folded.
@@ -769,6 +798,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
earliestStart = std::min(earliestStart, i->first->beginNumber());
std::vector<LiveInterval*> newIs =
li_->addIntervalsForSpills(*i->first, loopInfo, *vrm_);
addStackInterval(i->first, ls_, li_, *vrm_);
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
spilled.insert(reg);
}
@@ -782,6 +812,7 @@ void RALinScan::assignRegOrStackSlotAtInterval(LiveInterval* cur)
earliestStart = std::min(earliestStart, i->first->beginNumber());
std::vector<LiveInterval*> newIs =
li_->addIntervalsForSpills(*i->first, loopInfo, *vrm_);
addStackInterval(i->first, ls_, li_, *vrm_);
std::copy(newIs.begin(), newIs.end(), std::back_inserter(added));
spilled.insert(reg);
}

View File

@@ -0,0 +1,271 @@
//===-- StackSlotColoring.cpp - Sinking for machine instructions ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the stack slot coloring pass.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "stackcoloring"
#include "llvm/CodeGen/LiveStackAnalysis.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include <vector>
using namespace llvm;
static cl::opt<bool>
DisableSharing("no-stack-slot-sharing",
cl::init(false), cl::Hidden,
cl::desc("Surpress slot sharing during stack coloring"));
static cl::opt<int>
DeleteLimit("slot-delete-limit", cl::init(-1), cl::Hidden,
cl::desc("Stack coloring slot deletion limit"));
STATISTIC(NumEliminated, "Number of stack slots eliminated due to coloring");
namespace {
class VISIBILITY_HIDDEN StackSlotColoring : public MachineFunctionPass {
LiveStacks* LS;
MachineFrameInfo *MFI;
// SSIntervals - Spill slot intervals.
std::vector<LiveInterval*> SSIntervals;
// OrigAlignments - Alignments of stack objects before coloring.
SmallVector<unsigned, 16> OrigAlignments;
// OrigSizes - Sizess of stack objects before coloring.
SmallVector<unsigned, 16> OrigSizes;
// AllColors - If index is set, it's a spill slot, i.e. color.
// FIXME: This assumes PEI locate spill slot with smaller indices
// closest to stack pointer / frame pointer. Therefore, smaller
// index == better color.
BitVector AllColors;
// NextColor - Next "color" that's not yet used.
int NextColor;
// UsedColors - "Colors" that have been assigned.
BitVector UsedColors;
// Assignments - Color to intervals mapping.
SmallVector<SmallVector<LiveInterval*,4>,16> Assignments;
public:
static char ID; // Pass identification
StackSlotColoring() : MachineFunctionPass((intptr_t)&ID), NextColor(-1) {}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<LiveStacks>();
MachineFunctionPass::getAnalysisUsage(AU);
}
virtual bool runOnMachineFunction(MachineFunction &MF);
virtual const char* getPassName() const {
return "Stack Slot Coloring";
}
private:
bool InitializeSlots();
bool OverlapWithAssignments(LiveInterval *li, int Color) const;
int ColorSlot(LiveInterval *li);
bool ColorSlots(MachineFunction &MF);
};
} // end anonymous namespace
char StackSlotColoring::ID = 0;
static RegisterPass<StackSlotColoring>
X("stack-slot-coloring", "Stack Slot Coloring");
FunctionPass *llvm::createStackSlotColoringPass() {
return new StackSlotColoring();
}
namespace {
// IntervalSorter - Comparison predicate that sort live intervals by
// their weight.
struct IntervalSorter {
bool operator()(LiveInterval* LHS, LiveInterval* RHS) const {
return LHS->weight > RHS->weight;
}
};
}
/// InitializeSlots - Process all spill stack slot liveintervals and add them
/// to a sorted (by weight) list.
bool StackSlotColoring::InitializeSlots() {
if (LS->getNumIntervals() < 2)
return false;
int LastFI = MFI->getObjectIndexEnd();
OrigAlignments.resize(LastFI);
OrigSizes.resize(LastFI);
AllColors.resize(LastFI);
UsedColors.resize(LastFI);
Assignments.resize(LastFI);
// Gather all spill slots into a list.
for (LiveStacks::iterator i = LS->begin(), e = LS->end(); i != e; ++i) {
LiveInterval &li = i->second;
int FI = li.getStackSlotIndex();
if (MFI->isDeadObjectIndex(FI))
continue;
SSIntervals.push_back(&li);
OrigAlignments[FI] = MFI->getObjectAlignment(FI);
OrigSizes[FI] = MFI->getObjectSize(FI);
AllColors.set(FI);
}
// Sort them by weight.
std::stable_sort(SSIntervals.begin(), SSIntervals.end(), IntervalSorter());
// Get first "color".
NextColor = AllColors.find_first();
return true;
}
/// OverlapWithAssignments - Return true if LiveInterval overlaps with any
/// LiveIntervals that have already been assigned to the specified color.
bool
StackSlotColoring::OverlapWithAssignments(LiveInterval *li, int Color) const {
const SmallVector<LiveInterval*,4> &OtherLIs = Assignments[Color];
for (unsigned i = 0, e = OtherLIs.size(); i != e; ++i) {
LiveInterval *OtherLI = OtherLIs[i];
if (OtherLI->overlaps(*li))
return true;
}
return false;
}
/// ColorSlot - Assign a "color" (stack slot) to the specified stack slot.
///
int StackSlotColoring::ColorSlot(LiveInterval *li) {
int Color = -1;
bool Share = false;
if (!DisableSharing &&
(DeleteLimit == -1 || (int)NumEliminated < DeleteLimit)) {
// Check if it's possible to reuse any of the used colors.
Color = UsedColors.find_first();
while (Color != -1) {
if (!OverlapWithAssignments(li, Color)) {
Share = true;
++NumEliminated;
break;
}
Color = UsedColors.find_next(Color);
}
}
// Assign it to the first available color (assumed to be the best) if it's
// not possible to share a used color with other objects.
if (!Share) {
assert(NextColor != -1 && "No more spill slots?");
Color = NextColor;
UsedColors.set(Color);
NextColor = AllColors.find_next(NextColor);
}
// Record the assignment.
Assignments[Color].push_back(li);
int FI = li->getStackSlotIndex();
DOUT << "Assigning fi #" << FI << " to fi #" << Color << "\n";
// Change size and alignment of the allocated slot. If there are multiple
// objects sharing the same slot, then make sure the size and alignment
// are large enough for all.
unsigned Align = OrigAlignments[FI];
if (!Share || Align > MFI->getObjectAlignment(Color))
MFI->setObjectAlignment(Color, Align);
int64_t Size = OrigSizes[FI];
if (!Share || Size > MFI->getObjectSize(Color))
MFI->setObjectSize(Color, Size);
return Color;
}
/// Colorslots - Color all spill stack slots and rewrite all frameindex machine
/// operands in the function.
bool StackSlotColoring::ColorSlots(MachineFunction &MF) {
unsigned NumObjs = MFI->getObjectIndexEnd();
std::vector<int> SlotMapping(NumObjs, -1);
SlotMapping.resize(NumObjs, -1);
bool Changed = false;
for (unsigned i = 0, e = SSIntervals.size(); i != e; ++i) {
LiveInterval *li = SSIntervals[i];
int SS = li->getStackSlotIndex();
int NewSS = ColorSlot(li);
SlotMapping[SS] = NewSS;
Changed |= (SS != NewSS);
}
if (!Changed)
return false;
// Rewrite all MO_FrameIndex operands.
// FIXME: Need the equivalent of MachineRegisterInfo for frameindex operands.
for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
MBB != E; ++MBB) {
for (MachineBasicBlock::iterator MII = MBB->begin(), EE = MBB->end();
MII != EE; ++MII) {
MachineInstr &MI = *MII;
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
MachineOperand &MO = MI.getOperand(i);
if (!MO.isFrameIndex())
continue;
int FI = MO.getIndex();
if (FI < 0)
continue;
FI = SlotMapping[FI];
if (FI == -1)
continue;
MO.setIndex(FI);
}
}
}
// Delete unused stack slots.
while (NextColor != -1) {
DOUT << "Removing unused stack object fi #" << NextColor << "\n";
MFI->RemoveStackObject(NextColor);
NextColor = AllColors.find_next(NextColor);
}
return true;
}
bool StackSlotColoring::runOnMachineFunction(MachineFunction &MF) {
DOUT << "******** Stack Slot Coloring ********\n";
MFI = MF.getFrameInfo();
LS = &getAnalysis<LiveStacks>();
bool Changed = false;
if (InitializeSlots())
Changed = ColorSlots(MF);
NextColor = -1;
SSIntervals.clear();
OrigAlignments.clear();
OrigSizes.clear();
AllColors.clear();
UsedColors.clear();
for (unsigned i = 0, e = Assignments.size(); i != e; ++i)
Assignments[i].clear();
Assignments.clear();
return Changed;
}