adds complete Zfh support, small rework regarding floating point interface

This commit is contained in:
Eyck-Alexander Jentzsch 2025-03-10 16:55:50 +01:00
parent 8220c00a3d
commit 0e35a2a8c9
3 changed files with 144 additions and 24 deletions

View File

@ -33,7 +33,9 @@
////////////////////////////////////////////////////////////////////////////////
#include "fp_functions.h"
#include "softfloat_types.h"
#include <array>
#include <cstdint>
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<uint32_t>::max() & ~((uint64_t)std::numeric_limits<uint16_t>::max());
break;
}
case 64: {
mask = std::numeric_limits<uint64_t>::max() & ~((uint64_t)std::numeric_limits<uint16_t>::max());
break;
}
default:
break;
}
if((v & mask) != mask)
return 0x7e00;
else
return v & std::numeric_limits<uint32_t>::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;
}

View File

@ -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_ */

View File

@ -1541,16 +1541,8 @@ template <> inline uint64_t fp_i_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t v
template <> inline uint16_t fp_f_to_f<uint16_t, uint8_t>(uint8_t rm, uint8_t val) {
throw new std::runtime_error("Attempting illegal widening conversion");
}
template <> inline uint32_t fp_f_to_f<uint32_t, uint16_t>(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<uint64_t, uint32_t>(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<uint32_t, uint16_t>(uint8_t rm, uint16_t val) { return f16tof32(val, rm); }
template <> inline uint64_t fp_f_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t val) { return f32tof64(val, rm); }
template <typename dest_elem_t, typename src_elem_t>
std::function<dest_elem_t(uint8_t, uint8_t&, src_elem_t)> get_fp_widening_fn(unsigned unary_op) {
@ -1676,16 +1668,8 @@ template <> inline uint32_t fp_i_to_f<uint32_t, uint64_t>(uint8_t rm, uint64_t v
template <> inline uint8_t fp_f_to_f<uint8_t, uint16_t>(uint8_t rm, uint16_t val) {
throw new std::runtime_error("Attempting illegal narrowing conversion");
}
template <> inline uint16_t fp_f_to_f<uint16_t, uint32_t>(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<uint32_t, uint64_t>(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<uint16_t, uint32_t>(uint8_t rm, uint32_t val) { return f32tof16(val, rm); }
template <> inline uint32_t fp_f_to_f<uint32_t, uint64_t>(uint8_t rm, uint64_t val) { return f64tof32(val, rm); }
template <typename dest_elem_t, typename src_elem_t>
std::function<dest_elem_t(uint8_t, uint8_t&, src_elem_t)> get_fp_narrowing_fn(unsigned unary_op) {
switch(unary_op) {