| ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --filter-out-after "middle.block" --version 6 | |
| ; RUN: opt -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 \ | |
| ; RUN: -vplan-print-after=VPlanTransforms::combineRecipes$ -disable-output %s 2>&1 \ | |
| ; RUN: | FileCheck --strict-whitespace %s | |
| ; REQUIRES: asserts | |
| ; Tests that simplifyRecipes performs constant folding on VPlan0 (the initial | |
| ; VPlan, before VF specific transforms). | |
| %rec8 = type { i16 } | |
| @a = global [1 x %rec8] zeroinitializer | |
| @b = global [2 x ptr] zeroinitializer | |
| ; %_tmp2 = getelementptr @a, 0, 0 folds to @a, so the store stores @a directly. | |
| define void @f1() { | |
| ; CHECK-LABEL: VPlan for loop in 'f1' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<bb1>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): bb2 | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: bb2: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%c.1.0> = phi [ ir<0>, vector.ph ], [ ir<%_tmp9>, bb2 ] | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%_tmp6> = sext ir<%c.1.0> to i64 | |
| ; CHECK-NEXT: EMIT ir<%_tmp7> = getelementptr ir<@b>, ir<0>, ir<%_tmp6> | |
| ; CHECK-NEXT: EMIT store ir<@a>, ir<%_tmp7> | |
| ; CHECK-NEXT: EMIT ir<%_tmp9> = add nsw ir<%c.1.0>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%_tmp11> = icmp sge ir<%_tmp9>, ir<2> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%_tmp11> | |
| ; CHECK-NEXT: Successor(s): middle.block, bb2 | |
| ; | |
| bb1: | |
| br label %bb2 | |
| bb2: | |
| %c.1.0 = phi i16 [ 0, %bb1 ], [ %_tmp9, %bb2 ] | |
| %_tmp1 = zext i16 0 to i64 | |
| %_tmp2 = getelementptr [1 x %rec8], ptr @a, i16 0, i64 %_tmp1 | |
| %_tmp6 = sext i16 %c.1.0 to i64 | |
| %_tmp7 = getelementptr [2 x ptr], ptr @b, i16 0, i64 %_tmp6 | |
| store ptr %_tmp2, ptr %_tmp7 | |
| %_tmp9 = add nsw i16 %c.1.0, 1 | |
| %_tmp11 = icmp slt i16 %_tmp9, 2 | |
| br i1 %_tmp11, label %bb2, label %bb3 | |
| bb3: | |
| ret void | |
| } | |
| ; Test case for https://github.com/llvm/llvm-project/issues/131359. | |
| ; %or = or %cmp, true folds to true, simplifying the dependent select and | |
| ; branch-on-cond to use %c.1 directly. | |
| define void @redundant_or_1(ptr %dst, i1 %c.0, i1 %c.1) { | |
| ; CHECK-LABEL: VPlan for loop in 'redundant_or_1' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-NEXT: Live-in ir<3> = original trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): loop.header | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.header: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, loop.latch ] | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.0> | |
| ; CHECK-NEXT: Successor(s): loop.latch, then.1 | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.1: | |
| ; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.1> | |
| ; CHECK-NEXT: Successor(s): then.2, loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.2: | |
| ; CHECK-NEXT: EMIT ir<%gep> = getelementptr inbounds ir<%dst>, ir<%iv> | |
| ; CHECK-NEXT: EMIT store ir<0>, ir<%gep> | |
| ; CHECK-NEXT: Successor(s): loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.latch: | |
| ; CHECK-NEXT: EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%ec> = icmp eq ir<%iv.next>, ir<3> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%ec> | |
| ; CHECK-NEXT: Successor(s): middle.block, loop.header | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| br i1 %c.0, label %loop.latch, label %then.1 | |
| then.1: | |
| %cmp = icmp eq i32 %iv, 2 | |
| %or = or i1 %cmp, true | |
| %cond = select i1 %or, i1 %c.1, i1 false | |
| br i1 %cond, label %then.2, label %loop.latch | |
| then.2: | |
| %gep = getelementptr inbounds i32, ptr %dst, i32 %iv | |
| store i32 0, ptr %gep, align 4 | |
| br label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw nsw i32 %iv, 1 | |
| %ec = icmp eq i32 %iv.next, 3 | |
| br i1 %ec, label %exit, label %loop.header | |
| exit: | |
| ret void | |
| } | |
| ; %or = or true, %cmp folds to true (commuted form of redundant_or_1). | |
| define void @redundant_or_2(ptr %dst, i1 %c.0, i1 %c.1) { | |
| ; CHECK-LABEL: VPlan for loop in 'redundant_or_2' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-NEXT: Live-in ir<3> = original trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): loop.header | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.header: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, loop.latch ] | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.0> | |
| ; CHECK-NEXT: Successor(s): loop.latch, then.1 | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.1: | |
| ; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.1> | |
| ; CHECK-NEXT: Successor(s): then.2, loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.2: | |
| ; CHECK-NEXT: EMIT ir<%gep> = getelementptr inbounds ir<%dst>, ir<%iv> | |
| ; CHECK-NEXT: EMIT store ir<0>, ir<%gep> | |
| ; CHECK-NEXT: Successor(s): loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.latch: | |
| ; CHECK-NEXT: EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%ec> = icmp eq ir<%iv.next>, ir<3> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%ec> | |
| ; CHECK-NEXT: Successor(s): middle.block, loop.header | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| br i1 %c.0, label %loop.latch, label %then.1 | |
| then.1: | |
| %cmp = icmp eq i32 %iv, 2 | |
| %or = or i1 true, %cmp | |
| %cond = select i1 %or, i1 %c.1, i1 false | |
| br i1 %cond, label %then.2, label %loop.latch | |
| then.2: | |
| %gep = getelementptr inbounds i32, ptr %dst, i32 %iv | |
| store i32 0, ptr %gep, align 4 | |
| br label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw nsw i32 %iv, 1 | |
| %ec = icmp eq i32 %iv.next, 3 | |
| br i1 %ec, label %exit, label %loop.header | |
| exit: | |
| ret void | |
| } | |
| ; %or = or %cmp, false folds to %cmp, propagated into the dependent select. | |
| define void @redundant_and_1(ptr %dst, i1 %c.0, i1 %c.1) { | |
| ; CHECK-LABEL: VPlan for loop in 'redundant_and_1' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-NEXT: Live-in ir<3> = original trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): loop.header | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.header: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, loop.latch ] | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.0> | |
| ; CHECK-NEXT: Successor(s): loop.latch, then.1 | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.1: | |
| ; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2> | |
| ; CHECK-NEXT: EMIT ir<%cond> = select ir<%cmp>, ir<%c.1>, ir<false> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%cond> | |
| ; CHECK-NEXT: Successor(s): then.2, loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.2: | |
| ; CHECK-NEXT: EMIT ir<%gep> = getelementptr inbounds ir<%dst>, ir<%iv> | |
| ; CHECK-NEXT: EMIT store ir<0>, ir<%gep> | |
| ; CHECK-NEXT: Successor(s): loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.latch: | |
| ; CHECK-NEXT: EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%ec> = icmp eq ir<%iv.next>, ir<3> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%ec> | |
| ; CHECK-NEXT: Successor(s): middle.block, loop.header | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| br i1 %c.0, label %loop.latch, label %then.1 | |
| then.1: | |
| %cmp = icmp eq i32 %iv, 2 | |
| %or = or i1 %cmp, false | |
| %cond = select i1 %or, i1 %c.1, i1 false | |
| br i1 %cond, label %then.2, label %loop.latch | |
| then.2: | |
| %gep = getelementptr inbounds i32, ptr %dst, i32 %iv | |
| store i32 0, ptr %gep, align 4 | |
| br label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw nsw i32 %iv, 1 | |
| %ec = icmp eq i32 %iv.next, 3 | |
| br i1 %ec, label %exit, label %loop.header, !llvm.loop !1 | |
| exit: | |
| ret void | |
| } | |
| ; %or = and false, %cmp folds to false, simplifying the dependent select and | |
| ; branch-on-cond to false directly. | |
| define void @redundant_and_2(ptr %dst, i1 %c.0, i1 %c.1) { | |
| ; CHECK-LABEL: VPlan for loop in 'redundant_and_2' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-NEXT: Live-in ir<3> = original trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): loop.header | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.header: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, loop.latch ] | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%c.0> | |
| ; CHECK-NEXT: Successor(s): loop.latch, then.1 | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.1: | |
| ; CHECK-NEXT: EMIT ir<%cmp> = icmp eq ir<%iv>, ir<2> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<false> | |
| ; CHECK-NEXT: Successor(s): then.2, loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then.2: | |
| ; CHECK-NEXT: EMIT ir<%gep> = getelementptr inbounds ir<%dst>, ir<%iv> | |
| ; CHECK-NEXT: EMIT store ir<0>, ir<%gep> | |
| ; CHECK-NEXT: Successor(s): loop.latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop.latch: | |
| ; CHECK-NEXT: EMIT ir<%iv.next> = add nuw nsw ir<%iv>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%ec> = icmp eq ir<%iv.next>, ir<3> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%ec> | |
| ; CHECK-NEXT: Successor(s): middle.block, loop.header | |
| ; | |
| entry: | |
| br label %loop.header | |
| loop.header: | |
| %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ] | |
| br i1 %c.0, label %loop.latch, label %then.1 | |
| then.1: | |
| %cmp = icmp eq i32 %iv, 2 | |
| %or = and i1 false, %cmp | |
| %cond = select i1 %or, i1 %c.1, i1 false | |
| br i1 %cond, label %then.2, label %loop.latch | |
| then.2: | |
| %gep = getelementptr inbounds i32, ptr %dst, i32 %iv | |
| store i32 0, ptr %gep, align 4 | |
| br label %loop.latch | |
| loop.latch: | |
| %iv.next = add nuw nsw i32 %iv, 1 | |
| %ec = icmp eq i32 %iv.next, 3 | |
| br i1 %ec, label %exit, label %loop.header | |
| exit: | |
| ret void | |
| } | |
| define void @fold_replicating_umax_equal_live_ins(ptr noalias %dst, ptr %cond, i32 %x) { | |
| ; CHECK-LABEL: VPlan for loop in 'fold_replicating_umax_equal_live_ins' | |
| ; CHECK: VPlan ' for UF>=1' { | |
| ; CHECK-NEXT: Live-in ir<1024> = original trip-count | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: ir-bb<entry>: | |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: vector.ph: | |
| ; CHECK-NEXT: Successor(s): loop | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: loop: | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%iv> = phi [ ir<0>, vector.ph ], [ ir<%iv.next>, latch ] | |
| ; CHECK-NEXT: EMIT ir<%cond.gep> = getelementptr ir<%cond>, ir<%iv> | |
| ; CHECK-NEXT: EMIT-SCALAR ir<%c> = load ir<%cond.gep> | |
| ; CHECK-NEXT: EMIT ir<%tobool> = icmp ne ir<%c>, ir<0> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%tobool> | |
| ; CHECK-NEXT: Successor(s): then, latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: then: | |
| ; CHECK-NEXT: EMIT ir<%gep> = getelementptr ir<%dst>, ir<%iv> | |
| ; CHECK-NEXT: EMIT store ir<%x>, ir<%gep> | |
| ; CHECK-NEXT: Successor(s): latch | |
| ; CHECK-EMPTY: | |
| ; CHECK-NEXT: latch: | |
| ; CHECK-NEXT: EMIT ir<%iv.next> = add ir<%iv>, ir<1> | |
| ; CHECK-NEXT: EMIT ir<%ec> = icmp eq ir<%iv.next>, ir<1024> | |
| ; CHECK-NEXT: EMIT branch-on-cond ir<%ec> | |
| ; CHECK-NEXT: Successor(s): middle.block, loop | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %latch ] | |
| %cond.gep = getelementptr i8, ptr %cond, i64 %iv | |
| %c = load i8, ptr %cond.gep, align 1 | |
| %tobool = icmp ne i8 %c, 0 | |
| br i1 %tobool, label %then, label %latch | |
| then: | |
| %m = call i32 @llvm.umax.i32(i32 %x, i32 %x) | |
| %gep = getelementptr i32, ptr %dst, i64 %iv | |
| store i32 %m, ptr %gep, align 4 | |
| br label %latch | |
| latch: | |
| %iv.next = add i64 %iv, 1 | |
| %ec = icmp eq i64 %iv.next, 1024 | |
| br i1 %ec, label %exit, label %loop | |
| exit: | |
| ret void | |
| } | |
| !1 = distinct !{!1, !2, !3, !4} | |
| !2 = !{!"llvm.loop.vectorize.width", i32 4} | |
| !3 = !{!"llvm.loop.vectorize.enable"} | |
| !4 = !{!"llvm.loop.vectorize.predicate.enable"} |