[flang] Fix crash in HLFIR generation (#118399)
[llvm-project.git] / llvm / test / Transforms / LoopVectorize / X86 / drop-poison-generating-flags.ll
blobf6f77e274273e381b2ca56367864f9374f0fa229
1 ; RUN: opt %s -passes=loop-vectorize -force-vector-width=4 -force-vector-interleave=1 -S | FileCheck %s
3 ; Make sure that integer poison-generating flags (i.e., nuw/nsw, exact and inbounds)
4 ; are dropped from instructions in blocks that need predication and are linearized
5 ; and masked after vectorization. We only drop flags from scalar instructions that
6 ; contribute to the address computation of a masked vector load/store. After
7 ; linearizing the control flow and removing their guarding condition, these
8 ; instructions could generate a poison value which would be used as base address of
9 ; the masked vector load/store (see PR52111). For gather/scatter cases,
10 ; posiong-generating flags can be preserved since poison addresses in the vector GEP
11 ; reaching the gather/scatter instruction will be masked-out by the gather/scatter
12 ; instruction itself and won't be used.
13 ; We need AVX512 target features for the loop to be vectorized with masks instead of
14 ; predicates.
16 target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
17 target triple = "x86_64-pc-linux-gnu"
19 ; Drop poison-generating flags from 'sub' and 'getelementptr' feeding a masked load.
20 ; Test for PR52111.
21 define void @drop_scalar_nuw_nsw(ptr noalias nocapture readonly %input,
22                                  ptr %output) local_unnamed_addr #0 {
23 ; CHECK-LABEL: @drop_scalar_nuw_nsw(
24 ; CHECK:       vector.body:
25 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
26 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
27 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
28 ; CHECK:         [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
29 ; CHECK-NEXT:    [[TMP7:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
30 ; CHECK-NEXT:    [[TMP5:%.*]] = sub i64 [[TMP0]], 1
31 ; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr float, ptr [[INPUT:%.*]], i64 [[TMP5]]
32 ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr float, ptr [[TMP6]], i32 0
33 ; CHECK-NEXT:    [[WIDE_MASKED_LOAD:%.*]] = call <4 x float> @llvm.masked.load.v4f32.p0(ptr [[TMP8]], i32 4, <4 x i1> [[TMP7]], <4 x float> poison), !invariant.load !0
34 entry:
35   br label %loop.header
37 loop.header:
38   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
39   %i23 = icmp eq i64 %iv, 0
40   br i1 %i23, label %if.end, label %if.then
42 if.then:
43   %i27 = sub nuw nsw i64 %iv, 1
44   %i29 = getelementptr inbounds float, ptr %input, i64 %i27
45   %i30 = load float, ptr %i29, align 4, !invariant.load !0
46   br label %if.end
48 if.end:
49   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
50   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
51   store float %i34, ptr %i35, align 4
52   %iv.inc = add nuw nsw i64 %iv, 1
53   %exitcond = icmp eq i64 %iv.inc, 4
54   br i1 %exitcond, label %loop.exit, label %loop.header
56 loop.exit:
57   ret void
60 ; Drop poison-generating flags from 'sub' and 'getelementptr' feeding a masked load.
61 ; In this case, 'sub' and 'getelementptr' are not guarded by the predicate.
62 define void @drop_nonpred_scalar_nuw_nsw(ptr noalias nocapture readonly %input,
63                                          ptr %output) local_unnamed_addr #0 {
64 ; CHECK-LABEL: @drop_nonpred_scalar_nuw_nsw(
65 ; CHECK:       vector.body:
66 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
67 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
68 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
69 ; CHECK:         [[TMP5:%.*]] = sub i64 [[TMP0]], 1
70 ; CHECK-NEXT:    [[TMP6:%.*]] = getelementptr float, ptr [[INPUT:%.*]], i64 [[TMP5]]
71 ; CHECK-NEXT:    [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
72 ; CHECK-NEXT:    [[TMP7:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
73 ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr float, ptr [[TMP6]], i32 0
74 ; CHECK-NEXT:    [[WIDE_MASKED_LOAD:%.*]] = call <4 x float> @llvm.masked.load.v4f32.p0(ptr [[TMP8]], i32 4, <4 x i1> [[TMP7]], <4 x float> poison), !invariant.load !0
75 entry:
76   br label %loop.header
78 loop.header:
79   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
80   %i27 = sub i64 %iv, 1
81   %i29 = getelementptr float, ptr %input, i64 %i27
82   %i23 = icmp eq i64 %iv, 0
83   br i1 %i23, label %if.end, label %if.then
85 if.then:
86   %i30 = load float, ptr %i29, align 4, !invariant.load !0
87   br label %if.end
89 if.end:
90   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
91   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
92   store float %i34, ptr %i35, align 4
93   %iv.inc = add nuw nsw i64 %iv, 1
94   %exitcond = icmp eq i64 %iv.inc, 4
95   br i1 %exitcond, label %loop.exit, label %loop.header
97 loop.exit:
98   ret void
101 ; Preserve poison-generating flags from vector 'sub', 'mul' and 'getelementptr' feeding a masked gather.
102 define void @preserve_vector_nuw_nsw(ptr noalias nocapture readonly %input,
103                                      ptr %output) local_unnamed_addr #0 {
104 ; CHECK-LABEL: @preserve_vector_nuw_nsw(
105 ; CHECK:       vector.body:
106 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
107 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
108 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
109 ; CHECK:         [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
110 ; CHECK-NEXT:    [[TMP8:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
111 ; CHECK-NEXT:    [[TMP5:%.*]] = sub nuw nsw <4 x i64> [[VEC_IND]], splat (i64 1)
112 ; CHECK-NEXT:    [[TMP6:%.*]] = mul nuw nsw <4 x i64> [[TMP5]], splat (i64 2)
113 ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds float, ptr [[INPUT:%.*]], <4 x i64> [[TMP6]]
114 ; CHECK-NEXT:    [[WIDE_MASKED_GATHER:%.*]] = call <4 x float> @llvm.masked.gather.v4f32.v4p0(<4 x ptr> [[TMP7]], i32 4, <4 x i1> [[TMP8]], <4 x float> poison), !invariant.load !0
115 entry:
116   br label %loop.header
118 loop.header:
119   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
120   %i23 = icmp eq i64 %iv, 0
121   br i1 %i23, label %if.end, label %if.then
123 if.then:
124   %i27 = sub nuw nsw i64 %iv, 1
125   %i28 = mul nuw nsw i64 %i27, 2
126   %i29 = getelementptr inbounds float, ptr %input, i64 %i28
127   %i30 = load float, ptr %i29, align 4, !invariant.load !0
128   br label %if.end
130 if.end:
131   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
132   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
133   store float %i34, ptr %i35, align 4
134   %iv.inc = add nuw nsw i64 %iv, 1
135   %exitcond = icmp eq i64 %iv.inc, 4
136   br i1 %exitcond, label %loop.exit, label %loop.header
138 loop.exit:
139   ret void
142 ; Drop poison-generating flags from vector 'sub' and 'gep' feeding a masked load.
143 define void @drop_vector_nuw_nsw(ptr noalias nocapture readonly %input,
144                                  ptr %output, ptr noalias %ptrs) local_unnamed_addr #0 {
145 ; CHECK-LABEL: @drop_vector_nuw_nsw(
146 ; CHECK:       vector.body:
147 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
148 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
149 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
150 ; CHECK:         [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
151 ; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr inbounds ptr, ptr [[PTRS:%.*]], i64 [[TMP0]]
152 ; CHECK-NEXT:    [[TMP6:%.*]] = sub <4 x i64> [[VEC_IND]], splat (i64 1)
153 ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr float, ptr [[INPUT:%.*]], <4 x i64> [[TMP6]]
154 ; CHECK:         [[TMP10:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
155 ; CHECK-NEXT:    [[TMP11:%.*]] = extractelement <4 x ptr> [[TMP7]], i32 0
156 ; CHECK-NEXT:    [[TMP12:%.*]] = getelementptr float, ptr [[TMP11]], i32 0
157 ; CHECK-NEXT:    [[WIDE_MASKED_LOAD:%.*]] = call <4 x float> @llvm.masked.load.v4f32.p0(ptr [[TMP12]], i32 4, <4 x i1> [[TMP10]], <4 x float> poison), !invariant.load !0
158 entry:
159   br label %loop.header
161 loop.header:
162   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
163   %i23 = icmp eq i64 %iv, 0
164   %gep = getelementptr inbounds ptr, ptr %ptrs, i64 %iv
165   %i27 = sub nuw nsw i64 %iv, 1
166   %i29 = getelementptr inbounds float, ptr %input, i64 %i27
167   store ptr %i29, ptr %gep
168   br i1 %i23, label %if.end, label %if.then
170 if.then:
171   %i30 = load float, ptr %i29, align 4, !invariant.load !0
172   br label %if.end
174 if.end:
175   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
176   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
177   store float %i34, ptr %i35, align 4
178   %iv.inc = add nuw nsw i64 %iv, 1
179   %exitcond = icmp eq i64 %iv.inc, 4
180   br i1 %exitcond, label %loop.exit, label %loop.header
182 loop.exit:
183   ret void
186 ; Preserve poison-generating flags from 'sub', which is not contributing to any address computation
187 ; of any masked load/store/gather/scatter.
188 define void @preserve_nuw_nsw_no_addr(ptr %output) local_unnamed_addr #0 {
189 ; CHECK-LABEL: @preserve_nuw_nsw_no_addr(
190 ; CHECK:       vector.body:
191 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
192 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
193 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
194 ; CHECK:         [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
195 ; CHECK-NEXT:    [[TMP6:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
196 ; CHECK-NEXT:    [[TMP5:%.*]] = sub nuw nsw <4 x i64> [[VEC_IND]], splat (i64 1)
197 ; CHECK-NEXT:    [[PREDPHI:%.*]] = select <4 x i1> [[TMP6]], <4 x i64> [[TMP5]], <4 x i64> zeroinitializer
198 ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds i64, ptr [[OUTPUT:%.*]], i64 [[TMP0]]
199 ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds i64, ptr [[TMP7]], i32 0
200 ; CHECK-NEXT:    store <4 x i64> [[PREDPHI]], ptr [[TMP8]], align 4
201 entry:
202   br label %loop.header
204 loop.header:
205   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
206   %i23 = icmp eq i64 %iv, 0
207   br i1 %i23, label %if.end, label %if.then
209 if.then:
210   %i27 = sub nuw nsw i64 %iv, 1
211   br label %if.end
213 if.end:
214   %i34 = phi i64 [ 0, %loop.header ], [ %i27, %if.then ]
215   %i35 = getelementptr inbounds i64, ptr %output, i64 %iv
216   store i64 %i34, ptr %i35, align 4
217   %iv.inc = add nuw nsw i64 %iv, 1
218   %exitcond = icmp eq i64 %iv.inc, 4
219   br i1 %exitcond, label %loop.exit, label %loop.header
221 loop.exit:
222   ret void
225 ; Drop poison-generating flags from 'sdiv' and 'getelementptr' feeding a masked load.
226 define void @drop_scalar_exact(ptr noalias nocapture readonly %input,
227                                ptr %output) local_unnamed_addr #0 {
228 ; CHECK-LABEL: @drop_scalar_exact(
229 ; CHECK:       vector.body:
230 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
231 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
232 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
233 ; CHECK:         [[TMP4:%.*]] = icmp ne <4 x i64> [[VEC_IND]], zeroinitializer
234 ; CHECK-NEXT:    [[TMP5:%.*]] = and <4 x i64> [[VEC_IND]], splat (i64 1)
235 ; CHECK-NEXT:    [[TMP6:%.*]] = icmp eq <4 x i64> [[TMP5]], zeroinitializer
236 ; CHECK-NEXT:    [[TMP7:%.*]] = and <4 x i1> [[TMP4]], [[TMP6]]
237 ; CHECK-NEXT:    [[TMP10:%.*]] = xor <4 x i1> [[TMP7]], splat (i1 true)
238 ; CHECK-NEXT:    [[TMP8:%.*]] = sdiv i64 [[TMP0]], 1
239 ; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr float, ptr [[INPUT:%.*]], i64 [[TMP8]]
240 ; CHECK-NEXT:    [[TMP11:%.*]] = getelementptr float, ptr [[TMP9]], i32 0
241 ; CHECK-NEXT:    [[WIDE_MASKED_LOAD:%.*]] = call <4 x float> @llvm.masked.load.v4f32.p0(ptr [[TMP11]], i32 4, <4 x i1> [[TMP10]], <4 x float> poison), !invariant.load !0
242 entry:
243   br label %loop.header
245 loop.header:
246   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
247   %i7 = icmp ne i64 %iv, 0
248   %i8 = and i64 %iv, 1
249   %i9 = icmp eq i64 %i8, 0
250   %i10 = and i1 %i7, %i9
251   br i1 %i10, label %if.end, label %if.then
253 if.then:
254   %i26 = sdiv exact i64 %iv, 1
255   %i29 = getelementptr inbounds float, ptr %input, i64 %i26
256   %i30 = load float, ptr %i29, align 4, !invariant.load !0
257   br label %if.end
259 if.end:
260   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
261   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
262   store float %i34, ptr %i35, align 4
263   %iv.inc = add nuw nsw i64 %iv, 1
264   %exitcond = icmp eq i64 %iv.inc, 4
265   br i1 %exitcond, label %loop.exit, label %loop.header
267 loop.exit:
268   ret void
271 define void @drop_zext_nneg(ptr noalias %p, ptr noalias %p1) #0 {
272 ; CHECK-LABEL: define void @drop_zext_nneg(
273 ; CHECK-SAME: ptr noalias [[P:%.*]], ptr noalias [[P1:%.*]]) #[[ATTR0:[0-9]+]] {
274 ; CHECK-NEXT:  entry:
275 ; CHECK-NEXT:    br i1 true, label [[SCALAR_PH:%.*]], label [[VECTOR_SCEVCHECK:%.*]]
276 ; CHECK:       vector.scevcheck:
277 ; CHECK-NEXT:    br i1 true, label [[SCALAR_PH]], label [[VECTOR_PH:%.*]]
278 ; CHECK:       vector.ph:
279 ; CHECK-NEXT:    br label [[VECTOR_BODY:%.*]]
280 ; CHECK:       vector.body:
281 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
282 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i32> [ <i32 0, i32 1, i32 2, i32 3>, [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[VECTOR_BODY]] ]
283 ; CHECK-NEXT:    [[TMP0:%.*]] = icmp eq <4 x i32> [[VEC_IND]], zeroinitializer
284 ; CHECK-NEXT:    [[TMP1:%.*]] = zext <4 x i32> [[VEC_IND]] to <4 x i64>
285 ; CHECK-NEXT:    [[TMP2:%.*]] = extractelement <4 x i64> [[TMP1]], i32 0
286 ; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr double, ptr [[P]], i64 [[TMP2]]
287 ; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr double, ptr [[TMP3]], i32 0
288 ; CHECK-NEXT:    [[WIDE_MASKED_LOAD:%.*]] = call <4 x double> @llvm.masked.load.v4f64.p0(ptr [[TMP4]], i32 8, <4 x i1> [[TMP0]], <4 x double> poison)
289 ; CHECK-NEXT:    [[TMP5:%.*]] = xor <4 x i1> [[TMP0]], splat (i1 true)
290 ; CHECK-NEXT:    [[PREDPHI:%.*]] = select <4 x i1> [[TMP5]], <4 x double> zeroinitializer, <4 x double> [[WIDE_MASKED_LOAD]]
291 ; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <4 x double> [[PREDPHI]], i32 3
292 ; CHECK-NEXT:    store double [[TMP6]], ptr [[P1]], align 8
293 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
294 ; CHECK-NEXT:    [[VEC_IND_NEXT]] = add <4 x i32> [[VEC_IND]], splat (i32 4)
295 ; CHECK-NEXT:    [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 0
296 ; CHECK-NEXT:    br i1 [[TMP7]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP17:![0-9]+]]
297 ; CHECK:       middle.block:
298 ; CHECK-NEXT:    br i1 true, label [[EXIT:%.*]], label [[SCALAR_PH]]
299 ; CHECK:       scalar.ph:
300 ; CHECK-NEXT:    [[BC_RESUME_VAL:%.*]] = phi i64 [ 0, [[MIDDLE_BLOCK]] ], [ 0, [[ENTRY:%.*]] ], [ 0, [[VECTOR_SCEVCHECK]] ]
301 ; CHECK-NEXT:    br label [[BODY:%.*]]
302 ; CHECK:       body:
303 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ [[NEXT:%.*]], [[ELSE:%.*]] ], [ [[BC_RESUME_VAL]], [[SCALAR_PH]] ]
304 ; CHECK-NEXT:    [[TMP8:%.*]] = trunc i64 [[IV]] to i32
305 ; CHECK-NEXT:    [[C:%.*]] = icmp eq i32 [[TMP8]], 0
306 ; CHECK-NEXT:    br i1 [[C]], label [[THEN:%.*]], label [[ELSE]]
307 ; CHECK:       then:
308 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext nneg i32 [[TMP8]] to i64
309 ; CHECK-NEXT:    [[IDX1:%.*]] = getelementptr double, ptr [[P]], i64 [[ZEXT]]
310 ; CHECK-NEXT:    [[IDX2:%.*]] = getelementptr double, ptr [[P]], i64 [[ZEXT]]
311 ; CHECK-NEXT:    [[TMP9:%.*]] = load double, ptr [[IDX2]], align 8
312 ; CHECK-NEXT:    br label [[ELSE]]
313 ; CHECK:       else:
314 ; CHECK-NEXT:    [[PHI:%.*]] = phi double [ [[TMP9]], [[THEN]] ], [ 0.000000e+00, [[BODY]] ]
315 ; CHECK-NEXT:    store double [[PHI]], ptr [[P1]], align 8
316 ; CHECK-NEXT:    [[NEXT]] = add i64 [[IV]], 1
317 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[NEXT]], 0
318 ; CHECK-NEXT:    br i1 [[CMP]], label [[EXIT]], label [[BODY]], !llvm.loop [[LOOP18:![0-9]+]]
319 ; CHECK:       exit:
320 ; CHECK-NEXT:    ret void
322 entry:
323   br label %body
325 body:
326   %iv = phi i64 [ %next, %else ], [ 0, %entry ]
327   %0 = trunc i64 %iv to i32
328   %c = icmp eq i32 %0, 0
329   br i1 %c, label %then, label %else
331 then:
332   %zext = zext nneg i32 %0 to i64
333   %idx1 = getelementptr double, ptr %p, i64 %zext
334   %idx2 = getelementptr double, ptr %p, i64 %zext
335   %1 = load double, ptr %idx2, align 8
336   br label %else
338 else:
339   %phi = phi double [ %1, %then ], [ 0.000000e+00, %body ]
340   store double %phi, ptr %p1, align 8
341   %next = add i64 %iv, 1
342   %cmp = icmp eq i64 %next, 0
343   br i1 %cmp, label %exit, label %body
345 exit:
346   ret void
349 ; Preserve poison-generating flags from 'sdiv' and 'getelementptr' feeding a masked gather.
350 define void @preserve_vector_exact_no_addr(ptr noalias nocapture readonly %input,
351                                            ptr %output) local_unnamed_addr #0 {
352 ; CHECK-LABEL: @preserve_vector_exact_no_addr(
353 ; CHECK:       vector.body:
354 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
355 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
356 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
357 ; CHECK:         [[TMP4:%.*]] = icmp ne <4 x i64> [[VEC_IND]], zeroinitializer
358 ; CHECK-NEXT:    [[TMP5:%.*]] = and <4 x i64> [[VEC_IND]], splat (i64 1)
359 ; CHECK-NEXT:    [[TMP6:%.*]] = icmp eq <4 x i64> [[TMP5]], zeroinitializer
360 ; CHECK-NEXT:    [[TMP7:%.*]] = and <4 x i1> [[TMP4]], [[TMP6]]
361 ; CHECK-NEXT:    [[TMP10:%.*]] = xor <4 x i1> [[TMP7]], splat (i1 true)
362 ; CHECK-NEXT:    [[TMP8:%.*]] = sdiv exact <4 x i64> [[VEC_IND]], splat (i64 2)
363 ; CHECK-NEXT:    [[TMP9:%.*]] = getelementptr inbounds float, ptr [[INPUT:%.*]], <4 x i64> [[TMP8]]
364 ; CHECK-NEXT:    [[WIDE_MASKED_GATHER:%.*]] = call <4 x float> @llvm.masked.gather.v4f32.v4p0(<4 x ptr> [[TMP9]], i32 4, <4 x i1> [[TMP10]], <4 x float> poison), !invariant.load !0
366 entry:
367   br label %loop.header
369 loop.header:
370   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
371   %i7 = icmp ne i64 %iv, 0
372   %i8 = and i64 %iv, 1
373   %i9 = icmp eq i64 %i8, 0
374   %i10 = and i1 %i7, %i9
375   br i1 %i10, label %if.end, label %if.then
377 if.then:
378   %i26 = sdiv exact i64 %iv, 2
379   %i29 = getelementptr inbounds float, ptr %input, i64 %i26
380   %i30 = load float, ptr %i29, align 4, !invariant.load !0
381   br label %if.end
383 if.end:
384   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
385   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
386   store float %i34, ptr %i35, align 4
387   %iv.inc = add nuw nsw i64 %iv, 1
388   %exitcond = icmp eq i64 %iv.inc, 4
389   br i1 %exitcond, label %loop.exit, label %loop.header
391 loop.exit:
392   ret void
395 ; Preserve poison-generating flags from 'sdiv', which is not contributing to any address computation
396 ; of any masked load/store/gather/scatter.
397 define void @preserve_exact_no_addr(ptr %output) local_unnamed_addr #0 {
398 ; CHECK-LABEL: @preserve_exact_no_addr(
399 ; CHECK:       vector.body:
400 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, {{.*}} ]
401 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, {{.*}} ]
402 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
403 ; CHECK:         [[TMP4:%.*]] = icmp eq <4 x i64> [[VEC_IND]], zeroinitializer
404 ; CHECK-NEXT:    [[TMP6:%.*]] = xor <4 x i1> [[TMP4]], splat (i1 true)
405 ; CHECK-NEXT:    [[TMP5:%.*]] = sdiv exact <4 x i64> [[VEC_IND]], splat (i64 2)
406 ; CHECK-NEXT:    [[PREDPHI:%.*]] = select <4 x i1> [[TMP6]], <4 x i64> [[TMP5]], <4 x i64> zeroinitializer
407 ; CHECK-NEXT:    [[TMP7:%.*]] = getelementptr inbounds i64, ptr [[OUTPUT:%.*]], i64 [[TMP0]]
408 ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds i64, ptr [[TMP7]], i32 0
409 ; CHECK-NEXT:    store <4 x i64> [[PREDPHI]], ptr [[TMP8]], align 4
410 entry:
411   br label %loop.header
413 loop.header:
414   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
415   %i23 = icmp eq i64 %iv, 0
416   br i1 %i23, label %if.end, label %if.then
418 if.then:
419   %i27 = sdiv exact i64 %iv, 2
420   br label %if.end
422 if.end:
423   %i34 = phi i64 [ 0, %loop.header ], [ %i27, %if.then ]
424   %i35 = getelementptr inbounds i64, ptr %output, i64 %iv
425   store i64 %i34, ptr %i35, align 4
426   %iv.inc = add nuw nsw i64 %iv, 1
427   %exitcond = icmp eq i64 %iv.inc, 4
428   br i1 %exitcond, label %loop.exit, label %loop.header
430 loop.exit:
431   ret void
434 ; Make sure we don't vectorize a loop with a phi feeding a poison value to
435 ; a masked load/gather.
436 define void @dont_vectorize_poison_phi(ptr noalias nocapture readonly %input,
437 ; CHECK-LABEL: @dont_vectorize_poison_phi(
438 ; CHECK-NEXT:  entry:
439 ; CHECK-NEXT:    br label [[LOOP_HEADER:%.*]]
440 ; CHECK:       loop.header:
441 ; CHECK-NEXT:    [[POISON:%.*]] = phi i64 [ poison, [[ENTRY:%.*]] ], [ [[IV_INC:%.*]], [[IF_END:%.*]] ]
442 ; CHECK-NEXT:    [[IV:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[IV_INC]], [[IF_END]] ]
443 ; CHECK-NEXT:    [[I23:%.*]] = icmp eq i64 [[IV]], 0
444 ; CHECK-NEXT:    br i1 [[I23]], label [[IF_END]], label [[IF_THEN:%.*]]
445 ; CHECK:       if.then:
446 ; CHECK-NEXT:    [[I29:%.*]] = getelementptr inbounds float, ptr [[INPUT:%.*]], i64 [[POISON]]
447 ; CHECK-NEXT:    [[I30:%.*]] = load float, ptr [[I29]], align 4, !invariant.load !0
448 ; CHECK-NEXT:    br label [[IF_END]]
449 ; CHECK:       if.end:
450 ; CHECK-NEXT:    [[I34:%.*]] = phi float [ 0.000000e+00, [[LOOP_HEADER]] ], [ [[I30]], [[IF_THEN]] ]
451 ; CHECK-NEXT:    [[I35:%.*]] = getelementptr inbounds float, ptr [[OUTPUT:%.*]], i64 [[IV]]
452 ; CHECK-NEXT:    store float [[I34]], ptr [[I35]], align 4
453 ; CHECK-NEXT:    [[IV_INC]] = add nuw nsw i64 [[IV]], 1
454 ; CHECK-NEXT:    [[EXITCOND:%.*]] = icmp eq i64 [[IV_INC]], 4
455 ; CHECK-NEXT:    br i1 [[EXITCOND]], label [[LOOP_EXIT:%.*]], label [[LOOP_HEADER]]
456 ; CHECK:       loop.exit:
457 ; CHECK-NEXT:    ret void
459   ptr %output) local_unnamed_addr #0 {
460 entry:
461   br label %loop.header
463 loop.header:
464   %poison = phi i64 [ poison, %entry ], [ %iv.inc, %if.end ]
465   %iv = phi i64 [ 0, %entry ], [ %iv.inc, %if.end ]
466   %i23 = icmp eq i64 %iv, 0
467   br i1 %i23, label %if.end, label %if.then
469 if.then:
470   %i29 = getelementptr inbounds float, ptr %input, i64 %poison
471   %i30 = load float, ptr %i29, align 4, !invariant.load !0
472   br label %if.end
474 if.end:
475   %i34 = phi float [ 0.000000e+00, %loop.header ], [ %i30, %if.then ]
476   %i35 = getelementptr inbounds float, ptr %output, i64 %iv
477   store float %i34, ptr %i35, align 4
478   %iv.inc = add nuw nsw i64 %iv, 1
479   %exitcond = icmp eq i64 %iv.inc, 4
480   br i1 %exitcond, label %loop.exit, label %loop.header
482 loop.exit:
483   ret void
486 @c = external global [5 x i8]
488 ; Test case for https://github.com/llvm/llvm-project/issues/70590.
489 ; Note that the then block has UB, but I could not find any other way to
490 ; construct a suitable test case.
491 define void @pr70590_recipe_without_underlying_instr(i64 %n, ptr noalias %dst) {
492 ; CHECK-LABEL: @pr70590_recipe_without_underlying_instr(
493 ; CHECK:       vector.body:
494 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH:%.+]] ], [ [[INDEX_NEXT:%.*]], [[PRED_SREM_CONTINUE6:%.*]] ]
495 ; CHECK-NEXT:    [[VEC_IND:%.*]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, [[VECTOR_PH]] ], [ [[VEC_IND_NEXT:%.*]], [[PRED_SREM_CONTINUE6]] ]
496 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
497 ; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq <4 x i64> [[VEC_IND]],
498 ; CHECK-NEXT:    [[TMP2:%.*]] = xor <4 x i1> [[TMP1]], splat (i1 true)
499 ; CHECK-NEXT:    [[TMP3:%.*]] = extractelement <4 x i1> [[TMP2]], i32 0
500 ; CHECK-NEXT:    br i1 [[TMP3]], label [[PRED_SREM_IF:%.*]], label [[PRED_SREM_CONTINUE:%.*]]
501 ; CHECK:       pred.srem.if:
502 ; CHECK-NEXT:    [[TMP4:%.*]] = srem i64 3, 0
503 ; CHECK-NEXT:    br label [[PRED_SREM_CONTINUE]]
504 ; CHECK:       pred.srem.continue:
505 ; CHECK-NEXT:    [[TMP5:%.*]] = phi i64 [ poison, %vector.body ], [ [[TMP4]], [[PRED_SREM_IF]] ]
506 ; CHECK-NEXT:    [[TMP6:%.*]] = extractelement <4 x i1> [[TMP2]], i32 1
507 ; CHECK-NEXT:    br i1 [[TMP6]], label [[PRED_SREM_IF1:%.*]], label [[PRED_SREM_CONTINUE2:%.*]]
508 ; CHECK:       pred.srem.if1:
509 ; CHECK-NEXT:    [[TMP7:%.*]] = srem i64 3, 0
510 ; CHECK-NEXT:    br label [[PRED_SREM_CONTINUE2]]
511 ; CHECK:       pred.srem.continue2:
512 ; CHECK-NEXT:    [[TMP9:%.*]] = extractelement <4 x i1> [[TMP2]], i32 2
513 ; CHECK-NEXT:    br i1 [[TMP9]], label [[PRED_SREM_IF3:%.*]], label [[PRED_SREM_CONTINUE4:%.*]]
514 ; CHECK:       pred.srem.if3:
515 ; CHECK-NEXT:    [[TMP10:%.*]] = srem i64 3, 0
516 ; CHECK-NEXT:    br label [[PRED_SREM_CONTINUE4]]
517 ; CHECK:       pred.srem.continue4:
518 ; CHECK-NEXT:    [[TMP12:%.*]] = extractelement <4 x i1> [[TMP2]], i32 3
519 ; CHECK-NEXT:    br i1 [[TMP12]], label [[PRED_SREM_IF5:%.*]], label [[PRED_SREM_CONTINUE6]]
520 ; CHECK:       pred.srem.if5:
521 ; CHECK-NEXT:    [[TMP13:%.*]] = srem i64 3, 0
522 ; CHECK-NEXT:    br label [[PRED_SREM_CONTINUE6]]
523 ; CHECK:       pred.srem.continue6:
524 ; CHECK-NEXT:    [[TMP15:%.*]] = add i64 [[TMP5]], -3
525 ; CHECK-NEXT:    [[TMP16:%.*]] = add i64 [[TMP0]], [[TMP15]]
526 ; CHECK-NEXT:    [[TMP17:%.*]] = getelementptr [5 x i8], ptr @c, i64 0, i64 [[TMP16]]
527 ; CHECK-NEXT:    [[TMP18:%.*]] = getelementptr i8, ptr [[TMP17]], i32 0
528 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i8>, ptr [[TMP18]], align 1
529 ; CHECK-NEXT:    [[PREDPHI:%.*]] = select <4 x i1> [[TMP2]], <4 x i8> [[WIDE_LOAD]], <4 x i8> zeroinitializer
530 ; CHECK-NEXT:    [[TMP19:%.*]] = getelementptr i8, ptr %dst, i64 [[TMP0]]
531 ; CHECK-NEXT:    [[TMP20:%.*]] = getelementptr i8, ptr [[TMP19]], i32 0
532 ; CHECK-NEXT:    store <4 x i8> [[PREDPHI]], ptr [[TMP20]], align 4
533 ; CHECK-NEXT:    [[VEC_IND_NEXT]] = add <4 x i64> [[VEC_IND]], splat (i64 4)
534 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
535 ; CHECK-NEXT:    br i1 true, label %middle.block, label %vector.body
536 ; CHECK:       middle.block:
538 entry:
539   br label %loop.header
541 loop.header:
542   %iv = phi i64 [ 0, %entry ], [ %inc, %loop.latch ]
543   %cmp = icmp eq i64 %iv, %n
544   br i1 %cmp, label %loop.latch, label %then
546 then:
547   %rem = srem i64 3, 0
548   %add3 = add i64 %rem, -3
549   %add5 = add i64 %iv, %add3
550   %gep = getelementptr [5 x i8], ptr @c, i64 0, i64 %add5
551   %l = load i8, ptr %gep, align 1
552   br label %loop.latch
554 loop.latch:
555   %sr = phi i8 [ 0, %loop.header ], [ %l , %then ]
556   %gep.dst = getelementptr i8, ptr %dst, i64 %iv
557   store i8 %sr, ptr %gep.dst, align 4
558   %inc = add i64 %iv, 1
559   %exitcond.not = icmp eq i64 %inc, 4
560   br i1 %exitcond.not, label %exit, label %loop.header
562 exit:
563   ret void
566 ; %B.gep.0 and pointers based on it can preserve inbounds, as the inbounds
567 ; versionused unconditionally in the store in the latch.
568 ; FIXME: at the moment, inbounds is dropped from both the GEP feeding the vector load ans tore
569 define void @Bgep_inbounds_unconditionally_due_to_store(ptr noalias %B, ptr readonly %C) #0 {
570 ; CHECK-LABEL: define void @Bgep_inbounds_unconditionally_due_to_store(
571 ; CHECK:       vector.body:
572 ; CHECK-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %vector.ph ], [ [[INDEX_NEXT:%.*]], %vector.body ]
573 ; CHECK-NEXT:    [[TMP0:%.*]] = add i64 [[INDEX]], 0
574 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr %C, i64 [[TMP0]]
575 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i32 0
576 ; CHECK-NEXT:    [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP2]], align 4
577 ; CHECK-NEXT:    [[TMP3:%.*]] = icmp eq <4 x i32> [[WIDE_LOAD]], splat (i32 20)
578 ; CHECK-NEXT:    [[TMP4:%.*]] = getelementptr float, ptr %B, i64 [[TMP0]]
579 ; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr float, ptr [[TMP4]], i32 0
580 ; CHECK-NEXT:    [[WIDE_LOAD2:%.*]] = load <4 x float>, ptr [[TMP5]], align 4
581 ; CHECK-NEXT:    [[TMP6:%.*]] = fadd <4 x float> [[WIDE_LOAD2]], splat (float 2.000000e+00)
582 ; CHECK-NEXT:    [[PREDPHI:%.*]] = select <4 x i1> [[TMP3]], <4 x float> splat (float 3.300000e+01), <4 x float> [[TMP6]]
583 ; CHECK-NEXT:    [[TMP8:%.*]] = getelementptr inbounds float, ptr [[TMP4]], i32 0
584 ; CHECK-NEXT:    store <4 x float> [[PREDPHI]], ptr [[TMP8]], align 4
585 ; CHECK-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
586 ; CHECK-NEXT:    [[TMP9:%.*]] = icmp eq i64 [[INDEX_NEXT]], 10000
587 ; CHECK-NEXT:    br i1 [[TMP9]], label %middle.block, label %vector.body
589 entry:
590   br label %loop.body
592 loop.body:
593   %iv1 = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
594   %C.gep = getelementptr inbounds i32, ptr %C, i64 %iv1
595   %C.lv = load i32, ptr %C.gep, align 4
596   %cmp = icmp eq i32 %C.lv, 20
597   %B.gep.0 = getelementptr inbounds float, ptr %B, i64 %iv1
598   br i1 %cmp, label %loop.latch, label %else
600 else:
601   %B.lv = load float, ptr %B.gep.0, align 4
602   %add = fadd float %B.lv, 2.0
603   br label %loop.latch
605 loop.latch:
606   %add.sink = phi float [ %add, %else ], [ 33.0, %loop.body ]
607   store float %add.sink, ptr %B.gep.0, align 4
608   %iv.next = add nuw nsw i64 %iv1, 1
609   %exitcond.not = icmp eq i64 %iv.next, 10000
610   br i1 %exitcond.not, label %exit, label %loop.body
612 exit:
613   ret void
616 attributes #0 = { noinline nounwind uwtable "target-features"="+avx512bw,+avx512cd,+avx512dq,+avx512f,+avx512vl" }
618 !0 = !{}