Skip to content

Commit 0d6a584

Browse files
authored
[MachinePipeliner] Add an abstract layer to manipulate Data Dependenc… (llvm#109918)
…e Graph In MachinePipeliner, a DAG class is used to represent the Data Dependence Graph. Data Dependence Graph generally contains cycles, so it's not appropriate to use DAG classes. In fact, some "hacks" are used to express back-edges in the current implementation. This patch adds a new class to provide a better interface for manipulating dependencies. Our approach is as follows: - To build the graph, we use the ScheduleDAGInstrs class as it is, because it has powerful functions and the current implementation depends heavily on it. - After the graph construction is finished (i.e., during scheduling), we use the new class DataDependenceGraph to manipulate the dependencies. Since we don't change the dependencies during scheduling, the new class only provides functions to read them. Also, this patch is just a refactoring, i.e., scheduling results should not change with or without this patch.
1 parent 030829a commit 0d6a584

File tree

2 files changed

+429
-262
lines changed

2 files changed

+429
-262
lines changed

llvm/include/llvm/CodeGen/MachinePipeliner.h

Lines changed: 129 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#ifndef LLVM_CODEGEN_MACHINEPIPELINER_H
4141
#define LLVM_CODEGEN_MACHINEPIPELINER_H
4242

43+
#include "llvm/ADT/STLExtras.h"
4344
#include "llvm/ADT/SetVector.h"
4445
#include "llvm/CodeGen/DFAPacketizer.h"
4546
#include "llvm/CodeGen/MachineDominators.h"
@@ -114,10 +115,123 @@ class MachinePipeliner : public MachineFunctionPass {
114115
bool useWindowScheduler(bool Changed);
115116
};
116117

118+
/// Represents a dependence between two instruction.
119+
class SwingSchedulerDDGEdge {
120+
SUnit *Dst = nullptr;
121+
SDep Pred;
122+
unsigned Distance = 0;
123+
124+
public:
125+
/// Creates an edge corresponding to an edge represented by \p PredOrSucc and
126+
/// \p Dep in the original DAG. This pair has no information about the
127+
/// direction of the edge, so we need to pass an additional argument \p
128+
/// IsSucc.
129+
SwingSchedulerDDGEdge(SUnit *PredOrSucc, const SDep &Dep, bool IsSucc)
130+
: Dst(PredOrSucc), Pred(Dep), Distance(0u) {
131+
SUnit *Src = Dep.getSUnit();
132+
133+
if (IsSucc) {
134+
std::swap(Src, Dst);
135+
Pred.setSUnit(Src);
136+
}
137+
138+
// An anti-dependence to PHI means loop-carried dependence.
139+
if (Pred.getKind() == SDep::Anti && Src->getInstr()->isPHI()) {
140+
Distance = 1;
141+
std::swap(Src, Dst);
142+
auto Reg = Pred.getReg();
143+
Pred = SDep(Src, SDep::Kind::Data, Reg);
144+
}
145+
}
146+
147+
/// Returns the SUnit from which the edge comes (source node).
148+
SUnit *getSrc() const { return Pred.getSUnit(); }
149+
150+
/// Returns the SUnit to which the edge points (destination node).
151+
SUnit *getDst() const { return Dst; }
152+
153+
/// Returns the latency value for the edge.
154+
unsigned getLatency() const { return Pred.getLatency(); }
155+
156+
/// Sets the latency for the edge.
157+
void setLatency(unsigned Latency) { Pred.setLatency(Latency); }
158+
159+
/// Returns the distance value for the edge.
160+
unsigned getDistance() const { return Distance; }
161+
162+
/// Sets the distance value for the edge.
163+
void setDistance(unsigned D) { Distance = D; }
164+
165+
/// Returns the register associated with the edge.
166+
Register getReg() const { return Pred.getReg(); }
167+
168+
/// Returns true if the edge represents anti dependence.
169+
bool isAntiDep() const { return Pred.getKind() == SDep::Kind::Anti; }
170+
171+
/// Returns true if the edge represents output dependence.
172+
bool isOutputDep() const { return Pred.getKind() == SDep::Kind::Output; }
173+
174+
/// Returns true if the edge represents a dependence that is not data, anti or
175+
/// output dependence.
176+
bool isOrderDep() const { return Pred.getKind() == SDep::Kind::Order; }
177+
178+
/// Returns true if the edge represents unknown scheduling barrier.
179+
bool isBarrier() const { return Pred.isBarrier(); }
180+
181+
/// Returns true if the edge represents an artificial dependence.
182+
bool isArtificial() const { return Pred.isArtificial(); }
183+
184+
/// Tests if this is a Data dependence that is associated with a register.
185+
bool isAssignedRegDep() const { return Pred.isAssignedRegDep(); }
186+
187+
/// Returns true for DDG nodes that we ignore when computing the cost
188+
/// functions. We ignore the back-edge recurrence in order to avoid unbounded
189+
/// recursion in the calculation of the ASAP, ALAP, etc functions.
190+
bool ignoreDependence(bool IgnoreAnti) const;
191+
};
192+
193+
/// Represents dependencies between instructions. This class is a wrapper of
194+
/// `SUnits` and its dependencies to manipulate back-edges in a natural way.
195+
/// Currently it only supports back-edges via PHI, which are expressed as
196+
/// anti-dependencies in the original DAG.
197+
/// FIXME: Support any other loop-carried dependencies
198+
class SwingSchedulerDDG {
199+
using EdgesType = SmallVector<SwingSchedulerDDGEdge, 4>;
200+
201+
struct SwingSchedulerDDGEdges {
202+
EdgesType Preds;
203+
EdgesType Succs;
204+
};
205+
206+
void initEdges(SUnit *SU);
207+
208+
SUnit *EntrySU;
209+
SUnit *ExitSU;
210+
211+
std::vector<SwingSchedulerDDGEdges> EdgesVec;
212+
SwingSchedulerDDGEdges EntrySUEdges;
213+
SwingSchedulerDDGEdges ExitSUEdges;
214+
215+
void addEdge(const SUnit *SU, const SwingSchedulerDDGEdge &Edge);
216+
217+
SwingSchedulerDDGEdges &getEdges(const SUnit *SU);
218+
const SwingSchedulerDDGEdges &getEdges(const SUnit *SU) const;
219+
220+
public:
221+
SwingSchedulerDDG(std::vector<SUnit> &SUnits, SUnit *EntrySU, SUnit *ExitSU);
222+
223+
const EdgesType &getInEdges(const SUnit *SU) const;
224+
225+
const EdgesType &getOutEdges(const SUnit *SU) const;
226+
};
227+
117228
/// This class builds the dependence graph for the instructions in a loop,
118229
/// and attempts to schedule the instructions using the SMS algorithm.
119230
class SwingSchedulerDAG : public ScheduleDAGInstrs {
120231
MachinePipeliner &Pass;
232+
233+
std::unique_ptr<SwingSchedulerDDG> DDG;
234+
121235
/// The minimum initiation interval between iterations for this schedule.
122236
unsigned MII = 0;
123237
/// The maximum initiation interval between iterations for this schedule.
@@ -130,7 +244,7 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
130244
unsigned II_setByPragma = 0;
131245
TargetInstrInfo::PipelinerLoopInfo *LoopPipelinerInfo = nullptr;
132246

133-
/// A toplogical ordering of the SUnits, which is needed for changing
247+
/// A topological ordering of the SUnits, which is needed for changing
134248
/// dependences and iterating over the SUnits.
135249
ScheduleDAGTopologicalSort Topo;
136250

@@ -252,27 +366,7 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
252366
return ScheduleInfo[Node->NodeNum].ZeroLatencyHeight;
253367
}
254368

255-
/// Return true if the dependence is a back-edge in the data dependence graph.
256-
/// Since the DAG doesn't contain cycles, we represent a cycle in the graph
257-
/// using an anti dependence from a Phi to an instruction.
258-
bool isBackedge(SUnit *Source, const SDep &Dep) {
259-
if (Dep.getKind() != SDep::Anti)
260-
return false;
261-
return Source->getInstr()->isPHI() || Dep.getSUnit()->getInstr()->isPHI();
262-
}
263-
264-
bool isLoopCarriedDep(SUnit *Source, const SDep &Dep,
265-
bool isSucc = true) const;
266-
267-
/// The distance function, which indicates that operation V of iteration I
268-
/// depends on operations U of iteration I-distance.
269-
unsigned getDistance(SUnit *U, SUnit *V, const SDep &Dep) {
270-
// Instructions that feed a Phi have a distance of 1. Computing larger
271-
// values for arrays requires data dependence information.
272-
if (V->getInstr()->isPHI() && Dep.getKind() == SDep::Anti)
273-
return 1;
274-
return 0;
275-
}
369+
bool isLoopCarriedDep(const SwingSchedulerDDGEdge &Edge) const;
276370

277371
void applyInstrChange(MachineInstr *MI, SMSchedule &Schedule);
278372

@@ -294,6 +388,8 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
294388

295389
static bool classof(const ScheduleDAGInstrs *DAG) { return true; }
296390

391+
const SwingSchedulerDDG *getDDG() const { return DDG.get(); }
392+
297393
private:
298394
void addLoopCarriedDependences(AAResults *AA);
299395
void updatePhiDependences();
@@ -357,15 +453,16 @@ class NodeSet {
357453
//
358454
// Hold a map from each SUnit in the circle to the maximum distance from the
359455
// source node by only considering the nodes.
456+
const SwingSchedulerDDG *DDG = DAG->getDDG();
360457
DenseMap<SUnit *, unsigned> SUnitToDistance;
361458
for (auto *Node : Nodes)
362459
SUnitToDistance[Node] = 0;
363460

364461
for (unsigned I = 1, E = Nodes.size(); I <= E; ++I) {
365462
SUnit *U = Nodes[I - 1];
366463
SUnit *V = Nodes[I % Nodes.size()];
367-
for (const SDep &Succ : U->Succs) {
368-
SUnit *SuccSUnit = Succ.getSUnit();
464+
for (const SwingSchedulerDDGEdge &Succ : DDG->getOutEdges(U)) {
465+
SUnit *SuccSUnit = Succ.getDst();
369466
if (V != SuccSUnit)
370467
continue;
371468
if (SUnitToDistance[U] + Succ.getLatency() > SUnitToDistance[V]) {
@@ -377,13 +474,13 @@ class NodeSet {
377474
SUnit *FirstNode = Nodes[0];
378475
SUnit *LastNode = Nodes[Nodes.size() - 1];
379476

380-
for (auto &PI : LastNode->Preds) {
477+
for (auto &PI : DDG->getInEdges(LastNode)) {
381478
// If we have an order dep that is potentially loop carried then a
382479
// back-edge exists between the last node and the first node that isn't
383480
// modeled in the DAG. Handle it manually by adding 1 to the distance of
384481
// the last node.
385-
if (PI.getSUnit() != FirstNode || PI.getKind() != SDep::Order ||
386-
!DAG->isLoopCarriedDep(LastNode, PI, false))
482+
if (PI.getSrc() != FirstNode || !PI.isOrderDep() ||
483+
!DAG->isLoopCarriedDep(PI))
387484
continue;
388485
SUnitToDistance[FirstNode] =
389486
std::max(SUnitToDistance[FirstNode], SUnitToDistance[LastNode] + 1);
@@ -627,11 +724,13 @@ class SMSchedule {
627724

628725
/// Return the cycle of the earliest scheduled instruction in the dependence
629726
/// chain.
630-
int earliestCycleInChain(const SDep &Dep);
727+
int earliestCycleInChain(const SwingSchedulerDDGEdge &Dep,
728+
const SwingSchedulerDDG *DDG);
631729

632730
/// Return the cycle of the latest scheduled instruction in the dependence
633731
/// chain.
634-
int latestCycleInChain(const SDep &Dep);
732+
int latestCycleInChain(const SwingSchedulerDDGEdge &Dep,
733+
const SwingSchedulerDDG *DDG);
635734

636735
void computeStart(SUnit *SU, int *MaxEarlyStart, int *MinLateStart, int II,
637736
SwingSchedulerDAG *DAG);
@@ -694,7 +793,7 @@ class SMSchedule {
694793
MachineOperand &MO) const;
695794

696795
bool onlyHasLoopCarriedOutputOrOrderPreds(SUnit *SU,
697-
SwingSchedulerDAG *DAG) const;
796+
const SwingSchedulerDDG *DDG) const;
698797
void print(raw_ostream &os) const;
699798
void dump() const;
700799
};

0 commit comments

Comments
 (0)