772 lines · plain
1// RUN: mlir-opt -allow-unregistered-dialect -convert-scf-to-cf -split-input-file %s | FileCheck %s2// RUN: mlir-opt -allow-unregistered-dialect -convert-scf-to-cf="allow-pattern-rollback=0" -split-input-file %s | FileCheck %s3 4// CHECK-LABEL: func @simple_std_for_loop(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {5// CHECK-NEXT: cf.br ^bb1(%{{.*}} : index)6// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb27// CHECK-NEXT: %{{.*}} = arith.cmpi slt, %{{.*}}, %{{.*}} : index8// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb2, ^bb39// CHECK-NEXT: ^bb2: // pred: ^bb110// CHECK-NEXT: %{{.*}} = arith.constant 1 : index11// CHECK-NEXT: %[[iv:.*]] = arith.addi %{{.*}}, %{{.*}} : index12// CHECK-NEXT: cf.br ^bb1(%[[iv]] : index)13// CHECK-NEXT: ^bb3: // pred: ^bb114// CHECK-NEXT: return15func.func @simple_std_for_loop(%arg0 : index, %arg1 : index, %arg2 : index) {16 scf.for %i0 = %arg0 to %arg1 step %arg2 {17 %c1 = arith.constant 1 : index18 }19 return20}21 22// CHECK-LABEL: func @unsigned_loop(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {23// CHECK-NEXT: cf.br ^bb1(%{{.*}} : index)24// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb225// CHECK-NEXT: %{{.*}} = arith.cmpi ult, %{{.*}}, %{{.*}} : index26// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb2, ^bb327// CHECK-NEXT: ^bb2: // pred: ^bb128// CHECK-NEXT: %{{.*}} = arith.constant 1 : index29// CHECK-NEXT: %[[iv:.*]] = arith.addi %{{.*}}, %{{.*}} : index30// CHECK-NEXT: cf.br ^bb1(%[[iv]] : index)31// CHECK-NEXT: ^bb3: // pred: ^bb132// CHECK-NEXT: return33func.func @unsigned_loop(%arg0 : index, %arg1 : index, %arg2 : index) {34 scf.for unsigned %i0 = %arg0 to %arg1 step %arg2 {35 %c1 = arith.constant 1 : index36 }37 return38}39 40// CHECK-LABEL: func @simple_std_2_for_loops(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index) {41// CHECK-NEXT: cf.br ^bb1(%{{.*}} : index)42// CHECK-NEXT: ^bb1(%[[ub0:.*]]: index): // 2 preds: ^bb0, ^bb543// CHECK-NEXT: %[[cond0:.*]] = arith.cmpi slt, %[[ub0]], %{{.*}} : index44// CHECK-NEXT: cf.cond_br %[[cond0]], ^bb2, ^bb645// CHECK-NEXT: ^bb2: // pred: ^bb146// CHECK-NEXT: %{{.*}} = arith.constant 1 : index47// CHECK-NEXT: cf.br ^bb3(%{{.*}} : index)48// CHECK-NEXT: ^bb3(%[[ub1:.*]]: index): // 2 preds: ^bb2, ^bb449// CHECK-NEXT: %[[cond1:.*]] = arith.cmpi slt, %{{.*}}, %{{.*}} : index50// CHECK-NEXT: cf.cond_br %[[cond1]], ^bb4, ^bb551// CHECK-NEXT: ^bb4: // pred: ^bb352// CHECK-NEXT: %{{.*}} = arith.constant 1 : index53// CHECK-NEXT: %[[iv1:.*]] = arith.addi %{{.*}}, %{{.*}} : index54// CHECK-NEXT: cf.br ^bb3(%[[iv1]] : index)55// CHECK-NEXT: ^bb5: // pred: ^bb356// CHECK-NEXT: %[[iv0:.*]] = arith.addi %{{.*}}, %{{.*}} : index57// CHECK-NEXT: cf.br ^bb1(%[[iv0]] : index)58// CHECK-NEXT: ^bb6: // pred: ^bb159// CHECK-NEXT: return60func.func @simple_std_2_for_loops(%arg0 : index, %arg1 : index, %arg2 : index) {61 scf.for %i0 = %arg0 to %arg1 step %arg2 {62 %c1 = arith.constant 1 : index63 scf.for %i1 = %arg0 to %arg1 step %arg2 {64 %c1_0 = arith.constant 1 : index65 }66 }67 return68}69 70// CHECK-LABEL: func @simple_std_if(%{{.*}}: i1) {71// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb1, ^bb272// CHECK-NEXT: ^bb1: // pred: ^bb073// CHECK-NEXT: %{{.*}} = arith.constant 1 : index74// CHECK-NEXT: cf.br ^bb275// CHECK-NEXT: ^bb2: // 2 preds: ^bb0, ^bb176// CHECK-NEXT: return77func.func @simple_std_if(%arg0: i1) {78 scf.if %arg0 {79 %c1 = arith.constant 1 : index80 }81 return82}83 84// CHECK-LABEL: func @simple_std_if_else(%{{.*}}: i1) {85// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb1, ^bb286// CHECK-NEXT: ^bb1: // pred: ^bb087// CHECK-NEXT: %{{.*}} = arith.constant 1 : index88// CHECK-NEXT: cf.br ^bb389// CHECK-NEXT: ^bb2: // pred: ^bb090// CHECK-NEXT: %{{.*}} = arith.constant 1 : index91// CHECK-NEXT: cf.br ^bb392// CHECK-NEXT: ^bb3: // 2 preds: ^bb1, ^bb293// CHECK-NEXT: return94func.func @simple_std_if_else(%arg0: i1) {95 scf.if %arg0 {96 %c1 = arith.constant 1 : index97 } else {98 %c1_0 = arith.constant 1 : index99 }100 return101}102 103// CHECK-LABEL: func @simple_std_2_ifs(%{{.*}}: i1) {104// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb1, ^bb5105// CHECK-NEXT: ^bb1: // pred: ^bb0106// CHECK-NEXT: %{{.*}} = arith.constant 1 : index107// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb2, ^bb3108// CHECK-NEXT: ^bb2: // pred: ^bb1109// CHECK-NEXT: %{{.*}} = arith.constant 1 : index110// CHECK-NEXT: cf.br ^bb4111// CHECK-NEXT: ^bb3: // pred: ^bb1112// CHECK-NEXT: %{{.*}} = arith.constant 1 : index113// CHECK-NEXT: cf.br ^bb4114// CHECK-NEXT: ^bb4: // 2 preds: ^bb2, ^bb3115// CHECK-NEXT: cf.br ^bb5116// CHECK-NEXT: ^bb5: // 2 preds: ^bb0, ^bb4117// CHECK-NEXT: return118func.func @simple_std_2_ifs(%arg0: i1) {119 scf.if %arg0 {120 %c1 = arith.constant 1 : index121 scf.if %arg0 {122 %c1_0 = arith.constant 1 : index123 } else {124 %c1_1 = arith.constant 1 : index125 }126 }127 return128}129 130// CHECK-LABEL: func @simple_std_for_loop_with_2_ifs(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index, %{{.*}}: i1) {131// CHECK-NEXT: cf.br ^bb1(%{{.*}} : index)132// CHECK-NEXT: ^bb1(%{{.*}}: index): // 2 preds: ^bb0, ^bb7133// CHECK-NEXT: %{{.*}} = arith.cmpi slt, %{{.*}}, %{{.*}} : index134// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb2, ^bb8135// CHECK-NEXT: ^bb2: // pred: ^bb1136// CHECK-NEXT: %{{.*}} = arith.constant 1 : index137// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb3, ^bb7138// CHECK-NEXT: ^bb3: // pred: ^bb2139// CHECK-NEXT: %{{.*}} = arith.constant 1 : index140// CHECK-NEXT: cf.cond_br %{{.*}}, ^bb4, ^bb5141// CHECK-NEXT: ^bb4: // pred: ^bb3142// CHECK-NEXT: %{{.*}} = arith.constant 1 : index143// CHECK-NEXT: cf.br ^bb6144// CHECK-NEXT: ^bb5: // pred: ^bb3145// CHECK-NEXT: %{{.*}} = arith.constant 1 : index146// CHECK-NEXT: cf.br ^bb6147// CHECK-NEXT: ^bb6: // 2 preds: ^bb4, ^bb5148// CHECK-NEXT: cf.br ^bb7149// CHECK-NEXT: ^bb7: // 2 preds: ^bb2, ^bb6150// CHECK-NEXT: %[[iv0:.*]] = arith.addi %{{.*}}, %{{.*}} : index151// CHECK-NEXT: cf.br ^bb1(%[[iv0]] : index)152// CHECK-NEXT: ^bb8: // pred: ^bb1153// CHECK-NEXT: return154// CHECK-NEXT: }155func.func @simple_std_for_loop_with_2_ifs(%arg0 : index, %arg1 : index, %arg2 : index, %arg3 : i1) {156 scf.for %i0 = %arg0 to %arg1 step %arg2 {157 %c1 = arith.constant 1 : index158 scf.if %arg3 {159 %c1_0 = arith.constant 1 : index160 scf.if %arg3 {161 %c1_1 = arith.constant 1 : index162 } else {163 %c1_2 = arith.constant 1 : index164 }165 }166 }167 return168}169 170// CHECK-LABEL: func @simple_if_yield171func.func @simple_if_yield(%arg0: i1) -> (i1, i1) {172// CHECK: cf.cond_br %{{.*}}, ^[[then:.*]], ^[[else:.*]]173 %0:2 = scf.if %arg0 -> (i1, i1) {174// CHECK: ^[[then]]:175// CHECK: %[[v0:.*]] = arith.constant false176// CHECK: %[[v1:.*]] = arith.constant true177// CHECK: cf.br ^[[dom:.*]](%[[v0]], %[[v1]] : i1, i1)178 %c0 = arith.constant false179 %c1 = arith.constant true180 scf.yield %c0, %c1 : i1, i1181 } else {182// CHECK: ^[[else]]:183// CHECK: %[[v2:.*]] = arith.constant false184// CHECK: %[[v3:.*]] = arith.constant true185// CHECK: cf.br ^[[dom]](%[[v3]], %[[v2]] : i1, i1)186 %c0 = arith.constant false187 %c1 = arith.constant true188 scf.yield %c1, %c0 : i1, i1189 }190// CHECK: ^[[dom]](%[[arg1:.*]]: i1, %[[arg2:.*]]: i1):191// CHECK: cf.br ^[[cont:.*]]192// CHECK: ^[[cont]]:193// CHECK: return %[[arg1]], %[[arg2]]194 return %0#0, %0#1 : i1, i1195}196 197// CHECK-LABEL: func @nested_if_yield198func.func @nested_if_yield(%arg0: i1) -> (index) {199// CHECK: cf.cond_br %{{.*}}, ^[[first_then:.*]], ^[[first_else:.*]]200 %0 = scf.if %arg0 -> i1 {201// CHECK: ^[[first_then]]:202 %1 = arith.constant true203// CHECK: cf.br ^[[first_dom:.*]]({{.*}})204 scf.yield %1 : i1205 } else {206// CHECK: ^[[first_else]]:207 %2 = arith.constant false208// CHECK: cf.br ^[[first_dom]]({{.*}})209 scf.yield %2 : i1210 }211// CHECK: ^[[first_dom]](%[[arg1:.*]]: i1):212// CHECK: cf.br ^[[first_cont:.*]]213// CHECK: ^[[first_cont]]:214// CHECK: cf.cond_br %[[arg1]], ^[[second_outer_then:.*]], ^[[second_outer_else:.*]]215 %1 = scf.if %0 -> index {216// CHECK: ^[[second_outer_then]]:217// CHECK: cf.cond_br %arg0, ^[[second_inner_then:.*]], ^[[second_inner_else:.*]]218 %3 = scf.if %arg0 -> index {219// CHECK: ^[[second_inner_then]]:220 %4 = arith.constant 40 : index221// CHECK: cf.br ^[[second_inner_dom:.*]]({{.*}})222 scf.yield %4 : index223 } else {224// CHECK: ^[[second_inner_else]]:225 %5 = arith.constant 41 : index226// CHECK: cf.br ^[[second_inner_dom]]({{.*}})227 scf.yield %5 : index228 }229// CHECK: ^[[second_inner_dom]](%[[arg2:.*]]: index):230// CHECK: cf.br ^[[second_inner_cont:.*]]231// CHECK: ^[[second_inner_cont]]:232// CHECK: cf.br ^[[second_outer_dom:.*]]({{.*}})233 scf.yield %3 : index234 } else {235// CHECK: ^[[second_outer_else]]:236 %6 = arith.constant 42 : index237// CHECK: cf.br ^[[second_outer_dom]]({{.*}}238 scf.yield %6 : index239 }240// CHECK: ^[[second_outer_dom]](%[[arg3:.*]]: index):241// CHECK: cf.br ^[[second_outer_cont:.*]]242// CHECK: ^[[second_outer_cont]]:243// CHECK: return %[[arg3]] : index244 return %1 : index245}246 247// CHECK-LABEL: func @parallel_loop(248// CHECK-SAME: [[VAL_0:%.*]]: index, [[VAL_1:%.*]]: index, [[VAL_2:%.*]]: index, [[VAL_3:%.*]]: index, [[VAL_4:%.*]]: index) {249// CHECK: [[VAL_5:%.*]] = arith.constant 1 : index250// CHECK: cf.br ^bb1([[VAL_0]] : index)251// CHECK: ^bb1([[VAL_6:%.*]]: index):252// CHECK: [[VAL_7:%.*]] = arith.cmpi slt, [[VAL_6]], [[VAL_2]] : index253// CHECK: cf.cond_br [[VAL_7]], ^bb2, ^bb6254// CHECK: ^bb2:255// CHECK: cf.br ^bb3([[VAL_1]] : index)256// CHECK: ^bb3([[VAL_8:%.*]]: index):257// CHECK: [[VAL_9:%.*]] = arith.cmpi slt, [[VAL_8]], [[VAL_3]] : index258// CHECK: cf.cond_br [[VAL_9]], ^bb4, ^bb5259// CHECK: ^bb4:260// CHECK: [[VAL_10:%.*]] = arith.constant 1 : index261// CHECK: [[VAL_11:%.*]] = arith.addi [[VAL_8]], [[VAL_5]] : index262// CHECK: cf.br ^bb3([[VAL_11]] : index)263// CHECK: ^bb5:264// CHECK: [[VAL_12:%.*]] = arith.addi [[VAL_6]], [[VAL_4]] : index265// CHECK: cf.br ^bb1([[VAL_12]] : index)266// CHECK: ^bb6:267// CHECK: return268// CHECK: }269 270func.func @parallel_loop(%arg0 : index, %arg1 : index, %arg2 : index,271 %arg3 : index, %arg4 : index) {272 %step = arith.constant 1 : index273 scf.parallel (%i0, %i1) = (%arg0, %arg1) to (%arg2, %arg3)274 step (%arg4, %step) {275 %c1 = arith.constant 1 : index276 scf.reduce277 }278 return279}280 281// CHECK-LABEL: @for_yield282// CHECK-SAME: (%[[LB:.*]]: index, %[[UB:.*]]: index, %[[STEP:.*]]: index)283// CHECK: %[[INIT0:.*]] = arith.constant 0284// CHECK: %[[INIT1:.*]] = arith.constant 1285// CHECK: cf.br ^[[COND:.*]](%[[LB]], %[[INIT0]], %[[INIT1]] : index, f32, f32)286//287// CHECK: ^[[COND]](%[[ITER:.*]]: index, %[[ITER_ARG0:.*]]: f32, %[[ITER_ARG1:.*]]: f32):288// CHECK: %[[CMP:.*]] = arith.cmpi slt, %[[ITER]], %[[UB]] : index289// CHECK: cf.cond_br %[[CMP]], ^[[BODY:.*]], ^[[CONTINUE:.*]]290//291// CHECK: ^[[BODY]]:292// CHECK: %[[SUM:.*]] = arith.addf %[[ITER_ARG0]], %[[ITER_ARG1]] : f32293// CHECK: %[[STEPPED:.*]] = arith.addi %[[ITER]], %[[STEP]] : index294// CHECK: cf.br ^[[COND]](%[[STEPPED]], %[[SUM]], %[[SUM]] : index, f32, f32)295//296// CHECK: ^[[CONTINUE]]:297// CHECK: return %[[ITER_ARG0]], %[[ITER_ARG1]] : f32, f32298func.func @for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> (f32, f32) {299 %s0 = arith.constant 0.0 : f32300 %s1 = arith.constant 1.0 : f32301 %result:2 = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%si = %s0, %sj = %s1) -> (f32, f32) {302 %sn = arith.addf %si, %sj : f32303 scf.yield %sn, %sn : f32, f32304 }305 return %result#0, %result#1 : f32, f32306}307 308// CHECK-LABEL: @nested_for_yield309// CHECK-SAME: (%[[LB:.*]]: index, %[[UB:.*]]: index, %[[STEP:.*]]: index)310// CHECK: %[[INIT:.*]] = arith.constant311// CHECK: cf.br ^[[COND_OUT:.*]](%[[LB]], %[[INIT]] : index, f32)312// CHECK: ^[[COND_OUT]](%[[ITER_OUT:.*]]: index, %[[ARG_OUT:.*]]: f32):313// CHECK: cf.cond_br %{{.*}}, ^[[BODY_OUT:.*]], ^[[CONT_OUT:.*]]314// CHECK: ^[[BODY_OUT]]:315// CHECK: cf.br ^[[COND_IN:.*]](%[[LB]], %[[ARG_OUT]] : index, f32)316// CHECK: ^[[COND_IN]](%[[ITER_IN:.*]]: index, %[[ARG_IN:.*]]: f32):317// CHECK: cf.cond_br %{{.*}}, ^[[BODY_IN:.*]], ^[[CONT_IN:.*]]318// CHECK: ^[[BODY_IN]]319// CHECK: %[[RES:.*]] = arith.addf320// CHECK: cf.br ^[[COND_IN]](%{{.*}}, %[[RES]] : index, f32)321// CHECK: ^[[CONT_IN]]:322// CHECK: cf.br ^[[COND_OUT]](%{{.*}}, %[[ARG_IN]] : index, f32)323// CHECK: ^[[CONT_OUT]]:324// CHECK: return %[[ARG_OUT]] : f32325func.func @nested_for_yield(%arg0 : index, %arg1 : index, %arg2 : index) -> f32 {326 %s0 = arith.constant 1.0 : f32327 %r = scf.for %i0 = %arg0 to %arg1 step %arg2 iter_args(%iter = %s0) -> (f32) {328 %result = scf.for %i1 = %arg0 to %arg1 step %arg2 iter_args(%si = %iter) -> (f32) {329 %sn = arith.addf %si, %si : f32330 scf.yield %sn : f32331 }332 scf.yield %result : f32333 }334 return %r : f32335}336 337func.func private @generate() -> i64338 339// CHECK-LABEL: @simple_parallel_reduce_loop340// CHECK-SAME: %[[LB:.*]]: index, %[[UB:.*]]: index, %[[STEP:.*]]: index, %[[INIT:.*]]: f32341func.func @simple_parallel_reduce_loop(%arg0: index, %arg1: index,342 %arg2: index, %arg3: f32) -> f32 {343 // A parallel loop with reduction is converted through sequential loops with344 // reductions into a CFG of blocks where the partially reduced value is345 // passed across as a block argument.346 347 // Branch to the condition block passing in the initial reduction value.348 // CHECK: cf.br ^[[COND:.*]](%[[LB]], %[[INIT]]349 350 // Condition branch takes as arguments the current value of the iteration351 // variable and the current partially reduced value.352 // CHECK: ^[[COND]](%[[ITER:.*]]: index, %[[ITER_ARG:.*]]: f32353 // CHECK: %[[COMP:.*]] = arith.cmpi slt, %[[ITER]], %[[UB]]354 // CHECK: cf.cond_br %[[COMP]], ^[[BODY:.*]], ^[[CONTINUE:.*]]355 356 // Bodies of scf.reduce operations are folded into the main loop body. The357 // result of this partial reduction is passed as argument to the condition358 // block.359 // CHECK: ^[[BODY]]:360 // CHECK: %[[CST:.*]] = arith.constant 4.2361 // CHECK: %[[PROD:.*]] = arith.mulf %[[ITER_ARG]], %[[CST]]362 // CHECK: %[[INCR:.*]] = arith.addi %[[ITER]], %[[STEP]]363 // CHECK: cf.br ^[[COND]](%[[INCR]], %[[PROD]]364 365 // The continuation block has access to the (last value of) reduction.366 // CHECK: ^[[CONTINUE]]:367 // CHECK: return %[[ITER_ARG]]368 %0 = scf.parallel (%i) = (%arg0) to (%arg1) step (%arg2) init(%arg3) -> f32 {369 %cst = arith.constant 42.0 : f32370 scf.reduce(%cst : f32) {371 ^bb0(%lhs: f32, %rhs: f32):372 %1 = arith.mulf %lhs, %rhs : f32373 scf.reduce.return %1 : f32374 }375 }376 return %0 : f32377}378 379// CHECK-LABEL: parallel_reduce_loop380// CHECK-SAME: %[[INIT1:[0-9A-Za-z_]*]]: f32)381func.func @parallel_reduce_loop(%arg0 : index, %arg1 : index, %arg2 : index,382 %arg3 : index, %arg4 : index, %arg5 : f32) -> (f32, i64) {383 // Multiple reduction blocks should be folded in the same body, and the384 // reduction value must be forwarded through block structures.385 // CHECK: %[[INIT2:.*]] = arith.constant 42386 // CHECK: cf.br ^[[COND_OUT:.*]](%{{.*}}, %[[INIT1]], %[[INIT2]]387 // CHECK: ^[[COND_OUT]](%{{.*}}: index, %[[ITER_ARG1_OUT:.*]]: f32, %[[ITER_ARG2_OUT:.*]]: i64388 // CHECK: cf.cond_br %{{.*}}, ^[[BODY_OUT:.*]], ^[[CONT_OUT:.*]]389 // CHECK: ^[[BODY_OUT]]:390 // CHECK: cf.br ^[[COND_IN:.*]](%{{.*}}, %[[ITER_ARG1_OUT]], %[[ITER_ARG2_OUT]]391 // CHECK: ^[[COND_IN]](%{{.*}}: index, %[[ITER_ARG1_IN:.*]]: f32, %[[ITER_ARG2_IN:.*]]: i64392 // CHECK: cf.cond_br %{{.*}}, ^[[BODY_IN:.*]], ^[[CONT_IN:.*]]393 // CHECK: ^[[BODY_IN]]:394 // CHECK: %[[REDUCE1:.*]] = arith.addf %[[ITER_ARG1_IN]], %{{.*}}395 // CHECK: %[[REDUCE2:.*]] = arith.ori %[[ITER_ARG2_IN]], %{{.*}}396 // CHECK: cf.br ^[[COND_IN]](%{{.*}}, %[[REDUCE1]], %[[REDUCE2]]397 // CHECK: ^[[CONT_IN]]:398 // CHECK: cf.br ^[[COND_OUT]](%{{.*}}, %[[ITER_ARG1_IN]], %[[ITER_ARG2_IN]]399 // CHECK: ^[[CONT_OUT]]:400 // CHECK: return %[[ITER_ARG1_OUT]], %[[ITER_ARG2_OUT]]401 %step = arith.constant 1 : index402 %init = arith.constant 42 : i64403 %0:2 = scf.parallel (%i0, %i1) = (%arg0, %arg1) to (%arg2, %arg3)404 step (%arg4, %step) init(%arg5, %init) -> (f32, i64) {405 %cf = arith.constant 42.0 : f32406 %2 = func.call @generate() : () -> i64407 scf.reduce(%cf, %2 : f32, i64) {408 ^bb0(%lhs: f32, %rhs: f32):409 %1 = arith.addf %lhs, %rhs : f32410 scf.reduce.return %1 : f32411 }, {412 ^bb0(%lhs: i64, %rhs: i64):413 %3 = arith.ori %lhs, %rhs : i64414 scf.reduce.return %3 : i64415 }416 }417 return %0#0, %0#1 : f32, i64418}419 420// Check that the conversion is not overly conservative wrt unknown ops, i.e.421// that the presence of unknown ops does not prevent the conversion from being422// applied.423// CHECK-LABEL: @unknown_op_inside_loop424func.func @unknown_op_inside_loop(%arg0: index, %arg1: index, %arg2: index) {425 // CHECK-NOT: scf.for426 scf.for %i = %arg0 to %arg1 step %arg2 {427 // CHECK: unknown.op428 "unknown.op"() : () -> ()429 scf.yield430 }431 return432}433 434// CHECK-LABEL: @minimal_while435func.func @minimal_while() {436 // CHECK: %[[COND:.*]] = "test.make_condition"() : () -> i1437 // CHECK: cf.br ^[[BEFORE:.*]]438 %0 = "test.make_condition"() : () -> i1439 scf.while : () -> () {440 // CHECK: ^[[BEFORE]]:441 // CHECK: cf.cond_br %[[COND]], ^[[AFTER:.*]], ^[[CONT:.*]]442 scf.condition(%0)443 } do {444 // CHECK: ^[[AFTER]]:445 // CHECK: "test.some_payload"() : () -> ()446 "test.some_payload"() : () -> ()447 // CHECK: cf.br ^[[BEFORE]]448 scf.yield449 }450 // CHECK: ^[[CONT]]:451 // CHECK: return452 return453}454 455// CHECK-LABEL: @do_while456func.func @do_while(%arg0: f32) {457 // CHECK: cf.br ^[[BEFORE:.*]]({{.*}}: f32)458 scf.while (%arg1 = %arg0) : (f32) -> (f32) {459 // CHECK: ^[[BEFORE]](%[[VAL:.*]]: f32):460 // CHECK: %[[COND:.*]] = "test.make_condition"() : () -> i1461 %0 = "test.make_condition"() : () -> i1462 // CHECK: cf.cond_br %[[COND]], ^[[BEFORE]](%[[VAL]] : f32), ^[[CONT:.*]]463 scf.condition(%0) %arg1 : f32464 } do {465 ^bb0(%arg2: f32):466 // CHECK-NOT: cf.br ^[[BEFORE]]467 scf.yield %arg2 : f32468 }469 // CHECK: ^[[CONT]]:470 // CHECK: return471 return472}473 474// CHECK-LABEL: @while_values475// CHECK-SAME: (%[[ARG0:.*]]: i32, %[[ARG1:.*]]: f32)476func.func @while_values(%arg0: i32, %arg1: f32) {477 // CHECK: %[[COND:.*]] = "test.make_condition"() : () -> i1478 %0 = "test.make_condition"() : () -> i1479 %c0_i32 = arith.constant 0 : i32480 %cst = arith.constant 0.000000e+00 : f32481 // CHECK: cf.br ^[[BEFORE:.*]](%[[ARG0]], %[[ARG1]] : i32, f32)482 %1:2 = scf.while (%arg2 = %arg0, %arg3 = %arg1) : (i32, f32) -> (i64, f64) {483 // CHECK: ^bb1(%[[ARG2:.*]]: i32, %[[ARG3:.]]: f32):484 // CHECK: %[[VAL1:.*]] = arith.extui %[[ARG0]] : i32 to i64485 %2 = arith.extui %arg0 : i32 to i64486 // CHECK: %[[VAL2:.*]] = arith.extf %[[ARG3]] : f32 to f64487 %3 = arith.extf %arg3 : f32 to f64488 // CHECK: cf.cond_br %[[COND]],489 // CHECK: ^[[AFTER:.*]](%[[VAL1]], %[[VAL2]] : i64, f64),490 // CHECK: ^[[CONT:.*]]491 scf.condition(%0) %2, %3 : i64, f64492 } do {493 // CHECK: ^[[AFTER]](%[[ARG4:.*]]: i64, %[[ARG5:.*]]: f64):494 ^bb0(%arg2: i64, %arg3: f64):495 // CHECK: cf.br ^[[BEFORE]](%{{.*}}, %{{.*}} : i32, f32)496 scf.yield %c0_i32, %cst : i32, f32497 }498 // CHECK: ^bb3:499 // CHECK: return500 return501}502 503// CHECK-LABEL: @nested_while_ops504func.func @nested_while_ops(%arg0: f32) -> i64 {505 // CHECK: cf.br ^[[OUTER_BEFORE:.*]](%{{.*}} : f32)506 %0 = scf.while(%outer = %arg0) : (f32) -> i64 {507 // CHECK: ^[[OUTER_BEFORE]](%{{.*}}: f32):508 // CHECK: %[[OUTER_COND:.*]] = "test.outer_before_pre"() : () -> i1509 %cond = "test.outer_before_pre"() : () -> i1510 // CHECK: cf.br ^[[INNER_BEFORE_BEFORE:.*]](%{{.*}} : f32)511 %1 = scf.while(%inner = %outer) : (f32) -> i64 {512 // CHECK: ^[[INNER_BEFORE_BEFORE]](%{{.*}}: f32):513 // CHECK: %[[INNER1:.*]]:2 = "test.inner_before"(%{{.*}}) : (f32) -> (i1, i64)514 %2:2 = "test.inner_before"(%inner) : (f32) -> (i1, i64)515 // CHECK: cf.cond_br %[[INNER1]]#0,516 // CHECK: ^[[INNER_BEFORE_AFTER:.*]](%[[INNER1]]#1 : i64),517 // CHECK: ^[[OUTER_BEFORE_LAST:.*]]518 scf.condition(%2#0) %2#1 : i64519 } do {520 // CHECK: ^[[INNER_BEFORE_AFTER]](%{{.*}}: i64):521 ^bb0(%arg1: i64):522 // CHECK: %[[INNER2:.*]] = "test.inner_after"(%{{.*}}) : (i64) -> f32523 %3 = "test.inner_after"(%arg1) : (i64) -> f32524 // CHECK: cf.br ^[[INNER_BEFORE_BEFORE]](%[[INNER2]] : f32)525 scf.yield %3 : f32526 }527 // CHECK: ^[[OUTER_BEFORE_LAST]]:528 // CHECK: "test.outer_before_post"() : () -> ()529 "test.outer_before_post"() : () -> ()530 // CHECK: cf.cond_br %[[OUTER_COND]],531 // CHECK: ^[[OUTER_AFTER:.*]](%[[INNER1]]#1 : i64),532 // CHECK: ^[[CONTINUATION:.*]]533 scf.condition(%cond) %1 : i64534 } do {535 // CHECK: ^[[OUTER_AFTER]](%{{.*}}: i64):536 ^bb2(%arg2: i64):537 // CHECK: "test.outer_after_pre"(%{{.*}}) : (i64) -> ()538 "test.outer_after_pre"(%arg2) : (i64) -> ()539 // CHECK: cf.br ^[[INNER_AFTER_BEFORE:.*]](%{{.*}} : i64)540 %4 = scf.while(%inner = %arg2) : (i64) -> f32 {541 // CHECK: ^[[INNER_AFTER_BEFORE]](%{{.*}}: i64):542 // CHECK: %[[INNER3:.*]]:2 = "test.inner2_before"(%{{.*}}) : (i64) -> (i1, f32)543 %5:2 = "test.inner2_before"(%inner) : (i64) -> (i1, f32)544 // CHECK: cf.cond_br %[[INNER3]]#0,545 // CHECK: ^[[INNER_AFTER_AFTER:.*]](%[[INNER3]]#1 : f32),546 // CHECK: ^[[OUTER_AFTER_LAST:.*]]547 scf.condition(%5#0) %5#1 : f32548 } do {549 // CHECK: ^[[INNER_AFTER_AFTER]](%{{.*}}: f32):550 ^bb3(%arg3: f32):551 // CHECK: %{{.*}} = "test.inner2_after"(%{{.*}}) : (f32) -> i64552 %6 = "test.inner2_after"(%arg3) : (f32) -> i64553 // CHECK: cf.br ^[[INNER_AFTER_BEFORE]](%{{.*}} : i64)554 scf.yield %6 : i64555 }556 // CHECK: ^[[OUTER_AFTER_LAST]]:557 // CHECK: "test.outer_after_post"() : () -> ()558 "test.outer_after_post"() : () -> ()559 // CHECK: cf.br ^[[OUTER_BEFORE]](%[[INNER3]]#1 : f32)560 scf.yield %4 : f32561 }562 // CHECK: ^[[CONTINUATION]]:563 // CHECK: return %{{.*}} : i64564 return %0 : i64565}566 567// CHECK-LABEL: @ifs_in_parallel568// CHECK: (%[[ARG0:.*]]: index, %[[ARG1:.*]]: index, %[[ARG2:.*]]: index, %[[ARG3:.*]]: i1, %[[ARG4:.*]]: i1)569func.func @ifs_in_parallel(%arg1: index, %arg2: index, %arg3: index, %arg4: i1, %arg5: i1) {570 // CHECK: cf.br ^[[LOOP_LATCH:.*]](%[[ARG0]] : index)571 // CHECK: ^[[LOOP_LATCH]](%[[LOOP_IV:.*]]: index):572 // CHECK: %[[LOOP_COND:.*]] = arith.cmpi slt, %[[LOOP_IV]], %[[ARG1]] : index573 // CHECK: cf.cond_br %[[LOOP_COND]], ^[[LOOP_BODY:.*]], ^[[LOOP_CONT:.*]]574 // CHECK: ^[[LOOP_BODY]]:575 // CHECK: cf.cond_br %[[ARG3]], ^[[IF1_THEN:.*]], ^[[IF1_CONT:.*]]576 // CHECK: ^[[IF1_THEN]]:577 // CHECK: cf.cond_br %[[ARG4]], ^[[IF2_THEN:.*]], ^[[IF2_ELSE:.*]]578 // CHECK: ^[[IF2_THEN]]:579 // CHECK: %{{.*}} = "test.if2"() : () -> index580 // CHECK: cf.br ^[[IF2_MERGE:.*]](%{{.*}} : index)581 // CHECK: ^[[IF2_ELSE]]:582 // CHECK: %{{.*}} = "test.else2"() : () -> index583 // CHECK: cf.br ^[[IF2_MERGE]](%{{.*}} : index)584 // CHECK: ^[[IF2_MERGE]](%{{.*}}: index):585 // CHECK: cf.br ^[[IF2_CONT:.*]]586 // CHECK: ^[[IF2_CONT]]:587 // CHECK: cf.br ^[[IF1_CONT]]588 // CHECK: ^[[IF1_CONT]]:589 // CHECK: %{{.*}} = arith.addi %[[LOOP_IV]], %[[ARG2]] : index590 // CHECK: cf.br ^[[LOOP_LATCH]](%{{.*}} : index)591 scf.parallel (%i) = (%arg1) to (%arg2) step (%arg3) {592 scf.if %arg4 {593 %0 = scf.if %arg5 -> (index) {594 %1 = "test.if2"() : () -> index595 scf.yield %1 : index596 } else {597 %2 = "test.else2"() : () -> index598 scf.yield %2 : index599 }600 }601 scf.reduce602 }603 604 // CHECK: ^[[LOOP_CONT]]:605 // CHECK: return606 return607}608 609// CHECK-LABEL: func @func_execute_region_elim_multi_yield610func.func @func_execute_region_elim_multi_yield() {611 "test.foo"() : () -> ()612 %v = scf.execute_region -> i64 {613 %c = "test.cmp"() : () -> i1614 cf.cond_br %c, ^bb2, ^bb3615 ^bb2:616 %x = "test.val1"() : () -> i64617 scf.yield %x : i64618 ^bb3:619 %y = "test.val2"() : () -> i64620 scf.yield %y : i64621 }622 "test.bar"(%v) : (i64) -> ()623 return624}625 626// CHECK-NOT: execute_region627// CHECK: "test.foo"628// CHECK: cf.br ^[[rentry:.+]]629// CHECK: ^[[rentry]]630// CHECK: %[[cmp:.+]] = "test.cmp"631// CHECK: cf.cond_br %[[cmp]], ^[[bb1:.+]], ^[[bb2:.+]]632// CHECK: ^[[bb1]]:633// CHECK: %[[x:.+]] = "test.val1"634// CHECK: cf.br ^[[bb3:.+]](%[[x]] : i64)635// CHECK: ^[[bb2]]:636// CHECK: %[[y:.+]] = "test.val2"637// CHECK: cf.br ^[[bb3]](%[[y:.+]] : i64)638// CHECK: ^[[bb3]](%[[z:.+]]: i64):639// CHECK: "test.bar"(%[[z]])640// CHECK: return641 642// CHECK-LABEL: @index_switch643func.func @index_switch(%i: index, %a: i32, %b: i32, %c: i32) -> i32 {644 // CHECK: %[[CASE:.*]] = arith.index_cast %arg0 : index to i32645 // CHECK: cf.switch %[[CASE]] : i32646 // CHECK-NEXT: default: ^[[DEFAULT:.+]],647 // CHECK-NEXT: 0: ^[[bb1:.+]],648 // CHECK-NEXT: 1: ^[[bb2:.+]]649 %0 = scf.index_switch %i -> i32650 // CHECK: ^[[bb1]]:651 case 0 {652 // CHECK-NEXT: br ^[[bb4:.+]](%arg1 : i32)653 scf.yield %a : i32654 }655 // CHECK: ^[[bb2]]:656 case 1 {657 // CHECK-NEXT: br ^[[bb4]](%arg2 : i32)658 scf.yield %b : i32659 }660 // CHECK: ^[[DEFAULT]]:661 default {662 // CHECK-NEXT: br ^[[bb4]](%arg3 : i32)663 scf.yield %c : i32664 }665 // CHECK: ^[[bb4]](%[[V:.*]]: i32666 // CHECK-NEXT: return %[[V]]667 return %0 : i32668}669 670// Note: scf.forall is lowered to scf.parallel, which is currently lowered to671// scf.for and then to unstructured control flow. scf.parallel could lower more672// efficiently to multi-threaded IR, at which point scf.forall would673// automatically lower to multi-threaded IR.674 675// CHECK-LABEL: func @forall(676// CHECK-SAME: %[[num_threads:.*]]: index)677// CHECK: %[[c0:.*]] = arith.constant 0 : index678// CHECK: %[[c1:.*]] = arith.constant 1 : index679// CHECK: cf.br ^[[bb1:.*]](%[[c0]] : index)680// CHECK: ^[[bb1]](%[[arg0:.*]]: index):681// CHECK: %[[cmpi:.*]] = arith.cmpi slt, %[[arg0]], %[[num_threads]]682// CHECK: cf.cond_br %[[cmpi]], ^[[bb2:.*]], ^[[bb3:.*]]683// CHECK: ^[[bb2]]:684// CHECK: "test.foo"(%[[arg0]])685// CHECK: %[[addi:.*]] = arith.addi %[[arg0]], %[[c1]]686// CHECK: cf.br ^[[bb1]](%[[addi]] : index)687// CHECK: ^[[bb3]]:688// CHECK: return689func.func @forall(%num_threads: index) {690 scf.forall (%thread_idx) in (%num_threads) {691 "test.foo"(%thread_idx) : (index) -> ()692 scf.forall.in_parallel {693 }694 }695 return696}697 698// -----699 700// CHECK: #[[LOOP_UNROLL:.*]] = #llvm.loop_unroll<full = true>701// CHECK-DAG: #[[LOOP_UNROLL_DISABLE:.*]] = #llvm.loop_unroll<disable = true>702 703// CHECK-DAG: #[[FULL_UNROLL:.*]] = #llvm.loop_annotation<unroll = #[[LOOP_UNROLL]]>704// CHECK-DAG: #[[NO_UNROLL:.*]] = #llvm.loop_annotation<unroll = #[[LOOP_UNROLL_DISABLE]]>705// CHECK: func @simple_std_for_loops_annotation706// CHECK: ^[[bb1:.*]](%{{.*}}: index):707// CHECK: cf.cond_br %{{.*}}, ^[[bb2:.*]], ^[[bb6:.*]]708// CHECK: ^[[bb2]]:709// CHECK: cf.br ^[[bb3:.*]]({{.*}})710// CHECK: ^[[bb3]](%{{.*}}: index):711// CHECK: cf.cond_br %{{.*}}, ^[[bb4:.*]], ^[[bb5:.*]]712// CHECK: ^[[bb4]]:713// CHECK: cf.br ^[[bb3]]({{.*}}) {llvm.loop_annotation = #[[FULL_UNROLL]]}714// CHECK: ^[[bb5]]:715// CHECK: cf.br ^[[bb1]]({{.*}}) {llvm.loop_annotation = #[[NO_UNROLL]]}716// CHECK: ^[[bb6]]:717// CHECK: return718#no_unroll = #llvm.loop_annotation<unroll = <disable = true>>719#full_unroll = #llvm.loop_annotation<unroll = <full = true>>720func.func @simple_std_for_loops_annotation(%arg0 : index, %arg1 : index, %arg2 : index) {721 scf.for %i0 = %arg0 to %arg1 step %arg2 {722 %c0 = arith.constant 0 : index723 %c1 = arith.constant 1 : index724 %c4 = arith.constant 4 : index725 scf.for %i1 = %c0 to %c4 step %c1 {726 %c1_0 = arith.constant 1 : index727 } {llvm.loop_annotation = #full_unroll}728 } {llvm.loop_annotation = #no_unroll}729 return730}731 732// -----733 734// CHECK: #[[LOOP_UNROLL_DISABLE:.*]] = #llvm.loop_unroll<disable = true>735// CHECK: #[[NO_UNROLL:.*]] = #llvm.loop_annotation<unroll = #[[LOOP_UNROLL_DISABLE]]>736// CHECK: func @simple_while_loops_annotation737// CHECK: cf.br738// CHECK: cf.cond_br {{.*}} {llvm.loop_annotation = #[[NO_UNROLL]]}739// CHECK: return740#no_unroll = #llvm.loop_annotation<unroll = <disable = true>>741func.func @simple_while_loops_annotation(%arg0 : i1) {742 scf.while : () -> () {743 scf.condition(%arg0)744 } do {745 scf.yield746 } attributes {llvm.loop_annotation = #no_unroll}747 return748}749 750// -----751 752// CHECK: #[[LOOP_UNROLL_DISABLE:.*]] = #llvm.loop_unroll<disable = true>753// CHECK: #[[NO_UNROLL:.*]] = #llvm.loop_annotation<unroll = #[[LOOP_UNROLL_DISABLE]]>754// CHECK: func @do_while_loops_annotation755// CHECK: cf.br756// CHECK: cf.cond_br757// CHECK: cf.br {{.*}} {llvm.loop_annotation = #[[NO_UNROLL]]}758// CHECK: return759#no_unroll = #llvm.loop_annotation<unroll = <disable = true>>760func.func @do_while_loops_annotation() {761 %c0_i32 = arith.constant 0 : i32762 scf.while (%arg2 = %c0_i32) : (i32) -> (i32) {763 %0 = "test.make_condition"() : () -> i1764 scf.condition(%0) %c0_i32 : i32765 } do {766 ^bb0(%arg2: i32): 767 scf.yield %c0_i32: i32768 } attributes {llvm.loop_annotation = #no_unroll}769 return770}771 772