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:    Report: cannot identify array bounds
8; CHECK-NEXT:    Dependences:
9; CHECK-NEXT:    Run-time memory checks:
10; CHECK-NEXT:    Grouped accesses:
11; CHECK-EMPTY:
12; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
13; CHECK-NEXT:    SCEV assumptions:
14; CHECK-EMPTY:
15; CHECK-NEXT:    Expressions re-written:
16
17define void @forked_ptrs_simple(float* nocapture readonly %Base1, float* nocapture readonly %Base2, float* %Dest) {
18entry:
19  br label %loop
20
21loop:
22  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
23  %gep.Dest = getelementptr inbounds float, float* %Dest, i64 %iv
24  %l.Dest = load float, float* %gep.Dest
25  %cmp = fcmp une float %l.Dest, 0.0
26  %gep.1 = getelementptr inbounds float, float* %Base1, i64 %iv
27  %gep.2 = getelementptr inbounds float, float* %Base2, i64 %iv
28  %select = select i1 %cmp, float* %gep.1, float* %gep.2
29  %sink = load float, float* %select, align 4
30  store float %sink, float* %gep.Dest, align 4
31  %iv.next = add nuw nsw i64 %iv, 1
32  %exitcond.not = icmp eq i64 %iv.next, 100
33  br i1 %exitcond.not, label %exit, label %loop
34
35exit:
36  ret void
37}
38
39
40; CHECK-LABEL: function 'forked_ptrs_different_base_same_offset':
41; CHECK-NEXT:  for.body:
42; CHECK-NEXT:    Report: cannot identify array bounds
43; CHECK-NEXT:    Dependences:
44; CHECK-NEXT:    Run-time memory checks:
45; CHECK-NEXT:    Grouped accesses:
46; CHECK-EMPTY:
47; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
48; CHECK-NEXT:    SCEV assumptions:
49; CHECK-EMPTY:
50; CHECK-NEXT:    Expressions re-written:
51
52;;;; Derived from the following C code
53;; void forked_ptrs_different_base_same_offset(float *A, float *B, float *C, int *D) {
54;;   for (int i=0; i<100; i++) {
55;;     if (D[i] != 0) {
56;;       C[i] = A[i];
57;;     } else {
58;;       C[i] = B[i];
59;;     }
60;;   }
61;; }
62
63define dso_local void @forked_ptrs_different_base_same_offset(float* nocapture readonly %Base1, float* nocapture readonly %Base2, float* nocapture %Dest, i32* nocapture readonly %Preds) {
64entry:
65  br label %for.body
66
67for.cond.cleanup:
68  ret void
69
70for.body:
71  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
72  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
73  %0 = load i32, i32* %arrayidx, align 4
74  %cmp1.not = icmp eq i32 %0, 0
75  %spec.select = select i1 %cmp1.not, float* %Base2, float* %Base1
76  %.sink.in = getelementptr inbounds float, float* %spec.select, i64 %indvars.iv
77  %.sink = load float, float* %.sink.in, align 4
78  %1 = getelementptr inbounds float, float* %Dest, i64 %indvars.iv
79  store float %.sink, float* %1, align 4
80  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
81  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
82  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
83}
84
85; CHECK-LABEL: function 'forked_ptrs_same_base_different_offset':
86; CHECK-NEXT:   for.body:
87; CHECK-NEXT:     Report: cannot identify array bounds
88; CHECK-NEXT:     Dependences:
89; CHECK-NEXT:     Run-time memory checks:
90; CHECK-NEXT:     Grouped accesses:
91; CHECK-EMPTY:
92; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
93; CHECK-NEXT:     SCEV assumptions:
94; CHECK-EMPTY:
95; CHECK-NEXT:     Expressions re-written:
96
97;;;; Derived from the following C code
98;; void forked_ptrs_same_base_different_offset(float *A, float *B, int *C) {
99;;   int offset;
100;;   for (int i = 0; i < 100; i++) {
101;;     if (C[i] != 0)
102;;       offset = i;
103;;     else
104;;       offset = i+1;
105;;     B[i] = A[offset];
106;;   }
107;; }
108
109define dso_local void @forked_ptrs_same_base_different_offset(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) {
110entry:
111  br label %for.body
112
113for.cond.cleanup:                                 ; preds = %for.body
114  ret void
115
116for.body:                                         ; preds = %entry, %for.body
117  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
118  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
119  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
120  %0 = load i32, i32* %arrayidx, align 4
121  %cmp1.not = icmp eq i32 %0, 0
122  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
123  %add = add nuw nsw i32 %i.014, 1
124  %1 = trunc i64 %indvars.iv to i32
125  %offset.0 = select i1 %cmp1.not, i32 %add, i32 %1
126  %idxprom213 = zext i32 %offset.0 to i64
127  %arrayidx3 = getelementptr inbounds float, float* %Base, i64 %idxprom213
128  %2 = load float, float* %arrayidx3, align 4
129  %arrayidx5 = getelementptr inbounds float, float* %Dest, i64 %indvars.iv
130  store float %2, float* %arrayidx5, align 4
131  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
132  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
133}
134
135;;;; Cases that can be handled by a forked pointer but are not currently allowed.
136
137; CHECK-LABEL: function 'forked_ptrs_uniform_and_strided_forks':
138; CHECK-NEXT:  for.body:
139; CHECK-NEXT:    Report: cannot identify array bounds
140; CHECK-NEXT:    Dependences:
141; CHECK-NEXT:    Run-time memory checks:
142; CHECK-NEXT:    Grouped accesses:
143; CHECK-EMPTY:
144; CHECK-NEXT:    Non vectorizable stores to invariant address were not found in loop.
145; CHECK-NEXT:    SCEV assumptions:
146; CHECK-EMPTY:
147; CHECK-NEXT:    Expressions re-written:
148
149;;;; Derived from forked_ptrs_same_base_different_offset with a manually
150;;;; added uniform offset and a mul to provide a stride
151
152define dso_local void @forked_ptrs_uniform_and_strided_forks(float* nocapture readonly %Base, float* nocapture %Dest, i32* nocapture readonly %Preds) {
153entry:
154  br label %for.body
155
156for.cond.cleanup:                                 ; preds = %for.body
157  ret void
158
159for.body:                                         ; preds = %entry, %for.body
160  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
161  %i.014 = phi i32 [ 0, %entry ], [ %add, %for.body ]
162  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
163  %0 = load i32, i32* %arrayidx, align 4
164  %cmp1.not = icmp eq i32 %0, 0
165  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
166  %add = add nuw nsw i32 %i.014, 1
167  %1 = trunc i64 %indvars.iv to i32
168  %mul = mul i32 %1, 3
169  %offset.0 = select i1 %cmp1.not, i32 4, i32 %mul
170  %idxprom213 = sext i32 %offset.0 to i64
171  %arrayidx3 = getelementptr inbounds float, float* %Base, i64 %idxprom213
172  %2 = load float, float* %arrayidx3, align 4
173  %arrayidx5 = getelementptr inbounds float, float* %Dest, i64 %indvars.iv
174  store float %2, float* %arrayidx5, align 4
175  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
176  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
177}
178
179; CHECK-LABEL:  function 'forked_ptrs_gather_and_contiguous_forks':
180; CHECK-NEXT:   for.body:
181; CHECK-NEXT:     Report: cannot identify array bounds
182; CHECK-NEXT:     Dependences:
183; CHECK-NEXT:     Run-time memory checks:
184; CHECK-NEXT:     Grouped accesses:
185; CHECK-EMPTY:
186; CHECK-NEXT:     Non vectorizable stores to invariant address were not found in loop.
187; CHECK-NEXT:     SCEV assumptions:
188; CHECK-EMPTY:
189; CHECK-NEXT:     Expressions re-written:
190
191;;;; Derived from forked_ptrs_same_base_different_offset with a gather
192;;;; added using Preds as an index array in addition to the per-iteration
193;;;; condition.
194
195define dso_local void @forked_ptrs_gather_and_contiguous_forks(float* nocapture readonly %Base1, float* nocapture readonly %Base2, float* nocapture %Dest, i32* nocapture readonly %Preds) {
196entry:
197  br label %for.body
198
199for.cond.cleanup:                                 ; preds = %for.body
200  ret void
201
202for.body:                                         ; preds = %entry, %for.body
203  %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]
204  %arrayidx = getelementptr inbounds i32, i32* %Preds, i64 %indvars.iv
205  %0 = load i32, i32* %arrayidx, align 4
206  %cmp1.not = icmp eq i32 %0, 0
207  %arrayidx9 = getelementptr inbounds float, float* %Base2, i64 %indvars.iv
208  %idxprom4 = sext i32 %0 to i64
209  %arrayidx5 = getelementptr inbounds float, float* %Base1, i64 %idxprom4
210  %.sink.in = select i1 %cmp1.not, float* %arrayidx9, float* %arrayidx5
211  %.sink = load float, float* %.sink.in, align 4
212  %1 = getelementptr inbounds float, float* %Dest, i64 %indvars.iv
213  store float %.sink, float* %1, align 4
214  %indvars.iv.next = add nuw nsw i64 %indvars.iv, 1
215  %exitcond.not = icmp eq i64 %indvars.iv.next, 100
216  br i1 %exitcond.not, label %for.cond.cleanup, label %for.body
217}
218