@@ -67,6 +67,10 @@ struct LoopPipelinerInternal {
67
67
// / the Value.
68
68
std::pair<Operation *, int64_t > getDefiningOpAndDistance (Value value);
69
69
70
+ // / Return true if the schedule is possible and return false otherwise. A
71
+ // / schedule is correct if all definitions are scheduled before uses.
72
+ bool verifySchedule ();
73
+
70
74
public:
71
75
// / Initalize the information for the given `op`, return true if it
72
76
// / satisfies the pre-condition to apply pipelining.
@@ -156,6 +160,11 @@ bool LoopPipelinerInternal::initializeLoopInfo(
156
160
}
157
161
}
158
162
163
+ if (!verifySchedule ()) {
164
+ LDBG (" --invalid schedule: " << op << " -> BAIL" );
165
+ return false ;
166
+ }
167
+
159
168
// Currently, we do not support assigning stages to ops in nested regions. The
160
169
// block of all operations assigned a stage should be the single `scf.for`
161
170
// body block.
@@ -194,6 +203,40 @@ bool LoopPipelinerInternal::initializeLoopInfo(
194
203
return true ;
195
204
}
196
205
206
+ // / Compute unrolled cycles of each op (consumer) and verify that each op is
207
+ // / scheduled after its operands (producers) while adjusting for the distance
208
+ // / between producer and consumer.
209
+ bool LoopPipelinerInternal::verifySchedule () {
210
+ int64_t numCylesPerIter = opOrder.size ();
211
+ // Pre-compute the unrolled cycle of each op.
212
+ DenseMap<Operation *, int64_t > unrolledCyles;
213
+ for (int64_t cycle = 0 ; cycle < numCylesPerIter; cycle++) {
214
+ Operation *def = opOrder[cycle];
215
+ auto it = stages.find (def);
216
+ assert (it != stages.end ());
217
+ int64_t stage = it->second ;
218
+ unrolledCyles[def] = cycle + stage * numCylesPerIter;
219
+ }
220
+ for (Operation *consumer : opOrder) {
221
+ int64_t consumerCycle = unrolledCyles[consumer];
222
+ for (Value operand : consumer->getOperands ()) {
223
+ auto [producer, distance] = getDefiningOpAndDistance (operand);
224
+ if (!producer)
225
+ continue ;
226
+ auto it = unrolledCyles.find (producer);
227
+ // Skip producer coming from outside the loop.
228
+ if (it == unrolledCyles.end ())
229
+ continue ;
230
+ int64_t producerCycle = it->second ;
231
+ if (consumerCycle < producerCycle - numCylesPerIter * distance) {
232
+ consumer->emitError (" operation scheduled before its operands" );
233
+ return false ;
234
+ }
235
+ }
236
+ }
237
+ return true ;
238
+ }
239
+
197
240
// / Clone `op` and call `callback` on the cloned op's oeprands as well as any
198
241
// / operands of nested ops that:
199
242
// / 1) aren't defined within the new op or
0 commit comments