xref: /llvm-project/llvm/test/Transforms/InstCombine/constant-fold-gep.ll (revision 10f315dc9c96ec2413881ab55a285e35d80def88)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes='require<loops>,instcombine' -S | FileCheck %s
3target datalayout = "E-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64"
4
5; Constant folding should fix notionally out-of-bounds indices
6; and add inbounds keywords.
7
8%struct.X = type { [3 x i32], [3 x i32] }
9
10@Y = internal global [3 x %struct.X] zeroinitializer
11
12define void @frob() {
13; CHECK-LABEL: @frob(
14; CHECK-NEXT:    store i32 1, ptr @Y, align 4
15; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 4), align 4
16; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 8), align 4
17; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 12), align 4
18; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 16), align 4
19; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 20), align 4
20; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 24), align 4
21; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 28), align 4
22; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 32), align 4
23; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 36), align 4
24; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 40), align 4
25; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 44), align 4
26; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 48), align 4
27; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 52), align 4
28; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 56), align 8
29; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 60), align 4
30; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 64), align 8
31; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 68), align 4
32; CHECK-NEXT:    store i32 1, ptr getelementptr inbounds nuw (i8, ptr @Y, i64 72), align 8
33; CHECK-NEXT:    store i32 1, ptr getelementptr (i8, ptr @Y, i64 144), align 8
34; CHECK-NEXT:    store i32 1, ptr getelementptr (i8, ptr @Y, i64 76), align 8
35; CHECK-NEXT:    ret void
36;
37  store i32 1, ptr @Y, align 4
38  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 1), align 4
39  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 2), align 4
40  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 3), align 4
41  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 4), align 4
42  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 5), align 4
43  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 6), align 4
44  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 7), align 4
45  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 8), align 4
46  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 9), align 4
47  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 10), align 4
48  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 11), align 4
49  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 12), align 4
50  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 13), align 4
51  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 14), align 8
52  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 15), align 4
53  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 16), align 8
54  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 17), align 4
55  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 18), align 8
56  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 36), align 8
57  store i32 1, ptr getelementptr ([3 x %struct.X], ptr @Y, i64 0, i64 0, i32 0, i64 19), align 8
58  ret void
59}
60
61
62; PR8883 - Constant fold exotic gep subtract
63@X = global [1000 x i8] zeroinitializer, align 16
64
65define i64 @test2() {
66; CHECK-LABEL: @test2(
67; CHECK-NEXT:  entry:
68; CHECK-NEXT:    ret i64 1000
69;
70entry:
71  %A = bitcast ptr getelementptr inbounds ([1000 x i8], ptr @X, i64 1, i64 0) to ptr
72
73  %B2 = ptrtoint ptr @X to i64
74  %C = sub i64 0, %B2
75  %D = getelementptr i8, ptr %A, i64 %C
76  %E = ptrtoint ptr %D to i64
77
78  ret i64 %E
79}
80
81@X_as1 = addrspace(1) global [1000 x i8] zeroinitializer, align 16
82
83define i16 @test2_as1() {
84; CHECK-LABEL: @test2_as1(
85; CHECK-NEXT:  entry:
86; CHECK-NEXT:    ret i16 1000
87;
88
89entry:
90  %A = bitcast ptr addrspace(1) getelementptr inbounds ([1000 x i8], ptr addrspace(1) @X_as1, i64 1, i64 0) to ptr addrspace(1)
91
92  %B2 = ptrtoint ptr addrspace(1) @X_as1 to i16
93  %C = sub i16 0, %B2
94  %D = getelementptr i8, ptr addrspace(1) %A, i16 %C
95  %E = ptrtoint ptr addrspace(1) %D to i16
96
97  ret i16 %E
98}
99
100@g = external global i8
101@g2 = external global i8
102
103declare i64 @get.i64()
104declare void @use.ptr(ptr)
105
106define ptr @gep_sub_self() {
107; CHECK-LABEL: @gep_sub_self(
108; CHECK-NEXT:    ret ptr getelementptr (i8, ptr @g, i64 sub (i64 0, i64 ptrtoint (ptr @g to i64)))
109;
110  %p.int = ptrtoint ptr @g to i64
111  %p.int.neg = sub i64 0, %p.int
112  %p1 = getelementptr i8, ptr @g, i64 %p.int.neg
113  ret ptr %p1
114}
115
116define ptr @gep_sub_self_plus_addr(i64 %addr) {
117; CHECK-LABEL: @gep_sub_self_plus_addr(
118; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr getelementptr (i8, ptr @g, i64 sub (i64 0, i64 ptrtoint (ptr @g to i64))), i64 [[ADDR:%.*]]
119; CHECK-NEXT:    ret ptr [[P2]]
120;
121  %p.int = ptrtoint ptr @g to i64
122  %p.int.neg = sub i64 0, %p.int
123  %p1 = getelementptr i8, ptr @g, i64 %p.int.neg
124  %p2 = getelementptr i8, ptr %p1, i64 %addr
125  ret ptr %p2
126}
127
128define ptr @gep_plus_addr_sub_self(i64 %addr) {
129; CHECK-LABEL: @gep_plus_addr_sub_self(
130; CHECK-NEXT:    [[P1:%.*]] = getelementptr i8, ptr @g, i64 [[ADDR:%.*]]
131; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P1]], i64 sub (i64 0, i64 ptrtoint (ptr @g to i64))
132; CHECK-NEXT:    ret ptr [[P2]]
133;
134  %p.int = ptrtoint ptr @g to i64
135  %p.int.neg = sub i64 0, %p.int
136  %p1 = getelementptr i8, ptr @g, i64 %addr
137  %p2 = getelementptr i8, ptr %p1, i64 %p.int.neg
138  ret ptr %p2
139}
140
141define ptr @gep_plus_addr_sub_self_in_loop() {
142; CHECK-LABEL: @gep_plus_addr_sub_self_in_loop(
143; CHECK-NEXT:    br label [[LOOP:%.*]]
144; CHECK:       loop:
145; CHECK-NEXT:    [[ADDR:%.*]] = call i64 @get.i64()
146; CHECK-NEXT:    [[P1:%.*]] = getelementptr i8, ptr @g, i64 [[ADDR]]
147; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P1]], i64 sub (i64 0, i64 ptrtoint (ptr @g to i64))
148; CHECK-NEXT:    call void @use.ptr(ptr [[P2]])
149; CHECK-NEXT:    br label [[LOOP]]
150;
151  %p.int = ptrtoint ptr @g to i64
152  %p.int.neg = sub i64 0, %p.int
153  br label %loop
154
155loop:
156  %addr = call i64 @get.i64()
157  %p1 = getelementptr i8, ptr @g, i64 %addr
158  %p2 = getelementptr i8, ptr %p1, i64 %p.int.neg
159  call void @use.ptr(ptr %p2)
160  br label %loop
161}
162
163define ptr @gep_sub_other() {
164; CHECK-LABEL: @gep_sub_other(
165; CHECK-NEXT:    ret ptr getelementptr (i8, ptr @g, i64 sub (i64 0, i64 ptrtoint (ptr @g2 to i64)))
166;
167  %p.int = ptrtoint ptr @g2 to i64
168  %p.int.neg = sub i64 0, %p.int
169  %p1 = getelementptr i8, ptr @g, i64 %p.int.neg
170  ret ptr %p1
171}
172
173define i64 @gep_sub_other_to_int() {
174; CHECK-LABEL: @gep_sub_other_to_int(
175; CHECK-NEXT:    ret i64 sub (i64 ptrtoint (ptr @g to i64), i64 ptrtoint (ptr @g2 to i64))
176;
177  %p.int = ptrtoint ptr @g2 to i64
178  %p.int.neg = sub i64 0, %p.int
179  %p1 = getelementptr i8, ptr @g, i64 %p.int.neg
180  %p1.int = ptrtoint ptr %p1 to i64
181  ret i64 %p1.int
182}
183