xref: /llvm-project/llvm/test/Transforms/LICM/gep-reassociate.ll (revision 243df834c6ae8b80441d8348368935b253c1be45)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
2; RUN: opt -S -passes=licm < %s | FileCheck %s --check-prefixes=CHECK,SPEC
3; RUN: opt -S -passes='licm<no-allowspeculation>' < %s | FileCheck %s --check-prefixes=CHECK,NOSPEC
4
5declare void @use(ptr)
6declare i32 @get.i32()
7declare i64 @get.i64()
8declare ptr @get.ptr()
9
10define void @only_one_inbounds(ptr %ptr, i1 %c, i32 %arg) {
11; CHECK-LABEL: define void @only_one_inbounds
12; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
13; CHECK-NEXT:  entry:
14; CHECK-NEXT:    [[ARG_EXT:%.*]] = zext i32 [[ARG]] to i64
15; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG_EXT]]
16; CHECK-NEXT:    br label [[LOOP:%.*]]
17; CHECK:       loop:
18; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
19; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
20; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
21; CHECK-NEXT:    call void @use(ptr [[GEP]])
22; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
23; CHECK:       exit:
24; CHECK-NEXT:    ret void
25;
26entry:
27  %arg.ext = zext i32 %arg to i64
28  br label %loop
29
30loop:
31  %val = call i32 @get.i32()
32  %val.ext = zext i32 %val to i64
33  %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
34  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg.ext
35  call void @use(ptr %ptr3)
36  br i1 %c, label %loop, label %exit
37
38exit:
39  ret void
40}
41
42define void @both_inbounds_one_neg(ptr %ptr, i1 %c) {
43; CHECK-LABEL: define void @both_inbounds_one_neg
44; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
45; CHECK-NEXT:  entry:
46; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i64 -1
47; CHECK-NEXT:    br label [[LOOP:%.*]]
48; CHECK:       loop:
49; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
50; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
51; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
52; CHECK-NEXT:    call void @use(ptr [[GEP]])
53; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
54; CHECK:       exit:
55; CHECK-NEXT:    ret void
56;
57entry:
58  br label %loop
59
60loop:
61  %val = call i32 @get.i32()
62  %val.ext = zext i32 %val to i64
63  %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
64  %ptr3 = getelementptr i8, ptr %ptr2, i64 -1
65  call void @use(ptr %ptr3)
66  br i1 %c, label %loop, label %exit
67
68exit:
69  ret void
70}
71
72define void @both_inbounds_pos(ptr %ptr, i1 %c) {
73; CHECK-LABEL: define void @both_inbounds_pos
74; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
75; CHECK-NEXT:  entry:
76; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr inbounds i8, ptr [[PTR]], i64 1
77; CHECK-NEXT:    br label [[LOOP:%.*]]
78; CHECK:       loop:
79; CHECK-NEXT:    [[VAL:%.*]] = call i32 @get.i32()
80; CHECK-NEXT:    [[VAL_EXT:%.*]] = zext i32 [[VAL]] to i64
81; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i8, ptr [[INVARIANT_GEP]], i64 [[VAL_EXT]]
82; CHECK-NEXT:    call void @use(ptr [[GEP]])
83; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
84; CHECK:       exit:
85; CHECK-NEXT:    ret void
86;
87entry:
88  br label %loop
89
90loop:
91  %val = call i32 @get.i32()
92  %val.ext = zext i32 %val to i64
93  %ptr2 = getelementptr inbounds i8, ptr %ptr, i64 %val.ext
94  %ptr3 = getelementptr inbounds i8, ptr %ptr2, i64 1
95  call void @use(ptr %ptr3)
96  br i1 %c, label %loop, label %exit
97
98exit:
99  ret void
100}
101
102define void @different_elem_types(ptr %ptr, i1 %c, i64 %arg) {
103; CHECK-LABEL: define void @different_elem_types
104; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
105; CHECK-NEXT:  entry:
106; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i64, ptr [[PTR]], i64 [[ARG]]
107; CHECK-NEXT:    br label [[LOOP:%.*]]
108; CHECK:       loop:
109; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
110; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i32, ptr [[INVARIANT_GEP]], i64 [[VAL]]
111; CHECK-NEXT:    call void @use(ptr [[GEP]])
112; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
113; CHECK:       exit:
114; CHECK-NEXT:    ret void
115;
116entry:
117  br label %loop
118
119loop:
120  %val = call i64 @get.i64()
121  %ptr2 = getelementptr i32, ptr %ptr, i64 %val
122  %ptr3 = getelementptr i64, ptr %ptr2, i64 %arg
123  call void @use(ptr %ptr3)
124  br i1 %c, label %loop, label %exit
125
126exit:
127  ret void
128}
129
130define void @different_index_types(ptr %ptr, i1 %c, i32 %arg) {
131; CHECK-LABEL: define void @different_index_types
132; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i32 [[ARG:%.*]]) {
133; CHECK-NEXT:  entry:
134; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr i8, ptr [[PTR]], i32 [[ARG]]
135; CHECK-NEXT:    br label [[LOOP:%.*]]
136; CHECK:       loop:
137; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
138; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
139; CHECK-NEXT:    call void @use(ptr [[GEP]])
140; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
141; CHECK:       exit:
142; CHECK-NEXT:    ret void
143;
144entry:
145  br label %loop
146
147loop:
148  %val = call i64 @get.i64()
149  %ptr2 = getelementptr i8, ptr %ptr, i64 %val
150  %ptr3 = getelementptr i8, ptr %ptr2, i32 %arg
151  call void @use(ptr %ptr3)
152  br i1 %c, label %loop, label %exit
153
154exit:
155  ret void
156}
157
158define void @different_index_count(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
159; CHECK-LABEL: define void @different_index_count
160; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
161; CHECK-NEXT:  entry:
162; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
163; CHECK-NEXT:    br label [[LOOP:%.*]]
164; CHECK:       loop:
165; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
166; CHECK-NEXT:    [[GEP:%.*]] = getelementptr i8, ptr [[INVARIANT_GEP]], i64 [[VAL]]
167; CHECK-NEXT:    call void @use(ptr [[GEP]])
168; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
169; CHECK:       exit:
170; CHECK-NEXT:    ret void
171;
172entry:
173  br label %loop
174
175loop:
176  %val = call i64 @get.i64()
177  %ptr2 = getelementptr i8, ptr %ptr, i64 %val
178  %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
179  call void @use(ptr %ptr3)
180  br i1 %c, label %loop, label %exit
181
182exit:
183  ret void
184}
185
186define void @src_has_extra_use(ptr %ptr, i1 %c, i64 %arg) {
187; CHECK-LABEL: define void @src_has_extra_use
188; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG:%.*]]) {
189; CHECK-NEXT:  entry:
190; CHECK-NEXT:    br label [[LOOP:%.*]]
191; CHECK:       loop:
192; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
193; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL]]
194; CHECK-NEXT:    call void @use(ptr [[PTR2]])
195; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG]]
196; CHECK-NEXT:    call void @use(ptr [[PTR3]])
197; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
198; CHECK:       exit:
199; CHECK-NEXT:    ret void
200;
201entry:
202  br label %loop
203
204loop:
205  %val = call i64 @get.i64()
206  %ptr2 = getelementptr i8, ptr %ptr, i64 %val
207  call void @use(ptr %ptr2)
208  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg
209  call void @use(ptr %ptr3)
210  br i1 %c, label %loop, label %exit
211
212exit:
213  ret void
214}
215
216define void @src_already_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
217; CHECK-LABEL: define void @src_already_invariant
218; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
219; CHECK-NEXT:  entry:
220; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
221; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
222; CHECK-NEXT:    br label [[LOOP:%.*]]
223; CHECK:       loop:
224; CHECK-NEXT:    call void @use(ptr [[PTR3]])
225; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
226; CHECK:       exit:
227; CHECK-NEXT:    ret void
228;
229entry:
230  br label %loop
231
232loop:
233  %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
234  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
235  call void @use(ptr %ptr3)
236  br i1 %c, label %loop, label %exit
237
238exit:
239  ret void
240}
241
242define void @gep_idx_not_invariant(ptr %ptr, i1 %c) {
243; CHECK-LABEL: define void @gep_idx_not_invariant
244; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]]) {
245; CHECK-NEXT:  entry:
246; CHECK-NEXT:    br label [[LOOP:%.*]]
247; CHECK:       loop:
248; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
249; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
250; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[VAL1]]
251; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL2]]
252; CHECK-NEXT:    call void @use(ptr [[PTR3]])
253; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
254; CHECK:       exit:
255; CHECK-NEXT:    ret void
256;
257entry:
258  br label %loop
259
260loop:
261  %val1 = call i64 @get.i64()
262  %val2 = call i64 @get.i64()
263  %ptr2 = getelementptr i8, ptr %ptr, i64 %val1
264  %ptr3 = getelementptr i8, ptr %ptr2, i64 %val2
265  call void @use(ptr %ptr3)
266  br i1 %c, label %loop, label %exit
267
268exit:
269  ret void
270}
271
272define void @src_ptr_not_invariant(i1 %c, i64 %arg) {
273; CHECK-LABEL: define void @src_ptr_not_invariant
274; CHECK-SAME: (i1 [[C:%.*]], i64 [[ARG:%.*]]) {
275; CHECK-NEXT:  entry:
276; CHECK-NEXT:    br label [[LOOP:%.*]]
277; CHECK:       loop:
278; CHECK-NEXT:    [[VAL:%.*]] = call i64 @get.i64()
279; CHECK-NEXT:    [[PTR:%.*]] = call ptr @get.ptr()
280; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG]]
281; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[VAL]]
282; CHECK-NEXT:    call void @use(ptr [[PTR3]])
283; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
284; CHECK:       exit:
285; CHECK-NEXT:    ret void
286;
287entry:
288  br label %loop
289
290loop:
291  %val = call i64 @get.i64()
292  %ptr = call ptr @get.ptr()
293  %ptr2 = getelementptr i8, ptr %ptr, i64 %arg
294  %ptr3 = getelementptr i8, ptr %ptr2, i64 %val
295  call void @use(ptr %ptr3)
296  br i1 %c, label %loop, label %exit
297
298exit:
299  ret void
300}
301
302define void @multiple_indices(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2) {
303; CHECK-LABEL: define void @multiple_indices
304; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
305; CHECK-NEXT:  entry:
306; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
307; CHECK-NEXT:    br label [[LOOP:%.*]]
308; CHECK:       loop:
309; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
310; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
311; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[VAL1]], i64 [[VAL2]]
312; CHECK-NEXT:    call void @use(ptr [[GEP]])
313; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
314; CHECK:       exit:
315; CHECK-NEXT:    ret void
316;
317entry:
318  br label %loop
319
320loop:
321  %val1 = call i64 @get.i64()
322  %val2 = call i64 @get.i64()
323  %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
324  %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
325  call void @use(ptr %ptr3)
326  br i1 %c, label %loop, label %exit
327
328exit:
329  ret void
330}
331
332define void @multiple_indices_not_invariant(ptr %ptr, i1 %c, i64 %arg1) {
333; CHECK-LABEL: define void @multiple_indices_not_invariant
334; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]]) {
335; CHECK-NEXT:  entry:
336; CHECK-NEXT:    br label [[LOOP:%.*]]
337; CHECK:       loop:
338; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
339; CHECK-NEXT:    [[VAL2:%.*]] = call i64 @get.i64()
340; CHECK-NEXT:    [[VAL3:%.*]] = call i64 @get.i64()
341; CHECK-NEXT:    [[PTR2:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[VAL1]], i64 [[VAL2]]
342; CHECK-NEXT:    [[PTR3:%.*]] = getelementptr [0 x i8], ptr [[PTR2]], i64 [[ARG1]], i64 [[VAL3]]
343; CHECK-NEXT:    call void @use(ptr [[PTR3]])
344; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
345; CHECK:       exit:
346; CHECK-NEXT:    ret void
347;
348entry:
349  br label %loop
350
351loop:
352  %val1 = call i64 @get.i64()
353  %val2 = call i64 @get.i64()
354  %val3 = call i64 @get.i64()
355  %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %val1, i64 %val2
356  %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %val3
357  call void @use(ptr %ptr3)
358  br i1 %c, label %loop, label %exit
359
360exit:
361  ret void
362}
363
364define void @multiple_indices_very_invariant(ptr %ptr, i1 %c, i64 %arg1, i64 %arg2, i64 %arg3) {
365; CHECK-LABEL: define void @multiple_indices_very_invariant
366; CHECK-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]], i64 [[ARG3:%.*]]) {
367; CHECK-NEXT:  entry:
368; CHECK-NEXT:    [[INVARIANT_GEP:%.*]] = getelementptr [0 x i8], ptr [[PTR]], i64 [[ARG1]], i64 [[ARG2]]
369; CHECK-NEXT:    br label [[LOOP:%.*]]
370; CHECK:       loop:
371; CHECK-NEXT:    [[VAL1:%.*]] = call i64 @get.i64()
372; CHECK-NEXT:    [[GEP:%.*]] = getelementptr [0 x i8], ptr [[INVARIANT_GEP]], i64 [[ARG3]], i64 [[VAL1]]
373; CHECK-NEXT:    call void @use(ptr [[GEP]])
374; CHECK-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
375; CHECK:       exit:
376; CHECK-NEXT:    ret void
377;
378entry:
379  br label %loop
380
381loop:
382  %val1 = call i64 @get.i64()
383  %ptr2 = getelementptr [0 x i8], ptr %ptr, i64 %arg3, i64 %val1
384  %ptr3 = getelementptr [0 x i8], ptr %ptr2, i64 %arg1, i64 %arg2
385  call void @use(ptr %ptr3)
386  br i1 %c, label %loop, label %exit
387
388exit:
389  ret void
390}
391
392define void @src_already_invariant_speculation(ptr %ptr, i1 %c, i1 %c2, i64 %arg1, i64 %arg2) {
393; SPEC-LABEL: define void @src_already_invariant_speculation
394; SPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
395; SPEC-NEXT:  entry:
396; SPEC-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
397; SPEC-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
398; SPEC-NEXT:    br label [[LOOP:%.*]]
399; SPEC:       loop:
400; SPEC-NEXT:    br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
401; SPEC:       if:
402; SPEC-NEXT:    call void @use(ptr [[PTR3]])
403; SPEC-NEXT:    br label [[LATCH]]
404; SPEC:       latch:
405; SPEC-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
406; SPEC:       exit:
407; SPEC-NEXT:    ret void
408;
409; NOSPEC-LABEL: define void @src_already_invariant_speculation
410; NOSPEC-SAME: (ptr [[PTR:%.*]], i1 [[C:%.*]], i1 [[C2:%.*]], i64 [[ARG1:%.*]], i64 [[ARG2:%.*]]) {
411; NOSPEC-NEXT:  entry:
412; NOSPEC-NEXT:    br label [[LOOP:%.*]]
413; NOSPEC:       loop:
414; NOSPEC-NEXT:    br i1 [[C2]], label [[IF:%.*]], label [[LATCH:%.*]]
415; NOSPEC:       if:
416; NOSPEC-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[ARG1]]
417; NOSPEC-NEXT:    [[PTR3:%.*]] = getelementptr i8, ptr [[PTR2]], i64 [[ARG2]]
418; NOSPEC-NEXT:    call void @use(ptr [[PTR3]])
419; NOSPEC-NEXT:    br label [[LATCH]]
420; NOSPEC:       latch:
421; NOSPEC-NEXT:    br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]]
422; NOSPEC:       exit:
423; NOSPEC-NEXT:    ret void
424;
425entry:
426  br label %loop
427
428loop:
429  br i1 %c2, label %if, label %latch
430
431if:
432  %ptr2 = getelementptr i8, ptr %ptr, i64 %arg1
433  %ptr3 = getelementptr i8, ptr %ptr2, i64 %arg2
434  call void @use(ptr %ptr3)
435  br label %latch
436
437latch:
438  br i1 %c, label %loop, label %exit
439
440exit:
441  ret void
442}
443