1// RUN: mlir-opt %s -pass-pipeline='func.func(canonicalize)' -split-input-file | FileCheck %s 2 3 4// ----- 5 6func.func @single_iteration_some(%A: memref<?x?x?xi32>) { 7 %c0 = arith.constant 0 : index 8 %c1 = arith.constant 1 : index 9 %c2 = arith.constant 2 : index 10 %c3 = arith.constant 3 : index 11 %c6 = arith.constant 6 : index 12 %c7 = arith.constant 7 : index 13 %c10 = arith.constant 10 : index 14 scf.parallel (%i0, %i1, %i2) = (%c0, %c3, %c7) to (%c1, %c6, %c10) step (%c1, %c2, %c3) { 15 %c42 = arith.constant 42 : i32 16 memref.store %c42, %A[%i0, %i1, %i2] : memref<?x?x?xi32> 17 scf.yield 18 } 19 return 20} 21 22// CHECK-LABEL: func @single_iteration_some( 23// CHECK-SAME: [[ARG0:%.*]]: memref<?x?x?xi32>) { 24// CHECK-DAG: [[C42:%.*]] = arith.constant 42 : i32 25// CHECK-DAG: [[C7:%.*]] = arith.constant 7 : index 26// CHECK-DAG: [[C6:%.*]] = arith.constant 6 : index 27// CHECK-DAG: [[C3:%.*]] = arith.constant 3 : index 28// CHECK-DAG: [[C2:%.*]] = arith.constant 2 : index 29// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 30// CHECK: scf.parallel ([[V0:%.*]]) = ([[C3]]) to ([[C6]]) step ([[C2]]) { 31// CHECK: memref.store [[C42]], [[ARG0]]{{\[}}[[C0]], [[V0]], [[C7]]] : memref<?x?x?xi32> 32// CHECK: scf.yield 33// CHECK: } 34// CHECK: return 35 36// ----- 37 38func.func @single_iteration_all(%A: memref<?x?x?xi32>) { 39 %c0 = arith.constant 0 : index 40 %c1 = arith.constant 1 : index 41 %c3 = arith.constant 3 : index 42 %c6 = arith.constant 6 : index 43 %c7 = arith.constant 7 : index 44 %c10 = arith.constant 10 : index 45 scf.parallel (%i0, %i1, %i2) = (%c0, %c3, %c7) to (%c1, %c6, %c10) step (%c1, %c3, %c3) { 46 %c42 = arith.constant 42 : i32 47 memref.store %c42, %A[%i0, %i1, %i2] : memref<?x?x?xi32> 48 scf.yield 49 } 50 return 51} 52 53// CHECK-LABEL: func @single_iteration_all( 54// CHECK-SAME: [[ARG0:%.*]]: memref<?x?x?xi32>) { 55// CHECK-DAG: [[C42:%.*]] = arith.constant 42 : i32 56// CHECK-DAG: [[C7:%.*]] = arith.constant 7 : index 57// CHECK-DAG: [[C3:%.*]] = arith.constant 3 : index 58// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 59// CHECK-NOT: scf.parallel 60// CHECK: memref.store [[C42]], [[ARG0]]{{\[}}[[C0]], [[C3]], [[C7]]] : memref<?x?x?xi32> 61// CHECK-NOT: scf.yield 62// CHECK: return 63 64// ----- 65 66func.func @single_iteration_reduce(%A: index, %B: index) -> (index, index) { 67 %c0 = arith.constant 0 : index 68 %c1 = arith.constant 1 : index 69 %c2 = arith.constant 2 : index 70 %c3 = arith.constant 3 : index 71 %c6 = arith.constant 6 : index 72 %0:2 = scf.parallel (%i0, %i1) = (%c1, %c3) to (%c2, %c6) step (%c1, %c3) init(%A, %B) -> (index, index) { 73 scf.reduce(%i0) : index { 74 ^bb0(%lhs: index, %rhs: index): 75 %1 = arith.addi %lhs, %rhs : index 76 scf.reduce.return %1 : index 77 } 78 scf.reduce(%i1) : index { 79 ^bb0(%lhs: index, %rhs: index): 80 %2 = arith.muli %lhs, %rhs : index 81 scf.reduce.return %2 : index 82 } 83 scf.yield 84 } 85 return %0#0, %0#1 : index, index 86} 87 88// CHECK-LABEL: func @single_iteration_reduce( 89// CHECK-SAME: [[ARG0:%.*]]: index, [[ARG1:%.*]]: index) 90// CHECK-DAG: [[C3:%.*]] = arith.constant 3 : index 91// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 92// CHECK-NOT: scf.parallel 93// CHECK-NOT: scf.reduce 94// CHECK-NOT: scf.reduce.return 95// CHECK-NOT: scf.yield 96// CHECK: [[V0:%.*]] = arith.addi [[ARG0]], [[C1]] 97// CHECK: [[V1:%.*]] = arith.muli [[ARG1]], [[C3]] 98// CHECK: return [[V0]], [[V1]] 99 100// ----- 101 102func.func @nested_parallel(%0: memref<?x?x?xf64>) -> memref<?x?x?xf64> { 103 %c0 = arith.constant 0 : index 104 %c1 = arith.constant 1 : index 105 %c2 = arith.constant 2 : index 106 %1 = memref.dim %0, %c0 : memref<?x?x?xf64> 107 %2 = memref.dim %0, %c1 : memref<?x?x?xf64> 108 %3 = memref.dim %0, %c2 : memref<?x?x?xf64> 109 %4 = memref.alloc(%1, %2, %3) : memref<?x?x?xf64> 110 scf.parallel (%arg1) = (%c0) to (%1) step (%c1) { 111 scf.parallel (%arg2) = (%c0) to (%2) step (%c1) { 112 scf.parallel (%arg3) = (%c0) to (%3) step (%c1) { 113 %5 = memref.load %0[%arg1, %arg2, %arg3] : memref<?x?x?xf64> 114 memref.store %5, %4[%arg1, %arg2, %arg3] : memref<?x?x?xf64> 115 scf.yield 116 } 117 scf.yield 118 } 119 scf.yield 120 } 121 return %4 : memref<?x?x?xf64> 122} 123 124// CHECK-LABEL: func @nested_parallel( 125// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 126// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 127// CHECK-DAG: [[C2:%.*]] = arith.constant 2 : index 128// CHECK: [[B0:%.*]] = memref.dim {{.*}}, [[C0]] 129// CHECK: [[B1:%.*]] = memref.dim {{.*}}, [[C1]] 130// CHECK: [[B2:%.*]] = memref.dim {{.*}}, [[C2]] 131// CHECK: scf.parallel ([[V0:%.*]], [[V1:%.*]], [[V2:%.*]]) = ([[C0]], [[C0]], [[C0]]) to ([[B0]], [[B1]], [[B2]]) step ([[C1]], [[C1]], [[C1]]) 132// CHECK: memref.load {{.*}}{{\[}}[[V0]], [[V1]], [[V2]]] 133// CHECK: memref.store {{.*}}{{\[}}[[V0]], [[V1]], [[V2]]] 134 135// ----- 136 137func.func private @side_effect() 138func.func @one_unused(%cond: i1) -> (index) { 139 %0, %1 = scf.if %cond -> (index, index) { 140 func.call @side_effect() : () -> () 141 %c0 = "test.value0"() : () -> (index) 142 %c1 = "test.value1"() : () -> (index) 143 scf.yield %c0, %c1 : index, index 144 } else { 145 %c2 = "test.value2"() : () -> (index) 146 %c3 = "test.value3"() : () -> (index) 147 scf.yield %c2, %c3 : index, index 148 } 149 return %1 : index 150} 151 152// CHECK-LABEL: func @one_unused 153// CHECK: [[V0:%.*]] = scf.if %{{.*}} -> (index) { 154// CHECK: call @side_effect() : () -> () 155// CHECK: [[C1:%.*]] = "test.value1" 156// CHECK: scf.yield [[C1]] : index 157// CHECK: } else 158// CHECK: [[C3:%.*]] = "test.value3" 159// CHECK: scf.yield [[C3]] : index 160// CHECK: } 161// CHECK: return [[V0]] : index 162 163// ----- 164 165func.func private @side_effect() 166func.func @nested_unused(%cond1: i1, %cond2: i1) -> (index) { 167 %0, %1 = scf.if %cond1 -> (index, index) { 168 %2, %3 = scf.if %cond2 -> (index, index) { 169 func.call @side_effect() : () -> () 170 %c0 = "test.value0"() : () -> (index) 171 %c1 = "test.value1"() : () -> (index) 172 scf.yield %c0, %c1 : index, index 173 } else { 174 %c2 = "test.value2"() : () -> (index) 175 %c3 = "test.value3"() : () -> (index) 176 scf.yield %c2, %c3 : index, index 177 } 178 scf.yield %2, %3 : index, index 179 } else { 180 %c0 = "test.value0_2"() : () -> (index) 181 %c1 = "test.value1_2"() : () -> (index) 182 scf.yield %c0, %c1 : index, index 183 } 184 return %1 : index 185} 186 187// CHECK-LABEL: func @nested_unused 188// CHECK: [[V0:%.*]] = scf.if {{.*}} -> (index) { 189// CHECK: [[V1:%.*]] = scf.if {{.*}} -> (index) { 190// CHECK: call @side_effect() : () -> () 191// CHECK: [[C1:%.*]] = "test.value1" 192// CHECK: scf.yield [[C1]] : index 193// CHECK: } else 194// CHECK: [[C3:%.*]] = "test.value3" 195// CHECK: scf.yield [[C3]] : index 196// CHECK: } 197// CHECK: scf.yield [[V1]] : index 198// CHECK: } else 199// CHECK: [[C1_2:%.*]] = "test.value1_2" 200// CHECK: scf.yield [[C1_2]] : index 201// CHECK: } 202// CHECK: return [[V0]] : index 203 204// ----- 205 206func.func private @side_effect() 207func.func @all_unused(%cond: i1) { 208 %c0 = arith.constant 0 : index 209 %c1 = arith.constant 1 : index 210 %0, %1 = scf.if %cond -> (index, index) { 211 func.call @side_effect() : () -> () 212 scf.yield %c0, %c1 : index, index 213 } else { 214 func.call @side_effect() : () -> () 215 scf.yield %c0, %c1 : index, index 216 } 217 return 218} 219 220// CHECK-LABEL: func @all_unused 221// CHECK: scf.if %{{.*}} { 222// CHECK: call @side_effect() : () -> () 223// CHECK: } else 224// CHECK: call @side_effect() : () -> () 225// CHECK: } 226// CHECK: return 227 228// ----- 229 230func.func @empty_if1(%cond: i1) { 231 scf.if %cond { 232 scf.yield 233 } 234 return 235} 236 237// CHECK-LABEL: func @empty_if1 238// CHECK-NOT: scf.if 239// CHECK: return 240 241// ----- 242 243func.func @empty_if2(%cond: i1) { 244 scf.if %cond { 245 scf.yield 246 } else { 247 scf.yield 248 } 249 return 250} 251 252// CHECK-LABEL: func @empty_if2 253// CHECK-NOT: scf.if 254// CHECK: return 255 256// ----- 257 258func.func @empty_else(%cond: i1, %v : memref<i1>) { 259 scf.if %cond { 260 memref.store %cond, %v[] : memref<i1> 261 } else { 262 } 263 return 264} 265 266// CHECK-LABEL: func @empty_else 267// CHECK: scf.if 268// CHECK-NOT: else 269 270// ----- 271 272func.func @to_select1(%cond: i1) -> index { 273 %c0 = arith.constant 0 : index 274 %c1 = arith.constant 1 : index 275 %0 = scf.if %cond -> index { 276 scf.yield %c0 : index 277 } else { 278 scf.yield %c1 : index 279 } 280 return %0 : index 281} 282 283// CHECK-LABEL: func @to_select1 284// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 285// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 286// CHECK: [[V0:%.*]] = arith.select {{.*}}, [[C0]], [[C1]] 287// CHECK: return [[V0]] : index 288 289// ----- 290 291func.func @to_select_same_val(%cond: i1) -> (index, index) { 292 %c0 = arith.constant 0 : index 293 %c1 = arith.constant 1 : index 294 %0, %1 = scf.if %cond -> (index, index) { 295 scf.yield %c0, %c1 : index, index 296 } else { 297 scf.yield %c1, %c1 : index, index 298 } 299 return %0, %1 : index, index 300} 301 302// CHECK-LABEL: func @to_select_same_val 303// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 304// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 305// CHECK: [[V0:%.*]] = arith.select {{.*}}, [[C0]], [[C1]] 306// CHECK: return [[V0]], [[C1]] : index, index 307 308 309func.func @to_select_with_body(%cond: i1) -> index { 310 %c0 = arith.constant 0 : index 311 %c1 = arith.constant 1 : index 312 %0 = scf.if %cond -> index { 313 "test.op"() : () -> () 314 scf.yield %c0 : index 315 } else { 316 scf.yield %c1 : index 317 } 318 return %0 : index 319} 320 321// CHECK-LABEL: func @to_select_with_body 322// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 323// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 324// CHECK: [[V0:%.*]] = arith.select {{.*}}, [[C0]], [[C1]] 325// CHECK: scf.if {{.*}} { 326// CHECK: "test.op"() : () -> () 327// CHECK: } 328// CHECK: return [[V0]] : index 329// ----- 330 331func.func @to_select2(%cond: i1) -> (index, index) { 332 %c0 = arith.constant 0 : index 333 %c1 = arith.constant 1 : index 334 %c2 = arith.constant 2 : index 335 %c3 = arith.constant 3 : index 336 %0, %1 = scf.if %cond -> (index, index) { 337 scf.yield %c0, %c1 : index, index 338 } else { 339 scf.yield %c2, %c3 : index, index 340 } 341 return %0, %1 : index, index 342} 343 344// CHECK-LABEL: func @to_select2 345// CHECK-DAG: [[C0:%.*]] = arith.constant 0 : index 346// CHECK-DAG: [[C1:%.*]] = arith.constant 1 : index 347// CHECK-DAG: [[C2:%.*]] = arith.constant 2 : index 348// CHECK-DAG: [[C3:%.*]] = arith.constant 3 : index 349// CHECK: [[V0:%.*]] = arith.select {{.*}}, [[C0]], [[C2]] 350// CHECK: [[V1:%.*]] = arith.select {{.*}}, [[C1]], [[C3]] 351// CHECK: return [[V0]], [[V1]] : index 352 353// ----- 354 355func.func private @make_i32() -> i32 356 357func.func @for_yields_2(%lb : index, %ub : index, %step : index) -> i32 { 358 %a = call @make_i32() : () -> (i32) 359 %b = scf.for %i = %lb to %ub step %step iter_args(%0 = %a) -> i32 { 360 scf.yield %0 : i32 361 } 362 return %b : i32 363} 364 365// CHECK-LABEL: func @for_yields_2 366// CHECK-NEXT: %[[R:.*]] = call @make_i32() : () -> i32 367// CHECK-NEXT: return %[[R]] : i32 368 369func.func @for_yields_3(%lb : index, %ub : index, %step : index) -> (i32, i32, i32) { 370 %a = call @make_i32() : () -> (i32) 371 %b = call @make_i32() : () -> (i32) 372 %r:3 = scf.for %i = %lb to %ub step %step iter_args(%0 = %a, %1 = %a, %2 = %b) -> (i32, i32, i32) { 373 %c = func.call @make_i32() : () -> (i32) 374 scf.yield %0, %c, %2 : i32, i32, i32 375 } 376 return %r#0, %r#1, %r#2 : i32, i32, i32 377} 378 379// CHECK-LABEL: func @for_yields_3 380// CHECK-NEXT: %[[a:.*]] = call @make_i32() : () -> i32 381// CHECK-NEXT: %[[b:.*]] = call @make_i32() : () -> i32 382// CHECK-NEXT: %[[r1:.*]] = scf.for {{.*}} iter_args(%arg4 = %[[a]]) -> (i32) { 383// CHECK-NEXT: %[[c:.*]] = func.call @make_i32() : () -> i32 384// CHECK-NEXT: scf.yield %[[c]] : i32 385// CHECK-NEXT: } 386// CHECK-NEXT: return %[[a]], %[[r1]], %[[b]] : i32, i32, i32 387 388// ----- 389 390// Test that an empty loop which iterates at least once and only returns 391// values defined outside of the loop is folded away. 392func.func @for_yields_4() -> i32 { 393 %c0 = arith.constant 0 : index 394 %c1 = arith.constant 1 : index 395 %c2 = arith.constant 2 : index 396 %a = arith.constant 3 : i32 397 %b = arith.constant 4 : i32 398 %r = scf.for %i = %c0 to %c2 step %c1 iter_args(%0 = %a) -> i32 { 399 scf.yield %b : i32 400 } 401 return %r : i32 402} 403 404// CHECK-LABEL: func @for_yields_4 405// CHECK-NEXT: %[[b:.*]] = arith.constant 4 : i32 406// CHECK-NEXT: return %[[b]] : i32 407 408// ----- 409 410// CHECK-LABEL: @replace_true_if 411func.func @replace_true_if() { 412 %true = arith.constant true 413 // CHECK-NOT: scf.if 414 // CHECK: "test.op" 415 scf.if %true { 416 "test.op"() : () -> () 417 scf.yield 418 } 419 return 420} 421 422// ----- 423 424// CHECK-LABEL: @remove_false_if 425func.func @remove_false_if() { 426 %false = arith.constant false 427 // CHECK-NOT: scf.if 428 // CHECK-NOT: "test.op" 429 scf.if %false { 430 "test.op"() : () -> () 431 scf.yield 432 } 433 return 434} 435 436// ----- 437 438// CHECK-LABEL: @replace_true_if_with_values 439func.func @replace_true_if_with_values() { 440 %true = arith.constant true 441 // CHECK-NOT: scf.if 442 // CHECK: %[[VAL:.*]] = "test.op" 443 %0 = scf.if %true -> (i32) { 444 %1 = "test.op"() : () -> i32 445 scf.yield %1 : i32 446 } else { 447 %2 = "test.other_op"() : () -> i32 448 scf.yield %2 : i32 449 } 450 // CHECK: "test.consume"(%[[VAL]]) 451 "test.consume"(%0) : (i32) -> () 452 return 453} 454 455// ----- 456 457// CHECK-LABEL: @replace_false_if_with_values 458func.func @replace_false_if_with_values() { 459 %false = arith.constant false 460 // CHECK-NOT: scf.if 461 // CHECK: %[[VAL:.*]] = "test.other_op" 462 %0 = scf.if %false -> (i32) { 463 %1 = "test.op"() : () -> i32 464 scf.yield %1 : i32 465 } else { 466 %2 = "test.other_op"() : () -> i32 467 scf.yield %2 : i32 468 } 469 // CHECK: "test.consume"(%[[VAL]]) 470 "test.consume"(%0) : (i32) -> () 471 return 472} 473 474// ----- 475 476// CHECK-LABEL: @merge_nested_if 477// CHECK-SAME: (%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1) 478func.func @merge_nested_if(%arg0: i1, %arg1: i1) { 479// CHECK: %[[COND:.*]] = arith.andi %[[ARG0]], %[[ARG1]] 480// CHECK: scf.if %[[COND]] { 481// CHECK-NEXT: "test.op"() 482 scf.if %arg0 { 483 scf.if %arg1 { 484 "test.op"() : () -> () 485 scf.yield 486 } 487 scf.yield 488 } 489 return 490} 491 492// ----- 493 494// CHECK-LABEL: @merge_yielding_nested_if 495// CHECK-SAME: (%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1) 496func.func @merge_yielding_nested_if(%arg0: i1, %arg1: i1) -> (i32, f32, i32, i8) { 497// CHECK: %[[PRE0:.*]] = "test.op"() : () -> i32 498// CHECK: %[[PRE1:.*]] = "test.op1"() : () -> f32 499// CHECK: %[[PRE2:.*]] = "test.op2"() : () -> i32 500// CHECK: %[[PRE3:.*]] = "test.op3"() : () -> i8 501// CHECK: %[[COND:.*]] = arith.andi %[[ARG0]], %[[ARG1]] 502// CHECK: %[[RES:.*]]:2 = scf.if %[[COND]] -> (f32, i32) 503// CHECK: %[[IN0:.*]] = "test.inop"() : () -> i32 504// CHECK: %[[IN1:.*]] = "test.inop1"() : () -> f32 505// CHECK: scf.yield %[[IN1]], %[[IN0]] : f32, i32 506// CHECK: } else { 507// CHECK: scf.yield %[[PRE1]], %[[PRE2]] : f32, i32 508// CHECK: } 509// CHECK: return %[[PRE0]], %[[RES]]#0, %[[RES]]#1, %[[PRE3]] : i32, f32, i32, i8 510 %0 = "test.op"() : () -> (i32) 511 %1 = "test.op1"() : () -> (f32) 512 %2 = "test.op2"() : () -> (i32) 513 %3 = "test.op3"() : () -> (i8) 514 %r:4 = scf.if %arg0 -> (i32, f32, i32, i8) { 515 %a:2 = scf.if %arg1 -> (i32, f32) { 516 %i = "test.inop"() : () -> (i32) 517 %i1 = "test.inop1"() : () -> (f32) 518 scf.yield %i, %i1 : i32, f32 519 } else { 520 scf.yield %2, %1 : i32, f32 521 } 522 scf.yield %0, %a#1, %a#0, %3 : i32, f32, i32, i8 523 } else { 524 scf.yield %0, %1, %2, %3 : i32, f32, i32, i8 525 } 526 return %r#0, %r#1, %r#2, %r#3 : i32, f32, i32, i8 527} 528 529// CHECK-LABEL: @merge_yielding_nested_if_nv1 530// CHECK-SAME: (%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1) 531func.func @merge_yielding_nested_if_nv1(%arg0: i1, %arg1: i1) { 532// CHECK: %[[PRE0:.*]] = "test.op"() : () -> i32 533// CHECK: %[[PRE1:.*]] = "test.op1"() : () -> f32 534// CHECK: %[[COND:.*]] = arith.andi %[[ARG0]], %[[ARG1]] 535// CHECK: scf.if %[[COND]] 536// CHECK: %[[IN0:.*]] = "test.inop"() : () -> i32 537// CHECK: %[[IN1:.*]] = "test.inop1"() : () -> f32 538// CHECK: } 539 %0 = "test.op"() : () -> (i32) 540 %1 = "test.op1"() : () -> (f32) 541 scf.if %arg0 { 542 %a:2 = scf.if %arg1 -> (i32, f32) { 543 %i = "test.inop"() : () -> (i32) 544 %i1 = "test.inop1"() : () -> (f32) 545 scf.yield %i, %i1 : i32, f32 546 } else { 547 scf.yield %0, %1 : i32, f32 548 } 549 } 550 return 551} 552 553// CHECK-LABEL: @merge_yielding_nested_if_nv2 554// CHECK-SAME: (%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1) 555func.func @merge_yielding_nested_if_nv2(%arg0: i1, %arg1: i1) -> i32 { 556// CHECK: %[[PRE0:.*]] = "test.op"() : () -> i32 557// CHECK: %[[PRE1:.*]] = "test.op1"() : () -> i32 558// CHECK: %[[COND:.*]] = arith.andi %[[ARG0]], %[[ARG1]] 559// CHECK: %[[RES:.*]] = arith.select %[[ARG0]], %[[PRE0]], %[[PRE1]] 560// CHECK: scf.if %[[COND]] 561// CHECK: "test.run"() : () -> () 562// CHECK: } 563// CHECK: return %[[RES]] 564 %0 = "test.op"() : () -> (i32) 565 %1 = "test.op1"() : () -> (i32) 566 %r = scf.if %arg0 -> i32 { 567 scf.if %arg1 { 568 "test.run"() : () -> () 569 } 570 scf.yield %0 : i32 571 } else { 572 scf.yield %1 : i32 573 } 574 return %r : i32 575} 576 577// CHECK-LABEL: @merge_fail_yielding_nested_if 578// CHECK-SAME: (%[[ARG0:.*]]: i1, %[[ARG1:.*]]: i1) 579func.func @merge_fail_yielding_nested_if(%arg0: i1, %arg1: i1) -> (i32, f32, i32, i8) { 580// CHECK-NOT: andi 581 %0 = "test.op"() : () -> (i32) 582 %1 = "test.op1"() : () -> (f32) 583 %2 = "test.op2"() : () -> (i32) 584 %3 = "test.op3"() : () -> (i8) 585 %r:4 = scf.if %arg0 -> (i32, f32, i32, i8) { 586 %a:2 = scf.if %arg1 -> (i32, f32) { 587 %i = "test.inop"() : () -> (i32) 588 %i1 = "test.inop1"() : () -> (f32) 589 scf.yield %i, %i1 : i32, f32 590 } else { 591 scf.yield %0, %1 : i32, f32 592 } 593 scf.yield %0, %a#1, %a#0, %3 : i32, f32, i32, i8 594 } else { 595 scf.yield %0, %1, %2, %3 : i32, f32, i32, i8 596 } 597 return %r#0, %r#1, %r#2, %r#3 : i32, f32, i32, i8 598} 599 600// ----- 601 602// CHECK-LABEL: func @if_condition_swap 603// CHECK-NEXT: %{{.*}} = scf.if %arg0 -> (index) { 604// CHECK-NEXT: %[[i1:.+]] = "test.origFalse"() : () -> index 605// CHECK-NEXT: scf.yield %[[i1]] : index 606// CHECK-NEXT: } else { 607// CHECK-NEXT: %[[i2:.+]] = "test.origTrue"() : () -> index 608// CHECK-NEXT: scf.yield %[[i2]] : index 609// CHECK-NEXT: } 610func.func @if_condition_swap(%cond: i1) -> index { 611 %true = arith.constant true 612 %not = arith.xori %cond, %true : i1 613 %0 = scf.if %not -> (index) { 614 %1 = "test.origTrue"() : () -> index 615 scf.yield %1 : index 616 } else { 617 %1 = "test.origFalse"() : () -> index 618 scf.yield %1 : index 619 } 620 return %0 : index 621} 622 623// ----- 624 625// CHECK-LABEL: @remove_zero_iteration_loop 626func.func @remove_zero_iteration_loop() { 627 %c42 = arith.constant 42 : index 628 %c1 = arith.constant 1 : index 629 // CHECK: %[[INIT:.*]] = "test.init" 630 %init = "test.init"() : () -> i32 631 // CHECK-NOT: scf.for 632 %0 = scf.for %i = %c42 to %c1 step %c1 iter_args(%arg = %init) -> (i32) { 633 %1 = "test.op"(%i, %arg) : (index, i32) -> i32 634 scf.yield %1 : i32 635 } 636 // CHECK: "test.consume"(%[[INIT]]) 637 "test.consume"(%0) : (i32) -> () 638 return 639} 640 641// ----- 642 643// CHECK-LABEL: @remove_zero_iteration_loop_vals 644func.func @remove_zero_iteration_loop_vals(%arg0: index) { 645 %c2 = arith.constant 2 : index 646 // CHECK: %[[INIT:.*]] = "test.init" 647 %init = "test.init"() : () -> i32 648 // CHECK-NOT: scf.for 649 // CHECK-NOT: test.op 650 %0 = scf.for %i = %arg0 to %arg0 step %c2 iter_args(%arg = %init) -> (i32) { 651 %1 = "test.op"(%i, %arg) : (index, i32) -> i32 652 scf.yield %1 : i32 653 } 654 // CHECK: "test.consume"(%[[INIT]]) 655 "test.consume"(%0) : (i32) -> () 656 return 657} 658 659// ----- 660 661// CHECK-LABEL: @replace_single_iteration_loop_1 662func.func @replace_single_iteration_loop_1() { 663 // CHECK: %[[LB:.*]] = arith.constant 42 664 %c42 = arith.constant 42 : index 665 %c43 = arith.constant 43 : index 666 %c1 = arith.constant 1 : index 667 // CHECK: %[[INIT:.*]] = "test.init" 668 %init = "test.init"() : () -> i32 669 // CHECK-NOT: scf.for 670 // CHECK: %[[VAL:.*]] = "test.op"(%[[LB]], %[[INIT]]) 671 %0 = scf.for %i = %c42 to %c43 step %c1 iter_args(%arg = %init) -> (i32) { 672 %1 = "test.op"(%i, %arg) : (index, i32) -> i32 673 scf.yield %1 : i32 674 } 675 // CHECK: "test.consume"(%[[VAL]]) 676 "test.consume"(%0) : (i32) -> () 677 return 678} 679 680// ----- 681 682// CHECK-LABEL: @replace_single_iteration_loop_2 683func.func @replace_single_iteration_loop_2() { 684 // CHECK: %[[LB:.*]] = arith.constant 5 685 %c5 = arith.constant 5 : index 686 %c6 = arith.constant 6 : index 687 %c11 = arith.constant 11 : index 688 // CHECK: %[[INIT:.*]] = "test.init" 689 %init = "test.init"() : () -> i32 690 // CHECK-NOT: scf.for 691 // CHECK: %[[VAL:.*]] = "test.op"(%[[LB]], %[[INIT]]) 692 %0 = scf.for %i = %c5 to %c11 step %c6 iter_args(%arg = %init) -> (i32) { 693 %1 = "test.op"(%i, %arg) : (index, i32) -> i32 694 scf.yield %1 : i32 695 } 696 // CHECK: "test.consume"(%[[VAL]]) 697 "test.consume"(%0) : (i32) -> () 698 return 699} 700 701// ----- 702 703// CHECK-LABEL: @replace_single_iteration_loop_non_unit_step 704func.func @replace_single_iteration_loop_non_unit_step() { 705 // CHECK: %[[LB:.*]] = arith.constant 42 706 %c42 = arith.constant 42 : index 707 %c47 = arith.constant 47 : index 708 %c5 = arith.constant 5 : index 709 // CHECK: %[[INIT:.*]] = "test.init" 710 %init = "test.init"() : () -> i32 711 // CHECK-NOT: scf.for 712 // CHECK: %[[VAL:.*]] = "test.op"(%[[LB]], %[[INIT]]) 713 %0 = scf.for %i = %c42 to %c47 step %c5 iter_args(%arg = %init) -> (i32) { 714 %1 = "test.op"(%i, %arg) : (index, i32) -> i32 715 scf.yield %1 : i32 716 } 717 // CHECK: "test.consume"(%[[VAL]]) 718 "test.consume"(%0) : (i32) -> () 719 return 720} 721 722// ----- 723 724// CHECK-LABEL: @remove_empty_parallel_loop 725func.func @remove_empty_parallel_loop(%lb: index, %ub: index, %s: index) { 726 // CHECK: %[[INIT:.*]] = "test.init" 727 %init = "test.init"() : () -> f32 728 // CHECK-NOT: scf.parallel 729 // CHECK-NOT: test.produce 730 // CHECK-NOT: test.transform 731 %0 = scf.parallel (%i, %j, %k) = (%lb, %ub, %lb) to (%ub, %ub, %ub) step (%s, %s, %s) init(%init) -> f32 { 732 %1 = "test.produce"() : () -> f32 733 scf.reduce(%1) : f32 { 734 ^bb0(%lhs: f32, %rhs: f32): 735 %2 = "test.transform"(%lhs, %rhs) : (f32, f32) -> f32 736 scf.reduce.return %2 : f32 737 } 738 scf.yield 739 } 740 // CHECK: "test.consume"(%[[INIT]]) 741 "test.consume"(%0) : (f32) -> () 742 return 743} 744 745// ----- 746 747func.func private @process(%0 : memref<128x128xf32>) 748func.func private @process_tensor(%0 : tensor<128x128xf32>) -> memref<128x128xf32> 749 750// CHECK-LABEL: last_value 751// CHECK-SAME: %[[T0:[0-9a-z]*]]: tensor<128x128xf32> 752// CHECK-SAME: %[[T1:[0-9a-z]*]]: tensor<128x128xf32> 753// CHECK-SAME: %[[T2:[0-9a-z]*]]: tensor<128x128xf32> 754// CHECK-SAME: %[[M0:[0-9a-z]*]]: memref<128x128xf32> 755func.func @last_value(%t0: tensor<128x128xf32>, %t1: tensor<128x128xf32>, 756 %t2: tensor<128x128xf32>, %m0: memref<128x128xf32>, 757 %lb : index, %ub : index, %step : index) 758 -> (tensor<128x128xf32>, tensor<128x128xf32>, tensor<128x128xf32>) 759{ 760 // CHECK-NEXT: %[[M1:.*]] = bufferization.to_memref %[[T1]] : memref<128x128xf32> 761 // CHECK-NEXT: %[[FOR_RES:.*]] = scf.for {{.*}} iter_args(%[[BBARG_T2:.*]] = %[[T2]]) -> (tensor<128x128xf32>) { 762 %0:3 = scf.for %arg0 = %lb to %ub step %step iter_args(%arg1 = %t0, %arg2 = %t1, %arg3 = %t2) 763 -> (tensor<128x128xf32>, tensor<128x128xf32>, tensor<128x128xf32>) 764 { 765 %m1 = bufferization.to_memref %arg2 : memref<128x128xf32> 766 767 // CHECK-NEXT: call @process(%[[M0]]) : (memref<128x128xf32>) -> () 768 func.call @process(%m0) : (memref<128x128xf32>) -> () 769 770 // CHECK-NEXT: call @process(%[[M1]]) : (memref<128x128xf32>) -> () 771 func.call @process(%m1) : (memref<128x128xf32>) -> () 772 773 // This does not hoist (fails the bbArg has at most a single check). 774 // CHECK-NEXT: %[[T:.*]] = func.call @process_tensor(%[[BBARG_T2]]) : (tensor<128x128xf32>) -> memref<128x128xf32> 775 // CHECK-NEXT: %[[YIELD_T:.*]] = bufferization.to_tensor %[[T:.*]] 776 %m2 = func.call @process_tensor(%arg3): (tensor<128x128xf32>) -> memref<128x128xf32> 777 %3 = bufferization.to_tensor %m2 : memref<128x128xf32> 778 779 // All this stuff goes away, incrementally 780 %1 = bufferization.to_tensor %m0 : memref<128x128xf32> 781 %2 = bufferization.to_tensor %m1 : memref<128x128xf32> 782 783 // CHECK-NEXT: scf.yield %[[YIELD_T]] : tensor<128x128xf32> 784 scf.yield %1, %2, %3 : tensor<128x128xf32>, tensor<128x128xf32>, tensor<128x128xf32> 785 786 // CHECK-NEXT: } 787 } 788 789 // CHECK-NEXT: %[[R0:.*]] = bufferization.to_tensor %[[M0]] : memref<128x128xf32> 790 // CHECK-NEXT: %[[R1:.*]] = bufferization.to_tensor %[[M1]] : memref<128x128xf32> 791 // CHECK-NEXT: return %[[R0]], %[[R1]], %[[FOR_RES]] : tensor<128x128xf32>, tensor<128x128xf32>, tensor<128x128xf32> 792 return %0#0, %0#1, %0#2 : tensor<128x128xf32>, tensor<128x128xf32>, tensor<128x128xf32> 793} 794 795// ----- 796 797// CHECK-LABEL: fold_away_iter_with_no_use_and_yielded_input 798// CHECK-SAME: %[[A0:[0-9a-z]*]]: i32 799func.func @fold_away_iter_with_no_use_and_yielded_input(%arg0 : i32, 800 %ub : index, %lb : index, %step : index) -> (i32, i32) { 801 // CHECK-NEXT: %[[C32:.*]] = arith.constant 32 : i32 802 %cst = arith.constant 32 : i32 803 // CHECK-NEXT: %[[FOR_RES:.*]] = scf.for {{.*}} iter_args({{.*}} = %[[A0]]) -> (i32) { 804 %0:2 = scf.for %arg1 = %lb to %ub step %step iter_args(%arg2 = %arg0, %arg3 = %cst) 805 -> (i32, i32) { 806 %1 = arith.addi %arg2, %cst : i32 807 scf.yield %1, %cst : i32, i32 808 } 809 810 // CHECK: return %[[FOR_RES]], %[[C32]] : i32, i32 811 return %0#0, %0#1 : i32, i32 812} 813 814// ----- 815 816// CHECK-LABEL: fold_away_iter_and_result_with_no_use 817// CHECK-SAME: %[[A0:[0-9a-z]*]]: i32 818func.func @fold_away_iter_and_result_with_no_use(%arg0 : i32, 819 %ub : index, %lb : index, %step : index) -> (i32) { 820 %cst = arith.constant 32 : i32 821 // CHECK: %[[FOR_RES:.*]] = scf.for {{.*}} iter_args({{.*}} = %[[A0]]) -> (i32) { 822 %0:2 = scf.for %arg1 = %lb to %ub step %step iter_args(%arg2 = %arg0, %arg3 = %cst) 823 -> (i32, i32) { 824 %1 = arith.addi %arg2, %cst : i32 825 scf.yield %1, %1 : i32, i32 826 } 827 828 // CHECK: return %[[FOR_RES]] : i32 829 return %0#0 : i32 830} 831 832// ----- 833 834func.func private @do(%arg0: tensor<?x?xf32>) -> tensor<?x?xf32> 835 836// CHECK-LABEL: matmul_on_tensors 837// CHECK-SAME: %[[T0:[0-9a-z]*]]: tensor<32x1024xf32> 838// CHECK-SAME: %[[T1:[0-9a-z]*]]: tensor<1024x1024xf32> 839func.func @matmul_on_tensors(%t0: tensor<32x1024xf32>, %t1: tensor<1024x1024xf32>) -> tensor<1024x1024xf32> { 840 %c0 = arith.constant 0 : index 841 %c32 = arith.constant 32 : index 842 %c1024 = arith.constant 1024 : index 843// CHECK-NOT: tensor.cast 844// CHECK: %[[FOR_RES:.*]] = scf.for {{.*}} iter_args(%[[ITER_T0:.*]] = %[[T0]]) -> (tensor<32x1024xf32>) { 845// CHECK: %[[CAST:.*]] = tensor.cast %[[ITER_T0]] : tensor<32x1024xf32> to tensor<?x?xf32> 846// CHECK: %[[DONE:.*]] = func.call @do(%[[CAST]]) : (tensor<?x?xf32>) -> tensor<?x?xf32> 847// CHECK: %[[UNCAST:.*]] = tensor.cast %[[DONE]] : tensor<?x?xf32> to tensor<32x1024xf32> 848// CHECK: scf.yield %[[UNCAST]] : tensor<32x1024xf32> 849 %0 = tensor.cast %t0 : tensor<32x1024xf32> to tensor<?x?xf32> 850 %1 = scf.for %i = %c0 to %c1024 step %c32 iter_args(%iter_t0 = %0) -> (tensor<?x?xf32>) { 851 %2 = func.call @do(%iter_t0) : (tensor<?x?xf32>) -> tensor<?x?xf32> 852 scf.yield %2 : tensor<?x?xf32> 853 } 854// CHECK-NOT: tensor.cast 855// CHECK: %[[RES:.*]] = tensor.insert_slice %[[FOR_RES]] into %[[T1]][0, 0] [32, 1024] [1, 1] : tensor<32x1024xf32> into tensor<1024x1024xf32> 856// CHECK: return %[[RES]] : tensor<1024x1024xf32> 857 %2 = tensor.cast %1 : tensor<?x?xf32> to tensor<32x1024xf32> 858 %res = tensor.insert_slice %2 into %t1[0, 0] [32, 1024] [1, 1] : tensor<32x1024xf32> into tensor<1024x1024xf32> 859 return %res : tensor<1024x1024xf32> 860} 861 862// ----- 863 864// CHECK-LABEL: @cond_prop 865func.func @cond_prop(%arg0 : i1) -> index { 866 %res = scf.if %arg0 -> index { 867 %res1 = scf.if %arg0 -> index { 868 %v1 = "test.get_some_value1"() : () -> index 869 scf.yield %v1 : index 870 } else { 871 %v2 = "test.get_some_value2"() : () -> index 872 scf.yield %v2 : index 873 } 874 scf.yield %res1 : index 875 } else { 876 %res2 = scf.if %arg0 -> index { 877 %v3 = "test.get_some_value3"() : () -> index 878 scf.yield %v3 : index 879 } else { 880 %v4 = "test.get_some_value4"() : () -> index 881 scf.yield %v4 : index 882 } 883 scf.yield %res2 : index 884 } 885 return %res : index 886} 887// CHECK-NEXT: %[[if:.+]] = scf.if %arg0 -> (index) { 888// CHECK-NEXT: %[[c1:.+]] = "test.get_some_value1"() : () -> index 889// CHECK-NEXT: scf.yield %[[c1]] : index 890// CHECK-NEXT: } else { 891// CHECK-NEXT: %[[c4:.+]] = "test.get_some_value4"() : () -> index 892// CHECK-NEXT: scf.yield %[[c4]] : index 893// CHECK-NEXT: } 894// CHECK-NEXT: return %[[if]] : index 895// CHECK-NEXT:} 896 897// ----- 898 899// CHECK-LABEL: @replace_if_with_cond1 900func.func @replace_if_with_cond1(%arg0 : i1) -> (i32, i1) { 901 %true = arith.constant true 902 %false = arith.constant false 903 %res:2 = scf.if %arg0 -> (i32, i1) { 904 %v = "test.get_some_value"() : () -> i32 905 scf.yield %v, %true : i32, i1 906 } else { 907 %v2 = "test.get_some_value"() : () -> i32 908 scf.yield %v2, %false : i32, i1 909 } 910 return %res#0, %res#1 : i32, i1 911} 912// CHECK-NEXT: %[[if:.+]] = scf.if %arg0 -> (i32) { 913// CHECK-NEXT: %[[sv1:.+]] = "test.get_some_value"() : () -> i32 914// CHECK-NEXT: scf.yield %[[sv1]] : i32 915// CHECK-NEXT: } else { 916// CHECK-NEXT: %[[sv2:.+]] = "test.get_some_value"() : () -> i32 917// CHECK-NEXT: scf.yield %[[sv2]] : i32 918// CHECK-NEXT: } 919// CHECK-NEXT: return %[[if]], %arg0 : i32, i1 920 921// ----- 922 923// CHECK-LABEL: @replace_if_with_cond2 924func.func @replace_if_with_cond2(%arg0 : i1) -> (i32, i1) { 925 %true = arith.constant true 926 %false = arith.constant false 927 %res:2 = scf.if %arg0 -> (i32, i1) { 928 %v = "test.get_some_value"() : () -> i32 929 scf.yield %v, %false : i32, i1 930 } else { 931 %v2 = "test.get_some_value"() : () -> i32 932 scf.yield %v2, %true : i32, i1 933 } 934 return %res#0, %res#1 : i32, i1 935} 936// CHECK-NEXT: %true = arith.constant true 937// CHECK-NEXT: %[[toret:.+]] = arith.xori %arg0, %true : i1 938// CHECK-NEXT: %[[if:.+]] = scf.if %arg0 -> (i32) { 939// CHECK-NEXT: %[[sv1:.+]] = "test.get_some_value"() : () -> i32 940// CHECK-NEXT: scf.yield %[[sv1]] : i32 941// CHECK-NEXT: } else { 942// CHECK-NEXT: %[[sv2:.+]] = "test.get_some_value"() : () -> i32 943// CHECK-NEXT: scf.yield %[[sv2]] : i32 944// CHECK-NEXT: } 945// CHECK-NEXT: return %[[if]], %[[toret]] : i32, i1 946 947// ----- 948 949// CHECK-LABEL: @replace_if_with_cond3 950func.func @replace_if_with_cond3(%arg0 : i1, %arg2: i64) -> (i32, i64) { 951 %res:2 = scf.if %arg0 -> (i32, i64) { 952 %v = "test.get_some_value"() : () -> i32 953 scf.yield %v, %arg2 : i32, i64 954 } else { 955 %v2 = "test.get_some_value"() : () -> i32 956 scf.yield %v2, %arg2 : i32, i64 957 } 958 return %res#0, %res#1 : i32, i64 959} 960// CHECK-NEXT: %[[if:.+]] = scf.if %arg0 -> (i32) { 961// CHECK-NEXT: %[[sv1:.+]] = "test.get_some_value"() : () -> i32 962// CHECK-NEXT: scf.yield %[[sv1]] : i32 963// CHECK-NEXT: } else { 964// CHECK-NEXT: %[[sv2:.+]] = "test.get_some_value"() : () -> i32 965// CHECK-NEXT: scf.yield %[[sv2]] : i32 966// CHECK-NEXT: } 967// CHECK-NEXT: return %[[if]], %arg1 : i32, i64 968 969// ----- 970 971// CHECK-LABEL: @while_cond_true 972func.func @while_cond_true() -> i1 { 973 %0 = scf.while () : () -> i1 { 974 %condition = "test.condition"() : () -> i1 975 scf.condition(%condition) %condition : i1 976 } do { 977 ^bb0(%arg0: i1): 978 "test.use"(%arg0) : (i1) -> () 979 scf.yield 980 } 981 return %0 : i1 982} 983// CHECK-NEXT: %[[true:.+]] = arith.constant true 984// CHECK-NEXT: %{{.+}} = scf.while : () -> i1 { 985// CHECK-NEXT: %[[cmp:.+]] = "test.condition"() : () -> i1 986// CHECK-NEXT: scf.condition(%[[cmp]]) %[[cmp]] : i1 987// CHECK-NEXT: } do { 988// CHECK-NEXT: ^bb0(%arg0: i1): 989// CHECK-NEXT: "test.use"(%[[true]]) : (i1) -> () 990// CHECK-NEXT: scf.yield 991// CHECK-NEXT: } 992 993// ----- 994 995// CHECK-LABEL: @while_unused_arg 996func.func @while_unused_arg(%x : i32, %y : f64) -> i32 { 997 %0 = scf.while (%arg1 = %x, %arg2 = %y) : (i32, f64) -> (i32) { 998 %condition = "test.condition"(%arg1) : (i32) -> i1 999 scf.condition(%condition) %arg1 : i32 1000 } do { 1001 ^bb0(%arg1: i32): 1002 %next = "test.use"(%arg1) : (i32) -> (i32) 1003 scf.yield %next, %y : i32, f64 1004 } 1005 return %0 : i32 1006} 1007// CHECK-NEXT: %[[res:.*]] = scf.while (%[[arg2:.+]] = %{{.*}}) : (i32) -> i32 { 1008// CHECK-NEXT: %[[cmp:.*]] = "test.condition"(%[[arg2]]) : (i32) -> i1 1009// CHECK-NEXT: scf.condition(%[[cmp]]) %[[arg2]] : i32 1010// CHECK-NEXT: } do { 1011// CHECK-NEXT: ^bb0(%[[post:.+]]: i32): 1012// CHECK-NEXT: %[[next:.+]] = "test.use"(%[[post]]) : (i32) -> i32 1013// CHECK-NEXT: scf.yield %[[next]] : i32 1014// CHECK-NEXT: } 1015// CHECK-NEXT: return %[[res]] : i32 1016 1017// ----- 1018 1019// CHECK-LABEL: @invariant_loop_args_in_same_order 1020// CHECK-SAME: (%[[FUNC_ARG0:.*]]: tensor<i32>) 1021func.func @invariant_loop_args_in_same_order(%f_arg0: tensor<i32>) -> (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) { 1022 %cst_0 = arith.constant dense<0> : tensor<i32> 1023 %cst_1 = arith.constant dense<1> : tensor<i32> 1024 %cst_42 = arith.constant dense<42> : tensor<i32> 1025 1026 %0:5 = scf.while (%arg0 = %cst_0, %arg1 = %f_arg0, %arg2 = %cst_1, %arg3 = %cst_1, %arg4 = %cst_0) : (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) -> (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) { 1027 %1 = arith.cmpi slt, %arg0, %cst_42 : tensor<i32> 1028 %2 = tensor.extract %1[] : tensor<i1> 1029 scf.condition(%2) %arg0, %arg1, %arg2, %arg3, %arg4 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1030 } do { 1031 ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>, %arg2: tensor<i32>, %arg3: tensor<i32>, %arg4: tensor<i32>): // no predecessors 1032 // %arg1 here will get replaced by %cst_1 1033 %1 = arith.addi %arg0, %arg1 : tensor<i32> 1034 %2 = arith.addi %arg2, %arg3 : tensor<i32> 1035 scf.yield %1, %arg1, %2, %2, %arg4 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1036 } 1037 return %0#0, %0#1, %0#2, %0#3, %0#4 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1038} 1039// CHECK: %[[CST42:.*]] = arith.constant dense<42> 1040// CHECK: %[[ONE:.*]] = arith.constant dense<1> 1041// CHECK: %[[ZERO:.*]] = arith.constant dense<0> 1042// CHECK: %[[WHILE:.*]]:3 = scf.while (%[[ARG0:.*]] = %[[ZERO]], %[[ARG2:.*]] = %[[ONE]], %[[ARG3:.*]] = %[[ONE]]) 1043// CHECK: arith.cmpi slt, %[[ARG0]], %{{.*}} 1044// CHECK: tensor.extract %{{.*}}[] 1045// CHECK: scf.condition(%{{.*}}) %[[ARG0]], %[[ARG2]], %[[ARG3]] 1046// CHECK: } do { 1047// CHECK: ^{{.*}}(%[[ARG0:.*]]: tensor<i32>, %[[ARG2:.*]]: tensor<i32>, %[[ARG3:.*]]: tensor<i32>): 1048// CHECK: %[[VAL0:.*]] = arith.addi %[[ARG0]], %[[FUNC_ARG0]] 1049// CHECK: %[[VAL1:.*]] = arith.addi %[[ARG2]], %[[ARG3]] 1050// CHECK: scf.yield %[[VAL0]], %[[VAL1]], %[[VAL1]] 1051// CHECK: } 1052// CHECK: return %[[WHILE]]#0, %[[FUNC_ARG0]], %[[WHILE]]#1, %[[WHILE]]#2, %[[ZERO]] 1053 1054// CHECK-LABEL: @while_loop_invariant_argument_different_order 1055func.func @while_loop_invariant_argument_different_order() -> (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) { 1056 %cst_0 = arith.constant dense<0> : tensor<i32> 1057 %cst_1 = arith.constant dense<1> : tensor<i32> 1058 %cst_42 = arith.constant dense<42> : tensor<i32> 1059 1060 %0:6 = scf.while (%arg0 = %cst_0, %arg1 = %cst_1, %arg2 = %cst_1, %arg3 = %cst_1, %arg4 = %cst_0) : (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) -> (tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>) { 1061 %1 = arith.cmpi slt, %arg0, %cst_42 : tensor<i32> 1062 %2 = tensor.extract %1[] : tensor<i1> 1063 scf.condition(%2) %arg1, %arg0, %arg2, %arg0, %arg3, %arg4 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1064 } do { 1065 ^bb0(%arg0: tensor<i32>, %arg1: tensor<i32>, %arg2: tensor<i32>, %arg3: tensor<i32>, %arg4: tensor<i32>, %arg5: tensor<i32>): // no predecessors 1066 %1 = arith.addi %arg0, %cst_1 : tensor<i32> 1067 %2 = arith.addi %arg2, %arg3 : tensor<i32> 1068 scf.yield %arg3, %arg1, %2, %2, %arg4 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1069 } 1070 return %0#0, %0#1, %0#2, %0#3, %0#4, %0#5 : tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32>, tensor<i32> 1071} 1072// CHECK: %[[CST42:.*]] = arith.constant dense<42> 1073// CHECK: %[[ONE:.*]] = arith.constant dense<1> 1074// CHECK: %[[ZERO:.*]] = arith.constant dense<0> 1075// CHECK: %[[WHILE:.*]]:2 = scf.while (%[[ARG1:.*]] = %[[ONE]], %[[ARG4:.*]] = %[[ZERO]]) 1076// CHECK: arith.cmpi slt, %[[ZERO]], %[[CST42]] 1077// CHECK: tensor.extract %{{.*}}[] 1078// CHECK: scf.condition(%{{.*}}) %[[ARG1]], %[[ARG4]] 1079// CHECK: } do { 1080// CHECK: ^{{.*}}(%{{.*}}: tensor<i32>, %{{.*}}: tensor<i32>): 1081// CHECK: scf.yield %[[ZERO]], %[[ONE]] 1082// CHECK: } 1083// CHECK: return %[[WHILE]]#0, %[[ZERO]], %[[ONE]], %[[ZERO]], %[[ONE]], %[[WHILE]]#1 1084 1085// ----- 1086 1087// CHECK-LABEL: @while_unused_result 1088func.func @while_unused_result() -> i32 { 1089 %0:2 = scf.while () : () -> (i32, i64) { 1090 %condition = "test.condition"() : () -> i1 1091 %v1 = "test.get_some_value"() : () -> i32 1092 %v2 = "test.get_some_value"() : () -> i64 1093 scf.condition(%condition) %v1, %v2 : i32, i64 1094 } do { 1095 ^bb0(%arg0: i32, %arg1: i64): 1096 "test.use"(%arg0) : (i32) -> () 1097 scf.yield 1098 } 1099 return %0#0 : i32 1100} 1101// CHECK-NEXT: %[[res:.*]] = scf.while : () -> i32 { 1102// CHECK-NEXT: %[[cmp:.*]] = "test.condition"() : () -> i1 1103// CHECK-NEXT: %[[val:.*]] = "test.get_some_value"() : () -> i32 1104// CHECK-NEXT: %{{.*}} = "test.get_some_value"() : () -> i64 1105// CHECK-NEXT: scf.condition(%[[cmp]]) %[[val]] : i32 1106// CHECK-NEXT: } do { 1107// CHECK-NEXT: ^bb0(%[[arg:.*]]: i32): 1108// CHECK-NEXT: "test.use"(%[[arg]]) : (i32) -> () 1109// CHECK-NEXT: scf.yield 1110// CHECK-NEXT: } 1111// CHECK-NEXT: return %[[res]] : i32 1112 1113// CHECK-LABEL: @while_cmp_lhs 1114func.func @while_cmp_lhs(%arg0 : i32) { 1115 %0 = scf.while () : () -> i32 { 1116 %val = "test.val"() : () -> i32 1117 %condition = arith.cmpi ne, %val, %arg0 : i32 1118 scf.condition(%condition) %val : i32 1119 } do { 1120 ^bb0(%val2: i32): 1121 %condition2 = arith.cmpi ne, %val2, %arg0 : i32 1122 %negcondition2 = arith.cmpi eq, %val2, %arg0 : i32 1123 "test.use"(%condition2, %negcondition2, %val2) : (i1, i1, i32) -> () 1124 scf.yield 1125 } 1126 return 1127} 1128// CHECK-DAG: %[[true:.+]] = arith.constant true 1129// CHECK-DAG: %[[false:.+]] = arith.constant false 1130// CHECK-DAG: %{{.+}} = scf.while : () -> i32 { 1131// CHECK-NEXT: %[[val:.+]] = "test.val" 1132// CHECK-NEXT: %[[cmp:.+]] = arith.cmpi ne, %[[val]], %arg0 : i32 1133// CHECK-NEXT: scf.condition(%[[cmp]]) %[[val]] : i32 1134// CHECK-NEXT: } do { 1135// CHECK-NEXT: ^bb0(%arg1: i32): 1136// CHECK-NEXT: "test.use"(%[[true]], %[[false]], %arg1) : (i1, i1, i32) -> () 1137// CHECK-NEXT: scf.yield 1138// CHECK-NEXT: } 1139 1140// CHECK-LABEL: @while_cmp_rhs 1141func.func @while_cmp_rhs(%arg0 : i32) { 1142 %0 = scf.while () : () -> i32 { 1143 %val = "test.val"() : () -> i32 1144 %condition = arith.cmpi ne, %arg0, %val : i32 1145 scf.condition(%condition) %val : i32 1146 } do { 1147 ^bb0(%val2: i32): 1148 %condition2 = arith.cmpi ne, %arg0, %val2 : i32 1149 %negcondition2 = arith.cmpi eq, %arg0, %val2 : i32 1150 "test.use"(%condition2, %negcondition2, %val2) : (i1, i1, i32) -> () 1151 scf.yield 1152 } 1153 return 1154} 1155// CHECK-DAG: %[[true:.+]] = arith.constant true 1156// CHECK-DAG: %[[false:.+]] = arith.constant false 1157// CHECK-DAG: %{{.+}} = scf.while : () -> i32 { 1158// CHECK-NEXT: %[[val:.+]] = "test.val" 1159// CHECK-NEXT: %[[cmp:.+]] = arith.cmpi ne, %arg0, %[[val]] : i32 1160// CHECK-NEXT: scf.condition(%[[cmp]]) %[[val]] : i32 1161// CHECK-NEXT: } do { 1162// CHECK-NEXT: ^bb0(%arg1: i32): 1163// CHECK-NEXT: "test.use"(%[[true]], %[[false]], %arg1) : (i1, i1, i32) -> () 1164// CHECK-NEXT: scf.yield 1165// CHECK-NEXT: } 1166 1167// ----- 1168 1169// CHECK-LABEL: @combineIfs 1170func.func @combineIfs(%arg0 : i1, %arg2: i64) -> (i32, i32) { 1171 %res = scf.if %arg0 -> i32 { 1172 %v = "test.firstCodeTrue"() : () -> i32 1173 scf.yield %v : i32 1174 } else { 1175 %v2 = "test.firstCodeFalse"() : () -> i32 1176 scf.yield %v2 : i32 1177 } 1178 %res2 = scf.if %arg0 -> i32 { 1179 %v = "test.secondCodeTrue"() : () -> i32 1180 scf.yield %v : i32 1181 } else { 1182 %v2 = "test.secondCodeFalse"() : () -> i32 1183 scf.yield %v2 : i32 1184 } 1185 return %res, %res2 : i32, i32 1186} 1187// CHECK-NEXT: %[[res:.+]]:2 = scf.if %arg0 -> (i32, i32) { 1188// CHECK-NEXT: %[[tval0:.+]] = "test.firstCodeTrue"() : () -> i32 1189// CHECK-NEXT: %[[tval:.+]] = "test.secondCodeTrue"() : () -> i32 1190// CHECK-NEXT: scf.yield %[[tval0]], %[[tval]] : i32, i32 1191// CHECK-NEXT: } else { 1192// CHECK-NEXT: %[[fval0:.+]] = "test.firstCodeFalse"() : () -> i32 1193// CHECK-NEXT: %[[fval:.+]] = "test.secondCodeFalse"() : () -> i32 1194// CHECK-NEXT: scf.yield %[[fval0]], %[[fval]] : i32, i32 1195// CHECK-NEXT: } 1196// CHECK-NEXT: return %[[res]]#0, %[[res]]#1 : i32, i32 1197 1198 1199// CHECK-LABEL: @combineIfs2 1200func.func @combineIfs2(%arg0 : i1, %arg2: i64) -> i32 { 1201 scf.if %arg0 { 1202 "test.firstCodeTrue"() : () -> () 1203 scf.yield 1204 } 1205 %res = scf.if %arg0 -> i32 { 1206 %v = "test.secondCodeTrue"() : () -> i32 1207 scf.yield %v : i32 1208 } else { 1209 %v2 = "test.secondCodeFalse"() : () -> i32 1210 scf.yield %v2 : i32 1211 } 1212 return %res : i32 1213} 1214// CHECK-NEXT: %[[res:.+]] = scf.if %arg0 -> (i32) { 1215// CHECK-NEXT: "test.firstCodeTrue"() : () -> () 1216// CHECK-NEXT: %[[tval:.+]] = "test.secondCodeTrue"() : () -> i32 1217// CHECK-NEXT: scf.yield %[[tval]] : i32 1218// CHECK-NEXT: } else { 1219// CHECK-NEXT: %[[fval:.+]] = "test.secondCodeFalse"() : () -> i32 1220// CHECK-NEXT: scf.yield %[[fval]] : i32 1221// CHECK-NEXT: } 1222// CHECK-NEXT: return %[[res]] : i32 1223 1224 1225// CHECK-LABEL: @combineIfs3 1226func.func @combineIfs3(%arg0 : i1, %arg2: i64) -> i32 { 1227 %res = scf.if %arg0 -> i32 { 1228 %v = "test.firstCodeTrue"() : () -> i32 1229 scf.yield %v : i32 1230 } else { 1231 %v2 = "test.firstCodeFalse"() : () -> i32 1232 scf.yield %v2 : i32 1233 } 1234 scf.if %arg0 { 1235 "test.secondCodeTrue"() : () -> () 1236 scf.yield 1237 } 1238 return %res : i32 1239} 1240// CHECK-NEXT: %[[res:.+]] = scf.if %arg0 -> (i32) { 1241// CHECK-NEXT: %[[tval:.+]] = "test.firstCodeTrue"() : () -> i32 1242// CHECK-NEXT: "test.secondCodeTrue"() : () -> () 1243// CHECK-NEXT: scf.yield %[[tval]] : i32 1244// CHECK-NEXT: } else { 1245// CHECK-NEXT: %[[fval:.+]] = "test.firstCodeFalse"() : () -> i32 1246// CHECK-NEXT: scf.yield %[[fval]] : i32 1247// CHECK-NEXT: } 1248// CHECK-NEXT: return %[[res]] : i32 1249 1250// CHECK-LABEL: @combineIfs4 1251func.func @combineIfs4(%arg0 : i1, %arg2: i64) { 1252 scf.if %arg0 { 1253 "test.firstCodeTrue"() : () -> () 1254 scf.yield 1255 } 1256 scf.if %arg0 { 1257 "test.secondCodeTrue"() : () -> () 1258 scf.yield 1259 } 1260 return 1261} 1262 1263// CHECK-NEXT: scf.if %arg0 { 1264// CHECK-NEXT: "test.firstCodeTrue"() : () -> () 1265// CHECK-NEXT: "test.secondCodeTrue"() : () -> () 1266// CHECK-NEXT: } 1267 1268// CHECK-LABEL: @combineIfsUsed 1269// CHECK-SAME: %[[arg0:.+]]: i1 1270func.func @combineIfsUsed(%arg0 : i1, %arg2: i64) -> (i32, i32) { 1271 %res = scf.if %arg0 -> i32 { 1272 %v = "test.firstCodeTrue"() : () -> i32 1273 scf.yield %v : i32 1274 } else { 1275 %v2 = "test.firstCodeFalse"() : () -> i32 1276 scf.yield %v2 : i32 1277 } 1278 %res2 = scf.if %arg0 -> i32 { 1279 %v = "test.secondCodeTrue"(%res) : (i32) -> i32 1280 scf.yield %v : i32 1281 } else { 1282 %v2 = "test.secondCodeFalse"(%res) : (i32) -> i32 1283 scf.yield %v2 : i32 1284 } 1285 return %res, %res2 : i32, i32 1286} 1287// CHECK-NEXT: %[[res:.+]]:2 = scf.if %[[arg0]] -> (i32, i32) { 1288// CHECK-NEXT: %[[tval0:.+]] = "test.firstCodeTrue"() : () -> i32 1289// CHECK-NEXT: %[[tval:.+]] = "test.secondCodeTrue"(%[[tval0]]) : (i32) -> i32 1290// CHECK-NEXT: scf.yield %[[tval0]], %[[tval]] : i32, i32 1291// CHECK-NEXT: } else { 1292// CHECK-NEXT: %[[fval0:.+]] = "test.firstCodeFalse"() : () -> i32 1293// CHECK-NEXT: %[[fval:.+]] = "test.secondCodeFalse"(%[[fval0]]) : (i32) -> i32 1294// CHECK-NEXT: scf.yield %[[fval0]], %[[fval]] : i32, i32 1295// CHECK-NEXT: } 1296// CHECK-NEXT: return %[[res]]#0, %[[res]]#1 : i32, i32 1297 1298// CHECK-LABEL: @combineIfsNot 1299// CHECK-SAME: %[[arg0:.+]]: i1 1300func.func @combineIfsNot(%arg0 : i1, %arg2: i64) { 1301 %true = arith.constant true 1302 %not = arith.xori %arg0, %true : i1 1303 scf.if %arg0 { 1304 "test.firstCodeTrue"() : () -> () 1305 scf.yield 1306 } 1307 scf.if %not { 1308 "test.secondCodeTrue"() : () -> () 1309 scf.yield 1310 } 1311 return 1312} 1313 1314// CHECK-NEXT: scf.if %[[arg0]] { 1315// CHECK-NEXT: "test.firstCodeTrue"() : () -> () 1316// CHECK-NEXT: } else { 1317// CHECK-NEXT: "test.secondCodeTrue"() : () -> () 1318// CHECK-NEXT: } 1319 1320// CHECK-LABEL: @combineIfsNot2 1321// CHECK-SAME: %[[arg0:.+]]: i1 1322func.func @combineIfsNot2(%arg0 : i1, %arg2: i64) { 1323 %true = arith.constant true 1324 %not = arith.xori %arg0, %true : i1 1325 scf.if %not { 1326 "test.firstCodeTrue"() : () -> () 1327 scf.yield 1328 } 1329 scf.if %arg0 { 1330 "test.secondCodeTrue"() : () -> () 1331 scf.yield 1332 } 1333 return 1334} 1335 1336// CHECK-NEXT: scf.if %[[arg0]] { 1337// CHECK-NEXT: "test.secondCodeTrue"() : () -> () 1338// CHECK-NEXT: } else { 1339// CHECK-NEXT: "test.firstCodeTrue"() : () -> () 1340// CHECK-NEXT: } 1341// ----- 1342 1343// CHECK-LABEL: func @propagate_into_execute_region 1344func.func @propagate_into_execute_region() { 1345 %cond = arith.constant 0 : i1 1346 affine.for %i = 0 to 100 { 1347 "test.foo"() : () -> () 1348 %v = scf.execute_region -> i64 { 1349 cf.cond_br %cond, ^bb1, ^bb2 1350 1351 ^bb1: 1352 %c1 = arith.constant 1 : i64 1353 cf.br ^bb3(%c1 : i64) 1354 1355 ^bb2: 1356 %c2 = arith.constant 2 : i64 1357 cf.br ^bb3(%c2 : i64) 1358 1359 ^bb3(%x : i64): 1360 scf.yield %x : i64 1361 } 1362 "test.bar"(%v) : (i64) -> () 1363 // CHECK: %[[C2:.*]] = arith.constant 2 : i64 1364 // CHECK: "test.foo" 1365 // CHECK-NEXT: "test.bar"(%[[C2]]) : (i64) -> () 1366 } 1367 return 1368} 1369 1370// ----- 1371 1372// CHECK-LABEL: func @execute_region_elim 1373func.func @execute_region_elim() { 1374 affine.for %i = 0 to 100 { 1375 "test.foo"() : () -> () 1376 %v = scf.execute_region -> i64 { 1377 %x = "test.val"() : () -> i64 1378 scf.yield %x : i64 1379 } 1380 "test.bar"(%v) : (i64) -> () 1381 } 1382 return 1383} 1384 1385// CHECK-NEXT: affine.for %arg0 = 0 to 100 { 1386// CHECK-NEXT: "test.foo"() : () -> () 1387// CHECK-NEXT: %[[VAL:.*]] = "test.val"() : () -> i64 1388// CHECK-NEXT: "test.bar"(%[[VAL]]) : (i64) -> () 1389// CHECK-NEXT: } 1390 1391 1392// ----- 1393 1394// CHECK-LABEL: func @func_execute_region_elim 1395func.func @func_execute_region_elim() { 1396 "test.foo"() : () -> () 1397 %v = scf.execute_region -> i64 { 1398 %c = "test.cmp"() : () -> i1 1399 cf.cond_br %c, ^bb2, ^bb3 1400 ^bb2: 1401 %x = "test.val1"() : () -> i64 1402 cf.br ^bb4(%x : i64) 1403 ^bb3: 1404 %y = "test.val2"() : () -> i64 1405 cf.br ^bb4(%y : i64) 1406 ^bb4(%z : i64): 1407 scf.yield %z : i64 1408 } 1409 "test.bar"(%v) : (i64) -> () 1410 return 1411} 1412 1413// CHECK-NOT: execute_region 1414// CHECK: "test.foo" 1415// CHECK: %[[cmp:.+]] = "test.cmp" 1416// CHECK: cf.cond_br %[[cmp]], ^[[bb1:.+]], ^[[bb2:.+]] 1417// CHECK: ^[[bb1]]: 1418// CHECK: %[[x:.+]] = "test.val1" 1419// CHECK: cf.br ^[[bb3:.+]](%[[x]] : i64) 1420// CHECK: ^[[bb2]]: 1421// CHECK: %[[y:.+]] = "test.val2" 1422// CHECK: cf.br ^[[bb3]](%[[y:.+]] : i64) 1423// CHECK: ^[[bb3]](%[[z:.+]]: i64): 1424// CHECK: "test.bar"(%[[z]]) 1425// CHECK: return 1426 1427 1428// ----- 1429 1430// CHECK-LABEL: func @func_execute_region_elim_multi_yield 1431func.func @func_execute_region_elim_multi_yield() { 1432 "test.foo"() : () -> () 1433 %v = scf.execute_region -> i64 { 1434 %c = "test.cmp"() : () -> i1 1435 cf.cond_br %c, ^bb2, ^bb3 1436 ^bb2: 1437 %x = "test.val1"() : () -> i64 1438 scf.yield %x : i64 1439 ^bb3: 1440 %y = "test.val2"() : () -> i64 1441 scf.yield %y : i64 1442 } 1443 "test.bar"(%v) : (i64) -> () 1444 return 1445} 1446 1447// CHECK-NOT: execute_region 1448// CHECK: "test.foo" 1449// CHECK: %[[cmp:.+]] = "test.cmp" 1450// CHECK: cf.cond_br %[[cmp]], ^[[bb1:.+]], ^[[bb2:.+]] 1451// CHECK: ^[[bb1]]: 1452// CHECK: %[[x:.+]] = "test.val1" 1453// CHECK: cf.br ^[[bb3:.+]](%[[x]] : i64) 1454// CHECK: ^[[bb2]]: 1455// CHECK: %[[y:.+]] = "test.val2" 1456// CHECK: cf.br ^[[bb3]](%[[y:.+]] : i64) 1457// CHECK: ^[[bb3]](%[[z:.+]]: i64): 1458// CHECK: "test.bar"(%[[z]]) 1459// CHECK: return 1460