From 6fcb3dbb669a0a4c0581395d53659b2b985fd3fd Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Thu, 6 Mar 2025 08:57:03 +0100 Subject: [PATCH] adds missing floating point instructions --- gen_input/templates/interp/CORENAME.cpp.gtl | 33 ++- src/vm/fp_functions.cpp | 15 +- src/vm/vector_functions.h | 4 +- src/vm/vector_functions.hpp | 293 ++++++++++++++------ 4 files changed, 243 insertions(+), 102 deletions(-) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index a2f359d..0b3ed96 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -857,16 +857,16 @@ if(vector != null) {%> throw new std::runtime_error("Unsupported sew bit value"); } } - void fp_vector_unary_op(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){ + void fp_vector_unary_op(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){ switch(sew_val){ case 0b000: throw new std::runtime_error("Unsupported sew bit value"); case 0b001: throw new std::runtime_error("Unsupported sew bit value"); case 0b010: - return softvector::fp_vector_unary_op<${vlen}, uint32_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm); + return softvector::fp_vector_unary_op<${vlen}, uint32_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm); case 0b011: - return softvector::fp_vector_unary_op<${vlen}, uint64_t>(V, unary_op, vl, vstart, vtype, vm, vd, vs2, rm); + return softvector::fp_vector_unary_op<${vlen}, uint64_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm); default: throw new std::runtime_error("Unsupported sew bit value"); } @@ -902,6 +902,33 @@ 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, int64_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){ + switch(sew_val){ + case 0b000: + throw new std::runtime_error("Unsupported sew bit value"); + case 0b001: + throw new std::runtime_error("Unsupported sew bit value"); + 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); + 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){ + switch(sew_val){ + case 0b000: + throw new std::runtime_error("Unsupported sew bit value"); + case 0b001: + throw new std::runtime_error("Unsupported sew bit value"); + case 0b010: + throw new std::runtime_error("Unsupported sew bit value"); + case 0b011: + return softvector::fp_vector_unary_op<${vlen}, uint32_t, uint64_t>(V, encoding_space, unary_op, vl, vstart, vtype, vm, vd, vs2, rm); + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } <%}%> uint64_t fetch_count{0}; uint64_t tval{0}; diff --git a/src/vm/fp_functions.cpp b/src/vm/fp_functions.cpp index 2791e76..ee5dd6c 100644 --- a/src/vm/fp_functions.cpp +++ b/src/vm/fp_functions.cpp @@ -45,10 +45,9 @@ extern "C" { using this_t = uint8_t*; // this does not inlcude any reserved rm or the DYN rm, as DYN rm should be taken care of in the vm_impl -const std::array rmm_map = { - softfloat_round_near_even /*RNE*/, softfloat_round_minMag /*RTZ*/, softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/, - softfloat_round_near_maxMag /*RMM*/ -}; +const std::array rmm_map = {softfloat_round_near_even /*RNE*/, softfloat_round_minMag /*RTZ*/, + softfloat_round_min /*RDN*/, softfloat_round_max /*RUP?*/, + softfloat_round_near_maxMag /*RMM*/, softfloat_round_odd /*ROD*/}; const uint32_t quiet_nan32 = 0x7fC00000; @@ -494,13 +493,7 @@ template T constexpr negZero(); template <> uint16_t constexpr negZero() { return 0x8000; } template <> uint32_t constexpr negZero() { return 0x80000000; } template <> uint64_t constexpr negZero() { return 0x8000000000000000; } -/* -function nxFlag() -> bits(5) = 0b_00001 softfloat_flag_inexact = 1, -function ufFlag() -> bits(5) = 0b_00010 softfloat_flag_underflow = 2, -function ofFlag() -> bits(5) = 0b_00100 softfloat_flag_overflow = 4, -function dzFlag() -> bits(5) = 0b_01000 softfloat_flag_infinite = 8, -function nvFlag() -> bits(5) = 0b_10000 softfloat_flag_invalid = 16 -*/ + template bool rsqrt_check(T fclass_val, bool& subnormal, T& ret_val) { softfloat_exceptionFlags = 0; switch(fclass_val) { diff --git a/src/vm/vector_functions.h b/src/vm/vector_functions.h index 6d0c51f..b8d0201 100644 --- a/src/vm/vector_functions.h +++ b/src/vm/vector_functions.h @@ -146,8 +146,8 @@ template -void fp_vector_unary_op(uint8_t* V, 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_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 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); diff --git a/src/vm/vector_functions.hpp b/src/vm/vector_functions.hpp index 3e0e584..db473f3 100644 --- a/src/vm/vector_functions.hpp +++ b/src/vm/vector_functions.hpp @@ -945,11 +945,7 @@ template <> constexpr bool isPosZero(uint64_t x) { return x == 0x00000 template dest_elem_t widen_float(src_elem_t val) { throw new std::runtime_error("Trying to widen a weird 'float'"); }; -template <> inline uint64_t widen_float(uint32_t val) { - float32_t v1{val}; - float64_t v2 = f32_to_f64(v1); - return v2.v; -} +template <> inline uint64_t widen_float(uint32_t val) { return f32_to_f64(float32_t{val}).v; } template elem_size_t fp_add(uint8_t, elem_size_t, elem_size_t); template <> inline uint32_t fp_add(uint8_t mode, uint32_t v2, uint32_t v1) { return fadd_s(v1, v2, mode); } @@ -1047,175 +1043,173 @@ template <> inline uint64_t fp_max(uint64_t v2, uint64_t v1) { } template -std::function get_fp_funct(unsigned funct6, unsigned funct3) { +std::function get_fp_funct(unsigned funct6, unsigned funct3) { if(funct3 == OPFVV || funct3 == OPFVF) switch(funct6) { case 0b000000: // VFADD - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_add(rm, vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b000010: // VFSUB - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_sub(rm, vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b000100: // VFMIN - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return fp_min(vs2, vs1); }; case 0b000110: // VFMAX - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { return fp_max(vs2, vs1); }; case 0b100000: // VFDIV - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_div(rm, vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b100001: // VFRDIV - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_div(rm, vs1, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b100100: // VFMUL - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_mul(rm, vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b100111: // VFRSUB - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_sub(rm, vs1, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101000: // VFMADD - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_madd(rm, vs1, vd, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101001: // VFNMADD - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmadd(rm, vs1, vd, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101010: // VFMSUB - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_msub(rm, vs1, vd, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101011: // VFNMSUB - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmsub(rm, vs1, vd, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101100: // VFMACC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_madd(rm, vs1, vs2, vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101101: // VFNMAC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmadd(rm, vs1, vs2, vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101110: // VFMSAC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_msub(rm, vs1, vs2, vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b101111: // VFNMSAC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmsub(rm, vs1, vs2, vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b110000: // VFWADD - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_add(rm, widen_float(vs2), widen_float(vs1)); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b110010: // VFWSUB - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_sub(rm, widen_float(vs2), widen_float(vs1)); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b110100: // VFWADD.W - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_add(rm, vs2, widen_float(vs1)); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b110110: // VFWSUB.W - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_sub(rm, vs2, widen_float(vs1)); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b111000: // VFWMUL - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_mul(rm, widen_float(vs2), vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b111100: // VFWMACC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_madd(rm, widen_float(vs1), widen_float(vs2), vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b111101: // VFWNMACC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmadd(rm, widen_float(vs1), widen_float(vs2), vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b111110: // VFWMSAC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_msub(rm, widen_float(vs1), widen_float(vs2), vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b111111: // VFWNMSAC - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t val = fp_nmsub(rm, widen_float(vs1), widen_float(vs2), vd); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b001000: // VFSGNJ - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t mask = std::numeric_limits::max() >> 1; dest_elem_t sign_mask = std::numeric_limits>::min(); return (vs2 & mask) | (vs1 & sign_mask); }; case 0b001001: // VFSGNJN - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t mask = std::numeric_limits::max() >> 1; dest_elem_t sign_mask = std::numeric_limits>::min(); return (vs2 & mask) | (~vs1 & sign_mask); }; case 0b001010: // VFSGNJX - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { dest_elem_t mask = std::numeric_limits::max() >> 1; dest_elem_t sign_mask = std::numeric_limits>::min(); return vs2 ^ (vs1 & sign_mask); }; - case 0b010111: // VFMERGE/VFMV - default: throw new std::runtime_error("Unknown funct6 in get_fp_funct"); } @@ -1231,7 +1225,7 @@ void fp_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t auto vs2_view = get_vreg(V, vs2, elem_count); auto vd_view = get_vreg(V, vd, elem_count); auto fn = get_fp_funct(funct6, funct3); - uint_fast8_t accrued_flags = 0; + uint8_t accrued_flags = 0; // elements w/ index smaller than vstart are in the prestart and get skipped // body is from vstart to min(elem_count, vl) for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) { @@ -1259,7 +1253,7 @@ void fp_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, auto vs2_view = get_vreg(V, vs2, elem_count); auto vd_view = get_vreg(V, vd, elem_count); auto fn = get_fp_funct(funct6, funct3); - uint_fast8_t accrued_flags = 0; + uint8_t accrued_flags = 0; // elements w/ index smaller than vstart are in the prestart and get skipped // body is from vstart to min(elem_count, vl) for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) { @@ -1280,34 +1274,34 @@ void fp_vector_imm_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, return; } template -std::function get_fp_red_funct(unsigned funct6, unsigned funct3) { +std::function get_fp_red_funct(unsigned funct6, unsigned funct3) { if(funct3 == OPFVV || funct3 == OPFVF) switch(funct6) { case 0b000001: // VFREDUSUM - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_add(rm, running_total, vs2); accrued_flags |= softfloat_exceptionFlags; }; case 0b000011: // VFREDOSUM - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_add(rm, running_total, vs2); accrued_flags |= softfloat_exceptionFlags; }; case 0b000101: // VFREDMIN - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_min(running_total, vs2); }; case 0b000111: // VFREDMAX - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_max(running_total, vs2); }; case 0b110001: // VFWREDUSUM - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_add(rm, running_total, widen_float(vs2)); accrued_flags |= softfloat_exceptionFlags; }; case 0b110011: // VFWREDOSUM - return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { + return [](uint8_t rm, uint8_t& accrued_flags, dest_elem_t& running_total, src_elem_t vs2) { running_total = fp_add(rm, running_total, widen_float(vs2)); accrued_flags |= softfloat_exceptionFlags; }; @@ -1329,7 +1323,7 @@ void fp_vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, auto vd_view = get_vreg(V, vd, elem_count); auto fn = get_fp_red_funct(funct6, funct3); dest_elem_t& running_total = {vs1_elem}; - uint_fast8_t accrued_flags = 0; + uint8_t accrued_flags = 0; for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) { bool mask_active = vm ? 1 : mask_reg[idx]; if(mask_active) { @@ -1356,46 +1350,173 @@ template <> inline uint64_t fp_rec7(uint8_t mode, uint64_t v2) { retur template elem_size_t fp_fclass(elem_size_t); template <> inline uint32_t fp_fclass(uint32_t v2) { return fclass_s(v2); } template <> inline uint64_t fp_fclass(uint64_t v2) { return fclass_d(v2); } +template dest_elem_size_t fp_f_to_ui(uint8_t, src_elem_size_t); +template <> inline uint32_t fp_f_to_ui(uint8_t rm, uint32_t v2) { + softfloat_exceptionFlags = 0; + return f32_to_ui32(float32_t{v2}, rm, true); +} +template <> inline uint64_t fp_f_to_ui(uint8_t rm, uint64_t v2) { + softfloat_exceptionFlags = 0; + return f64_to_ui64(float64_t{v2}, rm, true); +} +template <> inline uint64_t fp_f_to_ui(uint8_t rm, uint32_t v2) { + softfloat_exceptionFlags = 0; + return f32_to_ui64(float32_t{v2}, rm, true); +} +template <> inline uint32_t fp_f_to_ui(uint8_t rm, uint64_t v2) { + softfloat_exceptionFlags = 0; + return f64_to_ui32(float64_t{v2}, rm, true); +} +template dest_elem_size_t fp_f_to_i(uint8_t, src_elem_size_t); +template <> inline uint32_t fp_f_to_i(uint8_t rm, uint32_t v2) { + softfloat_exceptionFlags = 0; + return f32_to_i32(float32_t{v2}, rm, true); +} +template <> inline uint64_t fp_f_to_i(uint8_t rm, uint64_t v2) { + softfloat_exceptionFlags = 0; + return f64_to_i64(float64_t{v2}, rm, true); +} +template <> inline uint64_t fp_f_to_i(uint8_t rm, uint32_t v2) { + softfloat_exceptionFlags = 0; + return f32_to_i64(float32_t{v2}, rm, true); +} +template <> inline uint32_t fp_f_to_i(uint8_t rm, uint64_t v2) { + softfloat_exceptionFlags = 0; + return f64_to_i32(float64_t{v2}, rm, true); +} +template dest_elem_size_t fp_ui_to_f(src_elem_size_t); +template <> inline uint32_t fp_ui_to_f(uint32_t v2) { + softfloat_exceptionFlags = 0; + return ui32_to_f32(v2).v; +} +template <> inline uint64_t fp_ui_to_f(uint64_t v2) { + softfloat_exceptionFlags = 0; + return ui64_to_f64(v2).v; +} +template <> inline uint64_t fp_ui_to_f(uint32_t v2) { + softfloat_exceptionFlags = 0; + return ui32_to_f64(v2).v; +} +template <> inline uint32_t fp_ui_to_f(uint64_t v2) { + softfloat_exceptionFlags = 0; + return ui64_to_f32(v2).v; +} +template dest_elem_size_t fp_i_to_f(src_elem_size_t); +template <> inline uint32_t fp_i_to_f(uint32_t v2) { + softfloat_exceptionFlags = 0; + return i32_to_f32(v2).v; +} +template <> inline uint64_t fp_i_to_f(uint64_t v2) { + softfloat_exceptionFlags = 0; + return i64_to_f64(v2).v; +} +template <> inline uint64_t fp_i_to_f(uint32_t v2) { + softfloat_exceptionFlags = 0; + return i32_to_f64(v2).v; +} +template <> inline uint32_t fp_i_to_f(uint64_t v2) { + softfloat_exceptionFlags = 0; + return i64_to_f32(v2).v; +} +template dest_elem_t fp_f_to_f(uint8_t mode, src_elem_t val) { + throw new std::runtime_error("Conversion not explicitly specialized"); +} +template <> inline uint64_t fp_f_to_f(uint8_t mode, uint32_t val) { return fconv_f2d(val, mode); } +template <> inline uint32_t fp_f_to_f(uint8_t mode, uint64_t val) { return fconv_d2f(val, mode); } template -std::function get_fp_unary_fn(unsigned unary_op) { - switch(unary_op) { - case 0b00000: // VFSQRT - return [](uint8_t rm, uint_fast8_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, uint_fast8_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, uint_fast8_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, uint_fast8_t& accrued_flags, src_elem_t vs2) { - dest_elem_t val = fp_fclass(vs2); - return val; - }; - default: +std::function 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 0b01000: // VFWCVT.XU.F.V + case 0b10000: // VFNCVT.XU.F.W + return [](uint8_t rm, uint8_t& accrued_flags, src_elem_t vs2) { + dest_elem_t val = fp_f_to_ui(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(rm, vs2); + accrued_flags |= softfloat_exceptionFlags; + return val; + }; + case 0b00010: // VFCVT.F.XU.V + case 0b00110: // VFCVT.RTZ.XU.F.V + case 0b01010: // VFWCVT.F.XU.V + case 0b01110: // VFWCVT.RTZ.XU.F.V + case 0b10010: // VFNCVT.F.XU.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_ui_to_f(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(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(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 -void fp_vector_unary_op(uint8_t* V, 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_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 elem_count = VLEN * vtype.lmul() / vtype.sew(); vmask_view mask_reg = read_vmask(V, elem_count); auto vs2_view = get_vreg(V, vs2, elem_count); auto vd_view = get_vreg(V, vd, elem_count); - auto fn = get_fp_unary_fn(unary_op); - uint_fast8_t accrued_flags = 0; + auto fn = get_fp_unary_fn(encoding_space, unary_op); + uint8_t accrued_flags = 0; for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) { bool mask_active = vm ? 1 : mask_reg[idx]; if(mask_active) { @@ -1420,40 +1541,40 @@ template <> inline bool fp_le(uint64_t v2, uint64_t v1) { return fcmp_ template bool fp_lt(elem_size_t, elem_size_t); template <> inline bool fp_lt(uint32_t v2, uint32_t v1) { return fcmp_s(v2, v1, 2); } template <> inline bool fp_lt(uint64_t v2, uint64_t v1) { return fcmp_d(v2, v1, 2); } -template std::function get_fp_mask_funct(unsigned funct6) { +template std::function get_fp_mask_funct(unsigned funct6) { switch(funct6) { case 0b011000: // VMFEQ - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = fp_eq(vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b011001: // VMFLE - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = fp_le(vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b011011: // VMFLT - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = fp_lt(vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b011100: // VMFNE - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = !fp_eq(vs2, vs1); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b011101: // VMFGT - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = fp_lt(vs1, vs2); accrued_flags |= softfloat_exceptionFlags; return val; }; case 0b011111: // VMFGE - return [](uint8_t rm, uint_fast8_t& accrued_flags, elem_t vs2, elem_t vs1) { + return [](uint8_t rm, uint8_t& accrued_flags, elem_t vs2, elem_t vs1) { elem_t val = fp_le(vs1, vs2); accrued_flags |= softfloat_exceptionFlags; return val; @@ -1471,7 +1592,7 @@ void mask_fp_vector_vector_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t auto vs2_view = get_vreg(V, vs2, elem_count); vmask_view vd_mask_view = read_vmask(V, VLEN, vd); auto fn = get_fp_mask_funct(funct6); - uint_fast8_t accrued_flags = 0; + uint8_t accrued_flags = 0; for(unsigned idx = vstart; idx < vl; idx++) { bool mask_active = vm ? 1 : mask_reg[idx]; if(mask_active) { @@ -1494,7 +1615,7 @@ void mask_fp_vector_imm_op(uint8_t* V, unsigned funct6, uint64_t vl, uint64_t vs auto vs2_view = get_vreg(V, vs2, elem_count); vmask_view vd_mask_view = read_vmask(V, VLEN, vd); auto fn = get_fp_mask_funct(funct6); - uint_fast8_t accrued_flags = 0; + uint8_t accrued_flags = 0; for(unsigned idx = vstart; idx < vl; idx++) { bool mask_active = vm ? 1 : mask_reg[idx]; if(mask_active) {