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


Reply via email to