@samitouri / QOSamiQemu / commits / a4aa765c9e

fpu: Introduce FloatFmtExpMaxKind

Generalize arm_althp to indicate how exp==max should be handled for the format. Reorganize canonicalize and uncanon_normal to use a switch statement, allowing more cases to be added trivially. Reviewed-by: Chao Liu <chao.liu.zevorn@gmail.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Richard Henderson committed Feb 5, 2026 at 15:21 UTC a4aa765c9ed5350133c3f5bd4b985f81f7871f84
2 files changed +69 -40
fpu/softfloat-parts.c.inc
+56 -36
@@ -227,18 +227,30 @@ static void partsN(canonicalize)(FloatPartsN *p, float_status *status,
227 p->exp = fmt->frac_shift - fmt->exp_bias
228 - shift + !has_pseudo_denormals;
229 }
230 - } else if (likely(p->exp < fmt->exp_max) || fmt->arm_althp) {
231 - p->cls = float_class_normal;
232 - p->exp -= fmt->exp_bias;
233 - frac_shl(p, fmt->frac_shift);
234 - p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
235 - } else if (likely(frac_eqz(p))) {
236 - p->cls = float_class_inf;
237 - } else {
238 - frac_shl(p, fmt->frac_shift);
239 - p->cls = (parts_is_snan_frac(p->frac_hi, status)
240 - ? float_class_snan : float_class_qnan);
230 + return;
231 }
232 + if (unlikely(p->exp == fmt->exp_max)) {
233 + switch (fmt->exp_max_kind) {
234 + case float_expmax_ieee:
235 + if (likely(frac_eqz(p))) {
236 + p->cls = float_class_inf;
237 + } else {
238 + frac_shl(p, fmt->frac_shift);
239 + p->cls = (parts_is_snan_frac(p->frac_hi, status)
240 + ? float_class_snan : float_class_qnan);
241 + }
242 + return;
243 + case float_expmax_normal:
244 + break;
245 + default:
246 + g_assert_not_reached();
247 + }
248 + }
249 +
250 + p->cls = float_class_normal;
251 + p->exp -= fmt->exp_bias;
252 + frac_shl(p, fmt->frac_shift);
253 + p->frac_hi |= DECOMPOSED_IMPLICIT_BIT;
254 }
255
256 /*
@@ -314,29 +326,37 @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s,
326 p->frac_lo &= ~round_mask;
327 }
328
317 - if (fmt->arm_althp) {
318 - /* ARM Alt HP eschews Inf and NaN for a wider exponent. */
319 - if (unlikely(exp > exp_max)) {
320 - /* Overflow. Return the maximum normal. */
321 - flags = float_flag_invalid;
322 - exp = exp_max;
323 - frac_allones(p);
324 - p->frac_lo &= ~round_mask;
325 - }
326 - } else if (unlikely(exp >= exp_max)) {
327 - flags |= float_flag_overflow;
328 - if (s->rebias_overflow) {
329 - exp -= fmt->exp_re_bias;
330 - } else if (overflow_norm) {
331 - flags |= float_flag_inexact;
332 - exp = exp_max - 1;
333 - frac_allones(p);
334 - p->frac_lo &= ~round_mask;
335 - } else {
336 - flags |= float_flag_inexact;
337 - p->cls = float_class_inf;
338 - exp = exp_max;
339 - frac_clear(p);
329 + if (unlikely(exp >= exp_max)) {
330 + switch (fmt->exp_max_kind) {
331 + case float_expmax_ieee:
332 + flags |= float_flag_overflow;
333 + if (s->rebias_overflow) {
334 + exp -= fmt->exp_re_bias;
335 + } else if (overflow_norm) {
336 + flags |= float_flag_inexact;
337 + exp = exp_max - 1;
338 + frac_allones(p);
339 + p->frac_lo &= ~round_mask;
340 + } else {
341 + flags |= float_flag_inexact;
342 + p->cls = float_class_inf;
343 + exp = exp_max;
344 + frac_clear(p);
345 + }
346 + break;
347 +
348 + case float_expmax_normal:
349 + if (unlikely(exp > exp_max)) {
350 + /* Overflow. Return the maximum normal. */
351 + flags = float_flag_invalid;
352 + exp = exp_max;
353 + frac_allones(p);
354 + p->frac_lo &= ~round_mask;
355 + }
356 + break;
357 +
358 + default:
359 + g_assert_not_reached();
360 }
361 }
362 frac_shr(p, frac_shift);
@@ -434,13 +454,13 @@ static void partsN(uncanon)(FloatPartsN *p, float_status *s,
454 frac_clear(p);
455 return;
456 case float_class_inf:
437 - g_assert(!fmt->arm_althp);
457 + assert(fmt->exp_max_kind == float_expmax_ieee);
458 p->exp = fmt->exp_max;
459 frac_clear(p);
460 return;
461 case float_class_qnan:
462 case float_class_snan:
443 - g_assert(!fmt->arm_althp);
463 + assert(fmt->exp_max_kind != float_expmax_normal);
464 p->exp = fmt->exp_max;
465 frac_shr(p, fmt->frac_shift);
466 return;
fpu/softfloat.c
+13 -4
@@ -522,7 +522,16 @@ typedef struct {
522 #define DECOMPOSED_BINARY_POINT 63
523 #define DECOMPOSED_IMPLICIT_BIT (1ull << DECOMPOSED_BINARY_POINT)
524
525 -/* Structure holding all of the relevant parameters for a format.
525 +/* Format-specific handling of exp == exp_max */
526 +typedef enum __attribute__((__packed__)) {
527 + /* exp==max, frac==0 ? infinity : nan; this is ieee standard. */
528 + float_expmax_ieee,
529 + /* exp==max is a normal number; no infinity or nan representation. */
530 + float_expmax_normal,
531 +} FloatFmtExpMaxKind;
532 +
533 +/*
534 + * Structure holding all of the relevant parameters for a format.
535 * exp_size: the size of the exponent field
536 * exp_bias: the offset applied to the exponent field
537 * exp_max: the maximum normalised exponent
@@ -531,7 +540,7 @@ typedef struct {
540 * The following are computed based the size of fraction
541 * round_mask: bits below lsb which must be rounded
542 * The following optional modifiers are available:
534 - * arm_althp: handle ARM Alternative Half Precision
543 + * exp_max_kind: affects how exp == exp_max is interpreted
544 * has_explicit_bit: has an explicit integer bit; this affects whether
545 * the float_status floatx80_behaviour handling applies
546 */
@@ -542,7 +551,7 @@ typedef struct {
551 int exp_max;
552 int frac_size;
553 int frac_shift;
545 - bool arm_althp;
554 + FloatFmtExpMaxKind exp_max_kind;
555 bool has_explicit_bit;
556 uint64_t round_mask;
557 } FloatFmt;
@@ -566,7 +575,7 @@ static const FloatFmt float16_params = {
575
576 static const FloatFmt float16_params_ahp = {
577 FLOAT_PARAMS(5, 10),
569 - .arm_althp = true
578 + .exp_max_kind = float_expmax_normal,
579 };
580
581 static const FloatFmt bfloat16_params = {