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
7; These tests are each targeted at a particular RISC-V FPU instruction. Most
8; other files in this folder exercise LLVM IR instructions that don't directly
9; match a RISC-V instruction.
10
11define float @fadd_s(float %a, float %b) nounwind {
12; RV32IF-LABEL: fadd_s:
13; RV32IF:       # %bb.0:
14; RV32IF-NEXT:    fmv.w.x ft0, a1
15; RV32IF-NEXT:    fmv.w.x ft1, a0
16; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
17; RV32IF-NEXT:    fmv.x.w a0, ft0
18; RV32IF-NEXT:    ret
19;
20; RV64IF-LABEL: fadd_s:
21; RV64IF:       # %bb.0:
22; RV64IF-NEXT:    fmv.w.x ft0, a1
23; RV64IF-NEXT:    fmv.w.x ft1, a0
24; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
25; RV64IF-NEXT:    fmv.x.w a0, ft0
26; RV64IF-NEXT:    ret
27  %1 = fadd float %a, %b
28  ret float %1
29}
30
31define float @fsub_s(float %a, float %b) nounwind {
32; RV32IF-LABEL: fsub_s:
33; RV32IF:       # %bb.0:
34; RV32IF-NEXT:    fmv.w.x ft0, a1
35; RV32IF-NEXT:    fmv.w.x ft1, a0
36; RV32IF-NEXT:    fsub.s ft0, ft1, ft0
37; RV32IF-NEXT:    fmv.x.w a0, ft0
38; RV32IF-NEXT:    ret
39;
40; RV64IF-LABEL: fsub_s:
41; RV64IF:       # %bb.0:
42; RV64IF-NEXT:    fmv.w.x ft0, a1
43; RV64IF-NEXT:    fmv.w.x ft1, a0
44; RV64IF-NEXT:    fsub.s ft0, ft1, ft0
45; RV64IF-NEXT:    fmv.x.w a0, ft0
46; RV64IF-NEXT:    ret
47  %1 = fsub float %a, %b
48  ret float %1
49}
50
51define float @fmul_s(float %a, float %b) nounwind {
52; RV32IF-LABEL: fmul_s:
53; RV32IF:       # %bb.0:
54; RV32IF-NEXT:    fmv.w.x ft0, a1
55; RV32IF-NEXT:    fmv.w.x ft1, a0
56; RV32IF-NEXT:    fmul.s ft0, ft1, ft0
57; RV32IF-NEXT:    fmv.x.w a0, ft0
58; RV32IF-NEXT:    ret
59;
60; RV64IF-LABEL: fmul_s:
61; RV64IF:       # %bb.0:
62; RV64IF-NEXT:    fmv.w.x ft0, a1
63; RV64IF-NEXT:    fmv.w.x ft1, a0
64; RV64IF-NEXT:    fmul.s ft0, ft1, ft0
65; RV64IF-NEXT:    fmv.x.w a0, ft0
66; RV64IF-NEXT:    ret
67  %1 = fmul float %a, %b
68  ret float %1
69}
70
71define float @fdiv_s(float %a, float %b) nounwind {
72; RV32IF-LABEL: fdiv_s:
73; RV32IF:       # %bb.0:
74; RV32IF-NEXT:    fmv.w.x ft0, a1
75; RV32IF-NEXT:    fmv.w.x ft1, a0
76; RV32IF-NEXT:    fdiv.s ft0, ft1, ft0
77; RV32IF-NEXT:    fmv.x.w a0, ft0
78; RV32IF-NEXT:    ret
79;
80; RV64IF-LABEL: fdiv_s:
81; RV64IF:       # %bb.0:
82; RV64IF-NEXT:    fmv.w.x ft0, a1
83; RV64IF-NEXT:    fmv.w.x ft1, a0
84; RV64IF-NEXT:    fdiv.s ft0, ft1, ft0
85; RV64IF-NEXT:    fmv.x.w a0, ft0
86; RV64IF-NEXT:    ret
87  %1 = fdiv float %a, %b
88  ret float %1
89}
90
91declare float @llvm.sqrt.f32(float)
92
93define float @fsqrt_s(float %a) nounwind {
94; RV32IF-LABEL: fsqrt_s:
95; RV32IF:       # %bb.0:
96; RV32IF-NEXT:    fmv.w.x ft0, a0
97; RV32IF-NEXT:    fsqrt.s ft0, ft0
98; RV32IF-NEXT:    fmv.x.w a0, ft0
99; RV32IF-NEXT:    ret
100;
101; RV64IF-LABEL: fsqrt_s:
102; RV64IF:       # %bb.0:
103; RV64IF-NEXT:    fmv.w.x ft0, a0
104; RV64IF-NEXT:    fsqrt.s ft0, ft0
105; RV64IF-NEXT:    fmv.x.w a0, ft0
106; RV64IF-NEXT:    ret
107  %1 = call float @llvm.sqrt.f32(float %a)
108  ret float %1
109}
110
111declare float @llvm.copysign.f32(float, float)
112
113define float @fsgnj_s(float %a, float %b) nounwind {
114; RV32IF-LABEL: fsgnj_s:
115; RV32IF:       # %bb.0:
116; RV32IF-NEXT:    fmv.w.x ft0, a1
117; RV32IF-NEXT:    fmv.w.x ft1, a0
118; RV32IF-NEXT:    fsgnj.s ft0, ft1, ft0
119; RV32IF-NEXT:    fmv.x.w a0, ft0
120; RV32IF-NEXT:    ret
121;
122; RV64IF-LABEL: fsgnj_s:
123; RV64IF:       # %bb.0:
124; RV64IF-NEXT:    fmv.w.x ft0, a1
125; RV64IF-NEXT:    fmv.w.x ft1, a0
126; RV64IF-NEXT:    fsgnj.s ft0, ft1, ft0
127; RV64IF-NEXT:    fmv.x.w a0, ft0
128; RV64IF-NEXT:    ret
129  %1 = call float @llvm.copysign.f32(float %a, float %b)
130  ret float %1
131}
132
133; This function performs extra work to ensure that
134; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor.
135define i32 @fneg_s(float %a, float %b) nounwind {
136; RV32IF-LABEL: fneg_s:
137; RV32IF:       # %bb.0:
138; RV32IF-NEXT:    fmv.w.x ft0, a0
139; RV32IF-NEXT:    fadd.s ft0, ft0, ft0
140; RV32IF-NEXT:    fneg.s ft1, ft0
141; RV32IF-NEXT:    feq.s a0, ft0, ft1
142; RV32IF-NEXT:    ret
143;
144; RV64IF-LABEL: fneg_s:
145; RV64IF:       # %bb.0:
146; RV64IF-NEXT:    fmv.w.x ft0, a0
147; RV64IF-NEXT:    fadd.s ft0, ft0, ft0
148; RV64IF-NEXT:    fneg.s ft1, ft0
149; RV64IF-NEXT:    feq.s a0, ft0, ft1
150; RV64IF-NEXT:    ret
151  %1 = fadd float %a, %a
152  %2 = fneg float %1
153  %3 = fcmp oeq float %1, %2
154  %4 = zext i1 %3 to i32
155  ret i32 %4
156}
157
158; This function performs extra work to ensure that
159; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor.
160define float @fsgnjn_s(float %a, float %b) nounwind {
161; RV32IF-LABEL: fsgnjn_s:
162; RV32IF:       # %bb.0:
163; RV32IF-NEXT:    fmv.w.x ft0, a1
164; RV32IF-NEXT:    fmv.w.x ft1, a0
165; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
166; RV32IF-NEXT:    fsgnjn.s ft0, ft1, ft0
167; RV32IF-NEXT:    fmv.x.w a0, ft0
168; RV32IF-NEXT:    ret
169;
170; RV64IF-LABEL: fsgnjn_s:
171; RV64IF:       # %bb.0:
172; RV64IF-NEXT:    fmv.w.x ft0, a1
173; RV64IF-NEXT:    fmv.w.x ft1, a0
174; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
175; RV64IF-NEXT:    fsgnjn.s ft0, ft1, ft0
176; RV64IF-NEXT:    fmv.x.w a0, ft0
177; RV64IF-NEXT:    ret
178  %1 = fadd float %a, %b
179  %2 = fneg float %1
180  %3 = call float @llvm.copysign.f32(float %a, float %2)
181  ret float %3
182}
183
184declare float @llvm.fabs.f32(float)
185
186; This function performs extra work to ensure that
187; DAGCombiner::visitBITCAST doesn't replace the fabs with an and.
188define float @fabs_s(float %a, float %b) nounwind {
189; RV32IF-LABEL: fabs_s:
190; RV32IF:       # %bb.0:
191; RV32IF-NEXT:    fmv.w.x ft0, a1
192; RV32IF-NEXT:    fmv.w.x ft1, a0
193; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
194; RV32IF-NEXT:    fabs.s ft1, ft0
195; RV32IF-NEXT:    fadd.s ft0, ft1, ft0
196; RV32IF-NEXT:    fmv.x.w a0, ft0
197; RV32IF-NEXT:    ret
198;
199; RV64IF-LABEL: fabs_s:
200; RV64IF:       # %bb.0:
201; RV64IF-NEXT:    fmv.w.x ft0, a1
202; RV64IF-NEXT:    fmv.w.x ft1, a0
203; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
204; RV64IF-NEXT:    fabs.s ft1, ft0
205; RV64IF-NEXT:    fadd.s ft0, ft1, ft0
206; RV64IF-NEXT:    fmv.x.w a0, ft0
207; RV64IF-NEXT:    ret
208  %1 = fadd float %a, %b
209  %2 = call float @llvm.fabs.f32(float %1)
210  %3 = fadd float %2, %1
211  ret float %3
212}
213
214declare float @llvm.minnum.f32(float, float)
215
216define float @fmin_s(float %a, float %b) nounwind {
217; RV32IF-LABEL: fmin_s:
218; RV32IF:       # %bb.0:
219; RV32IF-NEXT:    fmv.w.x ft0, a1
220; RV32IF-NEXT:    fmv.w.x ft1, a0
221; RV32IF-NEXT:    fmin.s ft0, ft1, ft0
222; RV32IF-NEXT:    fmv.x.w a0, ft0
223; RV32IF-NEXT:    ret
224;
225; RV64IF-LABEL: fmin_s:
226; RV64IF:       # %bb.0:
227; RV64IF-NEXT:    fmv.w.x ft0, a1
228; RV64IF-NEXT:    fmv.w.x ft1, a0
229; RV64IF-NEXT:    fmin.s ft0, ft1, ft0
230; RV64IF-NEXT:    fmv.x.w a0, ft0
231; RV64IF-NEXT:    ret
232  %1 = call float @llvm.minnum.f32(float %a, float %b)
233  ret float %1
234}
235
236declare float @llvm.maxnum.f32(float, float)
237
238define float @fmax_s(float %a, float %b) nounwind {
239; RV32IF-LABEL: fmax_s:
240; RV32IF:       # %bb.0:
241; RV32IF-NEXT:    fmv.w.x ft0, a1
242; RV32IF-NEXT:    fmv.w.x ft1, a0
243; RV32IF-NEXT:    fmax.s ft0, ft1, ft0
244; RV32IF-NEXT:    fmv.x.w a0, ft0
245; RV32IF-NEXT:    ret
246;
247; RV64IF-LABEL: fmax_s:
248; RV64IF:       # %bb.0:
249; RV64IF-NEXT:    fmv.w.x ft0, a1
250; RV64IF-NEXT:    fmv.w.x ft1, a0
251; RV64IF-NEXT:    fmax.s ft0, ft1, ft0
252; RV64IF-NEXT:    fmv.x.w a0, ft0
253; RV64IF-NEXT:    ret
254  %1 = call float @llvm.maxnum.f32(float %a, float %b)
255  ret float %1
256}
257
258define i32 @feq_s(float %a, float %b) nounwind {
259; RV32IF-LABEL: feq_s:
260; RV32IF:       # %bb.0:
261; RV32IF-NEXT:    fmv.w.x ft0, a1
262; RV32IF-NEXT:    fmv.w.x ft1, a0
263; RV32IF-NEXT:    feq.s a0, ft1, ft0
264; RV32IF-NEXT:    ret
265;
266; RV64IF-LABEL: feq_s:
267; RV64IF:       # %bb.0:
268; RV64IF-NEXT:    fmv.w.x ft0, a1
269; RV64IF-NEXT:    fmv.w.x ft1, a0
270; RV64IF-NEXT:    feq.s a0, ft1, ft0
271; RV64IF-NEXT:    ret
272  %1 = fcmp oeq float %a, %b
273  %2 = zext i1 %1 to i32
274  ret i32 %2
275}
276
277define i32 @flt_s(float %a, float %b) nounwind {
278; RV32IF-LABEL: flt_s:
279; RV32IF:       # %bb.0:
280; RV32IF-NEXT:    fmv.w.x ft0, a1
281; RV32IF-NEXT:    fmv.w.x ft1, a0
282; RV32IF-NEXT:    flt.s a0, ft1, ft0
283; RV32IF-NEXT:    ret
284;
285; RV64IF-LABEL: flt_s:
286; RV64IF:       # %bb.0:
287; RV64IF-NEXT:    fmv.w.x ft0, a1
288; RV64IF-NEXT:    fmv.w.x ft1, a0
289; RV64IF-NEXT:    flt.s a0, ft1, ft0
290; RV64IF-NEXT:    ret
291  %1 = fcmp olt float %a, %b
292  %2 = zext i1 %1 to i32
293  ret i32 %2
294}
295
296define i32 @fle_s(float %a, float %b) nounwind {
297; RV32IF-LABEL: fle_s:
298; RV32IF:       # %bb.0:
299; RV32IF-NEXT:    fmv.w.x ft0, a1
300; RV32IF-NEXT:    fmv.w.x ft1, a0
301; RV32IF-NEXT:    fle.s a0, ft1, ft0
302; RV32IF-NEXT:    ret
303;
304; RV64IF-LABEL: fle_s:
305; RV64IF:       # %bb.0:
306; RV64IF-NEXT:    fmv.w.x ft0, a1
307; RV64IF-NEXT:    fmv.w.x ft1, a0
308; RV64IF-NEXT:    fle.s a0, ft1, ft0
309; RV64IF-NEXT:    ret
310  %1 = fcmp ole float %a, %b
311  %2 = zext i1 %1 to i32
312  ret i32 %2
313}
314
315declare float @llvm.fma.f32(float, float, float)
316
317define float @fmadd_s(float %a, float %b, float %c) nounwind {
318; RV32IF-LABEL: fmadd_s:
319; RV32IF:       # %bb.0:
320; RV32IF-NEXT:    fmv.w.x ft0, a2
321; RV32IF-NEXT:    fmv.w.x ft1, a1
322; RV32IF-NEXT:    fmv.w.x ft2, a0
323; RV32IF-NEXT:    fmadd.s ft0, ft2, ft1, ft0
324; RV32IF-NEXT:    fmv.x.w a0, ft0
325; RV32IF-NEXT:    ret
326;
327; RV64IF-LABEL: fmadd_s:
328; RV64IF:       # %bb.0:
329; RV64IF-NEXT:    fmv.w.x ft0, a2
330; RV64IF-NEXT:    fmv.w.x ft1, a1
331; RV64IF-NEXT:    fmv.w.x ft2, a0
332; RV64IF-NEXT:    fmadd.s ft0, ft2, ft1, ft0
333; RV64IF-NEXT:    fmv.x.w a0, ft0
334; RV64IF-NEXT:    ret
335  %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
336  ret float %1
337}
338
339define float @fmsub_s(float %a, float %b, float %c) nounwind {
340; RV32IF-LABEL: fmsub_s:
341; RV32IF:       # %bb.0:
342; RV32IF-NEXT:    lui a3, %hi(.LCPI15_0)
343; RV32IF-NEXT:    addi a3, a3, %lo(.LCPI15_0)
344; RV32IF-NEXT:    flw ft0, 0(a3)
345; RV32IF-NEXT:    fmv.w.x ft1, a1
346; RV32IF-NEXT:    fmv.w.x ft2, a0
347; RV32IF-NEXT:    fmv.w.x ft3, a2
348; RV32IF-NEXT:    fadd.s ft0, ft3, ft0
349; RV32IF-NEXT:    fmsub.s ft0, ft2, ft1, ft0
350; RV32IF-NEXT:    fmv.x.w a0, ft0
351; RV32IF-NEXT:    ret
352;
353; RV64IF-LABEL: fmsub_s:
354; RV64IF:       # %bb.0:
355; RV64IF-NEXT:    lui a3, %hi(.LCPI15_0)
356; RV64IF-NEXT:    addi a3, a3, %lo(.LCPI15_0)
357; RV64IF-NEXT:    flw ft0, 0(a3)
358; RV64IF-NEXT:    fmv.w.x ft1, a1
359; RV64IF-NEXT:    fmv.w.x ft2, a0
360; RV64IF-NEXT:    fmv.w.x ft3, a2
361; RV64IF-NEXT:    fadd.s ft0, ft3, ft0
362; RV64IF-NEXT:    fmsub.s ft0, ft2, ft1, ft0
363; RV64IF-NEXT:    fmv.x.w a0, ft0
364; RV64IF-NEXT:    ret
365  %c_ = fadd float 0.0, %c ; avoid negation using xor
366  %negc = fsub float -0.0, %c_
367  %1 = call float @llvm.fma.f32(float %a, float %b, float %negc)
368  ret float %1
369}
370
371define float @fnmadd_s(float %a, float %b, float %c) nounwind {
372; RV32IF-LABEL: fnmadd_s:
373; RV32IF:       # %bb.0:
374; RV32IF-NEXT:    lui a3, %hi(.LCPI16_0)
375; RV32IF-NEXT:    addi a3, a3, %lo(.LCPI16_0)
376; RV32IF-NEXT:    flw ft0, 0(a3)
377; RV32IF-NEXT:    fmv.w.x ft1, a1
378; RV32IF-NEXT:    fmv.w.x ft2, a2
379; RV32IF-NEXT:    fmv.w.x ft3, a0
380; RV32IF-NEXT:    fadd.s ft3, ft3, ft0
381; RV32IF-NEXT:    fadd.s ft0, ft2, ft0
382; RV32IF-NEXT:    fnmadd.s ft0, ft3, ft1, ft0
383; RV32IF-NEXT:    fmv.x.w a0, ft0
384; RV32IF-NEXT:    ret
385;
386; RV64IF-LABEL: fnmadd_s:
387; RV64IF:       # %bb.0:
388; RV64IF-NEXT:    lui a3, %hi(.LCPI16_0)
389; RV64IF-NEXT:    addi a3, a3, %lo(.LCPI16_0)
390; RV64IF-NEXT:    flw ft0, 0(a3)
391; RV64IF-NEXT:    fmv.w.x ft1, a1
392; RV64IF-NEXT:    fmv.w.x ft2, a2
393; RV64IF-NEXT:    fmv.w.x ft3, a0
394; RV64IF-NEXT:    fadd.s ft3, ft3, ft0
395; RV64IF-NEXT:    fadd.s ft0, ft2, ft0
396; RV64IF-NEXT:    fnmadd.s ft0, ft3, ft1, ft0
397; RV64IF-NEXT:    fmv.x.w a0, ft0
398; RV64IF-NEXT:    ret
399  %a_ = fadd float 0.0, %a
400  %c_ = fadd float 0.0, %c
401  %nega = fsub float -0.0, %a_
402  %negc = fsub float -0.0, %c_
403  %1 = call float @llvm.fma.f32(float %nega, float %b, float %negc)
404  ret float %1
405}
406
407define float @fnmsub_s(float %a, float %b, float %c) nounwind {
408; RV32IF-LABEL: fnmsub_s:
409; RV32IF:       # %bb.0:
410; RV32IF-NEXT:    lui a3, %hi(.LCPI17_0)
411; RV32IF-NEXT:    addi a3, a3, %lo(.LCPI17_0)
412; RV32IF-NEXT:    flw ft0, 0(a3)
413; RV32IF-NEXT:    fmv.w.x ft1, a2
414; RV32IF-NEXT:    fmv.w.x ft2, a1
415; RV32IF-NEXT:    fmv.w.x ft3, a0
416; RV32IF-NEXT:    fadd.s ft0, ft3, ft0
417; RV32IF-NEXT:    fnmsub.s ft0, ft0, ft2, ft1
418; RV32IF-NEXT:    fmv.x.w a0, ft0
419; RV32IF-NEXT:    ret
420;
421; RV64IF-LABEL: fnmsub_s:
422; RV64IF:       # %bb.0:
423; RV64IF-NEXT:    lui a3, %hi(.LCPI17_0)
424; RV64IF-NEXT:    addi a3, a3, %lo(.LCPI17_0)
425; RV64IF-NEXT:    flw ft0, 0(a3)
426; RV64IF-NEXT:    fmv.w.x ft1, a2
427; RV64IF-NEXT:    fmv.w.x ft2, a1
428; RV64IF-NEXT:    fmv.w.x ft3, a0
429; RV64IF-NEXT:    fadd.s ft0, ft3, ft0
430; RV64IF-NEXT:    fnmsub.s ft0, ft0, ft2, ft1
431; RV64IF-NEXT:    fmv.x.w a0, ft0
432; RV64IF-NEXT:    ret
433  %a_ = fadd float 0.0, %a
434  %nega = fsub float -0.0, %a_
435  %1 = call float @llvm.fma.f32(float %nega, float %b, float %c)
436  ret float %1
437}
438