aboutsummaryrefslogtreecommitdiff
path: root/fpu/softfloat-parts.c.inc
diff options
context:
space:
mode:
authorRichard Henderson <richard.henderson@linaro.org>2020-11-14 16:52:38 -0800
committerRichard Henderson <richard.henderson@linaro.org>2021-06-03 13:59:34 -0700
commite1c4667a9b91b1500e47f4cbb4e43a36136e6d29 (patch)
treeed091608ea2fe0b859f757f001eeef7f92e0bd24 /fpu/softfloat-parts.c.inc
parent37c954a1b96a65d836705a6e530eeab58cc9d964 (diff)
softfloat: Move minmax_flags to softfloat-parts.c.inc
Rename to parts$N_minmax. Combine 3 bool arguments to a bitmask. Introduce ftype_minmax functions as a common optimization point. Fold bfloat16 expansions into the same macro as the other types. Reviewed-by: David Hildenbrand <david@redhat.com> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'fpu/softfloat-parts.c.inc')
-rw-r--r--fpu/softfloat-parts.c.inc80
1 files changed, 80 insertions, 0 deletions
diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc
index 2eb7bb96b3..b9094768db 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -938,3 +938,83 @@ static void partsN(uint_to_float)(FloatPartsN *p, uint64_t a,
p->frac_hi = a << shift;
}
}
+
+/*
+ * Float min/max.
+ */
+static FloatPartsN *partsN(minmax)(FloatPartsN *a, FloatPartsN *b,
+ float_status *s, int flags)
+{
+ int ab_mask = float_cmask(a->cls) | float_cmask(b->cls);
+ int a_exp, b_exp, cmp;
+
+ if (unlikely(ab_mask & float_cmask_anynan)) {
+ /*
+ * For minnum/maxnum, if one operand is a QNaN, and the other
+ * operand is numerical, then return numerical argument.
+ */
+ if ((flags & minmax_isnum)
+ && !(ab_mask & float_cmask_snan)
+ && (ab_mask & ~float_cmask_qnan)) {
+ return is_nan(a->cls) ? b : a;
+ }
+ return parts_pick_nan(a, b, s);
+ }
+
+ a_exp = a->exp;
+ b_exp = b->exp;
+
+ if (unlikely(ab_mask != float_cmask_normal)) {
+ switch (a->cls) {
+ case float_class_normal:
+ break;
+ case float_class_inf:
+ a_exp = INT16_MAX;
+ break;
+ case float_class_zero:
+ a_exp = INT16_MIN;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ switch (b->cls) {
+ case float_class_normal:
+ break;
+ case float_class_inf:
+ b_exp = INT16_MAX;
+ break;
+ case float_class_zero:
+ b_exp = INT16_MIN;
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+ }
+
+ /* Compare magnitudes. */
+ cmp = a_exp - b_exp;
+ if (cmp == 0) {
+ cmp = frac_cmp(a, b);
+ }
+
+ /*
+ * Take the sign into account.
+ * For ismag, only do this if the magnitudes are equal.
+ */
+ if (!(flags & minmax_ismag) || cmp == 0) {
+ if (a->sign != b->sign) {
+ /* For differing signs, the negative operand is less. */
+ cmp = a->sign ? -1 : 1;
+ } else if (a->sign) {
+ /* For two negative operands, invert the magnitude comparison. */
+ cmp = -cmp;
+ }
+ }
+
+ if (flags & minmax_ismin) {
+ cmp = -cmp;
+ }
+ return cmp < 0 ? b : a;
+}