xref: /llvm-project/llvm/test/Transforms/InstCombine/ptrtoint-nullgep.ll (revision cc158d4c0bb50554dadcad44c10cafb052376cea)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
2; Check that we can fold operations with (gep null) inputs.
3; Note: the LLParser already does some constant folding, check that output first:
4; RUN: opt -passes=verify -S < %s | FileCheck %s --check-prefixes=ALL,LLPARSER
5; We should be able to fold almost everything in InstSimplify other than the final test which requries InstCombine
6; RUN: opt -S -passes=instsimplify < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTSIMPLIFY,INTEGRAL-INSTSIMPLIFY
7; RUN: opt -S -passes=instcombine < %s | FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,INTEGRAL,INSTCOMBINE,INTEGRAL-INSTCOMBINE
8; Non-integral pointers limit certain transformations on pointers:
9; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instsimplify | \
10; RUN:   FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTSIMPLIFY,NONINTEGRAL-INSTSIMPLIFY
11; RUN: sed -e 's/p:64:64:64:64/p:64:64:64:64-ni:1/g' %s | opt -S -passes=instcombine | \
12; RUN:   FileCheck %s --allow-unused-prefixes --check-prefixes=ALL,CHECK,NONINTEGRAL,INSTCOMBINE,NONINTEGRAL-INSTCOMBINE
13target datalayout = "p:64:64:64:64"
14
15declare void @use_i64(i64)
16declare void @use_ptr(ptr addrspace(1))
17
18define i64 @constant_fold_ptrtoint_gep_zero() {
19; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero() {
20; ALL-NEXT:    ret i64 0
21;
22  ret i64 ptrtoint (ptr addrspace(1) null to i64)
23}
24define i64 @constant_fold_ptrtoint_gep_nonzero() {
25; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
26; LLPARSER-NEXT:    ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64)
27;
28; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
29; INSTSIMPLIFY-NEXT:    ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64)
30;
31; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero() {
32; INSTCOMBINE-NEXT:    ret i64 4936
33;
34  ret i64 ptrtoint (ptr addrspace(1) getelementptr (i32, ptr addrspace(1) null, i64 1234) to i64)
35}
36
37define i64 @constant_fold_ptrtoint_gep_zero_inbounds() {
38; ALL-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_zero_inbounds() {
39; ALL-NEXT:    ret i64 0
40;
41  ret i64 ptrtoint (ptr addrspace(1) null to i64)
42}
43
44; In theory we could fold this to poison/null, but that would break offsetof
45; implementations that don't use __builtin_offsetof.
46; TODO: should Clang special case ((INTEGER)&((TYPE *)0)->MEMBER) to emit a non-inbounds GEP?
47define i64 @constant_fold_ptrtoint_gep_nonzero_inbounds() {
48; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
49; LLPARSER-NEXT:    ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64)
50;
51; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
52; INSTSIMPLIFY-NEXT:    ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64)
53;
54; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_gep_nonzero_inbounds() {
55; INSTCOMBINE-NEXT:    ret i64 4936
56;
57  ret i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i32, ptr addrspace(1) null, i64 1234) to i64)
58}
59
60; Check all combinations of inbounds+non-inbounds GEP with the outer GEP having a non-zero offset
61define void @constant_fold_ptrtoint_of_gep_of_nullgep() {
62; LLPARSER-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
63; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
64; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
65; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
66; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
67; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
68; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
69; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
70; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
71; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
72; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
73; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
74; LLPARSER-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
75; LLPARSER-NEXT:    ret void
76;
77; INSTSIMPLIFY-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
78; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
79; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
80; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
81; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
82; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
83; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
84; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
85; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
86; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
87; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
88; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
89; INSTSIMPLIFY-NEXT:    call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
90; INSTSIMPLIFY-NEXT:    ret void
91;
92; INSTCOMBINE-LABEL: define {{[^@]+}}@constant_fold_ptrtoint_of_gep_of_nullgep() {
93; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
94; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
95; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
96; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
97; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
98; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
99; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
100; INSTCOMBINE-NEXT:    call void @use_i64(i64 1234)
101; INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
102; INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
103; INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
104; INSTCOMBINE-NEXT:    call void @use_i64(i64 0)
105; INSTCOMBINE-NEXT:    ret void
106;
107  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
108  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
109  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234) to i64))
110  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234) to i64))
111  ; Same again but this time with the inner GEP using the non-zero offset
112  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
113  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
114  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
115  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 1234), i64 0) to i64))
116  ; And finally with two constants that sum to zero
117  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
118  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
119  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr inbounds (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
120  call void @use_i64(i64 ptrtoint (ptr addrspace(1) getelementptr (i8, ptr addrspace(1) getelementptr (i8, ptr addrspace(1) null, i64 -1), i64 1) to i64))
121  ret void
122}
123
124; Another set of tests for instructions instead of constants
125define i64 @fold_ptrtoint_nullgep_zero() {
126; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() {
127; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 0, 0
128; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[OFFSET]]
129; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
130; LLPARSER-NEXT:    ret i64 [[RET]]
131;
132; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero() {
133; CHECK-NEXT:    ret i64 0
134;
135  %offset = add i64 0, 0
136  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %offset
137  %ret = ptrtoint ptr addrspace(1) %ptr to i64
138  ret i64 %ret
139}
140
141define i64 @fold_ptrtoint_nullgep_zero_inbounds() {
142; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() {
143; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 0, 0
144; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[OFFSET]]
145; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
146; LLPARSER-NEXT:    ret i64 [[RET]]
147;
148; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_zero_inbounds() {
149; CHECK-NEXT:    ret i64 0
150;
151  %offset = add i64 0, 0
152  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %offset
153  %ret = ptrtoint ptr addrspace(1) %ptr to i64
154  ret i64 %ret
155}
156
157define i64 @fold_ptrtoint_nullgep_nonzero() {
158; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
159; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 1234, 0
160; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[OFFSET]]
161; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
162; LLPARSER-NEXT:    ret i64 [[RET]]
163;
164; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero() {
165; CHECK-NEXT:    ret i64 1234
166;
167  %offset = add i64 1234, 0
168  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %offset
169  %ret = ptrtoint ptr addrspace(1) %ptr to i64
170  ret i64 %ret
171}
172
173; Inbounds constant null-GEP with non-zero could be constant-folded to null/poison,
174; but folding it to the value makes ((INTEGER)&((TYPE *)0)->MEMBER) work.
175define i64 @fold_ptrtoint_nullgep_nonzero_inbounds() {
176; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
177; LLPARSER-NEXT:    [[OFFSET:%.*]] = add i64 1234, 0
178; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[OFFSET]]
179; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
180; LLPARSER-NEXT:    ret i64 [[RET]]
181;
182; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_nonzero_inbounds() {
183; CHECK-NEXT:    ret i64 1234
184;
185  %offset = add i64 1234, 0
186  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %offset
187  %ret = ptrtoint ptr addrspace(1) %ptr to i64
188  ret i64 %ret
189}
190
191; We should be able to fold ptrtoint(gep null, x) to x
192define i64 @fold_ptrtoint_nullgep_variable(i64 %val) {
193; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
194; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
195; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
196; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
197; LLPARSER-NEXT:    ret i64 [[RET]]
198;
199; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
200; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
201; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
202; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
203; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
204;
205; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable
206; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
207; INSTCOMBINE-NEXT:    ret i64 [[VAL]]
208;
209  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %val
210  %ret = ptrtoint ptr addrspace(1) %ptr to i64
211  ret i64 %ret
212}
213
214; Inbounds null-GEP with non-zero offset could be folded to poison/null.
215define i64 @fold_ptrtoint_nullgep_variable_known_nonzero(i64 %val) {
216; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
217; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
218; LLPARSER-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
219; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
220; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
221; LLPARSER-NEXT:    ret i64 [[RET]]
222;
223; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
224; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
225; INSTSIMPLIFY-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
226; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
227; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
228; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
229;
230; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero
231; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
232; INSTCOMBINE-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
233; INSTCOMBINE-NEXT:    ret i64 [[NON_ZERO_OFFSET]]
234;
235  %non_zero_offset = or i64 %val, 1
236  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %non_zero_offset
237  %ret = ptrtoint ptr addrspace(1) %ptr to i64
238  ret i64 %ret
239}
240
241; This is only valid if %val is zero so we could fold the result to 0.
242define i64 @fold_ptrtoint_nullgep_variable_inbounds(i64 %val) {
243; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
244; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
245; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]]
246; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
247; LLPARSER-NEXT:    ret i64 [[RET]]
248;
249; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
250; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
251; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[VAL]]
252; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
253; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
254;
255; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_inbounds
256; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
257; INSTCOMBINE-NEXT:    ret i64 [[VAL]]
258;
259  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %val
260  %ret = ptrtoint ptr addrspace(1) %ptr to i64
261  ret i64 %ret
262}
263
264; A non-constant but known-non-zero GEP could be folded to poison/null
265define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds(i64 %val) {
266; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
267; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
268; LLPARSER-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
269; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
270; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
271; LLPARSER-NEXT:    ret i64 [[RET]]
272;
273; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
274; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
275; INSTSIMPLIFY-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
276; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]]
277; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
278; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
279;
280; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds
281; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
282; INSTCOMBINE-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
283; INSTCOMBINE-NEXT:    ret i64 [[NON_ZERO_OFFSET]]
284;
285  %non_zero_offset = or i64 %val, 1
286  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %non_zero_offset
287  %ret = ptrtoint ptr addrspace(1) %ptr to i64
288  ret i64 %ret
289}
290
291; A non-constant but known-non-zero GEP could be folded to poison/null
292define i64 @fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices(i64 %val) {
293; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
294; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
295; LLPARSER-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
296; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1
297; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
298; LLPARSER-NEXT:    ret i64 [[RET]]
299;
300; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
301; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
302; INSTSIMPLIFY-NEXT:    [[NON_ZERO_OFFSET:%.*]] = or i64 [[VAL]], 1
303; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 [[NON_ZERO_OFFSET]], i32 1
304; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
305; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
306;
307; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_known_nonzero_inbounds_multiple_indices
308; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
309; INSTCOMBINE-NEXT:    [[NON_ZERO_OFFSET:%.*]] = shl i64 [[VAL]], 1
310; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = or i64 [[NON_ZERO_OFFSET]], 3
311; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
312;
313  %non_zero_offset = or i64 %val, 1
314  %ptr = getelementptr inbounds [2 x i8], ptr addrspace(1) null, i64 %non_zero_offset, i32 1
315  %ret = ptrtoint ptr addrspace(1) %ptr to i64
316  ret i64 %ret
317}
318
319; We can't fold non-i8 GEPs in InstSimplify since that would require adding new arithmetic.
320; However, InstCombine can decompose the null gep and convert it to a shift.
321define i64 @fold_ptrtoint_nullgep_i32_variable(i64 %val) {
322; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
323; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
324; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]]
325; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
326; LLPARSER-NEXT:    ret i64 [[RET]]
327;
328; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
329; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
330; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr addrspace(1) null, i64 [[VAL]]
331; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
332; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
333;
334; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_i32_variable
335; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
336; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[VAL]], 2
337; INSTCOMBINE-NEXT:    ret i64 [[PTR_IDX]]
338;
339  %ptr = getelementptr i32, ptr addrspace(1) null, i64 %val
340  %ret = ptrtoint ptr addrspace(1) %ptr to i64
341  ret i64 %ret
342}
343
344; ptrtoint type does not match index type so requires requite a new trunc instruction
345define i32 @fold_ptrtoint_nullgep_variable_trunc(i64 %val) {
346; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
347; LLPARSER-SAME: (i64 [[VAL:%.*]]) {
348; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
349; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32
350; LLPARSER-NEXT:    ret i32 [[RET]]
351;
352; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
353; INSTSIMPLIFY-SAME: (i64 [[VAL:%.*]]) {
354; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[VAL]]
355; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i32
356; INSTSIMPLIFY-NEXT:    ret i32 [[RET]]
357;
358; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_variable_trunc
359; INSTCOMBINE-SAME: (i64 [[VAL:%.*]]) {
360; INSTCOMBINE-NEXT:    [[RET:%.*]] = trunc i64 [[VAL]] to i32
361; INSTCOMBINE-NEXT:    ret i32 [[RET]]
362;
363  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %val
364  %ret = ptrtoint ptr addrspace(1) %ptr to i32
365  ret i32 %ret
366}
367
368; For the following three tests, we could fold the result to poison/null since there is at least
369; one inbounds GEP on null with a non-zero offset.
370define i64 @fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
371; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
372; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
373; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
374; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]]
375; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]]
376; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
377; LLPARSER-NEXT:    ret i64 [[RET]]
378;
379; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_zero_nullgep_of_nonzero_inbounds_nullgep() {
380; CHECK-NEXT:    ret i64 1234
381;
382  %nonzero_offset = add i64 1234, 0
383  %zero_offset = sub i64 %nonzero_offset, 1234
384  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset
385  %ptr2 = getelementptr i8, ptr addrspace(1) %ptr, i64 %zero_offset
386  %ret = ptrtoint ptr addrspace(1) %ptr2 to i64
387  ret i64 %ret
388}
389
390define i64 @fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
391; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
392; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
393; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
394; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr addrspace(1) null, i64 [[ZERO_OFFSET]]
395; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[NONZERO_OFFSET]]
396; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
397; LLPARSER-NEXT:    ret i64 [[RET]]
398;
399; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_nonzero_inbounds_nullgep_of_zero_noninbounds_nullgep() {
400; CHECK-NEXT:    ret i64 1234
401;
402  %nonzero_offset = add i64 1234, 0
403  %zero_offset = sub i64 %nonzero_offset, 1234
404  %ptr = getelementptr i8, ptr addrspace(1) null, i64 %zero_offset
405  %ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %nonzero_offset
406  %ret = ptrtoint ptr addrspace(1) %ptr2 to i64
407  ret i64 %ret
408}
409
410; We should also be able to fold GEPs with multiple indices.
411%struct.S = type { [2 x %struct.K] }
412%struct.K = type { [32 x i8] }
413
414define i64 @fold_complex_index_last_nonzero(i64 %x) local_unnamed_addr #0 {
415; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
416; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
417; LLPARSER-NEXT:  entry:
418; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]]
419; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
420; LLPARSER-NEXT:    ret i64 [[RET]]
421;
422; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
423; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
424; INSTSIMPLIFY-NEXT:  entry:
425; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 [[X]]
426; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
427; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
428;
429; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_last_nonzero
430; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
431; INSTCOMBINE-NEXT:  entry:
432; INSTCOMBINE-NEXT:    ret i64 [[X]]
433;
434entry:
435  %ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 0, i32 0, i64 0, i32 0, i64 %x
436  %ret = ptrtoint ptr addrspace(1) %ptr to i64
437  ret i64 %ret
438}
439
440define i64 @fold_complex_index_multiple_nonzero(i64 %x) local_unnamed_addr #0 {
441; LLPARSER-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
442; LLPARSER-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
443; LLPARSER-NEXT:  entry:
444; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]]
445; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
446; LLPARSER-NEXT:    ret i64 [[RET]]
447;
448; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
449; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
450; INSTSIMPLIFY-NEXT:  entry:
451; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 [[X]]
452; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
453; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
454;
455; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_complex_index_multiple_nonzero
456; INSTCOMBINE-SAME: (i64 [[X:%.*]]) local_unnamed_addr {
457; INSTCOMBINE-NEXT:  entry:
458; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add nsw i64 [[X]], 96
459; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
460;
461entry:
462  %ptr = getelementptr inbounds %struct.S, ptr addrspace(1) null, i64 1, i32 0, i64 1, i32 0, i64 %x
463  %ret = ptrtoint ptr addrspace(1) %ptr to i64
464  ret i64 %ret
465}
466
467define i64 @fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
468; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
469; LLPARSER-NEXT:    [[NONZERO_OFFSET:%.*]] = add i64 1234, 0
470; LLPARSER-NEXT:    [[ZERO_OFFSET:%.*]] = sub i64 [[NONZERO_OFFSET]], 1234
471; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr addrspace(1) null, i64 [[NONZERO_OFFSET]]
472; LLPARSER-NEXT:    [[PTR2:%.*]] = getelementptr inbounds i8, ptr addrspace(1) [[PTR]], i64 [[ZERO_OFFSET]]
473; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR2]] to i64
474; LLPARSER-NEXT:    ret i64 [[RET]]
475;
476; CHECK-LABEL: define {{[^@]+}}@fold_ptrtoint_inbounds_nullgep_of_nonzero_inbounds_nullgep() {
477; CHECK-NEXT:    ret i64 1234
478;
479  %nonzero_offset = add i64 1234, 0
480  %zero_offset = sub i64 %nonzero_offset, 1234
481  %ptr = getelementptr inbounds i8, ptr addrspace(1) null, i64 %nonzero_offset
482  %ptr2 = getelementptr inbounds i8, ptr addrspace(1) %ptr, i64 %zero_offset
483  %ret = ptrtoint ptr addrspace(1) %ptr2 to i64
484  ret i64 %ret
485}
486
487; Check that InstCombine can convert ptrtoint(gep null) with multiple indices
488define i64 @fold_ptrtoint_nullgep_array_one_var_1(i64 %x) {
489; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
490; LLPARSER-SAME: (i64 [[X:%.*]]) {
491; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3
492; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
493; LLPARSER-NEXT:    ret i64 [[RET]]
494;
495; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
496; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) {
497; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 3
498; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
499; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
500;
501; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_1
502; INSTCOMBINE-SAME: (i64 [[X:%.*]]) {
503; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[X]], 2
504; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 6
505; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
506;
507  %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 3
508  %ret = ptrtoint ptr addrspace(1) %ptr to i64
509  ret i64 %ret
510}
511
512define i64 @fold_ptrtoint_nullgep_array_one_var_2(i64 %x) {
513; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
514; LLPARSER-SAME: (i64 [[X:%.*]]) {
515; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]]
516; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
517; LLPARSER-NEXT:    ret i64 [[RET]]
518;
519; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
520; INSTSIMPLIFY-SAME: (i64 [[X:%.*]]) {
521; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 [[X]]
522; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
523; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
524;
525; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nullgep_array_one_var_2
526; INSTCOMBINE-SAME: (i64 [[X:%.*]]) {
527; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[X]], 1
528; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], 28
529; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
530;
531  %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 7, i64 %x
532  %ret = ptrtoint ptr addrspace(1) %ptr to i64
533  ret i64 %ret
534}
535
536define i64 @fold_ptrtoint_nested_array_two_vars(i64 %x, i64 %y) {
537; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
538; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
539; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
540; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
541; LLPARSER-NEXT:    ret i64 [[RET]]
542;
543; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
544; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
545; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
546; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
547; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
548;
549; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars
550; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
551; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[X]], 2
552; INSTCOMBINE-NEXT:    [[PTR_IDX1:%.*]] = shl i64 [[Y]], 1
553; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
554; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
555;
556
557  %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y
558  %ret = ptrtoint ptr addrspace(1) %ptr to i64
559  ret i64 %ret
560}
561
562define i64 @fold_ptrtoint_nested_array_two_vars_plus_zero(i64 %x, i64 %y) {
563; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
564; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
565; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0
566; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
567; LLPARSER-NEXT:    ret i64 [[RET]]
568;
569; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
570; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
571; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 0
572; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
573; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
574;
575; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_zero
576; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
577; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[X]], 3
578; INSTCOMBINE-NEXT:    [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2
579; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
580; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS]]
581;
582  %ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 0
583  %ret = ptrtoint ptr addrspace(1) %ptr to i64
584  ret i64 %ret
585}
586
587define i64 @fold_ptrtoint_nested_array_two_vars_plus_const(i64 %x, i64 %y) {
588; LLPARSER-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
589; LLPARSER-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
590; LLPARSER-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1
591; LLPARSER-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
592; LLPARSER-NEXT:    ret i64 [[RET]]
593;
594; INSTSIMPLIFY-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
595; INSTSIMPLIFY-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
596; INSTSIMPLIFY-NEXT:    [[PTR:%.*]] = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 [[X]], i64 [[Y]], i64 1
597; INSTSIMPLIFY-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
598; INSTSIMPLIFY-NEXT:    ret i64 [[RET]]
599;
600; INSTCOMBINE-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_array_two_vars_plus_const
601; INSTCOMBINE-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
602; INSTCOMBINE-NEXT:    [[PTR_IDX:%.*]] = shl i64 [[X]], 3
603; INSTCOMBINE-NEXT:    [[PTR_IDX1:%.*]] = shl i64 [[Y]], 2
604; INSTCOMBINE-NEXT:    [[PTR_OFFS:%.*]] = add i64 [[PTR_IDX]], [[PTR_IDX1]]
605; INSTCOMBINE-NEXT:    [[PTR_OFFS2:%.*]] = or disjoint i64 [[PTR_OFFS]], 2
606; INSTCOMBINE-NEXT:    ret i64 [[PTR_OFFS2]]
607;
608  %ptr = getelementptr [2 x [2 x i16]], ptr addrspace(1) null, i64 %x, i64 %y, i64 1
609  %ret = ptrtoint ptr addrspace(1) %ptr to i64
610  ret i64 %ret
611}
612
613; Negative test -- should not be folded since there are multiple GEP uses
614define i64 @fold_ptrtoint_nested_nullgep_array_variable_multiple_uses(i64 %x, i64 %y) {
615; ALL-LABEL: define {{[^@]+}}@fold_ptrtoint_nested_nullgep_array_variable_multiple_uses
616; ALL-SAME: (i64 [[X:%.*]], i64 [[Y:%.*]]) {
617; ALL-NEXT:    [[PTR:%.*]] = getelementptr [2 x i16], ptr addrspace(1) null, i64 [[X]], i64 [[Y]]
618; ALL-NEXT:    call void @use_ptr(ptr addrspace(1) [[PTR]])
619; ALL-NEXT:    [[RET:%.*]] = ptrtoint ptr addrspace(1) [[PTR]] to i64
620; ALL-NEXT:    ret i64 [[RET]]
621;
622  %ptr = getelementptr [2 x i16], ptr addrspace(1) null, i64 %x, i64 %y
623  call void @use_ptr(ptr addrspace(1) %ptr)
624  %ret = ptrtoint ptr addrspace(1) %ptr to i64
625  ret i64 %ret
626}
627