xref: /llvm-project/llvm/test/Transforms/StraightLineStrengthReduce/slsr-gep.ll (revision 9bc4355f091b530625ec6839a8c4858b6de4f1b4)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2; RUN: opt < %s -passes=slsr,gvn -S | FileCheck %s
3
4target datalayout = "e-i64:64-v16:16-v32:32-n16:32:64-p:64:64:64-p1:32:32:32-p2:128:128:128:32"
5
6; foo(input[0]);
7; foo(input[s]);
8; foo(input[s * 2]);
9;   =>
10; p0 = &input[0];
11; foo(*p);
12; p1 = p0 + s;
13; foo(*p1);
14; p2 = p1 + s;
15; foo(*p2);
16define void @slsr_gep(ptr %input, i64 %s) {
17; CHECK-LABEL: define void @slsr_gep(
18; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]]) {
19; CHECK-NEXT:    call void @foo(ptr [[INPUT]])
20; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i64 [[S]]
21; CHECK-NEXT:    call void @foo(ptr [[P1]])
22; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[S]], 2
23; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]]
24; CHECK-NEXT:    call void @foo(ptr [[P2]])
25; CHECK-NEXT:    ret void
26;
27  ; v0 = input[0];
28  call void @foo(ptr %input)
29
30  ; v1 = input[s];
31  %p1 = getelementptr inbounds i32, ptr %input, i64 %s
32  call void @foo(ptr %p1)
33
34  ; v2 = input[s * 2];
35  %s2 = shl nsw i64 %s, 1
36  %p2 = getelementptr inbounds i32, ptr %input, i64 %s2
37  call void @foo(ptr %p2)
38
39  ret void
40}
41
42; foo(input[0]);
43; foo(input[(long)s]);
44; foo(input[(long)(s * 2)]);
45;   =>
46; p0 = &input[0];
47; foo(*p);
48; p1 = p0 + (long)s;
49; foo(*p1);
50; p2 = p1 + (long)s;
51; foo(*p2);
52define void @slsr_gep_sext(ptr %input, i32 %s) {
53; CHECK-LABEL: define void @slsr_gep_sext(
54; CHECK-SAME: ptr [[INPUT:%.*]], i32 [[S:%.*]]) {
55; CHECK-NEXT:    call void @foo(ptr [[INPUT]])
56; CHECK-NEXT:    [[T:%.*]] = sext i32 [[S]] to i64
57; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i64 [[T]]
58; CHECK-NEXT:    call void @foo(ptr [[P1]])
59; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[T]], 2
60; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]]
61; CHECK-NEXT:    call void @foo(ptr [[P2]])
62; CHECK-NEXT:    ret void
63;
64  ; v0 = input[0];
65  call void @foo(ptr %input)
66
67  ; v1 = input[s];
68  %t = sext i32 %s to i64
69  %p1 = getelementptr inbounds i32, ptr %input, i64 %t
70  call void @foo(ptr %p1)
71
72  ; v2 = input[s * 2];
73  %s2 = shl nsw i32 %s, 1
74  %t2 = sext i32 %s2 to i64
75  %p2 = getelementptr inbounds i32, ptr %input, i64 %t2
76  call void @foo(ptr %p2)
77
78  ret void
79}
80
81; int input[10][5];
82; foo(input[s][t]);
83; foo(input[s * 2][t]);
84; foo(input[s * 3][t]);
85;   =>
86; p0 = &input[s][t];
87; foo(*p0);
88; p1 = p0 + 5s;
89; foo(*p1);
90; p2 = p1 + 5s;
91; foo(*p2);
92define void @slsr_gep_2d(ptr %input, i64 %s, i64 %t) {
93; CHECK-LABEL: define void @slsr_gep_2d(
94; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]], i64 [[T:%.*]]) {
95; CHECK-NEXT:    [[P0:%.*]] = getelementptr inbounds [10 x [5 x i32]], ptr [[INPUT]], i64 0, i64 [[S]], i64 [[T]]
96; CHECK-NEXT:    call void @foo(ptr [[P0]])
97; CHECK-NEXT:    [[TMP1:%.*]] = mul i64 [[S]], 20
98; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i8, ptr [[P0]], i64 [[TMP1]]
99; CHECK-NEXT:    call void @foo(ptr [[P1]])
100; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]]
101; CHECK-NEXT:    call void @foo(ptr [[P2]])
102; CHECK-NEXT:    ret void
103;
104  ; v0 = input[s][t];
105  %p0 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s, i64 %t
106  call void @foo(ptr %p0)
107
108  ; v1 = input[s * 2][t];
109  %s2 = shl nsw i64 %s, 1
110  %p1 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s2, i64 %t
111  call void @foo(ptr %p1)
112
113  ; v3 = input[s * 3][t];
114  %s3 = mul nsw i64 %s, 3
115  %p2 = getelementptr inbounds [10 x [5 x i32]], ptr %input, i64 0, i64 %s3, i64 %t
116  call void @foo(ptr %p2)
117
118  ret void
119}
120
121%struct.S = type <{ i64, i32 }>
122
123; In this case, the bump
124;     = (char *)&input[s * 2][t].f1 - (char *)&input[s][t].f1
125;     = 60 * s
126; which may not be divisible by typeof(input[s][t].f1) = 8. Therefore, we
127; rewrite the candidates using byte offset instead of index offset as in
128; @slsr_gep_2d.
129define void @slsr_gep_uglygep(ptr %input, i64 %s, i64 %t) {
130; CHECK-LABEL: define void @slsr_gep_uglygep(
131; CHECK-SAME: ptr [[INPUT:%.*]], i64 [[S:%.*]], i64 [[T:%.*]]) {
132; CHECK-NEXT:    [[P0:%.*]] = getelementptr inbounds [10 x [5 x %struct.S]], ptr [[INPUT]], i64 0, i64 [[S]], i64 [[T]], i32 0
133; CHECK-NEXT:    call void @bar(ptr [[P0]])
134; CHECK-NEXT:    [[TMP1:%.*]] = mul i64 [[S]], 60
135; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i8, ptr [[P0]], i64 [[TMP1]]
136; CHECK-NEXT:    call void @bar(ptr [[P1]])
137; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i8, ptr [[P1]], i64 [[TMP1]]
138; CHECK-NEXT:    call void @bar(ptr [[P2]])
139; CHECK-NEXT:    ret void
140;
141  ; v0 = input[s][t].f1;
142  %p0 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s, i64 %t, i32 0
143  call void @bar(ptr %p0)
144
145  ; v1 = input[s * 2][t].f1;
146  %s2 = shl nsw i64 %s, 1
147  %p1 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s2, i64 %t, i32 0
148  call void @bar(ptr %p1)
149
150  ; v2 = input[s * 3][t].f1;
151  %s3 = mul nsw i64 %s, 3
152  %p2 = getelementptr inbounds [10 x [5 x %struct.S]], ptr %input, i64 0, i64 %s3, i64 %t, i32 0
153  call void @bar(ptr %p2)
154
155  ret void
156}
157
158define void @slsr_out_of_bounds_gep(ptr %input, i32 %s) {
159; CHECK-LABEL: define void @slsr_out_of_bounds_gep(
160; CHECK-SAME: ptr [[INPUT:%.*]], i32 [[S:%.*]]) {
161; CHECK-NEXT:    call void @foo(ptr [[INPUT]])
162; CHECK-NEXT:    [[T:%.*]] = sext i32 [[S]] to i64
163; CHECK-NEXT:    [[P1:%.*]] = getelementptr i32, ptr [[INPUT]], i64 [[T]]
164; CHECK-NEXT:    call void @foo(ptr [[P1]])
165; CHECK-NEXT:    [[TMP1:%.*]] = shl i64 [[T]], 2
166; CHECK-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P1]], i64 [[TMP1]]
167; CHECK-NEXT:    call void @foo(ptr [[P2]])
168; CHECK-NEXT:    ret void
169;
170  ; v0 = input[0];
171  call void @foo(ptr %input)
172
173  ; v1 = input[(long)s];
174  %t = sext i32 %s to i64
175  %p1 = getelementptr i32, ptr %input, i64 %t
176  call void @foo(ptr %p1)
177
178  ; v2 = input[(long)(s * 2)];
179  %s2 = shl nsw i32 %s, 1
180  %t2 = sext i32 %s2 to i64
181  %p2 = getelementptr i32, ptr %input, i64 %t2
182  call void @foo(ptr %p2)
183
184  ret void
185}
186
187define void @slsr_gep_128bit_index(ptr %input, i128 %s) {
188; CHECK-LABEL: define void @slsr_gep_128bit_index(
189; CHECK-SAME: ptr [[INPUT:%.*]], i128 [[S:%.*]]) {
190; CHECK-NEXT:    call void @foo(ptr [[INPUT]])
191; CHECK-NEXT:    [[S125:%.*]] = shl nsw i128 [[S]], 125
192; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i128 [[S125]]
193; CHECK-NEXT:    call void @foo(ptr [[P1]])
194; CHECK-NEXT:    [[S126:%.*]] = shl nsw i128 [[S]], 126
195; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i32, ptr [[INPUT]], i128 [[S126]]
196; CHECK-NEXT:    call void @foo(ptr [[P2]])
197; CHECK-NEXT:    ret void
198;
199  ; p0 = &input[0]
200  call void @foo(ptr %input)
201
202  ; p1 = &input[s << 125]
203  %s125 = shl nsw i128 %s, 125
204  %p1 = getelementptr inbounds i32, ptr %input, i128 %s125
205  call void @foo(ptr %p1)
206
207  ; p2 = &input[s << 126]
208  %s126 = shl nsw i128 %s, 126
209  %p2 = getelementptr inbounds i32, ptr %input, i128 %s126
210  call void @foo(ptr %p2)
211
212  ret void
213}
214
215define void @slsr_gep_32bit_pointer(ptr addrspace(1) %input, i64 %s) {
216; CHECK-LABEL: define void @slsr_gep_32bit_pointer(
217; CHECK-SAME: ptr addrspace(1) [[INPUT:%.*]], i64 [[S:%.*]]) {
218; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i32, ptr addrspace(1) [[INPUT]], i64 [[S]]
219; CHECK-NEXT:    call void @baz(ptr addrspace(1) [[P1]])
220; CHECK-NEXT:    [[S2:%.*]] = mul nsw i64 [[S]], 2
221; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i32, ptr addrspace(1) [[INPUT]], i64 [[S2]]
222; CHECK-NEXT:    call void @baz(ptr addrspace(1) [[P2]])
223; CHECK-NEXT:    ret void
224;
225  ; p1 = &input[s]
226  %p1 = getelementptr inbounds i32, ptr addrspace(1) %input, i64 %s
227  call void @baz(ptr addrspace(1) %p1)
228
229  ; p2 = &input[s * 2]
230  %s2 = mul nsw i64 %s, 2
231  %p2 = getelementptr inbounds i32, ptr addrspace(1) %input, i64 %s2
232  ; %s2 is wider than the pointer size of addrspace(1), so do not factor it.
233  call void @baz(ptr addrspace(1) %p2)
234
235  ret void
236}
237
238define void @slsr_gep_fat_pointer(ptr addrspace(2) %input, i32 %s) {
239  ; p1 = &input[s]
240; CHECK-LABEL: define void @slsr_gep_fat_pointer(
241; CHECK-SAME: ptr addrspace(2) [[INPUT:%.*]], i32 [[S:%.*]]) {
242; CHECK-NEXT:    [[P1:%.*]] = getelementptr inbounds i32, ptr addrspace(2) [[INPUT]], i32 [[S]]
243; CHECK-NEXT:    call void @baz2(ptr addrspace(2) [[P1]])
244; CHECK-NEXT:    [[TMP1:%.*]] = shl i32 [[S]], 2
245; CHECK-NEXT:    [[P2:%.*]] = getelementptr inbounds i8, ptr addrspace(2) [[P1]], i32 [[TMP1]]
246; CHECK-NEXT:    call void @baz2(ptr addrspace(2) [[P2]])
247; CHECK-NEXT:    ret void
248;
249  %p1 = getelementptr inbounds i32, ptr addrspace(2) %input, i32 %s
250  call void @baz2(ptr addrspace(2) %p1)
251
252  ; p2 = &input[s * 2]
253  %s2 = mul nsw i32 %s, 2
254  %p2 = getelementptr inbounds i32, ptr addrspace(2) %input, i32 %s2
255  ; Use index bitwidth, not pointer size (i128)
256  call void @baz2(ptr addrspace(2) %p2)
257
258  ret void
259}
260
261
262declare void @foo(ptr)
263declare void @bar(ptr)
264declare void @baz(ptr addrspace(1))
265declare void @baz2(ptr addrspace(2))
266