blob: 057e2c71eacd54fd00ae58d78679d751b8d90be9 [file]
; 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"}