This commit provides the implementation defined behavior flags and the basic operation support for the OCP float8 data types(E4M3 & E5M2).
Signed-off-by: Max Chou <[email protected]> --- fpu/softfloat-specialize.c.inc | 57 ++++++++++++++++++++++++++- include/fpu/softfloat-helpers.h | 20 ++++++++++ include/fpu/softfloat-types.h | 23 +++++++++++ include/fpu/softfloat.h | 70 +++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 1 deletion(-) diff --git a/fpu/softfloat-specialize.c.inc b/fpu/softfloat-specialize.c.inc index ba4fa08b7b..3a3bcd22ae 100644 --- a/fpu/softfloat-specialize.c.inc +++ b/fpu/softfloat-specialize.c.inc @@ -226,6 +226,30 @@ floatx80 floatx80_default_inf(bool zSign, float_status *status) return packFloatx80(zSign, 0x7fff, z ? 0 : (1ULL << 63)); } +/*---------------------------------------------------------------------------- +| Returns 1 if the OCP(Open Compute Platform) FP8 value `a' is a quiet NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +bool float8_e4m3_is_quiet_nan(float8_e4m3 a_, float_status *status) +{ + return float8_e4m3_is_any_nan(a_); +} + +bool float8_e5m2_is_quiet_nan(float8_e5m2 a_, float_status *status) +{ + if (no_signaling_nans(status) || status->ocp_fp8e5m2_no_signal_nan) { + return float8_e5m2_is_any_nan(a_); + } else { + uint8_t a = float8_e5m2_val(a_); + if (snan_bit_is_one(status)) { + return (((a >> 1) & 0x3F) == 0x3E) && (a & 0x1); + } else { + return ((a >> 1) & 0x3F) == 0x3F; + } + } +} + /*---------------------------------------------------------------------------- | Returns 1 if the half-precision floating-point value `a' is a quiet | NaN; otherwise returns 0. @@ -240,7 +264,6 @@ bool float16_is_quiet_nan(float16 a_, float_status *status) if (snan_bit_is_one(status)) { return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); } else { - return ((a >> 9) & 0x3F) == 0x3F; } } @@ -265,6 +288,38 @@ bool bfloat16_is_quiet_nan(bfloat16 a_, float_status *status) } } +/*---------------------------------------------------------------------------- +| Returns 1 if the OCP(Open Compute Platform) FP8 value `a' is a signaling NaN; +| otherwise returns 0. +*----------------------------------------------------------------------------*/ + +bool float8_e4m3_is_signaling_nan(float8_e4m3 a_, float_status *status) +{ + if (no_signaling_nans(status)) { + return false; + } else { + if (snan_bit_is_one(status)) { + return float8_e4m3_is_any_nan(a_); + } else { + return false; + } + } +} + +bool float8_e5m2_is_signaling_nan(float8_e5m2 a_, float_status *status) +{ + if (no_signaling_nans(status)) { + return false; + } else { + uint8_t a = float8_e5m2_val(a_); + if (snan_bit_is_one(status)) { + return ((a >> 1) & 0x3F) == 0x3F; + } else { + return (((a >> 1) & 0x3F) == 0x3E && (a & 0x1)); + } + } +} + /*---------------------------------------------------------------------------- | Returns 1 if the half-precision floating-point value `a' is a signaling | NaN; otherwise returns 0. diff --git a/include/fpu/softfloat-helpers.h b/include/fpu/softfloat-helpers.h index 90862f5cd2..4e278a3ee3 100644 --- a/include/fpu/softfloat-helpers.h +++ b/include/fpu/softfloat-helpers.h @@ -136,6 +136,26 @@ static inline void set_no_signaling_nans(bool val, float_status *status) status->no_signaling_nans = val; } +static inline void set_ocp_fp8e5m2_no_signal_nan(bool val, float_status *status) +{ + status->ocp_fp8e5m2_no_signal_nan = val; +} + +static inline bool get_ocp_fp8e5m2_no_signal_nan(const float_status *status) +{ + return status->ocp_fp8e5m2_no_signal_nan; +} + +static inline void set_ocp_fp8_same_canonical_nan(bool val, float_status *status) +{ + status->ocp_fp8_same_canonical_nan = val; +} + +static inline bool get_ocp_fp8_same_canonical_nan(const float_status *status) +{ + return status->ocp_fp8_same_canonical_nan; +} + static inline bool get_float_detect_tininess(const float_status *status) { return status->tininess_before_rounding; diff --git a/include/fpu/softfloat-types.h b/include/fpu/softfloat-types.h index 8f82fdfc97..835dd33bf1 100644 --- a/include/fpu/softfloat-types.h +++ b/include/fpu/softfloat-types.h @@ -119,6 +119,18 @@ typedef struct { */ typedef uint16_t bfloat16; +/* + * Software OCP(Open Compute Project) 8-bit floating point types + */ +typedef uint8_t float8_e4m3; +typedef uint8_t float8_e5m2; +#define float8_e4m3_val(x) (x) +#define float8_e5m2_val(x) (x) +#define make_float8_e4m3(x) (x) +#define make_float8_e5m2(x) (x) +#define const_float8_e4m3(x) (x) +#define const_float8_e5m2(x) (x) + /* * Software IEC/IEEE floating-point underflow tininess-detection mode. */ @@ -410,6 +422,17 @@ typedef struct float_status { */ bool snan_bit_is_one; bool no_signaling_nans; + /* + * When true, OCP FP8 E5M2 format does not generate signaling NaNs. + * RISC-V uses only quiet NaNs in its OCP FP8 implementation. + */ + bool ocp_fp8e5m2_no_signal_nan; + /* + * When true, OCP FP8 formats use the same canonical NaN representation + * (0x7F) for all NaN outputs. RISC-V specifies a single canonical NaN + * for both E4M3 and E5M2. + */ + bool ocp_fp8_same_canonical_nan; /* should overflowed results subtract re_bias to its exponent? */ bool rebias_overflow; /* should underflowed results add re_bias to its exponent? */ diff --git a/include/fpu/softfloat.h b/include/fpu/softfloat.h index c18ab2cb60..6f7259f9dd 100644 --- a/include/fpu/softfloat.h +++ b/include/fpu/softfloat.h @@ -189,6 +189,76 @@ float128 int128_to_float128(Int128, float_status *status); float128 uint64_to_float128(uint64_t, float_status *status); float128 uint128_to_float128(Int128, float_status *status); +/*---------------------------------------------------------------------------- +| Software OCP FP8 operations. +*----------------------------------------------------------------------------*/ + +bool float8_e4m3_is_quiet_nan(float8_e4m3, float_status *status); +bool float8_e4m3_is_signaling_nan(float8_e4m3, float_status *status); +bool float8_e5m2_is_quiet_nan(float8_e5m2, float_status *status); +bool float8_e5m2_is_signaling_nan(float8_e5m2, float_status *status); + +static inline bool float8_e4m3_is_any_nan(float8_e4m3 a) +{ + return ((float8_e4m3_val(a) & ~0x80) == 0x7f); +} + +static inline bool float8_e5m2_is_any_nan(float8_e5m2 a) +{ + return ((float8_e5m2_val(a) & ~0x80) > 0x7c); +} + +static inline bool float8_e4m3_is_neg(float8_e4m3 a) +{ + return float8_e4m3_val(a) >> 7; +} + +static inline bool float8_e5m2_is_neg(float8_e5m2 a) +{ + return float8_e5m2_val(a) >> 7; +} + +static inline bool float8_e4m3_is_infinity(float8_e4m3 a) +{ + return false; +} + +static inline bool float8_e5m2_is_infinity(float8_e5m2 a) +{ + return (float8_e5m2_val(a) & 0x7f) == 0x7c; +} + +static inline bool float8_e4m3_is_zero(float8_e4m3 a) +{ + return (float8_e4m3_val(a) & 0x7f) == 0; +} + +static inline bool float8_e5m2_is_zero(float8_e5m2 a) +{ + return (float8_e5m2_val(a) & 0x7f) == 0; +} + +static inline bool float8_e4m3_is_zero_or_denormal(float8_e4m3 a) +{ + return (float8_e4m3_val(a) & 0x78) == 0; +} + +static inline bool float8_e5m2_is_zero_or_denormal(float8_e5m2 a) +{ + return (float8_e5m2_val(a) & 0x7c) == 0; +} + +static inline bool float8_e4m3_is_normal(float8_e4m3 a) +{ + uint8_t em = float8_e4m3_val(a) & 0x7f; + return em >= 0x8 && em <= 0x7e; +} + +static inline bool float8_e5m2_is_normal(float8_e5m2 a) +{ + return (((float8_e5m2_val(a) >> 2) + 1) & 0x1f) >= 2; +} + /*---------------------------------------------------------------------------- | Software half-precision conversion routines. *----------------------------------------------------------------------------*/ -- 2.43.7
