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
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
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
48 ; Offsets of first and last GEP cancel out.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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