xref: /llvm-project/llvm/test/Transforms/LoopVectorize/uncountable-early-exit-vplan.ll (revision 7f3428d3ed71d87a2088b77b6cab9f3d86544234)
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