xref: /llvm-project/llvm/test/CodeGen/RISCV/mem64.ll (revision eabaee0c59110d0e11b33a69db54ccda526b35fd)
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
4
5; Check indexed and unindexed, sext, zext and anyext loads
6
7define dso_local i64 @lb(ptr %a) nounwind {
8; RV64I-LABEL: lb:
9; RV64I:       # %bb.0:
10; RV64I-NEXT:    lb a1, 1(a0)
11; RV64I-NEXT:    lbu zero, 0(a0)
12; RV64I-NEXT:    mv a0, a1
13; RV64I-NEXT:    ret
14  %1 = getelementptr i8, ptr %a, i32 1
15  %2 = load i8, ptr %1
16  %3 = sext i8 %2 to i64
17  ; the unused load will produce an anyext for selection
18  %4 = load volatile i8, ptr %a
19  ret i64 %3
20}
21
22define dso_local i64 @lh(ptr %a) nounwind {
23; RV64I-LABEL: lh:
24; RV64I:       # %bb.0:
25; RV64I-NEXT:    lh a1, 4(a0)
26; RV64I-NEXT:    lh zero, 0(a0)
27; RV64I-NEXT:    mv a0, a1
28; RV64I-NEXT:    ret
29  %1 = getelementptr i16, ptr %a, i32 2
30  %2 = load i16, ptr %1
31  %3 = sext i16 %2 to i64
32  ; the unused load will produce an anyext for selection
33  %4 = load volatile i16, ptr %a
34  ret i64 %3
35}
36
37define dso_local i64 @lw(ptr %a) nounwind {
38; RV64I-LABEL: lw:
39; RV64I:       # %bb.0:
40; RV64I-NEXT:    lw a1, 12(a0)
41; RV64I-NEXT:    lw zero, 0(a0)
42; RV64I-NEXT:    mv a0, a1
43; RV64I-NEXT:    ret
44  %1 = getelementptr i32, ptr %a, i32 3
45  %2 = load i32, ptr %1
46  %3 = sext i32 %2 to i64
47  ; the unused load will produce an anyext for selection
48  %4 = load volatile i32, ptr %a
49  ret i64 %3
50}
51
52define dso_local i64 @lbu(ptr %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, ptr %a, i32 4
60  %2 = load i8, ptr %1
61  %3 = zext i8 %2 to i64
62  %4 = load volatile i8, ptr %a
63  %5 = zext i8 %4 to i64
64  %6 = add i64 %3, %5
65  ret i64 %6
66}
67
68define dso_local i64 @lhu(ptr %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, ptr %a, i32 5
76  %2 = load i16, ptr %1
77  %3 = zext i16 %2 to i64
78  %4 = load volatile i16, ptr %a
79  %5 = zext i16 %4 to i64
80  %6 = add i64 %3, %5
81  ret i64 %6
82}
83
84define dso_local i64 @lwu(ptr %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, ptr %a, i32 6
92  %2 = load i32, ptr %1
93  %3 = zext i32 %2 to i64
94  %4 = load volatile i32, ptr %a
95  %5 = zext i32 %4 to i64
96  %6 = add i64 %3, %5
97  ret i64 %6
98}
99
100; Check indexed and unindexed stores
101
102define dso_local void @sb(ptr %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, ptr %a
109  %1 = getelementptr i8, ptr %a, i32 7
110  store i8 %b, ptr %1
111  ret void
112}
113
114define dso_local void @sh(ptr %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, ptr %a
121  %1 = getelementptr i16, ptr %a, i32 8
122  store i16 %b, ptr %1
123  ret void
124}
125
126define dso_local void @sw(ptr %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, ptr %a
133  %1 = getelementptr i32, ptr %a, i32 9
134  store i32 %b, ptr %1
135  ret void
136}
137
138; 64-bit loads and stores
139
140define dso_local i64 @ld(ptr %a) nounwind {
141; RV64I-LABEL: ld:
142; RV64I:       # %bb.0:
143; RV64I-NEXT:    ld a1, 80(a0)
144; RV64I-NEXT:    ld zero, 0(a0)
145; RV64I-NEXT:    mv a0, a1
146; RV64I-NEXT:    ret
147  %1 = getelementptr i64, ptr %a, i32 10
148  %2 = load i64, ptr %1
149  %3 = load volatile i64, ptr %a
150  ret i64 %2
151}
152
153define dso_local void @sd(ptr %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, ptr %a
160  %1 = getelementptr i64, ptr %a, i32 11
161  store i64 %b, ptr %1
162  ret void
163}
164
165; Check load and store to an i1 location
166define dso_local i64 @load_sext_zext_anyext_i1(ptr %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:    lbu zero, 0(a0)
172; RV64I-NEXT:    sub a0, a2, a1
173; RV64I-NEXT:    ret
174  ; sextload i1
175  %1 = getelementptr i1, ptr %a, i32 1
176  %2 = load i1, ptr %1
177  %3 = sext i1 %2 to i64
178  ; zextload i1
179  %4 = getelementptr i1, ptr %a, i32 2
180  %5 = load i1, ptr %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, ptr %a
185  ret i64 %7
186}
187
188define dso_local i16 @load_sext_zext_anyext_i1_i16(ptr %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:    lbu zero, 0(a0)
194; RV64I-NEXT:    sub a0, a2, a1
195; RV64I-NEXT:    ret
196  ; sextload i1
197  %1 = getelementptr i1, ptr %a, i32 1
198  %2 = load i1, ptr %1
199  %3 = sext i1 %2 to i16
200  ; zextload i1
201  %4 = getelementptr i1, ptr %a, i32 2
202  %5 = load i1, ptr %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, ptr %a
207  ret i16 %7
208}
209
210; Check load and store to a global
211@G = dso_local global i64 0
212
213define 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 zero, 72(a3)
221; RV64I-NEXT:    sd a0, 72(a3)
222; RV64I-NEXT:    mv a0, a1
223; RV64I-NEXT:    ret
224  %1 = load volatile i64, ptr @G
225  store i64 %a, ptr @G
226  %2 = getelementptr i64, ptr @G, i64 9
227  %3 = load volatile i64, ptr %2
228  store i64 %a, ptr %2
229  ret i64 %1
230}
231
232define i64 @lw_near_local(ptr %a)  {
233; RV64I-LABEL: lw_near_local:
234; RV64I:       # %bb.0:
235; RV64I-NEXT:    addi a0, a0, 2047
236; RV64I-NEXT:    ld a0, 9(a0)
237; RV64I-NEXT:    ret
238  %1 = getelementptr inbounds i64, ptr %a, i64 257
239  %2 = load volatile i64, ptr %1
240  ret i64 %2
241}
242
243define void @st_near_local(ptr %a, i64 %b)  {
244; RV64I-LABEL: st_near_local:
245; RV64I:       # %bb.0:
246; RV64I-NEXT:    addi a0, a0, 2047
247; RV64I-NEXT:    sd a1, 9(a0)
248; RV64I-NEXT:    ret
249  %1 = getelementptr inbounds i64, ptr %a, i64 257
250  store i64 %b, ptr %1
251  ret void
252}
253
254define i64 @lw_sw_near_local(ptr %a, i64 %b)  {
255; RV64I-LABEL: lw_sw_near_local:
256; RV64I:       # %bb.0:
257; RV64I-NEXT:    addi a2, a0, 2047
258; RV64I-NEXT:    ld a0, 9(a2)
259; RV64I-NEXT:    sd a1, 9(a2)
260; RV64I-NEXT:    ret
261  %1 = getelementptr inbounds i64, ptr %a, i64 257
262  %2 = load volatile i64, ptr %1
263  store i64 %b, ptr %1
264  ret i64 %2
265}
266
267define i64 @lw_far_local(ptr %a)  {
268; RV64I-LABEL: lw_far_local:
269; RV64I:       # %bb.0:
270; RV64I-NEXT:    lui a1, 8
271; RV64I-NEXT:    add a0, a0, a1
272; RV64I-NEXT:    ld a0, -8(a0)
273; RV64I-NEXT:    ret
274  %1 = getelementptr inbounds i64, ptr %a, i64 4095
275  %2 = load volatile i64, ptr %1
276  ret i64 %2
277}
278
279define void @st_far_local(ptr %a, i64 %b)  {
280; RV64I-LABEL: st_far_local:
281; RV64I:       # %bb.0:
282; RV64I-NEXT:    lui a2, 8
283; RV64I-NEXT:    add a0, a0, a2
284; RV64I-NEXT:    sd a1, -8(a0)
285; RV64I-NEXT:    ret
286  %1 = getelementptr inbounds i64, ptr %a, i64 4095
287  store i64 %b, ptr %1
288  ret void
289}
290
291define i64 @lw_sw_far_local(ptr %a, i64 %b)  {
292; RV64I-LABEL: lw_sw_far_local:
293; RV64I:       # %bb.0:
294; RV64I-NEXT:    lui a2, 8
295; RV64I-NEXT:    add a2, a0, a2
296; RV64I-NEXT:    ld a0, -8(a2)
297; RV64I-NEXT:    sd a1, -8(a2)
298; RV64I-NEXT:    ret
299  %1 = getelementptr inbounds i64, ptr %a, i64 4095
300  %2 = load volatile i64, ptr %1
301  store i64 %b, ptr %1
302  ret i64 %2
303}
304
305; Make sure we don't fold the addiw into the load offset. The sign extend of the
306; addiw is required.
307define i64 @lw_really_far_local(ptr %a)  {
308; RV64I-LABEL: lw_really_far_local:
309; RV64I:       # %bb.0:
310; RV64I-NEXT:    lui a1, 524288
311; RV64I-NEXT:    addiw a1, a1, -2048
312; RV64I-NEXT:    add a0, a0, a1
313; RV64I-NEXT:    ld a0, 0(a0)
314; RV64I-NEXT:    ret
315  %1 = getelementptr inbounds i64, ptr %a, i64 268435200
316  %2 = load volatile i64, ptr %1
317  ret i64 %2
318}
319
320; Make sure we don't fold the addiw into the store offset. The sign extend of
321; the addiw is required.
322define void @st_really_far_local(ptr %a, i64 %b)  {
323; RV64I-LABEL: st_really_far_local:
324; RV64I:       # %bb.0:
325; RV64I-NEXT:    lui a2, 524288
326; RV64I-NEXT:    addiw a2, a2, -2048
327; RV64I-NEXT:    add a0, a0, a2
328; RV64I-NEXT:    sd a1, 0(a0)
329; RV64I-NEXT:    ret
330  %1 = getelementptr inbounds i64, ptr %a, i64 268435200
331  store i64 %b, ptr %1
332  ret void
333}
334
335; Make sure we don't fold the addiw into the load/store offset. The sign extend
336; of the addiw is required.
337define i64 @lw_sw_really_far_local(ptr %a, i64 %b)  {
338; RV64I-LABEL: lw_sw_really_far_local:
339; RV64I:       # %bb.0:
340; RV64I-NEXT:    lui a2, 524288
341; RV64I-NEXT:    addiw a2, a2, -2048
342; RV64I-NEXT:    add a2, a0, a2
343; RV64I-NEXT:    ld a0, 0(a2)
344; RV64I-NEXT:    sd a1, 0(a2)
345; RV64I-NEXT:    ret
346  %1 = getelementptr inbounds i64, ptr %a, i64 268435200
347  %2 = load volatile i64, ptr %1
348  store i64 %b, ptr %1
349  ret i64 %2
350}
351
352%struct.quux = type { i32, [0 x i8] }
353
354; Make sure we don't remove the addi and fold the C from
355; (add (addi FrameIndex, C), X) into the store address.
356; FrameIndex cannot be the operand of an ADD. We must keep the ADDI.
357define void @addi_fold_crash(i64 %arg) nounwind {
358; RV64I-LABEL: addi_fold_crash:
359; RV64I:       # %bb.0: # %bb
360; RV64I-NEXT:    addi sp, sp, -16
361; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
362; RV64I-NEXT:    addi a1, sp, 4
363; RV64I-NEXT:    add a0, a1, a0
364; RV64I-NEXT:    sb zero, 0(a0)
365; RV64I-NEXT:    mv a0, a1
366; RV64I-NEXT:    call snork
367; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
368; RV64I-NEXT:    addi sp, sp, 16
369; RV64I-NEXT:    ret
370bb:
371  %tmp = alloca %struct.quux, align 8
372  %tmp1 = getelementptr inbounds %struct.quux, ptr %tmp, i64 0, i32 1
373  %tmp2 = getelementptr inbounds %struct.quux, ptr %tmp, i64 0, i32 1, i64 %arg
374  store i8 0, ptr %tmp2, align 1
375  call void @snork(ptr %tmp1)
376  ret void
377}
378
379declare void @snork(ptr)
380