xref: /llvm-project/llvm/test/CodeGen/RISCV/double-mem.ll (revision 9122c5235ec85ce0c0ad337e862b006e7b349d84)
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -mattr=+d -verify-machineinstrs < %s \
3; RUN:   -target-abi=ilp32d | FileCheck -check-prefixes=CHECKIFD,RV32IFD %s
4; RUN: llc -mtriple=riscv64 -mattr=+d -verify-machineinstrs < %s \
5; RUN:   -target-abi=lp64d | FileCheck -check-prefixes=CHECKIFD,RV64IFD %s
6; RUN: llc -mtriple=riscv32 -mattr=+zdinx -verify-machineinstrs < %s \
7; RUN:   -target-abi=ilp32 | FileCheck -check-prefixes=RV32IZFINXZDINX %s
8; RUN: llc -mtriple=riscv64 -mattr=+zdinx -verify-machineinstrs < %s \
9; RUN:   -target-abi=lp64 | FileCheck -check-prefixes=RV64IZFINXZDINX %s
10
11define dso_local double @fld(ptr %a) nounwind {
12; CHECKIFD-LABEL: fld:
13; CHECKIFD:       # %bb.0:
14; CHECKIFD-NEXT:    fld fa5, 0(a0)
15; CHECKIFD-NEXT:    fld fa4, 24(a0)
16; CHECKIFD-NEXT:    fadd.d fa0, fa5, fa4
17; CHECKIFD-NEXT:    ret
18;
19; RV32IZFINXZDINX-LABEL: fld:
20; RV32IZFINXZDINX:       # %bb.0:
21; RV32IZFINXZDINX-NEXT:    lw a2, 0(a0)
22; RV32IZFINXZDINX-NEXT:    lw a3, 4(a0)
23; RV32IZFINXZDINX-NEXT:    lw a1, 28(a0)
24; RV32IZFINXZDINX-NEXT:    lw a0, 24(a0)
25; RV32IZFINXZDINX-NEXT:    fadd.d a0, a2, a0
26; RV32IZFINXZDINX-NEXT:    ret
27;
28; RV64IZFINXZDINX-LABEL: fld:
29; RV64IZFINXZDINX:       # %bb.0:
30; RV64IZFINXZDINX-NEXT:    ld a1, 0(a0)
31; RV64IZFINXZDINX-NEXT:    ld a0, 24(a0)
32; RV64IZFINXZDINX-NEXT:    fadd.d a0, a1, a0
33; RV64IZFINXZDINX-NEXT:    ret
34  %1 = load double, ptr %a
35  %2 = getelementptr double, ptr %a, i32 3
36  %3 = load double, ptr %2
37; Use both loaded values in an FP op to ensure an fld is used, even for the
38; soft float ABI
39  %4 = fadd double %1, %3
40  ret double %4
41}
42
43define dso_local void @fsd(ptr %a, double %b, double %c) nounwind {
44; CHECKIFD-LABEL: fsd:
45; CHECKIFD:       # %bb.0:
46; CHECKIFD-NEXT:    fadd.d fa5, fa0, fa1
47; CHECKIFD-NEXT:    fsd fa5, 0(a0)
48; CHECKIFD-NEXT:    fsd fa5, 64(a0)
49; CHECKIFD-NEXT:    ret
50;
51; RV32IZFINXZDINX-LABEL: fsd:
52; RV32IZFINXZDINX:       # %bb.0:
53; RV32IZFINXZDINX-NEXT:    mv a5, a4
54; RV32IZFINXZDINX-NEXT:    mv a7, a2
55; RV32IZFINXZDINX-NEXT:    mv a4, a3
56; RV32IZFINXZDINX-NEXT:    mv a6, a1
57; RV32IZFINXZDINX-NEXT:    fadd.d a2, a6, a4
58; RV32IZFINXZDINX-NEXT:    sw a2, 0(a0)
59; RV32IZFINXZDINX-NEXT:    sw a3, 4(a0)
60; RV32IZFINXZDINX-NEXT:    sw a2, 64(a0)
61; RV32IZFINXZDINX-NEXT:    sw a3, 68(a0)
62; RV32IZFINXZDINX-NEXT:    ret
63;
64; RV64IZFINXZDINX-LABEL: fsd:
65; RV64IZFINXZDINX:       # %bb.0:
66; RV64IZFINXZDINX-NEXT:    fadd.d a1, a1, a2
67; RV64IZFINXZDINX-NEXT:    sd a1, 0(a0)
68; RV64IZFINXZDINX-NEXT:    sd a1, 64(a0)
69; RV64IZFINXZDINX-NEXT:    ret
70; Use %b and %c in an FP op to ensure floating point registers are used, even
71; for the soft float ABI
72  %1 = fadd double %b, %c
73  store double %1, ptr %a
74  %2 = getelementptr double, ptr %a, i32 8
75  store double %1, ptr %2
76  ret void
77}
78
79; Check load and store to a global
80@G = dso_local global double 0.0
81
82define dso_local double @fld_fsd_global(double %a, double %b) nounwind {
83; CHECKIFD-LABEL: fld_fsd_global:
84; CHECKIFD:       # %bb.0:
85; CHECKIFD-NEXT:    fadd.d fa0, fa0, fa1
86; CHECKIFD-NEXT:    lui a0, %hi(G)
87; CHECKIFD-NEXT:    fld fa5, %lo(G)(a0)
88; CHECKIFD-NEXT:    addi a1, a0, %lo(G)
89; CHECKIFD-NEXT:    fsd fa0, %lo(G)(a0)
90; CHECKIFD-NEXT:    fld fa5, 72(a1)
91; CHECKIFD-NEXT:    fsd fa0, 72(a1)
92; CHECKIFD-NEXT:    ret
93;
94; RV32IZFINXZDINX-LABEL: fld_fsd_global:
95; RV32IZFINXZDINX:       # %bb.0:
96; RV32IZFINXZDINX-NEXT:    lui a4, %hi(G)
97; RV32IZFINXZDINX-NEXT:    fadd.d a0, a0, a2
98; RV32IZFINXZDINX-NEXT:    lw a2, %lo(G)(a4)
99; RV32IZFINXZDINX-NEXT:    lw a3, %lo(G+4)(a4)
100; RV32IZFINXZDINX-NEXT:    addi a2, a4, %lo(G)
101; RV32IZFINXZDINX-NEXT:    sw a0, %lo(G)(a4)
102; RV32IZFINXZDINX-NEXT:    sw a1, %lo(G+4)(a4)
103; RV32IZFINXZDINX-NEXT:    lw a4, 72(a2)
104; RV32IZFINXZDINX-NEXT:    lw a5, 76(a2)
105; RV32IZFINXZDINX-NEXT:    sw a0, 72(a2)
106; RV32IZFINXZDINX-NEXT:    sw a1, 76(a2)
107; RV32IZFINXZDINX-NEXT:    ret
108;
109; RV64IZFINXZDINX-LABEL: fld_fsd_global:
110; RV64IZFINXZDINX:       # %bb.0:
111; RV64IZFINXZDINX-NEXT:    fadd.d a0, a0, a1
112; RV64IZFINXZDINX-NEXT:    lui a1, %hi(G)
113; RV64IZFINXZDINX-NEXT:    ld zero, %lo(G)(a1)
114; RV64IZFINXZDINX-NEXT:    addi a2, a1, %lo(G)
115; RV64IZFINXZDINX-NEXT:    sd a0, %lo(G)(a1)
116; RV64IZFINXZDINX-NEXT:    ld zero, 72(a2)
117; RV64IZFINXZDINX-NEXT:    sd a0, 72(a2)
118; RV64IZFINXZDINX-NEXT:    ret
119; Use %a and %b in an FP op to ensure floating point registers are used, even
120; for the soft float ABI
121  %1 = fadd double %a, %b
122  %2 = load volatile double, ptr @G
123  store double %1, ptr @G
124  %3 = getelementptr double, ptr @G, i32 9
125  %4 = load volatile double, ptr %3
126  store double %1, ptr %3
127  ret double %1
128}
129
130; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1
131define dso_local double @fld_fsd_constant(double %a) nounwind {
132; RV32IFD-LABEL: fld_fsd_constant:
133; RV32IFD:       # %bb.0:
134; RV32IFD-NEXT:    lui a0, 912092
135; RV32IFD-NEXT:    fld fa5, -273(a0)
136; RV32IFD-NEXT:    fadd.d fa0, fa0, fa5
137; RV32IFD-NEXT:    fsd fa0, -273(a0)
138; RV32IFD-NEXT:    ret
139;
140; RV64IFD-LABEL: fld_fsd_constant:
141; RV64IFD:       # %bb.0:
142; RV64IFD-NEXT:    lui a0, 228023
143; RV64IFD-NEXT:    slli a0, a0, 2
144; RV64IFD-NEXT:    fld fa5, -273(a0)
145; RV64IFD-NEXT:    fadd.d fa0, fa0, fa5
146; RV64IFD-NEXT:    fsd fa0, -273(a0)
147; RV64IFD-NEXT:    ret
148;
149; RV32IZFINXZDINX-LABEL: fld_fsd_constant:
150; RV32IZFINXZDINX:       # %bb.0:
151; RV32IZFINXZDINX-NEXT:    lui a2, 912092
152; RV32IZFINXZDINX-NEXT:    lw a4, -273(a2)
153; RV32IZFINXZDINX-NEXT:    lw a5, -269(a2)
154; RV32IZFINXZDINX-NEXT:    fadd.d a0, a0, a4
155; RV32IZFINXZDINX-NEXT:    sw a0, -273(a2)
156; RV32IZFINXZDINX-NEXT:    sw a1, -269(a2)
157; RV32IZFINXZDINX-NEXT:    ret
158;
159; RV64IZFINXZDINX-LABEL: fld_fsd_constant:
160; RV64IZFINXZDINX:       # %bb.0:
161; RV64IZFINXZDINX-NEXT:    lui a1, 228023
162; RV64IZFINXZDINX-NEXT:    slli a1, a1, 2
163; RV64IZFINXZDINX-NEXT:    ld a2, -273(a1)
164; RV64IZFINXZDINX-NEXT:    fadd.d a0, a0, a2
165; RV64IZFINXZDINX-NEXT:    sd a0, -273(a1)
166; RV64IZFINXZDINX-NEXT:    ret
167  %1 = inttoptr i32 3735928559 to ptr
168  %2 = load volatile double, ptr %1
169  %3 = fadd double %a, %2
170  store double %3, ptr %1
171  ret double %3
172}
173
174declare void @notdead(ptr)
175
176define dso_local double @fld_stack(double %a) nounwind {
177; RV32IFD-LABEL: fld_stack:
178; RV32IFD:       # %bb.0:
179; RV32IFD-NEXT:    addi sp, sp, -32
180; RV32IFD-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
181; RV32IFD-NEXT:    fsd fs0, 16(sp) # 8-byte Folded Spill
182; RV32IFD-NEXT:    fmv.d fs0, fa0
183; RV32IFD-NEXT:    addi a0, sp, 8
184; RV32IFD-NEXT:    call notdead
185; RV32IFD-NEXT:    fld fa5, 8(sp)
186; RV32IFD-NEXT:    fadd.d fa0, fa5, fs0
187; RV32IFD-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
188; RV32IFD-NEXT:    fld fs0, 16(sp) # 8-byte Folded Reload
189; RV32IFD-NEXT:    addi sp, sp, 32
190; RV32IFD-NEXT:    ret
191;
192; RV64IFD-LABEL: fld_stack:
193; RV64IFD:       # %bb.0:
194; RV64IFD-NEXT:    addi sp, sp, -32
195; RV64IFD-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
196; RV64IFD-NEXT:    fsd fs0, 16(sp) # 8-byte Folded Spill
197; RV64IFD-NEXT:    fmv.d fs0, fa0
198; RV64IFD-NEXT:    addi a0, sp, 8
199; RV64IFD-NEXT:    call notdead
200; RV64IFD-NEXT:    fld fa5, 8(sp)
201; RV64IFD-NEXT:    fadd.d fa0, fa5, fs0
202; RV64IFD-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
203; RV64IFD-NEXT:    fld fs0, 16(sp) # 8-byte Folded Reload
204; RV64IFD-NEXT:    addi sp, sp, 32
205; RV64IFD-NEXT:    ret
206;
207; RV32IZFINXZDINX-LABEL: fld_stack:
208; RV32IZFINXZDINX:       # %bb.0:
209; RV32IZFINXZDINX-NEXT:    addi sp, sp, -32
210; RV32IZFINXZDINX-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
211; RV32IZFINXZDINX-NEXT:    sw s0, 24(sp) # 4-byte Folded Spill
212; RV32IZFINXZDINX-NEXT:    sw s1, 20(sp) # 4-byte Folded Spill
213; RV32IZFINXZDINX-NEXT:    mv s1, a1
214; RV32IZFINXZDINX-NEXT:    mv s0, a0
215; RV32IZFINXZDINX-NEXT:    addi a0, sp, 8
216; RV32IZFINXZDINX-NEXT:    call notdead
217; RV32IZFINXZDINX-NEXT:    lw a0, 8(sp)
218; RV32IZFINXZDINX-NEXT:    lw a1, 12(sp)
219; RV32IZFINXZDINX-NEXT:    fadd.d a0, a0, s0
220; RV32IZFINXZDINX-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
221; RV32IZFINXZDINX-NEXT:    lw s0, 24(sp) # 4-byte Folded Reload
222; RV32IZFINXZDINX-NEXT:    lw s1, 20(sp) # 4-byte Folded Reload
223; RV32IZFINXZDINX-NEXT:    addi sp, sp, 32
224; RV32IZFINXZDINX-NEXT:    ret
225;
226; RV64IZFINXZDINX-LABEL: fld_stack:
227; RV64IZFINXZDINX:       # %bb.0:
228; RV64IZFINXZDINX-NEXT:    addi sp, sp, -32
229; RV64IZFINXZDINX-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
230; RV64IZFINXZDINX-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
231; RV64IZFINXZDINX-NEXT:    mv s0, a0
232; RV64IZFINXZDINX-NEXT:    addi a0, sp, 8
233; RV64IZFINXZDINX-NEXT:    call notdead
234; RV64IZFINXZDINX-NEXT:    ld a0, 8(sp)
235; RV64IZFINXZDINX-NEXT:    fadd.d a0, a0, s0
236; RV64IZFINXZDINX-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
237; RV64IZFINXZDINX-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
238; RV64IZFINXZDINX-NEXT:    addi sp, sp, 32
239; RV64IZFINXZDINX-NEXT:    ret
240  %1 = alloca double, align 8
241  call void @notdead(ptr %1)
242  %2 = load double, ptr %1
243  %3 = fadd double %2, %a ; force load in to FPR64
244  ret double %3
245}
246
247define dso_local void @fsd_stack(double %a, double %b) nounwind {
248; RV32IFD-LABEL: fsd_stack:
249; RV32IFD:       # %bb.0:
250; RV32IFD-NEXT:    addi sp, sp, -16
251; RV32IFD-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
252; RV32IFD-NEXT:    fadd.d fa5, fa0, fa1
253; RV32IFD-NEXT:    fsd fa5, 0(sp)
254; RV32IFD-NEXT:    mv a0, sp
255; RV32IFD-NEXT:    call notdead
256; RV32IFD-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
257; RV32IFD-NEXT:    addi sp, sp, 16
258; RV32IFD-NEXT:    ret
259;
260; RV64IFD-LABEL: fsd_stack:
261; RV64IFD:       # %bb.0:
262; RV64IFD-NEXT:    addi sp, sp, -16
263; RV64IFD-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
264; RV64IFD-NEXT:    fadd.d fa5, fa0, fa1
265; RV64IFD-NEXT:    fsd fa5, 0(sp)
266; RV64IFD-NEXT:    mv a0, sp
267; RV64IFD-NEXT:    call notdead
268; RV64IFD-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
269; RV64IFD-NEXT:    addi sp, sp, 16
270; RV64IFD-NEXT:    ret
271;
272; RV32IZFINXZDINX-LABEL: fsd_stack:
273; RV32IZFINXZDINX:       # %bb.0:
274; RV32IZFINXZDINX-NEXT:    addi sp, sp, -16
275; RV32IZFINXZDINX-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
276; RV32IZFINXZDINX-NEXT:    fadd.d a0, a0, a2
277; RV32IZFINXZDINX-NEXT:    sw a0, 0(sp)
278; RV32IZFINXZDINX-NEXT:    sw a1, 4(sp)
279; RV32IZFINXZDINX-NEXT:    mv a0, sp
280; RV32IZFINXZDINX-NEXT:    call notdead
281; RV32IZFINXZDINX-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
282; RV32IZFINXZDINX-NEXT:    addi sp, sp, 16
283; RV32IZFINXZDINX-NEXT:    ret
284;
285; RV64IZFINXZDINX-LABEL: fsd_stack:
286; RV64IZFINXZDINX:       # %bb.0:
287; RV64IZFINXZDINX-NEXT:    addi sp, sp, -16
288; RV64IZFINXZDINX-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
289; RV64IZFINXZDINX-NEXT:    fadd.d a0, a0, a1
290; RV64IZFINXZDINX-NEXT:    sd a0, 0(sp)
291; RV64IZFINXZDINX-NEXT:    mv a0, sp
292; RV64IZFINXZDINX-NEXT:    call notdead
293; RV64IZFINXZDINX-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
294; RV64IZFINXZDINX-NEXT:    addi sp, sp, 16
295; RV64IZFINXZDINX-NEXT:    ret
296  %1 = fadd double %a, %b ; force store from FPR64
297  %2 = alloca double, align 8
298  store double %1, ptr %2
299  call void @notdead(ptr %2)
300  ret void
301}
302
303; Test selection of store<ST4[%a], trunc to f32>, ..
304define dso_local void @fsd_trunc(ptr %a, double %b) nounwind noinline optnone {
305; CHECKIFD-LABEL: fsd_trunc:
306; CHECKIFD:       # %bb.0:
307; CHECKIFD-NEXT:    fcvt.s.d fa5, fa0
308; CHECKIFD-NEXT:    fsw fa5, 0(a0)
309; CHECKIFD-NEXT:    ret
310;
311; RV32IZFINXZDINX-LABEL: fsd_trunc:
312; RV32IZFINXZDINX:       # %bb.0:
313; RV32IZFINXZDINX-NEXT:    mv a3, a2
314; RV32IZFINXZDINX-NEXT:    mv a2, a1
315; RV32IZFINXZDINX-NEXT:    fcvt.s.d a1, a2
316; RV32IZFINXZDINX-NEXT:    sw a1, 0(a0)
317; RV32IZFINXZDINX-NEXT:    ret
318;
319; RV64IZFINXZDINX-LABEL: fsd_trunc:
320; RV64IZFINXZDINX:       # %bb.0:
321; RV64IZFINXZDINX-NEXT:    fcvt.s.d a1, a1
322; RV64IZFINXZDINX-NEXT:    sw a1, 0(a0)
323; RV64IZFINXZDINX-NEXT:    ret
324  %1 = fptrunc double %b to float
325  store float %1, ptr %a, align 4
326  ret void
327}
328