Skip to content

Commit 2424835

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 2424835

File tree

2 files changed

+421
-262
lines changed

2 files changed

+421
-262
lines changed

llvm/include/llvm/CodeGen/MachinePipeliner.h

Lines changed: 132 additions & 30 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 SwingSchedulerDDGEdge;
65+
class SwingSchedulerDDG;
6266

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

121+
/// Represents a dependnece between two instruction.
122+
class SwingSchedulerDDGEdge {
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+
SwingSchedulerDDGEdge(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 SwingSchedulerDDG {
202+
using EdgesType = SmallVector<SwingSchedulerDDGEdge, 4>;
203+
204+
struct SwingSchedulerDDGEdges {
205+
EdgesType Preds;
206+
EdgesType Succs;
207+
};
208+
209+
void initEdges(SUnit *SU);
210+
211+
SUnit *EntrySU;
212+
SUnit *ExitSU;
213+
214+
std::vector<SwingSchedulerDDGEdges> EdgesVec;
215+
SwingSchedulerDDGEdges EntrySUEdges;
216+
SwingSchedulerDDGEdges ExitSUEdges;
217+
218+
void addEdge(SUnit *SU, const SwingSchedulerDDGEdge &Edge);
219+
220+
SwingSchedulerDDGEdges &getEdges(const SUnit *SU);
221+
const SwingSchedulerDDGEdges &getEdges(const SUnit *SU) const;
222+
223+
public:
224+
SwingSchedulerDDG(std::vector<SUnit> &SUnits, SUnit *EntrySU, SUnit *ExitSU);
225+
226+
const EdgesType &getInEdges(const SUnit *SU) const;
227+
228+
const EdgesType &getOutEdges(const SUnit *SU) const;
229+
};
230+
117231
/// This class builds the dependence graph for the instructions in a loop,
118232
/// and attempts to schedule the instructions using the SMS algorithm.
119233
class SwingSchedulerDAG : public ScheduleDAGInstrs {
120234
MachinePipeliner &Pass;
235+
236+
std::unique_ptr<SwingSchedulerDDG> DDG;
237+
121238
/// The minimum initiation interval between iterations for this schedule.
122239
unsigned MII = 0;
123240
/// The maximum initiation interval between iterations for this schedule.
@@ -130,7 +247,7 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
130247
unsigned II_setByPragma = 0;
131248
TargetInstrInfo::PipelinerLoopInfo *LoopPipelinerInfo = nullptr;
132249

133-
/// A toplogical ordering of the SUnits, which is needed for changing
250+
/// A topological ordering of the SUnits, which is needed for changing
134251
/// dependences and iterating over the SUnits.
135252
ScheduleDAGTopologicalSort Topo;
136253

@@ -252,27 +369,7 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
252369
return ScheduleInfo[Node->NodeNum].ZeroLatencyHeight;
253370
}
254371

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-
}
372+
bool isLoopCarriedDep(const SwingSchedulerDDGEdge &Edge) const;
276373

277374
void applyInstrChange(MachineInstr *MI, SMSchedule &Schedule);
278375

@@ -294,6 +391,8 @@ class SwingSchedulerDAG : public ScheduleDAGInstrs {
294391

295392
static bool classof(const ScheduleDAGInstrs *DAG) { return true; }
296393

394+
const SwingSchedulerDDG *getDDG() const { return DDG.get(); }
395+
297396
private:
298397
void addLoopCarriedDependences(AAResults *AA);
299398
void updatePhiDependences();
@@ -357,15 +456,16 @@ class NodeSet {
357456
//
358457
// Hold a map from each SUnit in the circle to the maximum distance from the
359458
// source node by only considering the nodes.
459+
const SwingSchedulerDDG *DDG = DAG->getDDG();
360460
DenseMap<SUnit *, unsigned> SUnitToDistance;
361461
for (auto *Node : Nodes)
362462
SUnitToDistance[Node] = 0;
363463

364464
for (unsigned I = 1, E = Nodes.size(); I <= E; ++I) {
365465
SUnit *U = Nodes[I - 1];
366466
SUnit *V = Nodes[I % Nodes.size()];
367-
for (const SDep &Succ : U->Succs) {
368-
SUnit *SuccSUnit = Succ.getSUnit();
467+
for (const SwingSchedulerDDGEdge &Succ : DDG->getOutEdges(U)) {
468+
SUnit *SuccSUnit = Succ.getDst();
369469
if (V != SuccSUnit)
370470
continue;
371471
if (SUnitToDistance[U] + Succ.getLatency() > SUnitToDistance[V]) {
@@ -377,13 +477,13 @@ class NodeSet {
377477
SUnit *FirstNode = Nodes[0];
378478
SUnit *LastNode = Nodes[Nodes.size() - 1];
379479

380-
for (auto &PI : LastNode->Preds) {
480+
for (auto &PI : DDG->getInEdges(LastNode)) {
381481
// If we have an order dep that is potentially loop carried then a
382482
// back-edge exists between the last node and the first node that isn't
383483
// modeled in the DAG. Handle it manually by adding 1 to the distance of
384484
// the last node.
385-
if (PI.getSUnit() != FirstNode || PI.getKind() != SDep::Order ||
386-
!DAG->isLoopCarriedDep(LastNode, PI, false))
485+
if (PI.getSrc() != FirstNode || !PI.isOrderDep() ||
486+
!DAG->isLoopCarriedDep(PI))
387487
continue;
388488
SUnitToDistance[FirstNode] =
389489
std::max(SUnitToDistance[FirstNode], SUnitToDistance[LastNode] + 1);
@@ -627,11 +727,13 @@ class SMSchedule {
627727

628728
/// Return the cycle of the earliest scheduled instruction in the dependence
629729
/// chain.
630-
int earliestCycleInChain(const SDep &Dep);
730+
int earliestCycleInChain(const SwingSchedulerDDGEdge &Dep,
731+
const SwingSchedulerDDG *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 SwingSchedulerDDGEdge &Dep,
736+
const SwingSchedulerDDG *DDG);
635737

636738
void computeStart(SUnit *SU, int *MaxEarlyStart, int *MinLateStart, int II,
637739
SwingSchedulerDAG *DAG);
@@ -694,7 +796,7 @@ class SMSchedule {
694796
MachineOperand &MO) const;
695797

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

0 commit comments

Comments
 (0)