forked from OSchip/llvm-project
Refactor scheduler code. Move register-reduction list scheduler to a
separate file. Added an initial implementation of top-down register pressure reduction list scheduler. llvm-svn: 28226
This commit is contained in:
parent
873ef133ce
commit
d38c22bdd3
|
@ -17,6 +17,8 @@
|
||||||
|
|
||||||
#include "llvm/CodeGen/SelectionDAG.h"
|
#include "llvm/CodeGen/SelectionDAG.h"
|
||||||
|
|
||||||
|
#include <set>
|
||||||
|
|
||||||
namespace llvm {
|
namespace llvm {
|
||||||
struct InstrStage;
|
struct InstrStage;
|
||||||
class MachineConstantPool;
|
class MachineConstantPool;
|
||||||
|
@ -71,8 +73,88 @@ namespace llvm {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or
|
||||||
|
/// a group of nodes flagged together.
|
||||||
|
struct SUnit {
|
||||||
|
SDNode *Node; // Representative node.
|
||||||
|
std::vector<SDNode*> FlaggedNodes; // All nodes flagged to Node.
|
||||||
|
|
||||||
|
// Preds/Succs - The SUnits before/after us in the graph. The boolean value
|
||||||
|
// is true if the edge is a token chain edge, false if it is a value edge.
|
||||||
|
std::set<std::pair<SUnit*,bool> > Preds; // All sunit predecessors.
|
||||||
|
std::set<std::pair<SUnit*,bool> > Succs; // All sunit successors.
|
||||||
|
|
||||||
|
short NumPreds; // # of preds.
|
||||||
|
short NumSuccs; // # of sucss.
|
||||||
|
short NumPredsLeft; // # of preds not scheduled.
|
||||||
|
short NumSuccsLeft; // # of succs not scheduled.
|
||||||
|
short NumChainPredsLeft; // # of chain preds not scheduled.
|
||||||
|
short NumChainSuccsLeft; // # of chain succs not scheduled.
|
||||||
|
bool isTwoAddress : 1; // Is a two-address instruction.
|
||||||
|
bool isDefNUseOperand : 1; // Is a def&use operand.
|
||||||
|
bool isPending : 1; // True once pending.
|
||||||
|
bool isAvailable : 1; // True once available.
|
||||||
|
bool isScheduled : 1; // True once scheduled.
|
||||||
|
unsigned short Latency; // Node latency.
|
||||||
|
unsigned CycleBound; // Upper/lower cycle to be scheduled at.
|
||||||
|
unsigned Cycle; // Once scheduled, the cycle of the op.
|
||||||
|
unsigned Depth; // Node depth;
|
||||||
|
unsigned Height; // Node height;
|
||||||
|
unsigned NodeNum; // Entry # of node in the node vector.
|
||||||
|
|
||||||
|
SUnit(SDNode *node, unsigned nodenum)
|
||||||
|
: Node(node), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
|
||||||
|
NumChainPredsLeft(0), NumChainSuccsLeft(0),
|
||||||
|
isTwoAddress(false), isDefNUseOperand(false),
|
||||||
|
isPending(false), isAvailable(false), isScheduled(false),
|
||||||
|
Latency(0), CycleBound(0), Cycle(0), Depth(0), Height(0),
|
||||||
|
NodeNum(nodenum) {}
|
||||||
|
|
||||||
|
void dump(const SelectionDAG *G) const;
|
||||||
|
void dumpAll(const SelectionDAG *G) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
//===--------------------------------------------------------------------===//
|
||||||
|
/// SchedulingPriorityQueue - This interface is used to plug different
|
||||||
|
/// priorities computation algorithms into the list scheduler. It implements
|
||||||
|
/// the interface of a standard priority queue, where nodes are inserted in
|
||||||
|
/// arbitrary order and returned in priority order. The computation of the
|
||||||
|
/// priority and the representation of the queue are totally up to the
|
||||||
|
/// implementation to decide.
|
||||||
|
///
|
||||||
|
class SchedulingPriorityQueue {
|
||||||
|
public:
|
||||||
|
virtual ~SchedulingPriorityQueue() {}
|
||||||
|
|
||||||
|
virtual void initNodes(const std::vector<SUnit> &SUnits) = 0;
|
||||||
|
virtual void releaseState() = 0;
|
||||||
|
|
||||||
|
virtual bool empty() const = 0;
|
||||||
|
virtual void push(SUnit *U) = 0;
|
||||||
|
|
||||||
|
virtual void push_all(const std::vector<SUnit *> &Nodes) = 0;
|
||||||
|
virtual SUnit *pop() = 0;
|
||||||
|
|
||||||
|
/// ScheduledNode - As each node is scheduled, this method is invoked. This
|
||||||
|
/// allows the priority function to adjust the priority of node that have
|
||||||
|
/// already been emitted.
|
||||||
|
virtual void ScheduledNode(SUnit *Node) {}
|
||||||
|
};
|
||||||
|
|
||||||
class ScheduleDAG {
|
class ScheduleDAG {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
// Scheduling heuristics
|
||||||
|
enum SchedHeuristics {
|
||||||
|
defaultScheduling, // Let the target specify its preference.
|
||||||
|
noScheduling, // No scheduling, emit breadth first sequence.
|
||||||
|
simpleScheduling, // Two pass, min. critical path, max. utilization.
|
||||||
|
simpleNoItinScheduling, // Same as above exact using generic latency.
|
||||||
|
listSchedulingBURR, // Bottom-up reg reduction list scheduling.
|
||||||
|
listSchedulingTDRR, // Top-down reg reduction list scheduling.
|
||||||
|
listSchedulingTD // Top-down list scheduler.
|
||||||
|
};
|
||||||
|
|
||||||
SelectionDAG &DAG; // DAG of the current basic block
|
SelectionDAG &DAG; // DAG of the current basic block
|
||||||
MachineBasicBlock *BB; // Current basic block
|
MachineBasicBlock *BB; // Current basic block
|
||||||
const TargetMachine &TM; // Target processor
|
const TargetMachine &TM; // Target processor
|
||||||
|
@ -80,6 +162,10 @@ namespace llvm {
|
||||||
const MRegisterInfo *MRI; // Target processor register info
|
const MRegisterInfo *MRI; // Target processor register info
|
||||||
SSARegMap *RegMap; // Virtual/real register map
|
SSARegMap *RegMap; // Virtual/real register map
|
||||||
MachineConstantPool *ConstPool; // Target constant pool
|
MachineConstantPool *ConstPool; // Target constant pool
|
||||||
|
std::vector<SUnit*> Sequence; // The schedule. Null SUnit*'s represent
|
||||||
|
// noop instructions.
|
||||||
|
std::map<SDNode*, SUnit*> SUnitMap; // SDNode to SUnit mapping (n -> 1).
|
||||||
|
std::vector<SUnit> SUnits; // The scheduling units.
|
||||||
|
|
||||||
ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
|
ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
|
||||||
const TargetMachine &tm)
|
const TargetMachine &tm)
|
||||||
|
@ -105,6 +191,23 @@ namespace llvm {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// NewSUnit - Creates a new SUnit and return a ptr to it.
|
||||||
|
///
|
||||||
|
SUnit *NewSUnit(SDNode *N) {
|
||||||
|
SUnits.push_back(SUnit(N, SUnits.size()));
|
||||||
|
return &SUnits.back();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// BuildSchedUnits - Build SUnits from the selection dag that we are input.
|
||||||
|
/// This SUnit graph is similar to the SelectionDAG, but represents flagged
|
||||||
|
/// together nodes with a single SUnit.
|
||||||
|
void BuildSchedUnits();
|
||||||
|
|
||||||
|
/// CalculateDepths, CalculateHeights - Calculate node depth / height.
|
||||||
|
///
|
||||||
|
void CalculateDepths();
|
||||||
|
void CalculateHeights();
|
||||||
|
|
||||||
/// EmitNode - Generate machine code for an node and needed dependencies.
|
/// EmitNode - Generate machine code for an node and needed dependencies.
|
||||||
/// VRBaseMap contains, for each already emitted node, the first virtual
|
/// VRBaseMap contains, for each already emitted node, the first virtual
|
||||||
/// register number for the results of the node.
|
/// register number for the results of the node.
|
||||||
|
@ -115,6 +218,9 @@ namespace llvm {
|
||||||
///
|
///
|
||||||
void EmitNoop();
|
void EmitNoop();
|
||||||
|
|
||||||
|
void EmitSchedule();
|
||||||
|
|
||||||
|
void dumpSchedule() const;
|
||||||
|
|
||||||
/// Schedule - Order nodes according to selected style.
|
/// Schedule - Order nodes according to selected style.
|
||||||
///
|
///
|
||||||
|
@ -138,6 +244,11 @@ namespace llvm {
|
||||||
ScheduleDAG* createBURRListDAGScheduler(SelectionDAG &DAG,
|
ScheduleDAG* createBURRListDAGScheduler(SelectionDAG &DAG,
|
||||||
MachineBasicBlock *BB);
|
MachineBasicBlock *BB);
|
||||||
|
|
||||||
|
/// createTDRRListDAGScheduler - This creates a top down register usage
|
||||||
|
/// reduction list scheduler.
|
||||||
|
ScheduleDAG* createTDRRListDAGScheduler(SelectionDAG &DAG,
|
||||||
|
MachineBasicBlock *BB);
|
||||||
|
|
||||||
/// createTDListDAGScheduler - This creates a top-down list scheduler with
|
/// createTDListDAGScheduler - This creates a top-down list scheduler with
|
||||||
/// the specified hazard recognizer. This takes ownership of the hazard
|
/// the specified hazard recognizer. This takes ownership of the hazard
|
||||||
/// recognizer and deletes it when done.
|
/// recognizer and deletes it when done.
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
//
|
//
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "sched"
|
||||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||||
#include "llvm/CodeGen/MachineFunction.h"
|
#include "llvm/CodeGen/MachineFunction.h"
|
||||||
|
@ -20,10 +21,185 @@
|
||||||
#include "llvm/Target/TargetMachine.h"
|
#include "llvm/Target/TargetMachine.h"
|
||||||
#include "llvm/Target/TargetInstrInfo.h"
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
#include "llvm/Target/TargetLowering.h"
|
#include "llvm/Target/TargetLowering.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
#include "llvm/Support/MathExtras.h"
|
#include "llvm/Support/MathExtras.h"
|
||||||
|
#include <iostream>
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
|
||||||
|
/// BuildSchedUnits - Build SUnits from the selection dag that we are input.
|
||||||
|
/// This SUnit graph is similar to the SelectionDAG, but represents flagged
|
||||||
|
/// together nodes with a single SUnit.
|
||||||
|
void ScheduleDAG::BuildSchedUnits() {
|
||||||
|
// Reserve entries in the vector for each of the SUnits we are creating. This
|
||||||
|
// ensure that reallocation of the vector won't happen, so SUnit*'s won't get
|
||||||
|
// invalidated.
|
||||||
|
SUnits.reserve(std::distance(DAG.allnodes_begin(), DAG.allnodes_end()));
|
||||||
|
|
||||||
|
const InstrItineraryData &InstrItins = TM.getInstrItineraryData();
|
||||||
|
|
||||||
|
for (SelectionDAG::allnodes_iterator NI = DAG.allnodes_begin(),
|
||||||
|
E = DAG.allnodes_end(); NI != E; ++NI) {
|
||||||
|
if (isPassiveNode(NI)) // Leaf node, e.g. a TargetImmediate.
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// If this node has already been processed, stop now.
|
||||||
|
if (SUnitMap[NI]) continue;
|
||||||
|
|
||||||
|
SUnit *NodeSUnit = NewSUnit(NI);
|
||||||
|
|
||||||
|
// See if anything is flagged to this node, if so, add them to flagged
|
||||||
|
// nodes. Nodes can have at most one flag input and one flag output. Flags
|
||||||
|
// are required the be the last operand and result of a node.
|
||||||
|
|
||||||
|
// Scan up, adding flagged preds to FlaggedNodes.
|
||||||
|
SDNode *N = NI;
|
||||||
|
while (N->getNumOperands() &&
|
||||||
|
N->getOperand(N->getNumOperands()-1).getValueType() == MVT::Flag) {
|
||||||
|
N = N->getOperand(N->getNumOperands()-1).Val;
|
||||||
|
NodeSUnit->FlaggedNodes.push_back(N);
|
||||||
|
SUnitMap[N] = NodeSUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan down, adding this node and any flagged succs to FlaggedNodes if they
|
||||||
|
// have a user of the flag operand.
|
||||||
|
N = NI;
|
||||||
|
while (N->getValueType(N->getNumValues()-1) == MVT::Flag) {
|
||||||
|
SDOperand FlagVal(N, N->getNumValues()-1);
|
||||||
|
|
||||||
|
// There are either zero or one users of the Flag result.
|
||||||
|
bool HasFlagUse = false;
|
||||||
|
for (SDNode::use_iterator UI = N->use_begin(), E = N->use_end();
|
||||||
|
UI != E; ++UI)
|
||||||
|
if (FlagVal.isOperand(*UI)) {
|
||||||
|
HasFlagUse = true;
|
||||||
|
NodeSUnit->FlaggedNodes.push_back(N);
|
||||||
|
SUnitMap[N] = NodeSUnit;
|
||||||
|
N = *UI;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!HasFlagUse) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now all flagged nodes are in FlaggedNodes and N is the bottom-most node.
|
||||||
|
// Update the SUnit
|
||||||
|
NodeSUnit->Node = N;
|
||||||
|
SUnitMap[N] = NodeSUnit;
|
||||||
|
|
||||||
|
// Compute the latency for the node. We use the sum of the latencies for
|
||||||
|
// all nodes flagged together into this SUnit.
|
||||||
|
if (InstrItins.isEmpty()) {
|
||||||
|
// No latency information.
|
||||||
|
NodeSUnit->Latency = 1;
|
||||||
|
} else {
|
||||||
|
NodeSUnit->Latency = 0;
|
||||||
|
if (N->isTargetOpcode()) {
|
||||||
|
unsigned SchedClass = TII->getSchedClass(N->getTargetOpcode());
|
||||||
|
InstrStage *S = InstrItins.begin(SchedClass);
|
||||||
|
InstrStage *E = InstrItins.end(SchedClass);
|
||||||
|
for (; S != E; ++S)
|
||||||
|
NodeSUnit->Latency += S->Cycles;
|
||||||
|
}
|
||||||
|
for (unsigned i = 0, e = NodeSUnit->FlaggedNodes.size(); i != e; ++i) {
|
||||||
|
SDNode *FNode = NodeSUnit->FlaggedNodes[i];
|
||||||
|
if (FNode->isTargetOpcode()) {
|
||||||
|
unsigned SchedClass = TII->getSchedClass(FNode->getTargetOpcode());
|
||||||
|
InstrStage *S = InstrItins.begin(SchedClass);
|
||||||
|
InstrStage *E = InstrItins.end(SchedClass);
|
||||||
|
for (; S != E; ++S)
|
||||||
|
NodeSUnit->Latency += S->Cycles;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass 2: add the preds, succs, etc.
|
||||||
|
for (unsigned su = 0, e = SUnits.size(); su != e; ++su) {
|
||||||
|
SUnit *SU = &SUnits[su];
|
||||||
|
SDNode *MainNode = SU->Node;
|
||||||
|
|
||||||
|
if (MainNode->isTargetOpcode()) {
|
||||||
|
unsigned Opc = MainNode->getTargetOpcode();
|
||||||
|
if (TII->isTwoAddrInstr(Opc)) {
|
||||||
|
SU->isTwoAddress = true;
|
||||||
|
SDNode *OpN = MainNode->getOperand(0).Val;
|
||||||
|
SUnit *OpSU = SUnitMap[OpN];
|
||||||
|
if (OpSU)
|
||||||
|
OpSU->isDefNUseOperand = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find all predecessors and successors of the group.
|
||||||
|
// Temporarily add N to make code simpler.
|
||||||
|
SU->FlaggedNodes.push_back(MainNode);
|
||||||
|
|
||||||
|
for (unsigned n = 0, e = SU->FlaggedNodes.size(); n != e; ++n) {
|
||||||
|
SDNode *N = SU->FlaggedNodes[n];
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
|
||||||
|
SDNode *OpN = N->getOperand(i).Val;
|
||||||
|
if (isPassiveNode(OpN)) continue; // Not scheduled.
|
||||||
|
SUnit *OpSU = SUnitMap[OpN];
|
||||||
|
assert(OpSU && "Node has no SUnit!");
|
||||||
|
if (OpSU == SU) continue; // In the same group.
|
||||||
|
|
||||||
|
MVT::ValueType OpVT = N->getOperand(i).getValueType();
|
||||||
|
assert(OpVT != MVT::Flag && "Flagged nodes should be in same sunit!");
|
||||||
|
bool isChain = OpVT == MVT::Other;
|
||||||
|
|
||||||
|
if (SU->Preds.insert(std::make_pair(OpSU, isChain)).second) {
|
||||||
|
if (!isChain) {
|
||||||
|
SU->NumPreds++;
|
||||||
|
SU->NumPredsLeft++;
|
||||||
|
} else {
|
||||||
|
SU->NumChainPredsLeft++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (OpSU->Succs.insert(std::make_pair(SU, isChain)).second) {
|
||||||
|
if (!isChain) {
|
||||||
|
OpSU->NumSuccs++;
|
||||||
|
OpSU->NumSuccsLeft++;
|
||||||
|
} else {
|
||||||
|
OpSU->NumChainSuccsLeft++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove MainNode from FlaggedNodes again.
|
||||||
|
SU->FlaggedNodes.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CalculateDepths(SUnit *SU, unsigned Depth) {
|
||||||
|
if (Depth > SU->Depth) SU->Depth = Depth;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
|
||||||
|
E = SU->Succs.end(); I != E; ++I)
|
||||||
|
CalculateDepths(I->first, Depth+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduleDAG::CalculateDepths() {
|
||||||
|
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
|
||||||
|
::CalculateDepths(Entry, 0U);
|
||||||
|
for (unsigned i = 0, e = SUnits.size(); i != e; ++i)
|
||||||
|
if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry) {
|
||||||
|
::CalculateDepths(&SUnits[i], 0U);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void CalculateHeights(SUnit *SU, unsigned Height) {
|
||||||
|
if (Height > SU->Height) SU->Height = Height;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
|
||||||
|
E = SU->Preds.end(); I != E; ++I)
|
||||||
|
CalculateHeights(I->first, Height+1);
|
||||||
|
}
|
||||||
|
void ScheduleDAG::CalculateHeights() {
|
||||||
|
SUnit *Root = SUnitMap[DAG.getRoot().Val];
|
||||||
|
::CalculateHeights(Root, 0U);
|
||||||
|
}
|
||||||
|
|
||||||
/// CountResults - The results of target nodes have register or immediate
|
/// CountResults - The results of target nodes have register or immediate
|
||||||
/// operands first, then an optional chain, and optional flag operands (which do
|
/// operands first, then an optional chain, and optional flag operands (which do
|
||||||
/// not go into the machine instrs.)
|
/// not go into the machine instrs.)
|
||||||
|
@ -348,6 +524,32 @@ void ScheduleDAG::EmitNoop() {
|
||||||
TII->insertNoop(*BB, BB->end());
|
TII->insertNoop(*BB, BB->end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EmitSchedule - Emit the machine code in scheduled order.
|
||||||
|
void ScheduleDAG::EmitSchedule() {
|
||||||
|
std::map<SDNode*, unsigned> VRBaseMap;
|
||||||
|
for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
|
||||||
|
if (SUnit *SU = Sequence[i]) {
|
||||||
|
for (unsigned j = 0, ee = SU->FlaggedNodes.size(); j != ee; j++)
|
||||||
|
EmitNode(SU->FlaggedNodes[j], VRBaseMap);
|
||||||
|
EmitNode(SU->Node, VRBaseMap);
|
||||||
|
} else {
|
||||||
|
// Null SUnit* is a noop.
|
||||||
|
EmitNoop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// dump - dump the schedule.
|
||||||
|
void ScheduleDAG::dumpSchedule() const {
|
||||||
|
for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
|
||||||
|
if (SUnit *SU = Sequence[i])
|
||||||
|
SU->dump(&DAG);
|
||||||
|
else
|
||||||
|
std::cerr << "**** NOOP ****\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Run - perform scheduling.
|
/// Run - perform scheduling.
|
||||||
///
|
///
|
||||||
MachineBasicBlock *ScheduleDAG::Run() {
|
MachineBasicBlock *ScheduleDAG::Run() {
|
||||||
|
@ -360,4 +562,53 @@ MachineBasicBlock *ScheduleDAG::Run() {
|
||||||
return BB;
|
return BB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or
|
||||||
|
/// a group of nodes flagged together.
|
||||||
|
void SUnit::dump(const SelectionDAG *G) const {
|
||||||
|
std::cerr << "SU(" << NodeNum << "): ";
|
||||||
|
Node->dump(G);
|
||||||
|
std::cerr << "\n";
|
||||||
|
if (FlaggedNodes.size() != 0) {
|
||||||
|
for (unsigned i = 0, e = FlaggedNodes.size(); i != e; i++) {
|
||||||
|
std::cerr << " ";
|
||||||
|
FlaggedNodes[i]->dump(G);
|
||||||
|
std::cerr << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SUnit::dumpAll(const SelectionDAG *G) const {
|
||||||
|
dump(G);
|
||||||
|
|
||||||
|
std::cerr << " # preds left : " << NumPredsLeft << "\n";
|
||||||
|
std::cerr << " # succs left : " << NumSuccsLeft << "\n";
|
||||||
|
std::cerr << " # chain preds left : " << NumChainPredsLeft << "\n";
|
||||||
|
std::cerr << " # chain succs left : " << NumChainSuccsLeft << "\n";
|
||||||
|
std::cerr << " Latency : " << Latency << "\n";
|
||||||
|
std::cerr << " Depth : " << Depth << "\n";
|
||||||
|
std::cerr << " Height : " << Height << "\n";
|
||||||
|
|
||||||
|
if (Preds.size() != 0) {
|
||||||
|
std::cerr << " Predecessors:\n";
|
||||||
|
for (std::set<std::pair<SUnit*,bool> >::const_iterator I = Preds.begin(),
|
||||||
|
E = Preds.end(); I != E; ++I) {
|
||||||
|
if (I->second)
|
||||||
|
std::cerr << " ch ";
|
||||||
|
else
|
||||||
|
std::cerr << " val ";
|
||||||
|
I->first->dump(G);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Succs.size() != 0) {
|
||||||
|
std::cerr << " Successors:\n";
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::const_iterator I = Succs.begin(),
|
||||||
|
E = Succs.end(); I != E; ++I) {
|
||||||
|
if (I->second)
|
||||||
|
std::cerr << " ch ";
|
||||||
|
else
|
||||||
|
std::cerr << " val ";
|
||||||
|
I->first->dump(G);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cerr << "\n";
|
||||||
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,813 @@
|
||||||
|
//===----- ScheduleDAGList.cpp - Reg pressure reduction list scheduler ----===//
|
||||||
|
//
|
||||||
|
// The LLVM Compiler Infrastructure
|
||||||
|
//
|
||||||
|
// This file was developed by Evan Cheng and is distributed under the
|
||||||
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This implements bottom-up and top-down register pressure reduction list
|
||||||
|
// schedulers, using standard algorithms. The basic approach uses a priority
|
||||||
|
// queue of available nodes to schedule. One at a time, nodes are taken from
|
||||||
|
// the priority queue (thus in priority order), checked for legality to
|
||||||
|
// schedule, and emitted if legal.
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "sched"
|
||||||
|
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||||
|
#include "llvm/CodeGen/SSARegMap.h"
|
||||||
|
#include "llvm/Target/MRegisterInfo.h"
|
||||||
|
#include "llvm/Target/TargetMachine.h"
|
||||||
|
#include "llvm/Target/TargetInstrInfo.h"
|
||||||
|
#include "llvm/Support/Debug.h"
|
||||||
|
#include "llvm/ADT/Statistic.h"
|
||||||
|
#include <climits>
|
||||||
|
#include <iostream>
|
||||||
|
#include <queue>
|
||||||
|
#include "llvm/Support/CommandLine.h"
|
||||||
|
using namespace llvm;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
cl::opt<bool> SchedLowerDefNUse("sched-lower-defnuse", cl::Hidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
/// ScheduleDAGRRList - The actual register reduction list scheduler
|
||||||
|
/// implementation. This supports both top-down and bottom-up scheduling.
|
||||||
|
///
|
||||||
|
|
||||||
|
class ScheduleDAGRRList : public ScheduleDAG {
|
||||||
|
private:
|
||||||
|
/// isBottomUp - This is true if the scheduling problem is bottom-up, false if
|
||||||
|
/// it is top-down.
|
||||||
|
bool isBottomUp;
|
||||||
|
|
||||||
|
/// AvailableQueue - The priority queue to use for the available SUnits.
|
||||||
|
///
|
||||||
|
SchedulingPriorityQueue *AvailableQueue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ScheduleDAGRRList(SelectionDAG &dag, MachineBasicBlock *bb,
|
||||||
|
const TargetMachine &tm, bool isbottomup,
|
||||||
|
SchedulingPriorityQueue *availqueue)
|
||||||
|
: ScheduleDAG(dag, bb, tm), isBottomUp(isbottomup),
|
||||||
|
AvailableQueue(availqueue) {
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScheduleDAGRRList() {
|
||||||
|
delete AvailableQueue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Schedule();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void ReleasePred(SUnit *PredSU, bool isChain, unsigned CurCycle);
|
||||||
|
void ReleaseSucc(SUnit *SuccSU, bool isChain, unsigned CurCycle);
|
||||||
|
void ScheduleNodeBottomUp(SUnit *SU, unsigned& CurCycle);
|
||||||
|
void ScheduleNodeTopDown(SUnit *SU, unsigned& CurCycle);
|
||||||
|
void ListScheduleTopDown();
|
||||||
|
void ListScheduleBottomUp();
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
|
||||||
|
/// Schedule - Schedule the DAG using list scheduling.
|
||||||
|
void ScheduleDAGRRList::Schedule() {
|
||||||
|
DEBUG(std::cerr << "********** List Scheduling **********\n");
|
||||||
|
|
||||||
|
// Build scheduling units.
|
||||||
|
BuildSchedUnits();
|
||||||
|
|
||||||
|
CalculateDepths();
|
||||||
|
CalculateHeights();
|
||||||
|
DEBUG(for (unsigned su = 0, e = SUnits.size(); su != e; ++su)
|
||||||
|
SUnits[su].dumpAll(&DAG));
|
||||||
|
|
||||||
|
AvailableQueue->initNodes(SUnits);
|
||||||
|
|
||||||
|
// Execute the actual scheduling loop Top-Down or Bottom-Up as appropriate.
|
||||||
|
if (isBottomUp)
|
||||||
|
ListScheduleBottomUp();
|
||||||
|
else
|
||||||
|
ListScheduleTopDown();
|
||||||
|
|
||||||
|
AvailableQueue->releaseState();
|
||||||
|
|
||||||
|
DEBUG(std::cerr << "*** Final schedule ***\n");
|
||||||
|
DEBUG(dumpSchedule());
|
||||||
|
DEBUG(std::cerr << "\n");
|
||||||
|
|
||||||
|
// Emit in scheduled order
|
||||||
|
EmitSchedule();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Bottom-Up Scheduling
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
static const TargetRegisterClass *getRegClass(SUnit *SU,
|
||||||
|
const TargetInstrInfo *TII,
|
||||||
|
const MRegisterInfo *MRI,
|
||||||
|
SSARegMap *RegMap) {
|
||||||
|
if (SU->Node->isTargetOpcode()) {
|
||||||
|
unsigned Opc = SU->Node->getTargetOpcode();
|
||||||
|
const TargetInstrDescriptor &II = TII->get(Opc);
|
||||||
|
return II.OpInfo->RegClass;
|
||||||
|
} else {
|
||||||
|
assert(SU->Node->getOpcode() == ISD::CopyFromReg);
|
||||||
|
unsigned SrcReg = cast<RegisterSDNode>(SU->Node->getOperand(1))->getReg();
|
||||||
|
if (MRegisterInfo::isVirtualRegister(SrcReg))
|
||||||
|
return RegMap->getRegClass(SrcReg);
|
||||||
|
else {
|
||||||
|
for (MRegisterInfo::regclass_iterator I = MRI->regclass_begin(),
|
||||||
|
E = MRI->regclass_end(); I != E; ++I)
|
||||||
|
if ((*I)->hasType(SU->Node->getValueType(0)) &&
|
||||||
|
(*I)->contains(SrcReg))
|
||||||
|
return *I;
|
||||||
|
assert(false && "Couldn't find register class for reg copy!");
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned getNumResults(SUnit *SU) {
|
||||||
|
unsigned NumResults = 0;
|
||||||
|
for (unsigned i = 0, e = SU->Node->getNumValues(); i != e; ++i) {
|
||||||
|
MVT::ValueType VT = SU->Node->getValueType(i);
|
||||||
|
if (VT != MVT::Other && VT != MVT::Flag)
|
||||||
|
NumResults++;
|
||||||
|
}
|
||||||
|
return NumResults;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. Add it to
|
||||||
|
/// the Available queue is the count reaches zero. Also update its cycle bound.
|
||||||
|
void ScheduleDAGRRList::ReleasePred(SUnit *PredSU, bool isChain,
|
||||||
|
unsigned CurCycle) {
|
||||||
|
// FIXME: the distance between two nodes is not always == the predecessor's
|
||||||
|
// latency. For example, the reader can very well read the register written
|
||||||
|
// by the predecessor later than the issue cycle. It also depends on the
|
||||||
|
// interrupt model (drain vs. freeze).
|
||||||
|
PredSU->CycleBound = std::max(PredSU->CycleBound, CurCycle + PredSU->Latency);
|
||||||
|
|
||||||
|
if (!isChain)
|
||||||
|
PredSU->NumSuccsLeft--;
|
||||||
|
else
|
||||||
|
PredSU->NumChainSuccsLeft--;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (PredSU->NumSuccsLeft < 0 || PredSU->NumChainSuccsLeft < 0) {
|
||||||
|
std::cerr << "*** List scheduling failed! ***\n";
|
||||||
|
PredSU->dump(&DAG);
|
||||||
|
std::cerr << " has been released too many times!\n";
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((PredSU->NumSuccsLeft + PredSU->NumChainSuccsLeft) == 0) {
|
||||||
|
// EntryToken has to go last! Special case it here.
|
||||||
|
if (PredSU->Node->getOpcode() != ISD::EntryToken) {
|
||||||
|
PredSU->isAvailable = true;
|
||||||
|
AvailableQueue->push(PredSU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ScheduleNodeBottomUp - Add the node to the schedule. Decrement the pending
|
||||||
|
/// count of its predecessors. If a predecessor pending count is zero, add it to
|
||||||
|
/// the Available queue.
|
||||||
|
void ScheduleDAGRRList::ScheduleNodeBottomUp(SUnit *SU, unsigned& CurCycle) {
|
||||||
|
DEBUG(std::cerr << "*** Scheduling [" << CurCycle << "]: ");
|
||||||
|
DEBUG(SU->dump(&DAG));
|
||||||
|
SU->Cycle = CurCycle;
|
||||||
|
|
||||||
|
AvailableQueue->ScheduledNode(SU);
|
||||||
|
Sequence.push_back(SU);
|
||||||
|
|
||||||
|
// Bottom up: release predecessors
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
|
||||||
|
E = SU->Preds.end(); I != E; ++I)
|
||||||
|
ReleasePred(I->first, I->second, CurCycle);
|
||||||
|
SU->isScheduled = true;
|
||||||
|
CurCycle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// isReady - True if node's lower cycle bound is less or equal to the current
|
||||||
|
/// scheduling cycle. Always true if all nodes have uniform latency 1.
|
||||||
|
static inline bool isReady(SUnit *SU, unsigned CurCycle) {
|
||||||
|
return SU->CycleBound <= CurCycle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ListScheduleBottomUp - The main loop of list scheduling for bottom-up
|
||||||
|
/// schedulers.
|
||||||
|
void ScheduleDAGRRList::ListScheduleBottomUp() {
|
||||||
|
unsigned CurCycle = 0;
|
||||||
|
// Add root to Available queue.
|
||||||
|
AvailableQueue->push(SUnitMap[DAG.getRoot().Val]);
|
||||||
|
|
||||||
|
// While Available queue is not empty, grab the node with the highest
|
||||||
|
// priority. If it is not ready put it back. Schedule the node.
|
||||||
|
std::vector<SUnit*> NotReady;
|
||||||
|
SUnit *CurNode = NULL;
|
||||||
|
while (!AvailableQueue->empty()) {
|
||||||
|
SUnit *CurNode = AvailableQueue->pop();
|
||||||
|
while (!isReady(CurNode, CurCycle)) {
|
||||||
|
NotReady.push_back(CurNode);
|
||||||
|
CurNode = AvailableQueue->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the nodes that aren't ready back onto the available list.
|
||||||
|
AvailableQueue->push_all(NotReady);
|
||||||
|
NotReady.clear();
|
||||||
|
|
||||||
|
ScheduleNodeBottomUp(CurNode, CurCycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add entry node last
|
||||||
|
if (DAG.getEntryNode().Val != DAG.getRoot().Val) {
|
||||||
|
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
|
||||||
|
Sequence.push_back(Entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverse the order if it is bottom up.
|
||||||
|
std::reverse(Sequence.begin(), Sequence.end());
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Verify that all SUnits were scheduled.
|
||||||
|
bool AnyNotSched = false;
|
||||||
|
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
|
||||||
|
if (SUnits[i].NumSuccsLeft != 0 || SUnits[i].NumChainSuccsLeft != 0) {
|
||||||
|
if (!AnyNotSched)
|
||||||
|
std::cerr << "*** List scheduling failed! ***\n";
|
||||||
|
SUnits[i].dump(&DAG);
|
||||||
|
std::cerr << "has not been scheduled!\n";
|
||||||
|
AnyNotSched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(!AnyNotSched);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Top-Down Scheduling
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
/// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
|
||||||
|
/// the PendingQueue if the count reaches zero.
|
||||||
|
void ScheduleDAGRRList::ReleaseSucc(SUnit *SuccSU, bool isChain,
|
||||||
|
unsigned CurCycle) {
|
||||||
|
// FIXME: the distance between two nodes is not always == the predecessor's
|
||||||
|
// latency. For example, the reader can very well read the register written
|
||||||
|
// by the predecessor later than the issue cycle. It also depends on the
|
||||||
|
// interrupt model (drain vs. freeze).
|
||||||
|
SuccSU->CycleBound = std::max(SuccSU->CycleBound, CurCycle + SuccSU->Latency);
|
||||||
|
|
||||||
|
if (!isChain)
|
||||||
|
SuccSU->NumPredsLeft--;
|
||||||
|
else
|
||||||
|
SuccSU->NumChainPredsLeft--;
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (SuccSU->NumPredsLeft < 0 || SuccSU->NumChainPredsLeft < 0) {
|
||||||
|
std::cerr << "*** List scheduling failed! ***\n";
|
||||||
|
SuccSU->dump(&DAG);
|
||||||
|
std::cerr << " has been released too many times!\n";
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
|
||||||
|
SuccSU->isAvailable = true;
|
||||||
|
AvailableQueue->push(SuccSU);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending
|
||||||
|
/// count of its successors. If a successor pending count is zero, add it to
|
||||||
|
/// the Available queue.
|
||||||
|
void ScheduleDAGRRList::ScheduleNodeTopDown(SUnit *SU, unsigned& CurCycle) {
|
||||||
|
DEBUG(std::cerr << "*** Scheduling [" << CurCycle << "]: ");
|
||||||
|
DEBUG(SU->dump(&DAG));
|
||||||
|
SU->Cycle = CurCycle;
|
||||||
|
|
||||||
|
AvailableQueue->ScheduledNode(SU);
|
||||||
|
Sequence.push_back(SU);
|
||||||
|
|
||||||
|
// Top down: release successors
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
|
||||||
|
E = SU->Succs.end(); I != E; ++I)
|
||||||
|
ReleaseSucc(I->first, I->second, CurCycle);
|
||||||
|
SU->isScheduled = true;
|
||||||
|
CurCycle++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScheduleDAGRRList::ListScheduleTopDown() {
|
||||||
|
unsigned CurCycle = 0;
|
||||||
|
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
|
||||||
|
|
||||||
|
// All leaves to Available queue.
|
||||||
|
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
|
||||||
|
// It is available if it has no predecessors.
|
||||||
|
if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry) {
|
||||||
|
AvailableQueue->push(&SUnits[i]);
|
||||||
|
SUnits[i].isAvailable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the entry node first.
|
||||||
|
ScheduleNodeTopDown(Entry, CurCycle);
|
||||||
|
|
||||||
|
// While Available queue is not empty, grab the node with the highest
|
||||||
|
// priority. If it is not ready put it back. Schedule the node.
|
||||||
|
std::vector<SUnit*> NotReady;
|
||||||
|
SUnit *CurNode = NULL;
|
||||||
|
while (!AvailableQueue->empty()) {
|
||||||
|
SUnit *CurNode = AvailableQueue->pop();
|
||||||
|
while (!isReady(CurNode, CurCycle)) {
|
||||||
|
NotReady.push_back(CurNode);
|
||||||
|
CurNode = AvailableQueue->pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the nodes that aren't ready back onto the available list.
|
||||||
|
AvailableQueue->push_all(NotReady);
|
||||||
|
NotReady.clear();
|
||||||
|
|
||||||
|
ScheduleNodeTopDown(CurNode, CurCycle);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Verify that all SUnits were scheduled.
|
||||||
|
bool AnyNotSched = false;
|
||||||
|
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
|
||||||
|
if (!SUnits[i].isScheduled) {
|
||||||
|
if (!AnyNotSched)
|
||||||
|
std::cerr << "*** List scheduling failed! ***\n";
|
||||||
|
SUnits[i].dump(&DAG);
|
||||||
|
std::cerr << "has not been scheduled!\n";
|
||||||
|
AnyNotSched = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(!AnyNotSched);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// RegReductionPriorityQueue Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This is a SchedulingPriorityQueue that schedules using Sethi Ullman numbers
|
||||||
|
// to reduce register pressure.
|
||||||
|
//
|
||||||
|
namespace {
|
||||||
|
template<class SF>
|
||||||
|
class RegReductionPriorityQueue;
|
||||||
|
|
||||||
|
/// Sorting functions for the Available queue.
|
||||||
|
struct bu_ls_rr_sort : public std::binary_function<SUnit*, SUnit*, bool> {
|
||||||
|
RegReductionPriorityQueue<bu_ls_rr_sort> *SPQ;
|
||||||
|
bu_ls_rr_sort(RegReductionPriorityQueue<bu_ls_rr_sort> *spq) : SPQ(spq) {}
|
||||||
|
bu_ls_rr_sort(const bu_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {}
|
||||||
|
|
||||||
|
bool operator()(const SUnit* left, const SUnit* right) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct td_ls_rr_sort : public std::binary_function<SUnit*, SUnit*, bool> {
|
||||||
|
RegReductionPriorityQueue<td_ls_rr_sort> *SPQ;
|
||||||
|
td_ls_rr_sort(RegReductionPriorityQueue<td_ls_rr_sort> *spq) : SPQ(spq) {}
|
||||||
|
td_ls_rr_sort(const td_ls_rr_sort &RHS) : SPQ(RHS.SPQ) {}
|
||||||
|
|
||||||
|
bool operator()(const SUnit* left, const SUnit* right) const;
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template<class SF>
|
||||||
|
class RegReductionPriorityQueue : public SchedulingPriorityQueue {
|
||||||
|
std::priority_queue<SUnit*, std::vector<SUnit*>, SF> Queue;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RegReductionPriorityQueue() :
|
||||||
|
Queue(SF(this)) {}
|
||||||
|
|
||||||
|
virtual void initNodes(const std::vector<SUnit> &sunits) {}
|
||||||
|
virtual void releaseState() {}
|
||||||
|
|
||||||
|
virtual int getSethiUllmanNumber(unsigned NodeNum) const {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return Queue.empty(); }
|
||||||
|
|
||||||
|
void push(SUnit *U) {
|
||||||
|
Queue.push(U);
|
||||||
|
}
|
||||||
|
void push_all(const std::vector<SUnit *> &Nodes) {
|
||||||
|
for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
|
||||||
|
Queue.push(Nodes[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
SUnit *pop() {
|
||||||
|
SUnit *V = Queue.top();
|
||||||
|
Queue.pop();
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class SF>
|
||||||
|
class BURegReductionPriorityQueue : public RegReductionPriorityQueue<SF> {
|
||||||
|
// SUnits - The SUnits for the current graph.
|
||||||
|
const std::vector<SUnit> *SUnits;
|
||||||
|
|
||||||
|
// SethiUllmanNumbers - The SethiUllman number for each node.
|
||||||
|
std::vector<int> SethiUllmanNumbers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
BURegReductionPriorityQueue() {}
|
||||||
|
|
||||||
|
void initNodes(const std::vector<SUnit> &sunits) {
|
||||||
|
SUnits = &sunits;
|
||||||
|
// Add pseudo dependency edges for two-address nodes.
|
||||||
|
if (SchedLowerDefNUse)
|
||||||
|
AddPseudoTwoAddrDeps();
|
||||||
|
// Calculate node priorities.
|
||||||
|
CalculatePriorities();
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseState() {
|
||||||
|
SUnits = 0;
|
||||||
|
SethiUllmanNumbers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSethiUllmanNumber(unsigned NodeNum) const {
|
||||||
|
assert(NodeNum < SethiUllmanNumbers.size());
|
||||||
|
return SethiUllmanNumbers[NodeNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void AddPseudoTwoAddrDeps();
|
||||||
|
void CalculatePriorities();
|
||||||
|
int CalcNodePriority(const SUnit *SU);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
template<class SF>
|
||||||
|
class TDRegReductionPriorityQueue : public RegReductionPriorityQueue<SF> {
|
||||||
|
// SUnits - The SUnits for the current graph.
|
||||||
|
const std::vector<SUnit> *SUnits;
|
||||||
|
|
||||||
|
// SethiUllmanNumbers - The SethiUllman number for each node.
|
||||||
|
std::vector<int> SethiUllmanNumbers;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TDRegReductionPriorityQueue() {}
|
||||||
|
|
||||||
|
void initNodes(const std::vector<SUnit> &sunits) {
|
||||||
|
SUnits = &sunits;
|
||||||
|
// Calculate node priorities.
|
||||||
|
CalculatePriorities();
|
||||||
|
}
|
||||||
|
|
||||||
|
void releaseState() {
|
||||||
|
SUnits = 0;
|
||||||
|
SethiUllmanNumbers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getSethiUllmanNumber(unsigned NodeNum) const {
|
||||||
|
assert(NodeNum < SethiUllmanNumbers.size());
|
||||||
|
return SethiUllmanNumbers[NodeNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void CalculatePriorities();
|
||||||
|
int CalcNodePriority(const SUnit *SU);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bottom up
|
||||||
|
bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
|
||||||
|
unsigned LeftNum = left->NodeNum;
|
||||||
|
unsigned RightNum = right->NodeNum;
|
||||||
|
bool LIsTarget = left->Node->isTargetOpcode();
|
||||||
|
bool RIsTarget = right->Node->isTargetOpcode();
|
||||||
|
int LPriority = SPQ->getSethiUllmanNumber(LeftNum);
|
||||||
|
int RPriority = SPQ->getSethiUllmanNumber(RightNum);
|
||||||
|
bool LIsFloater = LIsTarget && (LPriority == 1 || LPriority == 0);
|
||||||
|
bool RIsFloater = RIsTarget && (RPriority == 1 || RPriority == 0);
|
||||||
|
int LBonus = 0;
|
||||||
|
int RBonus = 0;
|
||||||
|
|
||||||
|
// Schedule floaters (e.g. load from some constant address) and those nodes
|
||||||
|
// with a single predecessor each first. They maintain / reduce register
|
||||||
|
// pressure.
|
||||||
|
if (LIsFloater)
|
||||||
|
LBonus += 2;
|
||||||
|
if (RIsFloater)
|
||||||
|
RBonus += 2;
|
||||||
|
|
||||||
|
if (!SchedLowerDefNUse) {
|
||||||
|
// Special tie breaker: if two nodes share a operand, the one that use it
|
||||||
|
// as a def&use operand is preferred.
|
||||||
|
if (LIsTarget && RIsTarget) {
|
||||||
|
if (left->isTwoAddress && !right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = left->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(right->Node))
|
||||||
|
LBonus += 2;
|
||||||
|
}
|
||||||
|
if (!left->isTwoAddress && right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = right->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(left->Node))
|
||||||
|
RBonus += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (LPriority+LBonus < RPriority+RBonus)
|
||||||
|
return true;
|
||||||
|
else if (LPriority+LBonus == RPriority+RBonus)
|
||||||
|
if (left->NumPredsLeft > right->NumPredsLeft)
|
||||||
|
return true;
|
||||||
|
else if (left->NumPredsLeft+LBonus == right->NumPredsLeft+RBonus)
|
||||||
|
if (left->CycleBound > right->CycleBound)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool isCopyFromLiveIn(const SUnit *SU) {
|
||||||
|
SDNode *N = SU->Node;
|
||||||
|
return N->getOpcode() == ISD::CopyFromReg &&
|
||||||
|
N->getOperand(N->getNumOperands()-1).getValueType() != MVT::Flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: This is probably too slow!
|
||||||
|
static void isReachable(SUnit *SU, SUnit *TargetSU,
|
||||||
|
std::set<SUnit *> &Visited, bool &Reached) {
|
||||||
|
if (Reached) return;
|
||||||
|
if (SU == TargetSU) {
|
||||||
|
Reached = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Visited.insert(SU).second) return;
|
||||||
|
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
|
||||||
|
E = SU->Preds.end(); I != E; ++I)
|
||||||
|
isReachable(I->first, TargetSU, Visited, Reached);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isReachable(SUnit *SU, SUnit *TargetSU) {
|
||||||
|
std::set<SUnit *> Visited;
|
||||||
|
bool Reached = false;
|
||||||
|
isReachable(SU, TargetSU, Visited, Reached);
|
||||||
|
return Reached;
|
||||||
|
}
|
||||||
|
|
||||||
|
static SUnit *getDefUsePredecessor(SUnit *SU) {
|
||||||
|
SDNode *DU = SU->Node->getOperand(0).Val;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator
|
||||||
|
I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) {
|
||||||
|
if (I->second) continue; // ignore chain preds
|
||||||
|
SUnit *PredSU = I->first;
|
||||||
|
if (PredSU->Node == DU)
|
||||||
|
return PredSU;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must be flagged.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool canClobber(SUnit *SU, SUnit *Op) {
|
||||||
|
if (SU->isTwoAddress)
|
||||||
|
return Op == getDefUsePredecessor(SU);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AddPseudoTwoAddrDeps - If two nodes share an operand and one of them uses
|
||||||
|
/// it as a def&use operand. Add a pseudo control edge from it to the other
|
||||||
|
/// node (if it won't create a cycle) so the two-address one will be scheduled
|
||||||
|
/// first (lower in the schedule).
|
||||||
|
template<class SF>
|
||||||
|
void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
|
||||||
|
for (unsigned i = 0, e = SUnits->size(); i != e; ++i) {
|
||||||
|
SUnit *SU = (SUnit *)&((*SUnits)[i]);
|
||||||
|
SDNode *Node = SU->Node;
|
||||||
|
if (!Node->isTargetOpcode())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (SU->isTwoAddress) {
|
||||||
|
unsigned Depth = SU->Node->getNodeDepth();
|
||||||
|
SUnit *DUSU = getDefUsePredecessor(SU);
|
||||||
|
if (!DUSU) continue;
|
||||||
|
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::iterator I = DUSU->Succs.begin(),
|
||||||
|
E = DUSU->Succs.end(); I != E; ++I) {
|
||||||
|
SUnit *SuccSU = I->first;
|
||||||
|
if (SuccSU != SU && !canClobber(SuccSU, DUSU)) {
|
||||||
|
if (SuccSU->Node->getNodeDepth() <= Depth+2 &&
|
||||||
|
!isReachable(SuccSU, SU)) {
|
||||||
|
DEBUG(std::cerr << "Adding an edge from SU # " << SU->NodeNum
|
||||||
|
<< " to SU #" << SuccSU->NodeNum << "\n");
|
||||||
|
if (SU->Preds.insert(std::make_pair(SuccSU, true)).second)
|
||||||
|
SU->NumChainPredsLeft++;
|
||||||
|
if (SuccSU->Succs.insert(std::make_pair(SU, true)).second)
|
||||||
|
SuccSU->NumChainSuccsLeft++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CalcNodePriority - Priority is the Sethi Ullman number.
|
||||||
|
/// Smaller number is the higher priority.
|
||||||
|
template<class SF>
|
||||||
|
int BURegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) {
|
||||||
|
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
|
||||||
|
if (SethiUllmanNumber != 0)
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
|
||||||
|
unsigned Opc = SU->Node->getOpcode();
|
||||||
|
if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg)
|
||||||
|
SethiUllmanNumber = INT_MAX - 10;
|
||||||
|
else if (SU->NumSuccsLeft == 0)
|
||||||
|
// If SU does not have a use, i.e. it doesn't produce a value that would
|
||||||
|
// be consumed (e.g. store), then it terminates a chain of computation.
|
||||||
|
// Give it a small SethiUllman number so it will be scheduled right before its
|
||||||
|
// predecessors that it doesn't lengthen their live ranges.
|
||||||
|
SethiUllmanNumber = INT_MIN + 10;
|
||||||
|
else if (SU->NumPredsLeft == 0 &&
|
||||||
|
(Opc != ISD::CopyFromReg || isCopyFromLiveIn(SU)))
|
||||||
|
SethiUllmanNumber = 1;
|
||||||
|
else {
|
||||||
|
int Extra = 0;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::const_iterator
|
||||||
|
I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) {
|
||||||
|
if (I->second) continue; // ignore chain preds
|
||||||
|
SUnit *PredSU = I->first;
|
||||||
|
int PredSethiUllman = CalcNodePriority(PredSU);
|
||||||
|
if (PredSethiUllman > SethiUllmanNumber) {
|
||||||
|
SethiUllmanNumber = PredSethiUllman;
|
||||||
|
Extra = 0;
|
||||||
|
} else if (PredSethiUllman == SethiUllmanNumber && !I->second)
|
||||||
|
Extra++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SethiUllmanNumber += Extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CalculatePriorities - Calculate priorities of all scheduling units.
|
||||||
|
template<class SF>
|
||||||
|
void BURegReductionPriorityQueue<SF>::CalculatePriorities() {
|
||||||
|
SethiUllmanNumbers.assign(SUnits->size(), 0);
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = SUnits->size(); i != e; ++i)
|
||||||
|
CalcNodePriority(&(*SUnits)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned SumOfUnscheduledPredsOfSuccs(const SUnit *SU) {
|
||||||
|
unsigned Sum = 0;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::const_iterator
|
||||||
|
I = SU->Succs.begin(), E = SU->Succs.end(); I != E; ++I) {
|
||||||
|
SUnit *SuccSU = I->first;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::const_iterator
|
||||||
|
II = SuccSU->Preds.begin(), EE = SuccSU->Preds.end(); II != EE; ++II) {
|
||||||
|
SUnit *PredSU = II->first;
|
||||||
|
if (!PredSU->isScheduled)
|
||||||
|
Sum++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Top down
|
||||||
|
bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
|
||||||
|
unsigned LeftNum = left->NodeNum;
|
||||||
|
unsigned RightNum = right->NodeNum;
|
||||||
|
int LPriority = SPQ->getSethiUllmanNumber(LeftNum);
|
||||||
|
int RPriority = SPQ->getSethiUllmanNumber(RightNum);
|
||||||
|
bool LIsTarget = left->Node->isTargetOpcode();
|
||||||
|
bool RIsTarget = right->Node->isTargetOpcode();
|
||||||
|
bool LIsFloater = LIsTarget && left->NumPreds == 0;
|
||||||
|
bool RIsFloater = RIsTarget && right->NumPreds == 0;
|
||||||
|
unsigned LBonus = (SumOfUnscheduledPredsOfSuccs(left) == 1) ? 2 : 0;
|
||||||
|
unsigned RBonus = (SumOfUnscheduledPredsOfSuccs(right) == 1) ? 2 : 0;
|
||||||
|
|
||||||
|
if (left->NumSuccs == 0 && right->NumSuccs != 0)
|
||||||
|
return false;
|
||||||
|
else if (left->NumSuccs != 0 && right->NumSuccs == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Special tie breaker: if two nodes share a operand, the one that use it
|
||||||
|
// as a def&use operand is preferred.
|
||||||
|
if (LIsTarget && RIsTarget) {
|
||||||
|
if (left->isTwoAddress && !right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = left->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(right->Node))
|
||||||
|
RBonus += 2;
|
||||||
|
}
|
||||||
|
if (!left->isTwoAddress && right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = right->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(left->Node))
|
||||||
|
LBonus += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (LIsFloater)
|
||||||
|
LBonus -= 2;
|
||||||
|
if (RIsFloater)
|
||||||
|
RBonus -= 2;
|
||||||
|
if (left->NumSuccs == 1)
|
||||||
|
LBonus += 2;
|
||||||
|
if (right->NumSuccs == 1)
|
||||||
|
RBonus += 2;
|
||||||
|
|
||||||
|
if (LPriority+LBonus < RPriority+RBonus)
|
||||||
|
return true;
|
||||||
|
else if (LPriority == RPriority)
|
||||||
|
if (left->Depth < right->Depth)
|
||||||
|
return true;
|
||||||
|
else if (left->Depth == right->Depth)
|
||||||
|
if (left->NumSuccsLeft > right->NumSuccsLeft)
|
||||||
|
return true;
|
||||||
|
else if (left->NumSuccsLeft == right->NumSuccsLeft)
|
||||||
|
if (left->CycleBound > right->CycleBound)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CalcNodePriority - Priority is the Sethi Ullman number.
|
||||||
|
/// Smaller number is the higher priority.
|
||||||
|
template<class SF>
|
||||||
|
int TDRegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) {
|
||||||
|
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
|
||||||
|
if (SethiUllmanNumber != 0)
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
|
||||||
|
unsigned Opc = SU->Node->getOpcode();
|
||||||
|
if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg)
|
||||||
|
SethiUllmanNumber = INT_MAX - 10;
|
||||||
|
else if (SU->NumSuccsLeft == 0)
|
||||||
|
// If SU does not have a use, i.e. it doesn't produce a value that would
|
||||||
|
// be consumed (e.g. store), then it terminates a chain of computation.
|
||||||
|
// Give it a small SethiUllman number so it will be scheduled right before its
|
||||||
|
// predecessors that it doesn't lengthen their live ranges.
|
||||||
|
SethiUllmanNumber = INT_MIN + 10;
|
||||||
|
else if (SU->NumPredsLeft == 0 &&
|
||||||
|
(Opc != ISD::CopyFromReg || isCopyFromLiveIn(SU)))
|
||||||
|
SethiUllmanNumber = 1;
|
||||||
|
else {
|
||||||
|
int Extra = 0;
|
||||||
|
for (std::set<std::pair<SUnit*, bool> >::const_iterator
|
||||||
|
I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) {
|
||||||
|
if (I->second) continue; // ignore chain preds
|
||||||
|
SUnit *PredSU = I->first;
|
||||||
|
int PredSethiUllman = CalcNodePriority(PredSU);
|
||||||
|
if (PredSethiUllman > SethiUllmanNumber) {
|
||||||
|
SethiUllmanNumber = PredSethiUllman;
|
||||||
|
Extra = 0;
|
||||||
|
} else if (PredSethiUllman == SethiUllmanNumber && !I->second)
|
||||||
|
Extra++;
|
||||||
|
}
|
||||||
|
|
||||||
|
SethiUllmanNumber += Extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CalculatePriorities - Calculate priorities of all scheduling units.
|
||||||
|
template<class SF>
|
||||||
|
void TDRegReductionPriorityQueue<SF>::CalculatePriorities() {
|
||||||
|
SethiUllmanNumbers.assign(SUnits->size(), 0);
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = SUnits->size(); i != e; ++i)
|
||||||
|
CalcNodePriority(&(*SUnits)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Public Constructor Functions
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
llvm::ScheduleDAG* llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
|
||||||
|
MachineBasicBlock *BB) {
|
||||||
|
return new ScheduleDAGRRList(DAG, BB, DAG.getTarget(), true,
|
||||||
|
new BURegReductionPriorityQueue<bu_ls_rr_sort>());
|
||||||
|
}
|
||||||
|
|
||||||
|
llvm::ScheduleDAG* llvm::createTDRRListDAGScheduler(SelectionDAG &DAG,
|
||||||
|
MachineBasicBlock *BB) {
|
||||||
|
return new ScheduleDAGRRList(DAG, BB, DAG.getTarget(), false,
|
||||||
|
new TDRegReductionPriorityQueue<td_ls_rr_sort>());
|
||||||
|
}
|
||||||
|
|
|
@ -58,36 +58,28 @@ ViewSchedDAGs("view-sched-dags", cl::Hidden,
|
||||||
static const bool ViewISelDAGs = 0, ViewSchedDAGs = 0;
|
static const bool ViewISelDAGs = 0, ViewSchedDAGs = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Scheduling heuristics
|
|
||||||
enum SchedHeuristics {
|
|
||||||
defaultScheduling, // Let the target specify its preference.
|
|
||||||
noScheduling, // No scheduling, emit breadth first sequence.
|
|
||||||
simpleScheduling, // Two pass, min. critical path, max. utilization.
|
|
||||||
simpleNoItinScheduling, // Same as above exact using generic latency.
|
|
||||||
listSchedulingBURR, // Bottom up reg reduction list scheduling.
|
|
||||||
listSchedulingTD // Top-down list scheduler.
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
cl::opt<SchedHeuristics>
|
cl::opt<ScheduleDAG::SchedHeuristics>
|
||||||
ISHeuristic(
|
ISHeuristic(
|
||||||
"sched",
|
"sched",
|
||||||
cl::desc("Choose scheduling style"),
|
cl::desc("Choose scheduling style"),
|
||||||
cl::init(defaultScheduling),
|
cl::init(ScheduleDAG::defaultScheduling),
|
||||||
cl::values(
|
cl::values(
|
||||||
clEnumValN(defaultScheduling, "default",
|
clEnumValN(ScheduleDAG::defaultScheduling, "default",
|
||||||
"Target preferred scheduling style"),
|
"Target preferred scheduling style"),
|
||||||
clEnumValN(noScheduling, "none",
|
clEnumValN(ScheduleDAG::noScheduling, "none",
|
||||||
"No scheduling: breadth first sequencing"),
|
"No scheduling: breadth first sequencing"),
|
||||||
clEnumValN(simpleScheduling, "simple",
|
clEnumValN(ScheduleDAG::simpleScheduling, "simple",
|
||||||
"Simple two pass scheduling: minimize critical path "
|
"Simple two pass scheduling: minimize critical path "
|
||||||
"and maximize processor utilization"),
|
"and maximize processor utilization"),
|
||||||
clEnumValN(simpleNoItinScheduling, "simple-noitin",
|
clEnumValN(ScheduleDAG::simpleNoItinScheduling, "simple-noitin",
|
||||||
"Simple two pass scheduling: Same as simple "
|
"Simple two pass scheduling: Same as simple "
|
||||||
"except using generic latency"),
|
"except using generic latency"),
|
||||||
clEnumValN(listSchedulingBURR, "list-burr",
|
clEnumValN(ScheduleDAG::listSchedulingBURR, "list-burr",
|
||||||
"Bottom up register reduction list scheduling"),
|
"Bottom-up register reduction list scheduling"),
|
||||||
clEnumValN(listSchedulingTD, "list-td",
|
clEnumValN(ScheduleDAG::listSchedulingTDRR, "list-tdrr",
|
||||||
|
"Top-down register reduction list scheduling"),
|
||||||
|
clEnumValN(ScheduleDAG::listSchedulingTD, "list-td",
|
||||||
"Top-down list scheduler"),
|
"Top-down list scheduler"),
|
||||||
clEnumValEnd));
|
clEnumValEnd));
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -3418,7 +3410,7 @@ void SelectionDAGISel::ScheduleAndEmitDAG(SelectionDAG &DAG) {
|
||||||
|
|
||||||
switch (ISHeuristic) {
|
switch (ISHeuristic) {
|
||||||
default: assert(0 && "Unrecognized scheduling heuristic");
|
default: assert(0 && "Unrecognized scheduling heuristic");
|
||||||
case defaultScheduling:
|
case ScheduleDAG::defaultScheduling:
|
||||||
if (TLI.getSchedulingPreference() == TargetLowering::SchedulingForLatency)
|
if (TLI.getSchedulingPreference() == TargetLowering::SchedulingForLatency)
|
||||||
SL = createTDListDAGScheduler(DAG, BB, CreateTargetHazardRecognizer());
|
SL = createTDListDAGScheduler(DAG, BB, CreateTargetHazardRecognizer());
|
||||||
else {
|
else {
|
||||||
|
@ -3427,19 +3419,22 @@ void SelectionDAGISel::ScheduleAndEmitDAG(SelectionDAG &DAG) {
|
||||||
SL = createBURRListDAGScheduler(DAG, BB);
|
SL = createBURRListDAGScheduler(DAG, BB);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case noScheduling:
|
case ScheduleDAG::noScheduling:
|
||||||
SL = createBFS_DAGScheduler(DAG, BB);
|
SL = createBFS_DAGScheduler(DAG, BB);
|
||||||
break;
|
break;
|
||||||
case simpleScheduling:
|
case ScheduleDAG::simpleScheduling:
|
||||||
SL = createSimpleDAGScheduler(false, DAG, BB);
|
SL = createSimpleDAGScheduler(false, DAG, BB);
|
||||||
break;
|
break;
|
||||||
case simpleNoItinScheduling:
|
case ScheduleDAG::simpleNoItinScheduling:
|
||||||
SL = createSimpleDAGScheduler(true, DAG, BB);
|
SL = createSimpleDAGScheduler(true, DAG, BB);
|
||||||
break;
|
break;
|
||||||
case listSchedulingBURR:
|
case ScheduleDAG::listSchedulingBURR:
|
||||||
SL = createBURRListDAGScheduler(DAG, BB);
|
SL = createBURRListDAGScheduler(DAG, BB);
|
||||||
break;
|
break;
|
||||||
case listSchedulingTD:
|
case ScheduleDAG::listSchedulingTDRR:
|
||||||
|
SL = createTDRRListDAGScheduler(DAG, BB);
|
||||||
|
break;
|
||||||
|
case ScheduleDAG::listSchedulingTD:
|
||||||
SL = createTDListDAGScheduler(DAG, BB, CreateTargetHazardRecognizer());
|
SL = createTDListDAGScheduler(DAG, BB, CreateTargetHazardRecognizer());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue