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