[SLP] Add cost model for `llvm.powi.*` intrinsics
[llvm-project.git] / llvm / test / Transforms / InstCombine / gep-merge-constant-indices.ll
blobb82c366ca9e94ca8dab471746bf15a4a258c1cf8
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instcombine -opaque-pointers -S | FileCheck %s
4 ; Test merging GEP of GEP with constant indices.
6 target datalayout = "i24:8:8"
8 %struct.A = type { [123 x i8], i32 }
9 %struct.B = type { i8, [3 x i16], %struct.A, float }
10 %struct.C = type { i8, i32, i32 }
12 ; result = (i32*) p + 3
13 define ptr @mergeBasic(ptr %p) {
14 ; CHECK-LABEL: @mergeBasic(
15 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 3
16 ; CHECK-NEXT:    ret ptr [[TMP1]]
18   %1 = getelementptr inbounds i32, ptr %p, i64 1
19   %2 = getelementptr inbounds i32, ptr %1, i64 2
20   ret ptr %2
23 ; First GEP is merged into the second.
24 ; result = (i8*) p + 10
25 define ptr @mergeDifferentTypes(ptr %p) {
26 ; CHECK-LABEL: @mergeDifferentTypes(
27 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 10
28 ; CHECK-NEXT:    ret ptr [[TMP1]]
30   %1 = getelementptr inbounds i8, ptr %p, i64 2
31   %2 = getelementptr inbounds i64, ptr %1, i64 1
32   ret ptr %2
35 ; Second GEP is merged into the first.
36 ; result = (i8*) p + 10
37 define ptr @mergeReverse(ptr %p) {
38 ; CHECK-LABEL: @mergeReverse(
39 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
40 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 2
41 ; CHECK-NEXT:    ret ptr [[TMP2]]
43   %1 = getelementptr inbounds i64, ptr %p, i64 1
44   %2 = getelementptr inbounds i8, ptr %1, i64 2
45   ret ptr %2
48 ; Offsets of first and last GEP cancel out.
49 ; result = p
50 define ptr @zeroSum(ptr %p) {
51 ; CHECK-LABEL: @zeroSum(
52 ; CHECK-NEXT:    ret ptr [[P:%.*]]
54   %1 = getelementptr inbounds i32, ptr %p, i64 1
55   %2 = getelementptr inbounds i8, ptr %1, i64 -4
56   ret ptr %2
59 ; result = (i8*) (([20 x i8]*) p + 1) + 17
60 define ptr @array1(ptr %p) {
61 ; CHECK-LABEL: @array1(
62 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [20 x i8], ptr [[P:%.*]], i64 1, i64 17
63 ; CHECK-NEXT:    ret ptr [[TMP1]]
65   %1 = getelementptr inbounds [20 x i8], ptr %p, i64 1, i64 1
66   %2 = getelementptr inbounds i64, ptr %1, i64 2
67   ret ptr %2
70 ; result = (i8*) p + 14
71 define ptr @array2(ptr %p, i64 %a) {
72 ; CHECK-LABEL: @array2(
73 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [7 x i32], ptr [[P:%.*]], i64 0, i64 3
74 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 2
75 ; CHECK-NEXT:    ret ptr [[TMP2]]
77   %1 = getelementptr inbounds [7 x i32], ptr %p, i64 0, i64 3
78   %2 = getelementptr inbounds i8, ptr %1, i64 2
79   ret ptr %2
82 ; result = (i8*) (([3 x i8]*) p + 6) + 2
83 define ptr @array3(ptr %p) {
84 ; CHECK-LABEL: @array3(
85 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 2
86 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [3 x i8], ptr [[TMP1]], i64 1, i64 1
87 ; CHECK-NEXT:    ret ptr [[TMP2]]
89   %1 = getelementptr inbounds i64, ptr %p, i64 2
90   %2 = getelementptr inbounds [3 x i8], ptr %1, i64 1, i64 1
91   ret ptr %2
94 ; result = (struct.C*) p + 3
95 define ptr @struct1(ptr %p) {
96 ; CHECK-LABEL: @struct1(
97 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 3
98 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1
99 ; CHECK-NEXT:    ret ptr [[TMP2]]
101   %1 = getelementptr inbounds i64, ptr %p, i64 3
102   %2 = getelementptr inbounds %struct.C, ptr %1, i64 1
103   ret ptr %2
106 ; result = &((struct.A*) p - 1).member1
107 define ptr @struct2(ptr %p) {
108 ; CHECK-LABEL: @struct2(
109 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr [[STRUCT_A:%.*]], ptr [[P:%.*]], i64 -1, i32 1
110 ; CHECK-NEXT:    ret ptr [[TMP1]]
112   %1 = getelementptr inbounds %struct.A, ptr %p, i64 0, i32 1
113   %2 = getelementptr inbounds i8, ptr %1, i64 -128
114   ret ptr %2
117 ; result = (i8*) p - 4
118 define ptr @struct3(ptr %p, i64 %a) {
119 ; CHECK-LABEL: @struct3(
120 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 -4
121 ; CHECK-NEXT:    ret ptr [[TMP1]]
123   %1 = getelementptr inbounds i8, ptr %p, i64 -128
124   %2 = getelementptr inbounds %struct.A, ptr %1, i64 0, i32 1
125   ret ptr %2
127 ; result = ((struct.C*) p + 1).member2
128 define ptr @struct4(ptr %p, i64 %a) {
129 ; CHECK-LABEL: @struct4(
130 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
131 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1
132 ; CHECK-NEXT:    ret ptr [[TMP2]]
134   %1 = getelementptr inbounds i64, ptr %p, i64 1
135   %2 = getelementptr inbounds %struct.C, ptr %1, i64 1
136   ret ptr %2
139 ; result = (i8*) &((struct.B) p)[0].member2.member0 + 7
140 define ptr @structStruct(ptr %p) {
141 ; CHECK-LABEL: @structStruct(
142 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 0, i32 2, i32 0, i64 7
143 ; CHECK-NEXT:    ret ptr [[TMP1]]
145   %1 = getelementptr inbounds %struct.B, ptr %p, i64 0, i32 2, i32 0, i64 3
146   %2 = getelementptr inbounds %struct.A, ptr %1, i64 0, i32 0, i64 4
147   ret ptr %2
150 ; First GEP offset is not divisible by last GEP's source element size, but first
151 ; GEP points to an array such that the last GEP offset is divisible by the
152 ; array's element size, so the first GEP can be rewritten with an extra index.
153 ; result = (i16*) &((struct.B*) p)[0].member1 + 2
154 define ptr @appendIndex(ptr %p) {
155 ; CHECK-LABEL: @appendIndex(
156 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 2
157 ; CHECK-NEXT:    ret ptr [[TMP1]]
159   %1 = getelementptr inbounds %struct.B, ptr %p, i64 0, i32 1
160   %2 = getelementptr inbounds i32, ptr %1, i64 1
161   ret ptr %2
164 ; result = (i8*) &((struct.A*) &((struct.B*) p)[0].member2).member0 + 2
165 define ptr @appendIndexReverse(ptr %p) {
166 ; CHECK-LABEL: @appendIndexReverse(
167 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
168 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[TMP1]], i64 0, i32 1
169 ; CHECK-NEXT:    ret ptr [[TMP2]]
171   %1 = getelementptr inbounds i64, ptr %p, i64 1
172   %2 = getelementptr inbounds %struct.B, ptr %1, i64 0, i32 1
173   ret ptr %2
176 ; Constant-indexed GEP can be merged if the sum of offsets aliases a member's
177 ; address of one of the GEP instructions.
178 ; result = &((struct.C*) p + 2).member1
179 define ptr @structMemberAliasing(ptr %p, i64 %a) {
180 ; CHECK-LABEL: @structMemberAliasing(
181 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
182 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1, i32 2
183 ; CHECK-NEXT:    ret ptr [[TMP2]]
185   %1 = getelementptr inbounds i64, ptr %p, i64 1
186   %2 = getelementptr inbounds %struct.C, ptr %1, i64 1, i32 2
187   ret ptr %2
190 ; Negative test. Offset of either GEP is not divisible by the other's size.
191 ; Here i24 is 8-bit aligned.
192 define ptr @notDivisible(ptr %p) {
193 ; CHECK-LABEL: @notDivisible(
194 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i24, ptr [[P:%.*]], i64 1
195 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 1
196 ; CHECK-NEXT:    ret ptr [[TMP2]]
198   %1 = getelementptr inbounds i24, ptr %p, i64 1
199   %2 = getelementptr inbounds i32, ptr %1, i64 1
200   ret ptr %2
203 ; Two GEP instructions can be merged if one is constant-indexed and the other
204 ; is a sequential type with a constant last index, and the constant offset is
205 ; divisible by the sequential type size.
206 ; result = (i32*) (([4 x i32]*) p + a) + 3
207 define ptr @partialConstant1(ptr %p, i64 %a) {
208 ; CHECK-LABEL: @partialConstant1(
209 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
210 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [4 x i32], ptr [[TMP1]], i64 [[A:%.*]], i64 2
211 ; CHECK-NEXT:    ret ptr [[TMP2]]
213   %1 = getelementptr inbounds i32, ptr %p, i64 1
214   %2 = getelementptr inbounds [4 x i32], ptr %1, i64 %a, i64 2
215   ret ptr %2
218 ; Negative test. Similar to above, but two GEP should not be merged if the
219 ; constant offset is not divisible.
220 define ptr @partialConstant2(ptr %p, i64 %a) {
221 ; CHECK-LABEL: @partialConstant2(
222 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
223 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [4 x i64], ptr [[TMP1]], i64 [[A:%.*]], i64 2
224 ; CHECK-NEXT:    ret ptr [[TMP2]]
226   %1 = getelementptr inbounds i32, ptr %p, i64 1
227   %2 = getelementptr inbounds [4 x i64], ptr %1, i64 %a, i64 2
228   ret ptr %2
231 ; Negative test. Similar to above, but two GEP should not be merged if there is
232 ; another use of the first GEP by the second GEP.
233 define ptr @partialConstant3(ptr %p) {
234 ; CHECK-LABEL: @partialConstant3(
235 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
236 ; CHECK-NEXT:    [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
237 ; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr inbounds [4 x i64], ptr [[TMP1]], i64 [[TMP2]], i64 2
238 ; CHECK-NEXT:    ret ptr [[TMP3]]
240   %1 = getelementptr inbounds i32, ptr %p, i64 1
241   %2 = ptrtoint ptr %1 to i64
242   %3 = getelementptr inbounds [4 x i64], ptr %1, i64 %2, i64 2
243   ret ptr %3
246 ; Two GEP instructions can be merged if one is constant-indexed and the other
247 ; is an aggregate type with a constant last index, and the resulting pointer
248 ; address by adding the constant offset aliases the address of another member.
249 ; result = &((struct.C*) p + a).member2
250 define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
251 ; CHECK-LABEL: @partialConstantMemberAliasing1(
252 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
253 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 1
254 ; CHECK-NEXT:    ret ptr [[TMP2]]
256   %1 = getelementptr inbounds i32, ptr %p, i64 1
257   %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 1
258   ret ptr %2
261 ; Negative test. Similar to above, but the new address does not alias the
262 ; address of another member.
263 define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
264 ; CHECK-LABEL: @partialConstantMemberAliasing2(
265 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 1
266 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 1
267 ; CHECK-NEXT:    ret ptr [[TMP2]]
269   %1 = getelementptr inbounds i8, ptr %p, i64 1
270   %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 1
271   ret ptr %2
274 ; Negative test. Similar to above, but the new address falls outside the address
275 ; range of the object currently pointed by the non-constant GEP.
276 define ptr @partialConstantMemberAliasing3(ptr %p, i64 %a) {
277 ; CHECK-LABEL: @partialConstantMemberAliasing3(
278 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
279 ; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 2
280 ; CHECK-NEXT:    ret ptr [[TMP2]]
282   %1 = getelementptr inbounds i32, ptr %p, i64 1
283   %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 2
284   ret ptr %2