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
5; These tests are each targeted at a particular RISC-V FPU instruction. Most
6; other files in this folder exercise LLVM IR instructions that don't directly
7; match a RISC-V instruction.
8
9define float @fadd_s(float %a, float %b) nounwind {
10; RV32IF-LABEL: fadd_s:
11; RV32IF:       # %bb.0:
12; RV32IF-NEXT:    fmv.w.x ft0, a1
13; RV32IF-NEXT:    fmv.w.x ft1, a0
14; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
15; RV32IF-NEXT:    fmv.x.w a0, ft0
16; RV32IF-NEXT:    ret
17  %1 = fadd float %a, %b
18  ret float %1
19}
20
21define float @fsub_s(float %a, float %b) nounwind {
22; RV32IF-LABEL: fsub_s:
23; RV32IF:       # %bb.0:
24; RV32IF-NEXT:    fmv.w.x ft0, a1
25; RV32IF-NEXT:    fmv.w.x ft1, a0
26; RV32IF-NEXT:    fsub.s ft0, ft1, ft0
27; RV32IF-NEXT:    fmv.x.w a0, ft0
28; RV32IF-NEXT:    ret
29  %1 = fsub float %a, %b
30  ret float %1
31}
32
33define float @fmul_s(float %a, float %b) nounwind {
34; RV32IF-LABEL: fmul_s:
35; RV32IF:       # %bb.0:
36; RV32IF-NEXT:    fmv.w.x ft0, a1
37; RV32IF-NEXT:    fmv.w.x ft1, a0
38; RV32IF-NEXT:    fmul.s ft0, ft1, ft0
39; RV32IF-NEXT:    fmv.x.w a0, ft0
40; RV32IF-NEXT:    ret
41  %1 = fmul float %a, %b
42  ret float %1
43}
44
45define float @fdiv_s(float %a, float %b) nounwind {
46; RV32IF-LABEL: fdiv_s:
47; RV32IF:       # %bb.0:
48; RV32IF-NEXT:    fmv.w.x ft0, a1
49; RV32IF-NEXT:    fmv.w.x ft1, a0
50; RV32IF-NEXT:    fdiv.s ft0, ft1, ft0
51; RV32IF-NEXT:    fmv.x.w a0, ft0
52; RV32IF-NEXT:    ret
53  %1 = fdiv float %a, %b
54  ret float %1
55}
56
57declare float @llvm.sqrt.f32(float)
58
59define float @fsqrt_s(float %a) nounwind {
60; RV32IF-LABEL: fsqrt_s:
61; RV32IF:       # %bb.0:
62; RV32IF-NEXT:    fmv.w.x ft0, a0
63; RV32IF-NEXT:    fsqrt.s ft0, ft0
64; RV32IF-NEXT:    fmv.x.w a0, ft0
65; RV32IF-NEXT:    ret
66  %1 = call float @llvm.sqrt.f32(float %a)
67  ret float %1
68}
69
70declare float @llvm.copysign.f32(float, float)
71
72define float @fsgnj_s(float %a, float %b) nounwind {
73; RV32IF-LABEL: fsgnj_s:
74; RV32IF:       # %bb.0:
75; RV32IF-NEXT:    fmv.w.x ft0, a1
76; RV32IF-NEXT:    fmv.w.x ft1, a0
77; RV32IF-NEXT:    fsgnj.s ft0, ft1, ft0
78; RV32IF-NEXT:    fmv.x.w a0, ft0
79; RV32IF-NEXT:    ret
80  %1 = call float @llvm.copysign.f32(float %a, float %b)
81  ret float %1
82}
83
84define float @fneg_s(float %a) nounwind {
85; TODO: doesn't test the fneg selection pattern because
86; DAGCombiner::visitBITCAST will generate a xor on the incoming integer
87; argument
88; RV32IF-LABEL: fneg_s:
89; RV32IF:       # %bb.0:
90; RV32IF-NEXT:    lui a1, 524288
91; RV32IF-NEXT:    xor a0, a0, a1
92; RV32IF-NEXT:    ret
93  %1 = fsub float -0.0, %a
94  ret float %1
95}
96
97define float @fsgnjn_s(float %a, float %b) nounwind {
98; TODO: fsgnjn.s isn't selected because DAGCombiner::visitBITCAST will convert
99; (bitconvert (fneg x)) to a xor
100; RV32IF-LABEL: fsgnjn_s:
101; RV32IF:       # %bb.0:
102; RV32IF-NEXT:    lui a2, 524288
103; RV32IF-NEXT:    xor a1, a1, a2
104; RV32IF-NEXT:    fmv.w.x ft0, a1
105; RV32IF-NEXT:    fmv.w.x ft1, a0
106; RV32IF-NEXT:    fsgnj.s ft0, ft1, ft0
107; RV32IF-NEXT:    fmv.x.w a0, ft0
108; RV32IF-NEXT:    ret
109  %1 = fsub float -0.0, %b
110  %2 = call float @llvm.copysign.f32(float %a, float %1)
111  ret float %2
112}
113
114declare float @llvm.fabs.f32(float)
115
116define float @fabs_s(float %a) nounwind {
117; TODO: doesn't test the fabs selection pattern because
118; DAGCombiner::visitBITCAST will generate an and on the incoming integer
119; argument
120; RV32IF-LABEL: fabs_s:
121; RV32IF:       # %bb.0:
122; RV32IF-NEXT:    lui a1, 524288
123; RV32IF-NEXT:    addi a1, a1, -1
124; RV32IF-NEXT:    and a0, a0, a1
125; RV32IF-NEXT:    ret
126  %1 = call float @llvm.fabs.f32(float %a)
127  ret float %1
128}
129
130declare float @llvm.minnum.f32(float, float)
131
132define float @fmin_s(float %a, float %b) nounwind {
133; RV32IF-LABEL: fmin_s:
134; RV32IF:       # %bb.0:
135; RV32IF-NEXT:    fmv.w.x ft0, a1
136; RV32IF-NEXT:    fmv.w.x ft1, a0
137; RV32IF-NEXT:    fmin.s ft0, ft1, ft0
138; RV32IF-NEXT:    fmv.x.w a0, ft0
139; RV32IF-NEXT:    ret
140  %1 = call float @llvm.minnum.f32(float %a, float %b)
141  ret float %1
142}
143
144declare float @llvm.maxnum.f32(float, float)
145
146define float @fmax_s(float %a, float %b) nounwind {
147; RV32IF-LABEL: fmax_s:
148; RV32IF:       # %bb.0:
149; RV32IF-NEXT:    fmv.w.x ft0, a1
150; RV32IF-NEXT:    fmv.w.x ft1, a0
151; RV32IF-NEXT:    fmax.s ft0, ft1, ft0
152; RV32IF-NEXT:    fmv.x.w a0, ft0
153; RV32IF-NEXT:    ret
154  %1 = call float @llvm.maxnum.f32(float %a, float %b)
155  ret float %1
156}
157
158define i32 @feq_s(float %a, float %b) nounwind {
159; RV32IF-LABEL: feq_s:
160; RV32IF:       # %bb.0:
161; RV32IF-NEXT:    fmv.w.x ft0, a1
162; RV32IF-NEXT:    fmv.w.x ft1, a0
163; RV32IF-NEXT:    feq.s a0, ft1, ft0
164; RV32IF-NEXT:    ret
165  %1 = fcmp oeq float %a, %b
166  %2 = zext i1 %1 to i32
167  ret i32 %2
168}
169
170define i32 @flt_s(float %a, float %b) nounwind {
171; RV32IF-LABEL: flt_s:
172; RV32IF:       # %bb.0:
173; RV32IF-NEXT:    fmv.w.x ft0, a1
174; RV32IF-NEXT:    fmv.w.x ft1, a0
175; RV32IF-NEXT:    flt.s a0, ft1, ft0
176; RV32IF-NEXT:    ret
177  %1 = fcmp olt float %a, %b
178  %2 = zext i1 %1 to i32
179  ret i32 %2
180}
181
182define i32 @fle_s(float %a, float %b) nounwind {
183; RV32IF-LABEL: fle_s:
184; RV32IF:       # %bb.0:
185; RV32IF-NEXT:    fmv.w.x ft0, a1
186; RV32IF-NEXT:    fmv.w.x ft1, a0
187; RV32IF-NEXT:    fle.s a0, ft1, ft0
188; RV32IF-NEXT:    ret
189  %1 = fcmp ole float %a, %b
190  %2 = zext i1 %1 to i32
191  ret i32 %2
192}
193
194declare float @llvm.fma.f32(float, float, float)
195
196define float @fmadd_s(float %a, float %b, float %c) nounwind {
197; RV32IF-LABEL: fmadd_s:
198; RV32IF:       # %bb.0:
199; RV32IF-NEXT:    fmv.w.x ft0, a2
200; RV32IF-NEXT:    fmv.w.x ft1, a1
201; RV32IF-NEXT:    fmv.w.x ft2, a0
202; RV32IF-NEXT:    fmadd.s ft0, ft2, ft1, ft0
203; RV32IF-NEXT:    fmv.x.w a0, ft0
204; RV32IF-NEXT:    ret
205  %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
206  ret float %1
207}
208
209define float @fmsub_s(float %a, float %b, float %c) nounwind {
210; RV32IF-LABEL: fmsub_s:
211; RV32IF:       # %bb.0:
212; RV32IF-NEXT:    fmv.w.x ft0, a2
213; RV32IF-NEXT:    lui a2, %hi(.LCPI15_0)
214; RV32IF-NEXT:    addi a2, a2, %lo(.LCPI15_0)
215; RV32IF-NEXT:    flw ft1, 0(a2)
216; RV32IF-NEXT:    fadd.s ft0, ft0, ft1
217; RV32IF-NEXT:    fmv.w.x ft1, a1
218; RV32IF-NEXT:    fmv.w.x ft2, a0
219; RV32IF-NEXT:    fmsub.s ft0, ft2, ft1, ft0
220; RV32IF-NEXT:    fmv.x.w a0, ft0
221; RV32IF-NEXT:    ret
222  %c_ = fadd float 0.0, %c ; avoid negation using xor
223  %negc = fsub float -0.0, %c_
224  %1 = call float @llvm.fma.f32(float %a, float %b, float %negc)
225  ret float %1
226}
227
228define float @fnmadd_s(float %a, float %b, float %c) nounwind {
229; RV32IF-LABEL: fnmadd_s:
230; RV32IF:       # %bb.0:
231; RV32IF-NEXT:    fmv.w.x ft0, a2
232; RV32IF-NEXT:    lui a2, %hi(.LCPI16_0)
233; RV32IF-NEXT:    addi a2, a2, %lo(.LCPI16_0)
234; RV32IF-NEXT:    flw ft1, 0(a2)
235; RV32IF-NEXT:    fadd.s ft0, ft0, ft1
236; RV32IF-NEXT:    fmv.w.x ft2, a0
237; RV32IF-NEXT:    fadd.s ft1, ft2, ft1
238; RV32IF-NEXT:    fmv.w.x ft2, a1
239; RV32IF-NEXT:    fnmadd.s ft0, ft1, ft2, ft0
240; RV32IF-NEXT:    fmv.x.w a0, ft0
241; RV32IF-NEXT:    ret
242  %a_ = fadd float 0.0, %a
243  %c_ = fadd float 0.0, %c
244  %nega = fsub float -0.0, %a_
245  %negc = fsub float -0.0, %c_
246  %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc)
247  ret float %1
248}
249
250define float @fnmsub_s(float %a, float %b, float %c) nounwind {
251; RV32IF-LABEL: fnmsub_s:
252; RV32IF:       # %bb.0:
253; RV32IF-NEXT:    fmv.w.x ft0, a0
254; RV32IF-NEXT:    lui a0, %hi(.LCPI17_0)
255; RV32IF-NEXT:    addi a0, a0, %lo(.LCPI17_0)
256; RV32IF-NEXT:    flw ft1, 0(a0)
257; RV32IF-NEXT:    fadd.s ft0, ft0, ft1
258; RV32IF-NEXT:    fmv.w.x ft1, a2
259; RV32IF-NEXT:    fmv.w.x ft2, a1
260; RV32IF-NEXT:    fnmsub.s ft0, ft0, ft2, ft1
261; RV32IF-NEXT:    fmv.x.w a0, ft0
262; RV32IF-NEXT:    ret
263  %a_ = fadd float 0.0, %a
264  %nega = fsub float -0.0, %a_
265  %1 = call float @llvm.fma.f32(float %nega, float %b, float %c)
266  ret float %1
267}
268