| ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6 |
| ; RUN: opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -disable-output -vplan-print-after=printOptimizedVPlan %s 2>&1 | FileCheck %s |
| |
| declare void @init(ptr) |
| |
| define i64 @multi_exiting_to_different_exits_live_in_exit_values() { |
| ; CHECK-LABEL: 'multi_exiting_to_different_exits_live_in_exit_values' |
| ; CHECK: VPlan 'Initial VPlan for VF={4},UF>=1' { |
| ; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF |
| ; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = VF * UF |
| ; CHECK-NEXT: Live-in vp<[[VP2:%[0-9]+]]> = vector-trip-count |
| ; CHECK-NEXT: Live-in ir<128> = original trip-count |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<entry>: |
| ; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 |
| ; CHECK-NEXT: IR call void @init(ptr %src) |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.ph: |
| ; CHECK-NEXT: Successor(s): vector loop |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: <x1> vector loop: { |
| ; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = CANONICAL-IV |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.body: |
| ; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = SCALAR-STEPS vp<[[VP3]]>, ir<1>, vp<[[VP0]]> |
| ; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<[[VP4]]> |
| ; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = vector-pointer inbounds ir<%gep.src> |
| ; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VP5]]> |
| ; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP3]]>, vp<[[VP1]]> |
| ; CHECK-NEXT: EMIT vp<[[VP6:%[0-9]+]]> = any-of ir<%c.1> |
| ; CHECK-NEXT: EMIT vp<[[VP7:%[0-9]+]]> = icmp eq vp<%index.next>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-two-conds vp<[[VP6]]>, vp<[[VP7]]> |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; CHECK-NEXT: Successor(s): vector.early.exit, middle.block |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: middle.block: |
| ; CHECK-NEXT: EMIT vp<%cmp.n> = icmp eq ir<128>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-cond vp<%cmp.n> |
| ; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<e2>: |
| ; CHECK-NEXT: IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1> from middle.block) |
| ; CHECK-NEXT: No successors |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit: |
| ; CHECK-NEXT: Successor(s): ir-bb<e1> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<e1>: |
| ; CHECK-NEXT: IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0> from vector.early.exit) |
| ; CHECK-NEXT: No successors |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: scalar.ph: |
| ; CHECK-NEXT: EMIT-SCALAR vp<%bc.resume.val> = phi [ vp<[[VP2]]>, middle.block ], [ ir<0>, ir-bb<entry> ] |
| ; CHECK-NEXT: Successor(s): ir-bb<loop.header> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<loop.header>: |
| ; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<%bc.resume.val> from scalar.ph) |
| ; CHECK-NEXT: IR %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| ; CHECK-NEXT: IR %l = load i32, ptr %gep.src, align 4 |
| ; CHECK-NEXT: IR %c.1 = icmp eq i32 %l, 10 |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; |
| entry: |
| %src = alloca [128 x i32] |
| call void @init(ptr %src) |
| br label %loop.header |
| |
| loop.header: |
| %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] |
| %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| %l = load i32, ptr %gep.src |
| %c.1 = icmp eq i32 %l, 10 |
| br i1 %c.1, label %e1, label %loop.latch |
| |
| loop.latch: |
| %inc = add nuw i64 %iv, 1 |
| %c.2 = icmp eq i64 %inc, 128 |
| br i1 %c.2, label %e2, label %loop.header |
| |
| e1: |
| %p1 = phi i64 [ 0, %loop.header ] |
| ret i64 %p1 |
| |
| e2: |
| %p2 = phi i64 [ 1, %loop.latch ] |
| ret i64 %p2 |
| } |
| |
| define i64 @multi_exiting_to_same_exit_live_in_exit_values() { |
| ; CHECK-LABEL: 'multi_exiting_to_same_exit_live_in_exit_values' |
| ; CHECK: VPlan 'Initial VPlan for VF={4},UF>=1' { |
| ; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF |
| ; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = VF * UF |
| ; CHECK-NEXT: Live-in vp<[[VP2:%[0-9]+]]> = vector-trip-count |
| ; CHECK-NEXT: Live-in ir<128> = original trip-count |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<entry>: |
| ; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 |
| ; CHECK-NEXT: IR call void @init(ptr %src) |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.ph: |
| ; CHECK-NEXT: Successor(s): vector loop |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: <x1> vector loop: { |
| ; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = CANONICAL-IV |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.body: |
| ; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = SCALAR-STEPS vp<[[VP3]]>, ir<1>, vp<[[VP0]]> |
| ; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<[[VP4]]> |
| ; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = vector-pointer inbounds ir<%gep.src> |
| ; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VP5]]> |
| ; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP3]]>, vp<[[VP1]]> |
| ; CHECK-NEXT: EMIT vp<[[VP6:%[0-9]+]]> = any-of ir<%c.1> |
| ; CHECK-NEXT: EMIT vp<[[VP7:%[0-9]+]]> = icmp eq vp<%index.next>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-two-conds vp<[[VP6]]>, vp<[[VP7]]> |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; CHECK-NEXT: Successor(s): vector.early.exit, middle.block |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: middle.block: |
| ; CHECK-NEXT: EMIT vp<%cmp.n> = icmp eq ir<128>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-cond vp<%cmp.n> |
| ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit: |
| ; CHECK-NEXT: Successor(s): ir-bb<exit> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<exit>: |
| ; CHECK-NEXT: IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from vector.early.exit) |
| ; CHECK-NEXT: No successors |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: scalar.ph: |
| ; CHECK-NEXT: EMIT-SCALAR vp<%bc.resume.val> = phi [ vp<[[VP2]]>, middle.block ], [ ir<0>, ir-bb<entry> ] |
| ; CHECK-NEXT: Successor(s): ir-bb<loop.header> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<loop.header>: |
| ; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<%bc.resume.val> from scalar.ph) |
| ; CHECK-NEXT: IR %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| ; CHECK-NEXT: IR %l = load i32, ptr %gep.src, align 4 |
| ; CHECK-NEXT: IR %c.1 = icmp eq i32 %l, 10 |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; |
| |
| entry: |
| %src = alloca [128 x i32] |
| call void @init(ptr %src) |
| br label %loop.header |
| |
| loop.header: |
| %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] |
| %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| %l = load i32, ptr %gep.src |
| %c.1 = icmp eq i32 %l, 10 |
| br i1 %c.1, label %exit, label %loop.latch |
| |
| loop.latch: |
| %inc = add nuw i64 %iv, 1 |
| %c.2 = icmp eq i64 %inc, 128 |
| br i1 %c.2, label %exit, label %loop.header |
| |
| exit: |
| %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] |
| ret i64 %p |
| } |
| |
| define i64 @multi_exiting_to_same_exit_live_in_exit_values_2() { |
| ; CHECK-LABEL: 'multi_exiting_to_same_exit_live_in_exit_values_2' |
| ; CHECK: VPlan 'Initial VPlan for VF={4},UF>=1' { |
| ; CHECK-NEXT: Live-in vp<[[VP0:%[0-9]+]]> = VF |
| ; CHECK-NEXT: Live-in vp<[[VP1:%[0-9]+]]> = VF * UF |
| ; CHECK-NEXT: Live-in vp<[[VP2:%[0-9]+]]> = vector-trip-count |
| ; CHECK-NEXT: Live-in ir<128> = original trip-count |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<entry>: |
| ; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 |
| ; CHECK-NEXT: IR call void @init(ptr %src) |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.ph: |
| ; CHECK-NEXT: Successor(s): vector loop |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: <x1> vector loop: { |
| ; CHECK-NEXT: vp<[[VP3:%[0-9]+]]> = CANONICAL-IV |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.body: |
| ; CHECK-NEXT: vp<[[VP4:%[0-9]+]]> = SCALAR-STEPS vp<[[VP3]]>, ir<1>, vp<[[VP0]]> |
| ; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<[[VP4]]> |
| ; CHECK-NEXT: vp<[[VP5:%[0-9]+]]> = vector-pointer inbounds ir<%gep.src> |
| ; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VP5]]> |
| ; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[VP3]]>, vp<[[VP1]]> |
| ; CHECK-NEXT: EMIT vp<[[VP6:%[0-9]+]]> = any-of ir<%c.1> |
| ; CHECK-NEXT: EMIT vp<[[VP7:%[0-9]+]]> = icmp eq vp<%index.next>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-two-conds vp<[[VP6]]>, vp<[[VP7]]> |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; CHECK-NEXT: Successor(s): vector.early.exit, middle.block |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: middle.block: |
| ; CHECK-NEXT: EMIT vp<%cmp.n> = icmp eq ir<128>, vp<[[VP2]]> |
| ; CHECK-NEXT: EMIT branch-on-cond vp<%cmp.n> |
| ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit: |
| ; CHECK-NEXT: Successor(s): ir-bb<exit> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<exit>: |
| ; CHECK-NEXT: IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from vector.early.exit) |
| ; CHECK-NEXT: No successors |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: scalar.ph: |
| ; CHECK-NEXT: EMIT-SCALAR vp<%bc.resume.val> = phi [ vp<[[VP2]]>, middle.block ], [ ir<0>, ir-bb<entry> ] |
| ; CHECK-NEXT: Successor(s): ir-bb<loop.header> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<loop.header>: |
| ; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<%bc.resume.val> from scalar.ph) |
| ; CHECK-NEXT: IR %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| ; CHECK-NEXT: IR %l = load i32, ptr %gep.src, align 4 |
| ; CHECK-NEXT: IR %c.1 = icmp eq i32 %l, 10 |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; |
| |
| entry: |
| %src = alloca [128 x i32] |
| call void @init(ptr %src) |
| br label %loop.header |
| |
| loop.header: |
| %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] |
| %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv |
| %l = load i32, ptr %gep.src |
| %c.1 = icmp eq i32 %l, 10 |
| br i1 %c.1, label %exit, label %loop.latch |
| |
| loop.latch: |
| %inc = add nuw i64 %iv, 1 |
| %c.2 = icmp eq i64 %inc, 128 |
| br i1 %c.2, label %exit, label %loop.header |
| |
| exit: |
| %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] |
| ret i64 %p |
| |
| ; uselistorder directives |
| uselistorder label %exit, { 1, 0 } |
| } |
| |
| define i64 @two_early_exits_same_exit_with_constant_live_outs() { |
| ; CHECK-LABEL: 'two_early_exits_same_exit_with_constant_live_outs' |
| ; CHECK: VPlan 'Initial VPlan for VF={4},UF>=1' { |
| ; CHECK-NEXT: Live-in vp<[[VF:%.+]]> = VF |
| ; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF |
| ; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count |
| ; CHECK-NEXT: Live-in ir<67> = original trip-count |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<entry>: |
| ; CHECK-NEXT: IR %A = alloca [1024 x i8], align 1 |
| ; CHECK-NEXT: IR %B = alloca [1024 x i8], align 1 |
| ; CHECK-NEXT: IR call void @init(ptr %A, i64 1024) |
| ; CHECK-NEXT: IR call void @init(ptr %B, i64 1024) |
| ; CHECK-NEXT: Successor(s): scalar.ph, vector.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.ph: |
| ; CHECK-NEXT: Successor(s): vector loop |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: <x1> vector loop: { |
| ; CHECK-NEXT: vp<[[CAN_IV:%.+]]> = CANONICAL-IV |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.body: |
| ; CHECK-NEXT: vp<[[SCALAR_STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1>, vp<[[VF]]> |
| ; CHECK-NEXT: CLONE ir<%gep.A> = getelementptr inbounds ir<%A>, vp<[[SCALAR_STEPS]]> |
| ; CHECK-NEXT: vp<[[PTRA:%.+]]> = vector-pointer inbounds ir<%gep.A> |
| ; CHECK-NEXT: WIDEN ir<%ld.A> = load vp<[[PTRA]]> |
| ; CHECK-NEXT: WIDEN ir<%cmp1> = icmp eq ir<%ld.A>, ir<42> |
| ; CHECK-NEXT: CLONE ir<%gep.B> = getelementptr inbounds ir<%B>, vp<[[SCALAR_STEPS]]> |
| ; CHECK-NEXT: vp<[[PTRB:%.+]]> = vector-pointer inbounds ir<%gep.B> |
| ; CHECK-NEXT: WIDEN ir<%ld.B> = load vp<[[PTRB]]> |
| ; CHECK-NEXT: WIDEN ir<%cmp2> = icmp eq ir<%ld.A>, ir<%ld.B> |
| ; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]> |
| ; CHECK-NEXT: EMIT vp<[[OR:%.+]]> = logical-or ir<%cmp1>, ir<%cmp2> |
| ; CHECK-NEXT: EMIT vp<[[ANY_OF:%.+]]> = any-of vp<[[OR]]> |
| ; CHECK-NEXT: EMIT vp<[[CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]> |
| ; CHECK-NEXT: EMIT branch-on-two-conds vp<[[ANY_OF]]>, vp<[[CMP]]> |
| ; CHECK-NEXT: No successors |
| ; CHECK-NEXT: } |
| ; CHECK-NEXT: Successor(s): vector.early.exit.check, middle.block |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: middle.block: |
| ; CHECK-NEXT: EMIT vp<%cmp.n> = icmp eq ir<67>, vp<[[VTC]]> |
| ; CHECK-NEXT: EMIT branch-on-cond vp<%cmp.n> |
| ; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit.check: |
| ; CHECK-NEXT: EMIT vp<%first.active.lane> = first-active-lane vp<[[OR]]> |
| ; CHECK-NEXT: EMIT vp<%exit.cond.at.lane> = extract-lane vp<%first.active.lane>, ir<%cmp1> |
| ; CHECK-NEXT: EMIT branch-on-cond vp<%exit.cond.at.lane> |
| ; CHECK-NEXT: Successor(s): vector.early.exit.0, vector.early.exit.1 |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit.1: |
| ; CHECK-NEXT: Successor(s): ir-bb<exit> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: vector.early.exit.0: |
| ; CHECK-NEXT: EMIT vp<[[FIRST_ACTIVE:%.+]]> = first-active-lane vp<[[OR]]> |
| ; CHECK-NEXT: EMIT vp<[[FINAL_IV:%.+]]> = add vp<[[CAN_IV]]>, vp<[[FIRST_ACTIVE]]> |
| ; CHECK-NEXT: Successor(s): ir-bb<exit> |
| ; CHECK-EMPTY: |
| ; CHECK-NEXT: ir-bb<exit>: |
| ; CHECK-NEXT: IR %retval = phi i64 [ %iv, %loop.header ], [ 100, %early.exit.0 ], [ 43, %loop.latch ] (extra operands: ir<43> from middle.block, vp<[[FINAL_IV]]> from vector.early.exit.0, ir<100> from vector.early.exit.1) |
| ; |
| entry: |
| %A = alloca [1024 x i8] |
| %B = alloca [1024 x i8] |
| call void @init(ptr %A, i64 1024) |
| call void @init(ptr %B, i64 1024) |
| br label %loop.header |
| |
| loop.header: |
| %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ] |
| %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv |
| %ld.A = load i8, ptr %gep.A, align 1 |
| %cmp1 = icmp eq i8 %ld.A, 42 |
| br i1 %cmp1, label %exit, label %early.exit.0 |
| |
| early.exit.0: |
| %gep.B = getelementptr inbounds i8, ptr %B, i64 %iv |
| %ld.B = load i8, ptr %gep.B, align 1 |
| %cmp2 = icmp eq i8 %ld.A, %ld.B |
| br i1 %cmp2, label %exit, label %loop.latch |
| |
| loop.latch: |
| %iv.next = add i64 %iv, 1 |
| %ec = icmp ne i64 %iv.next, 67 |
| br i1 %ec, label %loop.header, label %exit |
| |
| exit: |
| %retval = phi i64 [ %iv, %loop.header ], [ 100, %early.exit.0 ], [ 43, %loop.latch ] |
| ret i64 %retval |
| } |