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