1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc -mtriple=riscv32 -mattr=+f -verify-machineinstrs < %s \
3; RUN:   | FileCheck -check-prefix=RV32IF %s
4; RUN: llc -mtriple=riscv64 -mattr=+f -verify-machineinstrs < %s \
5; RUN:   | FileCheck -check-prefix=RV64IF %s
6
7define dso_local float @flw(float *%a) nounwind {
8; RV32IF-LABEL: flw:
9; RV32IF:       # %bb.0:
10; RV32IF-NEXT:    flw ft0, 0(a0)
11; RV32IF-NEXT:    flw ft1, 12(a0)
12; RV32IF-NEXT:    fadd.s ft0, ft0, ft1
13; RV32IF-NEXT:    fmv.x.w a0, ft0
14; RV32IF-NEXT:    ret
15;
16; RV64IF-LABEL: flw:
17; RV64IF:       # %bb.0:
18; RV64IF-NEXT:    flw ft0, 0(a0)
19; RV64IF-NEXT:    flw ft1, 12(a0)
20; RV64IF-NEXT:    fadd.s ft0, ft0, ft1
21; RV64IF-NEXT:    fmv.x.w a0, ft0
22; RV64IF-NEXT:    ret
23  %1 = load float, float* %a
24  %2 = getelementptr float, float* %a, i32 3
25  %3 = load float, float* %2
26; Use both loaded values in an FP op to ensure an flw is used, even for the
27; soft float ABI
28  %4 = fadd float %1, %3
29  ret float %4
30}
31
32define dso_local void @fsw(float *%a, float %b, float %c) nounwind {
33; Use %b and %c in an FP op to ensure floating point registers are used, even
34; for the soft float ABI
35; RV32IF-LABEL: fsw:
36; RV32IF:       # %bb.0:
37; RV32IF-NEXT:    fmv.w.x ft0, a2
38; RV32IF-NEXT:    fmv.w.x ft1, a1
39; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
40; RV32IF-NEXT:    fsw ft0, 0(a0)
41; RV32IF-NEXT:    fsw ft0, 32(a0)
42; RV32IF-NEXT:    ret
43;
44; RV64IF-LABEL: fsw:
45; RV64IF:       # %bb.0:
46; RV64IF-NEXT:    fmv.w.x ft0, a2
47; RV64IF-NEXT:    fmv.w.x ft1, a1
48; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
49; RV64IF-NEXT:    fsw ft0, 0(a0)
50; RV64IF-NEXT:    fsw ft0, 32(a0)
51; RV64IF-NEXT:    ret
52  %1 = fadd float %b, %c
53  store float %1, float* %a
54  %2 = getelementptr float, float* %a, i32 8
55  store float %1, float* %2
56  ret void
57}
58
59; Check load and store to a global
60@G = dso_local global float 0.0
61
62define dso_local float @flw_fsw_global(float %a, float %b) nounwind {
63; Use %a and %b in an FP op to ensure floating point registers are used, even
64; for the soft float ABI
65; RV32IF-LABEL: flw_fsw_global:
66; RV32IF:       # %bb.0:
67; RV32IF-NEXT:    fmv.w.x ft0, a1
68; RV32IF-NEXT:    fmv.w.x ft1, a0
69; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
70; RV32IF-NEXT:    lui a0, %hi(G)
71; RV32IF-NEXT:    flw ft1, %lo(G)(a0)
72; RV32IF-NEXT:    fsw ft0, %lo(G)(a0)
73; RV32IF-NEXT:    addi a1, a0, %lo(G)
74; RV32IF-NEXT:    flw ft1, 36(a1)
75; RV32IF-NEXT:    fmv.x.w a0, ft0
76; RV32IF-NEXT:    fsw ft0, 36(a1)
77; RV32IF-NEXT:    ret
78;
79; RV64IF-LABEL: flw_fsw_global:
80; RV64IF:       # %bb.0:
81; RV64IF-NEXT:    fmv.w.x ft0, a1
82; RV64IF-NEXT:    fmv.w.x ft1, a0
83; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
84; RV64IF-NEXT:    lui a0, %hi(G)
85; RV64IF-NEXT:    flw ft1, %lo(G)(a0)
86; RV64IF-NEXT:    fsw ft0, %lo(G)(a0)
87; RV64IF-NEXT:    addi a1, a0, %lo(G)
88; RV64IF-NEXT:    flw ft1, 36(a1)
89; RV64IF-NEXT:    fmv.x.w a0, ft0
90; RV64IF-NEXT:    fsw ft0, 36(a1)
91; RV64IF-NEXT:    ret
92  %1 = fadd float %a, %b
93  %2 = load volatile float, float* @G
94  store float %1, float* @G
95  %3 = getelementptr float, float* @G, i32 9
96  %4 = load volatile float, float* %3
97  store float %1, float* %3
98  ret float %1
99}
100
101; Ensure that 1 is added to the high 20 bits if bit 11 of the low part is 1
102define dso_local float @flw_fsw_constant(float %a) nounwind {
103; RV32IF-LABEL: flw_fsw_constant:
104; RV32IF:       # %bb.0:
105; RV32IF-NEXT:    lui a1, 912092
106; RV32IF-NEXT:    flw ft0, -273(a1)
107; RV32IF-NEXT:    fmv.w.x ft1, a0
108; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
109; RV32IF-NEXT:    fmv.x.w a0, ft0
110; RV32IF-NEXT:    fsw ft0, -273(a1)
111; RV32IF-NEXT:    ret
112;
113; RV64IF-LABEL: flw_fsw_constant:
114; RV64IF:       # %bb.0:
115; RV64IF-NEXT:    lui a1, 228023
116; RV64IF-NEXT:    slli a1, a1, 2
117; RV64IF-NEXT:    flw ft0, -273(a1)
118; RV64IF-NEXT:    fmv.w.x ft1, a0
119; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
120; RV64IF-NEXT:    fmv.x.w a0, ft0
121; RV64IF-NEXT:    fsw ft0, -273(a1)
122; RV64IF-NEXT:    ret
123  %1 = inttoptr i32 3735928559 to float*
124  %2 = load volatile float, float* %1
125  %3 = fadd float %a, %2
126  store float %3, float* %1
127  ret float %3
128}
129
130declare void @notdead(i8*)
131
132define dso_local float @flw_stack(float %a) nounwind {
133; RV32IF-LABEL: flw_stack:
134; RV32IF:       # %bb.0:
135; RV32IF-NEXT:    addi sp, sp, -16
136; RV32IF-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
137; RV32IF-NEXT:    fmv.w.x ft0, a0
138; RV32IF-NEXT:    fsw ft0, 4(sp) # 4-byte Folded Spill
139; RV32IF-NEXT:    addi a0, sp, 8
140; RV32IF-NEXT:    call notdead@plt
141; RV32IF-NEXT:    flw ft0, 8(sp)
142; RV32IF-NEXT:    flw ft1, 4(sp) # 4-byte Folded Reload
143; RV32IF-NEXT:    fadd.s ft0, ft0, ft1
144; RV32IF-NEXT:    fmv.x.w a0, ft0
145; RV32IF-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
146; RV32IF-NEXT:    addi sp, sp, 16
147; RV32IF-NEXT:    ret
148;
149; RV64IF-LABEL: flw_stack:
150; RV64IF:       # %bb.0:
151; RV64IF-NEXT:    addi sp, sp, -16
152; RV64IF-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
153; RV64IF-NEXT:    fmv.w.x ft0, a0
154; RV64IF-NEXT:    fsw ft0, 0(sp) # 4-byte Folded Spill
155; RV64IF-NEXT:    addi a0, sp, 4
156; RV64IF-NEXT:    call notdead@plt
157; RV64IF-NEXT:    flw ft0, 4(sp)
158; RV64IF-NEXT:    flw ft1, 0(sp) # 4-byte Folded Reload
159; RV64IF-NEXT:    fadd.s ft0, ft0, ft1
160; RV64IF-NEXT:    fmv.x.w a0, ft0
161; RV64IF-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
162; RV64IF-NEXT:    addi sp, sp, 16
163; RV64IF-NEXT:    ret
164  %1 = alloca float, align 4
165  %2 = bitcast float* %1 to i8*
166  call void @notdead(i8* %2)
167  %3 = load float, float* %1
168  %4 = fadd float %3, %a ; force load in to FPR32
169  ret float %4
170}
171
172define dso_local void @fsw_stack(float %a, float %b) nounwind {
173; RV32IF-LABEL: fsw_stack:
174; RV32IF:       # %bb.0:
175; RV32IF-NEXT:    addi sp, sp, -16
176; RV32IF-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
177; RV32IF-NEXT:    fmv.w.x ft0, a1
178; RV32IF-NEXT:    fmv.w.x ft1, a0
179; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
180; RV32IF-NEXT:    fsw ft0, 8(sp)
181; RV32IF-NEXT:    addi a0, sp, 8
182; RV32IF-NEXT:    call notdead@plt
183; RV32IF-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
184; RV32IF-NEXT:    addi sp, sp, 16
185; RV32IF-NEXT:    ret
186;
187; RV64IF-LABEL: fsw_stack:
188; RV64IF:       # %bb.0:
189; RV64IF-NEXT:    addi sp, sp, -16
190; RV64IF-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
191; RV64IF-NEXT:    fmv.w.x ft0, a1
192; RV64IF-NEXT:    fmv.w.x ft1, a0
193; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
194; RV64IF-NEXT:    fsw ft0, 4(sp)
195; RV64IF-NEXT:    addi a0, sp, 4
196; RV64IF-NEXT:    call notdead@plt
197; RV64IF-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
198; RV64IF-NEXT:    addi sp, sp, 16
199; RV64IF-NEXT:    ret
200  %1 = fadd float %a, %b ; force store from FPR32
201  %2 = alloca float, align 4
202  store float %1, float* %2
203  %3 = bitcast float* %2 to i8*
204  call void @notdead(i8* %3)
205  ret void
206}
207