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
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.
11 define float @fadd_s(float %a, float %b) nounwind {
12 ; RV32IF-LABEL: fadd_s:
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
20 ; RV64IF-LABEL: fadd_s:
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
27 %1 = fadd float %a, %b
31 define float @fsub_s(float %a, float %b) nounwind {
32 ; RV32IF-LABEL: fsub_s:
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
40 ; RV64IF-LABEL: fsub_s:
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
47 %1 = fsub float %a, %b
51 define float @fmul_s(float %a, float %b) nounwind {
52 ; RV32IF-LABEL: fmul_s:
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
60 ; RV64IF-LABEL: fmul_s:
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
67 %1 = fmul float %a, %b
71 define float @fdiv_s(float %a, float %b) nounwind {
72 ; RV32IF-LABEL: fdiv_s:
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
80 ; RV64IF-LABEL: fdiv_s:
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
87 %1 = fdiv float %a, %b
91 declare float @llvm.sqrt.f32(float)
93 define float @fsqrt_s(float %a) nounwind {
94 ; RV32IF-LABEL: fsqrt_s:
96 ; RV32IF-NEXT: fmv.w.x ft0, a0
97 ; RV32IF-NEXT: fsqrt.s ft0, ft0
98 ; RV32IF-NEXT: fmv.x.w a0, ft0
101 ; RV64IF-LABEL: fsqrt_s:
103 ; RV64IF-NEXT: fmv.w.x ft0, a0
104 ; RV64IF-NEXT: fsqrt.s ft0, ft0
105 ; RV64IF-NEXT: fmv.x.w a0, ft0
107 %1 = call float @llvm.sqrt.f32(float %a)
111 declare float @llvm.copysign.f32(float, float)
113 define float @fsgnj_s(float %a, float %b) nounwind {
114 ; RV32IF-LABEL: fsgnj_s:
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
122 ; RV64IF-LABEL: fsgnj_s:
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
129 %1 = call float @llvm.copysign.f32(float %a, float %b)
133 ; This function performs extra work to ensure that
134 ; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor.
135 define i32 @fneg_s(float %a, float %b) nounwind {
136 ; RV32IF-LABEL: fneg_s:
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
144 ; RV64IF-LABEL: fneg_s:
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
151 %1 = fadd float %a, %a
153 %3 = fcmp oeq float %1, %2
154 %4 = zext i1 %3 to i32
158 ; This function performs extra work to ensure that
159 ; DAGCombiner::visitBITCAST doesn't replace the fneg with an xor.
160 define float @fsgnjn_s(float %a, float %b) nounwind {
161 ; RV32IF-LABEL: fsgnjn_s:
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
170 ; RV64IF-LABEL: fsgnjn_s:
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
178 %1 = fadd float %a, %b
180 %3 = call float @llvm.copysign.f32(float %a, float %2)
184 declare float @llvm.fabs.f32(float)
186 ; This function performs extra work to ensure that
187 ; DAGCombiner::visitBITCAST doesn't replace the fabs with an and.
188 define float @fabs_s(float %a, float %b) nounwind {
189 ; RV32IF-LABEL: fabs_s:
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
199 ; RV64IF-LABEL: fabs_s:
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
208 %1 = fadd float %a, %b
209 %2 = call float @llvm.fabs.f32(float %1)
210 %3 = fadd float %2, %1
214 declare float @llvm.minnum.f32(float, float)
216 define float @fmin_s(float %a, float %b) nounwind {
217 ; RV32IF-LABEL: fmin_s:
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
225 ; RV64IF-LABEL: fmin_s:
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
232 %1 = call float @llvm.minnum.f32(float %a, float %b)
236 declare float @llvm.maxnum.f32(float, float)
238 define float @fmax_s(float %a, float %b) nounwind {
239 ; RV32IF-LABEL: fmax_s:
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
247 ; RV64IF-LABEL: fmax_s:
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
254 %1 = call float @llvm.maxnum.f32(float %a, float %b)
258 define i32 @feq_s(float %a, float %b) nounwind {
259 ; RV32IF-LABEL: feq_s:
261 ; RV32IF-NEXT: fmv.w.x ft0, a1
262 ; RV32IF-NEXT: fmv.w.x ft1, a0
263 ; RV32IF-NEXT: feq.s a0, ft1, ft0
266 ; RV64IF-LABEL: feq_s:
268 ; RV64IF-NEXT: fmv.w.x ft0, a1
269 ; RV64IF-NEXT: fmv.w.x ft1, a0
270 ; RV64IF-NEXT: feq.s a0, ft1, ft0
272 %1 = fcmp oeq float %a, %b
273 %2 = zext i1 %1 to i32
277 define i32 @flt_s(float %a, float %b) nounwind {
278 ; RV32IF-LABEL: flt_s:
280 ; RV32IF-NEXT: fmv.w.x ft0, a1
281 ; RV32IF-NEXT: fmv.w.x ft1, a0
282 ; RV32IF-NEXT: flt.s a0, ft1, ft0
285 ; RV64IF-LABEL: flt_s:
287 ; RV64IF-NEXT: fmv.w.x ft0, a1
288 ; RV64IF-NEXT: fmv.w.x ft1, a0
289 ; RV64IF-NEXT: flt.s a0, ft1, ft0
291 %1 = fcmp olt float %a, %b
292 %2 = zext i1 %1 to i32
296 define i32 @fle_s(float %a, float %b) nounwind {
297 ; RV32IF-LABEL: fle_s:
299 ; RV32IF-NEXT: fmv.w.x ft0, a1
300 ; RV32IF-NEXT: fmv.w.x ft1, a0
301 ; RV32IF-NEXT: fle.s a0, ft1, ft0
304 ; RV64IF-LABEL: fle_s:
306 ; RV64IF-NEXT: fmv.w.x ft0, a1
307 ; RV64IF-NEXT: fmv.w.x ft1, a0
308 ; RV64IF-NEXT: fle.s a0, ft1, ft0
310 %1 = fcmp ole float %a, %b
311 %2 = zext i1 %1 to i32
315 declare float @llvm.fma.f32(float, float, float)
317 define float @fmadd_s(float %a, float %b, float %c) nounwind {
318 ; RV32IF-LABEL: fmadd_s:
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
327 ; RV64IF-LABEL: fmadd_s:
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
335 %1 = call float @llvm.fma.f32(float %a, float %b, float %c)
339 define float @fmsub_s(float %a, float %b, float %c) nounwind {
340 ; RV32IF-LABEL: fmsub_s:
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
353 ; RV64IF-LABEL: fmsub_s:
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
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)
371 define float @fnmadd_s(float %a, float %b, float %c) nounwind {
372 ; RV32IF-LABEL: fnmadd_s:
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
386 ; RV64IF-LABEL: fnmadd_s:
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
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)
407 define float @fnmsub_s(float %a, float %b, float %c) nounwind {
408 ; RV32IF-LABEL: fnmsub_s:
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
421 ; RV64IF-LABEL: fnmsub_s:
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
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)