Skip to content

Commit e02f4ab

Browse files
committed
[MachinePipeliner] Add an abstract layer to manipulate Data Dependence 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 only a refactoring, i.e., scheduling results should not change with or without this patch.
1 parent df6822f commit e02f4ab

File tree

2 files changed

+420
-263
lines changed

2 files changed

+420
-263
lines changed

llvm/include/llvm/CodeGen/MachinePipeliner.h

Lines changed: 133 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@
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"
45+
#include "llvm/Analysis/AliasAnalysis.h"
4446
#include "llvm/CodeGen/DFAPacketizer.h"
4547
#include "llvm/CodeGen/MachineDominators.h"
4648
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
@@ -59,6 +61,8 @@ namespace llvm {
5961
class AAResults;
6062
class NodeSet;
6163
class SMSchedule;
64+
class DDGEdge;
65+
class DataDependenceGraph;
6266

6367
extern cl::opt<bool> SwpEnableCopyToPhi;
6468
extern cl::opt<int> SwpForceIssueWidth;
@@ -114,10 +118,124 @@ class MachinePipeliner : public MachineFunctionPass {
114118
bool useWindowScheduler(bool Changed);
115119
};
116120

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

133-
/// A toplogical ordering of the SUnits, which is needed for changing
251+
/// A topological ordering of the SUnits, which is needed for changing
134252
/// dependences and iterating over the SUnits.
135253
ScheduleDAGTopologicalSort Topo;
136254

@@ -252,27 +370,7 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
252370
return ScheduleInfo[Node->NodeNum].ZeroLatencyHeight;
253371
}
254372

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-
}
373+
bool isLoopCarriedDep(const DDGEdge &Edge) const;
276374

277375
void applyInstrChange(MachineInstr *MI, SMSchedule &Schedule);
278376

@@ -294,6 +392,8 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
294392

295393
static bool classof(const ScheduleDAGInstrs *DAG) { return true; }
296394

395+
const DataDependenceGraph *getDDG() const { return DDG.get(); }
396+
297397
private:
298398
void addLoopCarriedDependences(AAResults *AA);
299399
void updatePhiDependences();
@@ -357,15 +457,16 @@ class NodeSet {
357457
//
358458
// Hold a map from each SUnit in the circle to the maximum distance from the
359459
// source node by only considering the nodes.
460+
const DataDependenceGraph *DDG = DAG->getDDG();
360461
DenseMap<SUnit *, unsigned> SUnitToDistance;
361462
for (auto *Node : Nodes)
362463
SUnitToDistance[Node] = 0;
363464

364465
for (unsigned I = 1, E = Nodes.size(); I <= E; ++I) {
365466
SUnit *U = Nodes[I - 1];
366467
SUnit *V = Nodes[I % Nodes.size()];
367-
for (const SDep &Succ : U->Succs) {
368-
SUnit *SuccSUnit = Succ.getSUnit();
468+
for (const DDGEdge &Succ : DDG->getOutEdges(U)) {
469+
SUnit *SuccSUnit = Succ.getDst();
369470
if (V != SuccSUnit)
370471
continue;
371472
if (SUnitToDistance[U] + Succ.getLatency() > SUnitToDistance[V]) {
@@ -377,13 +478,13 @@ class NodeSet {
377478
SUnit *FirstNode = Nodes[0];
378479
SUnit *LastNode = Nodes[Nodes.size() - 1];
379480

380-
for (auto &PI : LastNode->Preds) {
481+
for (auto &PI : DDG->getInEdges(LastNode)) {
381482
// If we have an order dep that is potentially loop carried then a
382483
// back-edge exists between the last node and the first node that isn't
383484
// modeled in the DAG. Handle it manually by adding 1 to the distance of
384485
// the last node.
385-
if (PI.getSUnit() != FirstNode || PI.getKind() != SDep::Order ||
386-
!DAG->isLoopCarriedDep(LastNode, PI, false))
486+
if (PI.getSrc() != FirstNode || !PI.isOrderDep() ||
487+
!DAG->isLoopCarriedDep(PI))
387488
continue;
388489
SUnitToDistance[FirstNode] =
389490
std::max(SUnitToDistance[FirstNode], SUnitToDistance[LastNode] + 1);
@@ -627,11 +728,11 @@ class SMSchedule {
627728

628729
/// Return the cycle of the earliest scheduled instruction in the dependence
629730
/// chain.
630-
int earliestCycleInChain(const SDep &Dep);
731+
int earliestCycleInChain(const DDGEdge &Dep, const DataDependenceGraph *DDG);
631732

632733
/// Return the cycle of the latest scheduled instruction in the dependence
633734
/// chain.
634-
int latestCycleInChain(const SDep &Dep);
735+
int latestCycleInChain(const DDGEdge &Dep, const DataDependenceGraph *DDG);
635736

636737
void computeStart(SUnit *SU, int *MaxEarlyStart, int *MinLateStart, int II,
637738
SwingSchedulerDAG *DAG);
@@ -693,8 +794,9 @@ class SMSchedule {
693794
bool isLoopCarriedDefOfUse(const SwingSchedulerDAG *SSD, MachineInstr *Def,
694795
MachineOperand &MO) const;
695796

696-
bool onlyHasLoopCarriedOutputOrOrderPreds(SUnit *SU,
697-
SwingSchedulerDAG *DAG) const;
797+
bool
798+
onlyHasLoopCarriedOutputOrOrderPreds(SUnit *SU,
799+
const DataDependenceGraph *DDG) const;
698800
void print(raw_ostream &os) const;
699801
void dump() const;
700802
};

0 commit comments

Comments
 (0)