From ae90adc8546a369be4906889cbdec7a81a2cd1ee Mon Sep 17 00:00:00 2001 From: Eyck-Alexander Jentzsch Date: Mon, 3 Mar 2025 19:39:44 +0100 Subject: [PATCH] adds most fp functions --- gen_input/templates/interp/CORENAME.cpp.gtl | 94 ++++++ src/vm/vector_functions.h | 9 + src/vm/vector_functions.hpp | 357 +++++++++++++++++++- 3 files changed, 450 insertions(+), 10 deletions(-) diff --git a/gen_input/templates/interp/CORENAME.cpp.gtl b/gen_input/templates/interp/CORENAME.cpp.gtl index 227a7fa..a8c4718 100644 --- a/gen_input/templates/interp/CORENAME.cpp.gtl +++ b/gen_input/templates/interp/CORENAME.cpp.gtl @@ -777,6 +777,100 @@ if(vector != null) {%> throw new std::runtime_error("Unsupported sew bit value"); } } + void fp_vector_vector_op(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"); + case 0b001: + throw new std::runtime_error("Unsupported sew bit value"); + case 0b010: + return softvector::fp_vector_vector_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm); + case 0b011: + return softvector::fp_vector_vector_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, vs1, rm); + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } + void fp_vector_imm_op(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, int64_t imm, 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_imm_op<${vlen}, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm); + case 0b011: + return softvector::fp_vector_imm_op<${vlen}, uint64_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm); + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } + void fp_vector_vector_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"); + case 0b001: + throw new std::runtime_error("Unsupported sew bit value"); + 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 + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } + void fp_vector_imm_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, int64_t imm, 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_imm_op<${vlen}, uint64_t, uint32_t>(V, funct6, funct3, vl, vstart, vtype, vm, vd, vs2, imm, rm); + case 0b011: // would widen to 128 bits + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } + void fp_vector_vector_ww(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"); + case 0b001: + throw new std::runtime_error("Unsupported sew bit value"); + 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 + default: + throw new std::runtime_error("Unsupported sew bit value"); + } + } + void fp_vector_imm_ww(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, int64_t imm, 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_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 + default: + 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){ + 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); + case 0b011: + return softvector::fp_vector_unary_op<${vlen}, uint64_t>(V, 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/vector_functions.h b/src/vm/vector_functions.h index 10a9d5e..c36dea3 100644 --- a/src/vm/vector_functions.h +++ b/src/vm/vector_functions.h @@ -125,6 +125,15 @@ template void vector_whole_move(uint8_t* V, unsigned vd, unsigne template void fp_vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, unsigned vs2, unsigned vs1, uint8_t rm); +template +void fp_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, + unsigned vs2, unsigned vs1, uint8_t rm); +template +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 +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); } // namespace softvector #include "vm/vector_functions.hpp" #endif /* _VM_VECTOR_FUNCTIONS_H_ */ diff --git a/src/vm/vector_functions.hpp b/src/vm/vector_functions.hpp index d50a277..2727031 100644 --- a/src/vm/vector_functions.hpp +++ b/src/vm/vector_functions.hpp @@ -32,7 +32,9 @@ // alex@minres.com - initial API and implementation //////////////////////////////////////////////////////////////////////////////// #pragma once -#include "softfloat.h" +extern "C" { +#include +} #include "softfloat_types.h" #include "specialize.h" #include "vm/fp_functions.h" @@ -951,16 +953,41 @@ template constexpr bool isPosZero(src_elem_t x); template <> constexpr bool isPosZero(uint32_t x) { return x == 0x00000000; } template <> constexpr bool isPosZero(uint64_t x) { return x == 0x0000000000000000; } -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 v1, uint32_t v2) { return fadd_s(v1, v2, mode); } -template <> inline uint64_t fp_add(uint8_t mode, uint64_t v1, uint64_t v2) { return fadd_d(v1, v2, mode); } template dest_elem_t widen_float(src_elem_t val) { - static_assert(sizeof(dest_elem_t) == 8 && sizeof(src_elem_t) == 4, ""); - return static_cast(static_cast(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 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); } +template <> inline uint64_t fp_add(uint8_t mode, uint64_t v2, uint64_t v1) { return fadd_d(v1, v2, mode); } +template elem_size_t fp_sub(uint8_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_sub(uint8_t mode, uint32_t v2, uint32_t v1) { return fsub_s(v1, v2, mode); } +template <> inline uint64_t fp_sub(uint8_t mode, uint64_t v2, uint64_t v1) { return fsub_d(v1, v2, mode); } +template elem_size_t fp_mul(uint8_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_mul(uint8_t mode, uint32_t v2, uint32_t v1) { return fmul_s(v1, v2, mode); } +template <> inline uint64_t fp_mul(uint8_t mode, uint64_t v2, uint64_t v1) { return fmul_d(v1, v2, mode); } +template elem_size_t fp_div(uint8_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_div(uint8_t mode, uint32_t v2, uint32_t v1) { return fdiv_s(v1, v2, mode); } +template <> inline uint64_t fp_div(uint8_t mode, uint64_t v2, uint64_t v1) { return fdiv_d(v1, v2, mode); } +template elem_size_t fp_madd(uint8_t, elem_size_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_madd(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(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 0, mode); } +template elem_size_t fp_nmadd(uint8_t, elem_size_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_nmadd(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(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 2, mode); } +template elem_size_t fp_msub(uint8_t, elem_size_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_msub(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(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 1, mode); } +template elem_size_t fp_nmsub(uint8_t, elem_size_t, elem_size_t, elem_size_t); +template <> inline uint32_t fp_nmsub(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(uint8_t mode, uint64_t v2, uint64_t v1, uint64_t v3) { return fmadd_d(v1, v2, v3, 3, mode); } template elem_size_t fp_min(elem_size_t, elem_size_t); -template <> inline uint32_t fp_min(uint32_t v1, uint32_t v2) { +template <> inline uint32_t fp_min(uint32_t v2, uint32_t v1) { bool v1_lt_v2 = fcmp_s(v1, v2, 2); if(isNaN(v1) && isNaN(v2)) return defaultNaNF32UI; @@ -977,7 +1004,7 @@ template <> inline uint32_t fp_min(uint32_t v1, uint32_t v2) { else return v2; } -template <> inline uint64_t fp_min(uint64_t v1, uint64_t v2) { +template <> inline uint64_t fp_min(uint64_t v2, uint64_t v1) { bool v1_lt_v2 = fcmp_d(v1, v2, 2); if(isNaN(v1) && isNaN(v2)) return defaultNaNF32UI; @@ -995,7 +1022,7 @@ template <> inline uint64_t fp_min(uint64_t v1, uint64_t v2) { return v2; } template elem_size_t fp_max(elem_size_t, elem_size_t); -template <> inline uint32_t fp_max(uint32_t v1, uint32_t v2) { +template <> inline uint32_t fp_max(uint32_t v2, uint32_t v1) { bool v1_lt_v2 = fcmp_s(v1, v2, 2); if(isNaN(v1) && isNaN(v2)) return defaultNaNF32UI; @@ -1012,7 +1039,7 @@ template <> inline uint32_t fp_max(uint32_t v1, uint32_t v2) { else return v1; } -template <> inline uint64_t fp_max(uint64_t v1, uint64_t v2) { +template <> inline uint64_t fp_max(uint64_t v2, uint64_t v1) { bool v1_lt_v2 = fcmp_d(v1, v2, 2); if(isNaN(v1) && isNaN(v2)) return defaultNaNF32UI; @@ -1030,6 +1057,249 @@ template <> inline uint64_t fp_max(uint64_t v1, uint64_t v2) { return v1; } +template +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) { + 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) { + 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) { + dest_elem_t val = fp_min(vs2, vs1); + accrued_flags |= softfloat_exceptionFlags; + return val; + }; + case 0b000110: // VFMAX + return [](uint8_t rm, uint_fast8_t& accrued_flags, dest_elem_t vd, src2_elem_t vs2, src1_elem_t vs1) { + dest_elem_t val = fp_max(vs2, vs1); + accrued_flags |= softfloat_exceptionFlags; + return val; + }; + case 0b100000: // VFDIV + return [](uint8_t rm, uint_fast8_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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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) { + 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 + case 0b011000: // VMFEQ + case 0b011001: // VMFLE + case 0b011011: // VMFLT + case 0b011100: // VMFNE + case 0b011101: // VMFGT + case 0b011111: // VMFGE + + default: + throw new std::runtime_error("Unknown funct6 in get_fp_funct"); + } + else + throw new std::runtime_error("Unknown funct3 in get_fp_funct"); +} +template +void fp_vector_vector_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, vtype_t vtype, bool vm, unsigned vd, + unsigned vs2, unsigned vs1, uint8_t rm) { + uint64_t elem_count = VLEN * vtype.lmul() / vtype.sew(); + vmask_view mask_reg = read_vmask(V, elem_count); + auto vs1_view = get_vreg(V, vs1, elem_count); + 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; + // 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++) { + bool mask_active = vm ? 1 : mask_reg[idx]; + if(mask_active) { + vd_view[idx] = fn(rm, accrued_flags, vd_view[idx], vs2_view[idx], vs1_view[idx]); + } else { + vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; + } + } + softfloat_exceptionFlags = accrued_flags; + // elements w/ index larger than elem_count are in the tail (fractional LMUL) + // elements w/ index larger than vl are in the tail + unsigned maximum_elems = VLEN * vtype.lmul() / (sizeof(dest_elem_t) * 8); + for(unsigned idx = std::min(elem_count, vl); idx < maximum_elems; idx++) { + vd_view[idx] = vtype.vta() ? vd_view[idx] : vd_view[idx]; + } + return; +} +template +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) { + 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_funct(funct6, funct3); + uint_fast8_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++) { + bool mask_active = vm ? 1 : mask_reg[idx]; + if(mask_active) { + vd_view[idx] = fn(rm, accrued_flags, vd_view[idx], vs2_view[idx], imm); + } else { + vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; + } + } + softfloat_exceptionFlags = accrued_flags; + // elements w/ index larger than elem_count are in the tail (fractional LMUL) + // elements w/ index larger than vl are in the tail + unsigned maximum_elems = VLEN * vtype.lmul() / (sizeof(dest_elem_t) * 8); + for(unsigned idx = std::min(elem_count, vl); idx < maximum_elems; idx++) { + vd_view[idx] = vtype.vta() ? vd_view[idx] : vd_view[idx]; + } + return; +} template std::function get_fp_red_funct(unsigned funct6, unsigned funct3) { if(funct3 == OPFVV || funct3 == OPFVF) @@ -1097,6 +1367,73 @@ void fp_vector_red_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, } return; } +template elem_size_t fp_sqrt(uint8_t, elem_size_t); +template <> inline uint32_t fp_sqrt(uint8_t mode, uint32_t v2) { return fsqrt_s(v2, mode); } +template <> inline uint64_t fp_sqrt(uint8_t mode, uint64_t v2) { return fsqrt_d(v2, mode); } +template elem_size_t fp_rsqrt7(elem_size_t); +template <> inline uint32_t fp_rsqrt7(uint32_t v2) { return frsqrt7_s(v2); } +template <> inline uint64_t fp_rsqrt7(uint64_t v2) { return frsqrt7_d(v2); } +template elem_size_t fp_rec7(uint8_t, elem_size_t); +template <> inline uint32_t fp_rec7(uint8_t mode, uint32_t v2) { return frec7_s(v2, mode); } +template <> inline uint64_t fp_rec7(uint8_t mode, uint64_t v2) { return frec7_d(v2, mode); } +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 +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: + 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) { + 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; + for(unsigned idx = vstart; idx < std::min(elem_count, vl); idx++) { + bool mask_active = vm ? 1 : mask_reg[idx]; + if(mask_active) { + vd_view[idx] = fn(rm, accrued_flags, vs2_view[idx]); + } else { + vd_view[idx] = vtype.vma() ? vd_view[idx] : vd_view[idx]; + } + } + softfloat_exceptionFlags = accrued_flags; + unsigned maximum_elems = VLEN * vtype.lmul() / (sizeof(dest_elem_t) * 8); + for(unsigned idx = std::min(elem_count, vl); idx < maximum_elems; idx++) { + vd_view[idx] = vtype.vta() ? vd_view[idx] : vd_view[idx]; + } + return; +} template void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1) { uint64_t elem_count = VLEN;