[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / InstCombine / sub-gep.ll
blobbc18608da7a577ead378f3057c21a7e7c308244b
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -instcombine < %s | FileCheck %s
4 target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
6 define i64 @test_inbounds([0 x i32]* %base, i64 %idx) {
7 ; CHECK-LABEL: @test_inbounds(
8 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 2
9 ; CHECK-NEXT:    ret i64 [[P2_IDX]]
11   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
12   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
13   %i1 = ptrtoint i32* %p1 to i64
14   %i2 = ptrtoint i32* %p2 to i64
15   %d = sub i64 %i2, %i1
16   ret i64 %d
19 define i64 @test_partial_inbounds1([0 x i32]* %base, i64 %idx) {
20 ; CHECK-LABEL: @test_partial_inbounds1(
21 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl i64 [[IDX:%.*]], 2
22 ; CHECK-NEXT:    ret i64 [[P2_IDX]]
24   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
25   %p2 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
26   %i1 = ptrtoint i32* %p1 to i64
27   %i2 = ptrtoint i32* %p2 to i64
28   %d = sub i64 %i2, %i1
29   ret i64 %d
32 define i64 @test_partial_inbounds2([0 x i32]* %base, i64 %idx) {
33 ; CHECK-LABEL: @test_partial_inbounds2(
34 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 2
35 ; CHECK-NEXT:    ret i64 [[P2_IDX]]
37   %p1 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 0
38   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
39   %i1 = ptrtoint i32* %p1 to i64
40   %i2 = ptrtoint i32* %p2 to i64
41   %d = sub i64 %i2, %i1
42   ret i64 %d
45 define i64 @test_inbounds_nuw([0 x i32]* %base, i64 %idx) {
46 ; CHECK-LABEL: @test_inbounds_nuw(
47 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl nuw nsw i64 [[IDX:%.*]], 2
48 ; CHECK-NEXT:    ret i64 [[P2_IDX]]
50   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
51   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
52   %i1 = ptrtoint i32* %p1 to i64
53   %i2 = ptrtoint i32* %p2 to i64
54   %d = sub nuw i64 %i2, %i1
55   ret i64 %d
58 define i64 @test_nuw([0 x i32]* %base, i64 %idx) {
59 ; CHECK-LABEL: @test_nuw(
60 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl i64 [[IDX:%.*]], 2
61 ; CHECK-NEXT:    ret i64 [[P2_IDX]]
63   %p1 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 0
64   %p2 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
65   %i1 = ptrtoint i32* %p1 to i64
66   %i2 = ptrtoint i32* %p2 to i64
67   %d = sub nuw i64 %i2, %i1
68   ret i64 %d
71 define i32 @test_inbounds_nuw_trunc([0 x i32]* %base, i64 %idx) {
72 ; CHECK-LABEL: @test_inbounds_nuw_trunc(
73 ; CHECK-NEXT:    [[IDX_TR:%.*]] = trunc i64 [[IDX:%.*]] to i32
74 ; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[IDX_TR]], 2
75 ; CHECK-NEXT:    ret i32 [[TMP1]]
77   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
78   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
79   %i1 = ptrtoint i32* %p1 to i64
80   %i2 = ptrtoint i32* %p2 to i64
81   %t1 = trunc i64 %i1 to i32
82   %t2 = trunc i64 %i2 to i32
83   %d = sub nuw i32 %t2, %t1
84   ret i32 %d
87 define i64 @test_inbounds_nuw_swapped([0 x i32]* %base, i64 %idx) {
88 ; CHECK-LABEL: @test_inbounds_nuw_swapped(
89 ; CHECK-NEXT:    [[P2_IDX_NEG:%.*]] = mul i64 [[IDX:%.*]], -4
90 ; CHECK-NEXT:    ret i64 [[P2_IDX_NEG]]
92   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
93   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
94   %i1 = ptrtoint i32* %p2 to i64
95   %i2 = ptrtoint i32* %p1 to i64
96   %d = sub nuw i64 %i2, %i1
97   ret i64 %d
100 define i64 @test_inbounds1_nuw_swapped([0 x i32]* %base, i64 %idx) {
101 ; CHECK-LABEL: @test_inbounds1_nuw_swapped(
102 ; CHECK-NEXT:    [[P2_IDX_NEG:%.*]] = mul i64 [[IDX:%.*]], -4
103 ; CHECK-NEXT:    ret i64 [[P2_IDX_NEG]]
105   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 0
106   %p2 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
107   %i1 = ptrtoint i32* %p2 to i64
108   %i2 = ptrtoint i32* %p1 to i64
109   %d = sub nuw i64 %i2, %i1
110   ret i64 %d
113 define i64 @test_inbounds2_nuw_swapped([0 x i32]* %base, i64 %idx) {
114 ; CHECK-LABEL: @test_inbounds2_nuw_swapped(
115 ; CHECK-NEXT:    [[P2_IDX_NEG:%.*]] = mul i64 [[IDX:%.*]], -4
116 ; CHECK-NEXT:    ret i64 [[P2_IDX_NEG]]
118   %p1 = getelementptr [0 x i32], [0 x i32]* %base, i64 0, i64 0
119   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
120   %i1 = ptrtoint i32* %p2 to i64
121   %i2 = ptrtoint i32* %p1 to i64
122   %d = sub nuw i64 %i2, %i1
123   ret i64 %d
126 define i64 @test_inbounds_two_gep([0 x i32]* %base, i64 %idx, i64 %idx2) {
127 ; CHECK-LABEL: @test_inbounds_two_gep(
128 ; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]]
129 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2
130 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
132   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
133   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx2
134   %i1 = ptrtoint i32* %p1 to i64
135   %i2 = ptrtoint i32* %p2 to i64
136   %d = sub i64 %i2, %i1
137   ret i64 %d
140 define i64 @test_inbounds_nsw_two_gep([0 x i32]* %base, i64 %idx, i64 %idx2) {
141 ; CHECK-LABEL: @test_inbounds_nsw_two_gep(
142 ; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]]
143 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2
144 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
146   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
147   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx2
148   %i1 = ptrtoint i32* %p1 to i64
149   %i2 = ptrtoint i32* %p2 to i64
150   %d = sub nsw i64 %i2, %i1
151   ret i64 %d
154 define i64 @test_inbounds_nuw_two_gep([0 x i32]* %base, i64 %idx, i64 %idx2) {
155 ; CHECK-LABEL: @test_inbounds_nuw_two_gep(
156 ; CHECK-NEXT:    [[TMP1:%.*]] = sub nsw i64 [[IDX2:%.*]], [[IDX:%.*]]
157 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = shl nsw i64 [[TMP1]], 2
158 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
160   %p1 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx
161   %p2 = getelementptr inbounds [0 x i32], [0 x i32]* %base, i64 0, i64 %idx2
162   %i1 = ptrtoint i32* %p1 to i64
163   %i2 = ptrtoint i32* %p2 to i64
164   %d = sub nuw i64 %i2, %i1
165   ret i64 %d
168 define i64 @test_inbounds_nuw_multi_index([0 x [2 x i32]]* %base, i64 %idx, i64 %idx2) {
169 ; CHECK-LABEL: @test_inbounds_nuw_multi_index(
170 ; CHECK-NEXT:    [[P2_IDX:%.*]] = shl nsw i64 [[IDX:%.*]], 3
171 ; CHECK-NEXT:    [[P2_IDX1:%.*]] = shl nsw i64 [[IDX2:%.*]], 2
172 ; CHECK-NEXT:    [[P2_OFFS:%.*]] = add nsw i64 [[P2_IDX]], [[P2_IDX1]]
173 ; CHECK-NEXT:    ret i64 [[P2_OFFS]]
175   %p1 = getelementptr inbounds [0 x [2 x i32]], [0 x [2 x i32]]* %base, i64 0, i64 0, i64 0
176   %p2 = getelementptr inbounds [0 x [2 x i32]], [0 x [2 x i32]]* %base, i64 0, i64 %idx, i64 %idx2
177   %i1 = ptrtoint i32* %p1 to i64
178   %i2 = ptrtoint i32* %p2 to i64
179   %d = sub nuw i64 %i2, %i1
180   ret i64 %d
183 ; rdar://7362831
184 define i32 @test23(i8* %P, i64 %A){
185 ; CHECK-LABEL: @test23(
186 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i32
187 ; CHECK-NEXT:    ret i32 [[TMP1]]
189   %B = getelementptr inbounds i8, i8* %P, i64 %A
190   %C = ptrtoint i8* %B to i64
191   %D = trunc i64 %C to i32
192   %E = ptrtoint i8* %P to i64
193   %F = trunc i64 %E to i32
194   %G = sub i32 %D, %F
195   ret i32 %G
198 define i8 @test23_as1(i8 addrspace(1)* %P, i16 %A) {
199 ; CHECK-LABEL: @test23_as1(
200 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i16 [[A:%.*]] to i8
201 ; CHECK-NEXT:    ret i8 [[TMP1]]
203   %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
204   %C = ptrtoint i8 addrspace(1)* %B to i16
205   %D = trunc i16 %C to i8
206   %E = ptrtoint i8 addrspace(1)* %P to i16
207   %F = trunc i16 %E to i8
208   %G = sub i8 %D, %F
209   ret i8 %G
212 define i64 @test24(i8* %P, i64 %A){
213 ; CHECK-LABEL: @test24(
214 ; CHECK-NEXT:    ret i64 [[A:%.*]]
216   %B = getelementptr inbounds i8, i8* %P, i64 %A
217   %C = ptrtoint i8* %B to i64
218   %E = ptrtoint i8* %P to i64
219   %G = sub i64 %C, %E
220   ret i64 %G
223 define i16 @test24_as1(i8 addrspace(1)* %P, i16 %A) {
224 ; CHECK-LABEL: @test24_as1(
225 ; CHECK-NEXT:    ret i16 [[A:%.*]]
227   %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
228   %C = ptrtoint i8 addrspace(1)* %B to i16
229   %E = ptrtoint i8 addrspace(1)* %P to i16
230   %G = sub i16 %C, %E
231   ret i16 %G
234 define i64 @test24a(i8* %P, i64 %A){
235 ; CHECK-LABEL: @test24a(
236 ; CHECK-NEXT:    [[DIFF_NEG:%.*]] = sub i64 0, [[A:%.*]]
237 ; CHECK-NEXT:    ret i64 [[DIFF_NEG]]
239   %B = getelementptr inbounds i8, i8* %P, i64 %A
240   %C = ptrtoint i8* %B to i64
241   %E = ptrtoint i8* %P to i64
242   %G = sub i64 %E, %C
243   ret i64 %G
246 define i16 @test24a_as1(i8 addrspace(1)* %P, i16 %A) {
247 ; CHECK-LABEL: @test24a_as1(
248 ; CHECK-NEXT:    [[DIFF_NEG:%.*]] = sub i16 0, [[A:%.*]]
249 ; CHECK-NEXT:    ret i16 [[DIFF_NEG]]
251   %B = getelementptr inbounds i8, i8 addrspace(1)* %P, i16 %A
252   %C = ptrtoint i8 addrspace(1)* %B to i16
253   %E = ptrtoint i8 addrspace(1)* %P to i16
254   %G = sub i16 %E, %C
255   ret i16 %G
258 @Arr = external global [42 x i16]
260 define i64 @test24b(i8* %P, i64 %A){
261 ; CHECK-LABEL: @test24b(
262 ; CHECK-NEXT:    [[B_IDX:%.*]] = shl nsw i64 [[A:%.*]], 1
263 ; CHECK-NEXT:    ret i64 [[B_IDX]]
265   %B = getelementptr inbounds [42 x i16], [42 x i16]* @Arr, i64 0, i64 %A
266   %C = ptrtoint i16* %B to i64
267   %G = sub i64 %C, ptrtoint ([42 x i16]* @Arr to i64)
268   ret i64 %G
271 define i64 @test25(i8* %P, i64 %A){
272 ; CHECK-LABEL: @test25(
273 ; CHECK-NEXT:    [[B_IDX:%.*]] = shl nsw i64 [[A:%.*]], 1
274 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = add nsw i64 [[B_IDX]], -84
275 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
277   %B = getelementptr inbounds [42 x i16], [42 x i16]* @Arr, i64 0, i64 %A
278   %C = ptrtoint i16* %B to i64
279   %G = sub i64 %C, ptrtoint (i16* getelementptr ([42 x i16], [42 x i16]* @Arr, i64 1, i64 0) to i64)
280   ret i64 %G
283 @Arr_as1 = external addrspace(1) global [42 x i16]
285 define i16 @test25_as1(i8 addrspace(1)* %P, i64 %A) {
286 ; CHECK-LABEL: @test25_as1(
287 ; CHECK-NEXT:    [[TMP1:%.*]] = trunc i64 [[A:%.*]] to i16
288 ; CHECK-NEXT:    [[B_IDX:%.*]] = shl nsw i16 [[TMP1]], 1
289 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = add nsw i16 [[B_IDX]], -84
290 ; CHECK-NEXT:    ret i16 [[GEPDIFF]]
292   %B = getelementptr inbounds [42 x i16], [42 x i16] addrspace(1)* @Arr_as1, i64 0, i64 %A
293   %C = ptrtoint i16 addrspace(1)* %B to i16
294   %G = sub i16 %C, ptrtoint (i16 addrspace(1)* getelementptr ([42 x i16], [42 x i16] addrspace(1)* @Arr_as1, i64 1, i64 0) to i16)
295   ret i16 %G
298 define i64 @test30(i8* %foo, i64 %i, i64 %j) {
299 ; CHECK-LABEL: @test30(
300 ; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nsw i64 [[I:%.*]], 2
301 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = sub nsw i64 [[GEP1_IDX]], [[J:%.*]]
302 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
304   %bit = bitcast i8* %foo to i32*
305   %gep1 = getelementptr inbounds i32, i32* %bit, i64 %i
306   %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
307   %cast1 = ptrtoint i32* %gep1 to i64
308   %cast2 = ptrtoint i8* %gep2 to i64
309   %sub = sub i64 %cast1, %cast2
310   ret i64 %sub
313 define i16 @test30_as1(i8 addrspace(1)* %foo, i16 %i, i16 %j) {
314 ; CHECK-LABEL: @test30_as1(
315 ; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nsw i16 [[I:%.*]], 2
316 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = sub nsw i16 [[GEP1_IDX]], [[J:%.*]]
317 ; CHECK-NEXT:    ret i16 [[GEPDIFF]]
319   %bit = bitcast i8 addrspace(1)* %foo to i32 addrspace(1)*
320   %gep1 = getelementptr inbounds i32, i32 addrspace(1)* %bit, i16 %i
321   %gep2 = getelementptr inbounds i8, i8 addrspace(1)* %foo, i16 %j
322   %cast1 = ptrtoint i32 addrspace(1)* %gep1 to i16
323   %cast2 = ptrtoint i8 addrspace(1)* %gep2 to i16
324   %sub = sub i16 %cast1, %cast2
325   ret i16 %sub
328 ; Inbounds translates to 'nsw' on sub
330 define i64 @gep_diff_both_inbounds(i8* %foo, i64 %i, i64 %j) {
331 ; CHECK-LABEL: @gep_diff_both_inbounds(
332 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = sub nsw i64 [[I:%.*]], [[J:%.*]]
333 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
335   %gep1 = getelementptr inbounds i8, i8* %foo, i64 %i
336   %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
337   %cast1 = ptrtoint i8* %gep1 to i64
338   %cast2 = ptrtoint i8* %gep2 to i64
339   %sub = sub i64 %cast1, %cast2
340   ret i64 %sub
343 ; Negative test for 'nsw' - both geps must be inbounds
345 define i64 @gep_diff_first_inbounds(i8* %foo, i64 %i, i64 %j) {
346 ; CHECK-LABEL: @gep_diff_first_inbounds(
347 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = sub i64 [[I:%.*]], [[J:%.*]]
348 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
350   %gep1 = getelementptr inbounds i8, i8* %foo, i64 %i
351   %gep2 = getelementptr i8, i8* %foo, i64 %j
352   %cast1 = ptrtoint i8* %gep1 to i64
353   %cast2 = ptrtoint i8* %gep2 to i64
354   %sub = sub i64 %cast1, %cast2
355   ret i64 %sub
358 ; Negative test for 'nsw' - both geps must be inbounds
360 define i64 @gep_diff_second_inbounds(i8* %foo, i64 %i, i64 %j) {
361 ; CHECK-LABEL: @gep_diff_second_inbounds(
362 ; CHECK-NEXT:    [[GEPDIFF:%.*]] = sub i64 [[I:%.*]], [[J:%.*]]
363 ; CHECK-NEXT:    ret i64 [[GEPDIFF]]
365   %gep1 = getelementptr i8, i8* %foo, i64 %i
366   %gep2 = getelementptr inbounds i8, i8* %foo, i64 %j
367   %cast1 = ptrtoint i8* %gep1 to i64
368   %cast2 = ptrtoint i8* %gep2 to i64
369   %sub = sub i64 %cast1, %cast2
370   ret i64 %sub