@samitouri / QOSamiQemu / commits / 523578ac36

target/arm: Use FloatParts64 in bfdotadd_ebf

Use softfloat-parts.h so that we can more naturally perform the required operations witha single rounding step. This happens to also simplify the NaN detection step. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260609192110.752384-2-richard.henderson@linaro.org Message-Id: <20260517002550.321291-9-richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Jun 9, 2026 at 12:20 UTC 523578ac36495058a421c03efd6249fa5750f9f4
1 file changed +40 -38
target/arm/tcg/vec_helper.c
+40 -38
@@ -22,6 +22,7 @@
22 #include "helper.h"
23 #include "tcg/tcg-gvec-desc.h"
24 #include "fpu/softfloat.h"
25 +#include "fpu/softfloat-parts.h"
26 #include "qemu/int128.h"
27 #include "crypto/clmul.h"
28 #include "vec_internal.h"
@@ -2895,61 +2896,62 @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst)
2896 float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2,
2897 float_status *fpst, float_status *fpst_odd)
2898 {
2899 + /* Unpack two BFloat16 into two Float32, trivially. */
2900 float32 s1r = e1 << 16;
2901 float32 s1c = e1 & 0xffff0000u;
2902 float32 s2r = e2 << 16;
2903 float32 s2c = e2 & 0xffff0000u;
2904 float32 t32;
2905
2906 + /*
2907 + * Compare f16_dotadd() in sme_helper.c, but here we have
2908 + * bfloat16 inputs. In particular that means that we do not
2909 + * want the FPCR.FZ16 flush semantics, so we use the normal
2910 + * float_status for the input handling here.
2911 + */
2912 + FloatParts64 p1r = float32_unpack_canonical(s1r, fpst);
2913 + FloatParts64 p1c = float32_unpack_canonical(s1c, fpst);
2914 + FloatParts64 p2r = float32_unpack_canonical(s2r, fpst);
2915 + FloatParts64 p2c = float32_unpack_canonical(s2c, fpst);
2916 +
2917 + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) |
2918 + float_cmask(p2r.cls) | float_cmask(p2c.cls));
2919 +
2920 /* C.f. FPProcessNaNs4 */
2905 - if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) ||
2906 - float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) {
2907 - if (float32_is_signaling_nan(s1r, fpst)) {
2908 - t32 = s1r;
2909 - } else if (float32_is_signaling_nan(s1c, fpst)) {
2910 - t32 = s1c;
2911 - } else if (float32_is_signaling_nan(s2r, fpst)) {
2912 - t32 = s2r;
2913 - } else if (float32_is_signaling_nan(s2c, fpst)) {
2914 - t32 = s2c;
2915 - } else if (float32_is_any_nan(s1r)) {
2916 - t32 = s1r;
2917 - } else if (float32_is_any_nan(s1c)) {
2918 - t32 = s1c;
2919 - } else if (float32_is_any_nan(s2r)) {
2920 - t32 = s2r;
2921 + if (unlikely(all_mask & float_cmask_anynan)) {
2922 + if (unlikely(all_mask & float_cmask_snan)) {
2923 + if (p1r.cls == float_class_snan) {
2924 + t32 = s1r;
2925 + } else if (p1c.cls == float_class_snan) {
2926 + t32 = s1c;
2927 + } else if (p2r.cls == float_class_snan) {
2928 + t32 = s2r;
2929 + } else {
2930 + t32 = s2c;
2931 + }
2932 } else {
2922 - t32 = s2c;
2933 + if (p1r.cls == float_class_qnan) {
2934 + t32 = s1r;
2935 + } else if (p1c.cls == float_class_qnan) {
2936 + t32 = s1c;
2937 + } else if (p2r.cls == float_class_qnan) {
2938 + t32 = s2r;
2939 + } else {
2940 + t32 = s2c;
2941 + }
2942 }
2943 /*
2944 * FPConvertNaN(FPProcessNaN(t32)) will be done as part
2945 * of the final addition below.
2946 */
2947 } else {
2929 - /*
2930 - * Compare f16_dotadd() in sme_helper.c, but here we have
2931 - * bfloat16 inputs. In particular that means that we do not
2932 - * want the FPCR.FZ16 flush semantics, so we use the normal
2933 - * float_status for the input handling here.
2934 - */
2935 - float64 e1r = float32_to_float64(s1r, fpst);
2936 - float64 e1c = float32_to_float64(s1c, fpst);
2937 - float64 e2r = float32_to_float64(s2r, fpst);
2938 - float64 e2c = float32_to_float64(s2c, fpst);
2939 - float64 t64;
2940 -
2948 /*
2949 * The ARM pseudocode function FPDot performs both multiplies
2943 - * and the add with a single rounding operation. Emulate this
2944 - * by performing the first multiply in round-to-odd, then doing
2945 - * the second multiply as fused multiply-add, and rounding to
2946 - * float32 all in one step.
2950 + * and the add with a single rounding operation.
2951 */
2948 - t64 = float64_mul(e1r, e2r, fpst_odd);
2949 - t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst);
2950 -
2951 - /* This conversion is exact, because we've already rounded. */
2952 - t32 = float64_to_float32(t64, fpst);
2952 + FloatParts64 tmp = parts64_mul(&p1r, &p2r, fpst);
2953 + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, fpst);
2954 + t32 = float32_round_pack_canonical(&tmp, fpst);
2955 }
2956
2957 /* The final accumulation step is not fused. */