adds support for half precision float

This commit is contained in:
Eyck-Alexander Jentzsch 2025-03-09 13:40:11 +01:00
parent d9f1e5d31b
commit 7a7035f267
5 changed files with 545 additions and 179 deletions

View File

@ -755,7 +755,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_red_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_red_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
@ -767,7 +767,7 @@ if(vector != null) {%>
void fp_vector_red_wv(uint8_t* V, uint8_t funct6, uint8_t funct3, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t vs1, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_red_op<${vlen}, uint16_t, uint8_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b001:
return softvector::fp_vector_red_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
@ -782,7 +782,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_vector_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
@ -796,7 +796,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_imm_op<${vlen}, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011:
@ -810,7 +810,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_vector_op<${vlen}, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011: // would widen to 128 bits
@ -823,7 +823,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_imm_op<${vlen}, uint32_t, uint16_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint64_t, uint32_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011: // would widen to 128 bits
@ -836,7 +836,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_vector_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::fp_vector_vector_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011: // would widen to 128 bits
@ -849,7 +849,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_imm_op<${vlen}, uint32_t, uint32_t, uint16_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::fp_vector_imm_op<${vlen}, uint64_t, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011: // would widen to 128 bits
@ -862,7 +862,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_unary_op<${vlen}, uint16_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_op<${vlen}, uint32_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011:
@ -876,7 +876,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::mask_fp_vector_vector_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b010:
return softvector::mask_fp_vector_vector_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, vs1, rm);
case 0b011:
@ -890,7 +890,7 @@ if(vector != null) {%>
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
case 0b001:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::mask_fp_vector_imm_op<${vlen}, uint16_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b010:
return softvector::mask_fp_vector_imm_op<${vlen}, uint32_t>(V, funct6, vl, vstart, vtype, vm, vd, vs2, imm, rm);
case 0b011:
@ -902,27 +902,27 @@ if(vector != null) {%>
void fp_vector_imm_merge(uint8_t* V, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint64_t imm, uint8_t sew_val){
vector_imm_merge(V, vl, vstart, vtype, vm, vd, vs2, imm, sew_val);
}
void fp_vector_unary_w(uint8_t* V, uint8_t encoding_space, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t rm, uint8_t sew_val){
void fp_vector_unary_w(uint8_t* V, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_unary_w<${vlen}, uint16_t, uint8_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b001:
return softvector::fp_vector_unary_op<${vlen}, uint32_t, uint16_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
return softvector::fp_vector_unary_w<${vlen}, uint32_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_op<${vlen}, uint64_t, uint32_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
return softvector::fp_vector_unary_w<${vlen}, uint64_t, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011: // would widen to 128 bits
default:
throw new std::runtime_error("Unsupported sew bit value");
}
}
void fp_vector_unary_n(uint8_t* V, uint8_t encoding_space, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t rm, uint8_t sew_val){
void fp_vector_unary_n(uint8_t* V, uint8_t unary_op, uint64_t vl, uint64_t vstart, softvector::vtype_t vtype, bool vm, uint8_t vd, uint8_t vs2, uint8_t rm, uint8_t sew_val){
switch(sew_val){
case 0b000:
throw new std::runtime_error("Unsupported sew bit value");
return softvector::fp_vector_unary_w<${vlen}, uint8_t, uint16_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b001:
return softvector::fp_vector_unary_op<${vlen}, uint16_t, uint32_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
return softvector::fp_vector_unary_w<${vlen}, uint16_t, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b010:
return softvector::fp_vector_unary_op<${vlen}, uint32_t, uint64_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
return softvector::fp_vector_unary_w<${vlen}, uint32_t, uint64_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm);
case 0b011: // would require 128 bit value to narrow
default:
throw new std::runtime_error("Unsupported sew bit value");

View File

@ -53,11 +53,40 @@ const std::array<uint8_t, 7> rmm_map = {softfloat_round_near_even /*RNE*/,
0 /*reserved*/,
softfloat_round_odd /*ROD*/};
const uint32_t quiet_nan32 = 0x7fC00000;
extern "C" {
uint32_t fget_flags() { return softfloat_exceptionFlags & 0x1f; }
uint16_t fadd_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
float16_t r = f16_add(v1f, v2f);
return r.v;
}
uint16_t fsub_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
float16_t r = f16_sub(v1f, v2f);
return r.v;
}
uint16_t fmul_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
float16_t r = f16_mul(v1f, v2f);
return r.v;
}
uint16_t fdiv_h(uint16_t v1, uint16_t v2, uint8_t mode) {
float16_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
float16_t r = f16_div(v1f, v2f);
return r.v;
}
uint16_t fsqrt_h(uint16_t v1, uint8_t mode) {
float16_t v1f{v1};
@ -67,6 +96,104 @@ uint16_t fsqrt_h(uint16_t v1, uint8_t mode) {
return r.v;
}
uint16_t fcmp_h(uint16_t v1, uint16_t v2, uint16_t op) {
float16_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = v1 == defaultNaNF16UI || v2 & defaultNaNF16UI;
bool snan = softfloat_isSigNaNF16UI(v1) || softfloat_isSigNaNF16UI(v2);
switch(op) {
case 0:
if(nan | snan) {
if(snan)
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_eq(v1f, v2f) ? 1 : 0;
case 1:
if(nan | snan) {
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_le(v1f, v2f) ? 1 : 0;
case 2:
if(nan | snan) {
softfloat_raiseFlags(softfloat_flag_invalid);
return 0;
} else
return f16_lt(v1f, v2f) ? 1 : 0;
default:
break;
}
return -1;
}
uint16_t fcvt_h(uint16_t v1, uint16_t op, uint8_t mode) {
float16_t v1f{v1};
softfloat_exceptionFlags = 0;
float16_t r;
switch(op) {
case 0: { // FCVT__W__S
uint_fast16_t res = f16_to_i32(v1f, rmm_map.at(mode), true);
return (uint16_t)res;
}
case 1: { // FCVT__WU__S
uint_fast16_t res = f16_to_ui32(v1f, rmm_map.at(mode), true);
return (uint16_t)res;
}
case 2: // FCVT__S__W
r = i32_to_f16((int16_t)v1);
return r.v;
case 3: // FCVT__S__WU
r = ui32_to_f16(v1);
return r.v;
}
return 0;
}
uint16_t fmadd_h(uint16_t v1, uint16_t v2, uint16_t v3, uint16_t op, uint8_t mode) {
uint16_t F16_SIGN = 1UL << 15;
switch(op) {
case 0: // FMADD_S
break;
case 1: // FMSUB_S
v3 ^= F16_SIGN;
break;
case 2: // FNMADD_S
v1 ^= F16_SIGN;
v3 ^= F16_SIGN;
break;
case 3: // FNMSUB_S
v1 ^= F16_SIGN;
break;
}
softfloat_roundingMode = rmm_map.at(mode);
softfloat_exceptionFlags = 0;
float16_t res = softfloat_mulAddF16(v1, v2, v3, 0);
return res.v;
}
uint16_t fsel_h(uint16_t v1, uint16_t v2, uint16_t op) {
softfloat_exceptionFlags = 0;
bool v1_nan = (v1 & defaultNaNF16UI) == defaultNaNF16UI;
bool v2_nan = (v2 & defaultNaNF16UI) == defaultNaNF16UI;
bool v1_snan = softfloat_isSigNaNF16UI(v1);
bool v2_snan = softfloat_isSigNaNF16UI(v2);
if(v1_snan || v2_snan)
softfloat_raiseFlags(softfloat_flag_invalid);
if(v1_nan || v1_snan)
return (v2_nan || v2_snan) ? defaultNaNF16UI : v2;
else if(v2_nan || v2_snan)
return v1;
else {
if((v1 & 0x7fff) == 0 && (v2 & 0x7fff) == 0) {
return op == 0 ? ((v1 & 0x8000) ? v1 : v2) : ((v1 & 0x8000) ? v2 : v1);
} else {
float16_t v1f{v1}, v2f{v2};
return op == 0 ? (f16_lt(v1f, v2f) ? v1 : v2) : (f16_lt(v1f, v2f) ? v2 : v1);
}
}
}
uint16_t fclass_h(uint16_t v1) {
float16_t a{v1};
@ -132,7 +259,7 @@ uint32_t fsqrt_s(uint32_t v1, uint8_t mode) {
uint32_t fcmp_s(uint32_t v1, uint32_t v2, uint32_t op) {
float32_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32 || (v2 & defaultNaNF32UI) == quiet_nan32;
bool nan = v1 == defaultNaNF32UI || v2 == defaultNaNF32UI;
bool snan = softfloat_isSigNaNF32UI(v1) || softfloat_isSigNaNF32UI(v2);
switch(op) {
case 0:
@ -273,7 +400,7 @@ uint64_t fconv_f2d(uint32_t v1, uint8_t mode) {
}
uint64_t fadd_d(uint64_t v1, uint64_t v2, uint8_t mode) {
bool nan = (v1 & defaultNaNF32UI) == quiet_nan32;
bool nan = v1 == defaultNaNF32UI;
bool snan = softfloat_isSigNaNF32UI(v1);
float64_t v1f{v1}, v2f{v2};
softfloat_roundingMode = rmm_map.at(mode);
@ -317,7 +444,7 @@ uint64_t fsqrt_d(uint64_t v1, uint8_t mode) {
uint64_t fcmp_d(uint64_t v1, uint64_t v2, uint32_t op) {
float64_t v1f{v1}, v2f{v2};
softfloat_exceptionFlags = 0;
bool nan = (v1 & defaultNaNF64UI) == quiet_nan32 || (v2 & defaultNaNF64UI) == quiet_nan32;
bool nan = v1 == defaultNaNF64UI || v2 == defaultNaNF64UI;
bool snan = softfloat_isSigNaNF64UI(v1) || softfloat_isSigNaNF64UI(v2);
switch(op) {
case 0:

View File

@ -39,6 +39,15 @@
extern "C" {
uint32_t fget_flags();
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);
uint16_t fdiv_h(uint16_t v1, uint16_t v2, uint8_t mode);
uint16_t fsqrt_h(uint16_t v1, uint8_t mode);
uint16_t fcmp_h(uint16_t v1, uint16_t v2, uint16_t op);
uint16_t fcvt_h(uint16_t v1, uint16_t op, uint8_t mode);
uint16_t fmadd_h(uint16_t v1, uint16_t v2, uint16_t v3, uint16_t op, uint8_t mode);
uint16_t fsel_h(uint16_t v1, uint16_t v2, uint16_t op);
uint16_t fsqrt_h(uint16_t v1, uint8_t mode);
uint16_t fclass_h(uint16_t v1);
uint16_t frsqrt7_h(uint16_t v);

View File

@ -147,9 +147,15 @@ void fp_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = src2_elem_t>
void fp_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd,
unsigned vs2, src1_elem_t imm, uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
template <unsigned VLEN, typename elem_t>
void fp_vector_unary_op(uint8_t* V, unsigned encoding_space, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm,
unsigned vd, unsigned vs2, uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_w(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm);
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_n(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm);
template <unsigned VLEN, typename elem_t>
void mask_fp_vector_vector_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
unsigned vs1, uint8_t rm);

View File

@ -863,14 +863,17 @@ void vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, ui
// might be that these exist somewhere in softfloat
template <typename src_elem_t> constexpr bool isNaN(src_elem_t x);
template <> constexpr bool isNaN<uint16_t>(uint16_t x) { return ((x & 0x7C00) == 0x7C00) && ((x & 0x03FF) != 0); }
template <> constexpr bool isNaN<uint32_t>(uint32_t x) { return ((x & 0x7F800000) == 0x7F800000) && ((x & 0x007FFFFF) != 0); }
template <> constexpr bool isNaN<uint64_t>(uint64_t x) {
return ((x & 0x7FF0000000000000) == 0x7FF0000000000000) && ((x & 0x000FFFFFFFFFFFFF) != 0);
}
template <typename src_elem_t> constexpr bool isNegZero(src_elem_t x);
template <> constexpr bool isNegZero<uint16_t>(uint16_t x) { return x == 0x8000; }
template <> constexpr bool isNegZero<uint32_t>(uint32_t x) { return x == 0x80000000; }
template <> constexpr bool isNegZero<uint64_t>(uint64_t x) { return x == 0x8000000000000000; }
template <typename src_elem_t> constexpr bool isPosZero(src_elem_t x);
template <> constexpr bool isPosZero<uint16_t>(uint16_t x) { return x == 0x0000; }
template <> constexpr bool isPosZero<uint32_t>(uint32_t x) { return x == 0x00000000; }
template <> constexpr bool isPosZero<uint64_t>(uint64_t x) { return x == 0x0000000000000000; }
@ -880,30 +883,54 @@ template <typename dest_elem_t, typename src_elem_t> dest_elem_t widen_float(src
template <> inline uint64_t widen_float<uint64_t, uint32_t>(uint32_t val) { return f32_to_f64(float32_t{val}).v; }
template <typename elem_size_t> elem_size_t fp_add(uint8_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_add<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1) { return fadd_h(v2, v1, mode); }
template <> inline uint32_t fp_add<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fadd_s(v2, v1, mode); }
template <> inline uint64_t fp_add<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fadd_d(v2, v1, mode); }
template <typename elem_size_t> elem_size_t fp_sub(uint8_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_sub<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1) { return fsub_h(v2, v1, mode); }
template <> inline uint32_t fp_sub<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fsub_s(v2, v1, mode); }
template <> inline uint64_t fp_sub<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fsub_d(v2, v1, mode); }
template <typename elem_size_t> elem_size_t fp_mul(uint8_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_mul<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1) { return fmul_h(v2, v1, mode); }
template <> inline uint32_t fp_mul<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fmul_s(v2, v1, mode); }
template <> inline uint64_t fp_mul<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fmul_d(v2, v1, mode); }
template <typename elem_size_t> elem_size_t fp_div(uint8_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_div<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1) { return fdiv_h(v2, v1, mode); }
template <> inline uint32_t fp_div<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fdiv_s(v2, v1, mode); }
template <> inline uint64_t fp_div<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fdiv_d(v2, v1, mode); }
template <typename elem_size_t> elem_size_t fp_madd(uint8_t, elem_size_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_madd<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1, uint16_t v3) { return fmadd_h(v1, v2, v3, 0, mode); }
template <> inline uint32_t fp_madd<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1, uint32_t v3) { return fmadd_s(v1, v2, v3, 0, mode); }
template <> inline uint64_t fp_madd<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 0, mode); }
template <typename elem_size_t> elem_size_t fp_nmadd(uint8_t, elem_size_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_nmadd<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1, uint16_t v3) { return fmadd_h(v1, v2, v3, 2, mode); }
template <> inline uint32_t fp_nmadd<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1, uint32_t v3) { return fmadd_s(v1, v2, v3, 2, mode); }
template <> inline uint64_t fp_nmadd<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 2, mode); }
template <typename elem_size_t> elem_size_t fp_msub(uint8_t, elem_size_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_msub<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1, uint16_t v3) { return fmadd_h(v1, v2, v3, 1, mode); }
template <> inline uint32_t fp_msub<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1, uint32_t v3) { return fmadd_s(v1, v2, v3, 1, mode); }
template <> inline uint64_t fp_msub<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 1, mode); }
template <typename elem_size_t> elem_size_t fp_nmsub(uint8_t, elem_size_t, elem_size_t, elem_size_t);
template <> inline uint16_t fp_nmsub<uint16_t>(uint8_t mode, uint16_t v2, uint16_t v1, uint16_t v3) { return fmadd_h(v1, v2, v3, 3, mode); }
template <> inline uint32_t fp_nmsub<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1, uint32_t v3) { return fmadd_s(v1, v2, v3, 3, mode); }
template <> inline uint64_t fp_nmsub<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 3, mode); }
template <typename elem_size_t> elem_size_t fp_min(elem_size_t, elem_size_t);
template <> inline uint16_t fp_min<uint16_t>(uint16_t v2, uint16_t v1) {
if(isNaN(v1) && isNaN(v2))
return defaultNaNF16UI;
else if(isNaN(v1))
return v2;
else if(isNaN(v2))
return v1;
else if(isNegZero(v1) && isNegZero(v2))
return v1;
else if(isNegZero(v2) && isNegZero(v1))
return v2;
else if(fcmp_h(v1, v2, 2))
return v1;
else
return v2;
}
template <> inline uint32_t fp_min<uint32_t>(uint32_t v2, uint32_t v1) {
if(isNaN(v1) && isNaN(v2))
return defaultNaNF32UI;
@ -937,6 +964,22 @@ template <> inline uint64_t fp_min<uint64_t>(uint64_t v2, uint64_t v1) {
return v2;
}
template <typename elem_size_t> elem_size_t fp_max(elem_size_t, elem_size_t);
template <> inline uint16_t fp_max<uint16_t>(uint16_t v2, uint16_t v1) {
if(isNaN(v1) && isNaN(v2))
return defaultNaNF16UI;
else if(isNaN(v1))
return v2;
else if(isNaN(v2))
return v1;
else if(isNegZero(v1) && isNegZero(v2))
return v2;
else if(isNegZero(v2) && isNegZero(v1))
return v1;
else if(fcmp_h(v1, v2, 2))
return v2;
else
return v1;
}
template <> inline uint32_t fp_max<uint32_t>(uint32_t v2, uint32_t v1) {
if(isNaN(v1) && isNaN(v2))
return defaultNaNF32UI;
@ -1264,7 +1307,18 @@ template <typename elem_size_t> elem_size_t fp_fclass(elem_size_t);
template <> inline uint16_t fp_fclass<uint16_t>(uint16_t v2) { return fclass_h(v2); }
template <> inline uint32_t fp_fclass<uint32_t>(uint32_t v2) { return fclass_s(v2); }
template <> inline uint64_t fp_fclass<uint64_t>(uint64_t v2) { return fclass_d(v2); }
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_f_to_ui(uint8_t, src_elem_size_t);
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_f_to_i(uint8_t, src_elem_size_t);
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_ui_to_f(uint8_t, src_elem_size_t);
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_i_to_f(uint8_t, src_elem_size_t);
template <typename dest_elem_t, typename src_elem_t> dest_elem_t fp_f_to_f(uint8_t rm, src_elem_t val);
template <> inline uint16_t fp_f_to_ui<uint16_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_ui32(float16_t{v2}, rm, true);
}
template <> inline uint32_t fp_f_to_ui<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
@ -1275,6 +1329,143 @@ template <> inline uint64_t fp_f_to_ui<uint64_t, uint64_t>(uint8_t rm, uint64_t
softfloat_roundingMode = rm;
return f64_to_ui64(float64_t{v2}, rm, true);
}
template <> inline uint16_t fp_f_to_i<uint16_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_i32(float16_t{v2}, rm, true);
}
template <> inline uint32_t fp_f_to_i<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i32(float32_t{v2}, rm, true);
}
template <> inline uint64_t fp_f_to_i<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_i64(float64_t{v2}, rm, true);
}
template <> inline uint16_t fp_ui_to_f<uint16_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f16(v2).v;
}
template <> inline uint32_t fp_ui_to_f<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f32(v2).v;
}
template <> inline uint64_t fp_ui_to_f<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui64_to_f64(v2).v;
}
template <> inline uint16_t fp_i_to_f<uint16_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f16(static_cast<int16_t>(v2)).v;
}
template <> inline uint32_t fp_i_to_f<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f32(v2).v;
}
template <> inline uint64_t fp_i_to_f<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i64_to_f64(v2).v;
}
template <typename elem_t> std::function<elem_t(uint8_t, uint8_t&, elem_t)> get_fp_unary_fn(unsigned encoding_space, unsigned unary_op) {
if(encoding_space == 0b010011) // VFUNARY1
switch(unary_op) {
case 0b00000: // VFSQRT
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_sqrt(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00100: // VFRSQRT7
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_rsqrt7(vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00101: // VFREC7
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_rec7(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10000: // VFCLASS
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_fclass(vs2);
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
else if(encoding_space == 0b010010) // VFUNARY0
switch(unary_op) {
case 0b00000: // VFCVT.XU.F.V
case 0b00110: // VFCVT.RTZ.XU.F.V
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_f_to_ui<elem_t, elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00001: // VFCVT.X.F.V
case 0b00111: // VFCVT.RTZ.X.F.V
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_f_to_i<elem_t, elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00010: // VFCVT.F.XU.V
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_ui_to_f<elem_t, elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00011: // VFCVT.F.X.V
return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2) {
elem_t val = fp_i_to_f<elem_t, elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
else
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
template <unsigned VLEN, typename elem_t>
void fp_vector_unary_op(uint8_t* V, unsigned encoding_space, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm,
unsigned vd, unsigned vs2, uint8_t rm) {
uint64_t vlmax = VLEN * vtype.lmul() / vtype.sew();
vmask_view mask_reg = read_vmask<VLEN>(V, vlmax);
auto vs2_view = get_vreg<VLEN, elem_t>(V, vs2, vlmax);
auto vd_view = get_vreg<VLEN, elem_t>(V, vd, vlmax);
auto fn = get_fp_unary_fn<elem_t>(encoding_space, unary_op);
uint8_t accrued_flags = 0;
for(size_t idx = vstart; idx < vl; idx++) {
bool mask_active = vm ? 1 : mask_reg[idx];
if(mask_active)
vd_view[idx] = fn(rm, accrued_flags, vs2_view[idx]);
else if(vtype.vma())
vd_view[idx] = agnostic_behavior(vd_view[idx]);
}
softfloat_exceptionFlags = accrued_flags;
if(vtype.vta())
for(size_t idx = vl; idx < vlmax; idx++)
vd_view[idx] = agnostic_behavior(vd_view[idx]);
}
template <> inline uint16_t fp_f_to_ui<uint16_t, uint8_t>(uint8_t rm, uint8_t v2) {
throw new std::runtime_error("Attempting illegal widening conversion");
}
template <> inline uint32_t fp_f_to_ui<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
@ -1285,29 +1476,145 @@ template <> inline uint64_t fp_f_to_ui<uint64_t, uint32_t>(uint8_t rm, uint32_t
softfloat_roundingMode = rm;
return f32_to_ui64(float32_t{v2}, rm, true);
}
template <> inline uint16_t fp_f_to_i<uint16_t, uint8_t>(uint8_t rm, uint8_t v2) {
throw new std::runtime_error("Attempting illegal widening conversion");
}
template <> inline uint32_t fp_f_to_i<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_i32(float16_t{v2}, rm, true);
}
template <> inline uint64_t fp_f_to_i<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i64(float32_t{v2}, rm, true);
}
template <> inline uint16_t fp_ui_to_f<uint16_t, uint8_t>(uint8_t rm, uint8_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f16(v2).v;
}
template <> inline uint32_t fp_ui_to_f<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f32(v2).v;
}
template <> inline uint64_t fp_ui_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f64(v2).v;
}
template <> inline uint16_t fp_i_to_f<uint16_t, uint8_t>(uint8_t rm, uint8_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f16(static_cast<int8_t>(v2)).v;
}
template <> inline uint32_t fp_i_to_f<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f32(static_cast<int16_t>(v2)).v;
}
template <> inline uint64_t fp_i_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f64(v2).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 <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) {
switch(unary_op) {
case 0b01000: // VFWCVT.XU.F.V
case 0b01110: // VFWCVT.RTZ.XU.F.V
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_ui<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b01001: // VFWCVT.X.F.V
case 0b01111: // VFWCVT.RTZ.X.F.V
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_i<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b01010: // VFWCVT.F.XU.V
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_ui_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b01011: // VFWCVT.F.X.V
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_i_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b01100: // VFWCVT.F.F.V
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
}
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_w(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm) {
uint64_t vlmax = VLEN * vtype.lmul() / vtype.sew();
vmask_view mask_reg = read_vmask<VLEN>(V, vlmax);
auto vs2_view = get_vreg<VLEN, src_elem_t>(V, vs2, vlmax);
auto vd_view = get_vreg<VLEN, dest_elem_t>(V, vd, vlmax);
auto fn = get_fp_widening_fn<dest_elem_t, src_elem_t>(unary_op);
uint8_t accrued_flags = 0;
for(size_t idx = vstart; idx < vl; idx++) {
bool mask_active = vm ? 1 : mask_reg[idx];
if(mask_active)
vd_view[idx] = fn(rm, accrued_flags, vs2_view[idx]);
else if(vtype.vma())
vd_view[idx] = agnostic_behavior(vd_view[idx]);
}
softfloat_exceptionFlags = accrued_flags;
if(vtype.vta())
for(size_t idx = vl; idx < vlmax; idx++)
vd_view[idx] = agnostic_behavior(vd_view[idx]);
}
template <> inline uint8_t fp_f_to_ui<uint8_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_ui32(float16_t{v2}, rm, true);
}
template <> inline uint16_t fp_f_to_ui<uint16_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
// return f32_to_ui16(float32_t{v2}, rm, true);
throw new std::runtime_error("No conversion from f32 to ui16 implemented");
return f32_to_ui32(float32_t{v2}, rm, true);
}
template <> inline uint32_t fp_f_to_ui<uint32_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_ui32(float64_t{v2}, rm, true);
}
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_f_to_i(uint8_t, src_elem_size_t);
template <> inline uint32_t fp_f_to_i<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i32(float32_t{v2}, rm, true);
}
template <> inline uint64_t fp_f_to_i<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_i64(float64_t{v2}, rm, true);
}
template <> inline uint32_t fp_f_to_i<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
template <> inline uint8_t fp_f_to_i<uint8_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f16_to_i32(float16_t{v2}, rm, true);
@ -1315,40 +1622,16 @@ template <> inline uint32_t fp_f_to_i<uint32_t, uint16_t>(uint8_t rm, uint16_t v
template <> inline uint16_t fp_f_to_i<uint16_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
// return f32_to_i16(float32_t{v2}, rm, true);
throw new std::runtime_error("No conversion from f32 to i16 implemented");
}
template <> inline uint64_t fp_f_to_i<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f32_to_i64(float32_t{v2}, rm, true);
return f32_to_i32(float32_t{v2}, rm, true);
}
template <> inline uint32_t fp_f_to_i<uint32_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return f64_to_i32(float64_t{v2}, rm, true);
}
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_ui_to_f(uint8_t, src_elem_size_t);
template <> inline uint32_t fp_ui_to_f<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f32(v2).v;
}
template <> inline uint64_t fp_ui_to_f<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui64_to_f64(v2).v;
}
template <> inline uint32_t fp_ui_to_f<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
// return ui16_to_f32(v2).v;
throw new std::runtime_error("No conversion from ui16 to f32 implemented");
}
template <> inline uint64_t fp_ui_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return ui32_to_f64(v2).v;
template <> inline uint8_t fp_ui_to_f<uint8_t, uint16_t>(uint8_t rm, uint16_t v2) {
throw new std::runtime_error("Attempting illegal narrowing conversion");
}
template <> inline uint16_t fp_ui_to_f<uint16_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
@ -1360,27 +1643,9 @@ template <> inline uint32_t fp_ui_to_f<uint32_t, uint64_t>(uint8_t rm, uint64_t
softfloat_roundingMode = rm;
return ui64_to_f32(v2).v;
}
template <typename dest_elem_size_t, typename src_elem_size_t> dest_elem_size_t fp_i_to_f(uint8_t, src_elem_size_t);
template <> inline uint32_t fp_i_to_f<uint32_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f32(v2).v;
}
template <> inline uint64_t fp_i_to_f<uint64_t, uint64_t>(uint8_t rm, uint64_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i64_to_f64(v2).v;
}
template <> inline uint32_t fp_i_to_f<uint32_t, uint16_t>(uint8_t rm, uint16_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
// return i16_to_f32(v2).v;
throw new std::runtime_error("No conversion from i16 to f32 implemented");
}
template <> inline uint64_t fp_i_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
softfloat_roundingMode = rm;
return i32_to_f64(v2).v;
template <> inline uint8_t fp_i_to_f<uint8_t, uint16_t>(uint8_t rm, uint16_t v2) {
throw new std::runtime_error("Attempting illegal narrowing conversion");
}
template <> inline uint16_t fp_i_to_f<uint16_t, uint32_t>(uint8_t rm, uint32_t v2) {
softfloat_exceptionFlags = 0;
@ -1392,112 +1657,68 @@ template <> inline uint32_t fp_i_to_f<uint32_t, uint64_t>(uint8_t rm, uint64_t v
softfloat_roundingMode = rm;
return i64_to_f32(v2).v;
}
template <typename dest_elem_t, typename src_elem_t> dest_elem_t fp_f_to_f(uint8_t rm, src_elem_t val) {
throw new std::runtime_error("Conversion not explicitly specialized");
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 uint64_t fp_f_to_f<uint64_t, uint32_t>(uint8_t rm, uint32_t val) {
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_f64(float32_t{val}).v;
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 <typename dest_elem_t, typename src_elem_t = dest_elem_t>
std::function<dest_elem_t(uint8_t, uint8_t&, src_elem_t)> get_fp_unary_fn(unsigned encoding_space, unsigned unary_op) {
if(encoding_space == 0b010011) // VFUNARY1
switch(unary_op) {
case 0b00000: // VFSQRT
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_sqrt(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00100: // VFRSQRT7
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_rsqrt7(vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00101: // VFREC7
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_rec7(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10000: // VFCLASS
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_fclass(vs2);
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
else if(encoding_space == 0b010010) // VFUNARY0
switch(unary_op) {
case 0b00000: // VFCVT.XU.F.V
case 0b00110: // VFCVT.RTZ.XU.F.V
case 0b01000: // VFWCVT.XU.F.V
case 0b01110: // VFWCVT.RTZ.XU.F.V
case 0b10000: // VFNCVT.XU.F.W
case 0b10110: // VFNCVT.RTZ.XU.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_ui<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00001: // VFCVT.X.F.V
case 0b01001: // VFWCVT.X.F.V
case 0b10001: // VFNCVT.X.F.W
case 0b00111: // VFCVT.RTZ.X.F.V
case 0b01111: // VFWCVT.RTZ.X.F.V
case 0b10111: // VFNCVT.RTZ.X.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_i<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00010: // VFCVT.F.XU.V
case 0b01010: // VFWCVT.F.XU.V
case 0b10010: // VFNCVT.F.XU.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_ui_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b00011: // VFCVT.F.X.V
case 0b01011: // VFWCVT.F.X.V
case 0b10011: // VFNCVT.F.X.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_i_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b01100: // VFWCVT.F.F.V
case 0b10100: // VFNCVT.F.F.W
case 0b10101: // VFNCVT.ROD.F.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
}
else
throw new std::runtime_error("Unknown funct in get_fp_unary_fn");
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) {
case 0b10000: // VFNCVT.XU.F.W
case 0b10110: // VFNCVT.RTZ.XU.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_ui<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10001: // VFNCVT.X.F.W
case 0b10111: // VFNCVT.RTZ.X.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_i<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10010: // VFNCVT.F.XU.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_ui_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10011: // VFNCVT.F.X.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_i_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
case 0b10100: // VFNCVT.F.F.W
case 0b10101: // VFNCVT.ROD.F.F.W
return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) {
dest_elem_t val = fp_f_to_f<dest_elem_t, src_elem_t>(rm, vs2);
accrued_flags |= softfloat_exceptionFlags;
return val;
};
default:
throw new std::runtime_error("Unknown funct in get_fp_narrowing_fn");
}
}
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
void fp_vector_unary_op(uint8_t* V, unsigned encoding_space, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm,
unsigned vd, unsigned vs2, uint8_t rm) {
void fp_vector_unary_n(uint8_t* V, unsigned unary_op, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2,
uint8_t rm) {
uint64_t vlmax = VLEN * vtype.lmul() / vtype.sew();
vmask_view mask_reg = read_vmask<VLEN>(V, vlmax);
auto vs2_view = get_vreg<VLEN, src_elem_t>(V, vs2, vlmax);
auto vd_view = get_vreg<VLEN, dest_elem_t>(V, vd, vlmax);
auto fn = get_fp_unary_fn<dest_elem_t, src_elem_t>(encoding_space, unary_op);
auto fn = get_fp_narrowing_fn<dest_elem_t, src_elem_t>(unary_op);
uint8_t accrued_flags = 0;
for(size_t idx = vstart; idx < vl; idx++) {
bool mask_active = vm ? 1 : mask_reg[idx];
@ -1512,12 +1733,15 @@ void fp_vector_unary_op(uint8_t* V, unsigned encoding_space, unsigned unary_op,
vd_view[idx] = agnostic_behavior(vd_view[idx]);
}
template <typename elem_size_t> bool fp_eq(elem_size_t, elem_size_t);
template <> inline bool fp_eq<uint16_t>(uint16_t v2, uint16_t v1) { return fcmp_h(v2, v1, 0); }
template <> inline bool fp_eq<uint32_t>(uint32_t v2, uint32_t v1) { return fcmp_s(v2, v1, 0); }
template <> inline bool fp_eq<uint64_t>(uint64_t v2, uint64_t v1) { return fcmp_d(v2, v1, 0); }
template <typename elem_size_t> bool fp_le(elem_size_t, elem_size_t);
template <> inline bool fp_le<uint16_t>(uint16_t v2, uint16_t v1) { return fcmp_h(v2, v1, 1); }
template <> inline bool fp_le<uint32_t>(uint32_t v2, uint32_t v1) { return fcmp_s(v2, v1, 1); }
template <> inline bool fp_le<uint64_t>(uint64_t v2, uint64_t v1) { return fcmp_d(v2, v1, 1); }
template <typename elem_size_t> bool fp_lt(elem_size_t, elem_size_t);
template <> inline bool fp_lt<uint16_t>(uint16_t v2, uint16_t v1) { return fcmp_h(v2, v1, 2); }
template <> inline bool fp_lt<uint32_t>(uint32_t v2, uint32_t v1) { return fcmp_s(v2, v1, 2); }
template <> inline bool fp_lt<uint64_t>(uint64_t v2, uint64_t v1) { return fcmp_d(v2, v1, 2); }
template <typename elem_t> std::function<bool(uint8_t, uint8_t&, elem_t, elem_t)> get_fp_mask_funct(unsigned funct6) {