Revert rGe6ccb57bb3f6b761f2310e97fd6ca99eff42f73e "[SLP] Add cost model for `llvm...
[llvm-project.git] / llvm / test / CodeGen / RISCV / mem64.ll
blob10255f4f7f0c0243be70d3919b7b7e1985078832
1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
3 ; RUN:   | FileCheck -check-prefix=RV64I %s
5 ; Check indexed and unindexed, sext, zext and anyext loads
7 define dso_local i64 @lb(i8 *%a) nounwind {
8 ; RV64I-LABEL: lb:
9 ; RV64I:       # %bb.0:
10 ; RV64I-NEXT:    lb a1, 1(a0)
11 ; RV64I-NEXT:    lb a0, 0(a0)
12 ; RV64I-NEXT:    mv a0, a1
13 ; RV64I-NEXT:    ret
14   %1 = getelementptr i8, i8* %a, i32 1
15   %2 = load i8, i8* %1
16   %3 = sext i8 %2 to i64
17   ; the unused load will produce an anyext for selection
18   %4 = load volatile i8, i8* %a
19   ret i64 %3
22 define dso_local i64 @lh(i16 *%a) nounwind {
23 ; RV64I-LABEL: lh:
24 ; RV64I:       # %bb.0:
25 ; RV64I-NEXT:    lh a1, 4(a0)
26 ; RV64I-NEXT:    lh a0, 0(a0)
27 ; RV64I-NEXT:    mv a0, a1
28 ; RV64I-NEXT:    ret
29   %1 = getelementptr i16, i16* %a, i32 2
30   %2 = load i16, i16* %1
31   %3 = sext i16 %2 to i64
32   ; the unused load will produce an anyext for selection
33   %4 = load volatile i16, i16* %a
34   ret i64 %3
37 define dso_local i64 @lw(i32 *%a) nounwind {
38 ; RV64I-LABEL: lw:
39 ; RV64I:       # %bb.0:
40 ; RV64I-NEXT:    lw a1, 12(a0)
41 ; RV64I-NEXT:    lw a0, 0(a0)
42 ; RV64I-NEXT:    mv a0, a1
43 ; RV64I-NEXT:    ret
44   %1 = getelementptr i32, i32* %a, i32 3
45   %2 = load i32, i32* %1
46   %3 = sext i32 %2 to i64
47   ; the unused load will produce an anyext for selection
48   %4 = load volatile i32, i32* %a
49   ret i64 %3
52 define dso_local i64 @lbu(i8 *%a) nounwind {
53 ; RV64I-LABEL: lbu:
54 ; RV64I:       # %bb.0:
55 ; RV64I-NEXT:    lbu a1, 4(a0)
56 ; RV64I-NEXT:    lbu a0, 0(a0)
57 ; RV64I-NEXT:    add a0, a1, a0
58 ; RV64I-NEXT:    ret
59   %1 = getelementptr i8, i8* %a, i32 4
60   %2 = load i8, i8* %1
61   %3 = zext i8 %2 to i64
62   %4 = load volatile i8, i8* %a
63   %5 = zext i8 %4 to i64
64   %6 = add i64 %3, %5
65   ret i64 %6
68 define dso_local i64 @lhu(i16 *%a) nounwind {
69 ; RV64I-LABEL: lhu:
70 ; RV64I:       # %bb.0:
71 ; RV64I-NEXT:    lhu a1, 10(a0)
72 ; RV64I-NEXT:    lhu a0, 0(a0)
73 ; RV64I-NEXT:    add a0, a1, a0
74 ; RV64I-NEXT:    ret
75   %1 = getelementptr i16, i16* %a, i32 5
76   %2 = load i16, i16* %1
77   %3 = zext i16 %2 to i64
78   %4 = load volatile i16, i16* %a
79   %5 = zext i16 %4 to i64
80   %6 = add i64 %3, %5
81   ret i64 %6
84 define dso_local i64 @lwu(i32 *%a) nounwind {
85 ; RV64I-LABEL: lwu:
86 ; RV64I:       # %bb.0:
87 ; RV64I-NEXT:    lwu a1, 24(a0)
88 ; RV64I-NEXT:    lwu a0, 0(a0)
89 ; RV64I-NEXT:    add a0, a1, a0
90 ; RV64I-NEXT:    ret
91   %1 = getelementptr i32, i32* %a, i32 6
92   %2 = load i32, i32* %1
93   %3 = zext i32 %2 to i64
94   %4 = load volatile i32, i32* %a
95   %5 = zext i32 %4 to i64
96   %6 = add i64 %3, %5
97   ret i64 %6
100 ; Check indexed and unindexed stores
102 define dso_local void @sb(i8 *%a, i8 %b) nounwind {
103 ; RV64I-LABEL: sb:
104 ; RV64I:       # %bb.0:
105 ; RV64I-NEXT:    sb a1, 0(a0)
106 ; RV64I-NEXT:    sb a1, 7(a0)
107 ; RV64I-NEXT:    ret
108   store i8 %b, i8* %a
109   %1 = getelementptr i8, i8* %a, i32 7
110   store i8 %b, i8* %1
111   ret void
114 define dso_local void @sh(i16 *%a, i16 %b) nounwind {
115 ; RV64I-LABEL: sh:
116 ; RV64I:       # %bb.0:
117 ; RV64I-NEXT:    sh a1, 0(a0)
118 ; RV64I-NEXT:    sh a1, 16(a0)
119 ; RV64I-NEXT:    ret
120   store i16 %b, i16* %a
121   %1 = getelementptr i16, i16* %a, i32 8
122   store i16 %b, i16* %1
123   ret void
126 define dso_local void @sw(i32 *%a, i32 %b) nounwind {
127 ; RV64I-LABEL: sw:
128 ; RV64I:       # %bb.0:
129 ; RV64I-NEXT:    sw a1, 0(a0)
130 ; RV64I-NEXT:    sw a1, 36(a0)
131 ; RV64I-NEXT:    ret
132   store i32 %b, i32* %a
133   %1 = getelementptr i32, i32* %a, i32 9
134   store i32 %b, i32* %1
135   ret void
138 ; 64-bit loads and stores
140 define dso_local i64 @ld(i64 *%a) nounwind {
141 ; RV64I-LABEL: ld:
142 ; RV64I:       # %bb.0:
143 ; RV64I-NEXT:    ld a1, 80(a0)
144 ; RV64I-NEXT:    ld a0, 0(a0)
145 ; RV64I-NEXT:    mv a0, a1
146 ; RV64I-NEXT:    ret
147   %1 = getelementptr i64, i64* %a, i32 10
148   %2 = load i64, i64* %1
149   %3 = load volatile i64, i64* %a
150   ret i64 %2
153 define dso_local void @sd(i64 *%a, i64 %b) nounwind {
154 ; RV64I-LABEL: sd:
155 ; RV64I:       # %bb.0:
156 ; RV64I-NEXT:    sd a1, 0(a0)
157 ; RV64I-NEXT:    sd a1, 88(a0)
158 ; RV64I-NEXT:    ret
159   store i64 %b, i64* %a
160   %1 = getelementptr i64, i64* %a, i32 11
161   store i64 %b, i64* %1
162   ret void
165 ; Check load and store to an i1 location
166 define dso_local i64 @load_sext_zext_anyext_i1(i1 *%a) nounwind {
167 ; RV64I-LABEL: load_sext_zext_anyext_i1:
168 ; RV64I:       # %bb.0:
169 ; RV64I-NEXT:    lbu a1, 1(a0)
170 ; RV64I-NEXT:    lbu a2, 2(a0)
171 ; RV64I-NEXT:    lb a0, 0(a0)
172 ; RV64I-NEXT:    sub a0, a2, a1
173 ; RV64I-NEXT:    ret
174   ; sextload i1
175   %1 = getelementptr i1, i1* %a, i32 1
176   %2 = load i1, i1* %1
177   %3 = sext i1 %2 to i64
178   ; zextload i1
179   %4 = getelementptr i1, i1* %a, i32 2
180   %5 = load i1, i1* %4
181   %6 = zext i1 %5 to i64
182   %7 = add i64 %3, %6
183   ; extload i1 (anyext). Produced as the load is unused.
184   %8 = load volatile i1, i1* %a
185   ret i64 %7
188 define dso_local i16 @load_sext_zext_anyext_i1_i16(i1 *%a) nounwind {
189 ; RV64I-LABEL: load_sext_zext_anyext_i1_i16:
190 ; RV64I:       # %bb.0:
191 ; RV64I-NEXT:    lbu a1, 1(a0)
192 ; RV64I-NEXT:    lbu a2, 2(a0)
193 ; RV64I-NEXT:    lb a0, 0(a0)
194 ; RV64I-NEXT:    sub a0, a2, a1
195 ; RV64I-NEXT:    ret
196   ; sextload i1
197   %1 = getelementptr i1, i1* %a, i32 1
198   %2 = load i1, i1* %1
199   %3 = sext i1 %2 to i16
200   ; zextload i1
201   %4 = getelementptr i1, i1* %a, i32 2
202   %5 = load i1, i1* %4
203   %6 = zext i1 %5 to i16
204   %7 = add i16 %3, %6
205   ; extload i1 (anyext). Produced as the load is unused.
206   %8 = load volatile i1, i1* %a
207   ret i16 %7
210 ; Check load and store to a global
211 @G = dso_local global i64 0
213 define dso_local i64 @ld_sd_global(i64 %a) nounwind {
214 ; RV64I-LABEL: ld_sd_global:
215 ; RV64I:       # %bb.0:
216 ; RV64I-NEXT:    lui a2, %hi(G)
217 ; RV64I-NEXT:    ld a1, %lo(G)(a2)
218 ; RV64I-NEXT:    addi a3, a2, %lo(G)
219 ; RV64I-NEXT:    sd a0, %lo(G)(a2)
220 ; RV64I-NEXT:    ld a2, 72(a3)
221 ; RV64I-NEXT:    sd a0, 72(a3)
222 ; RV64I-NEXT:    mv a0, a1
223 ; RV64I-NEXT:    ret
224   %1 = load volatile i64, i64* @G
225   store i64 %a, i64* @G
226   %2 = getelementptr i64, i64* @G, i64 9
227   %3 = load volatile i64, i64* %2
228   store i64 %a, i64* %2
229   ret i64 %1
232 define i64 @lw_far_local(i64* %a)  {
233 ; RV64I-LABEL: lw_far_local:
234 ; RV64I:       # %bb.0:
235 ; RV64I-NEXT:    lui a1, 8
236 ; RV64I-NEXT:    add a0, a0, a1
237 ; RV64I-NEXT:    ld a0, -8(a0)
238 ; RV64I-NEXT:    ret
239   %1 = getelementptr inbounds i64, i64* %a, i64 4095
240   %2 = load volatile i64, i64* %1
241   ret i64 %2
244 define void @st_far_local(i64* %a, i64 %b)  {
245 ; RV64I-LABEL: st_far_local:
246 ; RV64I:       # %bb.0:
247 ; RV64I-NEXT:    lui a2, 8
248 ; RV64I-NEXT:    add a0, a0, a2
249 ; RV64I-NEXT:    sd a1, -8(a0)
250 ; RV64I-NEXT:    ret
251   %1 = getelementptr inbounds i64, i64* %a, i64 4095
252   store i64 %b, i64* %1
253   ret void
256 define i64 @lw_sw_far_local(i64* %a, i64 %b)  {
257 ; RV64I-LABEL: lw_sw_far_local:
258 ; RV64I:       # %bb.0:
259 ; RV64I-NEXT:    lui a2, 8
260 ; RV64I-NEXT:    add a2, a0, a2
261 ; RV64I-NEXT:    ld a0, -8(a2)
262 ; RV64I-NEXT:    sd a1, -8(a2)
263 ; RV64I-NEXT:    ret
264   %1 = getelementptr inbounds i64, i64* %a, i64 4095
265   %2 = load volatile i64, i64* %1
266   store i64 %b, i64* %1
267   ret i64 %2
270 ; Make sure we don't fold the addiw into the load offset. The sign extend of the
271 ; addiw is required.
272 define i64 @lw_really_far_local(i64* %a)  {
273 ; RV64I-LABEL: lw_really_far_local:
274 ; RV64I:       # %bb.0:
275 ; RV64I-NEXT:    li a1, 1
276 ; RV64I-NEXT:    slli a1, a1, 31
277 ; RV64I-NEXT:    add a0, a0, a1
278 ; RV64I-NEXT:    ld a0, -2048(a0)
279 ; RV64I-NEXT:    ret
280   %1 = getelementptr inbounds i64, i64* %a, i64 268435200
281   %2 = load volatile i64, i64* %1
282   ret i64 %2
285 ; Make sure we don't fold the addiw into the store offset. The sign extend of
286 ; the addiw is required.
287 define void @st_really_far_local(i64* %a, i64 %b)  {
288 ; RV64I-LABEL: st_really_far_local:
289 ; RV64I:       # %bb.0:
290 ; RV64I-NEXT:    li a2, 1
291 ; RV64I-NEXT:    slli a2, a2, 31
292 ; RV64I-NEXT:    add a0, a0, a2
293 ; RV64I-NEXT:    sd a1, -2048(a0)
294 ; RV64I-NEXT:    ret
295   %1 = getelementptr inbounds i64, i64* %a, i64 268435200
296   store i64 %b, i64* %1
297   ret void
300 ; Make sure we don't fold the addiw into the load/store offset. The sign extend
301 ; of the addiw is required.
302 define i64 @lw_sw_really_far_local(i64* %a, i64 %b)  {
303 ; RV64I-LABEL: lw_sw_really_far_local:
304 ; RV64I:       # %bb.0:
305 ; RV64I-NEXT:    li a2, 1
306 ; RV64I-NEXT:    slli a2, a2, 31
307 ; RV64I-NEXT:    add a2, a0, a2
308 ; RV64I-NEXT:    ld a0, -2048(a2)
309 ; RV64I-NEXT:    sd a1, -2048(a2)
310 ; RV64I-NEXT:    ret
311   %1 = getelementptr inbounds i64, i64* %a, i64 268435200
312   %2 = load volatile i64, i64* %1
313   store i64 %b, i64* %1
314   ret i64 %2
317 %struct.quux = type { i32, [0 x i8] }
319 ; Make sure we don't remove the addi and fold the C from
320 ; (add (addi FrameIndex, C), X) into the store address.
321 ; FrameIndex cannot be the operand of an ADD. We must keep the ADDI.
322 define void @addi_fold_crash(i64 %arg) nounwind {
323 ; RV64I-LABEL: addi_fold_crash:
324 ; RV64I:       # %bb.0: # %bb
325 ; RV64I-NEXT:    addi sp, sp, -16
326 ; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
327 ; RV64I-NEXT:    addi a1, sp, 4
328 ; RV64I-NEXT:    add a0, a1, a0
329 ; RV64I-NEXT:    sb zero, 0(a0)
330 ; RV64I-NEXT:    mv a0, a1
331 ; RV64I-NEXT:    call snork@plt
332 ; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
333 ; RV64I-NEXT:    addi sp, sp, 16
334 ; RV64I-NEXT:    ret
336   %tmp = alloca %struct.quux, align 4
337   %tmp1 = getelementptr inbounds %struct.quux, %struct.quux* %tmp, i64 0, i32 1
338   %tmp2 = getelementptr inbounds %struct.quux, %struct.quux* %tmp, i64 0, i32 1, i64 %arg
339   store i8 0, i8* %tmp2, align 1
340   call void @snork([0 x i8]* %tmp1)
341   ret void
344 declare void @snork([0 x i8]*)