Newer
Older
//===------ RegAllocPBQP.cpp ---- PBQP Register Allocator -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This file contains a Partitioned Boolean Quadratic Programming (PBQP) based
// register allocator for LLVM. This allocator works by constructing a PBQP
// problem representing the register allocation problem under consideration,
// solving this using a PBQP solver, and mapping the solution back to a
// register assignment. If any variables are selected for spilling then spill
//
// The PBQP solver (pbqp.c) provided for this allocator uses a heuristic tuned
// for register allocation. For more information on PBQP for register
// allocation, see the following papers:
//
// (1) Hames, L. and Scholz, B. 2006. Nearly optimal register allocation with
// PBQP. In Proceedings of the 7th Joint Modular Languages Conference
// (JMLC'06). LNCS, vol. 4228. Springer, New York, NY, USA. 346-361.
//
// (2) Scholz, B., Eckstein, E. 2002. Register allocation for irregular
// architectures. In Proceedings of the Joint Conference on Languages,
// Compilers and Tools for Embedded Systems (LCTES'02), ACM Press, New York,
// NY, USA, 139-148.
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "regalloc"
#include "RenderMachineFunction.h"
Lang Hames
committed
#include "Splitter.h"
#include "VirtRegMap.h"
#include "VirtRegRewriter.h"
#include "llvm/CodeGen/CalcSpillWeights.h"
#include "llvm/CodeGen/LiveIntervalAnalysis.h"
Lang Hames
committed
#include "llvm/CodeGen/LiveStackAnalysis.h"
Lang Hames
committed
#include "llvm/CodeGen/RegAllocPBQP.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
Lang Hames
committed
#include "llvm/CodeGen/PBQP/HeuristicSolver.h"
#include "llvm/CodeGen/PBQP/Graph.h"
#include "llvm/CodeGen/PBQP/Heuristics/Briggs.h"
#include "llvm/CodeGen/RegAllocRegistry.h"
#include "llvm/CodeGen/RegisterCoalescer.h"
#include "llvm/Support/Debug.h"
Daniel Dunbar
committed
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetMachine.h"
#include <limits>
#include <memory>
#include <set>
#include <vector>
Lang Hames
committed
namespace llvm {
static RegisterRegAlloc
registerPBQPRepAlloc("pbqp", "PBQP register allocator",
Lang Hames
committed
static cl::opt<bool>
pbqpCoalescing("pbqp-coalescing",
cl::desc("Attempt coalescing during PBQP register allocation."),
cl::init(false), cl::Hidden);
Lang Hames
committed
Lang Hames
committed
static cl::opt<bool>
pbqpBuilder("pbqp-builder",
cl::desc("Use new builder system."),
cl::init(false), cl::Hidden);
Lang Hames
committed
static cl::opt<bool>
pbqpPreSplitting("pbqp-pre-splitting",
cl::desc("Pre-splite before PBQP register allocation."),
cl::init(false), cl::Hidden);
Lang Hames
committed
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
char RegAllocPBQP::ID = 0;
unsigned PBQPRAProblem::getVRegForNode(PBQP::Graph::ConstNodeItr node) const {
Node2VReg::const_iterator vregItr = node2VReg.find(node);
assert(vregItr != node2VReg.end() && "No vreg for node.");
return vregItr->second;
}
PBQP::Graph::NodeItr PBQPRAProblem::getNodeForVReg(unsigned vreg) const {
VReg2Node::const_iterator nodeItr = vreg2Node.find(vreg);
assert(nodeItr != vreg2Node.end() && "No node for vreg.");
return nodeItr->second;
}
const PBQPRAProblem::AllowedSet&
PBQPRAProblem::getAllowedSet(unsigned vreg) const {
AllowedSetMap::const_iterator allowedSetItr = allowedSets.find(vreg);
assert(allowedSetItr != allowedSets.end() && "No pregs for vreg.");
const AllowedSet &allowedSet = allowedSetItr->second;
return allowedSet;
}
unsigned PBQPRAProblem::getPRegForOption(unsigned vreg, unsigned option) const {
assert(isPRegOption(vreg, option) && "Not a preg option.");
const AllowedSet& allowedSet = getAllowedSet(vreg);
assert(option <= allowedSet.size() && "Option outside allowed set.");
return allowedSet[option - 1];
}
std::auto_ptr<PBQPRAProblem> PBQPBuilder::build(MachineFunction *mf,
const LiveIntervals *lis,
const MachineLoopInfo *loopInfo,
const RegSet &vregs) {
Lang Hames
committed
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
typedef std::vector<const LiveInterval*> LIVector;
MachineRegisterInfo *mri = &mf->getRegInfo();
const TargetRegisterInfo *tri = mf->getTarget().getRegisterInfo();
std::auto_ptr<PBQPRAProblem> p(new PBQPRAProblem());
PBQP::Graph &g = p->getGraph();
RegSet pregs;
// Collect the set of preg intervals, record that they're used in the MF.
for (LiveIntervals::const_iterator itr = lis->begin(), end = lis->end();
itr != end; ++itr) {
if (TargetRegisterInfo::isPhysicalRegister(itr->first)) {
pregs.insert(itr->first);
mri->setPhysRegUsed(itr->first);
}
}
BitVector reservedRegs = tri->getReservedRegs(*mf);
// Iterate over vregs.
for (RegSet::const_iterator vregItr = vregs.begin(), vregEnd = vregs.end();
vregItr != vregEnd; ++vregItr) {
unsigned vreg = *vregItr;
const TargetRegisterClass *trc = mri->getRegClass(vreg);
const LiveInterval *vregLI = &lis->getInterval(vreg);
// Compute an initial allowed set for the current vreg.
typedef std::vector<unsigned> VRAllowed;
VRAllowed vrAllowed;
for (TargetRegisterClass::iterator aoItr = trc->allocation_order_begin(*mf),
aoEnd = trc->allocation_order_end(*mf);
aoItr != aoEnd; ++aoItr) {
unsigned preg = *aoItr;
if (!reservedRegs.test(preg)) {
vrAllowed.push_back(preg);
}
}
// Remove any physical registers which overlap.
for (RegSet::const_iterator pregItr = pregs.begin(),
pregEnd = pregs.end();
pregItr != pregEnd; ++pregItr) {
unsigned preg = *pregItr;
const LiveInterval *pregLI = &lis->getInterval(preg);
if (pregLI->empty())
continue;
if (!vregLI->overlaps(*pregLI))
continue;
Lang Hames
committed
// Remove the register from the allowed set.
VRAllowed::iterator eraseItr =
std::find(vrAllowed.begin(), vrAllowed.end(), preg);
Lang Hames
committed
if (eraseItr != vrAllowed.end()) {
vrAllowed.erase(eraseItr);
}
Lang Hames
committed
// Also remove any aliases.
const unsigned *aliasItr = tri->getAliasSet(preg);
if (aliasItr != 0) {
for (; *aliasItr != 0; ++aliasItr) {
VRAllowed::iterator eraseItr =
std::find(vrAllowed.begin(), vrAllowed.end(), *aliasItr);
Lang Hames
committed
if (eraseItr != vrAllowed.end()) {
vrAllowed.erase(eraseItr);
}
}
}
}
Lang Hames
committed
// Construct the node.
PBQP::Graph::NodeItr node =
g.addNode(PBQP::Vector(vrAllowed.size() + 1, 0));
// Record the mapping and allowed set in the problem.
p->recordVReg(vreg, node, vrAllowed.begin(), vrAllowed.end());
PBQP::PBQPNum spillCost = (vregLI->weight != 0.0) ?
vregLI->weight : std::numeric_limits<PBQP::PBQPNum>::min();
addSpillCosts(g.getNodeCosts(node), spillCost);
}
for (RegSet::const_iterator vr1Itr = vregs.begin(), vrEnd = vregs.end();
Lang Hames
committed
vr1Itr != vrEnd; ++vr1Itr) {
unsigned vr1 = *vr1Itr;
const LiveInterval &l1 = lis->getInterval(vr1);
const PBQPRAProblem::AllowedSet &vr1Allowed = p->getAllowedSet(vr1);
for (RegSet::const_iterator vr2Itr = llvm::next(vr1Itr);
Lang Hames
committed
vr2Itr != vrEnd; ++vr2Itr) {
unsigned vr2 = *vr2Itr;
const LiveInterval &l2 = lis->getInterval(vr2);
const PBQPRAProblem::AllowedSet &vr2Allowed = p->getAllowedSet(vr2);
assert(!l2.empty() && "Empty interval in vreg set?");
if (l1.overlaps(l2)) {
PBQP::Graph::EdgeItr edge =
g.addEdge(p->getNodeForVReg(vr1), p->getNodeForVReg(vr2),
PBQP::Matrix(vr1Allowed.size()+1, vr2Allowed.size()+1, 0));
addInterferenceCosts(g.getEdgeCosts(edge), vr1Allowed, vr2Allowed, tri);
}
}
Lang Hames
committed
}
return p;
}
void PBQPBuilder::addSpillCosts(PBQP::Vector &costVec,
PBQP::PBQPNum spillCost) {
costVec[0] = spillCost;
}
void PBQPBuilder::addInterferenceCosts(
PBQP::Matrix &costMat,
const PBQPRAProblem::AllowedSet &vr1Allowed,
const PBQPRAProblem::AllowedSet &vr2Allowed,
const TargetRegisterInfo *tri) {
Lang Hames
committed
assert(costMat.getRows() == vr1Allowed.size() + 1 && "Matrix height mismatch.");
assert(costMat.getCols() == vr2Allowed.size() + 1 && "Matrix width mismatch.");
Lang Hames
committed
for (unsigned i = 0; i < vr1Allowed.size(); ++i) {
unsigned preg1 = vr1Allowed[i];
Lang Hames
committed
for (unsigned j = 0; j < vr2Allowed.size(); ++j) {
unsigned preg2 = vr2Allowed[j];
Lang Hames
committed
if (tri->regsOverlap(preg1, preg2)) {
costMat[i + 1][j + 1] = std::numeric_limits<PBQP::PBQPNum>::infinity();
Lang Hames
committed
}
}
}
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
std::auto_ptr<PBQPRAProblem> PBQPBuilderWithCoalescing::build(
MachineFunction *mf,
const LiveIntervals *lis,
const MachineLoopInfo *loopInfo,
const RegSet &vregs) {
std::auto_ptr<PBQPRAProblem> p = PBQPBuilder::build(mf, lis, loopInfo, vregs);
PBQP::Graph &g = p->getGraph();
const TargetMachine &tm = mf->getTarget();
CoalescerPair cp(*tm.getInstrInfo(), *tm.getRegisterInfo());
// Scan the machine function and add a coalescing cost whenever CoalescerPair
// gives the Ok.
for (MachineFunction::const_iterator mbbItr = mf->begin(),
mbbEnd = mf->end();
mbbItr != mbbEnd; ++mbbItr) {
const MachineBasicBlock *mbb = &*mbbItr;
for (MachineBasicBlock::const_iterator miItr = mbb->begin(),
miEnd = mbb->end();
miItr != miEnd; ++miItr) {
const MachineInstr *mi = &*miItr;
if (!mi->isCopy() && !mi->isSubregToReg())
continue; // Not coalescable.
if (!cp.setRegisters(mi))
continue; // Not coalescable.
if (cp.getSrcReg() == cp.getDstReg())
continue; // Already coalesced.
if (cp.isCoalescable(mi)) {
unsigned dst = cp.getDstReg(),
src = cp.getSrcReg();
PBQP::PBQPNum cBenefit = std::pow(10.0f, loopInfo->getLoopDepth(mbb));
if (cp.isPhys()) {
if (!lis->isAllocatable(dst))
continue;
const PBQPRAProblem::AllowedSet &allowed = p->getAllowedSet(src);
unsigned pregOpt = 0;
while (pregOpt < allowed.size() && allowed[pregOpt] != dst)
++pregOpt;
if (pregOpt < allowed.size()) {
++pregOpt; // +1 to account for spill option.
PBQP::Graph::NodeItr node = p->getNodeForVReg(src);
addPhysRegCoalesce(g.getNodeCosts(node), pregOpt, cBenefit);
}
} else {
const PBQPRAProblem::AllowedSet *allowed1 = &p->getAllowedSet(dst);
const PBQPRAProblem::AllowedSet *allowed2 = &p->getAllowedSet(src);
PBQP::Graph::NodeItr node1 = p->getNodeForVReg(dst);
PBQP::Graph::NodeItr node2 = p->getNodeForVReg(src);
PBQP::Graph::EdgeItr edge = g.findEdge(node1, node2);
if (edge == g.edgesEnd()) {
edge = g.addEdge(node1, node2, PBQP::Matrix(allowed1->size() + 1,
allowed2->size() + 1,
0));
} else {
if (g.getEdgeNode1(edge) == node2) {
std::swap(node1, node2);
std::swap(allowed1, allowed2);
}
}
addVirtRegCoalesce(g.getEdgeCosts(edge), *allowed1, *allowed2,
cBenefit);
}
}
}
}
return p;
}
void PBQPBuilderWithCoalescing::addPhysRegCoalesce(PBQP::Vector &costVec,
unsigned pregOption,
PBQP::PBQPNum benefit) {
costVec[pregOption] += -benefit;
}
void PBQPBuilderWithCoalescing::addVirtRegCoalesce(
PBQP::Matrix &costMat,
const PBQPRAProblem::AllowedSet &vr1Allowed,
const PBQPRAProblem::AllowedSet &vr2Allowed,
PBQP::PBQPNum benefit) {
assert(costMat.getRows() == vr1Allowed.size() + 1 && "Size mismatch.");
assert(costMat.getCols() == vr2Allowed.size() + 1 && "Size mismatch.");
for (unsigned i = 0; i < vr1Allowed.size(); ++i) {
unsigned preg1 = vr1Allowed[i];
for (unsigned j = 0; j < vr2Allowed.size(); ++j) {
unsigned preg2 = vr2Allowed[j];
if (preg1 == preg2) {
costMat[i + 1][j + 1] += -benefit;
}
}
}
}
Lang Hames
committed
void RegAllocPBQP::getAnalysisUsage(AnalysisUsage &au) const {
au.addRequired<SlotIndexes>();
au.addPreserved<SlotIndexes>();
au.addRequired<LiveIntervals>();
//au.addRequiredID(SplitCriticalEdgesID);
au.addRequired<RegisterCoalescer>();
au.addRequired<CalculateSpillWeights>();
au.addRequired<LiveStacks>();
au.addPreserved<LiveStacks>();
au.addRequired<MachineLoopInfo>();
au.addPreserved<MachineLoopInfo>();
if (pbqpPreSplitting)
au.addRequired<LoopSplitter>();
au.addRequired<VirtRegMap>();
au.addRequired<RenderMachineFunction>();
MachineFunctionPass::getAnalysisUsage(au);
}
Lang Hames
committed
template <typename RegContainer>
Lang Hames
committed
PBQP::Vector RegAllocPBQP::buildCostVector(unsigned vReg,
Lang Hames
committed
const RegContainer &allowed,
const CoalesceMap &coalesces,
PBQP::PBQPNum spillCost) const {
Lang Hames
committed
typedef typename RegContainer::const_iterator AllowedItr;
// Allocate vector. Additional element (0th) used for spill option
Lang Hames
committed
PBQP::Vector v(allowed.size() + 1, 0);
Lang Hames
committed
v[0] = spillCost;
Lang Hames
committed
// Iterate over the allowed registers inserting coalesce benefits if there
// are any.
unsigned ai = 0;
for (AllowedItr itr = allowed.begin(), end = allowed.end();
itr != end; ++itr, ++ai) {
unsigned pReg = *itr;
CoalesceMap::const_iterator cmItr =
coalesces.find(RegPair(vReg, pReg));
// No coalesce - on to the next preg.
if (cmItr == coalesces.end())
continue;
// We have a coalesce - insert the benefit.
Lang Hames
committed
v[ai + 1] = -cmItr->second;
Lang Hames
committed
}
return v;
}
Lang Hames
committed
template <typename RegContainer>
Lang Hames
committed
PBQP::Matrix* RegAllocPBQP::buildInterferenceMatrix(
Lang Hames
committed
const RegContainer &allowed1, const RegContainer &allowed2) const {
Lang Hames
committed
typedef typename RegContainer::const_iterator RegContainerIterator;
// Construct a PBQP matrix representing the cost of allocation options. The
// rows and columns correspond to the allocation options for the two live
// intervals. Elements will be infinite where corresponding registers alias,
// since we cannot allocate aliasing registers to interfering live intervals.
// All other elements (non-aliasing combinations) will have zero cost. Note
// that the spill option (element 0,0) has zero cost, since we can allocate
// both intervals to memory safely (the cost for each individual allocation
// to memory is accounted for by the cost vectors for each live interval).
Lang Hames
committed
PBQP::Matrix *m =
new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0);
// Assume this is a zero matrix until proven otherwise. Zero matrices occur
// between interfering live ranges with non-overlapping register sets (e.g.
// non-overlapping reg classes, or disjoint sets of allowed regs within the
// same class). The term "overlapping" is used advisedly: sets which do not
// intersect, but contain registers which alias, will have non-zero matrices.
// We optimize zero matrices away to improve solver speed.
bool isZeroMatrix = true;
// Row index. Starts at 1, since the 0th row is for the spill option, which
// is always zero.
// Iterate over allowed sets, insert infinities where required.
Lang Hames
committed
for (RegContainerIterator a1Itr = allowed1.begin(), a1End = allowed1.end();
a1Itr != a1End; ++a1Itr) {
// Column index, starts at 1 as for row index.
unsigned ci = 1;
unsigned reg1 = *a1Itr;
Lang Hames
committed
for (RegContainerIterator a2Itr = allowed2.begin(), a2End = allowed2.end();
a2Itr != a2End; ++a2Itr) {
unsigned reg2 = *a2Itr;
// If the row/column regs are identical or alias insert an infinity.
Lang Hames
committed
(*m)[ri][ci] = std::numeric_limits<PBQP::PBQPNum>::infinity();
isZeroMatrix = false;
}
++ci;
}
++ri;
}
// If this turns out to be a zero matrix...
if (isZeroMatrix) {
// free it and return null.
delete m;
return 0;
}
// ...otherwise return the cost matrix.
return m;
}
Lang Hames
committed
template <typename RegContainer>
Lang Hames
committed
PBQP::Matrix* RegAllocPBQP::buildCoalescingMatrix(
Lang Hames
committed
const RegContainer &allowed1, const RegContainer &allowed2,
Lang Hames
committed
PBQP::PBQPNum cBenefit) const {
Lang Hames
committed
typedef typename RegContainer::const_iterator RegContainerIterator;
// Construct a PBQP Matrix representing the benefits of coalescing. As with
// interference matrices the rows and columns represent allowed registers
// for the LiveIntervals which are (potentially) to be coalesced. The amount
// -cBenefit will be placed in any element representing the same register
// for both intervals.
Lang Hames
committed
PBQP::Matrix *m =
new PBQP::Matrix(allowed1.size() + 1, allowed2.size() + 1, 0);
Lang Hames
committed
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
// Reset costs to zero.
m->reset(0);
// Assume the matrix is zero till proven otherwise. Zero matrices will be
// optimized away as in the interference case.
bool isZeroMatrix = true;
// Row index. Starts at 1, since the 0th row is for the spill option, which
// is always zero.
unsigned ri = 1;
// Iterate over the allowed sets, insert coalescing benefits where
// appropriate.
for (RegContainerIterator a1Itr = allowed1.begin(), a1End = allowed1.end();
a1Itr != a1End; ++a1Itr) {
// Column index, starts at 1 as for row index.
unsigned ci = 1;
unsigned reg1 = *a1Itr;
for (RegContainerIterator a2Itr = allowed2.begin(), a2End = allowed2.end();
a2Itr != a2End; ++a2Itr) {
// If the row and column represent the same register insert a beneficial
// cost to preference this allocation - it would allow us to eliminate a
Lang Hames
committed
if (reg1 == *a2Itr) {
(*m)[ri][ci] = -cBenefit;
isZeroMatrix = false;
}
++ci;
}
++ri;
}
// If this turns out to be a zero matrix...
if (isZeroMatrix) {
// ...free it and return null.
delete m;
return 0;
}
return m;
}
Lang Hames
committed
RegAllocPBQP::CoalesceMap RegAllocPBQP::findCoalesces() {
Lang Hames
committed
typedef MachineFunction::const_iterator MFIterator;
typedef MachineBasicBlock::const_iterator MBBIterator;
typedef LiveInterval::const_vni_iterator VNIIterator;
Lang Hames
committed
CoalesceMap coalescesFound;
Lang Hames
committed
// To find coalesces we need to iterate over the function looking for
// copy instructions.
for (MFIterator bbItr = mf->begin(), bbEnd = mf->end();
bbItr != bbEnd; ++bbItr) {
const MachineBasicBlock *mbb = &*bbItr;
Lang Hames
committed
for (MBBIterator iItr = mbb->begin(), iEnd = mbb->end();
iItr != iEnd; ++iItr) {
const MachineInstr *instr = &*iItr;
Lang Hames
committed
// If this isn't a copy then continue to the next instruction.
Jakob Stoklund Olesen
committed
if (!instr->isCopy())
Lang Hames
committed
continue;
Jakob Stoklund Olesen
committed
unsigned srcReg = instr->getOperand(1).getReg();
unsigned dstReg = instr->getOperand(0).getReg();
Lang Hames
committed
// If the registers are already the same our job is nice and easy.
if (dstReg == srcReg)
continue;
Lang Hames
committed
bool srcRegIsPhysical = TargetRegisterInfo::isPhysicalRegister(srcReg),
dstRegIsPhysical = TargetRegisterInfo::isPhysicalRegister(dstReg);
Lang Hames
committed
// If both registers are physical then we can't coalesce.
if (srcRegIsPhysical && dstRegIsPhysical)
continue;
Rafael Espindola
committed
// If it's a copy that includes two virtual register but the source and
// destination classes differ then we can't coalesce.
if (!srcRegIsPhysical && !dstRegIsPhysical &&
mri->getRegClass(srcReg) != mri->getRegClass(dstReg))
Lang Hames
committed
continue;
Rafael Espindola
committed
// If one is physical and one is virtual, check that the physical is
// allocatable in the class of the virtual.
if (srcRegIsPhysical && !dstRegIsPhysical) {
const TargetRegisterClass *dstRegClass = mri->getRegClass(dstReg);
if (std::find(dstRegClass->allocation_order_begin(*mf),
dstRegClass->allocation_order_end(*mf), srcReg) ==
dstRegClass->allocation_order_end(*mf))
continue;
Lang Hames
committed
}
Rafael Espindola
committed
if (!srcRegIsPhysical && dstRegIsPhysical) {
const TargetRegisterClass *srcRegClass = mri->getRegClass(srcReg);
if (std::find(srcRegClass->allocation_order_begin(*mf),
srcRegClass->allocation_order_end(*mf), dstReg) ==
srcRegClass->allocation_order_end(*mf))
continue;
Lang Hames
committed
}
Lang Hames
committed
// If we've made it here we have a copy with compatible register classes.
// We can probably coalesce, but we need to consider overlap.
Lang Hames
committed
const LiveInterval *srcLI = &lis->getInterval(srcReg),
*dstLI = &lis->getInterval(dstReg);
if (srcLI->overlaps(*dstLI)) {
// Even in the case of an overlap we might still be able to coalesce,
// but we need to make sure that no definition of either range occurs
// while the other range is live.
// Otherwise start by assuming we're ok.
bool badDef = false;
// Test all defs of the source range.
Lang Hames
committed
vniItr = srcLI->vni_begin(), vniEnd = srcLI->vni_end();
vniItr != vniEnd; ++vniItr) {
// If we find a poorly defined def we err on the side of caution.
if (!(*vniItr)->def.isValid()) {
badDef = true;
break;
}
Lang Hames
committed
// If we find a def that kills the coalescing opportunity then
// record it and break from the loop.
if (dstLI->liveAt((*vniItr)->def)) {
badDef = true;
break;
}
}
Lang Hames
committed
// If we have a bad def give up, continue to the next instruction.
if (badDef)
continue;
Lang Hames
committed
// Otherwise test definitions of the destination range.
for (VNIIterator
vniItr = dstLI->vni_begin(), vniEnd = dstLI->vni_end();
vniItr != vniEnd; ++vniItr) {
Lang Hames
committed
// We want to make sure we skip the copy instruction itself.
Lang Hames
committed
if ((*vniItr)->getCopy() == instr)
Lang Hames
committed
continue;
if (!(*vniItr)->def.isValid()) {
badDef = true;
break;
}
Lang Hames
committed
if (srcLI->liveAt((*vniItr)->def)) {
badDef = true;
break;
}
}
Lang Hames
committed
// As before a bad def we give up and continue to the next instr.
if (badDef)
continue;
}
Lang Hames
committed
// If we make it to here then either the ranges didn't overlap, or they
// did, but none of their definitions would prevent us from coalescing.
// We're good to go with the coalesce.
float cBenefit = std::pow(10.0f, (float)loopInfo->getLoopDepth(mbb)) / 5.0;
Lang Hames
committed
coalescesFound[RegPair(srcReg, dstReg)] = cBenefit;
coalescesFound[RegPair(dstReg, srcReg)] = cBenefit;
}
}
Lang Hames
committed
return coalescesFound;
}
Lang Hames
committed
void RegAllocPBQP::findVRegIntervalsToAlloc() {
Lang Hames
committed
// Iterate over all live ranges.
for (LiveIntervals::iterator itr = lis->begin(), end = lis->end();
itr != end; ++itr) {
// Ignore physical ones.
if (TargetRegisterInfo::isPhysicalRegister(itr->first))
continue;
LiveInterval *li = itr->second;
// If this live interval is non-empty we will use pbqp to allocate it.
// Empty intervals we allocate in a simple post-processing stage in
// finalizeAlloc.
if (!li->empty()) {
Lang Hames
committed
vregsToAlloc.insert(li->reg);
Lang Hames
committed
}
else {
Lang Hames
committed
emptyIntervalVRegs.insert(li->reg);
Lang Hames
committed
}
}
}
Lang Hames
committed
PBQP::Graph RegAllocPBQP::constructPBQPProblem() {
typedef std::vector<const LiveInterval*> LIVector;
Lang Hames
committed
typedef std::vector<unsigned> RegVector;
Lang Hames
committed
// This will store the physical intervals for easy reference.
LIVector physIntervals;
// Start by clearing the old node <-> live interval mappings & allowed sets
li2Node.clear();
node2LI.clear();
allowedSets.clear();
Lang Hames
committed
// Populate physIntervals, update preg use:
for (LiveIntervals::iterator itr = lis->begin(), end = lis->end();
itr != end; ++itr) {
if (TargetRegisterInfo::isPhysicalRegister(itr->first)) {
physIntervals.push_back(itr->second);
mri->setPhysRegUsed(itr->second->reg);
}
Lang Hames
committed
}
Lang Hames
committed
// Iterate over vreg intervals, construct live interval <-> node number
// mappings.
Lang Hames
committed
for (RegSet::const_iterator itr = vregsToAlloc.begin(),
end = vregsToAlloc.end();
Lang Hames
committed
itr != end; ++itr) {
Lang Hames
committed
const LiveInterval *li = &lis->getInterval(*itr);
Lang Hames
committed
li2Node[li] = node2LI.size();
node2LI.push_back(li);
}
Lang Hames
committed
// Get the set of potential coalesces.
Lang Hames
committed
CoalesceMap coalesces;
if (pbqpCoalescing) {
coalesces = findCoalesces();
}
// Construct a PBQP solver for this problem
Lang Hames
committed
problemNodes.resize(vregsToAlloc.size());
// Resize allowedSets container appropriately.
Lang Hames
committed
allowedSets.resize(vregsToAlloc.size());
Jim Grosbach
committed
BitVector ReservedRegs = tri->getReservedRegs(*mf);
// Iterate over virtual register intervals to compute allowed sets...
for (unsigned node = 0; node < node2LI.size(); ++node) {
// Grab pointers to the interval and its register class.
const LiveInterval *li = node2LI[node];
const TargetRegisterClass *liRC = mri->getRegClass(li->reg);
// Start by assuming all allocable registers in the class are allowed...
Jim Grosbach
committed
RegVector liAllowed;
TargetRegisterClass::iterator aob = liRC->allocation_order_begin(*mf);
TargetRegisterClass::iterator aoe = liRC->allocation_order_end(*mf);
for (TargetRegisterClass::iterator it = aob; it != aoe; ++it)
if (!ReservedRegs.test(*it))
liAllowed.push_back(*it);
Lang Hames
committed
// Eliminate the physical registers which overlap with this range, along
// with all their aliases.
for (LIVector::iterator pItr = physIntervals.begin(),
pEnd = physIntervals.end(); pItr != pEnd; ++pItr) {
Lang Hames
committed
if (!li->overlaps(**pItr))
continue;
Lang Hames
committed
unsigned pReg = (*pItr)->reg;
Lang Hames
committed
// If we get here then the live intervals overlap, but we're still ok
// if they're coalescable.
Lang Hames
committed
if (coalesces.find(RegPair(li->reg, pReg)) != coalesces.end()) {
DEBUG(dbgs() << "CoalescingOverride: (" << li->reg << ", " << pReg << ")\n");
Lang Hames
committed
continue;
Lang Hames
committed
}
Lang Hames
committed
// If we get here then we have a genuine exclusion.
Lang Hames
committed
// Remove the overlapping reg...
RegVector::iterator eraseItr =
std::find(liAllowed.begin(), liAllowed.end(), pReg);
Lang Hames
committed
if (eraseItr != liAllowed.end())
liAllowed.erase(eraseItr);
const unsigned *aliasItr = tri->getAliasSet(pReg);
if (aliasItr != 0) {
// ...and its aliases.
for (; *aliasItr != 0; ++aliasItr) {
RegVector::iterator eraseItr =
std::find(liAllowed.begin(), liAllowed.end(), *aliasItr);
Lang Hames
committed
if (eraseItr != liAllowed.end()) {
liAllowed.erase(eraseItr);
}
}
}
}
// Copy the allowed set into a member vector for use when constructing cost
// vectors & matrices, and mapping PBQP solutions back to assignments.
allowedSets[node] = AllowedSet(liAllowed.begin(), liAllowed.end());
// Set the spill cost to the interval weight, or epsilon if the
// interval weight is zero
Lang Hames
committed
PBQP::PBQPNum spillCost = (li->weight != 0.0) ?
li->weight : std::numeric_limits<PBQP::PBQPNum>::min();
// Build a cost vector for this interval.
Lang Hames
committed
problemNodes[node] =
problem.addNode(
buildCostVector(li->reg, allowedSets[node], coalesces, spillCost));
}
Lang Hames
committed
// Now add the cost matrices...
for (unsigned node1 = 0; node1 < node2LI.size(); ++node1) {
const LiveInterval *li = node2LI[node1];
// Test for live range overlaps and insert interference matrices.
for (unsigned node2 = node1 + 1; node2 < node2LI.size(); ++node2) {
const LiveInterval *li2 = node2LI[node2];
Lang Hames
committed
CoalesceMap::const_iterator cmItr =
coalesces.find(RegPair(li->reg, li2->reg));
Lang Hames
committed
PBQP::Matrix *m = 0;
Lang Hames
committed
if (cmItr != coalesces.end()) {
m = buildCoalescingMatrix(allowedSets[node1], allowedSets[node2],
cmItr->second);
}
else if (li->overlaps(*li2)) {
m = buildInterferenceMatrix(allowedSets[node1], allowedSets[node2]);
}
Lang Hames
committed
if (m != 0) {
Lang Hames
committed
problem.addEdge(problemNodes[node1],
problemNodes[node2],
*m);
Lang Hames
committed
delete m;
}
}
}
Lang Hames
committed
assert(problem.getNumNodes() == allowedSets.size());
/*
std::cerr << "Allocating for " << problem.getNumNodes() << " nodes, "
<< problem.getNumEdges() << " edges.\n";
problem.printDot(std::cerr);
*/
// We're done, PBQP problem constructed - return it.
Lang Hames
committed
return problem;
}
Lang Hames
committed
void RegAllocPBQP::addStackInterval(const LiveInterval *spilled,
Evan Cheng
committed
MachineRegisterInfo* mri) {
Lang Hames
committed
int stackSlot = vrm->getStackSlot(spilled->reg);
if (stackSlot == VirtRegMap::NO_STACK_SLOT)
Lang Hames
committed
return;
Evan Cheng
committed
const TargetRegisterClass *RC = mri->getRegClass(spilled->reg);
LiveInterval &stackInterval = lss->getOrCreateInterval(stackSlot, RC);
Lang Hames
committed
VNInfo *vni;
if (stackInterval.getNumValNums() != 0)
vni = stackInterval.getValNumInfo(0);
else
vni = stackInterval.getNextValue(
Lang Hames
committed
LiveInterval &rhsInterval = lis->getInterval(spilled->reg);
stackInterval.MergeRangesInAsValue(rhsInterval, vni);
}
Lang Hames
committed
bool RegAllocPBQP::mapPBQPToRegAlloc(const PBQP::Solution &solution) {
Lang Hames
committed
// Set to true if we have any spills
bool anotherRoundNeeded = false;
// Clear the existing allocation.
vrm->clearAllVirt();
// Iterate over the nodes mapping the PBQP solution to a register assignment.
for (unsigned node = 0; node < node2LI.size(); ++node) {
Lang Hames
committed
unsigned virtReg = node2LI[node]->reg,
allocSelection = solution.getSelection(problemNodes[node]);
Lang Hames
committed
// If the PBQP solution is non-zero it's a physical register...
if (allocSelection != 0) {
// Get the physical reg, subtracting 1 to account for the spill option.
unsigned physReg = allowedSets[node][allocSelection - 1];
Lang Hames
committed
<< tri->getName(physReg) << " (Option: " << allocSelection << ")\n");
Lang Hames
committed
assert(physReg != 0);
// Add to the virt reg map and update the used phys regs.
Lang Hames
committed
vrm->assignVirt2Phys(virtReg, physReg);
}
// ...Otherwise it's a spill.
else {
// Make sure we ignore this virtual reg on the next round
// of allocation
Lang Hames
committed
vregsToAlloc.erase(virtReg);
// Insert spill ranges for this live range
Lang Hames
committed
const LiveInterval *spillInterval = node2LI[node];
double oldSpillWeight = spillInterval->weight;
SmallVector<LiveInterval*, 8> spillIs;
rmf->rememberUseDefs(spillInterval);
std::vector<LiveInterval*> newSpills =
Evan Cheng
committed
lis->addIntervalsForSpills(*spillInterval, spillIs, loopInfo, *vrm);
addStackInterval(spillInterval, mri);
rmf->rememberSpills(spillInterval, newSpills);
Lang Hames
committed
Lang Hames
committed
DEBUG(dbgs() << "VREG " << virtReg << " -> SPILLED (Option: 0, Cost: "
<< oldSpillWeight << ", New vregs: ");
Lang Hames
committed
// Copy any newly inserted live intervals into the list of regs to
// allocate.
for (std::vector<LiveInterval*>::const_iterator
itr = newSpills.begin(), end = newSpills.end();
itr != end; ++itr) {
assert(!(*itr)->empty() && "Empty spill range.");
Lang Hames
committed
Lang Hames
committed
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
vregsToAlloc.insert((*itr)->reg);
}
DEBUG(dbgs() << ")\n");
// We need another round if spill intervals were added.
anotherRoundNeeded |= !newSpills.empty();
}
}
return !anotherRoundNeeded;
}
bool RegAllocPBQP::mapPBQPToRegAlloc2(const PBQPRAProblem &problem,
const PBQP::Solution &solution) {
// Set to true if we have any spills
bool anotherRoundNeeded = false;
// Clear the existing allocation.
vrm->clearAllVirt();
const PBQP::Graph &g = problem.getGraph();
// Iterate over the nodes mapping the PBQP solution to a register
// assignment.
for (PBQP::Graph::ConstNodeItr node = g.nodesBegin(),
nodeEnd = g.nodesEnd();
node != nodeEnd; ++node) {
unsigned vreg = problem.getVRegForNode(node);
unsigned alloc = solution.getSelection(node);
if (problem.isPRegOption(vreg, alloc)) {
unsigned preg = problem.getPRegForOption(vreg, alloc);
DEBUG(dbgs() << "VREG " << vreg << " -> " << tri->getName(preg) << "\n");
assert(preg != 0 && "Invalid preg selected.");
vrm->assignVirt2Phys(vreg, preg);
} else if (problem.isSpillOption(vreg, alloc)) {
vregsToAlloc.erase(vreg);
const LiveInterval* spillInterval = &lis->getInterval(vreg);
double oldWeight = spillInterval->weight;
SmallVector<LiveInterval*, 8> spillIs;
rmf->rememberUseDefs(spillInterval);
std::vector<LiveInterval*> newSpills =
lis->addIntervalsForSpills(*spillInterval, spillIs, loopInfo, *vrm);
addStackInterval(spillInterval, mri);
rmf->rememberSpills(spillInterval, newSpills);
(void) oldWeight;
DEBUG(dbgs() << "VREG " << vreg << " -> SPILLED (Cost: "