@samitouri / QOSamiQemu / commits / d8be495376

fpu: Add conversion routines for OCP FP8 E5M2

Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Signed-off-by: Max Chou <max.chou@sifive.com> [rth: Split out of a larger patch] Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Max Chou committed Feb 5, 2026 at 17:35 UTC d8be49537658faef90722ca5fcd606cd09e91a7b
3 files changed +98
fpu/softfloat.c
+85
@@ -572,6 +572,10 @@ typedef struct {
572 .frac_shift = (-F - 1) & 63, \
573 .round_mask = (1ull << ((-F - 1) & 63)) - 1
574
575 +static const FloatFmt float8_e5m2_params = {
576 + FLOAT_PARAMS(5, 2)
577 +};
578 +
579 static const FloatFmt float16_params = {
580 FLOAT_PARAMS(5, 10)
581 };
@@ -627,6 +631,11 @@ static void unpack_raw64(FloatParts64 *r, const FloatFmt *fmt, uint64_t raw)
631 };
632 }
633
634 +static void QEMU_FLATTEN float8_e5m2_unpack_raw(FloatParts64 *p, float8_e5m2 f)
635 +{
636 + unpack_raw64(p, &float8_e5m2_params, f);
637 +}
638 +
639 static void QEMU_FLATTEN float16_unpack_raw(FloatParts64 *p, float16 f)
640 {
641 unpack_raw64(p, &float16_params, f);
@@ -684,6 +693,11 @@ static uint64_t pack_raw64(const FloatParts64 *p, const FloatFmt *fmt)
693 return ret;
694 }
695
696 +static float8_e5m2 QEMU_FLATTEN float8_e5m2_pack_raw(const FloatParts64 *p)
697 +{
698 + return pack_raw64(p, &float8_e5m2_params);
699 +}
700 +
701 static float16 QEMU_FLATTEN float16_pack_raw(const FloatParts64 *p)
702 {
703 return make_float16(pack_raw64(p, &float16_params));
@@ -1675,6 +1689,13 @@ static const uint16_t rsqrt_tab[128] = {
1689 * Pack/unpack routines with a specific FloatFmt.
1690 */
1691
1692 +static void float8_e5m2_unpack_canonical(FloatParts64 *p, float8_e5m2 f,
1693 + float_status *s)
1694 +{
1695 + float8_e5m2_unpack_raw(p, f);
1696 + parts_canonicalize(p, s, &float8_e5m2_params);
1697 +}
1698 +
1699 static void float16a_unpack_canonical(FloatParts64 *p, float16 f,
1700 float_status *s, const FloatFmt *params)
1701 {
@@ -1695,6 +1716,14 @@ static void bfloat16_unpack_canonical(FloatParts64 *p, bfloat16 f,
1716 parts_canonicalize(p, s, &bfloat16_params);
1717 }
1718
1719 +static float8_e5m2 float8_e5m2_round_pack_canonical(FloatParts64 *p,
1720 + float_status *s,
1721 + bool saturate)
1722 +{
1723 + parts_uncanon(p, s, &float8_e5m2_params, saturate);
1724 + return float8_e5m2_pack_raw(p);
1725 +}
1726 +
1727 static float16 float16a_round_pack_canonical(FloatParts64 *p,
1728 float_status *s,
1729 const FloatFmt *params)
@@ -2772,6 +2801,35 @@ static void parts_float_to_ahp(FloatParts64 *a, float_status *s)
2801 }
2802 }
2803
2804 +static void parts_float_to_e5m2(FloatParts64 *a, float_status *s, bool saturate)
2805 +{
2806 + switch (a->cls) {
2807 + case float_class_snan:
2808 + case float_class_qnan:
2809 + parts_return_nan(a, s);
2810 + break;
2811 +
2812 + case float_class_inf:
2813 + /* Per OCP, conversion in SATURATE mode bounds Inf to MAX. */
2814 + if (saturate) {
2815 + a->cls = float_class_normal;
2816 + a->exp = float8_e5m2_params.exp_max - 1;
2817 + a->frac = MAKE_64BIT_MASK(float8_e5m2_params.frac_shift,
2818 + float8_e5m2_params.frac_size + 1);
2819 + }
2820 + break;
2821 +
2822 + case float_class_denormal:
2823 + float_raise(float_flag_input_denormal_used, s);
2824 + break;
2825 + case float_class_normal:
2826 + case float_class_zero:
2827 + break;
2828 + default:
2829 + g_assert_not_reached();
2830 + }
2831 +}
2832 +
2833 static void parts64_float_to_float(FloatParts64 *a, float_status *s)
2834 {
2835 if (is_nan(a->cls)) {
@@ -2836,6 +2894,15 @@ static void parts_float_to_float_widen(FloatParts128 *a, FloatParts64 *b,
2894 }
2895 }
2896
2897 +bfloat16 float8_e5m2_to_bfloat16(float8_e5m2 a, float_status *s)
2898 +{
2899 + FloatParts64 p;
2900 +
2901 + float8_e5m2_unpack_canonical(&p, a, s);
2902 + parts_float_to_float(&p, s);
2903 + return bfloat16_round_pack_canonical(&p, s);
2904 +}
2905 +
2906 float32 float16_to_float32(float16 a, bool ieee, float_status *s)
2907 {
2908 const FloatFmt *fmt16 = ieee ? &float16_params : &float16_params_ahp;
@@ -2856,6 +2923,15 @@ float64 float16_to_float64(float16 a, bool ieee, float_status *s)
2923 return float64_round_pack_canonical(&p, s);
2924 }
2925
2926 +float8_e5m2 float32_to_float8_e5m2(float32 a, bool saturate, float_status *s)
2927 +{
2928 + FloatParts64 p;
2929 +
2930 + float32_unpack_canonical(&p, a, s);
2931 + parts_float_to_e5m2(&p, s, saturate);
2932 + return float8_e5m2_round_pack_canonical(&p, s, saturate);
2933 +}
2934 +
2935 float16 float32_to_float16(float32 a, bool ieee, float_status *s)
2936 {
2937 FloatParts64 p;
@@ -2923,6 +2999,15 @@ float32 float64_to_float32(float64 a, float_status *s)
2999 return float32_round_pack_canonical(&p, s);
3000 }
3001
3002 +float8_e5m2 bfloat16_to_float8_e5m2(bfloat16 a, bool saturate, float_status *s)
3003 +{
3004 + FloatParts64 p;
3005 +
3006 + bfloat16_unpack_canonical(&p, a, s);
3007 + parts_float_to_e5m2(&p, s, saturate);
3008 + return float8_e5m2_round_pack_canonical(&p, s, saturate);
3009 +}
3010 +
3011 float32 bfloat16_to_float32(bfloat16 a, float_status *s)
3012 {
3013 FloatParts64 p;
include/fpu/softfloat-types.h
+5
@@ -119,6 +119,11 @@ typedef struct {
119 */
120 typedef uint16_t bfloat16;
121
122 +/*
123 + * Open Compute Project (OCP) Microscaling Formats
124 + */
125 +typedef uint8_t float8_e5m2;
126 +
127 /*
128 * Software IEC/IEEE floating-point underflow tininess-detection mode.
129 */
include/fpu/softfloat.h
+8
@@ -189,6 +189,14 @@ float128 int128_to_float128(Int128, float_status *status);
189 float128 uint64_to_float128(uint64_t, float_status *status);
190 float128 uint128_to_float128(Int128, float_status *status);
191
192 +/*----------------------------------------------------------------------------
193 +| OCP FP8 conversion routines.
194 +*----------------------------------------------------------------------------*/
195 +
196 +bfloat16 float8_e5m2_to_bfloat16(float8_e5m2, float_status *status);
197 +float8_e5m2 bfloat16_to_float8_e5m2(bfloat16, bool sat, float_status *status);
198 +float8_e5m2 float32_to_float8_e5m2(float32, bool sat, float_status *status);
199 +
200 /*----------------------------------------------------------------------------
201 | Software half-precision conversion routines.
202 *----------------------------------------------------------------------------*/