1; RUN: opt -disable-output -passes='print-access-info' %s 2>&1 | FileCheck %s
2
3target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
4
5; CHECK-LABEL: function 'forked_ptrs_simple':
6; CHECK-NEXT:  loop:
7; CHECK-NEXT:    Memory dependences are safe with run-time checks
8; CHECK-NEXT:    Dependences:
9; CHECK-NEXT:    Run-time memory checks:
10; CHECK-NEXT:    Check 0:
11; CHECK-NEXT:      Comparing group ([[G1:.+]]):
12; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
13; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
14; CHECK-NEXT:      Against group ([[G2:.+]]):
15; CHECK-NEXT:        %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
16; CHECK-NEXT:    Check 1:
17; CHECK-NEXT:      Comparing group ([[G1]]):
18; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
19; CHECK-NEXT:        %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
20; CHECK-NEXT:      Against group ([[G3:.+]]):
21; CHECK-NEXT:        %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
22; CHECK-NEXT:    Grouped accesses:
23; CHECK-NEXT:      Group [[G1]]
24; CHECK-NEXT:        (Low: %Dest High: (400 + %Dest))
25; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%loop>
26; CHECK-NEXT:          Member: {%Dest,+,4}<nuw><%loop>
27; CHECK-NEXT:      Group [[G2]]:
28; CHECK-NEXT:        (Low: %Base1 High: (400 + %Base1))
29; CHECK-NEXT:          Member: {%Base1,+,4}<nw><%loop>
30; CHECK-NEXT:      Group [[G3]]:
31; CHECK-NEXT:        (Low: %Base2 High: (400 + %Base2))
32; CHECK-NEXT:          Member: {%Base2,+,4}<nw><%loop>
33; CHECK-EMPTY:
34; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
35; CHECK-NEXT:    SCEV assumptions:
36; CHECK-EMPTY:
37; CHECK-NEXT:    Expressions re-written:
38
39define void @forked_ptrs_simple(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr %Dest) {
40entry:
41  br label %loop
42
43loop:
44  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
45  %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
46  %l.Dest = load float, ptr %gep.Dest
47  %cmp = fcmp une float %l.Dest, 0.0
48  %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv
49  %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv
50  %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
51  %sink = load float, ptr %select, align 4
52  store float %sink, ptr %gep.Dest, align 4
53  %iv.next = add nuw nsw i64 %iv, 1
54  %exitcond.not = icmp eq i64 %iv.next, 100
55  br i1 %exitcond.not, label %exit, label %loop
56
57exit:
58  ret void
59}
60
61; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset':
62; CHECK-NEXT: for.body:
63; CHECK-NEXT:   Report: cannot identify array bounds
64; CHECK-NEXT:   Dependences:
65; CHECK-NEXT:   Run-time memory checks:
66; CHECK-NEXT:   Grouped accesses:
67; CHECK-EMPTY:
68; CHECK-NEXT:   Non vectorizable stores to invariant address were not found in loop.
69; CHECK-NEXT:   SCEV assumptions:
70; CHECK-EMPTY:
71; CHECK-NEXT:   Expressions re-written:
72
73;;;; Derived from the following C code
74;; void forked_ptrs_different_base_same_offset(float *A, float *B, float *C, int *D) {
75;;   for (int i=0; i<100; i++) {
76;;     if (D[i] != 0) {
77;;       C[i] = A[i];
78;;     } else {
79;;       C[i] = B[i];
80;;     }
81;;   }
82;; }
83
84define 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) {
85entry:
86  br label %for.body
87
88for.cond.cleanup:
89  ret void
90
91for.body:
92  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
93  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
94  %0 = load i32, ptr %arrayidx, align 4
95  %cmp1.not = icmp eq i32 %0, 0
96  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
97  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
98  %.sink = load float, ptr %.sink.in, align 4
99  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
100  store float %.sink, ptr %1, align 4
101  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
102  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
103  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
104}
105
106; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset_possible_poison':
107; CHECK-NEXT: for.body:
108; CHECK-NEXT:   Report: cannot identify array bounds
109; CHECK-NEXT:   Dependences:
110; CHECK-NEXT:   Run-time memory checks:
111; CHECK-NEXT:   Grouped accesses:
112; CHECK-EMPTY:
113; CHECK-NEXT:   Non vectorizable stores to invariant address were not found in loop.
114; CHECK-NEXT:   SCEV assumptions:
115; CHECK-EMPTY:
116; CHECK-NEXT:   Expressions re-written:
117
118define 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) {
119entry:
120  br label %for.body
121
122for.cond.cleanup:
123  ret void
124
125for.body:
126  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %latch ]
127  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
128  %0 = load i32, ptr %arrayidx, align 4
129  %cmp1.not = icmp eq i32 %0, 0
130  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
131  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %indvars.iv
132  %.sink = load float, ptr %.sink.in, align 4
133  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
134  br i1 %c, label %then, label %latch
135
136then:
137  store float %.sink, ptr %1, align 4
138  br label %latch
139
140latch:
141  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
142  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
143  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
144}
145
146; CHECK-LABEL: function 'forked_ptrs_same_base_different_offset':
147; CHECK-NEXT:   for.body:
148; CHECK-NEXT:     Report: cannot identify array bounds
149; CHECK-NEXT:     Dependences:
150; CHECK-NEXT:     Run-time memory checks:
151; CHECK-NEXT:     Grouped accesses:
152; CHECK-EMPTY:
153; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
154; CHECK-NEXT:     SCEV assumptions:
155; CHECK-EMPTY:
156; CHECK-NEXT:     Expressions re-written:
157
158;;;; Derived from the following C code
159;; void forked_ptrs_same_base_different_offset(float *A, float *B, int *C) {
160;;   int offset;
161;;   for (int i = 0; i < 100; i++) {
162;;     if (C[i] != 0)
163;;       offset = i;
164;;     else
165;;       offset = i+1;
166;;     B[i] = A[offset];
167;;   }
168;; }
169
170define dso_local void @forked_ptrs_same_base_different_offset(ptr nocapture readonly %Base, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
171entry:
172  br label %for.body
173
174for.cond.cleanup:                                 ; preds = %for.body
175  ret void
176
177for.body:                                         ; preds = %entry, %for.body
178  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
179  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
180  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
181  %0 = load i32, ptr %arrayidx, align 4
182  %cmp1.not = icmp eq i32 %0, 0
183  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
184  %add = add nuw nsw i32 %i.014, 1
185  %1 = trunc i64 %indvars.iv to i32
186  %offset.0 = select i1 %cmp1.not, i32 %add, i32 %1
187  %idxprom213 = zext i32 %offset.0 to i64
188  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213
189  %2 = load float, ptr %arrayidx3, align 4
190  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
191  store float %2, ptr %arrayidx5, align 4
192  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
193  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
194}
195
196;;;; Cases that can be handled by a forked pointer but are not currently allowed.
197
198; CHECK-LABEL: function 'forked_ptrs_uniform_and_strided_forks':
199; CHECK-NEXT:  for.body:
200; CHECK-NEXT:    Report: cannot identify array bounds
201; CHECK-NEXT:    Dependences:
202; CHECK-NEXT:    Run-time memory checks:
203; CHECK-NEXT:    Grouped accesses:
204; CHECK-EMPTY:
205; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
206; CHECK-NEXT:    SCEV assumptions:
207; CHECK-EMPTY:
208; CHECK-NEXT:    Expressions re-written:
209
210;;;; Derived from forked_ptrs_same_base_different_offset with a manually
211;;;; added uniform offset and a mul to provide a stride
212
213define dso_local void @forked_ptrs_uniform_and_strided_forks(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) {
214entry:
215  br label %for.body
216
217for.cond.cleanup:                                 ; preds = %for.body
218  ret void
219
220for.body:                                         ; preds = %entry, %for.body
221  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
222  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
223  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
224  %0 = load i32, ptr %arrayidx, align 4
225  %cmp1.not = icmp eq i32 %0, 0
226  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
227  %add = add nuw nsw i32 %i.014, 1
228  %1 = trunc i64 %indvars.iv to i32
229  %mul = mul i32 %1, 3
230  %offset.0 = select i1 %cmp1.not, i32 4, i32 %mul
231  %idxprom213 = sext i32 %offset.0 to i64
232  %arrayidx3 = getelementptr inbounds float, ptr %Base, i64 %idxprom213
233  %2 = load float, ptr %arrayidx3, align 4
234  %arrayidx5 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
235  store float %2, ptr %arrayidx5, align 4
236  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
237  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
238}
239
240; CHECK-LABEL:  function 'forked_ptrs_gather_and_contiguous_forks':
241; CHECK-NEXT:   for.body:
242; CHECK-NEXT:     Report: cannot identify array bounds
243; CHECK-NEXT:     Dependences:
244; CHECK-NEXT:     Run-time memory checks:
245; CHECK-NEXT:     Grouped accesses:
246; CHECK-EMPTY:
247; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
248; CHECK-NEXT:     SCEV assumptions:
249; CHECK-EMPTY:
250; CHECK-NEXT:     Expressions re-written:
251
252;;;; Derived from forked_ptrs_same_base_different_offset with a gather
253;;;; added using Preds as an index array in addition to the per-iteration
254;;;; condition.
255
256define dso_local void @forked_ptrs_gather_and_contiguous_forks(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
257entry:
258  br label %for.body
259
260for.cond.cleanup:                                 ; preds = %for.body
261  ret void
262
263for.body:                                         ; preds = %entry, %for.body
264  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
265  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
266  %0 = load i32, ptr %arrayidx, align 4
267  %cmp1.not = icmp eq i32 %0, 0
268  %arrayidx9 = getelementptr inbounds float, ptr %Base2, i64 %indvars.iv
269  %idxprom4 = sext i32 %0 to i64
270  %arrayidx5 = getelementptr inbounds float, ptr %Base1, i64 %idxprom4
271  %.sink.in = select i1 %cmp1.not, ptr %arrayidx9, ptr %arrayidx5
272  %.sink = load float, ptr %.sink.in, align 4
273  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
274  store float %.sink, ptr %1, align 4
275  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
276  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
277  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
278}
279
280;; We don't currently handle a fork in both the base and the offset of a
281;; GEP instruction.
282
283; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_forks_gep':
284; CHECK-NEXT:   for.body:
285; CHECK-NEXT:     Report: cannot identify array bounds
286; CHECK-NEXT:     Dependences:
287; CHECK-NEXT:     Run-time memory checks:
288; CHECK-NEXT:     Grouped accesses:
289; CHECK-EMPTY:
290; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
291; CHECK-NEXT:     SCEV assumptions:
292; CHECK-EMPTY:
293; CHECK-NEXT:     Expressions re-written:
294
295define dso_local void @forked_ptrs_two_forks_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
296entry:
297  br label %for.body
298
299for.cond.cleanup:
300  ret void
301
302for.body:
303  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
304  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
305  %0 = load i32, ptr %arrayidx, align 4
306  %cmp1.not = icmp eq i32 %0, 0
307  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
308  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
309  %offset = select i1 %cmp1.not, i64 %indvars.iv.next, i64 %indvars.iv
310  %.sink.in = getelementptr inbounds float, ptr %spec.select, i64 %offset
311  %.sink = load float, ptr %.sink.in, align 4
312  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
313  store float %.sink, ptr %1, align 4
314  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
315  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
316}
317
318;; We don't handle forks as children of a select
319
320; CHECK-LABEL: Loop access info in function 'forked_ptrs_two_select':
321; CHECK-NEXT:  loop:
322; CHECK-NEXT:    Report: cannot identify array bounds
323; CHECK-NEXT:    Dependences:
324; CHECK-NEXT:    Run-time memory checks:
325; CHECK-NEXT:    Grouped accesses:
326; CHECK-EMPTY:
327; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
328; CHECK-NEXT:    SCEV assumptions:
329; CHECK-EMPTY:
330; CHECK-NEXT:    Expressions re-written:
331
332define void @forked_ptrs_two_select(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture readonly %Base3, ptr %Dest) {
333entry:
334  br label %loop
335
336loop:
337  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
338  %gep.Dest = getelementptr inbounds float, ptr %Dest, i64 %iv
339  %l.Dest = load float, ptr %gep.Dest
340  %cmp = fcmp une float %l.Dest, 0.0
341  %cmp1 = fcmp une float %l.Dest, 1.0
342  %gep.1 = getelementptr inbounds float, ptr %Base1, i64 %iv
343  %gep.2 = getelementptr inbounds float, ptr %Base2, i64 %iv
344  %gep.3 = getelementptr inbounds float, ptr %Base3, i64 %iv
345  %select = select i1 %cmp, ptr %gep.1, ptr %gep.2
346  %select1 = select i1 %cmp1, ptr %select, ptr %gep.3
347  %sink = load float, ptr %select1, align 4
348  store float %sink, ptr %gep.Dest, align 4
349  %iv.next = add nuw nsw i64 %iv, 1
350  %exitcond.not = icmp eq i64 %iv.next, 100
351  br i1 %exitcond.not, label %exit, label %loop
352
353exit:
354  ret void
355}
356
357;; We don't yet handle geps with more than 2 operands
358; CHECK-LABEL: Loop access info in function 'forked_ptrs_too_many_gep_ops':
359; CHECK-NEXT:   for.body:
360; CHECK-NEXT:     Report: cannot identify array bounds
361; CHECK-NEXT:     Dependences:
362; CHECK-NEXT:     Run-time memory checks:
363; CHECK-NEXT:     Grouped accesses:
364; CHECK-EMPTY:
365; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
366; CHECK-NEXT:     SCEV assumptions:
367; CHECK-EMPTY:
368; CHECK-NEXT:     Expressions re-written:
369
370define void @forked_ptrs_too_many_gep_ops(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
371entry:
372  br label %for.body
373
374for.body:
375  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
376  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
377  %0 = load i32, ptr %arrayidx, align 4
378  %cmp1.not = icmp eq i32 %0, 0
379  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
380  %.sink.in = getelementptr inbounds [1000 x float], ptr %spec.select, i64 0, i64 %indvars.iv
381  %.sink = load float, ptr %.sink.in, align 4
382  %1 = getelementptr inbounds float, ptr %Dest, i64 %indvars.iv
383  store float %.sink, ptr %1, align 4
384  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
385  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
386  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
387
388for.cond.cleanup:
389  ret void
390}
391
392;; We don't currently handle vector GEPs
393; CHECK-LABEL: Loop access info in function 'forked_ptrs_vector_gep':
394; CHECK-NEXT:   for.body:
395; CHECK-NEXT:     Report: cannot identify array bounds
396; CHECK-NEXT:     Dependences:
397; CHECK-NEXT:     Run-time memory checks:
398; CHECK-NEXT:     Grouped accesses:
399; CHECK-EMPTY:
400; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
401; CHECK-NEXT:     SCEV assumptions:
402; CHECK-EMPTY:
403; CHECK-NEXT:     Expressions re-written:
404
405define void @forked_ptrs_vector_gep(ptr nocapture readonly %Base1, ptr nocapture readonly %Base2, ptr nocapture %Dest, ptr nocapture readonly %Preds) {
406entry:
407  br label %for.body
408
409for.body:
410  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
411  %arrayidx = getelementptr inbounds i32, ptr %Preds, i64 %indvars.iv
412  %0 = load i32, ptr %arrayidx, align 4
413  %cmp1.not = icmp eq i32 %0, 0
414  %spec.select = select i1 %cmp1.not, ptr %Base2, ptr %Base1
415  %.sink.in = getelementptr inbounds <4 x float>, ptr %spec.select, i64 %indvars.iv
416  %.sink = load <4 x float>, ptr %.sink.in, align 4
417  %1 = getelementptr inbounds <4 x float>, ptr %Dest, i64 %indvars.iv
418  store <4 x float> %.sink, ptr %1, align 4
419  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 4
420  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
421  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
422
423for.cond.cleanup:
424  ret void
425}
426