1; RUN: opt -disable-output -passes='print-access-info' %s 2>&1 | FileCheck %s
2; RUN: opt -disable-output -passes='print-access-info' -max-forked-scev-depth=2 %s 2>&1 | FileCheck -check-prefix=RECURSE %s
3
4target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
5
6; CHECK-LABEL: function 'forked_ptrs_simple':
7; CHECK-NEXT:  loop:
8; CHECK-NEXT:    Memory dependences are safe with run-time checks
9; CHECK-NEXT:    Dependences:
10; CHECK-NEXT:    Run-time memory checks:
11; CHECK-NEXT:    Check 0:
12; CHECK-NEXT:      Comparing group ([[G1:.+]]):
13; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
14; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
15; CHECK-NEXT:      Against group ([[G2:.+]]):
16; CHECK-NEXT:        %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
17; CHECK-NEXT:    Check 1:
18; CHECK-NEXT:      Comparing group ([[G1]]):
19; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
20; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
21; CHECK-NEXT:      Against group ([[G3:.+]]):
22; CHECK-NEXT:        %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
23; CHECK-NEXT:    Grouped accesses:
24; CHECK-NEXT:      Group [[G1]]
25; CHECK-NEXT:        (Low: %Dest High: (400 + %Dest))
26; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%loop>
27; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%loop>
28; CHECK-NEXT:      Group [[G2]]:
29; CHECK-NEXT:        (Low: %Base1 High: (400 + %Base1))
30; CHECK-NEXT:          Member: {%Base1,+,4}<nw><%loop>
31; CHECK-NEXT:      Group [[G3]]:
32; CHECK-NEXT:        (Low: %Base2 High: (400 + %Base2))
33; CHECK-NEXT:          Member: {%Base2,+,4}<nw><%loop>
34; CHECK-EMPTY:
35; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
36; CHECK-NEXT:    SCEV assumptions:
37; CHECK-EMPTY:
38; CHECK-NEXT:    Expressions re-written:
39
40define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr %Dest) {
41entry:
42  br label %loop
43
44loop:
45  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
46  %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
47  %l.Dest = load float, ptr %gep.Dest
48  %cmp = fcmp une float %l.Dest, 0.0
49  %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv
50  %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv
51  %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
52  %sink = load float, ptr %select, align 4
53  store float %sink, ptr %gep.Dest, align 4
54  %iv.next = add nuw nsw i64 %iv, 1
55  %exitcond.not = icmp eq i64 %iv.next, 100
56  br i1 %exitcond.not, label %exit, label %loop
57
58exit:
59  ret void
60}
61
62; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset':
63; CHECK-NEXT:  for.body:
64; CHECK-NEXT:    Memory dependences are safe with run-time checks
65; CHECK-NEXT:    Dependences:
66; CHECK-NEXT:    Run-time memory checks:
67; CHECK-NEXT:    Check 0:
68; CHECK-NEXT:      Comparing group ([[G1:.+]]):
69; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
70; CHECK-NEXT:      Against group ([[G2:.+]]):
71; CHECK-NEXT:        %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
72; CHECK-NEXT:    Check 1:
73; CHECK-NEXT:      Comparing group ([[G1]]):
74; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
75; CHECK-NEXT:      Against group ([[G3:.+]]):
76; CHECK-NEXT:        %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
77; CHECK-NEXT:    Check 2:
78; CHECK-NEXT:      Comparing group ([[G1]]):
79; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
80; CHECK-NEXT:      Against group ([[G4:.+]]):
81; CHECK-NEXT:        %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
82; CHECK-NEXT:    Grouped accesses:
83; CHECK-NEXT:      Group [[G1]]:
84; CHECK-NEXT:        (Low: %Dest High: (400 + %Dest))
85; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%for.body>
86; CHECK-NEXT:      Group [[G2]]:
87; CHECK-NEXT:        (Low: %Preds High: (400 + %Preds))
88; CHECK-NEXT:          Member: {%Preds,+,4}<nuw><%for.body>
89; CHECK-NEXT:      Group [[G3]]:
90; CHECK-NEXT:        (Low: %Base2 High: (400 + %Base2))
91; CHECK-NEXT:          Member: {%Base2,+,4}<nw><%for.body>
92; CHECK-NEXT:      Group [[G4]]:
93; CHECK-NEXT:        (Low: %Base1 High: (400 + %Base1))
94; CHECK-NEXT:          Member: {%Base1,+,4}<nw><%for.body>
95; CHECK-EMPTY:
96; CHECK-NEXT:   Non vectorizable stores to invariant address were not found in loop.
97; CHECK-NEXT:   SCEV assumptions:
98; CHECK-EMPTY:
99; CHECK-NEXT:   Expressions re-written:
100
101;; We have a limit on the recursion depth for finding a loop invariant or
102;; addrec term; confirm we won't exceed that depth by forcing a lower
103;; limit via -max-forked-scev-depth=2
104; RECURSE-LABEL: Loop access info in function 'forked_ptrs_same_base_different_offset':
105; RECURSE-NEXT:   for.body:
106; RECURSE-NEXT:     Report: cannot identify array bounds
107; RECURSE-NEXT:     Dependences:
108; RECURSE-NEXT:     Run-time memory checks:
109; RECURSE-NEXT:     Grouped accesses:
110; RECURSE-EMPTY:
111; RECURSE-NEXT:     Non vectorizable stores to invariant address were not found in loop.
112; RECURSE-NEXT:     SCEV assumptions:
113; RECURSE-EMPTY:
114; RECURSE-NEXT:     Expressions re-written:
115
116;;;; Derived from the following C code
117;; void forked_ptrs_different_base_same_offset(float *A, float *B, float *C, int *D) {
118;;   for (int i=0; i<100; i++) {
119;;     if (D[i] != 0) {
120;;       C[i] = A[i];
121;;     } else {
122;;       C[i] = B[i];
123;;     }
124;;   }
125;; }
126
127define dso_local void @forked_ptrs_different_base_same_offset(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
128entry:
129  br label %for.body
130
131for.cond.cleanup:
132  ret void
133
134for.body:
135  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
136  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
137  %0 = load i32, ptr %arrayidx, align 4
138  %cmp1.not = icmp eq i32 %0, 0
139  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
140  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
141  %.sink = load float, ptr %.sink.in, align 4
142  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
143  store float %.sink, ptr %1, align 4
144  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
145  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
146  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
147}
148
149; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_64b':
150; CHECK-NEXT:  for.body:
151; CHECK-NEXT:    Memory dependences are safe with run-time checks
152; CHECK-NEXT:    Dependences:
153; CHECK-NEXT:    Run-time memory checks:
154; CHECK-NEXT:    Check 0:
155; CHECK-NEXT:      Comparing group ([[G1:.+]]):
156; CHECK-NEXT:        %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv
157; CHECK-NEXT:      Against group ([[G2:.+]]):
158; CHECK-NEXT:        %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
159; CHECK-NEXT:    Check 1:
160; CHECK-NEXT:      Comparing group ([[G1]]):
161; CHECK-NEXT:        %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv
162; CHECK-NEXT:      Against group ([[G3:.+]]):
163; CHECK-NEXT:        %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv
164; CHECK-NEXT:    Check 2:
165; CHECK-NEXT:      Comparing group ([[G1]]):
166; CHECK-NEXT:        %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv
167; CHECK-NEXT:      Against group ([[G4:.+]]):
168; CHECK-NEXT:        %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv
169; CHECK-NEXT:    Grouped accesses:
170; CHECK-NEXT:      Group [[G1]]:
171; CHECK-NEXT:        (Low: %Dest High: (800 + %Dest))
172; CHECK-NEXT:          Member: {%Dest,+,8}<nuw><%for.body>
173; CHECK-NEXT:      Group [[G2]]:
174; CHECK-NEXT:        (Low: %Preds High: (400 + %Preds))
175; CHECK-NEXT:          Member: {%Preds,+,4}<nuw><%for.body>
176; CHECK-NEXT:      Group [[G3]]:
177; CHECK-NEXT:        (Low: %Base2 High: (800 + %Base2))
178; CHECK-NEXT:          Member: {%Base2,+,8}<nw><%for.body>
179; CHECK-NEXT:      Group [[G4]]:
180; CHECK-NEXT:        (Low: %Base1 High: (800 + %Base1))
181; CHECK-NEXT:          Member: {%Base1,+,8}<nw><%for.body>
182; CHECK-EMPTY:
183; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
184; CHECK-NEXT:    SCEV assumptions:
185; CHECK-EMPTY:
186; CHECK-NEXT:    Expressions re-written:
187
188define dso_local void @forked_ptrs_different_base_same_offset_64b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
189entry:
190  br label %for.body
191
192for.cond.cleanup:
193  ret void
194
195for.body:
196  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
197  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
198  %0 = load i32, ptr %arrayidx, align 4
199  %cmp1.not = icmp eq i32 %0, 0
200  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
201  %.sink.in = getelementptr inbounds double, ptr %spec.select, i64 %indvars.iv
202  %.sink = load double, ptr %.sink.in, align 8
203  %1 = getelementptr inbounds double, ptr %Dest, i64 %indvars.iv
204  store double %.sink, ptr %1, align 8
205  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
206  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
207  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
208}
209
210; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_23b':
211; CHECK-NEXT:  for.body:
212; CHECK-NEXT:    Memory dependences are safe with run-time checks
213; CHECK-NEXT:    Dependences:
214; CHECK-NEXT:    Run-time memory checks:
215; CHECK-NEXT:    Check 0:
216; CHECK-NEXT:      Comparing group ([[G1:.+]]):
217; CHECK-NEXT:        %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv
218; CHECK-NEXT:      Against group ([[G2:.+]]):
219; CHECK-NEXT:        %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
220; CHECK-NEXT:    Check 1:
221; CHECK-NEXT:      Comparing group ([[G1]]):
222; CHECK-NEXT:        %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv
223; CHECK-NEXT:      Against group ([[G3:.+]]):
224; CHECK-NEXT:        %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv
225; CHECK-NEXT:    Check 2:
226; CHECK-NEXT:      Comparing group ([[G1]]):
227; CHECK-NEXT:        %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv
228; CHECK-NEXT:      Against group ([[G4:.+]]):
229; CHECK-NEXT:        %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv
230; CHECK-NEXT:    Grouped accesses:
231; CHECK-NEXT:      Group [[G1]]:
232; CHECK-NEXT:        (Low: %Dest High: (399 + %Dest))
233; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%for.body>
234; CHECK-NEXT:      Group [[G2]]:
235; CHECK-NEXT:        (Low: %Preds High: (400 + %Preds))
236; CHECK-NEXT:          Member: {%Preds,+,4}<nuw><%for.body>
237; CHECK-NEXT:      Group [[G3]]:
238; CHECK-NEXT:        (Low: %Base2 High: (399 + %Base2))
239; CHECK-NEXT:          Member: {%Base2,+,4}<nw><%for.body>
240; CHECK-NEXT:      Group [[G4]]:
241; CHECK-NEXT:        (Low: %Base1 High: (399 + %Base1))
242; CHECK-NEXT:          Member: {%Base1,+,4}<nw><%for.body>
243; CHECK-EMPTY:
244; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
245; CHECK-NEXT:    SCEV assumptions:
246; CHECK-EMPTY:
247; CHECK-NEXT:    Expressions re-written:
248
249define dso_local void @forked_ptrs_different_base_same_offset_23b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
250entry:
251  br label %for.body
252
253for.cond.cleanup:
254  ret void
255
256for.body:
257  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
258  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
259  %0 = load i32, ptr %arrayidx, align 4
260  %cmp1.not = icmp eq i32 %0, 0
261  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
262  %.sink.in = getelementptr inbounds i23, ptr %spec.select, i64 %indvars.iv
263  %.sink = load i23, ptr %.sink.in
264  %1 = getelementptr inbounds i23, ptr %Dest, i64 %indvars.iv
265  store i23 %.sink, ptr %1
266  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
267  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
268  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
269}
270
271; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_6b':
272; CHECK-NEXT:  for.body:
273; CHECK-NEXT:    Memory dependences are safe with run-time checks
274; CHECK-NEXT:    Dependences:
275; CHECK-NEXT:    Run-time memory checks:
276; CHECK-NEXT:    Check 0:
277; CHECK-NEXT:      Comparing group ([[G1:.+]]):
278; CHECK-NEXT:        %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv
279; CHECK-NEXT:      Against group ([[G2:.+]]):
280; CHECK-NEXT:        %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
281; CHECK-NEXT:    Check 1:
282; CHECK-NEXT:      Comparing group ([[G1]]):
283; CHECK-NEXT:        %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv
284; CHECK-NEXT:      Against group ([[G3:.+]]):
285; CHECK-NEXT:        %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv
286; CHECK-NEXT:    Check 2:
287; CHECK-NEXT:      Comparing group ([[G1]]):
288; CHECK-NEXT:        %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv
289; CHECK-NEXT:      Against group ([[G4:.+]]):
290; CHECK-NEXT:        %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv
291; CHECK-NEXT:    Grouped accesses:
292; CHECK-NEXT:      Group [[G1]]:
293; CHECK-NEXT:        (Low: %Dest High: (100 + %Dest))
294; CHECK-NEXT:          Member: {%Dest,+,1}<nuw><%for.body>
295; CHECK-NEXT:      Group [[G2]]:
296; CHECK-NEXT:        (Low: %Preds High: (400 + %Preds))
297; CHECK-NEXT:          Member: {%Preds,+,4}<nuw><%for.body>
298; CHECK-NEXT:      Group [[G3]]:
299; CHECK-NEXT:        (Low: %Base2 High: (100 + %Base2))
300; CHECK-NEXT:          Member: {%Base2,+,1}<nw><%for.body>
301; CHECK-NEXT:      Group [[G4]]:
302; CHECK-NEXT:        (Low: %Base1 High: (100 + %Base1))
303; CHECK-NEXT:          Member: {%Base1,+,1}<nw><%for.body>
304; CHECK-EMPTY:
305; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
306; CHECK-NEXT:    SCEV assumptions:
307; CHECK-EMPTY:
308; CHECK-NEXT:    Expressions re-written:
309
310define dso_local void @forked_ptrs_different_base_same_offset_6b(ptr nocapture readonly nonnull %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
311entry:
312  br label %for.body
313
314for.cond.cleanup:
315  ret void
316
317for.body:
318  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
319  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
320  %0 = load i32, ptr %arrayidx, align 4
321  %cmp1.not = icmp eq i32 %0, 0
322  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
323  %.sink.in = getelementptr inbounds i6, ptr %spec.select, i64 %indvars.iv
324  %.sink = load i6, ptr %.sink.in
325  %1 = getelementptr inbounds i6, ptr %Dest, i64 %indvars.iv
326  store i6 %.sink, ptr %1
327  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
328  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
329  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
330}
331
332; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_possible_poison':
333; CHECK-NEXT:  for.body:
334; CHECK-NEXT:    Memory dependences are safe with run-time checks
335; CHECK-NEXT:    Dependences:
336; CHECK-NEXT:    Run-time memory checks:
337; CHECK-NEXT:    Check 0:
338; CHECK-NEXT:      Comparing group ([[G1:.+]]):
339; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
340; CHECK-NEXT:      Against group ([[G2:.+]]):
341; CHECK-NEXT:        %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
342; CHECK-NEXT:    Check 1:
343; CHECK-NEXT:      Comparing group ([[G1]]):
344; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
345; CHECK-NEXT:      Against group ([[G3:.+]]):
346; CHECK-NEXT:        %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
347; CHECK-NEXT:    Check 2:
348; CHECK-NEXT:      Comparing group ([[G1]]):
349; CHECK-NEXT:        %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
350; CHECK-NEXT:      Against group ([[G4:.+]]):
351; CHECK-NEXT:        %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
352; CHECK-NEXT:    Grouped accesses:
353; CHECK-NEXT:      Group [[G1]]:
354; CHECK-NEXT:        (Low: %Dest High: (400 + %Dest))
355; CHECK-NEXT:          Member: {%Dest,+,4}<nw><%for.body>
356; CHECK-NEXT:      Group [[G2]]:
357; CHECK-NEXT:        (Low: %Preds High: (400 + %Preds))
358; CHECK-NEXT:          Member: {%Preds,+,4}<nuw><%for.body>
359; CHECK-NEXT:      Group [[G3]]:
360; CHECK-NEXT:        (Low: %Base2 High: (400 + %Base2))
361; CHECK-NEXT:          Member: {%Base2,+,4}<nw><%for.body>
362; CHECK-NEXT:      Group [[G4]]:
363; CHECK-NEXT:        (Low: %Base1 High: (400 + %Base1))
364; CHECK-NEXT:          Member: {%Base1,+,4}<nw><%for.body>
365; CHECK-EMPTY:
366; CHECK-NEXT:   Non vectorizable stores to invariant address were not found in loop.
367; CHECK-NEXT:   SCEV assumptions:
368; CHECK-EMPTY:
369; CHECK-NEXT:   Expressions re-written:
370
371define dso_local void @forked_ptrs_different_base_same_offset_possible_poison(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds, i1 %c) {
372entry:
373  br label %for.body
374
375for.cond.cleanup:
376  ret void
377
378for.body:
379  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %latch ]
380  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
381  %0 = load i32, ptr %arrayidx, align 4
382  %cmp1.not = icmp eq i32 %0, 0
383  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
384  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
385  %.sink = load float, ptr %.sink.in, align 4
386  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
387  br i1 %c, label %then, label %latch
388
389then:
390  store float %.sink, ptr %1, align 4
391  br label %latch
392
393latch:
394  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
395  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
396  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
397}
398
399; CHECK-LABEL: function 'forked_ptrs_same_base_different_offset':
400; CHECK-NEXT:   for.body:
401; CHECK-NEXT:     Report: cannot identify array bounds
402; CHECK-NEXT:     Dependences:
403; CHECK-NEXT:     Run-time memory checks:
404; CHECK-NEXT:     Grouped accesses:
405; CHECK-EMPTY:
406; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
407; CHECK-NEXT:     SCEV assumptions:
408; CHECK-EMPTY:
409; CHECK-NEXT:     Expressions re-written:
410
411;;;; Derived from the following C code
412;; void forked_ptrs_same_base_different_offset(float *A, float *B, int *C) {
413;;   int offset;
414;;   for (int i = 0; i < 100; i++) {
415;;     if (C[i] != 0)
416;;       offset = i;
417;;     else
418;;       offset = i+1;
419;;     B[i] = A[offset];
420;;   }
421;; }
422
423define dso_local void @forked_ptrs_same_base_different_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
424entry:
425  br label %for.body
426
427for.cond.cleanup:                                 ; preds = %for.body
428  ret void
429
430for.body:                                         ; preds = %entry, %for.body
431  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
432  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
433  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
434  %0 = load i32, ptr %arrayidx, align 4
435  %cmp1.not = icmp eq i32 %0, 0
436  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
437  %add = add nuw nsw i32 %i.014, 1
438  %1 = trunc i64 %indvars.iv to i32
439  %offset.0 = select i1 %cmp1.not, i32 %add, i32 %1
440  %idxprom213 = zext i32 %offset.0 to i64
441  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213
442  %2 = load float, ptr %arrayidx3, align 4
443  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
444  store float %2, ptr %arrayidx5, align 4
445  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
446  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
447}
448
449; CHECK-LABEL: function 'forked_ptrs_add_to_offset'
450; CHECK-NEXT:  for.body:
451; CHECK-NEXT:    Report: cannot identify array bounds
452; CHECK-NEXT:    Dependences:
453; CHECK-NEXT:    Run-time memory checks:
454; CHECK-NEXT:    Grouped accesses:
455; CHECK-EMPTY:
456; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
457; CHECK-NEXT:    SCEV assumptions:
458; CHECK-EMPTY:
459; CHECK-NEXT:    Expressions re-written:
460
461define dso_local void @forked_ptrs_add_to_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) {
462entry:
463  br label %for.body
464
465for.cond.cleanup:                                 ; preds = %for.body
466  ret void
467
468for.body:                                         ; preds = %entry, %for.body
469  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
470  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
471  %0 = load i32, ptr %arrayidx, align 4
472  %cmp.not = icmp eq i32 %0, 0
473  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
474  %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv
475  %offset = add nuw nsw i64 %sel, %extra_offset
476  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset
477  %1 = load float, ptr %arrayidx3, align 4
478  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
479  store float %1, ptr %arrayidx5, align 4
480  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
481  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
482}
483
484; CHECK-LABEL: function 'forked_ptrs_sub_from_offset'
485; CHECK-NEXT:  for.body:
486; CHECK-NEXT:    Report: cannot identify array bounds
487; CHECK-NEXT:    Dependences:
488; CHECK-NEXT:    Run-time memory checks:
489; CHECK-NEXT:    Grouped accesses:
490; CHECK-EMPTY:
491; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
492; CHECK-NEXT:    SCEV assumptions:
493; CHECK-EMPTY:
494; CHECK-NEXT:    Expressions re-written:
495
496define dso_local void @forked_ptrs_sub_from_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) {
497entry:
498  br label %for.body
499
500for.cond.cleanup:                                 ; preds = %for.body
501  ret void
502
503for.body:                                         ; preds = %entry, %for.body
504  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
505  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
506  %0 = load i32, ptr %arrayidx, align 4
507  %cmp.not = icmp eq i32 %0, 0
508  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
509  %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv
510  %offset = sub nuw nsw i64 %sel, %extra_offset
511  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset
512  %1 = load float, ptr %arrayidx3, align 4
513  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
514  store float %1, ptr %arrayidx5, align 4
515  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
516  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
517}
518
519; CHECK-LABEL: function 'forked_ptrs_add_sub_offset'
520; CHECK-NEXT:  for.body:
521; CHECK-NEXT:    Report: cannot identify array bounds
522; CHECK-NEXT:    Dependences:
523; CHECK-NEXT:    Run-time memory checks:
524; CHECK-NEXT:    Grouped accesses:
525; CHECK-EMPTY:
526; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
527; CHECK-NEXT:    SCEV assumptions:
528; CHECK-EMPTY:
529; CHECK-NEXT:    Expressions re-written:
530
531define dso_local void @forked_ptrs_add_sub_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %to_add, i64 %to_sub) {
532entry:
533  br label %for.body
534
535for.cond.cleanup:                                 ; preds = %for.body
536  ret void
537
538for.body:                                         ; preds = %entry, %for.body
539  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
540  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
541  %0 = load i32, ptr %arrayidx, align 4
542  %cmp.not = icmp eq i32 %0, 0
543  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
544  %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv
545  %add = add nuw nsw i64 %sel, %to_add
546  %offset = sub nuw nsw i64 %add, %to_sub
547  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset
548  %1 = load float, ptr %arrayidx3, align 4
549  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
550  store float %1, ptr %arrayidx5, align 4
551  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
552  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
553}
554
555;;;; Cases that can be handled by a forked pointer but are not currently allowed.
556
557; CHECK-LABEL: function 'forked_ptrs_mul_by_offset'
558; CHECK-NEXT:  for.body:
559; CHECK-NEXT:    Report: cannot identify array bounds
560; CHECK-NEXT:    Dependences:
561; CHECK-NEXT:    Run-time memory checks:
562; CHECK-NEXT:    Grouped accesses:
563; CHECK-EMPTY:
564; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
565; CHECK-NEXT:    SCEV assumptions:
566; CHECK-EMPTY:
567; CHECK-NEXT:    Expressions re-written:
568
569define dso_local void @forked_ptrs_mul_by_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds, i64 %extra_offset) {
570entry:
571  br label %for.body
572
573for.cond.cleanup:                                 ; preds = %for.body
574  ret void
575
576for.body:                                         ; preds = %entry, %for.body
577  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
578  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
579  %0 = load i32, ptr %arrayidx, align 4
580  %cmp.not = icmp eq i32 %0, 0
581  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
582  %sel = select i1 %cmp.not, i64 %indvars.iv.next, i64 %indvars.iv
583  %offset = mul nuw nsw i64 %sel, %extra_offset
584  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %offset
585  %1 = load float, ptr %arrayidx3, align 4
586  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
587  store float %1, ptr %arrayidx5, align 4
588  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
589  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
590}
591
592; CHECK-LABEL: function 'forked_ptrs_uniform_and_strided_forks':
593; CHECK-NEXT:  for.body:
594; CHECK-NEXT:    Report: cannot identify array bounds
595; CHECK-NEXT:    Dependences:
596; CHECK-NEXT:    Run-time memory checks:
597; CHECK-NEXT:    Grouped accesses:
598; CHECK-EMPTY:
599; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
600; CHECK-NEXT:    SCEV assumptions:
601; CHECK-EMPTY:
602; CHECK-NEXT:    Expressions re-written:
603
604;;;; Derived from forked_ptrs_same_base_different_offset with a manually
605;;;; added uniform offset and a mul to provide a stride
606
607define dso_local void @forked_ptrs_uniform_and_strided_forks(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) {
608entry:
609  br label %for.body
610
611for.cond.cleanup:                                 ; preds = %for.body
612  ret void
613
614for.body:                                         ; preds = %entry, %for.body
615  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
616  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
617  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
618  %0 = load i32, ptr %arrayidx, align 4
619  %cmp1.not = icmp eq i32 %0, 0
620  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
621  %add = add nuw nsw i32 %i.014, 1
622  %1 = trunc i64 %indvars.iv to i32
623  %mul = mul i32 %1, 3
624  %offset.0 = select i1 %cmp1.not, i32 4, i32 %mul
625  %idxprom213 = sext i32 %offset.0 to i64
626  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213
627  %2 = load float, ptr %arrayidx3, align 4
628  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
629  store float %2, ptr %arrayidx5, align 4
630  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
631  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
632}
633
634; CHECK-LABEL:  function 'forked_ptrs_gather_and_contiguous_forks':
635; CHECK-NEXT:   for.body:
636; CHECK-NEXT:     Report: cannot identify array bounds
637; CHECK-NEXT:     Dependences:
638; CHECK-NEXT:     Run-time memory checks:
639; CHECK-NEXT:     Grouped accesses:
640; CHECK-EMPTY:
641; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
642; CHECK-NEXT:     SCEV assumptions:
643; CHECK-EMPTY:
644; CHECK-NEXT:     Expressions re-written:
645
646;;;; Derived from forked_ptrs_same_base_different_offset with a gather
647;;;; added using Preds as an index array in addition to the per-iteration
648;;;; condition.
649
650define dso_local void @forked_ptrs_gather_and_contiguous_forks(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
651entry:
652  br label %for.body
653
654for.cond.cleanup:                                 ; preds = %for.body
655  ret void
656
657for.body:                                         ; preds = %entry, %for.body
658  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
659  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
660  %0 = load i32, ptr %arrayidx, align 4
661  %cmp1.not = icmp eq i32 %0, 0
662  %arrayidx9 = getelementptr inbounds float, ptr %Base2, i64 %indvars.iv
663  %idxprom4 = sext i32 %0 to i64
664  %arrayidx5 = getelementptr inbounds float, ptr %Base1, i64 %idxprom4
665  %.sink.in = select i1 %cmp1.not, ptr %arrayidx9, ptr %arrayidx5
666  %.sink = load float, ptr %.sink.in, align 4
667  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
668  store float %.sink, ptr %1, align 4
669  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
670  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
671  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
672}
673
674;; We don't currently handle a fork in both the base and the offset of a
675;; GEP instruction.
676
677; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_forks_gep':
678; CHECK-NEXT:   for.body:
679; CHECK-NEXT:     Report: cannot identify array bounds
680; CHECK-NEXT:     Dependences:
681; CHECK-NEXT:     Run-time memory checks:
682; CHECK-NEXT:     Grouped accesses:
683; CHECK-EMPTY:
684; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
685; CHECK-NEXT:     SCEV assumptions:
686; CHECK-EMPTY:
687; CHECK-NEXT:     Expressions re-written:
688
689define dso_local void @forked_ptrs_two_forks_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
690entry:
691  br label %for.body
692
693for.cond.cleanup:
694  ret void
695
696for.body:
697  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
698  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
699  %0 = load i32, ptr %arrayidx, align 4
700  %cmp1.not = icmp eq i32 %0, 0
701  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
702  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
703  %offset = select i1 %cmp1.not, i64 %indvars.iv.next, i64 %indvars.iv
704  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %offset
705  %.sink = load float, ptr %.sink.in, align 4
706  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
707  store float %.sink, ptr %1, align 4
708  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
709  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
710}
711
712;; We don't handle forks as children of a select
713
714; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_select':
715; CHECK-NEXT:  loop:
716; CHECK-NEXT:    Report: cannot identify array bounds
717; CHECK-NEXT:    Dependences:
718; CHECK-NEXT:    Run-time memory checks:
719; CHECK-NEXT:    Grouped accesses:
720; CHECK-EMPTY:
721; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
722; CHECK-NEXT:    SCEV assumptions:
723; CHECK-EMPTY:
724; CHECK-NEXT:    Expressions re-written:
725
726define void @forked_ptrs_two_select(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture readonly %Base3, ptr %Dest) {
727entry:
728  br label %loop
729
730loop:
731  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
732  %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
733  %l.Dest = load float, ptr %gep.Dest
734  %cmp = fcmp une float %l.Dest, 0.0
735  %cmp1 = fcmp une float %l.Dest, 1.0
736  %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv
737  %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv
738  %gep.3 = getelementptr inbounds float, ptr %Base3, i64 %iv
739  %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
740  %select1 = select i1 %cmp1, ptr %select, ptr %gep.3
741  %sink = load float, ptr %select1, align 4
742  store float %sink, ptr %gep.Dest, align 4
743  %iv.next = add nuw nsw i64 %iv, 1
744  %exitcond.not = icmp eq i64 %iv.next, 100
745  br i1 %exitcond.not, label %exit, label %loop
746
747exit:
748  ret void
749}
750
751;; We don't yet handle geps with more than 2 operands
752; CHECK-LABEL: Loop access info in function 'forked_ptrs_too_many_gep_ops':
753; CHECK-NEXT:   for.body:
754; CHECK-NEXT:     Report: cannot identify array bounds
755; CHECK-NEXT:     Dependences:
756; CHECK-NEXT:     Run-time memory checks:
757; CHECK-NEXT:     Grouped accesses:
758; CHECK-EMPTY:
759; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
760; CHECK-NEXT:     SCEV assumptions:
761; CHECK-EMPTY:
762; CHECK-NEXT:     Expressions re-written:
763
764define void @forked_ptrs_too_many_gep_ops(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
765entry:
766  br label %for.body
767
768for.body:
769  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
770  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
771  %0 = load i32, ptr %arrayidx, align 4
772  %cmp1.not = icmp eq i32 %0, 0
773  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
774  %.sink.in = getelementptr inbounds [1000 x float], ptr %spec.select, i64 0, i64 %indvars.iv
775  %.sink = load float, ptr %.sink.in, align 4
776  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
777  store float %.sink, ptr %1, align 4
778  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
779  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
780  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
781
782for.cond.cleanup:
783  ret void
784}
785
786;; We don't currently handle vector GEPs
787; CHECK-LABEL: Loop access info in function 'forked_ptrs_vector_gep':
788; CHECK-NEXT:   for.body:
789; CHECK-NEXT:     Report: cannot identify array bounds
790; CHECK-NEXT:     Dependences:
791; CHECK-NEXT:     Run-time memory checks:
792; CHECK-NEXT:     Grouped accesses:
793; CHECK-EMPTY:
794; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
795; CHECK-NEXT:     SCEV assumptions:
796; CHECK-EMPTY:
797; CHECK-NEXT:     Expressions re-written:
798
799define void @forked_ptrs_vector_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
800entry:
801  br label %for.body
802
803for.body:
804  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
805  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
806  %0 = load i32, ptr %arrayidx, align 4
807  %cmp1.not = icmp eq i32 %0, 0
808  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
809  %.sink.in = getelementptr inbounds <4 x float>, ptr %spec.select, i64 %indvars.iv
810  %.sink = load <4 x float>, ptr %.sink.in, align 4
811  %1 = getelementptr inbounds <4 x float>, ptr %Dest, i64 %indvars.iv
812  store <4 x float> %.sink, ptr %1, align 4
813  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 4
814  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
815  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
816
817for.cond.cleanup:
818  ret void
819}
820