[SLP]Fix PR104422: Wrong value truncation
[llvm-project.git] / mlir / test / Transforms / cse.mlir
blob11a331026847334f7873078f54be073c172305e7
1 // RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(cse))' | FileCheck %s
3 // CHECK-DAG: #[[$MAP:.*]] = affine_map<(d0) -> (d0 mod 2)>
4 #map0 = affine_map<(d0) -> (d0 mod 2)>
6 // CHECK-LABEL: @simple_constant
7 func.func @simple_constant() -> (i32, i32) {
8   // CHECK-NEXT: %[[VAR_c1_i32:.*]] = arith.constant 1 : i32
9   %0 = arith.constant 1 : i32
11   // CHECK-NEXT: return %[[VAR_c1_i32]], %[[VAR_c1_i32]] : i32, i32
12   %1 = arith.constant 1 : i32
13   return %0, %1 : i32, i32
16 // CHECK-LABEL: @basic
17 func.func @basic() -> (index, index) {
18   // CHECK: %[[VAR_c0:[0-9a-zA-Z_]+]] = arith.constant 0 : index
19   %c0 = arith.constant 0 : index
20   %c1 = arith.constant 0 : index
22   // CHECK-NEXT: %[[VAR_0:[0-9a-zA-Z_]+]] = affine.apply #[[$MAP]](%[[VAR_c0]])
23   %0 = affine.apply #map0(%c0)
24   %1 = affine.apply #map0(%c1)
26   // CHECK-NEXT: return %[[VAR_0]], %[[VAR_0]] : index, index
27   return %0, %1 : index, index
30 // CHECK-LABEL: @many
31 func.func @many(f32, f32) -> (f32) {
32 ^bb0(%a : f32, %b : f32):
33   // CHECK-NEXT: %[[VAR_0:[0-9a-zA-Z_]+]] = arith.addf %{{.*}}, %{{.*}} : f32
34   %c = arith.addf %a, %b : f32
35   %d = arith.addf %a, %b : f32
36   %e = arith.addf %a, %b : f32
37   %f = arith.addf %a, %b : f32
39   // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_0]], %[[VAR_0]] : f32
40   %g = arith.addf %c, %d : f32
41   %h = arith.addf %e, %f : f32
42   %i = arith.addf %c, %e : f32
44   // CHECK-NEXT: %[[VAR_2:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_1]], %[[VAR_1]] : f32
45   %j = arith.addf %g, %h : f32
46   %k = arith.addf %h, %i : f32
48   // CHECK-NEXT: %[[VAR_3:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_2]], %[[VAR_2]] : f32
49   %l = arith.addf %j, %k : f32
51   // CHECK-NEXT: return %[[VAR_3]] : f32
52   return %l : f32
55 /// Check that operations are not eliminated if they have different operands.
56 // CHECK-LABEL: @different_ops
57 func.func @different_ops() -> (i32, i32) {
58   // CHECK: %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i32
59   // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
60   %0 = arith.constant 0 : i32
61   %1 = arith.constant 1 : i32
63   // CHECK-NEXT: return %[[VAR_c0_i32]], %[[VAR_c1_i32]] : i32, i32
64   return %0, %1 : i32, i32
67 /// Check that operations are not eliminated if they have different result
68 /// types.
69 // CHECK-LABEL: @different_results
70 func.func @different_results(%arg0: tensor<*xf32>) -> (tensor<?x?xf32>, tensor<4x?xf32>) {
71   // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = tensor.cast %{{.*}} : tensor<*xf32> to tensor<?x?xf32>
72   // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = tensor.cast %{{.*}} : tensor<*xf32> to tensor<4x?xf32>
73   %0 = tensor.cast %arg0 : tensor<*xf32> to tensor<?x?xf32>
74   %1 = tensor.cast %arg0 : tensor<*xf32> to tensor<4x?xf32>
76   // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]] : tensor<?x?xf32>, tensor<4x?xf32>
77   return %0, %1 : tensor<?x?xf32>, tensor<4x?xf32>
80 /// Check that operations are not eliminated if they have different attributes.
81 // CHECK-LABEL: @different_attributes
82 func.func @different_attributes(index, index) -> (i1, i1, i1) {
83 ^bb0(%a : index, %b : index):
84   // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = arith.cmpi slt, %{{.*}}, %{{.*}} : index
85   %0 = arith.cmpi slt, %a, %b : index
87   // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.cmpi ne, %{{.*}}, %{{.*}} : index
88   /// Predicate 1 means inequality comparison.
89   %1 = arith.cmpi ne, %a, %b : index
90   %2 = "arith.cmpi"(%a, %b) {predicate = 1} : (index, index) -> i1
92   // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]], %[[VAR_1]] : i1, i1, i1
93   return %0, %1, %2 : i1, i1, i1
96 /// Check that operations with side effects are not eliminated.
97 // CHECK-LABEL: @side_effect
98 func.func @side_effect() -> (memref<2x1xf32>, memref<2x1xf32>) {
99   // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = memref.alloc() : memref<2x1xf32>
100   %0 = memref.alloc() : memref<2x1xf32>
102   // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = memref.alloc() : memref<2x1xf32>
103   %1 = memref.alloc() : memref<2x1xf32>
105   // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]] : memref<2x1xf32>, memref<2x1xf32>
106   return %0, %1 : memref<2x1xf32>, memref<2x1xf32>
109 /// Check that operation definitions are properly propagated down the dominance
110 /// tree.
111 // CHECK-LABEL: @down_propagate_for
112 func.func @down_propagate_for() {
113   // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
114   %0 = arith.constant 1 : i32
116   // CHECK-NEXT: affine.for {{.*}} = 0 to 4 {
117   affine.for %i = 0 to 4 {
118     // CHECK-NEXT: "foo"(%[[VAR_c1_i32]], %[[VAR_c1_i32]]) : (i32, i32) -> ()
119     %1 = arith.constant 1 : i32
120     "foo"(%0, %1) : (i32, i32) -> ()
121   }
122   return
125 // CHECK-LABEL: @down_propagate
126 func.func @down_propagate() -> i32 {
127   // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
128   %0 = arith.constant 1 : i32
130   // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true
131   %cond = arith.constant true
133   // CHECK-NEXT: cf.cond_br %[[VAR_true]], ^bb1, ^bb2(%[[VAR_c1_i32]] : i32)
134   cf.cond_br %cond, ^bb1, ^bb2(%0 : i32)
136 ^bb1: // CHECK: ^bb1:
137   // CHECK-NEXT: cf.br ^bb2(%[[VAR_c1_i32]] : i32)
138   %1 = arith.constant 1 : i32
139   cf.br ^bb2(%1 : i32)
141 ^bb2(%arg : i32):
142   return %arg : i32
145 /// Check that operation definitions are NOT propagated up the dominance tree.
146 // CHECK-LABEL: @up_propagate_for
147 func.func @up_propagate_for() -> i32 {
148   // CHECK: affine.for {{.*}} = 0 to 4 {
149   affine.for %i = 0 to 4 {
150     // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
151     // CHECK-NEXT: "foo"(%[[VAR_c1_i32_0]]) : (i32) -> ()
152     %0 = arith.constant 1 : i32
153     "foo"(%0) : (i32) -> ()
154   }
156   // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
157   // CHECK-NEXT: return %[[VAR_c1_i32]] : i32
158   %1 = arith.constant 1 : i32
159   return %1 : i32
162 // CHECK-LABEL: func @up_propagate
163 func.func @up_propagate() -> i32 {
164   // CHECK-NEXT:  %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i32
165   %0 = arith.constant 0 : i32
167   // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true
168   %cond = arith.constant true
170   // CHECK-NEXT: cf.cond_br %[[VAR_true]], ^bb1, ^bb2(%[[VAR_c0_i32]] : i32)
171   cf.cond_br %cond, ^bb1, ^bb2(%0 : i32)
173 ^bb1: // CHECK: ^bb1:
174   // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
175   %1 = arith.constant 1 : i32
177   // CHECK-NEXT: cf.br ^bb2(%[[VAR_c1_i32]] : i32)
178   cf.br ^bb2(%1 : i32)
180 ^bb2(%arg : i32): // CHECK: ^bb2
181   // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
182   %2 = arith.constant 1 : i32
184   // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.addi %{{.*}}, %[[VAR_c1_i32_0]] : i32
185   %add = arith.addi %arg, %2 : i32
187   // CHECK-NEXT: return %[[VAR_1]] : i32
188   return %add : i32
191 /// The same test as above except that we are testing on a cfg embedded within
192 /// an operation region.
193 // CHECK-LABEL: func @up_propagate_region
194 func.func @up_propagate_region() -> i32 {
195   // CHECK-NEXT: {{.*}} "foo.region"
196   %0 = "foo.region"() ({
197     // CHECK-NEXT:  %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i32
198     // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true
199     // CHECK-NEXT: cf.cond_br
201     %1 = arith.constant 0 : i32
202     %true = arith.constant true
203     cf.cond_br %true, ^bb1, ^bb2(%1 : i32)
205   ^bb1: // CHECK: ^bb1:
206     // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
207     // CHECK-NEXT: cf.br
209     %c1_i32 = arith.constant 1 : i32
210     cf.br ^bb2(%c1_i32 : i32)
212   ^bb2(%arg : i32): // CHECK: ^bb2(%[[VAR_1:.*]]: i32):
213     // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32
214     // CHECK-NEXT: %[[VAR_2:[0-9a-zA-Z_]+]] = arith.addi %[[VAR_1]], %[[VAR_c1_i32_0]] : i32
215     // CHECK-NEXT: "foo.yield"(%[[VAR_2]]) : (i32) -> ()
217     %c1_i32_0 = arith.constant 1 : i32
218     %2 = arith.addi %arg, %c1_i32_0 : i32
219     "foo.yield" (%2) : (i32) -> ()
220   }) : () -> (i32)
221   return %0 : i32
224 /// This test checks that nested regions that are isolated from above are
225 /// properly handled.
226 // CHECK-LABEL: @nested_isolated
227 func.func @nested_isolated() -> i32 {
228   // CHECK-NEXT: arith.constant 1
229   %0 = arith.constant 1 : i32
231   // CHECK-NEXT: builtin.module
232   // CHECK-NEXT: @nested_func
233   builtin.module {
234     func.func @nested_func() {
235       // CHECK-NEXT: arith.constant 1
236       %foo = arith.constant 1 : i32
237       "foo.yield"(%foo) : (i32) -> ()
238     }
239   }
241   // CHECK: "foo.region"
242   "foo.region"() ({
243     // CHECK-NEXT: arith.constant 1
244     %foo = arith.constant 1 : i32
245     "foo.yield"(%foo) : (i32) -> ()
246   }) : () -> ()
248   return %0 : i32
251 /// This test is checking that CSE gracefully handles values in graph regions
252 /// where the use occurs before the def, and one of the defs could be CSE'd with
253 /// the other.
254 // CHECK-LABEL: @use_before_def
255 func.func @use_before_def() {
256   // CHECK-NEXT: test.graph_region
257   test.graph_region {
258     // CHECK-NEXT: arith.addi
259     %0 = arith.addi %1, %2 : i32
261     // CHECK-NEXT: arith.constant 1
262     // CHECK-NEXT: arith.constant 1
263     %1 = arith.constant 1 : i32
264     %2 = arith.constant 1 : i32
266     // CHECK-NEXT: "foo.yield"(%{{.*}}) : (i32) -> ()
267     "foo.yield"(%0) : (i32) -> ()
268   }
269   return
272 /// This test is checking that CSE is removing duplicated read op that follow
273 /// other.
274 // CHECK-LABEL: @remove_direct_duplicated_read_op
275 func.func @remove_direct_duplicated_read_op() -> i32 {
276   // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32
277   %0 = "test.op_with_memread"() : () -> (i32)
278   %1 = "test.op_with_memread"() : () -> (i32)
279   // CHECK-NEXT: %{{.*}} = arith.addi %[[READ_VALUE]], %[[READ_VALUE]] : i32
280   %2 = arith.addi %0, %1 : i32
281   return %2 : i32
284 /// This test is checking that CSE is removing duplicated read op that follow
285 /// other.
286 // CHECK-LABEL: @remove_multiple_duplicated_read_op
287 func.func @remove_multiple_duplicated_read_op() -> i64 {
288   // CHECK: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i64
289   %0 = "test.op_with_memread"() : () -> (i64)
290   %1 = "test.op_with_memread"() : () -> (i64)
291   // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %[[READ_VALUE]] : i64
292   %2 = arith.addi %0, %1 : i64
293   %3 = "test.op_with_memread"() : () -> (i64)
294   // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i64
295   %4 = arith.addi %2, %3 : i64
296   %5 = "test.op_with_memread"() : () -> (i64)
297   // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i64
298   %6 = arith.addi %4, %5 : i64
299   // CHECK-NEXT: return %{{.*}} : i64
300   return %6 : i64
303 /// This test is checking that CSE is not removing duplicated read op that
304 /// have write op in between.
305 // CHECK-LABEL: @dont_remove_duplicated_read_op_with_sideeffecting
306 func.func @dont_remove_duplicated_read_op_with_sideeffecting() -> i32 {
307   // CHECK-NEXT: %[[READ_VALUE0:.*]] = "test.op_with_memread"() : () -> i32
308   %0 = "test.op_with_memread"() : () -> (i32)
309   "test.op_with_memwrite"() : () -> ()
310   // CHECK: %[[READ_VALUE1:.*]] = "test.op_with_memread"() : () -> i32
311   %1 = "test.op_with_memread"() : () -> (i32)
312   // CHECK-NEXT: %{{.*}} = arith.addi %[[READ_VALUE0]], %[[READ_VALUE1]] : i32
313   %2 = arith.addi %0, %1 : i32
314   return %2 : i32
317 // Check that an operation with a single region can CSE.
318 func.func @cse_single_block_ops(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)
319   -> (tensor<?x?xf32>, tensor<?x?xf32>) {
320   %0 = test.cse_of_single_block_op inputs(%a, %b) {
321     ^bb0(%arg0 : f32):
322     test.region_yield %arg0 : f32
323   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
324   %1 = test.cse_of_single_block_op inputs(%a, %b) {
325     ^bb0(%arg0 : f32):
326     test.region_yield %arg0 : f32
327   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
328   return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>
330 // CHECK-LABEL: func @cse_single_block_ops
331 //       CHECK:   %[[OP:.+]] = test.cse_of_single_block_op
332 //   CHECK-NOT:   test.cse_of_single_block_op
333 //       CHECK:   return %[[OP]], %[[OP]]
335 // Operations with different number of bbArgs dont CSE.
336 func.func @no_cse_varied_bbargs(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)
337   -> (tensor<?x?xf32>, tensor<?x?xf32>) {
338   %0 = test.cse_of_single_block_op inputs(%a, %b) {
339     ^bb0(%arg0 : f32, %arg1 : f32):
340     test.region_yield %arg0 : f32
341   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
342   %1 = test.cse_of_single_block_op inputs(%a, %b) {
343     ^bb0(%arg0 : f32):
344     test.region_yield %arg0 : f32
345   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
346   return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>
348 // CHECK-LABEL: func @no_cse_varied_bbargs
349 //       CHECK:   %[[OP0:.+]] = test.cse_of_single_block_op
350 //       CHECK:   %[[OP1:.+]] = test.cse_of_single_block_op
351 //       CHECK:   return %[[OP0]], %[[OP1]]
353 // Operations with different regions dont CSE
354 func.func @no_cse_region_difference_simple(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)
355   -> (tensor<?x?xf32>, tensor<?x?xf32>) {
356   %0 = test.cse_of_single_block_op inputs(%a, %b) {
357     ^bb0(%arg0 : f32, %arg1 : f32):
358     test.region_yield %arg0 : f32
359   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
360   %1 = test.cse_of_single_block_op inputs(%a, %b) {
361     ^bb0(%arg0 : f32, %arg1 : f32):
362     test.region_yield %arg1 : f32
363   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
364   return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>
366 // CHECK-LABEL: func @no_cse_region_difference_simple
367 //       CHECK:   %[[OP0:.+]] = test.cse_of_single_block_op
368 //       CHECK:   %[[OP1:.+]] = test.cse_of_single_block_op
369 //       CHECK:   return %[[OP0]], %[[OP1]]
371 // Operation with identical region with multiple statements CSE.
372 func.func @cse_single_block_ops_identical_bodies(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>, %c : f32, %d : i1)
373   -> (tensor<?x?xf32>, tensor<?x?xf32>) {
374   %0 = test.cse_of_single_block_op inputs(%a, %b) {
375     ^bb0(%arg0 : f32, %arg1 : f32):
376     %1 = arith.divf %arg0, %arg1 : f32
377     %2 = arith.remf %arg0, %c : f32
378     %3 = arith.select %d, %1, %2 : f32
379     test.region_yield %3 : f32
380   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
381   %1 = test.cse_of_single_block_op inputs(%a, %b) {
382     ^bb0(%arg0 : f32, %arg1 : f32):
383     %1 = arith.divf %arg0, %arg1 : f32
384     %2 = arith.remf %arg0, %c : f32
385     %3 = arith.select %d, %1, %2 : f32
386     test.region_yield %3 : f32
387   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
388   return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>
390 // CHECK-LABEL: func @cse_single_block_ops_identical_bodies
391 //       CHECK:   %[[OP:.+]] = test.cse_of_single_block_op
392 //   CHECK-NOT:   test.cse_of_single_block_op
393 //       CHECK:   return %[[OP]], %[[OP]]
395 // Operation with non-identical regions dont CSE.
396 func.func @no_cse_single_block_ops_different_bodies(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>, %c : f32, %d : i1)
397   -> (tensor<?x?xf32>, tensor<?x?xf32>) {
398   %0 = test.cse_of_single_block_op inputs(%a, %b) {
399     ^bb0(%arg0 : f32, %arg1 : f32):
400     %1 = arith.divf %arg0, %arg1 : f32
401     %2 = arith.remf %arg0, %c : f32
402     %3 = arith.select %d, %1, %2 : f32
403     test.region_yield %3 : f32
404   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
405   %1 = test.cse_of_single_block_op inputs(%a, %b) {
406     ^bb0(%arg0 : f32, %arg1 : f32):
407     %1 = arith.divf %arg0, %arg1 : f32
408     %2 = arith.remf %arg0, %c : f32
409     %3 = arith.select %d, %2, %1 : f32
410     test.region_yield %3 : f32
411   } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>
412   return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>
414 // CHECK-LABEL: func @no_cse_single_block_ops_different_bodies
415 //       CHECK:   %[[OP0:.+]] = test.cse_of_single_block_op
416 //       CHECK:   %[[OP1:.+]] = test.cse_of_single_block_op
417 //       CHECK:   return %[[OP0]], %[[OP1]]
419 func.func @failing_issue_59135(%arg0: tensor<2x2xi1>, %arg1: f32, %arg2 : tensor<2xi1>) -> (tensor<2xi1>, tensor<2xi1>) {
420   %false_2 = arith.constant false
421   %true_5 = arith.constant true
422   %9 = test.cse_of_single_block_op inputs(%arg2) {
423   ^bb0(%out: i1):
424     %true_144 = arith.constant true
425     test.region_yield %true_144 : i1
426   } : tensor<2xi1> -> tensor<2xi1>
427   %15 = test.cse_of_single_block_op inputs(%arg2) {
428   ^bb0(%out: i1):
429     %true_144 = arith.constant true
430     test.region_yield %true_144 : i1
431   } : tensor<2xi1> -> tensor<2xi1>
432   %93 = arith.maxsi %false_2, %true_5 : i1
433   return %9, %15 : tensor<2xi1>, tensor<2xi1>
435 // CHECK-LABEL: func @failing_issue_59135
436 //       CHECK:   %[[TRUE:.+]] = arith.constant true
437 //       CHECK:   %[[OP:.+]] = test.cse_of_single_block_op
438 //       CHECK:     test.region_yield %[[TRUE]]
439 //       CHECK:   return %[[OP]], %[[OP]]
441 func.func @cse_multiple_regions(%c: i1, %t: tensor<5xf32>) -> (tensor<5xf32>, tensor<5xf32>) {
442   %r1 = scf.if %c -> (tensor<5xf32>) {
443     %0 = tensor.empty() : tensor<5xf32>
444     scf.yield %0 : tensor<5xf32>
445   } else {
446     scf.yield %t : tensor<5xf32>
447   }
448   %r2 = scf.if %c -> (tensor<5xf32>) {
449     %0 = tensor.empty() : tensor<5xf32>
450     scf.yield %0 : tensor<5xf32>
451   } else {
452     scf.yield %t : tensor<5xf32>
453   }
454   return %r1, %r2 : tensor<5xf32>, tensor<5xf32>
456 // CHECK-LABEL: func @cse_multiple_regions
457 //       CHECK:   %[[if:.*]] = scf.if {{.*}} {
458 //       CHECK:     tensor.empty
459 //       CHECK:     scf.yield
460 //       CHECK:   } else {
461 //       CHECK:     scf.yield
462 //       CHECK:   }
463 //   CHECK-NOT:   scf.if
464 //       CHECK:   return %[[if]], %[[if]]
466 // CHECK-LABEL: @cse_recursive_effects_success
467 func.func @cse_recursive_effects_success() -> (i32, i32, i32) {
468   // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32
469   %0 = "test.op_with_memread"() : () -> (i32)
471   // do something with recursive effects, containing no side effects
472   %true = arith.constant true
473   // CHECK-NEXT: %[[TRUE:.+]] = arith.constant true
474   // CHECK-NEXT: %[[IF:.+]] = scf.if %[[TRUE]] -> (i32) {
475   %1 = scf.if %true -> (i32) {
476     %c42 = arith.constant 42 : i32
477     scf.yield %c42 : i32
478     // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32
479     // CHECK-NEXT: scf.yield %[[C42]]
480     // CHECK-NEXT: } else {
481   } else {
482     %c24 = arith.constant 24 : i32
483     scf.yield %c24 : i32
484     // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32
485     // CHECK-NEXT: scf.yield %[[C24]]
486     // CHECK-NEXT: }
487   }
489   // %2 can be removed
490   // CHECK-NEXT: return %[[READ_VALUE]], %[[READ_VALUE]], %[[IF]] : i32, i32, i32
491   %2 = "test.op_with_memread"() : () -> (i32)
492   return %0, %2, %1 : i32, i32, i32
495 // CHECK-LABEL: @cse_recursive_effects_failure
496 func.func @cse_recursive_effects_failure() -> (i32, i32, i32) {
497   // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32
498   %0 = "test.op_with_memread"() : () -> (i32)
500   // do something with recursive effects, containing a write effect
501   %true = arith.constant true
502   // CHECK-NEXT: %[[TRUE:.+]] = arith.constant true
503   // CHECK-NEXT: %[[IF:.+]] = scf.if %[[TRUE]] -> (i32) {
504   %1 = scf.if %true -> (i32) {
505     "test.op_with_memwrite"() : () -> ()
506     // CHECK-NEXT: "test.op_with_memwrite"() : () -> ()
507     %c42 = arith.constant 42 : i32
508     scf.yield %c42 : i32
509     // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32
510     // CHECK-NEXT: scf.yield %[[C42]]
511     // CHECK-NEXT: } else {
512   } else {
513     %c24 = arith.constant 24 : i32
514     scf.yield %c24 : i32
515     // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32
516     // CHECK-NEXT: scf.yield %[[C24]]
517     // CHECK-NEXT: }
518   }
520   // %2 can not be be removed because of the write
521   // CHECK-NEXT: %[[READ_VALUE2:.*]] = "test.op_with_memread"() : () -> i32
522   // CHECK-NEXT: return %[[READ_VALUE]], %[[READ_VALUE2]], %[[IF]] : i32, i32, i32
523   %2 = "test.op_with_memread"() : () -> (i32)
524   return %0, %2, %1 : i32, i32, i32