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
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
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
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
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) -> ()
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
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) -> ()
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
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)
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
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
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) -> ()
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
234 func.func @nested_func() {
235 // CHECK-NEXT: arith.constant 1
236 %foo = arith.constant 1 : i32
237 "foo.yield"(%foo) : (i32) -> ()
241 // CHECK: "foo.region"
243 // CHECK-NEXT: arith.constant 1
244 %foo = arith.constant 1 : i32
245 "foo.yield"(%foo) : (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
254 // CHECK-LABEL: @use_before_def
255 func.func @use_before_def() {
256 // CHECK-NEXT: 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) -> ()
272 /// This test is checking that CSE is removing duplicated read op that follow
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
284 /// This test is checking that CSE is removing duplicated read op that follow
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
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
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) {
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) {
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) {
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) {
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) {
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>
446 scf.yield %t : tensor<5xf32>
448 %r2 = scf.if %c -> (tensor<5xf32>) {
449 %0 = tensor.empty() : tensor<5xf32>
450 scf.yield %0 : tensor<5xf32>
452 scf.yield %t : tensor<5xf32>
454 return %r1, %r2 : tensor<5xf32>, tensor<5xf32>
456 // CHECK-LABEL: func @cse_multiple_regions
457 // CHECK: %[[if:.*]] = scf.if {{.*}} {
458 // CHECK: tensor.empty
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
478 // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32
479 // CHECK-NEXT: scf.yield %[[C42]]
480 // CHECK-NEXT: } else {
482 %c24 = arith.constant 24 : i32
484 // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32
485 // CHECK-NEXT: scf.yield %[[C24]]
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
509 // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32
510 // CHECK-NEXT: scf.yield %[[C42]]
511 // CHECK-NEXT: } else {
513 %c24 = arith.constant 24 : i32
515 // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32
516 // CHECK-NEXT: scf.yield %[[C24]]
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