|
@@ -1693,6 +1693,50 @@ static float64 float64_round_pack_canonical(FloatParts64 *p,
|
|
|
return float64_pack_raw(p);
|
|
|
}
|
|
|
|
|
|
+static float64 float64r32_round_pack_canonical(FloatParts64 *p,
|
|
|
+ float_status *s)
|
|
|
+{
|
|
|
+ parts_uncanon(p, s, &float32_params);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * In parts_uncanon, we placed the fraction for float32 at the lsb.
|
|
|
+ * We need to adjust the fraction higher so that the least N bits are
|
|
|
+ * zero, and the fraction is adjacent to the float64 implicit bit.
|
|
|
+ */
|
|
|
+ switch (p->cls) {
|
|
|
+ case float_class_normal:
|
|
|
+ if (unlikely(p->exp == 0)) {
|
|
|
+ /*
|
|
|
+ * The result is denormal for float32, but can be represented
|
|
|
+ * in normalized form for float64. Adjust, per canonicalize.
|
|
|
+ */
|
|
|
+ int shift = frac_normalize(p);
|
|
|
+ p->exp = (float32_params.frac_shift -
|
|
|
+ float32_params.exp_bias - shift + 1 +
|
|
|
+ float64_params.exp_bias);
|
|
|
+ frac_shr(p, float64_params.frac_shift);
|
|
|
+ } else {
|
|
|
+ frac_shl(p, float32_params.frac_shift - float64_params.frac_shift);
|
|
|
+ p->exp += float64_params.exp_bias - float32_params.exp_bias;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case float_class_snan:
|
|
|
+ case float_class_qnan:
|
|
|
+ frac_shl(p, float32_params.frac_shift - float64_params.frac_shift);
|
|
|
+ p->exp = float64_params.exp_max;
|
|
|
+ break;
|
|
|
+ case float_class_inf:
|
|
|
+ p->exp = float64_params.exp_max;
|
|
|
+ break;
|
|
|
+ case float_class_zero:
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ g_assert_not_reached();
|
|
|
+ }
|
|
|
+
|
|
|
+ return float64_pack_raw(p);
|
|
|
+}
|
|
|
+
|
|
|
static void float128_unpack_canonical(FloatParts128 *p, float128 f,
|
|
|
float_status *s)
|
|
|
{
|
|
@@ -1938,6 +1982,28 @@ float64_sub(float64 a, float64 b, float_status *s)
|
|
|
return float64_addsub(a, b, s, hard_f64_sub, soft_f64_sub);
|
|
|
}
|
|
|
|
|
|
+static float64 float64r32_addsub(float64 a, float64 b, float_status *status,
|
|
|
+ bool subtract)
|
|
|
+{
|
|
|
+ FloatParts64 pa, pb, *pr;
|
|
|
+
|
|
|
+ float64_unpack_canonical(&pa, a, status);
|
|
|
+ float64_unpack_canonical(&pb, b, status);
|
|
|
+ pr = parts_addsub(&pa, &pb, status, subtract);
|
|
|
+
|
|
|
+ return float64r32_round_pack_canonical(pr, status);
|
|
|
+}
|
|
|
+
|
|
|
+float64 float64r32_add(float64 a, float64 b, float_status *status)
|
|
|
+{
|
|
|
+ return float64r32_addsub(a, b, status, false);
|
|
|
+}
|
|
|
+
|
|
|
+float64 float64r32_sub(float64 a, float64 b, float_status *status)
|
|
|
+{
|
|
|
+ return float64r32_addsub(a, b, status, true);
|
|
|
+}
|
|
|
+
|
|
|
static bfloat16 QEMU_FLATTEN
|
|
|
bfloat16_addsub(bfloat16 a, bfloat16 b, float_status *status, bool subtract)
|
|
|
{
|
|
@@ -2069,6 +2135,17 @@ float64_mul(float64 a, float64 b, float_status *s)
|
|
|
f64_is_zon2, f64_addsubmul_post);
|
|
|
}
|
|
|
|
|
|
+float64 float64r32_mul(float64 a, float64 b, float_status *status)
|
|
|
+{
|
|
|
+ FloatParts64 pa, pb, *pr;
|
|
|
+
|
|
|
+ float64_unpack_canonical(&pa, a, status);
|
|
|
+ float64_unpack_canonical(&pb, b, status);
|
|
|
+ pr = parts_mul(&pa, &pb, status);
|
|
|
+
|
|
|
+ return float64r32_round_pack_canonical(pr, status);
|
|
|
+}
|
|
|
+
|
|
|
bfloat16 QEMU_FLATTEN
|
|
|
bfloat16_mul(bfloat16 a, bfloat16 b, float_status *status)
|
|
|
{
|
|
@@ -2296,6 +2373,19 @@ float64_muladd(float64 xa, float64 xb, float64 xc, int flags, float_status *s)
|
|
|
return soft_f64_muladd(ua.s, ub.s, uc.s, flags, s);
|
|
|
}
|
|
|
|
|
|
+float64 float64r32_muladd(float64 a, float64 b, float64 c,
|
|
|
+ int flags, float_status *status)
|
|
|
+{
|
|
|
+ FloatParts64 pa, pb, pc, *pr;
|
|
|
+
|
|
|
+ float64_unpack_canonical(&pa, a, status);
|
|
|
+ float64_unpack_canonical(&pb, b, status);
|
|
|
+ float64_unpack_canonical(&pc, c, status);
|
|
|
+ pr = parts_muladd(&pa, &pb, &pc, flags, status);
|
|
|
+
|
|
|
+ return float64r32_round_pack_canonical(pr, status);
|
|
|
+}
|
|
|
+
|
|
|
bfloat16 QEMU_FLATTEN bfloat16_muladd(bfloat16 a, bfloat16 b, bfloat16 c,
|
|
|
int flags, float_status *status)
|
|
|
{
|
|
@@ -2419,6 +2509,17 @@ float64_div(float64 a, float64 b, float_status *s)
|
|
|
f64_div_pre, f64_div_post);
|
|
|
}
|
|
|
|
|
|
+float64 float64r32_div(float64 a, float64 b, float_status *status)
|
|
|
+{
|
|
|
+ FloatParts64 pa, pb, *pr;
|
|
|
+
|
|
|
+ float64_unpack_canonical(&pa, a, status);
|
|
|
+ float64_unpack_canonical(&pb, b, status);
|
|
|
+ pr = parts_div(&pa, &pb, status);
|
|
|
+
|
|
|
+ return float64r32_round_pack_canonical(pr, status);
|
|
|
+}
|
|
|
+
|
|
|
bfloat16 QEMU_FLATTEN
|
|
|
bfloat16_div(bfloat16 a, bfloat16 b, float_status *status)
|
|
|
{
|
|
@@ -4285,6 +4386,15 @@ float64 QEMU_FLATTEN float64_sqrt(float64 xa, float_status *s)
|
|
|
return soft_f64_sqrt(ua.s, s);
|
|
|
}
|
|
|
|
|
|
+float64 float64r32_sqrt(float64 a, float_status *status)
|
|
|
+{
|
|
|
+ FloatParts64 p;
|
|
|
+
|
|
|
+ float64_unpack_canonical(&p, a, status);
|
|
|
+ parts_sqrt(&p, status, &float64_params);
|
|
|
+ return float64r32_round_pack_canonical(&p, status);
|
|
|
+}
|
|
|
+
|
|
|
bfloat16 QEMU_FLATTEN bfloat16_sqrt(bfloat16 a, float_status *status)
|
|
|
{
|
|
|
FloatParts64 p;
|