adds most fp functions
This commit is contained in:
parent
cd358198ad
commit
ae90adc854
@ -777,6 +777,100 @@ if(vector != null) {%>
|
|||||||
throw new std::runtime_error("Unsupported sew bit value");
|
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 fetch_count{0};
|
||||||
uint64_t tval{0};
|
uint64_t tval{0};
|
||||||
|
@ -125,6 +125,15 @@ template <unsigned VLEN> void vector_whole_move(uint8_t* V, unsigned vd, unsigne
|
|||||||
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
|
template <unsigned VLEN, typename dest_elem_t, typename src_elem_t = dest_elem_t>
|
||||||
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,
|
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);
|
unsigned vs2, unsigned vs1, uint8_t rm);
|
||||||
|
template <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = dest_elem_t>
|
||||||
|
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 <unsigned VLEN, typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = dest_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>
|
||||||
|
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
|
} // namespace softvector
|
||||||
#include "vm/vector_functions.hpp"
|
#include "vm/vector_functions.hpp"
|
||||||
#endif /* _VM_VECTOR_FUNCTIONS_H_ */
|
#endif /* _VM_VECTOR_FUNCTIONS_H_ */
|
||||||
|
@ -32,7 +32,9 @@
|
|||||||
// alex@minres.com - initial API and implementation
|
// alex@minres.com - initial API and implementation
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "softfloat.h"
|
extern "C" {
|
||||||
|
#include <softfloat.h>
|
||||||
|
}
|
||||||
#include "softfloat_types.h"
|
#include "softfloat_types.h"
|
||||||
#include "specialize.h"
|
#include "specialize.h"
|
||||||
#include "vm/fp_functions.h"
|
#include "vm/fp_functions.h"
|
||||||
@ -951,16 +953,41 @@ template <typename src_elem_t> constexpr bool isPosZero(src_elem_t x);
|
|||||||
template <> constexpr bool isPosZero<uint32_t>(uint32_t x) { return x == 0x00000000; }
|
template <> constexpr bool isPosZero<uint32_t>(uint32_t x) { return x == 0x00000000; }
|
||||||
template <> constexpr bool isPosZero<uint64_t>(uint64_t x) { return x == 0x0000000000000000; }
|
template <> constexpr bool isPosZero<uint64_t>(uint64_t x) { return x == 0x0000000000000000; }
|
||||||
|
|
||||||
template <typename elem_size_t> elem_size_t fp_add(uint8_t, elem_size_t, elem_size_t);
|
|
||||||
template <> inline uint32_t fp_add<uint32_t>(uint8_t mode, uint32_t v1, uint32_t v2) { return fadd_s(v1, v2, mode); }
|
|
||||||
template <> inline uint64_t fp_add<uint64_t>(uint8_t mode, uint64_t v1, uint64_t v2) { return fadd_d(v1, v2, mode); }
|
|
||||||
template <typename dest_elem_t, typename src_elem_t> dest_elem_t widen_float(src_elem_t val) {
|
template <typename dest_elem_t, typename src_elem_t> dest_elem_t widen_float(src_elem_t val) {
|
||||||
static_assert(sizeof(dest_elem_t) == 8 && sizeof(src_elem_t) == 4, "");
|
throw new std::runtime_error("Trying to widen a weird 'float'");
|
||||||
return static_cast<double>(static_cast<float>(val));
|
|
||||||
};
|
};
|
||||||
|
template <> inline uint64_t widen_float<uint64_t, uint32_t>(uint32_t val) {
|
||||||
|
float32_t v1{val};
|
||||||
|
float64_t v2 = f32_to_f64(v1);
|
||||||
|
return v2.v;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename elem_size_t> elem_size_t fp_add(uint8_t, elem_size_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_add<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fadd_s(v1, v2, mode); }
|
||||||
|
template <> inline uint64_t fp_add<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fadd_d(v1, v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_sub(uint8_t, elem_size_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_sub<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fsub_s(v1, v2, mode); }
|
||||||
|
template <> inline uint64_t fp_sub<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fsub_d(v1, v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_mul(uint8_t, elem_size_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_mul<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fmul_s(v1, v2, mode); }
|
||||||
|
template <> inline uint64_t fp_mul<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fmul_d(v1, v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_div(uint8_t, elem_size_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_div<uint32_t>(uint8_t mode, uint32_t v2, uint32_t v1) { return fdiv_s(v1, v2, mode); }
|
||||||
|
template <> inline uint64_t fp_div<uint64_t>(uint8_t mode, uint64_t v2, uint64_t v1) { return fdiv_d(v1, v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_madd(uint8_t, elem_size_t, elem_size_t, elem_size_t);
|
||||||
|
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 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 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 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 <typename elem_size_t> elem_size_t fp_min(elem_size_t, elem_size_t);
|
||||||
template <> inline uint32_t fp_min<uint32_t>(uint32_t v1, uint32_t v2) {
|
template <> inline uint32_t fp_min<uint32_t>(uint32_t v2, uint32_t v1) {
|
||||||
bool v1_lt_v2 = fcmp_s(v1, v2, 2);
|
bool v1_lt_v2 = fcmp_s(v1, v2, 2);
|
||||||
if(isNaN(v1) && isNaN(v2))
|
if(isNaN(v1) && isNaN(v2))
|
||||||
return defaultNaNF32UI;
|
return defaultNaNF32UI;
|
||||||
@ -977,7 +1004,7 @@ template <> inline uint32_t fp_min<uint32_t>(uint32_t v1, uint32_t v2) {
|
|||||||
else
|
else
|
||||||
return v2;
|
return v2;
|
||||||
}
|
}
|
||||||
template <> inline uint64_t fp_min<uint64_t>(uint64_t v1, uint64_t v2) {
|
template <> inline uint64_t fp_min<uint64_t>(uint64_t v2, uint64_t v1) {
|
||||||
bool v1_lt_v2 = fcmp_d(v1, v2, 2);
|
bool v1_lt_v2 = fcmp_d(v1, v2, 2);
|
||||||
if(isNaN(v1) && isNaN(v2))
|
if(isNaN(v1) && isNaN(v2))
|
||||||
return defaultNaNF32UI;
|
return defaultNaNF32UI;
|
||||||
@ -995,7 +1022,7 @@ template <> inline uint64_t fp_min<uint64_t>(uint64_t v1, uint64_t v2) {
|
|||||||
return v2;
|
return v2;
|
||||||
}
|
}
|
||||||
template <typename elem_size_t> elem_size_t fp_max(elem_size_t, elem_size_t);
|
template <typename elem_size_t> elem_size_t fp_max(elem_size_t, elem_size_t);
|
||||||
template <> inline uint32_t fp_max<uint32_t>(uint32_t v1, uint32_t v2) {
|
template <> inline uint32_t fp_max<uint32_t>(uint32_t v2, uint32_t v1) {
|
||||||
bool v1_lt_v2 = fcmp_s(v1, v2, 2);
|
bool v1_lt_v2 = fcmp_s(v1, v2, 2);
|
||||||
if(isNaN(v1) && isNaN(v2))
|
if(isNaN(v1) && isNaN(v2))
|
||||||
return defaultNaNF32UI;
|
return defaultNaNF32UI;
|
||||||
@ -1012,7 +1039,7 @@ template <> inline uint32_t fp_max<uint32_t>(uint32_t v1, uint32_t v2) {
|
|||||||
else
|
else
|
||||||
return v1;
|
return v1;
|
||||||
}
|
}
|
||||||
template <> inline uint64_t fp_max<uint64_t>(uint64_t v1, uint64_t v2) {
|
template <> inline uint64_t fp_max<uint64_t>(uint64_t v2, uint64_t v1) {
|
||||||
bool v1_lt_v2 = fcmp_d(v1, v2, 2);
|
bool v1_lt_v2 = fcmp_d(v1, v2, 2);
|
||||||
if(isNaN(v1) && isNaN(v2))
|
if(isNaN(v1) && isNaN(v2))
|
||||||
return defaultNaNF32UI;
|
return defaultNaNF32UI;
|
||||||
@ -1030,6 +1057,249 @@ template <> inline uint64_t fp_max<uint64_t>(uint64_t v1, uint64_t v2) {
|
|||||||
return v1;
|
return v1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename dest_elem_t, typename src2_elem_t = dest_elem_t, typename src1_elem_t = dest_elem_t>
|
||||||
|
std::function<dest_elem_t(uint8_t, uint_fast8_t&, dest_elem_t, src2_elem_t, src1_elem_t)> 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<dest_elem_t>(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<dest_elem_t>(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<dest_elem_t>(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<dest_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<dest_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<src2_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs2), widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs2), widen_float<dest_elem_t>(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<dest_elem_t>(rm, vs2, widen_float<dest_elem_t>(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<dest_elem_t>(rm, vs2, widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs1), widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs1), widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs1), widen_float<dest_elem_t>(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<dest_elem_t>(rm, widen_float<dest_elem_t>(vs1), widen_float<dest_elem_t>(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<dest_elem_t>::max() >> 1;
|
||||||
|
dest_elem_t sign_mask = std::numeric_limits<std::make_signed_t<dest_elem_t>>::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<dest_elem_t>::max() >> 1;
|
||||||
|
dest_elem_t sign_mask = std::numeric_limits<std::make_signed_t<dest_elem_t>>::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<dest_elem_t>::max() >> 1;
|
||||||
|
dest_elem_t sign_mask = std::numeric_limits<std::make_signed_t<dest_elem_t>>::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 <unsigned VLEN, typename dest_elem_t, typename src2_elem_t, typename src1_elem_t>
|
||||||
|
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<VLEN>(V, elem_count);
|
||||||
|
auto vs1_view = get_vreg<VLEN, src1_elem_t>(V, vs1, elem_count);
|
||||||
|
auto vs2_view = get_vreg<VLEN, src2_elem_t>(V, vs2, elem_count);
|
||||||
|
auto vd_view = get_vreg<VLEN, dest_elem_t>(V, vd, elem_count);
|
||||||
|
auto fn = get_fp_funct<dest_elem_t, src2_elem_t, src1_elem_t>(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 <unsigned VLEN, typename dest_elem_t, typename src2_elem_t, typename src1_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) {
|
||||||
|
uint64_t elem_count = VLEN * vtype.lmul() / vtype.sew();
|
||||||
|
vmask_view mask_reg = read_vmask<VLEN>(V, elem_count);
|
||||||
|
auto vs2_view = get_vreg<VLEN, src2_elem_t>(V, vs2, elem_count);
|
||||||
|
auto vd_view = get_vreg<VLEN, dest_elem_t>(V, vd, elem_count);
|
||||||
|
auto fn = get_fp_funct<dest_elem_t, src2_elem_t, src1_elem_t>(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 <typename dest_elem_t, typename src_elem_t>
|
template <typename dest_elem_t, typename src_elem_t>
|
||||||
std::function<void(uint8_t, uint_fast8_t&, dest_elem_t&, src_elem_t)> get_fp_red_funct(unsigned funct6, unsigned funct3) {
|
std::function<void(uint8_t, uint_fast8_t&, dest_elem_t&, src_elem_t)> get_fp_red_funct(unsigned funct6, unsigned funct3) {
|
||||||
if(funct3 == OPFVV || funct3 == OPFVF)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
template <typename elem_size_t> elem_size_t fp_sqrt(uint8_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_sqrt<uint32_t>(uint8_t mode, uint32_t v2) { return fsqrt_s(v2, mode); }
|
||||||
|
template <> inline uint64_t fp_sqrt<uint64_t>(uint8_t mode, uint64_t v2) { return fsqrt_d(v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_rsqrt7(elem_size_t);
|
||||||
|
template <> inline uint32_t fp_rsqrt7<uint32_t>(uint32_t v2) { return frsqrt7_s(v2); }
|
||||||
|
template <> inline uint64_t fp_rsqrt7<uint64_t>(uint64_t v2) { return frsqrt7_d(v2); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_rec7(uint8_t, elem_size_t);
|
||||||
|
template <> inline uint32_t fp_rec7<uint32_t>(uint8_t mode, uint32_t v2) { return frec7_s(v2, mode); }
|
||||||
|
template <> inline uint64_t fp_rec7<uint64_t>(uint8_t mode, uint64_t v2) { return frec7_d(v2, mode); }
|
||||||
|
template <typename elem_size_t> elem_size_t fp_fclass(elem_size_t);
|
||||||
|
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_t, typename src_elem_t = dest_elem_t>
|
||||||
|
std::function<dest_elem_t(uint8_t, uint_fast8_t&, src_elem_t)> 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 <unsigned VLEN, typename dest_elem_t, typename src_elem_t>
|
||||||
|
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<VLEN>(V, elem_count);
|
||||||
|
auto vs2_view = get_vreg<VLEN, src_elem_t>(V, vs2, elem_count);
|
||||||
|
auto vd_view = get_vreg<VLEN, dest_elem_t>(V, vd, elem_count);
|
||||||
|
auto fn = get_fp_unary_fn<dest_elem_t, src_elem_t>(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 <unsigned VLEN>
|
template <unsigned VLEN>
|
||||||
void mask_mask_op(uint8_t* V, unsigned funct6, unsigned funct3, uint64_t vl, uint64_t vstart, unsigned vd, unsigned vs2, unsigned vs1) {
|
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;
|
uint64_t elem_count = VLEN;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user