• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// RUN: mlir-opt %s -pass-pipeline='func(canonicalize)' | FileCheck %s
2
3func @single_iteration(%A: memref<?x?x?xi32>) {
4  %c0 = constant 0 : index
5  %c1 = constant 1 : index
6  %c2 = constant 2 : index
7  %c3 = constant 3 : index
8  %c6 = constant 6 : index
9  %c7 = constant 7 : index
10  %c10 = constant 10 : index
11  scf.parallel (%i0, %i1, %i2) = (%c0, %c3, %c7) to (%c1, %c6, %c10) step (%c1, %c2, %c3) {
12    %c42 = constant 42 : i32
13    store %c42, %A[%i0, %i1, %i2] : memref<?x?x?xi32>
14    scf.yield
15  }
16  return
17}
18
19// CHECK-LABEL:   func @single_iteration(
20// CHECK-SAME:                        [[ARG0:%.*]]: memref<?x?x?xi32>) {
21// CHECK:           [[C0:%.*]] = constant 0 : index
22// CHECK:           [[C2:%.*]] = constant 2 : index
23// CHECK:           [[C3:%.*]] = constant 3 : index
24// CHECK:           [[C6:%.*]] = constant 6 : index
25// CHECK:           [[C7:%.*]] = constant 7 : index
26// CHECK:           [[C42:%.*]] = constant 42 : i32
27// CHECK:           scf.parallel ([[V0:%.*]]) = ([[C3]]) to ([[C6]]) step ([[C2]]) {
28// CHECK:             store [[C42]], [[ARG0]]{{\[}}[[C0]], [[V0]], [[C7]]] : memref<?x?x?xi32>
29// CHECK:             scf.yield
30// CHECK:           }
31// CHECK:           return
32
33// -----
34
35func @one_unused(%cond: i1) -> (index) {
36  %c0 = constant 0 : index
37  %c1 = constant 1 : index
38  %0, %1 = scf.if %cond -> (index, index) {
39    scf.yield %c0, %c1 : index, index
40  } else {
41    scf.yield %c0, %c1 : index, index
42  }
43  return %1 : index
44}
45
46// CHECK-LABEL:   func @one_unused
47// CHECK:           [[C0:%.*]] = constant 1 : index
48// CHECK:           [[V0:%.*]] = scf.if %{{.*}} -> (index) {
49// CHECK:             scf.yield [[C0]] : index
50// CHECK:           } else
51// CHECK:             scf.yield [[C0]] : index
52// CHECK:           }
53// CHECK:           return [[V0]] : index
54
55// -----
56
57func @nested_unused(%cond1: i1, %cond2: i1) -> (index) {
58  %c0 = constant 0 : index
59  %c1 = constant 1 : index
60  %0, %1 = scf.if %cond1 -> (index, index) {
61    %2, %3 = scf.if %cond2 -> (index, index) {
62      scf.yield %c0, %c1 : index, index
63    } else {
64      scf.yield %c0, %c1 : index, index
65    }
66    scf.yield %2, %3 : index, index
67  } else {
68    scf.yield %c0, %c1 : index, index
69  }
70  return %1 : index
71}
72
73// CHECK-LABEL:   func @nested_unused
74// CHECK:           [[C0:%.*]] = constant 1 : index
75// CHECK:           [[V0:%.*]] = scf.if {{.*}} -> (index) {
76// CHECK:             [[V1:%.*]] = scf.if {{.*}} -> (index) {
77// CHECK:               scf.yield [[C0]] : index
78// CHECK:             } else
79// CHECK:               scf.yield [[C0]] : index
80// CHECK:             }
81// CHECK:             scf.yield [[V1]] : index
82// CHECK:           } else
83// CHECK:             scf.yield [[C0]] : index
84// CHECK:           }
85// CHECK:           return [[V0]] : index
86
87// -----
88
89func private @side_effect()
90func @all_unused(%cond: i1) {
91  %c0 = constant 0 : index
92  %c1 = constant 1 : index
93  %0, %1 = scf.if %cond -> (index, index) {
94    call @side_effect() : () -> ()
95    scf.yield %c0, %c1 : index, index
96  } else {
97    call @side_effect() : () -> ()
98    scf.yield %c0, %c1 : index, index
99  }
100  return
101}
102
103// CHECK-LABEL:   func @all_unused
104// CHECK:           scf.if %{{.*}} {
105// CHECK:             call @side_effect() : () -> ()
106// CHECK:           } else
107// CHECK:             call @side_effect() : () -> ()
108// CHECK:           }
109// CHECK:           return
110
111// -----
112
113func private @make_i32() -> i32
114
115func @for_yields_2(%lb : index, %ub : index, %step : index) -> i32 {
116  %a = call @make_i32() : () -> (i32)
117  %b = scf.for %i = %lb to %ub step %step iter_args(%0 = %a) -> i32 {
118    scf.yield %0 : i32
119  }
120  return %b : i32
121}
122
123// CHECK-LABEL:   func @for_yields_2
124//  CHECK-NEXT:     %[[R:.*]] = call @make_i32() : () -> i32
125//  CHECK-NEXT:     return %[[R]] : i32
126
127func @for_yields_3(%lb : index, %ub : index, %step : index) -> (i32, i32, i32) {
128  %a = call @make_i32() : () -> (i32)
129  %b = call @make_i32() : () -> (i32)
130  %r:3 = scf.for %i = %lb to %ub step %step iter_args(%0 = %a, %1 = %a, %2 = %b) -> (i32, i32, i32) {
131    %c = call @make_i32() : () -> (i32)
132    scf.yield %0, %c, %2 : i32, i32, i32
133  }
134  return %r#0, %r#1, %r#2 : i32, i32, i32
135}
136
137// CHECK-LABEL:   func @for_yields_3
138//  CHECK-NEXT:     %[[a:.*]] = call @make_i32() : () -> i32
139//  CHECK-NEXT:     %[[b:.*]] = call @make_i32() : () -> i32
140//  CHECK-NEXT:     %[[r1:.*]] = scf.for {{.*}} iter_args(%arg4 = %[[a]]) -> (i32) {
141//  CHECK-NEXT:       %[[c:.*]] = call @make_i32() : () -> i32
142//  CHECK-NEXT:       scf.yield %[[c]] : i32
143//  CHECK-NEXT:     }
144//  CHECK-NEXT:     return %[[a]], %[[r1]], %[[b]] : i32, i32, i32
145
146// CHECK-LABEL: @replace_true_if
147func @replace_true_if() {
148  %true = constant true
149  // CHECK-NOT: scf.if
150  // CHECK: "test.op"
151  scf.if %true {
152    "test.op"() : () -> ()
153    scf.yield
154  }
155  return
156}
157
158// CHECK-LABEL: @remove_false_if
159func @remove_false_if() {
160  %false = constant false
161  // CHECK-NOT: scf.if
162  // CHECK-NOT: "test.op"
163  scf.if %false {
164    "test.op"() : () -> ()
165    scf.yield
166  }
167  return
168}
169
170// CHECK-LABEL: @replace_true_if_with_values
171func @replace_true_if_with_values() {
172  %true = constant true
173  // CHECK-NOT: scf.if
174  // CHECK: %[[VAL:.*]] = "test.op"
175  %0 = scf.if %true -> (i32) {
176    %1 = "test.op"() : () -> i32
177    scf.yield %1 : i32
178  } else {
179    %2 = "test.other_op"() : () -> i32
180    scf.yield %2 : i32
181  }
182  // CHECK: "test.consume"(%[[VAL]])
183  "test.consume"(%0) : (i32) -> ()
184  return
185}
186
187// CHECK-LABEL: @replace_false_if_with_values
188func @replace_false_if_with_values() {
189  %false = constant false
190  // CHECK-NOT: scf.if
191  // CHECK: %[[VAL:.*]] = "test.other_op"
192  %0 = scf.if %false -> (i32) {
193    %1 = "test.op"() : () -> i32
194    scf.yield %1 : i32
195  } else {
196    %2 = "test.other_op"() : () -> i32
197    scf.yield %2 : i32
198  }
199  // CHECK: "test.consume"(%[[VAL]])
200  "test.consume"(%0) : (i32) -> ()
201  return
202}
203
204// CHECK-LABEL: @remove_zero_iteration_loop
205func @remove_zero_iteration_loop() {
206  %c42 = constant 42 : index
207  %c1 = constant 1 : index
208  // CHECK: %[[INIT:.*]] = "test.init"
209  %init = "test.init"() : () -> i32
210  // CHECK-NOT: scf.for
211  %0 = scf.for %i = %c42 to %c1 step %c1 iter_args(%arg = %init) -> (i32) {
212    %1 = "test.op"(%i, %arg) : (index, i32) -> i32
213    scf.yield %1 : i32
214  }
215  // CHECK: "test.consume"(%[[INIT]])
216  "test.consume"(%0) : (i32) -> ()
217  return
218}
219
220// CHECK-LABEL: @remove_zero_iteration_loop_vals
221func @remove_zero_iteration_loop_vals(%arg0: index) {
222  %c2 = constant 2 : index
223  // CHECK: %[[INIT:.*]] = "test.init"
224  %init = "test.init"() : () -> i32
225  // CHECK-NOT: scf.for
226  // CHECK-NOT: test.op
227  %0 = scf.for %i = %arg0 to %arg0 step %c2 iter_args(%arg = %init) -> (i32) {
228    %1 = "test.op"(%i, %arg) : (index, i32) -> i32
229    scf.yield %1 : i32
230  }
231  // CHECK: "test.consume"(%[[INIT]])
232  "test.consume"(%0) : (i32) -> ()
233  return
234}
235
236// CHECK-LABEL: @replace_single_iteration_loop
237func @replace_single_iteration_loop() {
238  // CHECK: %[[LB:.*]] = constant 42
239  %c42 = constant 42 : index
240  %c43 = constant 43 : index
241  %c1 = constant 1 : index
242  // CHECK: %[[INIT:.*]] = "test.init"
243  %init = "test.init"() : () -> i32
244  // CHECK-NOT: scf.for
245  // CHECK: %[[VAL:.*]] = "test.op"(%[[LB]], %[[INIT]])
246  %0 = scf.for %i = %c42 to %c43 step %c1 iter_args(%arg = %init) -> (i32) {
247    %1 = "test.op"(%i, %arg) : (index, i32) -> i32
248    scf.yield %1 : i32
249  }
250  // CHECK: "test.consume"(%[[VAL]])
251  "test.consume"(%0) : (i32) -> ()
252  return
253}
254
255// CHECK-LABEL: @replace_single_iteration_loop_non_unit_step
256func @replace_single_iteration_loop_non_unit_step() {
257  // CHECK: %[[LB:.*]] = constant 42
258  %c42 = constant 42 : index
259  %c47 = constant 47 : index
260  %c5 = constant 5 : index
261  // CHECK: %[[INIT:.*]] = "test.init"
262  %init = "test.init"() : () -> i32
263  // CHECK-NOT: scf.for
264  // CHECK: %[[VAL:.*]] = "test.op"(%[[LB]], %[[INIT]])
265  %0 = scf.for %i = %c42 to %c47 step %c5 iter_args(%arg = %init) -> (i32) {
266    %1 = "test.op"(%i, %arg) : (index, i32) -> i32
267    scf.yield %1 : i32
268  }
269  // CHECK: "test.consume"(%[[VAL]])
270  "test.consume"(%0) : (i32) -> ()
271  return
272}
273
274// CHECK-LABEL: @remove_empty_parallel_loop
275func @remove_empty_parallel_loop(%lb: index, %ub: index, %s: index) {
276  // CHECK: %[[INIT:.*]] = "test.init"
277  %init = "test.init"() : () -> f32
278  // CHECK-NOT: scf.parallel
279  // CHECK-NOT: test.produce
280  // CHECK-NOT: test.transform
281  %0 = scf.parallel (%i, %j, %k) = (%lb, %ub, %lb) to (%ub, %ub, %ub) step (%s, %s, %s) init(%init) -> f32 {
282    %1 = "test.produce"() : () -> f32
283    scf.reduce(%1) : f32 {
284    ^bb0(%lhs: f32, %rhs: f32):
285      %2 = "test.transform"(%lhs, %rhs) : (f32, f32) -> f32
286      scf.reduce.return %2 : f32
287    }
288    scf.yield
289  }
290  // CHECK: "test.consume"(%[[INIT]])
291  "test.consume"(%0) : (f32) -> ()
292  return
293}
294