@samitouri / QOSamiQemu / commits / dbaa1996b6

target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD

Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-8-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

Richard Henderson committed Jun 9, 2026 at 12:20 UTC dbaa1996b6b4f149dbf1f214c7dc69f912a25b49
7 files changed +183
target/arm/helper-fp8.h new
+14
@@ -0,0 +1,14 @@
1 +/* SPDX-License-Identifier: GPL-2.0-or-later */
2 +
3 +#ifndef HELPER_FP8_H
4 +#define HELPER_FP8_H
5 +
6 +#include "exec/helper-proto-common.h"
7 +#include "exec/helper-gen-common.h"
8 +
9 +#define HELPER_H "tcg/helper-fp8-defs.h"
10 +#include "exec/helper-proto.h.inc"
11 +#include "exec/helper-gen.h.inc"
12 +#undef HELPER_H
13 +
14 +#endif /* HELPER_FP8_H */
target/arm/tcg/a64.decode
+3
@@ -1921,6 +1921,9 @@ URSQRTE_v 0.10 1110 101 00001 11001 0 ..... ..... @qrr_s
1921
1922 FCVTL_v 0.00 1110 0.1 00001 01111 0 ..... ..... @qrr_sd
1923
1924 +BF1CVTL 0.10 1110 101 00001 01111 0 ..... ..... @qrr_h
1925 +BF2CVTL 0.10 1110 111 00001 01111 0 ..... ..... @qrr_h
1926 +
1927 &fcvt_q rd rn esz q shift
1928 @fcvtq_h . q:1 . ...... 001 .... ...... rn:5 rd:5 \
1929 &fcvt_q esz=1 shift=%fcvt_f_sh_h
target/arm/tcg/fp8_helper.c new
+124
@@ -0,0 +1,124 @@
1 +/*
2 + * AArch64 FP8 Operations
3 + * SPDX-License-Identifier: GPL-2.0-or-later
4 + */
5 +
6 +#include "qemu/osdep.h"
7 +#include "cpu.h"
8 +#include "internals.h"
9 +#include "tcg/tcg-gvec-desc.h"
10 +#include "fpu/softfloat.h"
11 +#include "fpu/softfloat-parts.h"
12 +#include "helper-fp8.h"
13 +#include "vec_internal.h"
14 +
15 +#define HELPER_H "tcg/helper-fp8-defs.h"
16 +#include "exec/helper-info.c.inc"
17 +
18 +typedef enum FPMRType {
19 + OFP8_E5M2 = 0,
20 + OFP8_E4M3 = 1,
21 +} FPMRType;
22 +
23 +typedef struct FP8Context {
24 + float_status stat;
25 + ARMFPStatusFlavour fpst;
26 + FPMRType f8fmt;
27 + int scale;
28 + bool high;
29 +} FP8Context;
30 +
31 +static FP8Context fp8_start(CPUARMState *env, uint32_t desc,
32 + FPMRType f8fmt, int scale)
33 +{
34 + ARMFPStatusFlavour fpst = extract32(desc, SIMD_DATA_SHIFT + 2, 4);
35 +
36 + FP8Context ret = {
37 + .stat = env->vfp.fp_status[fpst],
38 + .fpst = fpst,
39 + .f8fmt = f8fmt,
40 + .scale = scale,
41 + .high = extract32(desc, SIMD_DATA_SHIFT + 1, 1),
42 + };
43 +
44 + set_flush_to_zero(0, &ret.stat);
45 + set_flush_inputs_to_zero(0, &ret.stat);
46 + set_default_nan_mode(true, &ret.stat);
47 + set_float_rounding_mode(float_round_nearest_even, &ret.stat);
48 +
49 + return ret;
50 +}
51 +
52 +static void fp8_cvt_finish(CPUARMState *env, FP8Context *c)
53 +{
54 + /* FP8 convert insns don't update FPSR.IDC */
55 + int e = get_float_exception_flags(&c->stat);
56 + float_raise(e & ~float_flag_input_denormal_used,
57 + &env->vfp.fp_status[c->fpst]);
58 +}
59 +
60 +static FP8Context fp8_src_start(CPUARMState *env, uint32_t desc, int scale_mask)
61 +{
62 + bool issrc2 = extract32(desc, SIMD_DATA_SHIFT, 1);
63 + uint64_t fpmr = env->vfp.fpmr;
64 + FPMRType f8fmt = (issrc2
65 + ? FIELD_EX64(fpmr, FPMR, F8S2)
66 + : FIELD_EX64(fpmr, FPMR, F8S1));
67 + int scale;
68 +
69 + scale = fpmr >> (issrc2 ? R_FPMR_LSCALE2_SHIFT : R_FPMR_LSCALE_SHIFT);
70 + scale = -(scale & scale_mask);
71 +
72 + return fp8_start(env, desc, f8fmt, scale);
73 +}
74 +
75 +/*
76 + * Invalid input format: we could take one of the usual set of
77 + * CONSTRAINED UNPREDICTABLE options for use of a reserved value,
78 + * but choose to take the additional option provided by the FPMR
79 + * register specification, of treating the input as if it were an SNaN.
80 + *
81 + * One of the uses of the input will convert to default nan (because
82 + * all fp8 operations use default_nan_mode) and raise invalid (which
83 + * the operation might suppress by not updating IOC).
84 + */
85 +static FloatParts64 fp8_invalid_input(uint8_t x, float_status *s)
86 +{
87 + return (FloatParts64){ .cls = float_class_snan };
88 +}
89 +
90 +typedef FloatParts64 fp8_input_fn(uint8_t x, float_status *s);
91 +
92 +static fp8_input_fn * const fp8_input_fmt[8] = {
93 + [0 ... 7] = fp8_invalid_input,
94 + [OFP8_E5M2] = float8_e5m2_unpack_canonical,
95 + [OFP8_E4M3] = float8_e4m3_unpack_canonical,
96 +};
97 +
98 +static bfloat16 fcvt_fp8_to_b16(uint8_t x, fp8_input_fn *f8fmt,
99 + int scale, float_status *s)
100 +{
101 + FloatParts64 p = f8fmt(x, s);
102 + p = parts64_scalbn(&p, scale, s);
103 + return bfloat16_round_pack_canonical(&p, s);
104 +}
105 +
106 +void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc)
107 +{
108 + FP8Context ctx = fp8_src_start(env, desc, 0x3f);
109 + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt];
110 + uint8_t *n = vn, scratch[16];
111 + bfloat16 *d = vd;
112 +
113 + if (vd == vn) {
114 + n = memcpy(scratch, vn, 16);
115 + }
116 + n += ctx.high * 8;
117 +
118 + for (size_t i = 0; i < 8; ++i) {
119 + d[H2(i)] = fcvt_fp8_to_b16(n[H1(i)], input_fmt, ctx.scale, &ctx.stat);
120 + }
121 +
122 + fp8_cvt_finish(env, &ctx);
123 + clear_tail(vd, 16, simd_maxsz(desc));
124 +}
target/arm/tcg/helper-fp8-defs.h new
+6
@@ -0,0 +1,6 @@
1 +/*
2 + * AArch64 FP8 helper definitions
3 + * SPDX-License-Identifier: GPL-2.0-or-later
4 + */
5 +
6 +DEF_HELPER_FLAGS_4(advsimd_bfcvtl, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32)
target/arm/tcg/meson.build
+1
@@ -41,6 +41,7 @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files(
41 'sme_helper.c',
42 'sve_helper.c',
43 'vec_helper64.c',
44 + 'fp8_helper.c',
45 ))
46
47 arm_common_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c'))
target/arm/tcg/translate-a64.c
+34
@@ -22,6 +22,7 @@
22 #include "helper-a64.h"
23 #include "helper-sme.h"
24 #include "helper-sve.h"
25 +#include "helper-fp8.h"
26 #include "translate.h"
27 #include "translate-a64.h"
28 #include "tcg/tcg-op.h"
@@ -1461,6 +1462,24 @@ static bool fp_access_check(DisasContext *s)
1462 return fp_access_check_only(s) && nonstreaming_check(s);
1463 }
1464
1465 +/*
1466 + * Check that FPMR access is enabled, for an indirect reference by a
1467 + * vector instruction. See CheckFPMREnabled().
1468 + */
1469 +bool fpmr_access_check(DisasContext *s)
1470 +{
1471 + if (s->fpmr_el) {
1472 + /*
1473 + * While denied direct access to the FPMR raises SystemRegisterTrap
1474 + * and targets a specific EL, denied indirect access to the FPMR
1475 + * results in a simple UNDEFINED to the default exception level.
1476 + */
1477 + unallocated_encoding(s);
1478 + return false;
1479 + }
1480 + return true;
1481 +}
1482 +
1483 /*
1484 * Return <0 for non-supported element sizes, with MO_16 controlled by
1485 * FEAT_FP16; return 0 for fp disabled; otherwise return >0 for success.
@@ -10709,6 +10728,21 @@ static bool trans_FCVTL_v(DisasContext *s, arg_qrr_e *a)
10728 return true;
10729 }
10730
10731 +static bool do_f8cvt(DisasContext *s, arg_qrr_e *a,
10732 + gen_helper_gvec_2_ptr *fn, bool issrc2)
10733 +{
10734 + if (fpmr_access_check(s) && fp_access_check(s)) {
10735 + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd),
10736 + vec_full_reg_offset(s, a->rn),
10737 + tcg_env, 16, vec_full_reg_size(s),
10738 + issrc2 | (a->q << 1) | (FPST_A64 << 2), fn);
10739 + }
10740 + return true;
10741 +}
10742 +
10743 +TRANS_FEAT(BF1CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, false)
10744 +TRANS_FEAT(BF2CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, true)
10745 +
10746 static bool trans_OK(DisasContext *s, arg_OK *a)
10747 {
10748 return true;
target/arm/tcg/translate-a64.h
+1
@@ -25,6 +25,7 @@ TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf);
25 void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v);
26 bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn,
27 unsigned int imms, unsigned int immr);
28 +bool fpmr_access_check(DisasContext *s);
29 bool sve_access_check(DisasContext *s);
30 bool sme_enabled_check(DisasContext *s);
31 bool sme_enabled_check_with_svcr(DisasContext *s, unsigned);