Skip to content

Commit bb73267

Browse files
committed
Improve fmin/fmax
Passed 2 more test in riscv-arch-test. Supports of fmin and fmax is complete. In IEEE 754-201x, fmin(x,y)/fmax(x,y) is defined as: - min(x,y)/max(x,y) if both x and y are numbers - if one is NAN and another is a number, return the number - if both are NAN, return NAN This operation raises invalid_operation when receiving SNAN.
1 parent d4c9560 commit bb73267

File tree

2 files changed

+90
-7
lines changed

2 files changed

+90
-7
lines changed

src/emulate.c

Lines changed: 79 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,8 +1065,8 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
10651065
/* dispatch based on func7 (low 2 bits are width) */
10661066
switch (funct7) {
10671067
case 0b0000000: /* FADD */
1068-
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2]) ||
1069-
isnan(rv->F[rs1] + rv->F[rs2])) {
1068+
if (isnanf(rv->F[rs1]) || isnanf(rv->F[rs2]) ||
1069+
isnanf(rv->F[rs1] + rv->F[rs2])) {
10701070
/* raise invalid operation */
10711071
rv->F_int[rd] = RV_NAN; /* F_int is the integer shortcut of F */
10721072
rv->csr_fcsr |= FFLAG_INVALID_OP;
@@ -1079,7 +1079,7 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
10791079
}
10801080
break;
10811081
case 0b0000100: /* FSUB */
1082-
if (isnan(rv->F[rs1]) || isnan(rv->F[rs2])) {
1082+
if (isnanf(rv->F[rs1]) || isnanf(rv->F[rs2])) {
10831083
rv->F_int[rd] = RV_NAN;
10841084
} else {
10851085
rv->F[rd] = rv->F[rs1] - rv->F[rs2];
@@ -1119,12 +1119,84 @@ static inline bool op_fp(struct riscv_t *rv, uint32_t insn)
11191119
}
11201120
case 0b0010100:
11211121
switch (rm) {
1122-
case 0b000: /* FMIN */
1123-
rv->F[rd] = fminf(rv->F[rs1], rv->F[rs2]);
1122+
case 0b000: { /* FMIN */
1123+
/*
1124+
In IEEE754-201x, fmin(x, y) return
1125+
- min(x,y) if both numbers are not NaN
1126+
- if one is NaN and another is a number, return the number
1127+
- if both are NaN, return NaN
1128+
1129+
When input is signaling NaN, raise invalid operation
1130+
*/
1131+
uint32_t x, y;
1132+
memcpy(&x, rv->F + rs1, 4);
1133+
memcpy(&y, rv->F + rs2, 4);
1134+
if (is_nan(x) || is_nan(y)) {
1135+
if (is_snan(x) || is_snan(y))
1136+
rv->csr_fcsr |= FFLAG_INVALID_OP;
1137+
if (is_nan(x) && !is_nan(y)) {
1138+
rv->F[rd] = rv->F[rs2];
1139+
} else if (!is_nan(x) && is_nan(y)) {
1140+
rv->F[rd] = rv->F[rs1];
1141+
} else {
1142+
rv->F_int[rd] = RV_NAN;
1143+
}
1144+
} else {
1145+
uint32_t a_sign, b_sign;
1146+
a_sign = x & FMASK_SIGN;
1147+
b_sign = y & FMASK_SIGN;
1148+
if (a_sign != b_sign) {
1149+
if (a_sign) {
1150+
rv->F[rd] = rv->F[rs1];
1151+
} else {
1152+
rv->F[rd] = rv->F[rs2];
1153+
}
1154+
} else {
1155+
if ((rv->F[rs1] < rv->F[rs2])) {
1156+
rv->F[rd] = rv->F[rs1];
1157+
} else {
1158+
rv->F[rd] = rv->F[rs2];
1159+
}
1160+
}
1161+
}
11241162
break;
1125-
case 0b001: /* FMAX */
1126-
rv->F[rd] = fmaxf(rv->F[rs1], rv->F[rs2]);
1163+
}
1164+
case 0b001: { /* FMAX */
1165+
uint32_t x, y;
1166+
memcpy(&x, rv->F + rs1, 4);
1167+
memcpy(&y, rv->F + rs2, 4);
1168+
if (is_nan(x) || is_nan(y)) {
1169+
if (is_snan(x) || is_snan(y))
1170+
rv->csr_fcsr |= FFLAG_INVALID_OP;
1171+
if (is_nan(x) && !is_nan(y)) {
1172+
rv->F[rd] = rv->F[rs2];
1173+
} else if (!is_nan(x) && is_nan(y)) {
1174+
rv->F[rd] = rv->F[rs1];
1175+
} else {
1176+
rv->F_int[rd] = RV_NAN;
1177+
}
1178+
} else {
1179+
uint32_t a_sign, b_sign;
1180+
a_sign = x & FMASK_SIGN;
1181+
b_sign = y & FMASK_SIGN;
1182+
if (a_sign != b_sign) {
1183+
if (a_sign) {
1184+
rv->F[rd] = rv->F[rs2];
1185+
} else {
1186+
rv->F[rd] = rv->F[rs1];
1187+
}
1188+
} else {
1189+
if ((rv->F[rs1] > rv->F[rs2])) {
1190+
rv->F[rd] = rv->F[rs1];
1191+
} else {
1192+
rv->F[rd] = rv->F[rs2];
1193+
}
1194+
}
1195+
}
1196+
1197+
11271198
break;
1199+
}
11281200
default:
11291201
rv_except_illegal_insn(rv, insn);
11301202
return false;

src/riscv_private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,17 @@ static inline uint32_t calc_fclass(uint32_t f) {
333333

334334
return out;
335335
}
336+
static inline bool is_nan(uint32_t f){
337+
const uint32_t expn = f & FMASK_EXPN;
338+
const uint32_t frac = f & FMASK_FRAC;
339+
return (expn == FMASK_EXPN && frac);
340+
}
341+
342+
static inline bool is_snan(uint32_t f){
343+
const uint32_t expn = f & FMASK_EXPN;
344+
const uint32_t frac = f & FMASK_FRAC;
345+
return (expn == FMASK_EXPN && frac && !(frac & FMASK_QNAN));
346+
}
336347
#endif
337348

338349
#ifdef ENABLE_RV32C

0 commit comments

Comments
 (0)