From 0e35a2a8c92e4b5e1c00150044ebbf1ba0df1827 Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Mon, 10 Mar 2025 16:55:50 +0100 Subject: [PATCH] adds complete Zfh support, small rework regarding floating point interface --- src/vm/fp_functions.cpp | 104 +++++++++++++++++++++++++++++++++++- src/vm/fp_functions.h | 40 ++++++++++++-- src/vm/vector_functions.hpp | 24 ++------- 3 files changed, 144 insertions(+), 24 deletions(-) diff --git a/src/vm/fp_functions.cpp b/src/vm/fp_functions.cpp index 75b6903..ac48073 100644 --- a/src/vm/fp_functions.cpp +++ b/src/vm/fp_functions.cpp @@ -33,7 +33,9 @@ //////////////////////////////////////////////////////////////////////////////// #include "fp_functions.h" +#include "softfloat_types.h" #include +#include extern "C" { #include "internals.h" @@ -194,7 +196,7 @@ uint16_t fclass_h(uint16_t v1) { uA.f = a; uiA = uA.ui; - bool infOrNaN = expF16UI(uiA) == 0xFF; + bool infOrNaN = expF16UI(uiA) == 0x1F; bool subnormalOrZero = expF16UI(uiA) == 0; bool sign = signF16UI(uiA); bool fracZero = fracF16UI(uiA) == 0; @@ -206,6 +208,25 @@ uint16_t fclass_h(uint16_t v1) { (!sign && !infOrNaN && !subnormalOrZero) << 6 | (!sign && subnormalOrZero && !fracZero) << 5 | (!sign && subnormalOrZero && fracZero) << 4 | (isNaN && isSNaN) << 8 | (isNaN && !isSNaN) << 9; } +uint16_t unbox_h(uint8_t FLEN, uint64_t v) { + uint64_t mask = 0; + switch(FLEN) { + case 32: { + mask = std::numeric_limits::max() & ~((uint64_t)std::numeric_limits::max()); + break; + } + case 64: { + mask = std::numeric_limits::max() & ~((uint64_t)std::numeric_limits::max()); + break; + } + default: + break; + } + if((v & mask) != mask) + return 0x7e00; + else + return v & std::numeric_limits::max(); +} uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode) { float32_t v1f{v1}, v2f{v2}; @@ -864,4 +885,85 @@ uint64_t frec7_d(uint64_t v, uint8_t mode) { if(frec_general(ret_val, s, e, sign, exp, sig, subnormal, mode)) softfloat_exceptionFlags |= (softfloat_flag_inexact | softfloat_flag_overflow); return ret_val; +} + +// conversion: float to float +uint32_t f16tof32(uint16_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_f32(float16_t{val}).v; +} +uint64_t f16tof64(uint16_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_f64(float16_t{val}).v; +} + +uint16_t f32tof16(uint32_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f32_to_f16(float32_t{val}).v; +} +uint64_t f32tof64(uint32_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f32_to_f64(float32_t{val}).v; +} + +uint16_t f64tof16(uint64_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f64_to_f16(float64_t{val}).v; +} +uint32_t f64tof32(uint64_t val, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f64_to_f32(float64_t{val}).v; +} +// conversions: float to unsigned +uint32_t f16toui32(uint16_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_ui32(float16_t{v}, rm, true); +} +uint64_t f16toui64(uint16_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_ui64(float16_t{v}, rm, true); +} + +// conversions: float to signed +uint32_t f16toi32(uint16_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_i32(float16_t{v}, rm, true); +} +uint64_t f16toi64(uint16_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return f16_to_i64(float16_t{v}, rm, true); +} + +// conversions: unsigned to float +uint16_t ui32tof16(uint32_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return ui32_to_f16(v).v; +} +uint16_t ui64tof16(uint64_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return ui64_to_f16(v).v; +} + +// conversions: signed to float +uint16_t i32tof16(uint32_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return i32_to_f16(v).v; +} +uint16_t i64tof16(uint64_t v, uint8_t rm) { + softfloat_exceptionFlags = 0; + softfloat_roundingMode = rm; + return i64_to_f16(v).v; } \ No newline at end of file diff --git a/src/vm/fp_functions.h b/src/vm/fp_functions.h index 85b734e..964fa11 100644 --- a/src/vm/fp_functions.h +++ b/src/vm/fp_functions.h @@ -39,6 +39,7 @@ extern "C" { uint32_t fget_flags(); +// half precision uint16_t fadd_h(uint16_t v1, uint16_t v2, uint8_t mode); uint16_t fsub_h(uint16_t v1, uint16_t v2, uint8_t mode); uint16_t fmul_h(uint16_t v1, uint16_t v2, uint8_t mode); @@ -52,6 +53,9 @@ uint16_t fsqrt_h(uint16_t v1, uint8_t mode); uint16_t fclass_h(uint16_t v1); uint16_t frsqrt7_h(uint16_t v); uint16_t frec7_h(uint16_t v, uint8_t mode); +uint16_t unbox_h(uint8_t FLEN, uint64_t v); + +// single precision uint32_t fadd_s(uint32_t v1, uint32_t v2, uint8_t mode); uint32_t fsub_s(uint32_t v1, uint32_t v2, uint8_t mode); uint32_t fmul_s(uint32_t v1, uint32_t v2, uint8_t mode); @@ -64,8 +68,9 @@ uint32_t fsel_s(uint32_t v1, uint32_t v2, uint32_t op); uint32_t fclass_s(uint32_t v1); uint32_t frsqrt7_s(uint32_t v); uint32_t frec7_s(uint32_t v, uint8_t mode); -uint32_t fconv_d2f(uint64_t v1, uint8_t mode); -uint64_t fconv_f2d(uint32_t v1, uint8_t mode); +uint32_t unbox_s(uint64_t v); + +// double precision uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode); uint64_t fsub_d(uint64_t v1, uint64_t v2, uint8_t mode); uint64_t fmul_d(uint64_t v1, uint64_t v2, uint8_t mode); @@ -78,8 +83,37 @@ uint64_t fsel_d(uint64_t v1, uint64_t v2, uint32_t op); uint64_t fclass_d(uint64_t v1); uint64_t frsqrt7_d(uint64_t v); uint64_t frec7_d(uint64_t v, uint8_t mode); + +// conversions +uint32_t fconv_d2f(uint64_t v1, uint8_t mode); +uint64_t fconv_f2d(uint32_t v1, uint8_t mode); uint64_t fcvt_32_64(uint32_t v1, uint32_t op, uint8_t mode); uint32_t fcvt_64_32(uint64_t v1, uint32_t op, uint8_t mode); -uint32_t unbox_s(uint64_t v); + +// conversion: float to float +uint32_t f16tof32(uint16_t val, uint8_t rm); +uint64_t f16tof64(uint16_t val, uint8_t rm); + +uint16_t f32tof16(uint32_t val, uint8_t rm); +uint64_t f32tof64(uint32_t val, uint8_t rm); + +uint16_t f64tof16(uint64_t val, uint8_t rm); +uint32_t f64tof32(uint64_t val, uint8_t rm); + +// conversions: float to unsigned +uint32_t f16toui32(uint16_t v, uint8_t rm); +uint64_t f16toui64(uint16_t v, uint8_t rm); + +// conversions: float to signed +uint32_t f16toi32(uint16_t v, uint8_t rm); +uint64_t f16toi64(uint16_t v, uint8_t rm); + +// conversions: unsigned to float +uint16_t ui32tof16(uint32_t v, uint8_t rm); +uint16_t ui64tof16(uint64_t v, uint8_t rm); + +// conversions: signed to float +uint16_t i32tof16(uint32_t v, uint8_t rm); +uint16_t i64tof16(uint64_t v, uint8_t rm); } #endif /* _VM_FP_FUNCTIONS_H_ */ diff --git a/src/vm/vector_functions.hpp b/src/vm/vector_functions.hpp index 9beec73..d308a50 100644 --- a/src/vm/vector_functions.hpp +++ b/src/vm/vector_functions.hpp @@ -1541,16 +1541,8 @@ template <> inline uint64_t fp_i_to_f(uint8_t rm, uint32_t v template <> inline uint16_t fp_f_to_f(uint8_t rm, uint8_t val) { throw new std::runtime_error("Attempting illegal widening conversion"); } -template <> inline uint32_t fp_f_to_f(uint8_t rm, uint16_t val) { - softfloat_exceptionFlags = 0; - softfloat_roundingMode = rm; - return f16_to_f32(float16_t{val}).v; -} -template <> inline uint64_t fp_f_to_f(uint8_t rm, uint32_t val) { - softfloat_exceptionFlags = 0; - softfloat_roundingMode = rm; - return f32_to_f64(float32_t{val}).v; -} +template <> inline uint32_t fp_f_to_f(uint8_t rm, uint16_t val) { return f16tof32(val, rm); } +template <> inline uint64_t fp_f_to_f(uint8_t rm, uint32_t val) { return f32tof64(val, rm); } template std::function get_fp_widening_fn(unsigned unary_op) { @@ -1676,16 +1668,8 @@ template <> inline uint32_t fp_i_to_f(uint8_t rm, uint64_t v template <> inline uint8_t fp_f_to_f(uint8_t rm, uint16_t val) { throw new std::runtime_error("Attempting illegal narrowing conversion"); } -template <> inline uint16_t fp_f_to_f(uint8_t rm, uint32_t val) { - softfloat_exceptionFlags = 0; - softfloat_roundingMode = rm; - return f32_to_f16(float32_t{val}).v; -} -template <> inline uint32_t fp_f_to_f(uint8_t rm, uint64_t val) { - softfloat_exceptionFlags = 0; - softfloat_roundingMode = rm; - return f64_to_f32(float64_t{val}).v; -} +template <> inline uint16_t fp_f_to_f(uint8_t rm, uint32_t val) { return f32tof16(val, rm); } +template <> inline uint32_t fp_f_to_f(uint8_t rm, uint64_t val) { return f64tof32(val, rm); } template std::function get_fp_narrowing_fn(unsigned unary_op) { switch(unary_op) {