1// RUN: mlir-opt --lift-cf-to-scf -split-input-file %s | FileCheck %s 2 3func.func @simple_if() { 4 %cond = "test.test1"() : () -> i1 5 cf.cond_br %cond, ^bb1, ^bb2 6^bb1: 7 "test.test2"() : () -> () 8 cf.br ^bb3 9^bb2: 10 "test.test3"() : () -> () 11 cf.br ^bb3 12^bb3: 13 "test.test4"() : () -> () 14 return 15} 16 17// CHECK-LABEL: func @simple_if 18// CHECK: %[[COND:.*]] = "test.test1"() 19// CHECK-NEXT: scf.if %[[COND]] 20// CHECK-NEXT: "test.test2"() 21// CHECK-NEXT: else 22// CHECK-NEXT: "test.test3"() 23// CHECK-NEXT: } 24// CHECK-NEXT: "test.test4"() 25// CHECK-NEXT: return 26 27// ----- 28 29func.func @if_with_block_args() -> index { 30 %cond = "test.test1"() : () -> i1 31 cf.cond_br %cond, ^bb1, ^bb2 32^bb1: 33 %1 = "test.test2"() : () -> (index) 34 cf.br ^bb3(%1: index) 35^bb2: 36 %2 = "test.test3"() : () -> (index) 37 cf.br ^bb3(%2: index) 38^bb3(%3: index): 39 "test.test4"() : () -> () 40 return %3 : index 41} 42 43// CHECK-LABEL: func @if_with_block_args 44// CHECK: %[[COND:.*]] = "test.test1"() 45// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]] 46// CHECK-NEXT: %[[VAL1:.*]] = "test.test2"() 47// CHECK-NEXT: scf.yield %[[VAL1]] 48// CHECK-NEXT: else 49// CHECK-NEXT: %[[VAL2:.*]] = "test.test3"() 50// CHECK-NEXT: scf.yield %[[VAL2]] 51// CHECK: "test.test4"() 52// CHECK-NEXT: return %[[RES]] 53 54// ----- 55 56func.func @empty_else() { 57 %cond = "test.test1"() : () -> i1 58 cf.cond_br %cond, ^bb1, ^bb3 59^bb1: 60 "test.test2"() : () -> () 61 cf.br ^bb3 62^bb3: 63 "test.test4"() : () -> () 64 return 65} 66 67// CHECK-LABEL: func @empty_else 68// CHECK: %[[COND:.*]] = "test.test1"() 69// CHECK-NEXT: scf.if %[[COND]] 70// CHECK-NEXT: "test.test2"() 71// CHECK: else 72// CHECK-NEXT: } 73// CHECK-NEXT: "test.test4"() 74// CHECK-NEXT: return 75 76// ----- 77 78func.func @while_loop() { 79 "test.test1"() : () -> () 80 cf.br ^bb1 81^bb1: 82 %cond = "test.test2"() : () -> i1 83 cf.cond_br %cond, ^bb2, ^bb3 84^bb2: 85 "test.test3"() : () -> () 86 cf.br ^bb1 87^bb3: 88 "test.test4"() : () -> () 89 return 90} 91 92// CHECK-LABEL: func @while_loop 93// CHECK-DAG: %[[C0:.*]] = arith.constant 0 94// CHECK-DAG: %[[C1:.*]] = arith.constant 1 95// CHECK-NEXT: "test.test1"() 96// CHECK-NEXT: scf.while 97// CHECK-NEXT: %[[COND:.*]] = "test.test2"() 98// CHECK-NEXT: %[[RES:.*]]:2 = scf.if %[[COND]] 99// CHECK-NEXT: "test.test3"() 100// CHECK-NEXT: scf.yield %[[C0]], %[[C1]] 101// CHECK-NEXT: else 102// CHECK-NEXT: scf.yield %[[C1]], %[[C0]] 103// CHECK: %[[COND:.*]] = arith.trunci %[[RES]]#1 104// CHECK-NEXT: scf.condition(%[[COND]]) 105// CHECK-NEXT: do 106// CHECK-NEXT: scf.yield 107// CHECK: "test.test4"() 108// CHECK-NEXT: return 109 110// ----- 111 112func.func @while_loop_with_block_args() -> i64{ 113 %1 = "test.test1"() : () -> index 114 cf.br ^bb1(%1: index) 115^bb1(%2: index): 116 %cond:2 = "test.test2"() : () -> (i1, i64) 117 cf.cond_br %cond#0, ^bb2(%cond#1: i64), ^bb3(%cond#1: i64) 118^bb2(%3: i64): 119 %4 = "test.test3"(%3) : (i64) -> index 120 cf.br ^bb1(%4: index) 121^bb3(%5: i64): 122 "test.test4"() : () -> () 123 return %5 : i64 124} 125 126// CHECK-LABEL: func @while_loop_with_block_args 127// CHECK-DAG: %[[C0:.*]] = arith.constant 0 128// CHECK-DAG: %[[C1:.*]] = arith.constant 1 129// CHECK-DAG: %[[POISON_i64:.*]] = ub.poison : i64 130// CHECK-DAG: %[[POISON_index:.*]] = ub.poison : index 131// CHECK-NEXT: %[[VAL1:.*]] = "test.test1"() 132// CHECK-NEXT: %[[RES:.*]]:2 = scf.while (%[[ARG0:.*]] = %[[VAL1]], %[[ARG1:.*]] = %[[POISON_i64]]) 133// CHECK-NEXT: %[[COND:.*]]:2 = "test.test2"() 134// CHECK-NEXT: %[[IF_VALS:.*]]:4 = scf.if %[[COND]]#0 135// CHECK-NEXT: %[[VAL:.*]] = "test.test3"(%[[COND]]#1) 136// CHECK-NEXT: scf.yield %[[VAL]], %[[POISON_i64]], %[[C0]], %[[C1]] 137// CHECK-NEXT: else 138// CHECK-NEXT: scf.yield %[[POISON_index]], %[[COND]]#1, %[[C1]], %[[C0]] 139// CHECK: %[[TRUNC:.*]] = arith.trunci %[[IF_VALS]]#3 140// CHECK-NEXT: scf.condition(%[[TRUNC]]) %[[IF_VALS]]#0, %[[IF_VALS]]#1 141// CHECK-NEXT: do 142// CHECK-NEXT: ^{{.+}}( 143// CHECK-SAME: [[ARG0:[[:alnum:]]+]]: 144// CHECK-SAME: [[ARG1:[[:alnum:]]+]]: 145// CHECK-NEXT: scf.yield %[[ARG0]], %[[ARG1]] 146// CHECK: "test.test4"() : () -> () 147// CHECK-NEXT: return %[[RES]]#1 : i64 148 149// ----- 150 151func.func @multi_exit_loop() { 152 "test.test1"() : () -> () 153 cf.br ^bb1 154^bb1: 155 %cond = "test.test2"() : () -> i1 156 cf.cond_br %cond, ^bb2, ^bb3 157^bb2: 158 %cond2 = "test.test3"() : () -> i1 159 cf.cond_br %cond2, ^bb3, ^bb1 160^bb3: 161 "test.test4"() : () -> () 162 return 163} 164 165// CHECK-LABEL: func @multi_exit_loop 166// CHECK-DAG: %[[C0:.*]] = arith.constant 0 167// CHECK-DAG: %[[C1:.*]] = arith.constant 1 168// CHECK-NEXT: "test.test1"() 169// CHECK-NEXT: scf.while 170// CHECK-NEXT: %[[COND:.*]] = "test.test2"() 171// CHECK-NEXT: %[[IF_PAIR:.*]]:2 = scf.if %[[COND]] 172// CHECK-NEXT: %[[COND2:.*]] = "test.test3"() 173// CHECK-NEXT: %[[IF_PAIR2:.*]]:2 = scf.if %[[COND2]] 174// CHECK-NEXT: scf.yield %[[C1]], %[[C0]] 175// CHECK-NEXT: else 176// CHECK-NEXT: scf.yield %[[C0]], %[[C1]] 177// CHECK: scf.yield %[[IF_PAIR2]]#0, %[[IF_PAIR2]]#1 178// CHECK: %[[TRUNC:.*]] = arith.trunci %[[IF_PAIR]]#1 179// CHECK-NEXT: scf.condition(%[[TRUNC]]) 180// CHECK-NEXT: do 181// CHECK-NEXT: scf.yield 182// CHECK: "test.test4"() 183// CHECK-NEXT: return 184 185// ----- 186 187func.func private @foo(%arg: f32) -> f32 188func.func private @bar(%arg: f32) 189 190func.func @switch_with_fallthrough(%flag: i32, %arg1 : f32, %arg2 : f32) { 191 cf.switch %flag : i32, [ 192 default: ^bb1(%arg1 : f32), 193 0: ^bb2(%arg2 : f32), 194 1: ^bb3 195 ] 196 197^bb1(%arg3 : f32): 198 %0 = call @foo(%arg3) : (f32) -> f32 199 cf.br ^bb2(%0 : f32) 200 201^bb2(%arg4 : f32): 202 call @bar(%arg4) : (f32) -> () 203 cf.br ^bb3 204 205^bb3: 206 return 207} 208 209// CHECK-LABEL: func @switch_with_fallthrough 210// CHECK-SAME: %[[ARG0:[[:alnum:]]+]] 211// CHECK-SAME: %[[ARG1:[[:alnum:]]+]] 212// CHECK-SAME: %[[ARG2:[[:alnum:]]+]] 213// CHECK-DAG: %[[C0:.*]] = arith.constant 0 214// CHECK-DAG: %[[C1:.*]] = arith.constant 1 215// CHECK-DAG: %[[POISON:.*]] = ub.poison 216// CHECK-NEXT: %[[INDEX_CAST:.*]] = arith.index_castui %[[ARG0]] 217// CHECK-NEXT: %[[SWITCH_PAIR:.*]]:2 = scf.index_switch %[[INDEX_CAST]] 218// CHECK-NEXT: case 0 219// CHECK-NEXT: scf.yield %[[ARG2]], %[[C0]] 220// CHECK: case 1 221// CHECK-NEXT: scf.yield %[[POISON]], %[[C1]] 222// CHECK: default 223// CHECK-NEXT: %[[RES:.*]] = func.call @foo(%[[ARG1]]) 224// CHECK-NEXT: scf.yield %[[RES]], %[[C0]] 225// CHECK: %[[INDEX_CAST:.*]] = arith.index_castui %[[SWITCH_PAIR]]#1 226// CHECK-NEXT: scf.index_switch %[[INDEX_CAST]] 227// CHECK-NEXT: case 0 228// CHECK-NEXT: call @bar(%[[SWITCH_PAIR]]#0) 229// CHECK-NEXT: scf.yield 230// CHECK: default { 231// CHECK-NEXT: } 232// CHECK-NEXT: return 233 234// ----- 235 236func.func private @bar(%arg: f32) -> (i1, f32) 237 238func.func @already_structured_loop(%arg: f32) -> f32 { 239 cf.br ^bb0 240 241^bb0: 242 %cond, %value = call @bar(%arg) : (f32) -> (i1, f32) 243 cf.cond_br %cond, ^bb1, ^bb0 244 245^bb1: 246 return %value : f32 247} 248 249// CHECK-LABEL: @already_structured_loop 250// CHECK-SAME: %[[ARG:.*]]: f32 251// CHECK-DAG: %[[C0:.*]] = arith.constant 0 252// CHECK-DAG: %[[C1:.*]] = arith.constant 1 253// CHECK-DAG: %[[POISON:.*]] = ub.poison 254// CHECK-NEXT: %[[RES:.*]] = scf.while (%[[ARG1:.*]] = %[[POISON]]) 255// CHECK-NEXT: %[[CALL_PAIR:.*]]:2 = func.call @bar(%[[ARG]]) 256// CHECK-NEXT: %[[IF_PAIR:.*]]:2 = scf.if %[[CALL_PAIR]]#0 257// CHECK-NEXT: scf.yield %[[C1]], %[[C0]] 258// CHECK-NEXT: else 259// CHECK-NEXT: scf.yield %[[C0]], %[[C1]] 260// CHECK: %[[TRUNC:.*]] = arith.trunci %[[IF_PAIR]]#1 261// CHECK-NEXT: scf.condition(%[[TRUNC]]) %[[CALL_PAIR]]#1 262// CHECK: return %[[RES]] 263 264// ----- 265 266func.func private @bar(%arg: f32) -> (i1, f32) 267 268// This test makes sure that the exit block using an iteration variable works 269// correctly. 270 271func.func @exit_loop_iter_use(%arg: f32) -> f32 { 272 cf.br ^bb0(%arg : f32) 273 274^bb0(%arg1: f32): 275 %cond, %value = call @bar(%arg1) : (f32) -> (i1, f32) 276 cf.cond_br %cond, ^bb1, ^bb0(%value : f32) 277 278^bb1: 279 return %arg1 : f32 280} 281 282// CHECK-LABEL: @exit_loop_iter_use 283// CHECK-SAME: %[[ARG:.*]]: 284// CHECK-DAG: %[[C0:.*]] = arith.constant 0 285// CHECK-DAG: %[[C1:.*]] = arith.constant 1 286// CHECK-DAG: %[[POISON:.*]] = ub.poison 287// CHECK-NEXT: %[[RES:.*]]:2 = scf.while 288// CHECK-SAME: %[[ARG1:.*]] = %[[ARG]] 289// CHECK-SAME: %[[ARG2:.*]] = %[[POISON]] 290// CHECK-NEXT: %[[CALL_PAIR:.*]]:2 = func.call @bar(%[[ARG1]]) 291// CHECK-NEXT: %[[IF_RES:.*]]:3 = scf.if %[[CALL_PAIR]]#0 292// CHECK-NEXT: scf.yield %[[POISON]], %[[C1]], %[[C0]] 293// CHECK-NEXT: else 294// CHECK-NEXT: scf.yield %[[CALL_PAIR]]#1, %[[C0]], %[[C1]] 295// CHECK: %[[TRUNC:.*]] = arith.trunci %[[IF_RES]]#2 296// CHECK-NEXT: scf.condition(%[[TRUNC]]) %[[IF_RES]]#0, %[[ARG1]] 297// CHECK: return %[[RES]]#1 298 299// ----- 300 301func.func private @bar(%arg: f32) -> f32 302 303func.func @infinite_loop(%arg: f32) -> f32 { 304 cf.br ^bb1(%arg: f32) 305 306^bb1(%arg1: f32): 307 %0 = call @bar(%arg1) : (f32) -> f32 308 cf.br ^bb1(%0 : f32) 309} 310 311// CHECK-LABEL: @infinite_loop 312// CHECK-SAME: %[[ARG:.*]]: 313// CHECK-DAG: %[[C0:.*]] = arith.constant 0 314// CHECK-DAG: %[[C1:.*]] = arith.constant 1 315// CHECK-NEXT: scf.while 316// CHECK-SAME: %[[ARG1:.*]] = %[[ARG]] 317// CHECK-NEXT: %[[CALL:.*]] = func.call @bar(%[[ARG1]]) 318// CHECK-NEXT: %[[TRUNC:.*]] = arith.trunci %[[C1]] 319// CHECK-NEXT: scf.condition(%[[TRUNC]]) %[[CALL]] 320// CHECK: %[[POISON:.*]] = ub.poison 321// CHECK: return %[[POISON]] 322 323// ----- 324 325func.func @multi_return() -> i32 { 326 %cond = "test.test1"() : () -> i1 327 cf.cond_br %cond, ^bb1, ^bb3 328^bb1: 329 %0 = "test.test2"() : () -> i32 330 return %0 : i32 331^bb3: 332 %1 = "test.test4"() : () -> i32 333 return %1 : i32 334} 335 336// CHECK-LABEL: func @multi_return 337// CHECK: %[[COND:.*]] = "test.test1"() 338// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]] 339// CHECK-NEXT: %[[VAL2:.*]] = "test.test2"() 340// CHECK: scf.yield %[[VAL2]] 341// CHECK-NEXT: else 342// CHECK-NEXT: %[[VAL4:.*]] = "test.test4"() 343// CHECK: scf.yield %[[VAL4]] 344// CHECK: return %[[RES]] 345 346// ----- 347 348func.func private @bar(%arg: f32) -> f32 349 350func.func @conditional_infinite_loop(%arg: f32, %cond: i1) -> f32 { 351 cf.cond_br %cond, ^bb1(%arg: f32), ^bb2 352 353^bb1(%arg1: f32): 354 %0 = call @bar(%arg1) : (f32) -> f32 355 cf.br ^bb1(%0 : f32) 356 357^bb2: 358 return %arg : f32 359} 360 361// CHECK-LABEL: @conditional_infinite_loop 362// CHECK-SAME: %[[ARG0:[[:alnum:]]+]]: 363// CHECK-SAME: %[[ARG1:[[:alnum:]]+]]: 364// CHECK-DAG: %[[C0:.*]] = arith.constant 0 365// CHECK-DAG: %[[C1:.*]] = arith.constant 1 366// CHECK-NEXT: %[[RES:.*]] = scf.if %[[ARG1]] 367// CHECK-NEXT: scf.while 368// CHECK-SAME: %[[ARG2:.*]] = %[[ARG0]] 369// CHECK-NEXT: %[[CALL:.*]] = func.call @bar(%[[ARG2]]) 370// CHECK-NEXT: %[[TRUNC:.*]] = arith.trunci %[[C1]] 371// CHECK-NEXT: scf.condition(%[[TRUNC]]) %[[CALL]] 372// CHECK: else 373// CHECK: scf.yield %[[ARG0]] 374// CHECK: return %[[RES]] 375 376// ----- 377 378// Different return-like terminators lead one control flow op remaining in the top level region. 379// Each of the blocks the control flow op leads to are transformed into regions nevertheless. 380 381func.func private @bar(%arg: i32) 382 383func.func @mixing_return_like(%cond: i1, %cond2: i1, %cond3: i1) { 384 %0 = arith.constant 0 : i32 385 %1 = arith.constant 1 : i32 386 cf.cond_br %cond, ^bb1, ^bb3 387 388^bb1: 389 cf.cond_br %cond2, ^bb2(%0 : i32), ^bb2(%1 : i32) 390^bb2(%arg: i32): 391 call @bar(%arg) : (i32) -> () 392 "test.returnLike"() : () -> () 393 394^bb3: 395 cf.cond_br %cond3, ^bb4(%1 : i32), ^bb4(%0 : i32) 396^bb4(%arg2: i32): 397 call @bar(%arg2) : (i32) -> () 398 return 399} 400 401// CHECK-LABEL: @mixing_return_like 402// CHECK-SAME: %[[COND1:[[:alnum:]]+]]: 403// CHECK-SAME: %[[COND2:[[:alnum:]]+]]: 404// CHECK-SAME: %[[COND3:[[:alnum:]]+]]: 405// CHECK-DAG: %[[C0:.*]] = arith.constant 0 406// CHECK-DAG: %[[C1:.*]] = arith.constant 1 407// CHECK: cf.cond_br %[[COND1]], ^[[BB1:.*]], ^[[BB2:[[:alnum:]]+]] 408 409// CHECK: ^[[BB1]]: 410// CHECK: scf.if 411// CHECK-NOT: cf.{{(switch|(cond_)?br)}} 412// CHECK: call @bar 413// CHECK: "test.returnLike" 414 415// CHECK: ^[[BB2]]: 416// CHECK: scf.if 417// CHECK-NOT: cf.{{(switch|(cond_)?br)}} 418// CHECK: call @bar 419// CHECK: return 420 421// ----- 422 423// cf.switch here only has some successors with different return-like ops. 424// This test makes sure that if there are at least two successors branching to 425// the same region, that this region gets properly turned to structured control 426// flow. 427 428func.func @some_successors_with_different_return(%flag: i32) -> i32 { 429 %0 = arith.constant 5 : i32 430 %1 = arith.constant 6 : i32 431 cf.switch %flag : i32, [ 432 default: ^bb1, 433 0: ^bb3(%0 : i32), 434 1: ^bb3(%1 : i32) 435 ] 436 437^bb1: 438 "test.returnLike"() : () -> () 439 440^bb3(%arg: i32): 441 cf.br ^bb3(%arg : i32) 442} 443 444// CHECK-LABEL: @some_successors_with_different_return 445// CHECK-SAME: %[[FLAG:[[:alnum:]]+]]: 446// CHECK-DAG: %[[C0:.*]] = arith.constant 0 : i32 447// CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32 448// CHECK-DAG: %[[POISON:.*]] = ub.poison 449// CHECK-DAG: %[[C5:.*]] = arith.constant 5 : i32 450// CHECK-DAG: %[[C6:.*]] = arith.constant 6 : i32 451// CHECK: %[[INDEX_CAST:.*]] = arith.index_castui %[[FLAG]] 452// CHECK-NEXT: %[[INDEX_SWITCH:.*]]:2 = scf.index_switch %[[INDEX_CAST]] 453// CHECK: case 0 454// CHECK-NEXT: scf.yield %[[C5]], %[[C1]] 455// CHECK: case 1 456// CHECK-NEXT: scf.yield %[[C6]], %[[C1]] 457// CHECK: default 458// CHECK-NEXT: scf.yield %[[POISON]], %[[C0]] 459// CHECK: cf.switch %[[INDEX_SWITCH]]#1 460// CHECK-NEXT: default: ^[[BB2:[[:alnum:]]+]] 461// CHECK-SAME: %[[INDEX_SWITCH]]#0 462// CHECK-NEXT: 0: ^[[BB1:[[:alnum:]]+]] 463// CHECK-NEXT: ] 464 465// CHECK: ^[[BB2]]{{.*}}: 466// CHECK: scf.while 467// CHECK-NOT: cf.{{(switch|(cond_)?br)}} 468// CHECK: return 469 470// CHECK: ^[[BB1]]: 471// CHECK-NEXT: "test.returnLike" 472 473// ----- 474 475func.func @select_like(%cond: i1) -> i32 { 476 %0 = arith.constant 0 : i32 477 %1 = arith.constant 1 : i32 478 cf.cond_br %cond, ^bb0(%0 : i32), ^bb0(%1 : i32) 479^bb0(%arg: i32): 480 return %arg : i32 481} 482 483// CHECK-LABEL: func @select_like 484// CHECK-SAME: %[[COND:.*]]: i1 485// CHECK-DAG: %[[C0:.*]] = arith.constant 0 486// CHECK-DAG: %[[C1:.*]] = arith.constant 1 487// CHECK-NEXT: %[[RES:.*]] = scf.if %[[COND]] 488// CHECK-NEXT: scf.yield %[[C0]] 489// CHECK-NEXT: else 490// CHECK-NEXT: scf.yield %[[C1]] 491// CHECK: return %[[RES]] 492 493// ----- 494 495func.func @return_like_dominated_by_condition(%cond1: i1, %cond2: i1, %cond3: i1) { 496 cf.cond_br %cond1, ^bb1, ^bb2 497 498^bb1: 499 return 500 501^bb2: 502 cf.cond_br %cond2, ^bb3, ^bb4 503 504^bb3: 505 "test.unreachable"() : () -> () 506 507^bb4: 508 cf.cond_br %cond3, ^bb3, ^bb5 509 510^bb5: 511 return 512} 513 514// CHECK-LABEL: func @return_like_dominated_by_condition 515// CHECK-SAME: %[[COND1:[[:alnum:]]+]] 516// CHECK-SAME: %[[COND2:[[:alnum:]]+]] 517// CHECK-SAME: %[[COND3:[[:alnum:]]+]] 518// CHECK-DAG: %[[C0:.*]] = arith.constant 0 519// CHECK-DAG: %[[C1:.*]] = arith.constant 1 520// CHECK: %[[IF:.*]] = scf.if %[[COND1]] 521// CHECK-NEXT: scf.yield 522// CHECK: else 523// CHECK: scf.if %[[COND2]] 524// CHECK-NEXT: scf.yield 525// CHECK: else 526// CHECK: scf.if %[[COND3]] 527// CHECK-NEXT: scf.yield 528// CHECK-NEXT: else 529// CHECK-NEXT: scf.yield 530 531// CHECK: cf.switch %[[IF]] 532// CHECK-NEXT: default: ^[[BB1:.*]], 533// CHECK-NEXT: 0: ^[[BB2:[[:alnum:]]+]] 534 535// CHECK: ^[[BB2]]: 536// CHECK-NEXT: return 537 538// CHECK: ^[[BB1]]: 539// CHECK-NEXT: "test.unreachable" 540 541// ----- 542 543func.func @dominator_issue(%cond: i1, %cond2: i1) -> i32 { 544 cf.cond_br %cond, ^bb1, ^bb2 545 546^bb1: 547 "test.unreachable"() : () -> () 548 549^bb2: 550 %value = "test.def"() : () -> i32 551 cf.cond_br %cond2, ^bb1, ^bb4 552 553^bb4: 554 return %value : i32 555} 556 557// CHECK-LABEL: func @dominator_issue 558// CHECK-SAME: %[[COND1:[[:alnum:]]+]] 559// CHECK-SAME: %[[COND2:[[:alnum:]]+]] 560// CHECK: %[[IF:.*]]:2 = scf.if %[[COND1]] 561// CHECK: else 562// CHECK: %[[VALUE:.*]] = "test.def" 563// CHECK: %[[IF_RES:.*]]:2 = scf.if %[[COND2]] 564// CHECK: else 565// CHECK-NEXT: scf.yield %[[VALUE]] 566// CHECK: scf.yield %[[IF_RES]]#0 567// CHECK: cf.switch %[[IF]]#1 568// CHECK-NEXT: default: ^[[BB2:[[:alnum:]]+]]( 569// CHECK-SAME: %[[IF]]#0 570// CHECK-NEXT: 0: ^[[BB1:[[:alnum:]]+]] 571// CHECK: ^[[BB1]]: 572// CHECK-NEXT: "test.unreachable" 573// CHECK: ^[[BB2]] 574// CHECK-SAME: %[[ARG:[[:alnum:]]+]] 575// CHECK-NEXT: return %[[ARG]] 576 577// ----- 578 579// Test that %value gets properly passed to ^bb4. 580 581func.func private @bar(i32) 582 583func.func @dominator_issue_loop(%cond: i1, %cond2: i1) -> i32 { 584 %0 = arith.constant 5 : i32 585 cf.br ^bb0 586 587^bb0: 588 cf.cond_br %cond, ^bb1, ^bb3 589 590^bb1: 591 %value = "test.def"() : () -> i32 592 cf.cond_br %cond2, ^bb0, ^bb4 593 594^bb3: 595 return %0 : i32 596 597^bb4: 598 return %value : i32 599} 600 601// CHECK-LABEL: func @dominator_issue_loop 602// CHECK-SAME: %[[COND1:[[:alnum:]]+]] 603// CHECK-SAME: %[[COND2:[[:alnum:]]+]] 604// CHECK: %[[WHILE:.*]]:2 = scf.while 605// CHECK: %[[IF:.*]]:3 = scf.if %[[COND1]] 606// CHECK: %[[DEF:.*]] = "test.def" 607// CHECK: %[[IF2:.*]]:3 = scf.if %[[COND2]] 608// CHECK: scf.yield 609// CHECK-SAME: %[[DEF]] 610// CHECK: else 611// CHECK: scf.yield %{{.*}}, %{{.*}}, %[[DEF]] 612// CHECK: scf.yield %[[IF2]]#0, %[[IF2]]#1, %[[IF2]]#2 613// CHECK: scf.condition(%{{.*}}) %[[IF]]#2, %[[IF]]#0 614 615// CHECK: %[[SWITCH:.*]] = scf.index_switch 616// CHECK: scf.yield %[[WHILE]]#0 617// CHECK: return %[[SWITCH]] 618 619// ----- 620 621// Multi entry loops generally produce code in dire need of canonicalization. 622 623func.func private @comp1(%arg: i32) -> i1 624func.func private @comp2(%arg: i32) -> i1 625func.func private @foo(%arg: i32) 626 627func.func @multi_entry_loop(%cond: i1) { 628 %0 = arith.constant 6 : i32 629 %1 = arith.constant 5 : i32 630 cf.cond_br %cond, ^bb0, ^bb1 631 632^bb0: 633 %exit = call @comp1(%0) : (i32) -> i1 634 cf.cond_br %exit, ^bb2(%0 : i32), ^bb1 635 636^bb1: 637 %exit2 = call @comp2(%1) : (i32) -> i1 638 cf.cond_br %exit2, ^bb2(%1 : i32), ^bb0 639 640^bb2(%arg3 : i32): 641 call @foo(%arg3) : (i32) -> () 642 return 643} 644 645// CHECK-LABEL: func @multi_entry_loop 646// CHECK-SAME: %[[ARG0:[[:alnum:]]+]] 647// CHECK-DAG: %[[C0:.*]] = arith.constant 0 648// CHECK-DAG: %[[UB:.*]] = ub.poison 649// CHECK-DAG: %[[C1:.*]] = arith.constant 1 650// CHECK-DAG: %[[C6:.*]] = arith.constant 6 651// CHECK-DAG: %[[C5:.*]] = arith.constant 5 652// CHECK: %[[IF:.*]]:{{.*}} = scf.if %[[ARG0]] 653// CHECK-NEXT: scf.yield %[[C1]], %[[UB]] 654// CHECK-NEXT: else 655// CHECK-NEXT: scf.yield %[[C0]], %[[UB]] 656// CHECK: %[[WHILE:.*]]:{{.*}} = scf.while 657// CHECK-SAME: %[[ARG1:.*]] = %[[IF]]#0 658// CHECK-SAME: %[[ARG2:.*]] = %[[IF]]#1 659// CHECK-NEXT: %[[FLAG:.*]] = arith.index_castui %[[ARG1]] 660// CHECK-NEXT: %[[SWITCH:.*]]:{{.*}} = scf.index_switch %[[FLAG]] 661// CHECK-NEXT: case 0 662// CHECK-NEXT: %[[EXIT:.*]] = func.call @comp2(%[[C5]]) 663// CHECK-NEXT: %[[IF_RES:.*]]:{{.*}} = scf.if %[[EXIT]] 664// CHECK-NEXT: scf.yield %[[UB]], %[[C5]], %[[C1]], %[[C0]] 665// CHECK-NEXT: else 666// CHECK-NEXT: scf.yield %[[C1]], %[[UB]], %[[C0]], %[[C1]] 667// CHECK: scf.yield %[[IF_RES]]#0, %[[IF_RES]]#1, %[[IF_RES]]#2, %[[IF_RES]]#3 668// CHECK: default 669// CHECK-NEXT: %[[EXIT:.*]] = func.call @comp1(%[[C6]]) 670// CHECK-NEXT: %[[IF_RES:.*]]:{{.*}} = scf.if %[[EXIT]] 671// CHECK-NEXT: scf.yield %[[UB]], %[[C6]], %[[C1]], %[[C0]] 672// CHECK-NEXT: else 673// CHECK-NEXT: scf.yield %[[C0]], %[[UB]], %[[C0]], %[[C1]] 674// CHECK: scf.yield %[[IF_RES]]#0, %[[IF_RES]]#1, %[[IF_RES]]#2, %[[IF_RES]]#3 675// CHECK: %[[COND:.*]] = arith.trunci %[[SWITCH]]#3 676// CHECK-NEXT: scf.condition(%[[COND]]) %[[SWITCH]]#0, %[[SWITCH]]#1 677// CHECK: do 678// CHECK: scf.yield 679// CHECK: call @foo(%[[WHILE]]#1) 680// CHECK-NEXT: return 681 682// ----- 683 684func.func @nested_region() { 685 scf.execute_region { 686 %cond = "test.test1"() : () -> i1 687 cf.cond_br %cond, ^bb1, ^bb2 688 ^bb1: 689 "test.test2"() : () -> () 690 cf.br ^bb3 691 ^bb2: 692 "test.test3"() : () -> () 693 cf.br ^bb3 694 ^bb3: 695 "test.test4"() : () -> () 696 scf.yield 697 } 698 return 699} 700 701// CHECK-LABEL: func @nested_region 702// CHECK: scf.execute_region { 703// CHECK: %[[COND:.*]] = "test.test1"() 704// CHECK-NEXT: scf.if %[[COND]] 705// CHECK-NEXT: "test.test2"() 706// CHECK-NEXT: else 707// CHECK-NEXT: "test.test3"() 708// CHECK-NEXT: } 709// CHECK-NEXT: "test.test4"() 710// CHECK-NEXT: scf.yield 711// CHECK-NEXT: } 712// CHECK-NEXT: return 713 714// ----- 715 716func.func @nested_region_inside_loop_use() { 717 cf.br ^bb1 718 719^bb1: 720 %3 = "test.test1"() : () -> i32 721 scf.execute_region { 722 "test.foo"(%3) : (i32) -> () 723 scf.yield 724 } 725 cf.br ^bb1 726} 727 728// CHECK-LABEL: func @nested_region_inside_loop_use 729// CHECK: scf.while 730// CHECK-NEXT: %[[DEF:.*]] = "test.test1"() 731// CHECK-NEXT: scf.execute_region 732// CHECK-NEXT: "test.foo"(%[[DEF]]) 733 734// ----- 735 736func.func @nested_region_outside_loop_use() { 737 cf.br ^bb1 738 739^bb1: 740 %3 = "test.test1"() : () -> i32 741 %cond = "test.test2"() : () -> i1 742 cf.cond_br %cond, ^bb1, ^bb2 743 744^bb2: 745 scf.execute_region { 746 "test.foo"(%3) : (i32) -> () 747 scf.yield 748 } 749 return 750} 751 752// CHECK-LABEL: func @nested_region_outside_loop_use 753// CHECK: %[[RES:.*]] = scf.while 754// CHECK: %[[DEF:.*]] = "test.test1"() 755// CHECK: scf.condition(%{{.*}}) %[[DEF]] 756 757// CHECK: scf.execute_region 758// CHECK-NEXT: "test.foo"(%[[RES]]) 759