//
// 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 file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
using namespace llvm;
STATISTIC(NumBacktracks, "Number of times scheduler backtraced");
+STATISTIC(NumUnfolds, "Number of nodes unfolded");
STATISTIC(NumDups, "Number of duplicated nodes");
STATISTIC(NumCCCopies, "Number of cross class copies");
continue;
SDNode *OpN = SU->Node->getOperand(j).Val;
- SUnit *OpSU = SUnitMap[OpN][SU->InstanceNo];
+ SUnit *OpSU = isPassiveNode(OpN) ? NULL : SUnitMap[OpN][SU->InstanceNo];
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 SU if no other source operands
for (unsigned k = 0; k < NumOps; ++k) {
if (k != j) {
OpN = SU->Node->getOperand(k).Val;
- OpSU = SUnitMap[OpN][SU->InstanceNo];
+ OpSU = isPassiveNode(OpN) ? NULL : SUnitMap[OpN][SU->InstanceNo];
if (OpSU && OperandSeen.count(OpSU) == 1) {
DoCommute = false;
break;
// interrupt model (drain vs. freeze).
PredSU->CycleBound = std::max(PredSU->CycleBound, CurCycle + PredSU->Latency);
- if (!isChain)
- --PredSU->NumSuccsLeft;
- else
- --PredSU->NumChainSuccsLeft;
+ --PredSU->NumSuccsLeft;
#ifndef NDEBUG
- if (PredSU->NumSuccsLeft < 0 || PredSU->NumChainSuccsLeft < 0) {
+ if (PredSU->NumSuccsLeft < 0) {
cerr << "*** List scheduling failed! ***\n";
PredSU->dump(&DAG);
cerr << " has been released too many times!\n";
}
#endif
- if ((PredSU->NumSuccsLeft + PredSU->NumChainSuccsLeft) == 0) {
+ if (PredSU->NumSuccsLeft == 0) {
// EntryToken has to go last! Special case it here.
if (!PredSU->Node || PredSU->Node->getOpcode() != ISD::EntryToken) {
PredSU->isAvailable = true;
AvailableQueue->remove(PredSU);
}
- if (!isChain)
- ++PredSU->NumSuccsLeft;
- else
- ++PredSU->NumChainSuccsLeft;
+ ++PredSU->NumSuccsLeft;
}
/// UnscheduleNodeBottomUp - Remove the node from the schedule, update its and
++NumBacktracks;
}
-/// isSafeToCopy - True if the SUnit for the given SDNode can safely cloned,
-/// i.e. the node does not produce a flag, it does not read a flag and it does
-/// not have an incoming chain.
-static bool isSafeToCopy(SDNode *N) {
- if (!N)
- return true;
+/// CopyAndMoveSuccessors - Clone the specified node and move its scheduled
+/// successors to the newly created node.
+SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
+ if (SU->FlaggedNodes.size())
+ return NULL;
- for (unsigned i = 0, e = N->getNumValues(); i != e; ++i)
- if (N->getValueType(i) == MVT::Flag)
- return false;
+ SDNode *N = SU->Node;
+ if (!N)
+ return NULL;
+
+ SUnit *NewSU;
+ bool TryUnfold = false;
+ for (unsigned i = 0, e = N->getNumValues(); i != e; ++i) {
+ MVT::ValueType VT = N->getValueType(i);
+ if (VT == MVT::Flag)
+ return NULL;
+ else if (VT == MVT::Other)
+ TryUnfold = true;
+ }
for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) {
const SDOperand &Op = N->getOperand(i);
MVT::ValueType VT = Op.Val->getValueType(Op.ResNo);
- if (VT == MVT::Other || VT == MVT::Flag)
- return false;
+ if (VT == MVT::Flag)
+ return NULL;
}
- return true;
-}
+ if (TryUnfold) {
+ SmallVector<SDNode*, 4> NewNodes;
+ if (!MRI->unfoldMemoryOperand(DAG, N, NewNodes))
+ return NULL;
+
+ DOUT << "Unfolding SU # " << SU->NodeNum << "\n";
+ assert(NewNodes.size() == 2 && "Expected a load folding node!");
+
+ N = NewNodes[1];
+ SDNode *LoadNode = NewNodes[0];
+ unsigned NumVals = N->getNumValues();
+ unsigned OldNumVals = SU->Node->getNumValues();
+ for (unsigned i = 0; i != NumVals; ++i)
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(SU->Node, i), SDOperand(N, i));
+ DAG.ReplaceAllUsesOfValueWith(SDOperand(SU->Node, OldNumVals-1),
+ SDOperand(LoadNode, 1));
+
+ SUnit *NewSU = NewSUnit(N);
+ SUnitMap[N].push_back(NewSU);
+ const TargetInstrDescriptor *TID = &TII->get(N->getTargetOpcode());
+ for (unsigned i = 0; i != TID->numOperands; ++i) {
+ if (TID->getOperandConstraint(i, TOI::TIED_TO) != -1) {
+ NewSU->isTwoAddress = true;
+ break;
+ }
+ }
+ if (TID->Flags & M_COMMUTABLE)
+ NewSU->isCommutable = true;
+ // FIXME: Calculate height / depth and propagate the changes?
+ NewSU->Depth = SU->Depth;
+ NewSU->Height = SU->Height;
+ ComputeLatency(NewSU);
+
+ // LoadNode may already exist. This can happen when there is another
+ // load from the same location and producing the same type of value
+ // but it has different alignment or volatileness.
+ bool isNewLoad = true;
+ SUnit *LoadSU;
+ DenseMap<SDNode*, std::vector<SUnit*> >::iterator SMI =
+ SUnitMap.find(LoadNode);
+ if (SMI != SUnitMap.end()) {
+ LoadSU = SMI->second.front();
+ isNewLoad = false;
+ } else {
+ LoadSU = NewSUnit(LoadNode);
+ SUnitMap[LoadNode].push_back(LoadSU);
+
+ LoadSU->Depth = SU->Depth;
+ LoadSU->Height = SU->Height;
+ ComputeLatency(LoadSU);
+ }
-/// CopyAndMoveSuccessors - Clone the specified node and move its scheduled
-/// successors to the newly created node.
-SUnit *ScheduleDAGRRList::CopyAndMoveSuccessors(SUnit *SU) {
- DOUT << "Duplicating SU # " << SU->NodeNum << "\n";
+ SUnit *ChainPred = NULL;
+ SmallVector<SDep, 4> ChainSuccs;
+ SmallVector<SDep, 4> LoadPreds;
+ SmallVector<SDep, 4> NodePreds;
+ SmallVector<SDep, 4> NodeSuccs;
+ for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
+ I != E; ++I) {
+ if (I->isCtrl)
+ ChainPred = I->Dep;
+ else if (I->Dep->Node && I->Dep->Node->isOperand(LoadNode))
+ LoadPreds.push_back(SDep(I->Dep, I->Reg, I->Cost, false, false));
+ else
+ NodePreds.push_back(SDep(I->Dep, I->Reg, I->Cost, false, false));
+ }
+ for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
+ I != E; ++I) {
+ if (I->isCtrl)
+ ChainSuccs.push_back(SDep(I->Dep, I->Reg, I->Cost,
+ I->isCtrl, I->isSpecial));
+ else
+ NodeSuccs.push_back(SDep(I->Dep, I->Reg, I->Cost,
+ I->isCtrl, I->isSpecial));
+ }
- SUnit *NewSU = Clone(SU);
+ SU->removePred(ChainPred, true, false);
+ if (isNewLoad)
+ LoadSU->addPred(ChainPred, true, false);
+ for (unsigned i = 0, e = LoadPreds.size(); i != e; ++i) {
+ SDep *Pred = &LoadPreds[i];
+ SU->removePred(Pred->Dep, Pred->isCtrl, Pred->isSpecial);
+ if (isNewLoad)
+ LoadSU->addPred(Pred->Dep, Pred->isCtrl, Pred->isSpecial,
+ Pred->Reg, Pred->Cost);
+ }
+ for (unsigned i = 0, e = NodePreds.size(); i != e; ++i) {
+ SDep *Pred = &NodePreds[i];
+ SU->removePred(Pred->Dep, Pred->isCtrl, Pred->isSpecial);
+ NewSU->addPred(Pred->Dep, Pred->isCtrl, Pred->isSpecial,
+ Pred->Reg, Pred->Cost);
+ }
+ for (unsigned i = 0, e = NodeSuccs.size(); i != e; ++i) {
+ SDep *Succ = &NodeSuccs[i];
+ Succ->Dep->removePred(SU, Succ->isCtrl, Succ->isSpecial);
+ Succ->Dep->addPred(NewSU, Succ->isCtrl, Succ->isSpecial,
+ Succ->Reg, Succ->Cost);
+ }
+ for (unsigned i = 0, e = ChainSuccs.size(); i != e; ++i) {
+ SDep *Succ = &ChainSuccs[i];
+ Succ->Dep->removePred(SU, Succ->isCtrl, Succ->isSpecial);
+ if (isNewLoad)
+ Succ->Dep->addPred(LoadSU, Succ->isCtrl, Succ->isSpecial,
+ Succ->Reg, Succ->Cost);
+ }
+ if (isNewLoad)
+ NewSU->addPred(LoadSU, false, false);
+
+ if (isNewLoad)
+ AvailableQueue->addNode(LoadSU);
+ AvailableQueue->addNode(NewSU);
+
+ ++NumUnfolds;
+
+ if (NewSU->NumSuccsLeft == 0) {
+ NewSU->isAvailable = true;
+ return NewSU;
+ }
+ SU = NewSU;
+ }
+
+ DOUT << "Duplicating SU # " << SU->NodeNum << "\n";
+ NewSU = Clone(SU);
// New SUnit has the exact same predecessors.
for (SUnit::pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
assert(LRegs.size() == 1 && "Can't handle this yet!");
unsigned Reg = LRegs[0];
SUnit *LRDef = LiveRegDefs[Reg];
- SUnit *NewDef;
- if (isSafeToCopy(LRDef->Node))
- NewDef = CopyAndMoveSuccessors(LRDef);
- else {
+ SUnit *NewDef = CopyAndMoveSuccessors(LRDef);
+ if (!NewDef) {
// Issue expensive cross register class copies.
MVT::ValueType VT = getPhysicalRegisterVT(LRDef->Node, Reg, TII);
const TargetRegisterClass *RC =
// 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 (SUnits[i].NumSuccsLeft != 0) {
if (!AnyNotSched)
cerr << "*** List scheduling failed! ***\n";
SUnits[i].dump(&DAG);
// interrupt model (drain vs. freeze).
SuccSU->CycleBound = std::max(SuccSU->CycleBound, CurCycle + SuccSU->Latency);
- if (!isChain)
- --SuccSU->NumPredsLeft;
- else
- --SuccSU->NumChainPredsLeft;
+ --SuccSU->NumPredsLeft;
#ifndef NDEBUG
- if (SuccSU->NumPredsLeft < 0 || SuccSU->NumChainPredsLeft < 0) {
+ if (SuccSU->NumPredsLeft < 0) {
cerr << "*** List scheduling failed! ***\n";
SuccSU->dump(&DAG);
cerr << " has been released too many times!\n";
}
#endif
- if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
+ if (SuccSU->NumPredsLeft == 0) {
SuccSU->isAvailable = true;
AvailableQueue->push(SuccSU);
}
std::vector<unsigned> SethiUllmanNumbers;
const TargetInstrInfo *TII;
+ const MRegisterInfo *MRI;
public:
- explicit BURegReductionPriorityQueue(const TargetInstrInfo *tii)
- : TII(tii) {}
+ explicit BURegReductionPriorityQueue(const TargetInstrInfo *tii,
+ const MRegisterInfo *mri)
+ : TII(tii), MRI(mri) {}
void initNodes(DenseMap<SDNode*, std::vector<SUnit*> > &sumap,
std::vector<SUnit> &sunits) {
// CopyToReg should be close to its uses to facilitate coalescing and
// avoid spilling.
return 0;
+ else if (Opc == TargetInstrInfo::EXTRACT_SUBREG ||
+ Opc == TargetInstrInfo::INSERT_SUBREG)
+ // EXTRACT_SUBREG / INSERT_SUBREG should be close to its use to
+ // facilitate coalescing.
+ return 0;
else if (SU->NumSuccs == 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.
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I) {
if (I->isCtrl) continue; // ignore chain preds
- if (!I->Dep->Node || I->Dep->Node->getOpcode() != ISD::CopyFromReg)
+ if (I->Dep->Node->getOpcode() != ISD::CopyFromReg)
Scratches++;
}
for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
I != E; ++I) {
if (I->isCtrl) continue; // ignore chain succs
- if (!I->Dep->Node || I->Dep->Node->getOpcode() != ISD::CopyToReg)
+ if (I->Dep->Node->getOpcode() != ISD::CopyToReg)
Scratches += 10;
}
return Scratches;
for (unsigned i = 0; i != NumOps; ++i) {
if (TII->getOperandConstraint(Opc, i+NumRes, TOI::TIED_TO) != -1) {
SDNode *DU = SU->Node->getOperand(i).Val;
- if (Op == (*SUnitMap)[DU][SU->InstanceNo])
+ if ((*SUnitMap).find(DU) != (*SUnitMap).end() &&
+ Op == (*SUnitMap)[DU][SU->InstanceNo])
return true;
}
}
}
+/// hasCopyToRegUse - Return true if SU has a value successor that is a
+/// CopyToReg node.
+static bool hasCopyToRegUse(SUnit *SU) {
+ for (SUnit::const_succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
+ I != E; ++I) {
+ if (I->isCtrl) continue;
+ SUnit *SuccSU = I->Dep;
+ if (SuccSU->Node && SuccSU->Node->getOpcode() == ISD::CopyToReg)
+ return true;
+ }
+ return false;
+}
+
+/// canClobberPhysRegDefs - True if SU would clobber one of SuccSU's
+/// physical register def.
+static bool canClobberPhysRegDefs(SUnit *SuccSU, SUnit *SU,
+ const TargetInstrInfo *TII,
+ const MRegisterInfo *MRI) {
+ SDNode *N = SuccSU->Node;
+ unsigned NumDefs = TII->getNumDefs(N->getTargetOpcode());
+ const unsigned *ImpDefs = TII->getImplicitDefs(N->getTargetOpcode());
+ if (!ImpDefs)
+ return false;
+ const unsigned *SUImpDefs = TII->getImplicitDefs(SU->Node->getTargetOpcode());
+ if (!SUImpDefs)
+ return false;
+ for (unsigned i = NumDefs, e = N->getNumValues(); i != e; ++i) {
+ MVT::ValueType VT = N->getValueType(i);
+ if (VT == MVT::Flag || VT == MVT::Other)
+ continue;
+ unsigned Reg = ImpDefs[i - NumDefs];
+ for (;*SUImpDefs; ++SUImpDefs) {
+ unsigned SUReg = *SUImpDefs;
+ if (MRI->regsOverlap(Reg, SUReg))
+ return true;
+ }
+ }
+ 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).
+/// first (lower in the schedule). If both nodes are two-address, favor the
+/// one that has a CopyToReg use (more likely to be a loop induction update).
+/// If both are two-address, but one is commutable while the other is not
+/// commutable, favor the one that's not commutable.
template<class SF>
void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
for (unsigned i = 0, e = SUnits->size(); i != e; ++i) {
continue;
SDNode *Node = SU->Node;
- if (!Node || !Node->isTargetOpcode())
+ if (!Node || !Node->isTargetOpcode() || SU->FlaggedNodes.size() > 0)
continue;
unsigned Opc = Node->getTargetOpcode();
for (unsigned j = 0; j != NumOps; ++j) {
if (TII->getOperandConstraint(Opc, j+NumRes, TOI::TIED_TO) != -1) {
SDNode *DU = SU->Node->getOperand(j).Val;
+ if ((*SUnitMap).find(DU) == (*SUnitMap).end())
+ continue;
SUnit *DUSU = (*SUnitMap)[DU][SU->InstanceNo];
if (!DUSU) continue;
for (SUnit::succ_iterator I = DUSU->Succs.begin(),E = DUSU->Succs.end();
I != E; ++I) {
if (I->isCtrl) continue;
SUnit *SuccSU = I->Dep;
- // Don't constraint nodes with implicit defs. It can create cycles
- // plus it may increase register pressures.
- if (SuccSU == SU || SuccSU->hasImplicitDefs)
+ if (SuccSU == SU)
continue;
- // Be conservative. Ignore if nodes aren't at the same depth.
- if (SuccSU->Depth != SU->Depth)
+ // Be conservative. Ignore if nodes aren't at roughly the same
+ // depth and height.
+ if (SuccSU->Height < SU->Height && (SU->Height - SuccSU->Height) > 1)
+ continue;
+ if (!SuccSU->Node || !SuccSU->Node->isTargetOpcode())
+ continue;
+ // Don't constrain nodes with physical register defs if the
+ // predecessor can cloober them.
+ if (SuccSU->hasPhysRegDefs) {
+ if (canClobberPhysRegDefs(SuccSU, SU, TII, MRI))
+ continue;
+ }
+ // Don't constraint extract_subreg / insert_subreg these may be
+ // coalesced away. We don't them close to their uses.
+ unsigned SuccOpc = SuccSU->Node->getTargetOpcode();
+ if (SuccOpc == TargetInstrInfo::EXTRACT_SUBREG ||
+ SuccOpc == TargetInstrInfo::INSERT_SUBREG)
continue;
if ((!canClobber(SuccSU, DUSU) ||
+ (hasCopyToRegUse(SU) && !hasCopyToRegUse(SuccSU)) ||
(!SU->isCommutable && SuccSU->isCommutable)) &&
!isReachable(SuccSU, SU)) {
DOUT << "Adding an edge from SU # " << SU->NodeNum
SelectionDAG *DAG,
MachineBasicBlock *BB) {
const TargetInstrInfo *TII = DAG->getTarget().getInstrInfo();
+ const MRegisterInfo *MRI = DAG->getTarget().getRegisterInfo();
return new ScheduleDAGRRList(*DAG, BB, DAG->getTarget(), true,
- new BURegReductionPriorityQueue<bu_ls_rr_sort>(TII));
+ new BURegReductionPriorityQueue<bu_ls_rr_sort>(TII, MRI));
}
llvm::ScheduleDAG* llvm::createTDRRListDAGScheduler(SelectionDAGISel *IS,