xref: /llvm-project/llvm/test/Transforms/SeparateConstOffsetFromGEP/RISCV/split-gep.ll (revision 9e5a77f252badfc932d1e28ee998746072ddc33f)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -mtriple=riscv64-unknown-elf -passes='separate-const-offset-from-gep,early-cse' \
3; RUN:       -S | FileCheck %s
4
5; Several tests for separate-const-offset-from-gep. The transformation
6; heavily relies on TargetTransformInfo, so we put these tests under
7; target-specific folders.
8
9; Simple case when GEPs should be optimized.
10define i64 @test1(ptr %array, i64 %i, i64 %j)  {
11; CHECK-LABEL: @test1(
12; CHECK-NEXT:  entry:
13; CHECK-NEXT:    [[ADD:%.*]] = add nsw i64 [[I:%.*]], 5
14; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr i64, ptr [[ARRAY:%.*]], i64 [[I]]
15; CHECK-NEXT:    [[GEP4:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 40
16; CHECK-NEXT:    store i64 [[J:%.*]], ptr [[GEP4]], align 8
17; CHECK-NEXT:    [[GEP26:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 48
18; CHECK-NEXT:    store i64 [[J]], ptr [[GEP26]], align 8
19; CHECK-NEXT:    [[GEP38:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 280
20; CHECK-NEXT:    store i64 [[ADD]], ptr [[GEP38]], align 8
21; CHECK-NEXT:    ret i64 undef
22;
23entry:
24  %add = add nsw i64 %i, 5
25  %gep = getelementptr inbounds i64, ptr %array, i64 %add
26  store i64 %j, ptr %gep
27  %add2 = add nsw i64 %i, 6
28  %gep2 = getelementptr inbounds i64, ptr %array, i64 %add2
29  store i64 %j, ptr %gep2
30  %add3 = add nsw i64 %i, 35
31  %gep3 = getelementptr inbounds i64, ptr %array, i64 %add3
32  store i64 %add, ptr %gep3
33  ret i64 undef
34}
35
36; Optimize GEPs when there sext instructions are needed to cast index value to expected type.
37define i32 @test2(ptr %array, i32 %i, i32 %j) {
38; CHECK-LABEL: @test2(
39; CHECK-NEXT:  entry:
40; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
41; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
42; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]]
43; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20
44; CHECK-NEXT:    store i32 [[J:%.*]], ptr [[GEP2]], align 4
45; CHECK-NEXT:    [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 24
46; CHECK-NEXT:    store i32 [[J]], ptr [[GEP54]], align 4
47; CHECK-NEXT:    [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 140
48; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP86]], align 4
49; CHECK-NEXT:    ret i32 undef
50;
51entry:
52  %add = add nsw i32 %i, 5
53  %sext = sext i32 %add to i64
54  %gep = getelementptr inbounds i32, ptr %array, i64 %sext
55  store i32 %j, ptr %gep
56  %add3 = add nsw i32 %i, 6
57  %sext4 = sext i32 %add3 to i64
58  %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4
59  store i32 %j, ptr %gep5
60  %add6 = add nsw i32 %i, 35
61  %sext7 = sext i32 %add6 to i64
62  %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7
63  store i32 %add, ptr %gep8
64  ret i32 undef
65}
66
67; No need to modify because all values are also used in other expressions.
68; Modification doesn't decrease register pressure.
69define i32 @test3(ptr %array, i32 %i) {
70; CHECK-LABEL: @test3(
71; CHECK-NEXT:  entry:
72; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
73; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
74; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]]
75; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20
76; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP2]], align 4
77; CHECK-NEXT:    [[ADD3:%.*]] = add nsw i32 [[I]], 6
78; CHECK-NEXT:    [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 24
79; CHECK-NEXT:    store i32 [[ADD3]], ptr [[GEP54]], align 4
80; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[I]], 35
81; CHECK-NEXT:    [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 140
82; CHECK-NEXT:    store i32 [[ADD6]], ptr [[GEP86]], align 4
83; CHECK-NEXT:    ret i32 undef
84;
85entry:
86  %add = add nsw i32 %i, 5
87  %sext = sext i32 %add to i64
88  %gep = getelementptr inbounds i32, ptr %array, i64 %sext
89  store i32 %add, ptr %gep
90  %add3 = add nsw i32 %i, 6
91  %sext4 = sext i32 %add3 to i64
92  %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4
93  store i32 %add3, ptr %gep5
94  %add6 = add nsw i32 %i, 35
95  %sext7 = sext i32 %add6 to i64
96  %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7
97  store i32 %add6, ptr %gep8
98  ret i32 undef
99}
100
101; Optimized GEPs for multidimensional array with same base
102define i32 @test4(ptr %array2, i32 %i) {
103; CHECK-LABEL: @test4(
104; CHECK-NEXT:  entry:
105; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
106; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
107; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2:%.*]], i64 [[TMP0]], i64 [[TMP0]]
108; CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1020
109; CHECK-NEXT:    store i32 [[I]], ptr [[GEP3]], align 4
110; CHECK-NEXT:    [[GEP56:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1024
111; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP56]], align 4
112; CHECK-NEXT:    [[GEP89:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1140
113; CHECK-NEXT:    store i32 [[I]], ptr [[GEP89]], align 4
114; CHECK-NEXT:    ret i32 undef
115;
116entry:
117  %add = add nsw i32 %i, 5
118  %sext = sext i32 %add to i64
119  %gep = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext
120  store i32 %i, ptr %gep
121  %add3 = add nsw i32 %i, 6
122  %sext4 = sext i32 %add3 to i64
123  %gep5 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext4
124  store i32 %add, ptr %gep5
125  %add6 = add nsw i32 %i, 35
126  %sext7 = sext i32 %add6 to i64
127  %gep8 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext7
128  store i32 %i, ptr %gep8
129  ret i32 undef
130}
131
132; Don't optimize GEPs for multidimensional array with same base because RISC-V doesn't support the addressing mode
133define i32 @test5(ptr %array2, i32 %i, i64 %j) {
134; CHECK-LABEL: @test5(
135; CHECK-NEXT:  entry:
136; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
137; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
138; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2:%.*]], i64 [[TMP0]], i64 [[TMP0]]
139; CHECK-NEXT:    [[GEP3:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1020
140; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP3]], align 4
141; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr [50 x i32], ptr [[ARRAY2]], i64 [[TMP0]], i64 [[J:%.*]]
142; CHECK-NEXT:    [[GEP55:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 1200
143; CHECK-NEXT:    store i32 [[I]], ptr [[GEP55]], align 4
144; CHECK-NEXT:    [[ADD6:%.*]] = add nsw i32 [[I]], 35
145; CHECK-NEXT:    [[SEXT7:%.*]] = sext i32 [[ADD6]] to i64
146; CHECK-NEXT:    [[GEP8:%.*]] = getelementptr inbounds [50 x i32], ptr [[ARRAY2]], i64 [[SEXT7]], i64 [[J]]
147; CHECK-NEXT:    store i32 [[I]], ptr [[GEP8]], align 4
148; CHECK-NEXT:    ret i32 undef
149;
150entry:
151  %add = add nsw i32 %i, 5
152  %sext = sext i32 %add to i64
153  %gep = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext, i64 %sext
154  store i32 %add, ptr %gep
155  %add3 = add nsw i32 %i, 6
156  %sext4 = sext i32 %add3 to i64
157  %gep5 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext4, i64 %j
158  store i32 %i, ptr %gep5
159  %add6 = add nsw i32 %i, 35
160  %sext7 = sext i32 %add6 to i64
161  %gep8 = getelementptr inbounds [50 x i32], ptr %array2, i64 %sext7, i64 %j
162  store i32 %i, ptr %gep8
163  ret i32 undef
164}
165
166; No need to optimize GEPs, because there is critical amount with non-constant offsets.
167define i64 @test6(ptr %array, i64 %i, i64 %j) {
168; CHECK-LABEL: @test6(
169; CHECK-NEXT:  entry:
170; CHECK-NEXT:    [[ADD:%.*]] = add nsw i64 [[I:%.*]], 5
171; CHECK-NEXT:    [[GEP:%.*]] = getelementptr inbounds i64, ptr [[ARRAY:%.*]], i64 [[J:%.*]]
172; CHECK-NEXT:    store i64 [[ADD]], ptr [[GEP]], align 8
173; CHECK-NEXT:    [[TMP0:%.*]] = getelementptr i64, ptr [[ARRAY]], i64 [[I]]
174; CHECK-NEXT:    [[GEP52:%.*]] = getelementptr inbounds i8, ptr [[TMP0]], i64 48
175; CHECK-NEXT:    store i64 [[I]], ptr [[GEP52]], align 8
176; CHECK-NEXT:    store i64 [[I]], ptr [[TMP0]], align 8
177; CHECK-NEXT:    ret i64 undef
178;
179entry:
180  %add = add nsw i64 %i, 5
181  %gep = getelementptr inbounds i64, ptr %array, i64 %j
182  store i64 %add, ptr %gep
183  %add3 = add nsw i64 %i, 6
184  %gep5 = getelementptr inbounds i64, ptr %array, i64 %add3
185  store i64 %i, ptr %gep5
186  %add6 = add nsw i64 %i, 35
187  %gep8 = getelementptr inbounds i64, ptr %array, i64 %i
188  store i64 %i, ptr %gep8
189  ret i64 undef
190}
191
192; No need to optimize GEPs, because the base variable is different.
193define i32 @test7(ptr %array, i32 %i, i32 %j, i32 %k) {
194; CHECK-LABEL: @test7(
195; CHECK-NEXT:  entry:
196; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
197; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
198; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]]
199; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20
200; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP2]], align 4
201; CHECK-NEXT:    [[TMP2:%.*]] = sext i32 [[K:%.*]] to i64
202; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY]], i64 [[TMP2]]
203; CHECK-NEXT:    [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 24
204; CHECK-NEXT:    store i32 [[I]], ptr [[GEP54]], align 4
205; CHECK-NEXT:    [[TMP4:%.*]] = sext i32 [[J:%.*]] to i64
206; CHECK-NEXT:    [[TMP5:%.*]] = getelementptr i32, ptr [[ARRAY]], i64 [[TMP4]]
207; CHECK-NEXT:    [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP5]], i64 140
208; CHECK-NEXT:    store i32 [[I]], ptr [[GEP86]], align 4
209; CHECK-NEXT:    ret i32 undef
210;
211entry:
212  %add = add nsw i32 %i, 5
213  %sext = sext i32 %add to i64
214  %gep = getelementptr inbounds i32, ptr %array, i64 %sext
215  store i32 %add, ptr %gep
216  %add3 = add nsw i32 %k, 6
217  %sext4 = sext i32 %add3 to i64
218  %gep5 = getelementptr inbounds i32, ptr %array, i64 %sext4
219  store i32 %i, ptr %gep5
220  %add6 = add nsw i32 %j, 35
221  %sext7 = sext i32 %add6 to i64
222  %gep8 = getelementptr inbounds i32, ptr %array, i64 %sext7
223  store i32 %i, ptr %gep8
224  ret i32 undef
225}
226
227; No need to optimize GEPs, because the base of GEP instructions is different.
228define i32 @test8(ptr %array, ptr %array2, ptr %array3, i32 %i) {
229; CHECK-LABEL: @test8(
230; CHECK-NEXT:  entry:
231; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
232; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
233; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY:%.*]], i64 [[TMP0]]
234; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20
235; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP2]], align 4
236; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr i32, ptr [[ARRAY2:%.*]], i64 [[TMP0]]
237; CHECK-NEXT:    [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 24
238; CHECK-NEXT:    store i32 [[I]], ptr [[GEP54]], align 4
239; CHECK-NEXT:    [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY3:%.*]], i64 [[TMP0]]
240; CHECK-NEXT:    [[GEP86:%.*]] = getelementptr inbounds i8, ptr [[TMP3]], i64 140
241; CHECK-NEXT:    store i32 [[I]], ptr [[GEP86]], align 4
242; CHECK-NEXT:    ret i32 undef
243;
244entry:
245  %add = add nsw i32 %i, 5
246  %sext = sext i32 %add to i64
247  %gep = getelementptr inbounds i32, ptr %array, i64 %sext
248  store i32 %add, ptr %gep
249  %add3 = add nsw i32 %i, 6
250  %sext4 = sext i32 %add3 to i64
251  %gep5 = getelementptr inbounds i32, ptr %array2, i64 %sext4
252  store i32 %i, ptr %gep5
253  %add6 = add nsw i32 %i, 35
254  %sext7 = sext i32 %add6 to i64
255  %gep8 = getelementptr inbounds i32, ptr %array3, i64 %sext7
256  store i32 %i, ptr %gep8
257  ret i32 undef
258}
259
260; No need to optimize GEPs of multidimensional array, because the base of GEP instructions is different.
261define i32 @test9(ptr %array, i32 %i) {
262; CHECK-LABEL: @test9(
263; CHECK-NEXT:  entry:
264; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[I:%.*]], 5
265; CHECK-NEXT:    [[TMP0:%.*]] = sext i32 [[I]] to i64
266; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr [50 x i32], ptr [[ARRAY:%.*]], i64 0, i64 [[TMP0]]
267; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 20
268; CHECK-NEXT:    store i32 [[ADD]], ptr [[GEP2]], align 4
269; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr [50 x i32], ptr [[ARRAY]], i64 [[TMP0]], i64 [[TMP0]]
270; CHECK-NEXT:    [[GEP54:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 24
271; CHECK-NEXT:    store i32 [[I]], ptr [[GEP54]], align 4
272; CHECK-NEXT:    [[GEP87:%.*]] = getelementptr inbounds i8, ptr [[TMP2]], i64 1340
273; CHECK-NEXT:    store i32 [[I]], ptr [[GEP87]], align 4
274; CHECK-NEXT:    ret i32 undef
275;
276entry:
277  %add = add nsw i32 %i, 5
278  %sext = sext i32 %add to i64
279  %gep = getelementptr inbounds [50 x i32], ptr %array, i64 0, i64 %sext
280  store i32 %add, ptr %gep
281  %add3 = add nsw i32 %i, 6
282  %sext4 = sext i32 %add3 to i64
283  %int = sext i32 %i to i64
284  %gep5 = getelementptr inbounds [50 x i32], ptr %array, i64 %int, i64 %sext4
285  store i32 %i, ptr %gep5
286  %add6 = add nsw i32 %i, 35
287  %sext7 = sext i32 %add6 to i64
288  %gep8 = getelementptr inbounds [50 x i32], ptr %array, i64 %sext4, i64 %sext7
289  store i32 %i, ptr %gep8
290  ret i32 undef
291}
292