Use Align for TFL::TransientStackAlignment
[llvm-core.git] / test / CodeGen / RISCV / float-arith.ll
blob5244a69a6fad0607561281974cc2683deced0be1
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:
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
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
31 define 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
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
51 define 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
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
71 define 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
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
91 declare float @llvm.sqrt.f32(float)
93 define 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
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
111 declare float @llvm.copysign.f32(float, float)
113 define 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
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
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:
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
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
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:
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
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
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:
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
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
214 declare float @llvm.minnum.f32(float, float)
216 define 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
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
236 declare float @llvm.maxnum.f32(float, float)
238 define 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
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
258 define 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
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
277 define 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
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
296 define 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
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
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:
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
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
339 define 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
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
371 define 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
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
407 define 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
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