|
| 1 | +// Copyright 2024 The Go Authors. All rights reserved. |
| 2 | +// Use of this source code is governed by a BSD-style |
| 3 | +// license that can be found in the LICENSE file. |
| 4 | + |
| 5 | +#include "textflag.h" |
| 6 | + |
| 7 | +// RISC-V offered floating-point (FP) rounding by FP conversion instructions (FCVT) |
| 8 | +// with rounding mode field. |
| 9 | +// As Go spec expects FP rounding result in FP, we have to use FCVT integer |
| 10 | +// back to FP (fp -> int -> fp). |
| 11 | +// RISC-V only set Inexact flag during invalid FP-integer conversion without changing any data, |
| 12 | +// on the other hand, RISC-V sets out of integer represent range yet valid FP into NaN. |
| 13 | +// When it comes to integer-FP conversion, invalid FP like NaN, +-Inf will be |
| 14 | +// converted into the closest valid FP, for example: |
| 15 | +// |
| 16 | +// `Floor(-Inf) -> int64(0x7fffffffffffffff) -> float64(9.22e+18)` |
| 17 | +// `Floor(18446744073709549568.0) -> int64(0x7fffffffffffffff) -> float64(9.22e+18)` |
| 18 | +// |
| 19 | +// This ISA conversion limitation requires we skip all invalid or out of range FP |
| 20 | +// before any normal rounding operations. |
| 21 | + |
| 22 | +#define ROUNDFN(NAME, MODE) \ |
| 23 | +TEXT NAME(SB),NOSPLIT,$0; \ |
| 24 | + MOVD x+0(FP), F10; \ |
| 25 | + FMVXD F10, X10; \ |
| 26 | + /* Drop all fraction bits */;\ |
| 27 | + SRL $52, X10, X12; \ |
| 28 | + /* Remove sign bit */; \ |
| 29 | + AND $0x7FF, X12, X12;\ |
| 30 | + /* Return either input is +-Inf, NaN(0x7FF) or out of precision limitation */;\ |
| 31 | + /* 1023: bias of exponent, [-2^53, 2^53]: exactly integer represent range */;\ |
| 32 | + MOV $1023+53, X11; \ |
| 33 | + BLTU X11, X12, 4(PC);\ |
| 34 | + FCVTLD.MODE F10, X11; \ |
| 35 | + FCVTDL X11, F11; \ |
| 36 | + /* RISC-V rounds negative values to +0, restore original sign */;\ |
| 37 | + FSGNJD F10, F11, F10; \ |
| 38 | + MOVD F10, ret+8(FP); \ |
| 39 | + RET |
| 40 | + |
| 41 | +// func archFloor(x float64) float64 |
| 42 | +ROUNDFN(·archFloor, RDN) |
| 43 | + |
| 44 | +// func archCeil(x float64) float64 |
| 45 | +ROUNDFN(·archCeil, RUP) |
| 46 | + |
| 47 | +// func archTrunc(x float64) float64 |
| 48 | +ROUNDFN(·archTrunc, RTZ) |
0 commit comments