xref: /llvm-project/llvm/test/Transforms/LoopVectorize/consecutive-ptr-uniforms.ll (revision ddbb382a7c09ff1b455a4b9513388fd0bf351284)
1; REQUIRES: asserts
2; RUN: opt %s -passes=loop-vectorize,instcombine -force-vector-width=4 -force-vector-interleave=1 -debug-only=loop-vectorize -disable-output -print-after=instcombine 2>&1 | FileCheck %s
3; RUN: opt %s -passes=loop-vectorize,instcombine -force-vector-width=4 -force-vector-interleave=1 -enable-interleaved-mem-accesses -debug-only=loop-vectorize -disable-output -print-after=instcombine 2>&1 | FileCheck %s --check-prefix=INTER
4
5target datalayout = "e-m:e-i64:64-i128:128-n32:64-S128"
6
7%pair = type { i32, i32 }
8
9; CHECK-LABEL: consecutive_ptr_forward
10;
11; Check that a forward consecutive pointer is recognized as uniform and remains
12; uniform after vectorization.
13;
14; CHECK:     LV: Found uniform instruction: %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i
15; CHECK:     vector.body
16; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
17; CHECK-NOT:   getelementptr
18; CHECK:       getelementptr inbounds i32, ptr %a, i64 %index
19; CHECK-NOT:   getelementptr
20; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
21;
22define i32 @consecutive_ptr_forward(ptr %a, i64 %n) {
23entry:
24  br label %for.body
25
26for.body:
27  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
28  %tmp0 = phi i32 [ %tmp3, %for.body ], [ 0, %entry ]
29  %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i
30  %tmp2 = load i32, ptr %tmp1, align 8
31  %tmp3 = add i32 %tmp0, %tmp2
32  %i.next = add nuw nsw i64 %i, 1
33  %cond = icmp slt i64 %i.next, %n
34  br i1 %cond, label %for.body, label %for.end
35
36for.end:
37  %tmp4 = phi i32 [ %tmp3, %for.body ]
38  ret i32 %tmp4
39}
40
41; CHECK-LABEL: consecutive_ptr_reverse
42;
43; Check that a reverse consecutive pointer is recognized as uniform and remains
44; uniform after vectorization.
45;
46; CHECK:     LV: Found uniform instruction: %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i
47; CHECK:     vector.body
48; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
49; CHECK:       [[OFFSET_IDX:%.+]] = sub i64 %n, %index
50; CHECK-NOT:   getelementptr
51; CHECK:       %[[G0:.+]] = getelementptr inbounds i32, ptr %a, i64 [[OFFSET_IDX]]
52; CHECK:       getelementptr inbounds i8, ptr %[[G0]], i64 -12
53; CHECK-NOT:   getelementptr
54; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
55;
56define i32 @consecutive_ptr_reverse(ptr %a, i64 %n) {
57entry:
58  br label %for.body
59
60for.body:
61  %i = phi i64 [ %i.next, %for.body ], [ %n, %entry ]
62  %tmp0 = phi i32 [ %tmp3, %for.body ], [ 0, %entry ]
63  %tmp1 = getelementptr inbounds i32, ptr %a, i64 %i
64  %tmp2 = load i32, ptr %tmp1, align 8
65  %tmp3 = add i32 %tmp0, %tmp2
66  %i.next = add nsw i64 %i, -1
67  %cond = icmp sgt i64 %i.next, 0
68  br i1 %cond, label %for.body, label %for.end
69
70for.end:
71  %tmp4 = phi i32 [ %tmp3, %for.body ]
72  ret i32 %tmp4
73}
74
75; CHECK-LABEL: interleaved_access_forward
76; INTER-LABEL: interleaved_access_forward
77;
78; Check that a consecutive-like pointer used by a forward interleaved group is
79; recognized as uniform and remains uniform after vectorization. When
80; interleaved memory accesses aren't enabled, the pointer should not be
81; recognized as uniform, and it should not be uniform after vectorization.
82;
83; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
84; CHECK-NOT: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
85; CHECK:     vector.body
86; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
87; CHECK:       %[[I1:.+]] = or disjoint i64 %index, 1
88; CHECK:       %[[I2:.+]] = or disjoint i64 %index, 2
89; CHECK:       %[[I3:.+]] = or disjoint i64 %index, 3
90; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %index, i32 0
91; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0
92; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0
93; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0
94; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %index, i32 1
95; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 1
96; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 1
97; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 1
98; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
99;
100; INTER:     LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
101; INTER:     LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
102; INTER:     vector.body
103; INTER:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
104; INTER-NOT:   getelementptr
105; INTER:       getelementptr inbounds %pair, ptr %p, i64 %index, i32 0
106; INTER-NOT:   getelementptr
107; INTER:       br i1 {{.*}}, label %middle.block, label %vector.body
108;
109define i32 @interleaved_access_forward(ptr %p, i64 %n) {
110entry:
111  br label %for.body
112
113for.body:
114  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
115  %tmp0 = phi i32 [ %tmp6, %for.body ], [ 0, %entry ]
116  %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
117  %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
118  %tmp3 = load i32, ptr %tmp1, align 8
119  %tmp4 = load i32, ptr %tmp2, align 8
120  %tmp5 = add i32 %tmp3, %tmp4
121  %tmp6 = add i32 %tmp0, %tmp5
122  %i.next = add nuw nsw i64 %i, 1
123  %cond = icmp slt i64 %i.next, %n
124  br i1 %cond, label %for.body, label %for.end
125
126for.end:
127  %tmp14 = phi i32 [ %tmp6, %for.body ]
128  ret i32 %tmp14
129}
130
131; CHECK-LABEL: interleaved_access_reverse
132; INTER-LABEL: interleaved_access_reverse
133;
134; Check that a consecutive-like pointer used by a reverse interleaved group is
135; recognized as uniform and remains uniform after vectorization. When
136; interleaved memory accesses aren't enabled, the pointer should not be
137; recognized as uniform, and it should not be uniform after vectorization.
138;
139; recognized as uniform, and it should not be uniform after vectorization.
140; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
141; CHECK-NOT: LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
142; CHECK:     vector.body
143; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
144; CHECK:       [[OFFSET_IDX:%.+]] = sub i64 %n, %index
145; CHECK:       %[[I1:.+]] = add i64 [[OFFSET_IDX]], -1
146; CHECK:       %[[I2:.+]] = add i64 [[OFFSET_IDX]], -2
147; CHECK:       %[[I3:.+]] = add i64 [[OFFSET_IDX]], -3
148; CHECK:       getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 0
149; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0
150; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0
151; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0
152; CHECK:       getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 1
153; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 1
154; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 1
155; CHECK:       getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 1
156; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
157;
158; INTER:     LV: Found uniform instruction: %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
159; INTER:     LV: Found uniform instruction: %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
160; INTER:     vector.body
161; INTER:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
162; INTER:       [[OFFSET_IDX:%.+]] = sub i64 %n, %index
163; INTER-NOT:   getelementptr
164; INTER:       %[[G0:.+]] = getelementptr inbounds %pair, ptr %p, i64 [[OFFSET_IDX]], i32 0
165; INTER:       getelementptr inbounds i8, ptr %[[G0]], i64 -24
166; INTER-NOT:   getelementptr
167; INTER:       br i1 {{.*}}, label %middle.block, label %vector.body
168;
169define i32 @interleaved_access_reverse(ptr %p, i64 %n) {
170entry:
171  br label %for.body
172
173for.body:
174  %i = phi i64 [ %i.next, %for.body ], [ %n, %entry ]
175  %tmp0 = phi i32 [ %tmp6, %for.body ], [ 0, %entry ]
176  %tmp1 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
177  %tmp2 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 1
178  %tmp3 = load i32, ptr %tmp1, align 8
179  %tmp4 = load i32, ptr %tmp2, align 8
180  %tmp5 = add i32 %tmp3, %tmp4
181  %tmp6 = add i32 %tmp0, %tmp5
182  %i.next = add nsw i64 %i, -1
183  %cond = icmp sgt i64 %i.next, 0
184  br i1 %cond, label %for.body, label %for.end
185
186for.end:
187  %tmp14 = phi i32 [ %tmp6, %for.body ]
188  ret i32 %tmp14
189}
190
191; INTER-LABEL: predicated_store
192;
193; Check that a consecutive-like pointer used by a forward interleaved group and
194; scalarized store is not recognized as uniform and is not uniform after
195; vectorization. The store is scalarized because it's in a predicated block.
196; Even though the load in this example is vectorized and only uses the pointer
197; as if it were uniform, the store is scalarized, making the pointer
198; non-uniform.
199;
200; INTER-NOT: LV: Found uniform instruction: %tmp0 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
201; INTER:     vector.body
202; INTER:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, {{.*}} ]
203; INTER:       %[[G0:.+]] = getelementptr inbounds %pair, ptr %p, i64 %index, i32 0
204; INTER:       %wide.vec = load <8 x i32>, ptr %[[G0]], align 8
205; INTER:       %[[I1:.+]] = or disjoint i64 %index, 1
206; INTER:       getelementptr inbounds %pair, ptr %p, i64 %[[I1]], i32 0
207; INTER:       %[[I2:.+]] = or disjoint i64 %index, 2
208; INTER:       getelementptr inbounds %pair, ptr %p, i64 %[[I2]], i32 0
209; INTER:       %[[I3:.+]] = or disjoint i64 %index, 3
210; INTER:       getelementptr inbounds %pair, ptr %p, i64 %[[I3]], i32 0
211; INTER:       br i1 {{.*}}, label %middle.block, label %vector.body
212;
213define void @predicated_store(ptr %p, i32 %x, i64 %n) {
214entry:
215  br label %for.body
216
217for.body:
218  %i  = phi i64 [ %i.next, %if.merge ], [ 0, %entry ]
219  %tmp0 = getelementptr inbounds %pair, ptr %p, i64 %i, i32 0
220  %tmp1 = load i32, ptr %tmp0, align 8
221  %tmp2 = icmp eq i32 %tmp1, %x
222  br i1 %tmp2, label %if.then, label %if.merge
223
224if.then:
225  store i32 %tmp1, ptr %tmp0, align 8
226  br label %if.merge
227
228if.merge:
229  %i.next = add nuw nsw i64 %i, 1
230  %cond = icmp slt i64 %i.next, %n
231  br i1 %cond, label %for.body, label %for.end
232
233for.end:
234  ret void
235}
236
237; CHECK-LABEL: irregular_type
238;
239; Check that a consecutive pointer used by a scalarized store is not recognized
240; as uniform and is not uniform after vectorization. The store is scalarized
241; because the stored type may required padding.
242;
243; CHECK-NOT: LV: Found uniform instruction: %tmp1 = getelementptr inbounds x86_fp80, ptr %a, i64 %i
244; CHECK:     vector.body
245; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
246; CHECK:       %[[I1:.+]] = or disjoint i64 %index, 1
247; CHECK:       %[[I2:.+]] = or disjoint i64 %index, 2
248; CHECK:       %[[I3:.+]] = or disjoint i64 %index, 3
249; CHECK:       getelementptr inbounds x86_fp80, ptr %a, i64 %index
250; CHECK:       getelementptr inbounds x86_fp80, ptr %a, i64 %[[I1]]
251; CHECK:       getelementptr inbounds x86_fp80, ptr %a, i64 %[[I2]]
252; CHECK:       getelementptr inbounds x86_fp80, ptr %a, i64 %[[I3]]
253; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
254;
255define void @irregular_type(ptr %a, i64 %n) {
256entry:
257  br label %for.body
258
259for.body:
260  %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ]
261  %tmp0 = sitofp i32 1 to x86_fp80
262  %tmp1 = getelementptr inbounds x86_fp80, ptr %a, i64 %i
263  store x86_fp80 %tmp0, ptr %tmp1, align 16
264  %i.next = add i64 %i, 1
265  %cond = icmp slt i64 %i.next, %n
266  br i1 %cond, label %for.body, label %for.end
267
268for.end:
269  ret void
270}
271
272; CHECK-LABEL: pointer_iv_uniform
273;
274; Check that a pointer induction variable is recognized as uniform and remains
275; uniform after vectorization.
276;
277; CHECK:     LV: Found uniform instruction: %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ]
278; CHECK:     vector.body
279; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
280; CHECK-NOT:   getelementptr
281; CHECK:       [[SHL:%.+]] = shl i64 %index, 2
282; CHECK:       %next.gep = getelementptr i8, ptr %a, i64 [[SHL]]
283; CHECK-NOT:   getelementptr
284; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
285;
286define void @pointer_iv_uniform(ptr %a, i32 %x, i64 %n) {
287entry:
288  br label %for.body
289
290for.body:
291  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
292  %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ]
293  store i32 %x, ptr %p, align 8
294  %tmp03 = getelementptr inbounds i32, ptr %p, i32 1
295  %i.next = add nuw nsw i64 %i, 1
296  %cond = icmp slt i64 %i.next, %n
297  br i1 %cond, label %for.body, label %for.end
298
299for.end:
300  ret void
301}
302
303; INTER-LABEL: pointer_iv_non_uniform_0
304;
305; Check that a pointer induction variable with a non-uniform user is not
306; recognized as uniform and is not uniform after vectorization. The pointer
307; induction variable is used by getelementptr instructions that are non-uniform
308; due to scalarization of the stores.
309;
310; INTER-NOT: LV: Found uniform instruction: %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ]
311; INTER:     vector.body
312; INTER:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
313; INTER:       %[[I0:.+]] = shl i64 %index, 4
314; INTER:       %[[I1:.+]] = or disjoint i64 %[[I0]], 16
315; INTER:       %[[I2:.+]] = or disjoint i64 %[[I0]], 32
316; INTER:       %[[I3:.+]] = or disjoint i64 %[[I0]], 48
317; INTER:       %next.gep = getelementptr i8, ptr %a, i64 %[[I0]]
318; INTER-NEXT:  = getelementptr i8, ptr %a, i64 %[[I1]]
319; INTER-NEXT:  = getelementptr i8, ptr %a, i64 %[[I2]]
320; INTER-NEXT:  = getelementptr i8, ptr %a, i64 %[[I3]]
321; INTER:       br i1 {{.*}}, label %middle.block, label %vector.body
322;
323define void @pointer_iv_non_uniform_0(ptr %a, i64 %n) {
324entry:
325  br label %for.body
326
327for.body:
328  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
329  %p = phi ptr [ %tmp03, %for.body ], [ %a, %entry ]
330  %tmp00 = load i32, ptr %p, align 8
331  %tmp01 = getelementptr inbounds i32, ptr %p, i32 1
332  %tmp02 = load i32, ptr %tmp01, align 8
333  %tmp03 = getelementptr inbounds i32, ptr %p, i32 4
334  %tmp04 = load i32, ptr %tmp03, align 8
335  %tmp05 = getelementptr inbounds i32, ptr %p, i32 5
336  %tmp06 = load i32, ptr %tmp05, align 8
337  %tmp07 = sub i32 %tmp04, %tmp00
338  %tmp08 = sub i32 %tmp02, %tmp02
339  %tmp09 = getelementptr inbounds i32, ptr %p, i32 2
340  store i32 %tmp07, ptr %tmp09, align 8
341  %tmp10 = getelementptr inbounds i32, ptr %p, i32 3
342  store i32 %tmp08, ptr %tmp10, align 8
343  %i.next = add nuw nsw i64 %i, 1
344  %cond = icmp slt i64 %i.next, %n
345  br i1 %cond, label %for.body, label %for.end
346
347for.end:
348  ret void
349}
350
351; CHECK-LABEL: pointer_iv_non_uniform_1
352;
353; Check that a pointer induction variable with a non-uniform user is not
354; recognized as uniform and is not uniform after vectorization. The pointer
355; induction variable is used by a store that will be scalarized.
356;
357; CHECK-NOT: LV: Found uniform instruction: %p = phi ptr [%tmp1, %for.body], [%a, %entry]
358; CHECK:     vector.body
359; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
360; CHECK:       [[SHL1:%.+]] = shl i64 %index, 4
361; CHECK:       %[[I1:.+]] = or disjoint i64 [[SHL1]], 16
362; CHECK:       %[[I2:.+]] = or disjoint i64 [[SHL1]], 32
363; CHECK:       %[[I3:.+]] = or disjoint i64 [[SHL1]], 48
364; CHECK:       %next.gep = getelementptr i8, ptr %a, i64 [[SHL1]]
365; CHECK:       = getelementptr i8, ptr %a, i64 %[[I1]]
366; CHECK:       = getelementptr i8, ptr %a, i64 %[[I2]]
367; CHECK:       = getelementptr i8, ptr %a, i64 %[[I3]]
368; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
369;
370define void @pointer_iv_non_uniform_1(ptr %a, i64 %n) {
371entry:
372  br label %for.body
373
374for.body:
375  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
376  %p = phi ptr [%tmp1, %for.body], [%a, %entry]
377  %tmp0 = sitofp i32 1 to x86_fp80
378  store x86_fp80 %tmp0, ptr %p, align 16
379  %tmp1 = getelementptr inbounds x86_fp80, ptr %p, i32 1
380  %i.next = add i64 %i, 1
381  %cond = icmp slt i64 %i.next, %n
382  br i1 %cond, label %for.body, label %for.end
383
384for.end:
385  ret void
386}
387
388; CHECK-LABEL: pointer_iv_mixed
389;
390; Check multiple pointer induction variables where only one is recognized as
391; uniform and remains uniform after vectorization. The other pointer induction
392; variable is not recognized as uniform and is not uniform after vectorization
393; because it is stored to memory.
394;
395; CHECK-NOT: LV: Found uniform instruction: %p = phi ptr [ %tmp3, %for.body ], [ %a, %entry ]
396; CHECK:     LV: Found uniform instruction: %q = phi ptr [ %tmp4, %for.body ], [ %b, %entry ]
397; CHECK:     vector.body
398; CHECK:       %pointer.phi = phi ptr [ %a, %vector.ph ], [ %ptr.ind, %vector.body ]
399; CHECK:       %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
400; CHECK:       %[[PTRVEC:.+]] = getelementptr i8, ptr %pointer.phi, <4 x i64> <i64 0, i64 4, i64 8, i64 12>
401; CHECK:       [[SHL:%.+]] = shl i64 %index, 3
402; CHECK:       %next.gep = getelementptr i8, ptr %b, i64 [[SHL]]
403; CHECK:       store <4 x ptr> %[[PTRVEC]], ptr %next.gep, align 8
404; CHECK:       %ptr.ind = getelementptr i8, ptr %pointer.phi, i64 16
405; CHECK:       br i1 {{.*}}, label %middle.block, label %vector.body
406;
407define i32 @pointer_iv_mixed(ptr %a, ptr %b, i64 %n) {
408entry:
409  br label %for.body
410
411for.body:
412  %i = phi i64 [ %i.next, %for.body ], [ 0, %entry ]
413  %p = phi ptr [ %tmp3, %for.body ], [ %a, %entry ]
414  %q = phi ptr [ %tmp4, %for.body ], [ %b, %entry ]
415  %tmp0 = phi i32 [ %tmp2, %for.body ], [ 0, %entry ]
416  %tmp1 = load i32, ptr %p, align 8
417  %tmp2 = add i32 %tmp1, %tmp0
418  store ptr %p, ptr %q, align 8
419  %tmp3 = getelementptr inbounds i32, ptr %p, i32 1
420  %tmp4 = getelementptr inbounds ptr, ptr %q, i32 1
421  %i.next = add nuw nsw i64 %i, 1
422  %cond = icmp slt i64 %i.next, %n
423  br i1 %cond, label %for.body, label %for.end
424
425for.end:
426  %tmp5 = phi i32 [ %tmp2, %for.body ]
427  ret i32 %tmp5
428}
429
430; INTER-LABEL: pointer_operand_geps_with_different_indexed_types
431;
432; Check that a pointer operand having a user other than a memory access is
433; recognized as uniform after vectorization. In this test case, %tmp0 is a
434; GEP that is used by a load and a getelementptr instruction (%tmp2). Once
435; %tmp2 is marked uniform, %tmp0 should be marked uniform as well.
436;
437; INTER:       LV: Found uniform instruction: %cond = icmp slt i64 %i.next, %n
438; INTER-NEXT:  LV: Found uniform instruction: %tmp2 = getelementptr inbounds i8, ptr %tmp0, i64 3
439; INTER-NEXT:  LV: Found uniform instruction: %tmp6 = getelementptr inbounds i8, ptr %B, i64 %i
440; INTER-NEXT:  LV: Found uniform instruction: %tmp0 = getelementptr inbounds i64, ptr %A, i64 %i
441; INTER-NEXT:  LV: Found uniform instruction: %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ]
442; INTER-NEXT:  LV: Found uniform instruction: %i.next = add nuw nsw i64 %i, 1
443; INTER:       define void @pointer_operand_geps_with_different_indexed_types(
444; INTER:       vector.body:
445; INTER-NEXT:    [[INDEX:%.*]] = phi i64 [ 0, %vector.ph ], [ [[INDEX_NEXT:%.*]], %vector.body ]
446; INTER-NEXT:    [[TMP4:%.*]] = getelementptr inbounds i64, ptr %A, i64 [[INDEX]]
447; INTER-NEXT:    [[WIDE_VEC:%.*]] = load <32 x i8>, ptr [[TMP4]], align 1
448; INTER-NEXT:    [[STRIDED_VEC:%.*]] = shufflevector <32 x i8> [[WIDE_VEC]], <32 x i8> poison, <4 x i32> <i32 0, i32 8, i32 16, i32 24>
449; INTER-NEXT:    [[STRIDED_VEC3:%.*]] = shufflevector <32 x i8> [[WIDE_VEC]], <32 x i8> poison, <4 x i32> <i32 3, i32 11, i32 19, i32 27>
450; INTER-NEXT:    [[TMP5:%.*]] = xor <4 x i8> [[STRIDED_VEC3]], [[STRIDED_VEC]]
451; INTER-NEXT:    [[TMP6:%.*]] = getelementptr inbounds i8, ptr %B, i64 [[INDEX]]
452; INTER-NEXT:    store <4 x i8> [[TMP5]], ptr [[TMP6]], align 1
453; INTER-NEXT:    [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
454; INTER:         br i1 {{.*}}, label %middle.block, label %vector.body
455;
456define void @pointer_operand_geps_with_different_indexed_types(ptr %A, ptr %B, i64 %n) {
457entry:
458  br label %for.body
459
460for.body:
461  %i = phi i64 [ 0, %entry ], [ %i.next, %for.body ]
462  %tmp0 = getelementptr inbounds i64, ptr %A, i64 %i
463  %tmp2 = getelementptr inbounds i8, ptr %tmp0, i64 3
464  %tmp3 = load i8, ptr %tmp2, align 1
465  %tmp4 = load i8, ptr %tmp0, align 1
466  %tmp5 = xor i8 %tmp3, %tmp4
467  %tmp6 = getelementptr inbounds i8, ptr %B, i64 %i
468  store i8 %tmp5, ptr %tmp6
469  %i.next = add nuw nsw i64 %i, 1
470  %cond = icmp slt i64 %i.next, %n
471  br i1 %cond, label %for.body, label %for.end
472
473for.end:
474  ret void
475}
476
477; CHECK-LABEL: pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store
478; CHECK-NOT: LV: Found uniform instruction: %cur.ptr = getelementptr inbounds ptr, ptr %ary, i64 %iv
479
480; CHECK:       define void @pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store(
481; CHECK:       vector.body:
482; CHECK-NEXT:    %index = phi i64 [ 0, %vector.ph ], [ %index.next, %vector.body ]
483; CHECK-NEXT:    [[VEC_IND:%.+]] = phi <4 x i64> [ <i64 0, i64 1, i64 2, i64 3>, %vector.ph ], [ %vec.ind.next, %vector.body ]
484; CHECK-NEXT:    [[GEP:%.+]] = getelementptr inbounds ptr, ptr %ary, <4 x i64> [[VEC_IND]]
485; CHECK-NEXT:    [[EXT:%.+]] = extractelement <4 x ptr> [[GEP]], i64 0
486; CHECK-NEXT:    store <4 x ptr> [[GEP]], ptr [[EXT]], align 8
487;
488
489define void @pr61396_pointer_used_as_both_stored_value_and_pointer_operand_by_store(ptr %ary) {
490entry:
491  br label %loop
492
493loop:
494  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
495  %cur.ptr = getelementptr inbounds ptr, ptr %ary, i64 %iv
496  store ptr %cur.ptr, ptr %cur.ptr, align 8
497  %iv.next = add nuw nsw i64 %iv, 1
498  %done = icmp eq i64 %iv, 10240
499  br i1 %done, label %exit, label %loop
500
501exit:
502  ret void
503}
504