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. */