Skip to content

Commit 945ed2e

Browse files
authored
[MLIR][SCF] fix loop pipelining pass use of uninitialized value (#146991)
fix issue #146990
1 parent 30298f9 commit 945ed2e

File tree

2 files changed

+51
-14
lines changed

2 files changed

+51
-14
lines changed

mlir/lib/Dialect/SCF/Transforms/LoopPipelining.cpp

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,20 @@ bool LoopPipelinerInternal::initializeLoopInfo(
106106
lb = forOp.getLowerBound();
107107
step = forOp.getStep();
108108

109+
std::vector<std::pair<Operation *, unsigned>> schedule;
110+
options.getScheduleFn(forOp, schedule);
111+
if (schedule.empty()) {
112+
LDBG("--empty schedule -> BAIL");
113+
return false;
114+
}
115+
116+
opOrder.reserve(schedule.size());
117+
for (auto &opSchedule : schedule) {
118+
maxStage = std::max(maxStage, opSchedule.second);
119+
stages[opSchedule.first] = opSchedule.second;
120+
opOrder.push_back(opSchedule.first);
121+
}
122+
109123
dynamicLoop = true;
110124
auto upperBoundCst = getConstantIntValue(ub);
111125
auto lowerBoundCst = getConstantIntValue(lb);
@@ -124,7 +138,7 @@ bool LoopPipelinerInternal::initializeLoopInfo(
124138
return false;
125139
}
126140
int64_t numIteration = llvm::divideCeilSigned(ubImm - lbImm, stepImm);
127-
if (numIteration > maxStage) {
141+
if (numIteration >= maxStage) {
128142
dynamicLoop = false;
129143
} else if (!options.supportDynamicLoops) {
130144
LDBG("--fewer loop iterations than pipeline stages -> BAIL");
@@ -137,19 +151,6 @@ bool LoopPipelinerInternal::initializeLoopInfo(
137151
LDBG("--no epilogue or predicate set -> BAIL");
138152
return false;
139153
}
140-
std::vector<std::pair<Operation *, unsigned>> schedule;
141-
options.getScheduleFn(forOp, schedule);
142-
if (schedule.empty()) {
143-
LDBG("--empty schedule -> BAIL");
144-
return false;
145-
}
146-
147-
opOrder.reserve(schedule.size());
148-
for (auto &opSchedule : schedule) {
149-
maxStage = std::max(maxStage, opSchedule.second);
150-
stages[opSchedule.first] = opSchedule.second;
151-
opOrder.push_back(opSchedule.first);
152-
}
153154

154155
// All operations need to have a stage.
155156
for (Operation &op : forOp.getBody()->without_terminator()) {

mlir/test/Dialect/SCF/loop-pipelining.mlir

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,42 @@ func.func @simple_pipeline(%A: memref<?xf32>, %result: memref<?xf32>) {
3434
return
3535
}
3636

37+
// -----
38+
39+
// A static loop does not satisfy `numIteration >= maxStage`
40+
41+
// CHECK-LABEL: func.func @iteration_lt_stage(
42+
// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : index
43+
// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
44+
// CHECK-DAG: %[[C_NEG1:.*]] = arith.constant -1 : index
45+
// CHECK-DAG: %[[TRUE:.*]] = arith.constant true
46+
// CHECK-DAG: %[[FALSE:.*]] = arith.constant false
47+
// Prologue:
48+
// CHECK: scf.if %[[TRUE]]
49+
// CHECK: scf.if %[[TRUE]]
50+
// CHECK: scf.if %[[FALSE]]
51+
// Kernel:
52+
// CHECK: scf.for %[[IV:.*]] = %[[C0:.*]] to %[[C_NEG1:.*]] step %[[C1:.*]]
53+
// Epilogue:
54+
// CHECK: scf.if %[[TRUE]]
55+
// CHECK: scf.if %[[TRUE]]
56+
// CHECK: scf.if %[[TRUE]]
57+
// CHECK: scf.if %[[TRUE]]
58+
// CHECK: scf.if %[[FALSE]]
59+
// CHECK: scf.if %[[FALSE]]
60+
func.func @iteration_lt_stage(%A: memref<?xf32>, %result: memref<?xf32>) {
61+
%c0 = arith.constant 0 : index
62+
%c1 = arith.constant 1 : index
63+
%c2 = arith.constant 2 : index
64+
%cf = arith.constant 1.0 : f32
65+
scf.for %i0 = %c0 to %c2 step %c1 {
66+
%A_elem = memref.load %A[%i0] { __test_pipelining_stage__ = 0, __test_pipelining_op_order__ = 2 } : memref<?xf32>
67+
%A1_elem = arith.addf %A_elem, %cf { __test_pipelining_stage__ = 3, __test_pipelining_op_order__ = 0 } : f32
68+
memref.store %A1_elem, %result[%i0] { __test_pipelining_stage__ = 3, __test_pipelining_op_order__ = 1 } : memref<?xf32>
69+
} { __test_pipelining_loop__ }
70+
return
71+
}
72+
3773

3874
// -----
3975

0 commit comments

Comments
 (0)