Skip to content

Improve fmin/fmax #51

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 79 additions & 7 deletions src/emulate.c
Original file line number Diff line number Diff line change
Expand Up @@ -1065,8 +1065,8 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
/* dispatch based on func7 (low 2 bits are width) */
switch (funct7) {
case 0b0000000: /* FADD */
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2]) ||
isnan(rv->F[rs1] + rv->F[rs2])) {
if (isnanf(rv->F[rs1]) || isnanf(rv->F[rs2]) ||
isnanf(rv->F[rs1] + rv->F[rs2])) {
/* raise invalid operation */
rv->F_int[rd] = RV_NAN; /* F_int is the integer shortcut of F */
rv->csr_fcsr |= FFLAG_INVALID_OP;
Expand All @@ -1079,7 +1079,7 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
}
break;
case 0b0000100: /* FSUB */
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2])) {
if (isnanf(rv->F[rs1]) || isnanf(rv->F[rs2])) {
rv->F_int[rd] = RV_NAN;
} else {
rv->F[rd] = rv->F[rs1] - rv->F[rs2];
Expand Down Expand Up @@ -1119,12 +1119,84 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
}
case 0b0010100:
switch (rm) {
case 0b000: /* FMIN */
rv->F[rd] = fminf(rv->F[rs1], rv->F[rs2]);
case 0b000: { /* FMIN */
/*
In IEEE754-201x, fmin(x, y) return
- min(x,y) if both numbers are not NaN
- if one is NaN and another is a number, return the number
- if both are NaN, return NaN

When input is signaling NaN, raise invalid operation
*/
uint32_t x, y;
memcpy(&x, rv->F + rs1, 4);
memcpy(&y, rv->F + rs2, 4);
if (is_nan(x) || is_nan(y)) {
if (is_snan(x) || is_snan(y))
rv->csr_fcsr |= FFLAG_INVALID_OP;
if (is_nan(x) && !is_nan(y)) {
rv->F[rd] = rv->F[rs2];
} else if (!is_nan(x) && is_nan(y)) {
rv->F[rd] = rv->F[rs1];
} else {
rv->F_int[rd] = RV_NAN;
}
} else {
uint32_t a_sign, b_sign;
a_sign = x & FMASK_SIGN;
b_sign = y & FMASK_SIGN;
if (a_sign != b_sign) {
if (a_sign) {
rv->F[rd] = rv->F[rs1];
} else {
rv->F[rd] = rv->F[rs2];
}
} else {
if ((rv->F[rs1] < rv->F[rs2])) {
rv->F[rd] = rv->F[rs1];
} else {
rv->F[rd] = rv->F[rs2];
}
}
}
break;
case 0b001: /* FMAX */
rv->F[rd] = fmaxf(rv->F[rs1], rv->F[rs2]);
}
case 0b001: { /* FMAX */
uint32_t x, y;
memcpy(&x, rv->F + rs1, 4);
memcpy(&y, rv->F + rs2, 4);
if (is_nan(x) || is_nan(y)) {
if (is_snan(x) || is_snan(y))
rv->csr_fcsr |= FFLAG_INVALID_OP;
if (is_nan(x) && !is_nan(y)) {
rv->F[rd] = rv->F[rs2];
} else if (!is_nan(x) && is_nan(y)) {
rv->F[rd] = rv->F[rs1];
} else {
rv->F_int[rd] = RV_NAN;
}
} else {
uint32_t a_sign, b_sign;
a_sign = x & FMASK_SIGN;
b_sign = y & FMASK_SIGN;
if (a_sign != b_sign) {
if (a_sign) {
rv->F[rd] = rv->F[rs2];
} else {
rv->F[rd] = rv->F[rs1];
}
} else {
if ((rv->F[rs1] > rv->F[rs2])) {
rv->F[rd] = rv->F[rs1];
} else {
rv->F[rd] = rv->F[rs2];
}
}
}


break;
}
default:
rv_except_illegal_insn(rv, insn);
return false;
Expand Down
17 changes: 16 additions & 1 deletion src/riscv_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,7 +302,8 @@ static inline uint32_t sign_extend_b(const uint32_t x)

#ifdef ENABLE_RV32F
/* compute the fclass result */
static inline uint32_t calc_fclass(uint32_t f) {
static inline uint32_t calc_fclass(uint32_t f)
{
const uint32_t sign = f & FMASK_SIGN;
const uint32_t expn = f & FMASK_EXPN;
const uint32_t frac = f & FMASK_FRAC;
Expand Down Expand Up @@ -333,6 +334,20 @@ static inline uint32_t calc_fclass(uint32_t f) {

return out;
}

static inline bool is_nan(uint32_t f)
{
const uint32_t expn = f & FMASK_EXPN;
const uint32_t frac = f & FMASK_FRAC;
return (expn == FMASK_EXPN && frac);
}

static inline bool is_snan(uint32_t f)
{
const uint32_t expn = f & FMASK_EXPN;
const uint32_t frac = f & FMASK_FRAC;
return (expn == FMASK_EXPN && frac && !(frac & FMASK_QNAN));
}
#endif

#ifdef ENABLE_RV32C
Expand Down