// Copyright 2024 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. #include "textflag.h" // RISC-V offered floating-point (FP) rounding by FP conversion instructions (FCVT) // with rounding mode field. // As Go spec expects FP rounding result in FP, we have to use FCVT integer // back to FP (fp -> int -> fp). // RISC-V only set Inexact flag during invalid FP-integer conversion without changing any data, // on the other hand, RISC-V sets out of integer represent range yet valid FP into NaN. // When it comes to integer-FP conversion, invalid FP like NaN, +-Inf will be // converted into the closest valid FP, for example: // // `Floor(-Inf) -> int64(0x7fffffffffffffff) -> float64(9.22e+18)` // `Floor(18446744073709549568.0) -> int64(0x7fffffffffffffff) -> float64(9.22e+18)` // // This ISA conversion limitation requires we skip all invalid or out of range FP // before any normal rounding operations. #define ROUNDFN(NAME, MODE) \ TEXT NAME(SB),NOSPLIT,$0; \ MOVD x+0(FP), F10; \ FMVXD F10, X10; \ /* Drop all fraction bits */;\ SRL $52, X10, X12; \ /* Remove sign bit */; \ AND $0x7FF, X12, X12;\ /* Return either input is +-Inf, NaN(0x7FF) or out of precision limitation */;\ /* 1023: bias of exponent, [-2^53, 2^53]: exactly integer represent range */;\ MOV $1023+53, X11; \ BLTU X11, X12, 4(PC);\ FCVTLD.MODE F10, X11; \ FCVTDL X11, F11; \ /* RISC-V rounds negative values to +0, restore original sign */;\ FSGNJD F10, F11, F10; \ MOVD F10, ret+8(FP); \ RET // func archFloor(x float64) float64 ROUNDFN(·archFloor, RDN) // func archCeil(x float64) float64 ROUNDFN(·archCeil, RUP) // func archTrunc(x float64) float64 ROUNDFN(·archTrunc, RTZ)