bool b_sign = b->sign ^ subtract;
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+ /*
+ * For addition and subtraction, we will consume an
+ * input denormal unless the other input is a NaN.
+ */
+ if ((ab_mask & (float_cmask_denormal | float_cmask_anynan)) ==
+ float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
if (a->sign != b_sign) {
/* Subtraction */
if (likely(cmask_is_only_normals(ab_mask))) {
if (likely(cmask_is_only_normals(ab_mask))) {
FloatPartsW tmp;
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
frac_mulw(&tmp, a, b);
frac_truncjam(a, &tmp);
}
/* Multiply by 0 or Inf */
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
if (ab_mask & float_cmask_inf) {
a->cls = float_class_inf;
a->sign = sign;
if (flags & float_muladd_negate_result) {
a->sign ^= 1;
}
+
+ /*
+ * All result types except for "return the default NaN
+ * because this is an Invalid Operation" go through here;
+ * this matches the set of cases where we consumed a
+ * denormal input.
+ */
+ if (abc_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
return a;
return_sub_zero:
bool sign = a->sign ^ b->sign;
if (likely(cmask_is_only_normals(ab_mask))) {
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
a->sign = sign;
a->exp -= b->exp + frac_div(a, b);
return a;
return parts_pick_nan(a, b, s);
}
+ if ((ab_mask & float_cmask_denormal) && b->cls != float_class_zero) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
a->sign = sign;
/* Inf / X */
int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
if (likely(cmask_is_only_normals(ab_mask))) {
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
frac_modrem(a, b, mod_quot);
return a;
}
return a;
}
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
/* N % Inf; 0 % N */
g_assert(b->cls == float_class_inf || a->cls == float_class_zero);
return a;
if (unlikely(a->cls != float_class_normal)) {
switch (a->cls) {
case float_class_denormal:
+ if (!a->sign) {
+ /* -ve denormal will be InvalidOperation */
+ float_raise(float_flag_input_denormal_used, status);
+ }
break;
case float_class_snan:
case float_class_qnan:
if ((flags & (minmax_isnum | minmax_isnumber))
&& !(ab_mask & float_cmask_snan)
&& (ab_mask & ~float_cmask_qnan)) {
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
return is_nan(a->cls) ? b : a;
}
return parts_pick_nan(a, b, s);
}
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
a_exp = a->exp;
b_exp = b->exp;
if (likely(cmask_is_only_normals(ab_mask))) {
FloatRelation cmp;
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
if (a->sign != b->sign) {
goto a_sign;
}
return float_relation_unordered;
}
+ if (ab_mask & float_cmask_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
+
if (ab_mask & float_cmask_zero) {
if (ab_mask == float_cmask_zero) {
return float_relation_equal;
case float_class_zero:
case float_class_inf:
break;
- case float_class_normal:
case float_class_denormal:
+ float_raise(float_flag_input_denormal_used, s);
+ /* fall through */
+ case float_class_normal:
a->exp += MIN(MAX(n, -0x10000), 0x10000);
break;
default:
if (unlikely(a->cls != float_class_normal)) {
switch (a->cls) {
case float_class_denormal:
+ if (!a->sign) {
+ /* -ve denormal will be InvalidOperation */
+ float_raise(float_flag_input_denormal_used, s);
+ }
break;
case float_class_snan:
case float_class_qnan:
float16_params_ahp.frac_size + 1);
break;
- case float_class_normal:
case float_class_denormal:
+ float_raise(float_flag_input_denormal_used, s);
+ break;
+ case float_class_normal:
case float_class_zero:
break;
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
static void parts128_float_to_float(FloatParts128 *a, float_status *s)
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
#define parts_float_to_float(P, S) \
a->sign = b->sign;
a->exp = b->exp;
- if (is_anynorm(a->cls)) {
+ switch (a->cls) {
+ case float_class_denormal:
+ float_raise(float_flag_input_denormal_used, s);
+ /* fall through */
+ case float_class_normal:
frac_truncjam(a, b);
- } else if (is_nan(a->cls)) {
+ break;
+ case float_class_snan:
+ case float_class_qnan:
/* Discard the low bits of the NaN. */
a->frac = b->frac_hi;
parts_return_nan(a, s);
+ break;
+ default:
+ break;
}
}
if (is_nan(a->cls)) {
parts_return_nan(a, s);
}
+ if (a->cls == float_class_denormal) {
+ float_raise(float_flag_input_denormal_used, s);
+ }
}
float32 float16_to_float32(float16 a, bool ieee, float_status *s)
goto soft;
}
- float32_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(float32_is_denormal(ua.s) || float32_is_denormal(ub.s))) {
+ /* We may need to set the input_denormal_used flag */
+ goto soft;
+ }
+
if (isgreaterequal(ua.h, ub.h)) {
if (isgreater(ua.h, ub.h)) {
return float_relation_greater;
goto soft;
}
- float64_input_flush2(&ua.s, &ub.s, s);
+ if (unlikely(float64_is_denormal(ua.s) || float64_is_denormal(ub.s))) {
+ /* We may need to set the input_denormal_used flag */
+ goto soft;
+ }
+
if (isgreaterequal(ua.h, ub.h)) {
if (isgreater(ua.h, ub.h)) {
return float_relation_greater;