aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/CodeGen/ScheduleDAG.h9
-rw-r--r--include/llvm/Target/TargetInstrInfo.h3
-rw-r--r--lib/CodeGen/SelectionDAG/ScheduleDAG.cpp22
-rw-r--r--lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp70
4 files changed, 69 insertions, 35 deletions
diff --git a/include/llvm/CodeGen/ScheduleDAG.h b/include/llvm/CodeGen/ScheduleDAG.h
index 5f9236d401..6263dfb57f 100644
--- a/include/llvm/CodeGen/ScheduleDAG.h
+++ b/include/llvm/CodeGen/ScheduleDAG.h
@@ -91,7 +91,7 @@ namespace llvm {
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 isCommutable : 1; // Is a commutable instruction.
bool isPending : 1; // True once pending.
bool isAvailable : 1; // True once available.
bool isScheduled : 1; // True once scheduled.
@@ -105,7 +105,7 @@ namespace llvm {
SUnit(SDNode *node, unsigned nodenum)
: Node(node), NumPreds(0), NumSuccs(0), NumPredsLeft(0), NumSuccsLeft(0),
NumChainPredsLeft(0), NumChainSuccsLeft(0),
- isTwoAddress(false), isDefNUseOperand(false),
+ isTwoAddress(false), isCommutable(false),
isPending(false), isAvailable(false), isScheduled(false),
Latency(0), CycleBound(0), Cycle(0), Depth(0), Height(0),
NodeNum(nodenum) {}
@@ -162,10 +162,11 @@ namespace llvm {
const MRegisterInfo *MRI; // Target processor register info
SSARegMap *RegMap; // Virtual/real register map
MachineConstantPool *ConstPool; // Target constant pool
- std::vector<SUnit*> Sequence; // The schedule. Null SUnit*'s represent
- // noop instructions.
+ 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.
+ std::set<SDNode*> CommuteSet; // Nodes the should be commuted.
ScheduleDAG(SelectionDAG &dag, MachineBasicBlock *bb,
const TargetMachine &tm)
diff --git a/include/llvm/Target/TargetInstrInfo.h b/include/llvm/Target/TargetInstrInfo.h
index c9a958e25a..625f5c2170 100644
--- a/include/llvm/Target/TargetInstrInfo.h
+++ b/include/llvm/Target/TargetInstrInfo.h
@@ -165,6 +165,9 @@ public:
bool isTwoAddrInstr(MachineOpCode Opcode) const {
return get(Opcode).Flags & M_2_ADDR_FLAG;
}
+ bool isCommutableInstr(MachineOpCode Opcode) const {
+ return get(Opcode).Flags & M_COMMUTABLE;
+ }
bool isTerminatorInstr(unsigned Opcode) const {
return get(Opcode).Flags & M_TERMINATOR_FLAG;
}
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
index 4a9b9c7f04..e05d9d7103 100644
--- a/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
+++ b/lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
@@ -120,13 +120,10 @@ void ScheduleDAG::BuildSchedUnits() {
if (MainNode->isTargetOpcode()) {
unsigned Opc = MainNode->getTargetOpcode();
- if (TII->isTwoAddrInstr(Opc)) {
+ if (TII->isTwoAddrInstr(Opc))
SU->isTwoAddress = true;
- SDNode *OpN = MainNode->getOperand(0).Val;
- SUnit *OpSU = SUnitMap[OpN];
- if (OpSU)
- OpSU->isDefNUseOperand = true;
- }
+ if (TII->isCommutableInstr(Opc))
+ SU->isCommutable = true;
}
// Find all predecessors and successors of the group.
@@ -391,7 +388,18 @@ void ScheduleDAG::EmitNode(SDNode *Node,
// instruction as appropriate.
for (unsigned i = 0; i != NodeOperands; ++i)
AddOperand(MI, Node->getOperand(i), i+NumResults, &II, VRBaseMap);
-
+
+ // Commute node if it has been determined to be profitable.
+ if (CommuteSet.count(Node)) {
+ MachineInstr *NewMI = TII->commuteInstruction(MI);
+ if (NewMI == 0)
+ DEBUG(std::cerr << "Sched: COMMUTING FAILED!\n");
+ else {
+ DEBUG(std::cerr << "Sched: COMMUTED TO: " << *NewMI);
+ MI = NewMI;
+ }
+ }
+
// Now that we have emitted all operands, emit this instruction itself.
if ((II.Flags & M_USES_CUSTOM_DAG_SCHED_INSERTION) == 0) {
BB->insert(BB->end(), MI);
diff --git a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
index acd6904ce2..9b359aa189 100644
--- a/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
+++ b/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp
@@ -30,7 +30,7 @@
using namespace llvm;
namespace {
- cl::opt<bool> SchedLowerDefNUse("sched-lower-defnuse", cl::Hidden);
+ cl::opt<bool> SchedCommuteNodes("sched-commute-nodes", cl::Hidden);
}
namespace {
@@ -70,6 +70,7 @@ private:
void ScheduleNodeTopDown(SUnit *SU, unsigned& CurCycle);
void ListScheduleTopDown();
void ListScheduleBottomUp();
+ void CommuteNodesToReducePressure();
};
} // end anonymous namespace
@@ -95,6 +96,9 @@ void ScheduleDAGRRList::Schedule() {
ListScheduleTopDown();
AvailableQueue->releaseState();
+
+ if (SchedCommuteNodes)
+ CommuteNodesToReducePressure();
DEBUG(std::cerr << "*** Final schedule ***\n");
DEBUG(dumpSchedule());
@@ -104,6 +108,41 @@ void ScheduleDAGRRList::Schedule() {
EmitSchedule();
}
+/// CommuteNodesToReducePressure - Is a node is two-address and commutable, and
+/// it is not the last use of its first operand, add it to the CommuteSet if
+/// possible. It will be commuted when it is translated to a MI.
+void ScheduleDAGRRList::CommuteNodesToReducePressure() {
+ std::set<SUnit *> OperandSeen;
+ for (unsigned i = Sequence.size()-1; i != 0; --i) { // Ignore first node.
+ SUnit *SU = Sequence[i];
+ if (!SU) continue;
+ if (SU->isTwoAddress && SU->isCommutable) {
+ SDNode *OpN = SU->Node->getOperand(0).Val;
+ SUnit *OpSU = SUnitMap[OpN];
+ if (OpSU && OperandSeen.count(OpSU) == 1) {
+ // Ok, so SU is not the last use of OpSU, but SU is two-address so
+ // it will clobber OpSU. Try to commute it if possible.
+ bool DoCommute = true;
+ for (unsigned j = 1, e = SU->Node->getNumOperands(); j != e; ++j) {
+ OpN = SU->Node->getOperand(j).Val;
+ OpSU = SUnitMap[OpN];
+ if (OpSU && OperandSeen.count(OpSU) == 1) {
+ DoCommute = false;
+ break;
+ }
+ }
+ if (DoCommute)
+ CommuteSet.insert(SU->Node);
+ }
+ }
+
+ for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
+ E = SU->Preds.end(); I != E; ++I) {
+ if (!I->second)
+ OperandSeen.insert(I->first);
+ }
+ }
+}
//===----------------------------------------------------------------------===//
// Bottom-Up Scheduling
@@ -436,8 +475,7 @@ namespace {
void initNodes(const std::vector<SUnit> &sunits) {
SUnits = &sunits;
// Add pseudo dependency edges for two-address nodes.
- if (SchedLowerDefNUse)
- AddPseudoTwoAddrDeps();
+ AddPseudoTwoAddrDeps();
// Calculate node priorities.
CalculatePriorities();
}
@@ -513,23 +551,6 @@ bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
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)
@@ -602,16 +623,17 @@ void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
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) {
+ if (I->second) continue;
SUnit *SuccSU = I->first;
- if (SuccSU != SU && !canClobber(SuccSU, DUSU)) {
- if (SuccSU->Node->getNodeDepth() <= Depth+2 &&
- !isReachable(SuccSU, SU)) {
+ if (SuccSU != SU &&
+ (!canClobber(SuccSU, DUSU) ||
+ (SchedCommuteNodes && !SU->isCommutable && SuccSU->isCommutable))){
+ if (SuccSU->Depth <= SU->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)