adds support for half precision float
This commit is contained in:
parent
d9f1e5d31b
commit
7a7035f267
@ -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");
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user