1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 2; RUN: opt -p loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S -enable-early-exit-vectorization -debug %s 2>&1 | FileCheck %s 3 4; REQUIRES: asserts 5 6declare void @init(ptr) 7 8define i64 @multi_exiting_to_different_exits_live_in_exit_values() { 9; CHECK: multi_exiting_to_different_exits_live_in_exit_values 10; CHECK-LABEL: VPlan 'Initial VPlan for VF={4},UF>=1' { 11; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF 12; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count 13; CHECK-NEXT: Live-in ir<128> = original trip-count 14; CHECK-EMPTY: 15; CHECK-NEXT: ir-bb<entry>: 16; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 17; CHECK-NEXT: IR call void @init(ptr %src) 18; CHECK-NEXT: Successor(s): vector.ph 19; CHECK-EMPTY: 20; CHECK-NEXT: vector.ph: 21; CHECK-NEXT: Successor(s): vector loop 22; CHECK-EMPTY: 23; CHECK-NEXT: <x1> vector loop: { 24; CHECK-NEXT: vector.body: 25; CHECK-NEXT: EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next> 26; CHECK-NEXT: vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1> 27; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3> 28; CHECK-NEXT: vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src> 29; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VEC_PTR]]> 30; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> 31; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]> 32; CHECK-NEXT: EMIT vp<[[EA_TAKEN:%.+]]> = any-of ir<%c.1> 33; CHECK-NEXT: EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]> 34; CHECK-NEXT: EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]> 35; CHECK-NEXT: EMIT branch-on-cond vp<[[EC]]> 36; CHECK-NEXT: No successors 37; CHECK-NEXT: } 38; CHECK-NEXT: Successor(s): middle.split 39; CHECK-EMPTY: 40; CHECK-NEXT: middle.split: 41; CHECK-NEXT: EMIT branch-on-cond vp<[[EA_TAKEN]]> 42; CHECK-NEXT: Successor(s): ir-bb<e1>, middle.block 43; CHECK-EMPTY: 44; CHECK-NEXT: middle.block: 45; CHECK-NEXT: EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]> 46; CHECK-NEXT: EMIT branch-on-cond vp<[[MIDDLE_CMP]]> 47; CHECK-NEXT: Successor(s): ir-bb<e2>, scalar.ph 48; CHECK-EMPTY: 49; CHECK-NEXT: scalar.ph: 50; CHECK-NEXT: EMIT vp<[[RESUME:%.+]]> = resume-phi vp<[[VTC]]>, ir<0> 51; CHECK-NEXT: ir-bb<loop.header> 52; CHECK-EMPTY: 53; CHECK-NEXT: ir-bb<loop.header>: 54; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<[[RESUME]]> from scalar.ph) 55; CHECK: No successors 56; CHECK-EMPTY: 57; CHECK-NEXT: ir-bb<e2>: 58; CHECK-NEXT: IR %p2 = phi i64 [ 1, %loop.latch ] (extra operand: ir<1> from middle.block) 59; CHECK-NEXT: No successors 60; CHECK-EMPTY: 61; CHECK-NEXT: ir-bb<e1>: 62; CHECK-NEXT: IR %p1 = phi i64 [ 0, %loop.header ] (extra operand: ir<0> from middle.split) 63; CHECK-NEXT: No successors 64; CHECK-NEXT: } 65entry: 66 %src = alloca [128 x i32] 67 call void @init(ptr %src) 68 br label %loop.header 69 70loop.header: 71 %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] 72 %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv 73 %l = load i32, ptr %gep.src 74 %c.1 = icmp eq i32 %l, 10 75 br i1 %c.1, label %e1, label %loop.latch 76 77loop.latch: 78 %inc = add nuw i64 %iv, 1 79 %c.2 = icmp eq i64 %inc, 128 80 br i1 %c.2, label %e2, label %loop.header 81 82e1: 83 %p1 = phi i64 [ 0, %loop.header ] 84 ret i64 %p1 85 86e2: 87 %p2 = phi i64 [ 1, %loop.latch ] 88 ret i64 %p2 89} 90 91define i64 @multi_exiting_to_same_exit_live_in_exit_values() { 92; CHECK: multi_exiting_to_same_exit_live_in_exit_values 93; CHECK-LABEL: VPlan 'Initial VPlan for VF={4},UF>=1' { 94; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF 95; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count 96; CHECK-NEXT: Live-in ir<128> = original trip-count 97; CHECK-EMPTY: 98; CHECK-NEXT: ir-bb<entry>: 99; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 100; CHECK-NEXT: IR call void @init(ptr %src) 101; CHECK-NEXT: Successor(s): vector.ph 102; CHECK-EMPTY: 103; CHECK-NEXT: vector.ph: 104; CHECK-NEXT: Successor(s): vector loop 105; CHECK-EMPTY: 106; CHECK-NEXT: <x1> vector loop: { 107; CHECK-NEXT: vector.body: 108; CHECK-NEXT: EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next> 109; CHECK-NEXT: vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1> 110; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3> 111; CHECK-NEXT: vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src> 112; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VEC_PTR]]> 113; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> 114; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]> 115; CHECK-NEXT: EMIT vp<[[EA_TAKEN:%.+]]> = any-of ir<%c.1> 116; CHECK-NEXT: EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]> 117; CHECK-NEXT: EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]> 118; CHECK-NEXT: EMIT branch-on-cond vp<[[EC]]> 119; CHECK-NEXT: No successors 120; CHECK-NEXT: } 121; CHECK-NEXT: Successor(s): middle.split 122; CHECK-EMPTY: 123; CHECK-NEXT: middle.split: 124; CHECK-NEXT: EMIT branch-on-cond vp<[[EA_TAKEN]]> 125; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block 126; CHECK-EMPTY: 127; CHECK-NEXT: middle.block: 128; CHECK-NEXT: EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]> 129; CHECK-NEXT: EMIT branch-on-cond vp<[[MIDDLE_CMP]]> 130; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph 131; CHECK-EMPTY: 132; CHECK-NEXT: scalar.ph: 133; CHECK-NEXT: EMIT vp<[[RESUME:%.+]]> = resume-phi vp<[[VTC]]>, ir<0> 134; CHECK-NEXT: ir-bb<loop.header> 135; CHECK-EMPTY: 136; CHECK-NEXT: ir-bb<loop.header>: 137; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<[[RESUME]]> from scalar.ph) 138; CHECK: No successors 139; CHECK-EMPTY: 140; CHECK-NEXT: ir-bb<exit>: 141; CHECK-NEXT: IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from middle.split) 142; CHECK-NEXT: No successors 143; CHECK-NEXT: } 144 145entry: 146 %src = alloca [128 x i32] 147 call void @init(ptr %src) 148 br label %loop.header 149 150loop.header: 151 %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] 152 %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv 153 %l = load i32, ptr %gep.src 154 %c.1 = icmp eq i32 %l, 10 155 br i1 %c.1, label %exit, label %loop.latch 156 157loop.latch: 158 %inc = add nuw i64 %iv, 1 159 %c.2 = icmp eq i64 %inc, 128 160 br i1 %c.2, label %exit, label %loop.header 161 162exit: 163 %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] 164 ret i64 %p 165} 166 167define i64 @multi_exiting_to_same_exit_live_in_exit_values_2() { 168; CHECK: multi_exiting_to_same_exit_live_in_exit_values_2 169; CHECK-LABEL: VPlan 'Initial VPlan for VF={4},UF>=1' { 170; CHECK-NEXT: Live-in vp<[[VFxUF:%.+]]> = VF * UF 171; CHECK-NEXT: Live-in vp<[[VTC:%.+]]> = vector-trip-count 172; CHECK-NEXT: Live-in ir<128> = original trip-count 173; CHECK-EMPTY: 174; CHECK-NEXT: ir-bb<entry>: 175; CHECK-NEXT: IR %src = alloca [128 x i32], align 4 176; CHECK-NEXT: IR call void @init(ptr %src) 177; CHECK-NEXT: Successor(s): vector.ph 178; CHECK-EMPTY: 179; CHECK-NEXT: vector.ph: 180; CHECK-NEXT: Successor(s): vector loop 181; CHECK-EMPTY: 182; CHECK-NEXT: <x1> vector loop: { 183; CHECK-NEXT: vector.body: 184; CHECK-NEXT: EMIT vp<[[CAN_IV:%.+]]> = CANONICAL-INDUCTION ir<0>, vp<%index.next> 185; CHECK-NEXT: vp<[[STEPS:%.+]]> = SCALAR-STEPS vp<[[CAN_IV]]>, ir<1> 186; CHECK-NEXT: CLONE ir<%gep.src> = getelementptr inbounds ir<%src>, vp<%3> 187; CHECK-NEXT: vp<[[VEC_PTR:%.+]]> = vector-pointer ir<%gep.src> 188; CHECK-NEXT: WIDEN ir<%l> = load vp<[[VEC_PTR]]> 189; CHECK-NEXT: WIDEN ir<%c.1> = icmp eq ir<%l>, ir<10> 190; CHECK-NEXT: EMIT vp<%index.next> = add nuw vp<[[CAN_IV]]>, vp<[[VFxUF]]> 191; CHECK-NEXT: EMIT vp<[[EA_TAKEN:%.+]]> = any-of ir<%c.1> 192; CHECK-NEXT: EMIT vp<[[LATCH_CMP:%.+]]> = icmp eq vp<%index.next>, vp<[[VTC]]> 193; CHECK-NEXT: EMIT vp<[[EC:%.+]]> = or vp<[[EA_TAKEN]]>, vp<[[LATCH_CMP]]> 194; CHECK-NEXT: EMIT branch-on-cond vp<[[EC]]> 195; CHECK-NEXT: No successors 196; CHECK-NEXT: } 197; CHECK-NEXT: Successor(s): middle.split 198; CHECK-EMPTY: 199; CHECK-NEXT: middle.split: 200; CHECK-NEXT: EMIT branch-on-cond vp<[[EA_TAKEN]]> 201; CHECK-NEXT: Successor(s): ir-bb<exit>, middle.block 202; CHECK-EMPTY: 203; CHECK-NEXT: middle.block: 204; CHECK-NEXT: EMIT vp<[[MIDDLE_CMP:%.+]]> = icmp eq ir<128>, vp<[[VTC]]> 205; CHECK-NEXT: EMIT branch-on-cond vp<[[MIDDLE_CMP]]> 206; CHECK-NEXT: Successor(s): ir-bb<exit>, scalar.ph 207; CHECK-EMPTY: 208; CHECK-NEXT: scalar.ph: 209; CHECK-NEXT: EMIT vp<[[RESUME:%.+]]> = resume-phi vp<[[VTC]]>, ir<0> 210; CHECK-NEXT: ir-bb<loop.header> 211; CHECK-EMPTY: 212; CHECK-NEXT: ir-bb<loop.header>: 213; CHECK-NEXT: IR %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] (extra operand: vp<[[RESUME]]> from scalar.ph) 214; CHECK: No successors 215; CHECK-EMPTY: 216; CHECK-NEXT: ir-bb<exit>: 217; CHECK-NEXT: IR %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] (extra operands: ir<1> from middle.block, ir<0> from middle.split) 218; CHECK-NEXT: No successors 219; CHECK-NEXT: } 220 221entry: 222 %src = alloca [128 x i32] 223 call void @init(ptr %src) 224 br label %loop.header 225 226loop.header: 227 %iv = phi i64 [ %inc, %loop.latch ], [ 0, %entry ] 228 %gep.src = getelementptr inbounds i32, ptr %src, i64 %iv 229 %l = load i32, ptr %gep.src 230 %c.1 = icmp eq i32 %l, 10 231 br i1 %c.1, label %exit, label %loop.latch 232 233loop.latch: 234 %inc = add nuw i64 %iv, 1 235 %c.2 = icmp eq i64 %inc, 128 236 br i1 %c.2, label %exit, label %loop.header 237 238exit: 239 %p = phi i64 [ 0, %loop.header ], [ 1, %loop.latch ] 240 ret i64 %p 241 242; uselistorder directives 243 uselistorder label %exit, { 1, 0 } 244} 245