576 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect %s -pass-pipeline='builtin.module(func.func(cse))' -split-input-file | FileCheck %s2 3// CHECK-LABEL: @simple_constant4func.func @simple_constant() -> (i32, i32) {5 // CHECK-NEXT: %[[VAR_c1_i32:.*]] = arith.constant 1 : i326 %0 = arith.constant 1 : i327 8 // CHECK-NEXT: return %[[VAR_c1_i32]], %[[VAR_c1_i32]] : i32, i329 %1 = arith.constant 1 : i3210 return %0, %1 : i32, i3211}12 13// -----14 15// CHECK: #[[$MAP:.*]] = affine_map<(d0) -> (d0 mod 2)>16#map0 = affine_map<(d0) -> (d0 mod 2)>17 18// CHECK-LABEL: @basic19func.func @basic() -> (index, index) {20 // CHECK: %[[VAR_c0:[0-9a-zA-Z_]+]] = arith.constant 0 : index21 %c0 = arith.constant 0 : index22 %c1 = arith.constant 0 : index23 24 // CHECK-NEXT: %[[VAR_0:[0-9a-zA-Z_]+]] = affine.apply #[[$MAP]](%[[VAR_c0]])25 %0 = affine.apply #map0(%c0)26 %1 = affine.apply #map0(%c1)27 28 // CHECK-NEXT: return %[[VAR_0]], %[[VAR_0]] : index, index29 return %0, %1 : index, index30}31 32// -----33 34// CHECK-LABEL: @many35func.func @many(f32, f32) -> (f32) {36^bb0(%a : f32, %b : f32):37 // CHECK-NEXT: %[[VAR_0:[0-9a-zA-Z_]+]] = arith.addf %{{.*}}, %{{.*}} : f3238 %c = arith.addf %a, %b : f3239 %d = arith.addf %a, %b : f3240 %e = arith.addf %a, %b : f3241 %f = arith.addf %a, %b : f3242 43 // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_0]], %[[VAR_0]] : f3244 %g = arith.addf %c, %d : f3245 %h = arith.addf %e, %f : f3246 %i = arith.addf %c, %e : f3247 48 // CHECK-NEXT: %[[VAR_2:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_1]], %[[VAR_1]] : f3249 %j = arith.addf %g, %h : f3250 %k = arith.addf %h, %i : f3251 52 // CHECK-NEXT: %[[VAR_3:[0-9a-zA-Z_]+]] = arith.addf %[[VAR_2]], %[[VAR_2]] : f3253 %l = arith.addf %j, %k : f3254 55 // CHECK-NEXT: return %[[VAR_3]] : f3256 return %l : f3257}58 59// -----60 61/// Check that operations are not eliminated if they have different operands.62// CHECK-LABEL: @different_ops63func.func @different_ops() -> (i32, i32) {64 // CHECK: %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i3265 // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i3266 %0 = arith.constant 0 : i3267 %1 = arith.constant 1 : i3268 69 // CHECK-NEXT: return %[[VAR_c0_i32]], %[[VAR_c1_i32]] : i32, i3270 return %0, %1 : i32, i3271}72 73// -----74 75/// Check that operations are not eliminated if they have different result76/// types.77// CHECK-LABEL: @different_results78func.func @different_results(%arg0: tensor<*xf32>) -> (tensor<?x?xf32>, tensor<4x?xf32>) {79 // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = tensor.cast %{{.*}} : tensor<*xf32> to tensor<?x?xf32>80 // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = tensor.cast %{{.*}} : tensor<*xf32> to tensor<4x?xf32>81 %0 = tensor.cast %arg0 : tensor<*xf32> to tensor<?x?xf32>82 %1 = tensor.cast %arg0 : tensor<*xf32> to tensor<4x?xf32>83 84 // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]] : tensor<?x?xf32>, tensor<4x?xf32>85 return %0, %1 : tensor<?x?xf32>, tensor<4x?xf32>86}87 88// -----89 90/// Check that operations are not eliminated if they have different attributes.91// CHECK-LABEL: @different_attributes92func.func @different_attributes(index, index) -> (i1, i1, i1) {93^bb0(%a : index, %b : index):94 // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = arith.cmpi slt, %{{.*}}, %{{.*}} : index95 %0 = arith.cmpi slt, %a, %b : index96 97 // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.cmpi ne, %{{.*}}, %{{.*}} : index98 /// Predicate 1 means inequality comparison.99 %1 = arith.cmpi ne, %a, %b : index100 %2 = "arith.cmpi"(%a, %b) {predicate = 1} : (index, index) -> i1101 102 // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]], %[[VAR_1]] : i1, i1, i1103 return %0, %1, %2 : i1, i1, i1104}105 106// -----107 108/// Check that operations with side effects are not eliminated.109// CHECK-LABEL: @side_effect110func.func @side_effect() -> (memref<2x1xf32>, memref<2x1xf32>) {111 // CHECK: %[[VAR_0:[0-9a-zA-Z_]+]] = memref.alloc() : memref<2x1xf32>112 %0 = memref.alloc() : memref<2x1xf32>113 114 // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = memref.alloc() : memref<2x1xf32>115 %1 = memref.alloc() : memref<2x1xf32>116 117 // CHECK-NEXT: return %[[VAR_0]], %[[VAR_1]] : memref<2x1xf32>, memref<2x1xf32>118 return %0, %1 : memref<2x1xf32>, memref<2x1xf32>119}120 121// -----122 123/// Check that operation definitions are properly propagated down the dominance124/// tree.125// CHECK-LABEL: @down_propagate_for126func.func @down_propagate_for() {127 // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32128 %0 = arith.constant 1 : i32129 130 // CHECK-NEXT: affine.for {{.*}} = 0 to 4 {131 affine.for %i = 0 to 4 {132 // CHECK-NEXT: "foo"(%[[VAR_c1_i32]], %[[VAR_c1_i32]]) : (i32, i32) -> ()133 %1 = arith.constant 1 : i32134 "foo"(%0, %1) : (i32, i32) -> ()135 }136 return137}138 139// -----140 141// CHECK-LABEL: @down_propagate142func.func @down_propagate() -> i32 {143 // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32144 %0 = arith.constant 1 : i32145 146 // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true147 %cond = arith.constant true148 149 // CHECK-NEXT: cf.cond_br %[[VAR_true]], ^bb1, ^bb2(%[[VAR_c1_i32]] : i32)150 cf.cond_br %cond, ^bb1, ^bb2(%0 : i32)151 152^bb1: // CHECK: ^bb1:153 // CHECK-NEXT: cf.br ^bb2(%[[VAR_c1_i32]] : i32)154 %1 = arith.constant 1 : i32155 cf.br ^bb2(%1 : i32)156 157^bb2(%arg : i32):158 return %arg : i32159}160 161// -----162 163/// Check that operation definitions are NOT propagated up the dominance tree.164// CHECK-LABEL: @up_propagate_for165func.func @up_propagate_for() -> i32 {166 // CHECK: affine.for {{.*}} = 0 to 4 {167 affine.for %i = 0 to 4 {168 // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32169 // CHECK-NEXT: "foo"(%[[VAR_c1_i32_0]]) : (i32) -> ()170 %0 = arith.constant 1 : i32171 "foo"(%0) : (i32) -> ()172 }173 174 // CHECK: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32175 // CHECK-NEXT: return %[[VAR_c1_i32]] : i32176 %1 = arith.constant 1 : i32177 return %1 : i32178}179 180// -----181 182// CHECK-LABEL: func @up_propagate183func.func @up_propagate() -> i32 {184 // CHECK-NEXT: %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i32185 %0 = arith.constant 0 : i32186 187 // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true188 %cond = arith.constant true189 190 // CHECK-NEXT: cf.cond_br %[[VAR_true]], ^bb1, ^bb2(%[[VAR_c0_i32]] : i32)191 cf.cond_br %cond, ^bb1, ^bb2(%0 : i32)192 193^bb1: // CHECK: ^bb1:194 // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32195 %1 = arith.constant 1 : i32196 197 // CHECK-NEXT: cf.br ^bb2(%[[VAR_c1_i32]] : i32)198 cf.br ^bb2(%1 : i32)199 200^bb2(%arg : i32): // CHECK: ^bb2201 // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32202 %2 = arith.constant 1 : i32203 204 // CHECK-NEXT: %[[VAR_1:[0-9a-zA-Z_]+]] = arith.addi %{{.*}}, %[[VAR_c1_i32_0]] : i32205 %add = arith.addi %arg, %2 : i32206 207 // CHECK-NEXT: return %[[VAR_1]] : i32208 return %add : i32209}210 211// -----212 213/// The same test as above except that we are testing on a cfg embedded within214/// an operation region.215// CHECK-LABEL: func @up_propagate_region216func.func @up_propagate_region() -> i32 {217 // CHECK-NEXT: {{.*}} "foo.region"218 %0 = "foo.region"() ({219 // CHECK-NEXT: %[[VAR_c0_i32:[0-9a-zA-Z_]+]] = arith.constant 0 : i32220 // CHECK-NEXT: %[[VAR_true:[0-9a-zA-Z_]+]] = arith.constant true221 // CHECK-NEXT: cf.cond_br222 223 %1 = arith.constant 0 : i32224 %true = arith.constant true225 cf.cond_br %true, ^bb1, ^bb2(%1 : i32)226 227 ^bb1: // CHECK: ^bb1:228 // CHECK-NEXT: %[[VAR_c1_i32:[0-9a-zA-Z_]+]] = arith.constant 1 : i32229 // CHECK-NEXT: cf.br230 231 %c1_i32 = arith.constant 1 : i32232 cf.br ^bb2(%c1_i32 : i32)233 234 ^bb2(%arg : i32): // CHECK: ^bb2(%[[VAR_1:.*]]: i32):235 // CHECK-NEXT: %[[VAR_c1_i32_0:[0-9a-zA-Z_]+]] = arith.constant 1 : i32236 // CHECK-NEXT: %[[VAR_2:[0-9a-zA-Z_]+]] = arith.addi %[[VAR_1]], %[[VAR_c1_i32_0]] : i32237 // CHECK-NEXT: "foo.yield"(%[[VAR_2]]) : (i32) -> ()238 239 %c1_i32_0 = arith.constant 1 : i32240 %2 = arith.addi %arg, %c1_i32_0 : i32241 "foo.yield" (%2) : (i32) -> ()242 }) : () -> (i32)243 return %0 : i32244}245 246// -----247 248/// This test checks that nested regions that are isolated from above are249/// properly handled.250// CHECK-LABEL: @nested_isolated251func.func @nested_isolated() -> i32 {252 // CHECK-NEXT: arith.constant 1253 %0 = arith.constant 1 : i32254 255 // CHECK-NEXT: builtin.module256 // CHECK-NEXT: @nested_func257 builtin.module {258 func.func @nested_func() {259 // CHECK-NEXT: arith.constant 1260 %foo = arith.constant 1 : i32261 "foo.yield"(%foo) : (i32) -> ()262 }263 }264 265 // CHECK: "foo.region"266 "foo.region"() ({267 // CHECK-NEXT: arith.constant 1268 %foo = arith.constant 1 : i32269 "foo.yield"(%foo) : (i32) -> ()270 }) : () -> ()271 272 return %0 : i32273}274 275// -----276 277/// This test is checking that CSE gracefully handles values in graph regions278/// where the use occurs before the def, and one of the defs could be CSE'd with279/// the other.280// CHECK-LABEL: @use_before_def281func.func @use_before_def() {282 // CHECK-NEXT: test.graph_region283 test.graph_region {284 // CHECK-NEXT: arith.addi285 %0 = arith.addi %1, %2 : i32286 287 // CHECK-NEXT: arith.constant 1288 // CHECK-NEXT: arith.constant 1289 %1 = arith.constant 1 : i32290 %2 = arith.constant 1 : i32291 292 // CHECK-NEXT: "foo.yield"(%{{.*}}) : (i32) -> ()293 "foo.yield"(%0) : (i32) -> ()294 }295 return296}297 298// -----299 300/// This test is checking that CSE is removing duplicated read op that follow301/// other.302// CHECK-LABEL: @remove_direct_duplicated_read_op303func.func @remove_direct_duplicated_read_op() -> i32 {304 // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32305 %0 = "test.op_with_memread"() : () -> (i32)306 %1 = "test.op_with_memread"() : () -> (i32)307 // CHECK-NEXT: %{{.*}} = arith.addi %[[READ_VALUE]], %[[READ_VALUE]] : i32308 %2 = arith.addi %0, %1 : i32309 return %2 : i32310}311 312// -----313 314/// This test is checking that CSE is removing duplicated read op that follow315/// other.316// CHECK-LABEL: @remove_multiple_duplicated_read_op317func.func @remove_multiple_duplicated_read_op() -> i64 {318 // CHECK: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i64319 %0 = "test.op_with_memread"() : () -> (i64)320 %1 = "test.op_with_memread"() : () -> (i64)321 // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %[[READ_VALUE]] : i64322 %2 = arith.addi %0, %1 : i64323 %3 = "test.op_with_memread"() : () -> (i64)324 // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i64325 %4 = arith.addi %2, %3 : i64326 %5 = "test.op_with_memread"() : () -> (i64)327 // CHECK-NEXT: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i64328 %6 = arith.addi %4, %5 : i64329 // CHECK-NEXT: return %{{.*}} : i64330 return %6 : i64331}332 333// -----334 335/// This test is checking that CSE is not removing duplicated read op that336/// have write op in between.337// CHECK-LABEL: @dont_remove_duplicated_read_op_with_sideeffecting338func.func @dont_remove_duplicated_read_op_with_sideeffecting() -> i32 {339 // CHECK-NEXT: %[[READ_VALUE0:.*]] = "test.op_with_memread"() : () -> i32340 %0 = "test.op_with_memread"() : () -> (i32)341 "test.op_with_memwrite"() : () -> ()342 // CHECK: %[[READ_VALUE1:.*]] = "test.op_with_memread"() : () -> i32343 %1 = "test.op_with_memread"() : () -> (i32)344 // CHECK-NEXT: %{{.*}} = arith.addi %[[READ_VALUE0]], %[[READ_VALUE1]] : i32345 %2 = arith.addi %0, %1 : i32346 return %2 : i32347}348 349// -----350 351// Check that an operation with a single region can CSE.352func.func @cse_single_block_ops(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)353 -> (tensor<?x?xf32>, tensor<?x?xf32>) {354 %0 = test.cse_of_single_block_op inputs(%a, %b) {355 ^bb0(%arg0 : f32):356 test.region_yield %arg0 : f32357 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>358 %1 = test.cse_of_single_block_op inputs(%a, %b) {359 ^bb0(%arg0 : f32):360 test.region_yield %arg0 : f32361 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>362 return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>363}364// CHECK-LABEL: func @cse_single_block_ops365// CHECK: %[[OP:.+]] = test.cse_of_single_block_op366// CHECK-NOT: test.cse_of_single_block_op367// CHECK: return %[[OP]], %[[OP]]368 369// -----370 371// Operations with different number of bbArgs dont CSE.372func.func @no_cse_varied_bbargs(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)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 test.region_yield %arg0 : f32377 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>378 %1 = test.cse_of_single_block_op inputs(%a, %b) {379 ^bb0(%arg0 : f32):380 test.region_yield %arg0 : f32381 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>382 return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>383}384// CHECK-LABEL: func @no_cse_varied_bbargs385// CHECK: %[[OP0:.+]] = test.cse_of_single_block_op386// CHECK: %[[OP1:.+]] = test.cse_of_single_block_op387// CHECK: return %[[OP0]], %[[OP1]]388 389// -----390 391// Operations with different regions dont CSE392func.func @no_cse_region_difference_simple(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>)393 -> (tensor<?x?xf32>, tensor<?x?xf32>) {394 %0 = test.cse_of_single_block_op inputs(%a, %b) {395 ^bb0(%arg0 : f32, %arg1 : f32):396 test.region_yield %arg0 : f32397 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>398 %1 = test.cse_of_single_block_op inputs(%a, %b) {399 ^bb0(%arg0 : f32, %arg1 : f32):400 test.region_yield %arg1 : f32401 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>402 return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>403}404// CHECK-LABEL: func @no_cse_region_difference_simple405// CHECK: %[[OP0:.+]] = test.cse_of_single_block_op406// CHECK: %[[OP1:.+]] = test.cse_of_single_block_op407// CHECK: return %[[OP0]], %[[OP1]]408 409// -----410 411// Operation with identical region with multiple statements CSE.412func.func @cse_single_block_ops_identical_bodies(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>, %c : f32, %d : i1)413 -> (tensor<?x?xf32>, tensor<?x?xf32>) {414 %0 = test.cse_of_single_block_op inputs(%a, %b) {415 ^bb0(%arg0 : f32, %arg1 : f32):416 %1 = arith.divf %arg0, %arg1 : f32417 %2 = arith.remf %arg0, %c : f32418 %3 = arith.select %d, %1, %2 : f32419 test.region_yield %3 : f32420 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>421 %1 = test.cse_of_single_block_op inputs(%a, %b) {422 ^bb0(%arg0 : f32, %arg1 : f32):423 %1 = arith.divf %arg0, %arg1 : f32424 %2 = arith.remf %arg0, %c : f32425 %3 = arith.select %d, %1, %2 : f32426 test.region_yield %3 : f32427 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>428 return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>429}430// CHECK-LABEL: func @cse_single_block_ops_identical_bodies431// CHECK: %[[OP:.+]] = test.cse_of_single_block_op432// CHECK-NOT: test.cse_of_single_block_op433// CHECK: return %[[OP]], %[[OP]]434 435// -----436 437// Operation with non-identical regions dont CSE.438func.func @no_cse_single_block_ops_different_bodies(%a : tensor<?x?xf32>, %b : tensor<?x?xf32>, %c : f32, %d : i1)439 -> (tensor<?x?xf32>, tensor<?x?xf32>) {440 %0 = test.cse_of_single_block_op inputs(%a, %b) {441 ^bb0(%arg0 : f32, %arg1 : f32):442 %1 = arith.divf %arg0, %arg1 : f32443 %2 = arith.remf %arg0, %c : f32444 %3 = arith.select %d, %1, %2 : f32445 test.region_yield %3 : f32446 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>447 %1 = test.cse_of_single_block_op inputs(%a, %b) {448 ^bb0(%arg0 : f32, %arg1 : f32):449 %1 = arith.divf %arg0, %arg1 : f32450 %2 = arith.remf %arg0, %c : f32451 %3 = arith.select %d, %2, %1 : f32452 test.region_yield %3 : f32453 } : tensor<?x?xf32>, tensor<?x?xf32> -> tensor<?x?xf32>454 return %0, %1 : tensor<?x?xf32>, tensor<?x?xf32>455}456// CHECK-LABEL: func @no_cse_single_block_ops_different_bodies457// CHECK: %[[OP0:.+]] = test.cse_of_single_block_op458// CHECK: %[[OP1:.+]] = test.cse_of_single_block_op459// CHECK: return %[[OP0]], %[[OP1]]460 461// -----462 463func.func @failing_issue_59135(%arg0: tensor<2x2xi1>, %arg1: f32, %arg2 : tensor<2xi1>) -> (tensor<2xi1>, tensor<2xi1>) {464 %false_2 = arith.constant false465 %true_5 = arith.constant true466 %9 = test.cse_of_single_block_op inputs(%arg2) {467 ^bb0(%out: i1):468 %true_144 = arith.constant true469 test.region_yield %true_144 : i1470 } : tensor<2xi1> -> tensor<2xi1>471 %15 = test.cse_of_single_block_op inputs(%arg2) {472 ^bb0(%out: i1):473 %true_144 = arith.constant true474 test.region_yield %true_144 : i1475 } : tensor<2xi1> -> tensor<2xi1>476 %93 = arith.maxsi %false_2, %true_5 : i1477 return %9, %15 : tensor<2xi1>, tensor<2xi1>478}479// CHECK-LABEL: func @failing_issue_59135480// CHECK: %[[TRUE:.+]] = arith.constant true481// CHECK: %[[OP:.+]] = test.cse_of_single_block_op482// CHECK: test.region_yield %[[TRUE]]483// CHECK: return %[[OP]], %[[OP]]484 485// -----486 487func.func @cse_multiple_regions(%c: i1, %t: tensor<5xf32>) -> (tensor<5xf32>, tensor<5xf32>) {488 %r1 = scf.if %c -> (tensor<5xf32>) {489 %0 = tensor.empty() : tensor<5xf32>490 scf.yield %0 : tensor<5xf32>491 } else {492 scf.yield %t : tensor<5xf32>493 }494 %r2 = scf.if %c -> (tensor<5xf32>) {495 %0 = tensor.empty() : tensor<5xf32>496 scf.yield %0 : tensor<5xf32>497 } else {498 scf.yield %t : tensor<5xf32>499 }500 return %r1, %r2 : tensor<5xf32>, tensor<5xf32>501}502// CHECK-LABEL: func @cse_multiple_regions503// CHECK: %[[if:.*]] = scf.if {{.*}} {504// CHECK: tensor.empty505// CHECK: scf.yield506// CHECK: } else {507// CHECK: scf.yield508// CHECK: }509// CHECK-NOT: scf.if510// CHECK: return %[[if]], %[[if]]511 512// -----513 514// CHECK-LABEL: @cse_recursive_effects_success515func.func @cse_recursive_effects_success() -> (i32, i32, i32) {516 // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32517 %0 = "test.op_with_memread"() : () -> (i32)518 519 // do something with recursive effects, containing no side effects520 %true = arith.constant true521 // CHECK-NEXT: %[[TRUE:.+]] = arith.constant true522 // CHECK-NEXT: %[[IF:.+]] = scf.if %[[TRUE]] -> (i32) {523 %1 = scf.if %true -> (i32) {524 %c42 = arith.constant 42 : i32525 scf.yield %c42 : i32526 // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32527 // CHECK-NEXT: scf.yield %[[C42]]528 // CHECK-NEXT: } else {529 } else {530 %c24 = arith.constant 24 : i32531 scf.yield %c24 : i32532 // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32533 // CHECK-NEXT: scf.yield %[[C24]]534 // CHECK-NEXT: }535 }536 537 // %2 can be removed538 // CHECK-NEXT: return %[[READ_VALUE]], %[[READ_VALUE]], %[[IF]] : i32, i32, i32539 %2 = "test.op_with_memread"() : () -> (i32)540 return %0, %2, %1 : i32, i32, i32541}542 543// -----544 545// CHECK-LABEL: @cse_recursive_effects_failure546func.func @cse_recursive_effects_failure() -> (i32, i32, i32) {547 // CHECK-NEXT: %[[READ_VALUE:.*]] = "test.op_with_memread"() : () -> i32548 %0 = "test.op_with_memread"() : () -> (i32)549 550 // do something with recursive effects, containing a write effect551 %true = arith.constant true552 // CHECK-NEXT: %[[TRUE:.+]] = arith.constant true553 // CHECK-NEXT: %[[IF:.+]] = scf.if %[[TRUE]] -> (i32) {554 %1 = scf.if %true -> (i32) {555 "test.op_with_memwrite"() : () -> ()556 // CHECK-NEXT: "test.op_with_memwrite"() : () -> ()557 %c42 = arith.constant 42 : i32558 scf.yield %c42 : i32559 // CHECK-NEXT: %[[C42:.+]] = arith.constant 42 : i32560 // CHECK-NEXT: scf.yield %[[C42]]561 // CHECK-NEXT: } else {562 } else {563 %c24 = arith.constant 24 : i32564 scf.yield %c24 : i32565 // CHECK-NEXT: %[[C24:.+]] = arith.constant 24 : i32566 // CHECK-NEXT: scf.yield %[[C24]]567 // CHECK-NEXT: }568 }569 570 // %2 can not be be removed because of the write571 // CHECK-NEXT: %[[READ_VALUE2:.*]] = "test.op_with_memread"() : () -> i32572 // CHECK-NEXT: return %[[READ_VALUE]], %[[READ_VALUE2]], %[[IF]] : i32, i32, i32573 %2 = "test.op_with_memread"() : () -> (i32)574 return %0, %2, %1 : i32, i32, i32575}576