:p
atchew
Login
Hi; here's an arm pullreq. The biggest part of this is RTH's patches implementing FEAT_FP8 and related features. Gabriel Brookman's MTE4 emulation is also in here. thanks -- PMM The following changes since commit de5d8bfd6105d3dd3ae668df9762df244a6d1506: Merge tag 'pull-loongarch-20260609' of https://github.com/gaosong715/qemu into staging (2026-06-09 14:00:28 -0400) are available in the Git repository at: https://gitlab.com/pm215/qemu.git tags/pull-target-arm-20260610 for you to fetch changes up to c45b02cb24ee20ffee2508f50278b392526427eb: target/arm: Enable FEAT_F8F16MM for -cpu max (2026-06-10 16:54:40 +0100) ---------------------------------------------------------------- target-arm queue: * Emulate various FP8 related features: FEAT_F8F16MM, FEAT_F8F32MM, FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2, FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4, FEAT_FP8FMA, FEAT_SSVE_FP8FMA, FEAT_SME_LUTv2, FEAT_FP8, FEAT_LUT * Emulate MTE4 features: FEAT_MTE_CANONICAL_TAGS, FEAT_MTE_NO_ADDRESS_TAGS, FEAT_MTE_PERM,FEAT_MTE_STORE_ONLY, FEAT_MTE_TAGGED_FAR * target/arm: fix WFET typo in syndrome * target/arm: Preparatory patches for implementing WFE * hw/dma/pl080: Don't use hw_error() for unimplemented features * hw/intc/exynos4210_combiner: Avoid hw_error for guest errors * hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet * hw/core/qdev-clock: Fix potential null pointer dereference ---------------------------------------------------------------- Alex Bennée (4): target/arm: fix WFET typo in syndrome target/arm: teach arm_cpu_has_work about halting reasons target/arm: redefine event stream fields target/arm: ensure aarch64 DISAS_WFE will exit Gabriel Brookman (15): target/arm: implement MTE_PERM target/arm: add TCSO bitmasks to SCTLR target/arm: mte_check unemitted on STORE_ONLY load linux-user: add MTE_STORE_ONLY to prctl target/arm: emit tag check when MTX without TBI target/arm: add MTX to MTEDESC and DisasContext target/arm: add canonical tag check helper target/arm: add canonical MTE check logic target/arm: load on canonical tag loads ext bits target/arm: fault on tag store to canonical tag target/arm: skip tag bit bounds check if MTX is on target/arm: tag is not a part of PAuth with MTX docs: add MTE4 features to docs tests/tcg: add test for MTE FAR tests/tcg: add test for MTE_STORE_ONLY Munkhbaatar Enkhbaatar (2): hw/usb/hcd-ohci: Assert isochronous TDs are never deferred hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet Peter Maydell (2): hw/intc/exynos4210_combiner: Avoid hw_error for guest errors hw/dma/pl080: Don't use hw_error() for unimplemented features Richard Henderson (47): fpu: Handle all rounding modes in partsN_uncanon_normal fpu: Handle all rounding modes in partsN_round_to_int_normal target/arm: Use FloatParts64 in bfdotadd_ebf target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf target/arm: Use FloatParts64 in f16_dotadd target/arm: Generalize TRANS_FEAT_STREAMING_SME2 target/arm: Introduce arm_init_fp_status target/arm: Set e4m3_nan_is_snan target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD target/arm: Implement BF1CVT, BF1CVTLT, BF2CVT, BF2CVTLT for SVE target/arm: Rename SME BFCVT patterns to BFCVT_hs target/arm: Implement BF1CVT, BF1CVTL, BF2CVT, BF2CVTL for SME target/arm: Implement F1CVTL, F1CVTL2, F2CVTL, F2CVTL2 for AdvSIMD target/arm: Implement F1CVT, F1CVTLT, F2CVT, F2CVTLT for SVE target/arm: Implement F1CVT, F1CVTL, F2CVT, F2CVTL for SME target/arm: Implement BFCVTN for SVE target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD target/arm: Implement FCVTN, FCVTN2 (32- to 8-bit fp) for AdvSIMD target/arm: Implement FCVTN (16- to 8-bit fp) for SVE target/arm: Implement FCVTNB, FCVTNT for SVE target/arm: Implement FCVT (FP16 to FP8) for SME target/arm: Implement FCVT, FCVTN (FP32 to FP8) for SME target/arm: Implement LUTI2, LUTI4 for AdvSIMD target/arm: Implement LUTI2, LUTI4 for SVE target/arm: Enable FEAT_LUT for -cpu max target/arm: Enable FEAT_FP8 for -cpu max target/arm: Update ID_AA64SMFR0_EL1 fields to ARM M.b target/arm: Implement MOVT (vector to table) target/arm: Implement LUTI4 (four registers, 8-bit) target/arm: Enable FEAT_SME_LUTv2 for -cpu max target/arm: Implement FMLALB, FMLALT for AdvSIMD target/arm: Implement FMLALB, FMLALT (FP8 to FP16) for SVE target/arm: Implement FMLALL{BB, BT, TB, TT} for AdvSIMD target/arm: Implement FMLALL{BB,BT,TB,TT} for SVE target/arm: Enable FEAT_FP8FMA, FEAT_SSVE_FP8FMA for -cpu max target/arm: Implement FDOT (FP8 to FP32) for AdvSIMD target/arm: Implement FDOT (FP8 to FP32) for SVE target/arm: Enable FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4 for -cpu max target/arm: Implement FDOT (FP8 to FP16) for AdvSIMD target/arm: Implement FDOT (FP8 to FP16) for SVE target/arm: Enable FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2 for -cpu max target/arm: Implement FMMLA (FP8 to FP32) for AdvSIMD target/arm: Implement FMMLA (FP8 to FP32) for SVE target/arm: Enable FEAT_F8F32MM for -cpu max target/arm: Implement FMMLA (FP8 to FP16) for AdvSIMD target/arm: Implement FMMLA (FP8 to FP16) for SVE target/arm: Enable FEAT_F8F16MM for -cpu max hemanshu.khilari.foss (1): hw/core/qdev-clock: Fix potential null pointer dereference docs/system/arm/emulation.rst | 16 + fpu/softfloat-parts.c.inc | 5 + hw/core/qdev-clock.c | 9 +- hw/dma/pl080.c | 6 +- hw/intc/exynos4210_combiner.c | 29 +- hw/usb/hcd-ohci.c | 10 +- linux-user/aarch64/elfload.c | 13 + linux-user/aarch64/mte_user_helper.c | 11 +- linux-user/aarch64/mte_user_helper.h | 14 +- linux-user/aarch64/target_prctl.h | 6 +- target/arm/arm-powerctl.c | 6 +- target/arm/cpu-features.h | 98 ++++ target/arm/cpu.c | 60 ++- target/arm/cpu.h | 21 + target/arm/gdbstub64.c | 2 +- target/arm/helper-fp8.h | 14 + target/arm/helper.c | 44 +- target/arm/internals.h | 62 ++- target/arm/kvm.c | 5 +- target/arm/machine.c | 2 +- target/arm/ptw.c | 60 ++- target/arm/syndrome.h | 2 +- target/arm/tcg/a64.decode | 39 ++ target/arm/tcg/cpu64.c | 21 + target/arm/tcg/fp8_helper.c | 859 +++++++++++++++++++++++++++++++++++ target/arm/tcg/helper-a64-defs.h | 16 +- target/arm/tcg/helper-a64.c | 7 +- target/arm/tcg/helper-defs.h | 6 + target/arm/tcg/helper-fp8-defs.h | 40 ++ target/arm/tcg/helper-sme-defs.h | 2 +- target/arm/tcg/hflags.c | 25 +- target/arm/tcg/meson.build | 1 + target/arm/tcg/mte_helper.c | 146 +++++- target/arm/tcg/op_helper.c | 3 + target/arm/tcg/pauth_helper.c | 18 +- target/arm/tcg/sme.decode | 25 +- target/arm/tcg/sme_helper.c | 109 ++--- target/arm/tcg/sve.decode | 48 +- target/arm/tcg/sve_helper.c | 6 +- target/arm/tcg/translate-a64.c | 229 ++++++++-- target/arm/tcg/translate-a64.h | 1 + target/arm/tcg/translate-sme.c | 71 ++- target/arm/tcg/translate-sve.c | 245 +++++++++- target/arm/tcg/translate.h | 10 +- target/arm/tcg/vec_helper.c | 194 +++++--- target/arm/tcg/vec_internal.h | 12 +- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/aarch64/mte-10.c | 49 ++ tests/tcg/aarch64/mte-9.c | 48 ++ tests/tcg/aarch64/mte.h | 7 +- 50 files changed, 2428 insertions(+), 306 deletions(-) create mode 100644 target/arm/helper-fp8.h create mode 100644 target/arm/tcg/fp8_helper.c create mode 100644 target/arm/tcg/helper-fp8-defs.h create mode 100644 tests/tcg/aarch64/mte-10.c create mode 100644 tests/tcg/aarch64/mte-9.c
From: "hemanshu.khilari.foss" <hemanshu.khilari.foss@gmail.com> qdev_get_clocklist() function returns a pointer to the NamedClockList struct. This function is called in qdev_alias_clock() and the returned pointer is immediately dereferenced without a null check. Passing a clock name that doesn't exist to qdev_get_clocklist() is a programming error, and so this change is not fixing a bug, only making the reporting of that programming error a bit more helpful and bringing it in to line with qdev_get_clock_in() and qdev_get_clock_out(). Cc: luc@lmichel.fr Cc: peter.maydell@linaro.org Cc: hemanshu_dev@proton.me Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2342 Signed-off-by: hemanshu.khilari.foss <hemanshu.khilari.foss@gmail.com> Message-id: 20260531153354.88909-2-hemanshu.khilari.foss@gmail.com Reviewed-by: Luc Michel <luc@lmichel.fr> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/core/qdev-clock.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index XXXXXXX..XXXXXXX 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -XXX,XX +XXX,XX @@ Clock *qdev_alias_clock(DeviceState *dev, const char *name, DeviceState *alias_dev, const char *alias_name) { NamedClockList *ncl = qdev_get_clocklist(dev, name); - Clock *clk = ncl->clock; + Clock *clk; + + if (!ncl) { + error_report("Can not find clock '%s' for device type '%s'", + name, object_get_typename(OBJECT(dev))); + abort(); + } + clk = ncl->clock; ncl = qdev_init_clocklist(alias_dev, alias_name, true, ncl->output, clk); -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Introduces a new stage 2 memory attribute, NoTagAccess, that raises a stage 2 data abort on a tag check, tag read, or tag write. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-1-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/ptw.c | 25 +++++++++++++++++++++--- target/arm/tcg/mte_helper.c | 38 +++++++++++++++++++++++++++++++++++-- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_mte3(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTE) >= 3; } +static inline bool isar_feature_aa64_mteperm(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTEPERM) >= 1; +} + static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0; diff --git a/target/arm/ptw.c b/target/arm/ptw.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -XXX,XX +XXX,XX @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, ARMCacheAttrs s1, ARMCacheAttrs s2) { ARMCacheAttrs ret; - bool tagged = false; + bool tagged = false, notagaccess = false; assert(!s1.is_s2_format); ret.is_s2_format = false; @@ -XXX,XX +XXX,XX @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, s1.attrs = 0xff; } + if (hcr & HCR_FWB) { + if (s2.attrs >= 0xe) { + notagaccess = true; + s2.attrs = 0x7; + } + } else { + if (s2.attrs == 0x4) { + notagaccess = true; + s2.attrs = 0xf; + } + } + /* Combine shareability attributes (table D4-43) */ if (s1.shareability == 2 || s2.shareability == 2) { /* if either are outer-shareable, the result is outer-shareable */ @@ -XXX,XX +XXX,XX @@ static ARMCacheAttrs combine_cacheattrs(uint64_t hcr, ret.shareability = 2; } - /* TODO: CombineS1S2Desc does not consider transient, only WB, RWA. */ + /* + * The attr encoding 0xe0 corresponds to Tagged NoTagAccess and is only + * valid with FEAT_MTE_PERM (otherwise RESERVED, constrained + * unpredictable)). The presence of this feature is checked in + * allocation_tag_mem_probe, where Tagged NoTagAccess has its effect. See + * J1.3.5.2 EncodePARAttrs. + * TODO: CombineS1S2Desc does not consider transient, only WB, RWA. + */ if (tagged && ret.attrs == 0xff) { - ret.attrs = 0xf0; + ret.attrs = notagaccess ? 0xe0 : 0xf0; } return ret; diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -XXX,XX +XXX,XX @@ static int choose_nonexcluded_tag(int tag, int offset, uint16_t exclude) return tag; } +#ifndef CONFIG_USER_ONLY +/* + * Constructs S2 Permission Fault as described in ARM ARM "Stage 2 Memory + * Tagging Attributes". + */ +static void mte_perm_check_fail(CPUARMState *env, uint64_t dirty_ptr, + uintptr_t ra, bool is_write) +{ + uint64_t syn; + + env->exception.vaddress = dirty_ptr; + + syn = syn_data_abort_no_iss(0, 0, 0, 0, 0, is_write, 0); + + syn |= BIT_ULL(41); /* TagAccess is bit 41 */ + + raise_exception_ra(env, EXCP_DATA_ABORT, syn, 2, ra); + g_assert_not_reached(); +} +#endif + uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, uint64_t ptr, MMUAccessType ptr_access, int ptr_size, MMUAccessType tag_access, @@ -XXX,XX +XXX,XX @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, } assert(!(flags & TLB_INVALID_MASK)); - /* If the virtual page MemAttr != Tagged, access unchecked. */ - if (full->extra.arm.pte_attrs != 0xf0) { + switch (full->extra.arm.pte_attrs) { + case 0xf0: /* Tagged */ + break; + + case 0xe0: /* NoTagAccess */ + if (cpu_isar_feature(aa64_mteperm, env_archcpu(env))) { + if (probe) { + return NULL; + } + assert(ra); + mte_perm_check_fail(env, ptr, ra, tag_access == MMU_DATA_STORE); + } + /* fall through */ + + default: /* Not Tagged */ return NULL; } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> These are the bitmasks used to control the FEAT_MTE_STORE_ONLY feature. They are now named and setting these fields of SCTLR is ignored if MTE or MTE4 is disabled, as per convention. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-2-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/cpu.h | 2 ++ target/arm/helper.c | 20 ++++++++++++++------ 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_mteperm(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTEPERM) >= 1; } +static inline bool isar_feature_aa64_mte_store_only(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTESTOREONLY) == 1; +} + static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0; diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ void pmu_init(ARMCPU *cpu); #define SCTLR_EnAS0 (1ULL << 55) /* FEAT_LS64_ACCDATA */ #define SCTLR_EnALS (1ULL << 56) /* FEAT_LS64 */ #define SCTLR_EPAN (1ULL << 57) /* FEAT_PAN3 */ +#define SCTLR_TCSO0 (1ULL << 58) /* FEAT_MTE_STORE_ONLY */ +#define SCTLR_TCSO (1ULL << 59) /* FEAT_MTE_STORE_ONLY */ #define SCTLR_EnTP2 (1ULL << 60) /* FEAT_SME */ #define SCTLR_NMI (1ULL << 61) /* FEAT_NMI */ #define SCTLR_SPINTMASK (1ULL << 62) /* FEAT_NMI */ diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, /* ??? Lots of these bits are not implemented. */ - if (ri->state == ARM_CP_STATE_AA64 && !cpu_isar_feature(aa64_mte, cpu)) { - if (ri->opc1 == 6) { /* SCTLR_EL3 */ - value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA); - } else { - value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF | - SCTLR_ATA0 | SCTLR_ATA); + if (ri->state == ARM_CP_STATE_AA64) { + if (!cpu_isar_feature(aa64_mte, cpu)) { + if (ri->opc1 == 6) { /* SCTLR_EL3 */ + value &= ~(SCTLR_ITFSB | SCTLR_TCF | SCTLR_ATA | SCTLR_TCSO); + } else { + value &= ~(SCTLR_ITFSB | SCTLR_TCF0 | SCTLR_TCF | + SCTLR_ATA0 | SCTLR_ATA | SCTLR_TCSO | SCTLR_TCSO0); + } + } else if (!cpu_isar_feature(aa64_mte_store_only, cpu)) { /* not mte4 */ + if (ri->opc1 == 6) { /* SCTLR_EL3 */ + value &= ~SCTLR_TCSO; + } else { + value &= ~(SCTLR_TCSO | SCTLR_TCSO0); + } } } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> This feature disables generation of the mte check helper on loads when STORE_ONLY tag checking mode is enabled. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-3-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.h | 2 ++ target/arm/tcg/hflags.c | 12 ++++++++++++ target/arm/tcg/translate-a64.c | 8 ++++++-- target/arm/tcg/translate.h | 2 ++ 4 files changed, 22 insertions(+), 2 deletions(-) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, GCS_EN, 41, 1) FIELD(TBFLAG_A64, GCS_RVCEN, 42, 1) FIELD(TBFLAG_A64, GCSSTR_EL, 43, 2) FIELD(TBFLAG_A64, FPMR_EL, 45, 2) +FIELD(TBFLAG_A64, MTE_STORE_ONLY, 47, 1) +FIELD(TBFLAG_A64, MTE0_STORE_ONLY, 48, 1) /* * Helpers for using the above. Note that only the A64 accessors use diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, */ DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1); } + /* + * Repeat for MTE_STORE_ONLY + */ + if ((el == 0 ? SCTLR_TCSO0 : SCTLR_TCSO) & sctlr) { + DP_TBFLAG_A64(flags, MTE_STORE_ONLY, 1); + if (!EX_TBFLAG_A64(flags, UNPRIV)) { + DP_TBFLAG_A64(flags, MTE0_STORE_ONLY, 1); + } + } } } /* And again for unprivileged accesses, if required. */ @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, && (sctlr & SCTLR_TCF0) && allocation_tag_access_enabled(env, 0, sctlr)) { DP_TBFLAG_A64(flags, MTE0_ACTIVE, 1); + if (SCTLR_TCSO0 & sctlr) { + DP_TBFLAG_A64(flags, MTE0_STORE_ONLY, 1); + } } /* * For unpriv tag-setting accesses we also need ATA0. Again, in diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, MemOp memop, bool is_unpriv, int core_idx) { - if (tag_checked && s->mte_active[is_unpriv]) { + if (tag_checked && s->mte_active[is_unpriv] && + (is_write || !s->mte_store_only[is_unpriv])) { TCGv_i64 ret; int desc = 0; @@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_check1(DisasContext *s, TCGv_i64 addr, bool is_write, TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, bool tag_checked, int total_size, MemOp single_mop) { - if (tag_checked && s->mte_active[0]) { + if (tag_checked && s->mte_active[0] && + (is_write || !s->mte_store_only[0])) { TCGv_i64 ret; int desc = 0; @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->ata[1] = EX_TBFLAG_A64(tb_flags, ATA0); dc->mte_active[0] = EX_TBFLAG_A64(tb_flags, MTE_ACTIVE); dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE); + dc->mte_store_only[0] = EX_TBFLAG_A64(tb_flags, MTE_STORE_ONLY); + dc->mte_store_only[1] = EX_TBFLAG_A64(tb_flags, MTE0_STORE_ONLY); dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM); dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA); dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { bool ata[2]; /* True if v8.5-MTE tag checks affect the PE; index with is_unpriv. */ bool mte_active[2]; + /* True if v8.5-MTE tag checks disabled for reads; index with is_unpriv. */ + bool mte_store_only[2]; /* True with v8.5-BTI and SCTLR_ELx.BT* set. */ bool bt; /* True if any CP15 access is trapped by HSTR_EL2 */ -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Linux-user processes can now control whether MTE_STORE_ONLY is enabled using the prctl syscall. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-4-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- linux-user/aarch64/mte_user_helper.c | 11 ++++++++++- linux-user/aarch64/mte_user_helper.h | 14 +++++++++----- linux-user/aarch64/target_prctl.h | 6 +++++- target/arm/gdbstub64.c | 2 +- tests/tcg/aarch64/mte.h | 3 +++ 5 files changed, 28 insertions(+), 8 deletions(-) diff --git a/linux-user/aarch64/mte_user_helper.c b/linux-user/aarch64/mte_user_helper.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/mte_user_helper.c +++ b/linux-user/aarch64/mte_user_helper.c @@ -XXX,XX +XXX,XX @@ #include "qemu.h" #include "mte_user_helper.h" -void arm_set_mte_tcf0(CPUArchState *env, abi_long value) +void arm_set_tagged_addr_ctrl(CPUArchState *env, abi_long value) { /* * Write PR_MTE_TCF to SCTLR_EL1[TCF0]. @@ -XXX,XX +XXX,XX @@ void arm_set_mte_tcf0(CPUArchState *env, abi_long value) tcf = 2; } env->cp15.sctlr_el[1] = deposit64(env->cp15.sctlr_el[1], 38, 2, tcf); + + /* + * If MTE_STORE_ONLY is enabled, set the corresponding sctlr_el1 bit + */ + if (value & PR_MTE_STORE_ONLY) { + env->cp15.sctlr_el[1] |= SCTLR_TCSO0; + } else { + env->cp15.sctlr_el[1] &= ~SCTLR_TCSO0; + } } diff --git a/linux-user/aarch64/mte_user_helper.h b/linux-user/aarch64/mte_user_helper.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/mte_user_helper.h +++ b/linux-user/aarch64/mte_user_helper.h @@ -XXX,XX +XXX,XX @@ # define PR_MTE_TAG_SHIFT 3 # define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) #endif +#ifndef PR_MTE_STORE_ONLY +# define PR_MTE_STORE_ONLY (1UL << 19) +#endif /** - * arm_set_mte_tcf0 - Set TCF0 field in SCTLR_EL1 register + * arm_set_tagged_addr_ctrl - Set TCF0 and TCSO0 fields in SCTLR_EL1 register * @env: The CPU environment - * @value: The value to be set for the Tag Check Fault in EL0 field. + * @value: The value to be set for the Tag Check Fault and Tag Check Store Only + * in EL0 field. * - * Only SYNC and ASYNC modes can be selected. If ASYMM mode is given, the SYNC - * mode is selected instead. So, there is no way to set the ASYMM mode. + * Only SYNC and ASYNC modes can be selected for TCF0. If ASYMM mode is given, + * the SYNC mode is selected instead. So, there is no way to set the ASYMM mode. */ -void arm_set_mte_tcf0(CPUArchState *env, abi_long value); +void arm_set_tagged_addr_ctrl(CPUArchState *env, abi_long value); #endif /* AARCH64_MTE_USER_HELPER_H */ diff --git a/linux-user/aarch64/target_prctl.h b/linux-user/aarch64/target_prctl.h index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/target_prctl.h +++ b/linux-user/aarch64/target_prctl.h @@ -XXX,XX +XXX,XX @@ static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2) if (cpu_isar_feature(aa64_mte, cpu)) { valid_mask |= PR_MTE_TCF_MASK; valid_mask |= PR_MTE_TAG_MASK; + if (cpu_isar_feature(aa64_mte_store_only, cpu)) { + valid_mask |= PR_MTE_STORE_ONLY; + } } if (arg2 & ~valid_mask) { @@ -XXX,XX +XXX,XX @@ static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2) env->tagged_addr_enable = arg2 & PR_TAGGED_ADDR_ENABLE; if (cpu_isar_feature(aa64_mte, cpu)) { - arm_set_mte_tcf0(env, arg2); + arm_set_tagged_addr_ctrl(env, arg2); /* * Write PR_MTE_TAG to GCR_EL1[Exclude]. @@ -XXX,XX +XXX,XX @@ static abi_long do_prctl_set_tagged_addr_ctrl(CPUArchState *env, abi_long arg2) */ env->cp15.gcr_el1 = deposit64(env->cp15.gcr_el1, 0, 16, ~arg2 >> PR_MTE_TAG_SHIFT); + arm_rebuild_hflags(env); } return 0; diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -XXX,XX +XXX,XX @@ int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg) * expose options regarding the type of MTE fault that can be controlled at * runtime. */ - arm_set_mte_tcf0(env, tcf); + arm_set_tagged_addr_ctrl(env, tcf); return 1; #else diff --git a/tests/tcg/aarch64/mte.h b/tests/tcg/aarch64/mte.h index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/aarch64/mte.h +++ b/tests/tcg/aarch64/mte.h @@ -XXX,XX +XXX,XX @@ #ifndef PR_TAGGED_ADDR_ENABLE # define PR_TAGGED_ADDR_ENABLE (1UL << 0) #endif +#ifndef PR_MTE_STORE_ONLY +# define PR_MTE_STORE_ONLY (1UL << 19) +#endif #ifndef PR_MTE_TCF_SHIFT # define PR_MTE_TCF_SHIFT 1 # define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT) -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Previously, the TBI bit was used to mediate whether tag checks happened. With MTE4, if the MTX bits are enabled, then tag checking happens even if TBI is disabled. See AccessIsTagChecked. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-5-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/helper.c | 10 ++++++++++ target/arm/internals.h | 13 ++++++++----- target/arm/tcg/helper-a64.c | 7 ++++--- target/arm/tcg/hflags.c | 11 +++++++---- target/arm/tcg/mte_helper.c | 9 ++++++--- target/arm/tcg/sme_helper.c | 4 ++-- target/arm/tcg/sve_helper.c | 6 +++--- 8 files changed, 45 insertions(+), 20 deletions(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_mte_store_only(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64PFR2, MTESTOREONLY) == 1; } +static inline bool isar_feature_aa64_mte_mtx(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64PFR1, MTEX) != 0; +} + static inline bool isar_feature_aa64_sme(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64PFR1, SME) != 0; diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ uint64_t arm_sctlr(CPUARMState *env, int el) return env->cp15.sctlr_el[el]; } +int aa64_va_parameter_mtx(uint64_t tcr, ARMMMUIdx mmu_idx) +{ + if (regime_has_2_ranges(mmu_idx)) { + return extract64(tcr, 60, 2); + } else { + /* Replicate the single MTX bit so we always have 2 bits. */ + return extract64(tcr, 33, 1) * 3; + } +} + int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx) { if (regime_has_2_ranges(mmu_idx)) { diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ARMMMUIdx mmu_idx, bool data, bool el1_is_aa32); +int aa64_va_parameter_mtx(uint64_t tcr, ARMMMUIdx mmu_idx); int aa64_va_parameter_tbi(uint64_t tcr, ARMMMUIdx mmu_idx); int aa64_va_parameter_tbid(uint64_t tcr, ARMMMUIdx mmu_idx); int aa64_va_parameter_tcma(uint64_t tcr, ARMMMUIdx mmu_idx); @@ -XXX,XX +XXX,XX @@ FIELD(MTEDESC, TBI, 4, 2) FIELD(MTEDESC, TCMA, 6, 2) FIELD(MTEDESC, WRITE, 8, 1) FIELD(MTEDESC, ALIGN, 9, 3) -FIELD(MTEDESC, SIZEM1, 12, 32 - 12) /* size - 1 */ +FIELD(MTEDESC, MTX, 12, 2) +FIELD(MTEDESC, SIZEM1, 14, 32 - 14) /* size - 1 */ bool mte_probe(CPUARMState *env, uint32_t desc, uint64_t ptr); uint64_t mte_check(CPUARMState *env, uint32_t desc, uint64_t ptr, uintptr_t ra); @@ -XXX,XX +XXX,XX @@ static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) return deposit64(ptr, 56, 4, rtag); } -/* Return true if tbi bits mean that the access is checked. */ -static inline bool tbi_check(uint32_t desc, int bit55) +/* Return true if tbi or mtx bits mean that the access is tag checked. */ +static inline bool tbi_or_mtx_check(uint32_t desc, int bit55) { - return (desc >> (R_MTEDESC_TBI_SHIFT + bit55)) & 1; + uint32_t mask = (1u << R_MTEDESC_TBI_SHIFT) | (1u << R_MTEDESC_MTX_SHIFT); + return desc & (mask << bit55); } /* Return true if tcma bits mean that the access is unchecked. */ @@ -XXX,XX +XXX,XX @@ static inline uint64_t useronly_maybe_clean_ptr(uint32_t desc, uint64_t ptr) { #ifdef CONFIG_USER_ONLY int64_t clean_ptr = sextract64(ptr, 0, 56); - if (tbi_check(desc, clean_ptr < 0)) { + if (tbi_or_mtx_check(desc, clean_ptr < 0)) { ptr = clean_ptr; } #endif diff --git a/target/arm/tcg/helper-a64.c b/target/arm/tcg/helper-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64.c +++ b/target/arm/tcg/helper-a64.c @@ -XXX,XX +XXX,XX @@ static int mops_sizereg(uint32_t syndrome) } /* - * Return true if TCMA and TBI bits mean we need to do MTE checks. + * Return true if the TCMA, TBI, and MTX bits mean we need to do MTE checks. * We only need to do this once per MOPS insn, not for every page. */ static bool mte_checks_needed(uint64_t ptr, uint32_t desc) @@ -XXX,XX +XXX,XX @@ static bool mte_checks_needed(uint64_t ptr, uint32_t desc) int bit55 = extract64(ptr, 55, 1); /* - * Note that tbi_check() returns true for "access checked" but + * Note that tbi_or_mtx_check() return true for "access checked", but * tcma_check() returns true for "access unchecked". */ - if (!tbi_check(desc, bit55)) { + if (!tbi_or_mtx_check(desc, bit55)) { return false; } + return !tcma_check(desc, bit55, allocation_tag_from_addr(ptr)); } diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, uint64_t tcr = regime_tcr(env, mmu_idx); uint64_t hcr = arm_hcr_el2_eff(env); uint64_t sctlr; - int tbii, tbid; + int tbii, tbid, mtx; DP_TBFLAG_ANY(flags, AARCH64_STATE, 1); /* Get control bits for tagged addresses. */ tbid = aa64_va_parameter_tbi(tcr, mmu_idx); tbii = tbid & ~aa64_va_parameter_tbid(tcr, mmu_idx); + mtx = cpu_isar_feature(aa64_mte_mtx, env_archcpu(env)) ? + aa64_va_parameter_mtx(tcr, mmu_idx) : + 0; DP_TBFLAG_A64(flags, TBII, tbii); DP_TBFLAG_A64(flags, TBID, tbid); @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, /* * Set MTE_ACTIVE if any access may be Checked, and leave clear * if all accesses must be Unchecked: - * 1) If no TBI, then there are no tags in the address to check, + * 1) If TBI and MTX are both unset, accesses are Unchecked. * 2) If Tag Check Override, then all accesses are Unchecked, * 3) If Tag Check Fail == 0, then Checked access have no effect, * 4) If no Allocation Tag Access, then all accesses are Unchecked. */ if (allocation_tag_access_enabled(env, el, sctlr)) { DP_TBFLAG_A64(flags, ATA, 1); - if (tbid + if ((tbid || mtx) && !(env->pstate & PSTATE_TCO) && (sctlr & (el == 0 ? SCTLR_TCF0 : SCTLR_TCF))) { DP_TBFLAG_A64(flags, MTE_ACTIVE, 1); @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, } /* And again for unprivileged accesses, if required. */ if (EX_TBFLAG_A64(flags, UNPRIV) - && tbid + && (tbid || mtx) && !(env->pstate & PSTATE_TCO) && (sctlr & SCTLR_TCF0) && allocation_tag_access_enabled(env, 0, sctlr)) { diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -XXX,XX +XXX,XX @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, bit55 = extract64(ptr, 55, 1); *fault = ptr; - /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ - if (unlikely(!tbi_check(desc, bit55))) { + /* + * If TBI and MTX are disabled, the access is unchecked, and ptr is not + * dirty. + */ + if (unlikely(!tbi_or_mtx_check(desc, bit55))) { return -1; } @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr) bit55 = extract64(ptr, 55, 1); /* If TBI is disabled, the access is unchecked, and ptr is not dirty. */ - if (unlikely(!tbi_check(desc, bit55))) { + if (unlikely(!tbi_or_mtx_check(desc, bit55))) { return ptr; } diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ void sme_ld1_mte(CPUARMState *env, void *za, uint64_t *vg, int bit55 = extract64(addr, 55, 1); /* Perform gross MTE suppression early. */ - if (!tbi_check(mtedesc, bit55) || + if (!tbi_or_mtx_check(mtedesc, bit55) || tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { mtedesc = 0; } @@ -XXX,XX +XXX,XX @@ void sme_st1_mte(CPUARMState *env, void *za, uint64_t *vg, target_ulong addr, int bit55 = extract64(addr, 55, 1); /* Perform gross MTE suppression early. */ - if (!tbi_check(mtedesc, bit55) || + if (!tbi_or_mtx_check(mtedesc, bit55) || tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { mtedesc = 0; } diff --git a/target/arm/tcg/sve_helper.c b/target/arm/tcg/sve_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve_helper.c +++ b/target/arm/tcg/sve_helper.c @@ -XXX,XX +XXX,XX @@ void sve_ldN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, int bit55 = extract64(addr, 55, 1); /* Perform gross MTE suppression early. */ - if (!tbi_check(mtedesc, bit55) || + if (!tbi_or_mtx_check(mtedesc, bit55) || tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { mtedesc = 0; } @@ -XXX,XX +XXX,XX @@ void sve_ldnfff1_r_mte(CPUARMState *env, void *vg, target_ulong addr, int bit55 = extract64(addr, 55, 1); /* Perform gross MTE suppression early. */ - if (!tbi_check(mtedesc, bit55) || + if (!tbi_or_mtx_check(mtedesc, bit55) || tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { mtedesc = 0; } @@ -XXX,XX +XXX,XX @@ void sve_stN_r_mte(CPUARMState *env, uint64_t *vg, target_ulong addr, int bit55 = extract64(addr, 55, 1); /* Perform gross MTE suppression early. */ - if (!tbi_check(mtedesc, bit55) || + if (!tbi_or_mtx_check(mtedesc, bit55) || tcma_check(mtedesc, bit55, allocation_tag_from_addr(addr))) { mtedesc = 0; } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Add fields for MTX to DisasContext and MTEDESC. With MTE4, the fields will be needed in future patches that alter tag check, tag load and tag store behavior. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-6-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.h | 1 + target/arm/tcg/hflags.c | 2 ++ target/arm/tcg/translate-a64.c | 7 +++++++ target/arm/tcg/translate.h | 1 + 4 files changed, 11 insertions(+) diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ FIELD(TBFLAG_A64, GCSSTR_EL, 43, 2) FIELD(TBFLAG_A64, FPMR_EL, 45, 2) FIELD(TBFLAG_A64, MTE_STORE_ONLY, 47, 1) FIELD(TBFLAG_A64, MTE0_STORE_ONLY, 48, 1) +FIELD(TBFLAG_A64, MTX, 49, 2) /* * Helpers for using the above. Note that only the A64 accessors use diff --git a/target/arm/tcg/hflags.c b/target/arm/tcg/hflags.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/hflags.c +++ b/target/arm/tcg/hflags.c @@ -XXX,XX +XXX,XX @@ static CPUARMTBFlags rebuild_hflags_a64(CPUARMState *env, int el, int fp_el, } /* Cache TCMA as well as TBI. */ DP_TBFLAG_A64(flags, TCMA, aa64_va_parameter_tcma(tcr, mmu_idx)); + /* Cache MTX. */ + DP_TBFLAG_A64(flags, MTX, mtx); } if (cpu_isar_feature(aa64_gcs, env_archcpu(env))) { diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static TCGv_i64 gen_mte_check1_mmuidx(DisasContext *s, TCGv_i64 addr, desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); desc = FIELD_DP32(desc, MTEDESC, ALIGN, memop_alignment_bits(memop)); + desc = FIELD_DP32(desc, MTEDESC, MTX, s->mtx); desc = FIELD_DP32(desc, MTEDESC, SIZEM1, memop_size(memop) - 1); ret = tcg_temp_new_i64(); @@ -XXX,XX +XXX,XX @@ TCGv_i64 gen_mte_checkN(DisasContext *s, TCGv_i64 addr, bool is_write, desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, is_write); desc = FIELD_DP32(desc, MTEDESC, ALIGN, memop_alignment_bits(single_mop)); + desc = FIELD_DP32(desc, MTEDESC, MTX, s->mtx); desc = FIELD_DP32(desc, MTEDESC, SIZEM1, total_size - 1); ret = tcg_temp_new_i64(); @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, desc = FIELD_DP32(desc, MTEDESC, MIDX, get_mem_index(s)); desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); + desc = FIELD_DP32(desc, MTEDESC, MTX, s->mtx); tcg_rt = tcg_temp_new_i64(); gen_helper_mte_check_zva(tcg_rt, tcg_env, @@ -XXX,XX +XXX,XX @@ static bool do_SET(DisasContext *s, arg_set *a, bool is_epilogue, desc = FIELD_DP32(desc, MTEDESC, TBI, s->tbid); desc = FIELD_DP32(desc, MTEDESC, TCMA, s->tcma); desc = FIELD_DP32(desc, MTEDESC, WRITE, true); + desc = FIELD_DP32(desc, MTEDESC, MTX, s->mtx); /* SIZEM1 and ALIGN we leave 0 (byte write) */ } /* The helper function always needs the memidx even with MTE disabled */ @@ -XXX,XX +XXX,XX @@ static bool do_CPY(DisasContext *s, arg_cpy *a, bool is_epilogue, CpyFn fn) if (s->mte_active[runpriv]) { rdesc = FIELD_DP32(rdesc, MTEDESC, TBI, s->tbid); rdesc = FIELD_DP32(rdesc, MTEDESC, TCMA, s->tcma); + rdesc = FIELD_DP32(rdesc, MTEDESC, MTX, s->mtx); } if (s->mte_active[wunpriv]) { wdesc = FIELD_DP32(wdesc, MTEDESC, TBI, s->tbid); wdesc = FIELD_DP32(wdesc, MTEDESC, TCMA, s->tcma); wdesc = FIELD_DP32(wdesc, MTEDESC, WRITE, true); + wdesc = FIELD_DP32(wdesc, MTEDESC, MTX, s->mtx); } /* The helper function needs these parts of the descriptor regardless */ rdesc = FIELD_DP32(rdesc, MTEDESC, MIDX, rmemidx); @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->mte_active[1] = EX_TBFLAG_A64(tb_flags, MTE0_ACTIVE); dc->mte_store_only[0] = EX_TBFLAG_A64(tb_flags, MTE_STORE_ONLY); dc->mte_store_only[1] = EX_TBFLAG_A64(tb_flags, MTE0_STORE_ONLY); + dc->mtx = EX_TBFLAG_A64(tb_flags, MTX); dc->pstate_sm = EX_TBFLAG_A64(tb_flags, PSTATE_SM); dc->pstate_za = EX_TBFLAG_A64(tb_flags, PSTATE_ZA); dc->sme_trap_nonstreaming = EX_TBFLAG_A64(tb_flags, SME_TRAP_NONSTREAMING); diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { uint8_t tbii; /* TBI1|TBI0 for insns */ uint8_t tbid; /* TBI1|TBI0 for data */ uint8_t tcma; /* TCMA1|TCMA0 for MTE */ + uint8_t mtx; /* MTX1|MTX0 for MTE */ bool ns; /* Use non-secure CPREG bank on access */ int fp_excp_el; /* FP exception EL or 0 if enabled */ int sve_excp_el; /* SVE exception EL or 0 if enabled */ -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Add a helper that checks whether mtx is active from MTEDESC. Refactored an existing function to use it. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-7-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/internals.h | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ static inline bool tbi_or_mtx_check(uint32_t desc, int bit55) return desc & (mask << bit55); } +/* Return whether or not the second nibble of a VA matches bit 55. */ +static inline bool tag_is_canonical(int ptr_tag, int bit55) +{ + return ((ptr_tag + bit55) & 0xf) == 0; +} + /* Return true if tcma bits mean that the access is unchecked. */ static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag) { @@ -XXX,XX +XXX,XX @@ static inline bool tcma_check(uint32_t desc, int bit55, int ptr_tag) * We had extracted bit55 and ptr_tag for other reasons, so fold * (ptr<59:55> == 00000 || ptr<59:55> == 11111) into a single test. */ - bool match = ((ptr_tag + bit55) & 0xf) == 0; + bool match = tag_is_canonical(ptr_tag, bit55); bool tcma = (desc >> (R_MTEDESC_TCMA_SHIFT + bit55)) & 1; return tcma && match; } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> With MTX active, address tag bits are checked for canonicity if the corresponding memory regions are not allocation tagged. See AArch64_CheckTag. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-8-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/internals.h | 6 ++++++ target/arm/tcg/mte_helper.c | 30 ++++++++++++++++++++++++++---- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ static inline uint64_t address_with_allocation_tag(uint64_t ptr, int rtag) return deposit64(ptr, 56, 4, rtag); } +/* Return true if mtx bits mean that the access is canonically checked. */ +static inline bool mtx_check(uint32_t desc, int bit55) +{ + return (desc >> (R_MTEDESC_MTX_SHIFT + bit55)) & 1; +} + /* Return true if tbi or mtx bits mean that the access is tag checked. */ static inline bool tbi_or_mtx_check(uint32_t desc, int bit55) { diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -XXX,XX +XXX,XX @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, mem1 = allocation_tag_mem(env, mmu_idx, ptr, type, sizem1 + 1, MMU_DATA_LOAD, ra); if (!mem1) { + /* + * If mtx is enabled, then the access is MemTag_CanonicallyTagged, + * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and + * AArch64.S1DisabledOutput. + */ + if (mtx_check(desc, bit55)) { + return tag_is_canonical(ptr_tag, bit55); + } return 1; } /* Perform all of the comparisons. */ @@ -XXX,XX +XXX,XX @@ static int mte_probe_int(CPUARMState *env, uint32_t desc, uint64_t ptr, /* * Perform all of the comparisons. - * Note the possible but unlikely case of the operation spanning - * two pages that do not both have tagging enabled. + * Note the possible but unlikely case of the operation spanning two + * pages that do not both have allocation tagging enabled. This can + * happen with or without mtx (canonical tagging) enabled. */ n = c = (next_page - tag_first) / TAG_GRANULE; if (mem1) { n = checkN(mem1, ptr & TAG_GRANULE, ptr_tag, c); + } else if (mtx_check(desc, bit55) && + !tag_is_canonical(ptr_tag, bit55)) { + return 0; } if (n == c) { - if (!mem2) { + if (mem2) { + n += checkN(mem2, 0, ptr_tag, tag_count - c); + } else if (!mtx_check(desc, bit55) || + tag_is_canonical(ptr_tag, bit55)) { return 1; } - n += checkN(mem2, 0, ptr_tag, tag_count - c); } } @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(mte_check_zva)(CPUARMState *env, uint32_t desc, uint64_t ptr) mem = allocation_tag_mem(env, mmu_idx, align_ptr, MMU_DATA_STORE, dcz_bytes, MMU_DATA_LOAD, ra); if (!mem) { + /* + * If mtx is enabled, then the access is MemTag_CanonicallyTagged, + * otherwise it is Untagged. See AArch64.S1DecodeMemAttrs and + * AArch64.S1DisabledOutput. + */ + if (mtx_check(desc, bit55) && !tag_is_canonical(ptr_tag, bit55)) { + mte_check_fail(env, desc, ptr, ra); + } goto done; } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Loading tags from canonically tagged regions should use the canonical tags (extension bits), not allocation tags. See AArch64_MemTagRead(). Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-9-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-a64-defs.h | 4 ++-- target/arm/tcg/mte_helper.c | 14 ++++++++++++-- target/arm/tcg/translate-a64.c | 4 ++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/target/arm/tcg/helper-a64-defs.h b/target/arm/tcg/helper-a64-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64-defs.h +++ b/target/arm/tcg/helper-a64-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(mte_check, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) -DEF_HELPER_FLAGS_3(ldg, TCG_CALL_NO_WG, i64, env, i64, i64) +DEF_HELPER_FLAGS_4(ldg, TCG_CALL_NO_WG, i64, env, i64, i64, i32) DEF_HELPER_FLAGS_3(stg, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_3(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_2(stg_stub, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(st2g, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_3(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_2(ldgm, TCG_CALL_NO_WG, i64, env, i64) +DEF_HELPER_FLAGS_3(ldgm, TCG_CALL_NO_WG, i64, env, i64, i32) DEF_HELPER_FLAGS_3(stgm, TCG_CALL_NO_WG, void, env, i64, i64) DEF_HELPER_FLAGS_3(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64) diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -XXX,XX +XXX,XX @@ int load_tag1(uint64_t ptr, uint8_t *mem) return extract32(*mem, ofs, 4); } -uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr, uint64_t xt) +uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr, uint64_t xt, uint32_t mtx) { int mmu_idx = arm_env_mmu_index(env); uint8_t *mem; @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(ldg)(CPUARMState *env, uint64_t ptr, uint64_t xt) /* Load if page supports tags. */ if (mem) { rtag = load_tag1(ptr, mem); + } else if (mtx) { + uint64_t bit55 = extract64(ptr, 55, 1); + rtag = 0xF * bit55; } return address_with_allocation_tag(xt, rtag); @@ -XXX,XX +XXX,XX @@ void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) } } -uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) +uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr, uint32_t mtx) { int mmu_idx = arm_env_mmu_index(env); uintptr_t ra = GETPC(); @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr) /* The tag is squashed to zero if the page does not support tags. */ if (!tag_mem) { + /* Load canonical value if mtx is set (untagged memory region) */ + if (mtx) { + bool bit55 = extract64(ptr, 55, 1); + ret = extract64(-bit55, 0, 1 << gm_bs); + shift = extract64(ptr, LOG2_TAG_GRANULE, 4) * 4; + return ret << shift; + } return 0; } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_LDGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_ldgm(tcg_rt, tcg_env, addr); + gen_helper_ldgm(tcg_rt, tcg_env, addr, tcg_constant_i32(s->mtx)); } else { MMUAccessType acc = MMU_DATA_LOAD; int size = 4 << s->gm_blocksize; @@ -XXX,XX +XXX,XX @@ static bool trans_LDG(DisasContext *s, arg_ldst_tag *a) tcg_gen_andi_i64(addr, addr, -TAG_GRANULE); tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_ldg(tcg_rt, tcg_env, addr, tcg_rt); + gen_helper_ldg(tcg_rt, tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } else { /* * Tag access disabled: we must check for aborts on the load -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> According to ARM ARM, section "Memory region tagging types", tag-store instructions targeting canonically tagged regions cause a stage 1 permission fault with MTX enabled. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-10-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-a64-defs.h | 12 +++---- target/arm/tcg/mte_helper.c | 55 +++++++++++++++++++++++++------- target/arm/tcg/translate-a64.c | 26 +++++++++------ 3 files changed, 65 insertions(+), 28 deletions(-) diff --git a/target/arm/tcg/helper-a64-defs.h b/target/arm/tcg/helper-a64-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-a64-defs.h +++ b/target/arm/tcg/helper-a64-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_3(mte_check_zva, TCG_CALL_NO_WG, i64, env, i32, i64) DEF_HELPER_FLAGS_3(irg, TCG_CALL_NO_RWG, i64, env, i64, i64) DEF_HELPER_FLAGS_4(addsubg, TCG_CALL_NO_RWG_SE, i64, env, i64, s32, i32) DEF_HELPER_FLAGS_4(ldg, TCG_CALL_NO_WG, i64, env, i64, i64, i32) -DEF_HELPER_FLAGS_3(stg, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(stg, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(stg_parallel, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_2(stg_stub, TCG_CALL_NO_WG, void, env, i64) -DEF_HELPER_FLAGS_3(st2g, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(st2g, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(st2g_parallel, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_2(st2g_stub, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_3(ldgm, TCG_CALL_NO_WG, i64, env, i64, i32) -DEF_HELPER_FLAGS_3(stgm, TCG_CALL_NO_WG, void, env, i64, i64) -DEF_HELPER_FLAGS_3(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64) +DEF_HELPER_FLAGS_4(stgm, TCG_CALL_NO_WG, void, env, i64, i64, i32) +DEF_HELPER_FLAGS_4(stzgm_tags, TCG_CALL_NO_WG, void, env, i64, i64, i32) DEF_HELPER_FLAGS_4(arm_unaligned_access, TCG_CALL_NO_WG, noreturn, env, i64, i32, i32) diff --git a/target/arm/tcg/mte_helper.c b/target/arm/tcg/mte_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/mte_helper.c +++ b/target/arm/tcg/mte_helper.c @@ -XXX,XX +XXX,XX @@ uint8_t *allocation_tag_mem_probe(CPUARMState *env, int ptr_mmu_idx, #endif } +static G_NORETURN void canonical_tag_write_fail(CPUARMState *env, + uint64_t dirty_ptr, uintptr_t ra) +{ + uint64_t syn; + + env->exception.vaddress = dirty_ptr; + + syn = syn_data_abort_no_iss(arm_current_el(env) != 0, 0, 0, 0, 0, 1, 0); + syn |= BIT_ULL(42); /* TnD is bit 42 */ + + raise_exception_ra(env, EXCP_DATA_ABORT, syn, exception_target_el(env), ra); +} + static uint8_t *allocation_tag_mem(CPUARMState *env, int ptr_mmu_idx, uint64_t ptr, MMUAccessType ptr_access, int ptr_size, MMUAccessType tag_access, @@ -XXX,XX +XXX,XX @@ static void store_tag1_parallel(uint64_t ptr, uint8_t *mem, int tag) typedef void stg_store1(uint64_t, uint8_t *, int); static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt, - uintptr_t ra, stg_store1 store1) + uint32_t mtx, uintptr_t ra, stg_store1 store1) { int mmu_idx = arm_env_mmu_index(env); uint8_t *mem; @@ -XXX,XX +XXX,XX @@ static inline void do_stg(CPUARMState *env, uint64_t ptr, uint64_t xt, /* Store if page supports tags. */ if (mem) { store1(ptr, mem, allocation_tag_from_addr(xt)); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } } -void HELPER(stg)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(stg)(CPUARMState *env, uint64_t ptr, uint64_t xt, uint32_t mtx) { - do_stg(env, ptr, xt, GETPC(), store_tag1); + do_stg(env, ptr, xt, mtx, GETPC(), store_tag1); } -void HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(stg_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt, + uint32_t mtx) { - do_stg(env, ptr, xt, GETPC(), store_tag1_parallel); + do_stg(env, ptr, xt, mtx, GETPC(), store_tag1_parallel); } void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr) @@ -XXX,XX +XXX,XX @@ void HELPER(stg_stub)(CPUARMState *env, uint64_t ptr) } static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, - uintptr_t ra, stg_store1 store1) + uint32_t mtx, uintptr_t ra, stg_store1 store1) { int mmu_idx = arm_env_mmu_index(env); int tag = allocation_tag_from_addr(xt); @@ -XXX,XX +XXX,XX @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, /* Store if page(s) support tags. */ if (mem1) { store1(TAG_GRANULE, mem1, tag); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } if (mem2) { store1(0, mem2, tag); + } else if (mtx) { + canonical_tag_write_fail(env, ptr + TAG_GRANULE, ra); } } else { /* Two stores aligned mod TAG_GRANULE*2 -- modify one byte. */ @@ -XXX,XX +XXX,XX @@ static inline void do_st2g(CPUARMState *env, uint64_t ptr, uint64_t xt, if (mem1) { tag |= tag << 4; qatomic_set(mem1, tag); + } else if (mtx) { + /* Writing tags to canonically tagged memory region: faults */ + canonical_tag_write_fail(env, ptr, ra); } } } -void HELPER(st2g)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(st2g)(CPUARMState *env, uint64_t ptr, uint64_t xt, uint32_t mtx) { - do_st2g(env, ptr, xt, GETPC(), store_tag1); + do_st2g(env, ptr, xt, mtx, GETPC(), store_tag1); } -void HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt) +void HELPER(st2g_parallel)(CPUARMState *env, uint64_t ptr, uint64_t xt, + uint32_t mtx) { - do_st2g(env, ptr, xt, GETPC(), store_tag1_parallel); + do_st2g(env, ptr, xt, mtx, GETPC(), store_tag1_parallel); } void HELPER(st2g_stub)(CPUARMState *env, uint64_t ptr) @@ -XXX,XX +XXX,XX @@ uint64_t HELPER(ldgm)(CPUARMState *env, uint64_t ptr, uint32_t mtx) return ret << shift; } -void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) +void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val, uint32_t mtx) { int mmu_idx = arm_env_mmu_index(env); uintptr_t ra = GETPC(); @@ -XXX,XX +XXX,XX @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) * and if the OS has enabled access to the tags. */ if (!tag_mem) { + /* Storing tags to canonically tagged region: fault. */ + if (mtx) { + canonical_tag_write_fail(env, ptr, ra); + } return; } @@ -XXX,XX +XXX,XX @@ void HELPER(stgm)(CPUARMState *env, uint64_t ptr, uint64_t val) } } -void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) +void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val, + uint32_t mtx) { uintptr_t ra = GETPC(); int mmu_idx = arm_env_mmu_index(env); @@ -XXX,XX +XXX,XX @@ void HELPER(stzgm_tags)(CPUARMState *env, uint64_t ptr, uint64_t val) if (mem) { int tag_pair = (val & 0xf) * 0x11; memset(mem, tag_pair, tag_bytes); + } else if (mtx) { + canonical_tag_write_fail(env, ptr, ra); } } diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(tcg_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag, + tcg_constant_i32(s->mtx)); } } return; @@ -XXX,XX +XXX,XX @@ static void handle_sys(DisasContext *s, bool isread, /* Extract the tag from the register to match STZGM. */ tag = tcg_temp_new_i64(); tcg_gen_shri_i64(tag, tcg_rt, 56); - gen_helper_stzgm_tags(tcg_env, clean_addr, tag); + gen_helper_stzgm_tags(tcg_env, clean_addr, tag, + tcg_constant_i32(s->mtx)); } } return; @@ -XXX,XX +XXX,XX @@ static bool trans_STGP(DisasContext *s, arg_ldstpair *a) /* Perform the tag store, if tag access enabled. */ if (s->ata[0]) { if (tb_cflags(s->base.tb) & CF_PARALLEL) { - gen_helper_stg_parallel(tcg_env, dirty_addr, dirty_addr); + gen_helper_stg_parallel(tcg_env, dirty_addr, dirty_addr, + tcg_constant_i32(s->mtx)); } else { - gen_helper_stg(tcg_env, dirty_addr, dirty_addr); + gen_helper_stg(tcg_env, dirty_addr, dirty_addr, + tcg_constant_i32(s->mtx)); } } @@ -XXX,XX +XXX,XX @@ static bool trans_STZGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stzgm_tags(tcg_env, addr, tcg_rt); + gen_helper_stzgm_tags(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } /* * The non-tags portion of STZGM is mostly like DC_ZVA, @@ -XXX,XX +XXX,XX @@ static bool trans_STGM(DisasContext *s, arg_ldst_tag *a) tcg_rt = cpu_reg(s, a->rt); if (s->ata[0]) { - gen_helper_stgm(tcg_env, addr, tcg_rt); + gen_helper_stgm(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } else { MMUAccessType acc = MMU_DATA_STORE; int size = 4 << s->gm_blocksize; @@ -XXX,XX +XXX,XX @@ static bool do_STG(DisasContext *s, arg_ldst_tag *a, bool is_zero, bool is_pair) } } else if (tb_cflags(s->base.tb) & CF_PARALLEL) { if (is_pair) { - gen_helper_st2g_parallel(tcg_env, addr, tcg_rt); + gen_helper_st2g_parallel(tcg_env, addr, tcg_rt, + tcg_constant_i32(s->mtx)); } else { - gen_helper_stg_parallel(tcg_env, addr, tcg_rt); + gen_helper_stg_parallel(tcg_env, addr, tcg_rt, + tcg_constant_i32(s->mtx)); } } else { if (is_pair) { - gen_helper_st2g(tcg_env, addr, tcg_rt); + gen_helper_st2g(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } else { - gen_helper_stg(tcg_env, addr, tcg_rt); + gen_helper_stg(tcg_env, addr, tcg_rt, tcg_constant_i32(s->mtx)); } } -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Virtual address canonicity checks should ignore mismatch in tag bits during translation step if MTX is set. This mismatch is checked during the tag check instead, in that case. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-11-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 6 +++++- target/arm/internals.h | 1 + target/arm/ptw.c | 35 ++++++++++++++++++++++++++++++----- 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, { uint64_t tcr = regime_tcr(env, mmu_idx); bool epd, hpd, tsz_oob, ds, ha, hd, pie = false; - bool aie = false; + bool mtx, aie = false; int select, tsz, tbi, max_tsz, min_tsz, ps, sh; ARMGranuleSize gran; ARMCPU *cpu = env_archcpu(env); @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, ha = extract32(tcr, 21, 1) && cpu_isar_feature(aa64_hafs, cpu); hd = extract32(tcr, 22, 1) && cpu_isar_feature(aa64_hdbs, cpu); ds = extract64(tcr, 32, 1); + mtx = extract64(tcr, 33, 1) && cpu_isar_feature(aa64_mte_mtx, cpu); } else { bool e0pd; @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, sh = extract32(tcr, 12, 2); hpd = extract64(tcr, 41, 1); e0pd = extract64(tcr, 55, 1); + mtx = extract64(tcr, 60, 1) && cpu_isar_feature(aa64_mte_mtx, cpu); } else { tsz = extract32(tcr, 16, 6); gran = tg1_to_gran_size(extract32(tcr, 30, 2)); @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, sh = extract32(tcr, 28, 2); hpd = extract64(tcr, 42, 1); e0pd = extract64(tcr, 56, 1); + mtx = extract64(tcr, 61, 1) && cpu_isar_feature(aa64_mte_mtx, cpu); } ps = extract64(tcr, 32, 3); ha = extract64(tcr, 39, 1) && cpu_isar_feature(aa64_hafs, cpu); @@ -XXX,XX +XXX,XX @@ ARMVAParameters aa64_va_parameters(CPUARMState *env, uint64_t va, .gran = gran, .pie = pie, .aie = aie, + .mtx = mtx, }; } diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ typedef struct ARMVAParameters { ARMGranuleSize gran : 2; bool pie : 1; bool aie : 1; + bool mtx : 1; } ARMVAParameters; /** diff --git a/target/arm/ptw.c b/target/arm/ptw.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/ptw.c +++ b/target/arm/ptw.c @@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_lpae(CPUARMState *env, S1Translate *ptw, * validation to do here. */ if (inputsize < addrsize) { - uint64_t top_bits = sextract64(address, inputsize, - addrsize - inputsize); - if (-top_bits != param.select) { + /* + * If MTX is enabled, bits 56-59 aren't checked for canonicity + * during translation, since they will later be checked during + * the tag check step. + */ + + uint64_t cmp_mask = MAKE_64BIT_MASK(inputsize, addrsize - inputsize); + + if (param.mtx) { + cmp_mask &= ~MAKE_64BIT_MASK(56, 4); + } + if ((address ^ -param.select) & cmp_mask) { /* The gap between the two regions is a Translation fault */ goto do_translation_fault; } @@ -XXX,XX +XXX,XX @@ static bool get_phys_addr_disabled(CPUARMState *env, int pamax = arm_pamax(env_archcpu(env)); uint64_t tcr = env->cp15.tcr_el[r_el]; int addrtop, tbi; + bool bit55; tbi = aa64_va_parameter_tbi(tcr, mmu_idx); if (access_type == MMU_INST_FETCH) { tbi &= ~aa64_va_parameter_tbid(tcr, mmu_idx); } - tbi = (tbi >> extract64(address, 55, 1)) & 1; + bit55 = extract64(address, 55, 1); + tbi = (tbi >> bit55) & 1; addrtop = (tbi ? 55 : 63); - if (extract64(address, pamax, addrtop - pamax + 1) != 0) { + /* + * With MTX enabled, bits 56-59 are not checked according to + * AArch64.S1DisabledOutput. + */ + uint64_t cmp_mask = MAKE_64BIT_MASK(pamax, addrtop - pamax + 1); + + if (access_type != MMU_INST_FETCH && + cpu_isar_feature(aa64_mte_mtx, env_archcpu(env))) { + int mtx = aa64_va_parameter_mtx(tcr, mmu_idx); + if (mtx & (1 << bit55)) { + cmp_mask &= ~MAKE_64BIT_MASK(56, 4); + } + } + + if (address & cmp_mask) { fi->type = ARMFault_AddressSize; fi->level = 0; fi->stage2 = false; -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> As described in the section on MTX, tag bits should not be used to store or compute the PAC when MTX is set. See also Authenticate(), InsertPAC(), and Strip(). Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-12-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/internals.h | 12 +++++++++++- target/arm/tcg/pauth_helper.c | 18 +++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ static inline uint64_t pauth_ptr_mask(ARMVAParameters param) int bot_pac_bit = 64 - param.tsz; int top_pac_bit = 64 - 8 * param.tbi; - return MAKE_64BIT_MASK(bot_pac_bit, top_pac_bit - bot_pac_bit); + uint64_t mask = MAKE_64BIT_MASK(bot_pac_bit, top_pac_bit - bot_pac_bit); + + /* + * If mtx is enabled, second nibble is not part of PAC. See + * InsertPAC(). + */ + if (param.mtx) { + mask &= ~MAKE_64BIT_MASK(56, 4); + } + + return mask; } /* Add the cpreg definitions for debug related system registers */ diff --git a/target/arm/tcg/pauth_helper.c b/target/arm/tcg/pauth_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/pauth_helper.c +++ b/target/arm/tcg/pauth_helper.c @@ -XXX,XX +XXX,XX @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, } /* Build a pointer with known good extension bits. */ - top_bit = 64 - 8 * param.tbi; + top_bit = 64 - 8 * (param.tbi || param.mtx); bot_bit = 64 - param.tsz; ext_ptr = deposit64(ptr, bot_bit, top_bit - bot_bit, ext); + /* + * If mtx is active but not tbi, then the top 4 bits are replaced with the + * ext bit, while leaving bits 56-59 alone. See InsertPAC(). + */ + if (param.mtx && !param.tbi) { + ext_ptr = deposit64(ext_ptr, 60, 4, ext); + } pac = pauth_computepac(env, ext_ptr, modifier, *key); @@ -XXX,XX +XXX,XX @@ static uint64_t pauth_addpac(CPUARMState *env, uint64_t ptr, uint64_t modifier, if (param.tbi) { ptr &= ~MAKE_64BIT_MASK(bot_bit, 55 - bot_bit + 1); pac &= MAKE_64BIT_MASK(bot_bit, 54 - bot_bit + 1); + } else if (param.mtx) { + ptr &= ~(MAKE_64BIT_MASK(60, 4) | + MAKE_64BIT_MASK(bot_bit, 55 - bot_bit + 1)); + pac &= MAKE_64BIT_MASK(60, 4) | + MAKE_64BIT_MASK(bot_bit, 54 - bot_bit + 1); } else { ptr &= MAKE_64BIT_MASK(0, bot_bit); pac &= ~(MAKE_64BIT_MASK(55, 1) | MAKE_64BIT_MASK(0, bot_bit)); @@ -XXX,XX +XXX,XX @@ static uint64_t pauth_auth(CPUARMState *env, uint64_t ptr, uint64_t modifier, cmp_mask = MAKE_64BIT_MASK(bot_bit, top_bit - bot_bit); cmp_mask &= ~MAKE_64BIT_MASK(55, 1); + if (param.mtx) { + cmp_mask &= ~MAKE_64BIT_MASK(56, 4); + } + if (pauth_feature >= PauthFeat_2) { ARMPauthFeature fault_feature = is_combined ? PauthFeat_FPACCOMBINED : PauthFeat_FPAC; -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> The implemented MTE4 features are now present in docs/system/arm/emulation.rst Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-13-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 5 +++++ target/arm/tcg/cpu64.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_MTE3 (MTE Asymmetric Fault Handling) - FEAT_MTE_ASYM_FAULT (Memory tagging asymmetric faults) - FEAT_MTE_ASYNC (Asynchronous reporting of Tag Check Fault) +- FEAT_MTE_CANONICAL_TAGS (Canonical tag checking) +- FEAT_MTE_NO_ADDRESS_TAGS (Address tagging disabled) +- FEAT_MTE_PERM (NoTagAccess memory attribute) +- FEAT_MTE_STORE_ONLY (Store-only tag checking) +- FEAT_MTE_TAGGED_FAR (Full address reporting of Tag Check Fault) - FEAT_NMI (Non-maskable Interrupt) - FEAT_NV (Nested Virtualization) - FEAT_NV2 (Enhanced nested virtualization support) diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64PFR1, CSV2_FRAC, 0); /* FEAT_CSV2_3 */ t = FIELD_DP64(t, ID_AA64PFR1, NMI, 1); /* FEAT_NMI */ t = FIELD_DP64(t, ID_AA64PFR1, GCS, 1); /* FEAT_GCS */ + /* FEAT_MTE_NO_ADDRESS_TAGS + FEAT_MTE_CANONICAL_TAGS */ + t = FIELD_DP64(t, ID_AA64PFR1, MTEX, 1); SET_IDREG(isar, ID_AA64PFR1, t); t = GET_IDREG(isar, ID_AA64PFR2); t = FIELD_DP64(t, ID_AA64PFR2, FPMR, 1); /* FEAT_FPMR */ + t = FIELD_DP64(t, ID_AA64PFR2, MTEFAR, 1); /* FEAT_MTE_TAGGED_FAR */ + t = FIELD_DP64(t, ID_AA64PFR2, MTESTOREONLY, 1); /* FEAT_MTE_STORE_ONLY */ + t = FIELD_DP64(t, ID_AA64PFR2, MTEPERM, 1); /* FEAT_MTE_PERM */ SET_IDREG(isar, ID_AA64PFR2, t); t = GET_IDREG(isar, ID_AA64MMFR0); -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> This functionality was previously enabled but not advertised or tested. This commit adds a new test, mte-9, that tests the code for proper full-address reporting. FEAT_MTE_TAGGED_FAR requires that FAR_ELx report the full logical address, including tag bits. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-14-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/aarch64/mte-9.c | 48 +++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 tests/tcg/aarch64/mte-9.c diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -XXX,XX +XXX,XX @@ AARCH64_TESTS += bti-2 # MTE Tests ifneq ($(CROSS_CC_HAS_ARMV8_MTE),) -AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 +AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE) endif diff --git a/tests/tcg/aarch64/mte-9.c b/tests/tcg/aarch64/mte-9.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/tcg/aarch64/mte-9.c @@ -XXX,XX +XXX,XX @@ +/* + * Memory tagging, full-address reporting. + * + * Copyright (c) 2021 Linaro Ltd + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "mte.h" + +static void *faulting_ptr; + +void pass(int sig, siginfo_t *info, void *uc) +{ + assert(faulting_ptr == info->si_addr); + exit(0); +} + +int main(int ac, char **av) +{ + struct sigaction sa; + int *p0, *p1, *p2; + long excl = 1; + + enable_mte(PR_MTE_TCF_SYNC); + p0 = alloc_mte_mem(sizeof(*p0)); + + /* Create two differently tagged pointers. */ + asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); + asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); + assert(excl != 1); + asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); + assert(p1 != p2); + + /* Store the tag from the first pointer. */ + asm("stg %0, [%0]" : : "r"(p1)); + + *p1 = 0; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = pass; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + + faulting_ptr = p2; + *p2 = 0; + + abort(); +} -- 2.43.0
From: Gabriel Brookman <brookmangabriel@gmail.com> Added a test that checks that MTE checks are not performed on loads when MTE_STORE_ONLY is enabled. Signed-off-by: Gabriel Brookman <brookmangabriel@gmail.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260529-feat-mte4-v7-15-ccbd3c14eb3c@gmail.com Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- tests/tcg/aarch64/Makefile.target | 2 +- tests/tcg/aarch64/mte-10.c | 49 +++++++++++++++++++++++++++++++ tests/tcg/aarch64/mte.h | 4 +-- 3 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 tests/tcg/aarch64/mte-10.c diff --git a/tests/tcg/aarch64/Makefile.target b/tests/tcg/aarch64/Makefile.target index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/aarch64/Makefile.target +++ b/tests/tcg/aarch64/Makefile.target @@ -XXX,XX +XXX,XX @@ AARCH64_TESTS += bti-2 # MTE Tests ifneq ($(CROSS_CC_HAS_ARMV8_MTE),) -AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 +AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4 mte-5 mte-6 mte-7 mte-8 mte-9 mte-10 mte-%: CFLAGS += $(CROSS_CC_HAS_ARMV8_MTE) endif diff --git a/tests/tcg/aarch64/mte-10.c b/tests/tcg/aarch64/mte-10.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/tests/tcg/aarch64/mte-10.c @@ -XXX,XX +XXX,XX @@ +/* + * Memory tagging, write-only tag checking + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "mte.h" + +void pass(int sig, siginfo_t *info, void *uc) +{ + exit(0); +} + +int main(int ac, char **av) +{ + struct sigaction sa; + int *p0, *p1, *p2; + long excl = 1; + + enable_mte(PR_MTE_TCF_SYNC | PR_MTE_STORE_ONLY); + p0 = alloc_mte_mem(sizeof(*p0)); + + /* Create two differently tagged pointers. */ + asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl)); + asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1)); + assert(excl != 1); + asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl)); + assert(p1 != p2); + + /* Store the tag from the first pointer. */ + asm("stg %0, [%0]" : : "r"(p1)); + + /* + * We write to p1 (stg above makes this check pass) and read from + * p2 (improperly tagged, but since it's a read, we don't care). + */ + *p1 = *p2; + + /* enable handler */ + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = pass; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + + /* now we write to badly tagged p2, should fault. */ + *p2 = 0; + + abort(); +} diff --git a/tests/tcg/aarch64/mte.h b/tests/tcg/aarch64/mte.h index XXXXXXX..XXXXXXX 100644 --- a/tests/tcg/aarch64/mte.h +++ b/tests/tcg/aarch64/mte.h @@ -XXX,XX +XXX,XX @@ # define SEGV_MTESERR 9 #endif -static void enable_mte(int tcf) +static void enable_mte(int flags) { int r = prctl(PR_SET_TAGGED_ADDR_CTRL, - PR_TAGGED_ADDR_ENABLE | tcf | (0xfffe << PR_MTE_TAG_SHIFT), + PR_TAGGED_ADDR_ENABLE | flags | (0xfffe << PR_MTE_TAG_SHIFT), 0, 0, 0); if (r < 0) { perror("PR_SET_TAGGED_ADDR_CTRL"); -- 2.43.0
From: Munkhbaatar Enkhbaatar <munkhuu0825@gmail.com> Suggested-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Munkhbaatar Enkhbaatar <munkhuu0825@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/usb/hcd-ohci.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -XXX,XX +XXX,XX @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed) usb_packet_setup(pkt, pid, ep, 0, addr, false, int_req); usb_packet_addbuf(pkt, buf, len); usb_handle_packet(dev, pkt); - if (pkt->status == USB_RET_ASYNC) { - usb_device_flush_ep_queue(dev, ep); - g_free(pkt); - return 1; - } + + /* The USB core guarantees to never defer ISO TDs. */ + assert(pkt->status != USB_RET_ASYNC); + if (pkt->status == USB_RET_SUCCESS) { ret = pkt->actual_length; } else { -- 2.43.0
From: Munkhbaatar Enkhbaatar <munkhuu0825@gmail.com> ohci_service_iso_td() allocates a USBPacket and frees it after synchronous completion, but it does not call usb_packet_cleanup() first. Call usb_packet_cleanup() before g_free() so resources owned by USBPacket are released. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3463 Signed-off-by: Munkhbaatar Enkhbaatar <munkhuu0825@gmail.com> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- hw/usb/hcd-ohci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/hw/usb/hcd-ohci.c b/hw/usb/hcd-ohci.c index XXXXXXX..XXXXXXX 100644 --- a/hw/usb/hcd-ohci.c +++ b/hw/usb/hcd-ohci.c @@ -XXX,XX +XXX,XX @@ static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed) } else { ret = pkt->status; } + usb_packet_cleanup(pkt); g_free(pkt); trace_usb_ohci_iso_td_so(start_offset, end_offset, start_addr, end_addr, -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> A stray x slipped in and we didn't notice! Fortunately we haven't implemented WFET yet so nothing is affected. But we are about to so lets fix it. Fixes: 4575da5ecb7 (target/arm: report register in WFIT syndromes) Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260529082948.363931-2-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/syndrome.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/target/arm/syndrome.h b/target/arm/syndrome.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/syndrome.h +++ b/target/arm/syndrome.h @@ -XXX,XX +XXX,XX @@ typedef enum { WFI = 0b00, WFE = 0b01, WFIT = 0b10, - WFET = 0xb11 + WFET = 0b11 } wfx_ti; static inline uint32_t syn_wfx(int cv, int cond, int rn, bool rv, wfx_ti ti, bool is_16bit) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> With the advent of WFE and WFI we need to pay closer attention to the reason why the vCPU may be sleeping to figure out if we should wake it up. Create env->halt_reason to track this and then re-order the tests so we: - ignore everything is the vCPU is powered off - wake up if the event_register is set and we were in a WFE - otherwise any IRQ event does wake the vCPU up. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260529082948.363931-3-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/arm-powerctl.c | 6 +++--- target/arm/cpu.c | 40 +++++++++++++++++++++++++++----------- target/arm/cpu.h | 16 +++++++++++++++ target/arm/internals.h | 11 +++++++++++ target/arm/kvm.c | 5 +++-- target/arm/machine.c | 2 +- target/arm/tcg/op_helper.c | 3 +++ 7 files changed, 66 insertions(+), 17 deletions(-) diff --git a/target/arm/arm-powerctl.c b/target/arm/arm-powerctl.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/arm-powerctl.c +++ b/target/arm/arm-powerctl.c @@ -XXX,XX +XXX,XX @@ static void arm_set_cpu_on_async_work(CPUState *target_cpu_state, /* Finally set the power status */ assert(bql_locked()); - target_cpu->power_state = PSCI_ON; + arm_set_cpu_power_state(target_cpu, PSCI_ON); } int arm_set_cpu_on(uint64_t cpuid, uint64_t entry, uint64_t context_id, @@ -XXX,XX +XXX,XX @@ static void arm_set_cpu_on_and_reset_async_work(CPUState *target_cpu_state, /* Finally set the power status */ assert(bql_locked()); - target_cpu->power_state = PSCI_ON; + arm_set_cpu_power_state(target_cpu, PSCI_ON); } int arm_set_cpu_on_and_reset(uint64_t cpuid) @@ -XXX,XX +XXX,XX @@ static void arm_set_cpu_off_async_work(CPUState *target_cpu_state, ARMCPU *target_cpu = ARM_CPU(target_cpu_state); assert(bql_locked()); - target_cpu->power_state = PSCI_OFF; + arm_set_cpu_power_state(target_cpu, PSCI_OFF); target_cpu_state->halted = 1; target_cpu_state->exception_index = EXCP_HLT; } diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static bool arm_cpu_has_work(CPUState *cs) { ARMCPU *cpu = ARM_CPU(cs); - if (arm_feature(&cpu->env, ARM_FEATURE_M)) { - if (cpu->env.event_register) { - return true; - } + /* + * Only another PSCI call can wake the CPU up in which case the + * power_state would be set by arm_set_cpu_on_and_reset_async_work() + */ + if (cpu->power_state == PSCI_OFF) { + g_assert(cpu->env.halt_reason == HALT_PSCI); + return false; } - return (cpu->power_state != PSCI_OFF) - && cpu_test_interrupt(cs, - CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD - | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI - | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR - | CPU_INTERRUPT_EXITTB); + /* + * A wake-up event should only wake us if we are halted on a WFE + */ + if (cpu->env.halt_reason == HALT_WFE && cpu->env.event_register) { + cpu->env.halt_reason = NOT_HALTED; + return true; + } + + /* + * Otherwise pretty much any IRQ would wake us up + */ + if (cpu_test_interrupt(cs, + CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD + | CPU_INTERRUPT_NMI | CPU_INTERRUPT_VINMI | CPU_INTERRUPT_VFNMI + | CPU_INTERRUPT_VFIQ | CPU_INTERRUPT_VIRQ | CPU_INTERRUPT_VSERR + | CPU_INTERRUPT_EXITTB)) { + cpu->env.halt_reason = NOT_HALTED; + return true; + } + + return false; } #endif /* !CONFIG_USER_ONLY */ @@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset_hold(Object *obj, ResetType type) env->vfp.xregs[ARM_VFP_MVFR1] = cpu->isar.mvfr1; env->vfp.xregs[ARM_VFP_MVFR2] = cpu->isar.mvfr2; - cpu->power_state = cs->start_powered_off ? PSCI_OFF : PSCI_ON; + arm_set_cpu_power_state(cpu, cs->start_powered_off ? PSCI_OFF : PSCI_ON); if (arm_feature(env, ARM_FEATURE_AARCH64)) { /* 64 bit CPUs always start in 64 bit mode */ diff --git a/target/arm/cpu.h b/target/arm/cpu.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -XXX,XX +XXX,XX @@ typedef enum ARMFPStatusFlavour { /* Architecturally there are 128 PPIs in a GICv5 */ #define GICV5_NUM_PPIS 128 +/** + * ARMHaltReason - the reason we have entered halt state + * + * To be able to correctly wake up via arm_cpu_has_work() we need to + * track the reason we went to sleep. + */ +typedef enum { + NOT_HALTED = 0, + HALT_PSCI, + HALT_WFI, + HALT_WFE +} ARMHaltReason; + typedef struct CPUArchState { /* Regs for current mode. */ uint32_t regs[16]; @@ -XXX,XX +XXX,XX @@ typedef struct CPUArchState { /* Optional fault info across tlb lookup. */ ARMMMUFaultInfo *tlb_fi; + /* Reason the CPU is halted */ + ARMHaltReason halt_reason; + /* * The event register is shared by all ARM profiles (A/R/M), * so it is stored in the top-level CPU state. diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ bool arm_cpu_match_cpreg_mig_tolerance(ARMCPU *cpu, uint64_t kvmidx, ARMCPRegMigToleranceType type); +/** + * arm_set_cpu_power_state() - set power state synced with halt_reason + */ +static inline void arm_set_cpu_power_state(ARMCPU *cpu, ARMPSCIState state) +{ + CPUARMState *env = &cpu->env; + + cpu->power_state = state; + env->halt_reason = state == PSCI_OFF ? HALT_PSCI : NOT_HALTED; +} + #endif diff --git a/target/arm/kvm.c b/target/arm/kvm.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/kvm.c +++ b/target/arm/kvm.c @@ -XXX,XX +XXX,XX @@ static int kvm_arm_sync_mpstate_to_qemu(ARMCPU *cpu) if (cap_has_mp_state) { struct kvm_mp_state mp_state; int ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MP_STATE, &mp_state); + ARMPSCIState state; if (ret) { return ret; } - cpu->power_state = (mp_state.mp_state == KVM_MP_STATE_STOPPED) ? - PSCI_OFF : PSCI_ON; + state = (mp_state.mp_state == KVM_MP_STATE_STOPPED) ? PSCI_OFF : PSCI_ON; + arm_set_cpu_power_state(cpu, state); } return 0; } diff --git a/target/arm/machine.c b/target/arm/machine.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/machine.c +++ b/target/arm/machine.c @@ -XXX,XX +XXX,XX @@ static int get_power(QEMUFile *f, void *opaque, size_t size, { ARMCPU *cpu = opaque; bool powered_off = qemu_get_byte(f); - cpu->power_state = powered_off ? PSCI_OFF : PSCI_ON; + arm_set_cpu_power_state(cpu, powered_off ? PSCI_OFF : PSCI_ON); return 0; } diff --git a/target/arm/tcg/op_helper.c b/target/arm/tcg/op_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/op_helper.c +++ b/target/arm/tcg/op_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(wfi)(CPUARMState *env, uint32_t insn_len) target_el); } + env->halt_reason = HALT_WFI; cs->exception_index = EXCP_HLT; cs->halted = 1; cpu_loop_exit(cs); @@ -XXX,XX +XXX,XX @@ void HELPER(wfit)(CPUARMState *env, uint32_t rd) } else { timer_mod(cpu->wfxt_timer, nexttick); } + env->halt_reason = HALT_WFI; cs->exception_index = EXCP_HLT; cs->halted = 1; cpu_loop_exit(cs); @@ -XXX,XX +XXX,XX @@ void HELPER(wfe)(CPUARMState *env) return; } + env->halt_reason = HALT_WFE; cs->exception_index = EXCP_HLT; cs->halted = 1; cpu_loop_exit(cs); -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> The event stream control bits are the same for both CNTHCTL and CNTKCTL so rather than duplicating the definitions rename them to be useful in both cases. We will need these in a later commit when we start implementing event streams. Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260529082948.363931-4-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/helper.c | 8 ++++---- target/arm/internals.h | 11 +++++++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri, uint32_t valid_mask = R_CNTHCTL_EL0PCTEN_E2H1_MASK | R_CNTHCTL_EL0VCTEN_E2H1_MASK | - R_CNTHCTL_EVNTEN_MASK | - R_CNTHCTL_EVNTDIR_MASK | - R_CNTHCTL_EVNTI_MASK | + R_CNTxCTL_EVNTEN_MASK | + R_CNTxCTL_EVNTDIR_MASK | + R_CNTxCTL_EVNTI_MASK | R_CNTHCTL_EL0VTEN_MASK | R_CNTHCTL_EL0PTEN_MASK | R_CNTHCTL_EL1PCTEN_E2H1_MASK | @@ -XXX,XX +XXX,XX @@ static void gt_cnthctl_write(CPUARMState *env, const ARMCPRegInfo *ri, R_CNTHCTL_EL1TVCT_MASK | R_CNTHCTL_EL1NVPCT_MASK | R_CNTHCTL_EL1NVVCT_MASK | - R_CNTHCTL_EVNTIS_MASK; + R_CNTxCTL_EVNTIS_MASK; } if (cpu_isar_feature(aa64_ecv, cpu)) { valid_mask |= R_CNTHCTL_ECV_MASK; diff --git a/target/arm/internals.h b/target/arm/internals.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -XXX,XX +XXX,XX @@ FIELD(VSTCR, SA, 30, 1) * have different bit definitions, and EL1PCTEN might be * bit 0 or bit 10. We use _E2H1 and _E2H0 suffixes to * disambiguate if necessary. + * + * The event stream bits (EVN*) are in the same position for + * CNTKCTL_EL1/CTNKCTL. */ FIELD(CNTHCTL, EL0PCTEN_E2H1, 0, 1) FIELD(CNTHCTL, EL0VCTEN_E2H1, 1, 1) FIELD(CNTHCTL, EL1PCTEN_E2H0, 0, 1) FIELD(CNTHCTL, EL1PCEN_E2H0, 1, 1) -FIELD(CNTHCTL, EVNTEN, 2, 1) -FIELD(CNTHCTL, EVNTDIR, 3, 1) -FIELD(CNTHCTL, EVNTI, 4, 4) +FIELD(CNTxCTL, EVNTEN, 2, 1) +FIELD(CNTxCTL, EVNTDIR, 3, 1) +FIELD(CNTxCTL, EVNTI, 4, 4) FIELD(CNTHCTL, EL0VTEN, 8, 1) FIELD(CNTHCTL, EL0PTEN, 9, 1) FIELD(CNTHCTL, EL1PCTEN_E2H1, 10, 1) @@ -XXX,XX +XXX,XX @@ FIELD(CNTHCTL, EL1TVT, 13, 1) FIELD(CNTHCTL, EL1TVCT, 14, 1) FIELD(CNTHCTL, EL1NVPCT, 15, 1) FIELD(CNTHCTL, EL1NVVCT, 16, 1) -FIELD(CNTHCTL, EVNTIS, 17, 1) +FIELD(CNTxCTL, EVNTIS, 17, 1) FIELD(CNTHCTL, CNTVMASK, 18, 1) FIELD(CNTHCTL, CNTPMASK, 19, 1) -- 2.43.0
From: Alex Bennée <alex.bennee@linaro.org> This mirrors the logic for DISAS_WFE in 32 bit world. As the WFE/WFI have similar behaviours shuffle the case statements around a little and update the commentary to cover both. Fixes: 252ec405768 (target-arm: implement WFE/YIELD as a yield for AArch64) Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-id: 20260529082948.363931-5-alex.bennee@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-a64.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_tb_stop(DisasContextBase *dcbase, CPUState *cpu) case DISAS_NORETURN: case DISAS_SWI: break; - case DISAS_WFE: - gen_a64_update_pc(dc, 4); - gen_helper_wfe(tcg_env); - break; case DISAS_YIELD: gen_a64_update_pc(dc, 4); gen_helper_yield(tcg_env); break; + /* + * Both WFE/WFI can cause exceptions or exit the loop to + * halt so we have to make sure we have rectified the PC. + * However they can also return directly if they don't + * enter a wait state so we must add an exit block so we exit + * the loop and check for interrupts. + */ + case DISAS_WFE: + gen_a64_update_pc(dc, 4); + gen_helper_wfe(tcg_env); + tcg_gen_exit_tb(NULL, 0); + break; case DISAS_WFI: - /* - * This is a special case because we don't want to just halt - * the CPU if trying to debug across a WFI. - */ gen_a64_update_pc(dc, 4); gen_helper_wfi(tcg_env, tcg_constant_i32(4)); - /* - * The helper doesn't necessarily throw an exception, but we - * must go back to the main loop to check for interrupts anyway. - */ tcg_gen_exit_tb(NULL, 0); break; } -- 2.43.0
In the exynos4210_combiner device, several cases of bad register offsets passed by the guest are handled by calling hw_error(). This causes QEMU to abort with a guest register dump. These days we prefer to handle "guest does something wrong" by logging it and continuing. Update the hw_error() calls to qemu_log_mask(LOG_GUEST_ERROR). Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3396 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260529143624.158935-2-peter.maydell@linaro.org --- hw/intc/exynos4210_combiner.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/hw/intc/exynos4210_combiner.c b/hw/intc/exynos4210_combiner.c index XXXXXXX..XXXXXXX 100644 --- a/hw/intc/exynos4210_combiner.c +++ b/hw/intc/exynos4210_combiner.c @@ -XXX,XX +XXX,XX @@ */ #include "qemu/osdep.h" +#include "qemu/log.h" #include "hw/core/sysbus.h" #include "migration/vmstate.h" #include "qemu/module.h" #include "hw/intc/exynos4210_combiner.h" #include "hw/arm/exynos4210.h" -#include "hw/core/hw-error.h" #include "hw/core/irq.h" #include "hw/core/qdev-properties.h" #include "qom/object.h" @@ -XXX,XX +XXX,XX @@ exynos4210_combiner_read(void *opaque, hwaddr offset, unsigned size) break; default: if (offset >> 2 >= IIC_REGSET_SIZE) { - hw_error("exynos4210.combiner: overflow of reg_set by 0x" - HWADDR_FMT_plx "offset\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "exynos4210.combiner: overflow of reg_set by 0x" + HWADDR_FMT_plx "offset\n", offset); + return 0; } val = s->reg_set[offset >> 2]; } @@ -XXX,XX +XXX,XX @@ static void exynos4210_combiner_write(void *opaque, hwaddr offset, reg_n = (offset - (req_quad_base_n << 4)) >> 2; if (req_quad_base_n >= IIC_NGRP) { - hw_error("exynos4210.combiner: unallowed write access at offset 0x" - HWADDR_FMT_plx "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "exynos4210.combiner: unallowed write access at offset 0x" + HWADDR_FMT_plx "\n", offset); return; } if (reg_n > 1) { - hw_error("exynos4210.combiner: unallowed write access at offset 0x" - HWADDR_FMT_plx "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "exynos4210.combiner: unallowed write access at offset 0x" + HWADDR_FMT_plx "\n", offset); return; } if (offset >> 2 >= IIC_REGSET_SIZE) { - hw_error("exynos4210.combiner: overflow of reg_set by 0x" - HWADDR_FMT_plx "offset\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "exynos4210.combiner: overflow of reg_set by 0x" + HWADDR_FMT_plx "offset\n", offset); + return; } s->reg_set[offset >> 2] = val; @@ -XXX,XX +XXX,XX @@ static void exynos4210_combiner_write(void *opaque, hwaddr offset, exynos4210_combiner_update(s, grp_quad_base_n + 3); break; default: - hw_error("exynos4210.combiner: unallowed write access at offset 0x" - HWADDR_FMT_plx "\n", offset); + qemu_log_mask(LOG_GUEST_ERROR, + "exynos4210.combiner: unallowed write access at offset 0x" + HWADDR_FMT_plx "\n", offset); break; } } -- 2.43.0
In the pl080 device, we don't implement "peripheral flow control", which is where the DMA engine can be programmed to transfer data until a source or destination peripheral tells it to stop. We currently call hw_error() if the guest tries to use this missing feature, which prints a register dump and aborts QEMU. Change the hw_error() call to the LOG_UNIMP log-and-continue, which is how we prefer to report guest attempts to use unimplemented features these days. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3409 Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Message-id: 20260529143624.158935-3-peter.maydell@linaro.org --- hw/dma/pl080.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hw/dma/pl080.c b/hw/dma/pl080.c index XXXXXXX..XXXXXXX 100644 --- a/hw/dma/pl080.c +++ b/hw/dma/pl080.c @@ -XXX,XX +XXX,XX @@ #include "qemu/log.h" #include "qemu/module.h" #include "hw/dma/pl080.h" -#include "hw/core/hw-error.h" #include "hw/core/irq.h" #include "hw/core/qdev-properties.h" #include "qapi/error.h" @@ -XXX,XX +XXX,XX @@ again: continue; flow = (ch->conf >> 11) & 7; if (flow >= 4) { - hw_error( - "pl080_run: Peripheral flow control not implemented\n"); + qemu_log_mask(LOG_UNIMP, + "pl080_run: Peripheral flow control not implemented\n"); + continue; } src_id = (ch->conf >> 1) & 0x1f; dest_id = (ch->conf >> 6) & 0x1f; -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Missed float_round_nearest_even_max when recomputing round. CC: qemu-stable@nongnu.org Fixes: 72330260cdb ("softfloat: Add float_round_nearest_even_max") Reported-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260608190155.637067-2-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- fpu/softfloat-parts.c.inc | 1 + 1 file changed, 1 insertion(+) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static void partsN(uncanon_normal)(FloatPartsN *p, float_status *s, /* Need to recompute round-to-even/round-to-odd. */ switch (get_float_rounding_mode(s)) { case float_round_nearest_even: + case float_round_nearest_even_max: if (N > 64 && frac_lsb == 0) { inc = ((p->frac_hi & 1) || (p->frac_lo & round_mask) != frac_lsbm1 -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Missed float_round_nearest_even_max and float_round_to_odd_inf in both switch statements. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com> Message-id: 20260608190155.637067-3-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- fpu/softfloat-parts.c.inc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fpu/softfloat-parts.c.inc b/fpu/softfloat-parts.c.inc index XXXXXXX..XXXXXXX 100644 --- a/fpu/softfloat-parts.c.inc +++ b/fpu/softfloat-parts.c.inc @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, /* All fractional */ switch (rmode) { case float_round_nearest_even: + case float_round_nearest_even_max: one = false; if (a->exp == -1) { FloatPartsN tmp; @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, one = a->sign; break; case float_round_to_odd: + case float_round_to_odd_inf: one = true; break; default: @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, switch (rmode) { case float_round_nearest_even: + case float_round_nearest_even_max: inc = ((a->frac_lo & rnd_even_mask) != frac_lsbm1 ? frac_lsbm1 : 0); break; case float_round_ties_away: @@ -XXX,XX +XXX,XX @@ static bool partsN(round_to_int_normal)(FloatPartsN *a, FloatRoundMode rmode, inc = a->sign ? rnd_mask : 0; break; case float_round_to_odd: + case float_round_to_odd_inf: inc = a->frac_lo & frac_lsb ? 0 : rnd_mask; break; default: -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> 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> --- target/arm/tcg/vec_helper.c | 78 +++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ #include "helper.h" #include "tcg/tcg-gvec-desc.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "qemu/int128.h" #include "crypto/clmul.h" #include "vec_internal.h" @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst, float_status *fpst_odd) { + /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; float32 s1c = e1 & 0xffff0000u; float32 s2r = e2 << 16; float32 s2c = e2 & 0xffff0000u; float32 t32; + /* + * Compare f16_dotadd() in sme_helper.c, but here we have + * bfloat16 inputs. In particular that means that we do not + * want the FPCR.FZ16 flush semantics, so we use the normal + * float_status for the input handling here. + */ + FloatParts64 p1r = float32_unpack_canonical(s1r, fpst); + FloatParts64 p1c = float32_unpack_canonical(s1c, fpst); + FloatParts64 p2r = float32_unpack_canonical(s2r, fpst); + FloatParts64 p2c = float32_unpack_canonical(s2c, fpst); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p2r.cls) | float_cmask(p2c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float32_is_any_nan(s1r) || float32_is_any_nan(s1c) || - float32_is_any_nan(s2r) || float32_is_any_nan(s2c)) { - if (float32_is_signaling_nan(s1r, fpst)) { - t32 = s1r; - } else if (float32_is_signaling_nan(s1c, fpst)) { - t32 = s1c; - } else if (float32_is_signaling_nan(s2r, fpst)) { - t32 = s2r; - } else if (float32_is_signaling_nan(s2c, fpst)) { - t32 = s2c; - } else if (float32_is_any_nan(s1r)) { - t32 = s1r; - } else if (float32_is_any_nan(s1c)) { - t32 = s1c; - } else if (float32_is_any_nan(s2r)) { - t32 = s2r; + if (unlikely(all_mask & float_cmask_anynan)) { + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t32 = s1r; + } else if (p1c.cls == float_class_snan) { + t32 = s1c; + } else if (p2r.cls == float_class_snan) { + t32 = s2r; + } else { + t32 = s2c; + } } else { - t32 = s2c; + if (p1r.cls == float_class_qnan) { + t32 = s1r; + } else if (p1c.cls == float_class_qnan) { + t32 = s1c; + } else if (p2r.cls == float_class_qnan) { + t32 = s2r; + } else { + t32 = s2c; + } } /* * FPConvertNaN(FPProcessNaN(t32)) will be done as part * of the final addition below. */ } else { - /* - * Compare f16_dotadd() in sme_helper.c, but here we have - * bfloat16 inputs. In particular that means that we do not - * want the FPCR.FZ16 flush semantics, so we use the normal - * float_status for the input handling here. - */ - float64 e1r = float32_to_float64(s1r, fpst); - float64 e1c = float32_to_float64(s1c, fpst); - float64 e2r = float32_to_float64(s2r, fpst); - float64 e2c = float32_to_float64(s2c, fpst); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, fpst_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, fpst); - - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, fpst); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, fpst); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, fpst); + t32 = float32_round_pack_canonical(&tmp, fpst); } /* The final accumulation step is not fused. */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> This argument is no longer used. Reviewed-by: Philippe Mathieu-Daudé <philmd@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-3-richard.henderson@linaro.org Message-Id: <20260517002550.321291-10-richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/sme_helper.c | 6 ++--- target/arm/tcg/vec_helper.c | 50 +++++++++++++++-------------------- target/arm/tcg/vec_internal.h | 12 +++------ 3 files changed, 29 insertions(+), 39 deletions(-) diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t desc, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; do { @@ -XXX,XX +XXX,XX @@ static void do_bfmopa_w(void *vza, void *vzn, void *vzm, uint32_t m = *(uint32_t *)(vzm + H1_4(col)); m = f16mop_adj_pair(m, pcol, 0); - *a = bfdotadd_ebf(*a, n, m, &fpst, &fpst_odd); + *a = bfdotadd_ebf(*a, n, m, &fpst); } col += 4; pcol >>= 4; diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ DO_MMLA_B(gvec_usmmla_b, do_usmmla_b) * BFloat16 Dot Product */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) +bool is_ebf(CPUARMState *env, float_status *statusp) { /* * For BFDOT, BFMMLA, etc, the behaviour depends on FPCR.EBF. @@ -XXX,XX +XXX,XX @@ bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp) *statusp = env->vfp.fp_status[is_a64(env) ? FPST_A64 : FPST_A32]; set_default_nan_mode(true, statusp); - if (ebf) { - /* EBF=1 needs to do a step with round-to-odd semantics */ - *oddstatusp = *statusp; - set_float_rounding_mode(float_round_to_odd, oddstatusp); - } else { + if (!ebf) { set_flush_to_zero(true, statusp); set_flush_inputs_to_zero(true, statusp); set_float_rounding_mode(float_round_to_odd_inf, statusp); @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) return t1; } -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd) +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst) { /* Unpack two BFloat16 into two Float32, trivially. */ float32 s1r = e1 << 16; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot)(void *vd, void *vn, void *vm, void *va, intptr_t i, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < opr_sz / 4; ++i) { - d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst, &fpst_odd); + d[i] = bfdotadd_ebf(a[i], n[i], m[i], &fpst); } } else { for (i = 0; i < opr_sz / 4; ++i) { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfdot_idx)(void *vd, void *vn, void *vm, intptr_t eltspersegment = MIN(16 / 4, elements); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(index)]; for (j = i; j < i + eltspersegment; j++) { - d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst, &fpst_odd); + d[j] = bfdotadd_ebf(a[j], n[j], m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_bfvdot_idx)(void *vd, void *vn, void *vm, uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (i = 0; i < elements; i += eltspersegment) { uint32_t m_idx = m[i + H4(idx)]; for (j = 0; j < eltspersegment; j++) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); - d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, - &fpst, &fpst_odd); + d[i + H4(j)] = bfdotadd_ebf(a[i + H4(j)], nn, m_idx, &fpst); } } } else { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, intptr_t s, opr_sz = simd_oprsz(desc); float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - float_status fpst, fpst_odd; + float_status fpst; - if (is_ebf(env, &fpst, &fpst_odd)) { + if (is_ebf(env, &fpst)) { for (s = 0; s < opr_sz / 4; s += 4) { float32 sum00, sum01, sum10, sum11; @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_bfmmla)(void *vd, void *vn, void *vm, void *va, * i j i k j k */ sum00 = a[s + H4(0 + 0)]; - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 0)], m[s + H4(0 + 0)], &fpst); + sum00 = bfdotadd_ebf(sum00, n[s + H4(0 + 1)], m[s + H4(0 + 1)], &fpst); sum01 = a[s + H4(0 + 1)]; - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 0)], m[s + H4(2 + 0)], &fpst); + sum01 = bfdotadd_ebf(sum01, n[s + H4(0 + 1)], m[s + H4(2 + 1)], &fpst); sum10 = a[s + H4(2 + 0)]; - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst, &fpst_odd); - sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst, &fpst_odd); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 0)], m[s + H4(0 + 0)], &fpst); + sum10 = bfdotadd_ebf(sum10, n[s + H4(2 + 1)], m[s + H4(0 + 1)], &fpst); sum11 = a[s + H4(2 + 1)]; - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst, &fpst_odd); - sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst, &fpst_odd); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 0)], m[s + H4(2 + 0)], &fpst); + sum11 = bfdotadd_ebf(sum11, n[s + H4(2 + 1)], m[s + H4(2 + 1)], &fpst); d[s + H4(0 + 0)] = sum00; d[s + H4(0 + 1)] = sum01; diff --git a/target/arm/tcg/vec_internal.h b/target/arm/tcg/vec_internal.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_internal.h +++ b/target/arm/tcg/vec_internal.h @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * @sum: addend * @e1, @e2: multiplicand vectors * @fpst: floating-point status to use - * @fpst_odd: floating-point status to use for round-to-odd operations * * BFloat16 2-way dot product of @e1 & @e2, accumulating with @sum. * The @e1 and @e2 operands correspond to the 32-bit source vector @@ -XXX,XX +XXX,XX @@ float32 bfdotadd(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); * Corresponds to the ARM pseudocode function BFDotAdd, specialized * for the FPCR.EBF == 1 case. */ -float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, - float_status *fpst, float_status *fpst_odd); +float32 bfdotadd_ebf(float32 sum, uint32_t e1, uint32_t e2, float_status *fpst); /** * is_ebf: * @env: CPU state * @statusp: pointer to floating point status to fill in - * @oddstatusp: pointer to floating point status to fill in for round-to-odd * * Determine whether a BFDotAdd operation should use FPCR.EBF = 0 - * or FPCR.EBF = 1 semantics. On return, has initialized *statusp - * and *oddstatusp to suitable float_status arguments to use with either - * bfdotadd() or bfdotadd_ebf(). + * or FPCR.EBF = 1 semantics. On return, has initialized *statusp as suitable + * for float_status arguments to either bfdotadd() or bfdotadd_ebf(). * Returns true for EBF = 1, false for EBF = 0. (The caller should use this * to decide whether to call bfdotadd() or bfdotadd_ebf().) */ -bool is_ebf(CPUARMState *env, float_status *statusp, float_status *oddstatusp); +bool is_ebf(CPUARMState *env, float_status *statusp); /* * Negate as for FPCR.AH=1 -- do not negate NaNs. -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> 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-4-richard.henderson@linaro.org Message-Id: <20260517002550.321291-11-richard.henderson@linaro.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/sme_helper.c | 97 +++++++++++++++---------------------- 1 file changed, 40 insertions(+), 57 deletions(-) diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ #include "accel/tcg/helper-retaddr.h" #include "qemu/int128.h" #include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" #include "vec_internal.h" #include "sve_ldst_internal.h" @@ -XXX,XX +XXX,XX @@ static inline uint32_t bf16mop_ah_neg_adj_pair(uint32_t pair, uint32_t pg) } static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, - float_status *s_f16, float_status *s_std, - float_status *s_odd) + float_status *s_f16, float_status *s_std) { /* - * We need three different float_status for different parts of this + * We need two different float_status for different parts of this * operation: * - the input conversion of the float16 values must use the * f16-specific float_status, so that the FPCR.FZ16 control is applied * - operations on float32 including the final accumulation must use * the normal float_status, so that FPCR.FZ is applied - * - we have pre-set-up copy of s_std which is set to round-to-odd, - * for the multiply (see below) */ float16 h1r = e1 & 0xffff; float16 h1c = e1 >> 16; @@ -XXX,XX +XXX,XX @@ static float32 f16_dotadd(float32 sum, uint32_t e1, uint32_t e2, float16 h2c = e2 >> 16; float32 t32; + FloatParts64 p1r = float16_unpack_canonical(h1r, s_f16); + FloatParts64 p1c = float16_unpack_canonical(h1c, s_f16); + FloatParts64 p2r = float16_unpack_canonical(h2r, s_f16); + FloatParts64 p2c = float16_unpack_canonical(h2c, s_f16); + + int all_mask = (float_cmask(p1r.cls) | float_cmask(p1c.cls) | + float_cmask(p2r.cls) | float_cmask(p2c.cls)); + /* C.f. FPProcessNaNs4 */ - if (float16_is_any_nan(h1r) || float16_is_any_nan(h1c) || - float16_is_any_nan(h2r) || float16_is_any_nan(h2c)) { + if (unlikely(all_mask & float_cmask_anynan)) { float16 t16; - if (float16_is_signaling_nan(h1r, s_f16)) { - t16 = h1r; - } else if (float16_is_signaling_nan(h1c, s_f16)) { - t16 = h1c; - } else if (float16_is_signaling_nan(h2r, s_f16)) { - t16 = h2r; - } else if (float16_is_signaling_nan(h2c, s_f16)) { - t16 = h2c; - } else if (float16_is_any_nan(h1r)) { - t16 = h1r; - } else if (float16_is_any_nan(h1c)) { - t16 = h1c; - } else if (float16_is_any_nan(h2r)) { - t16 = h2r; + if (unlikely(all_mask & float_cmask_snan)) { + if (p1r.cls == float_class_snan) { + t16 = h1r; + } else if (p1c.cls == float_class_snan) { + t16 = h1c; + } else if (p2r.cls == float_class_snan) { + t16 = h2r; + } else { + t16 = h2c; + } } else { - t16 = h2c; + if (p1r.cls == float_class_qnan) { + t16 = h1r; + } else if (p1c.cls == float_class_qnan) { + t16 = h1c; + } else if (p2r.cls == float_class_qnan) { + t16 = h2r; + } else { + t16 = h2c; + } } t32 = float16_to_float32(t16, true, s_f16); } else { - float64 e1r = float16_to_float64(h1r, true, s_f16); - float64 e1c = float16_to_float64(h1c, true, s_f16); - float64 e2r = float16_to_float64(h2r, true, s_f16); - float64 e2c = float16_to_float64(h2c, true, s_f16); - float64 t64; - /* * The ARM pseudocode function FPDot performs both multiplies - * and the add with a single rounding operation. Emulate this - * by performing the first multiply in round-to-odd, then doing - * the second multiply as fused multiply-add, and rounding to - * float32 all in one step. + * and the add with a single rounding operation. */ - t64 = float64_mul(e1r, e2r, s_odd); - t64 = float64r32_muladd(e1c, e2c, t64, 0, s_std); - - /* This conversion is exact, because we've already rounded. */ - t32 = float64_to_float32(t64, s_std); + FloatParts64 tmp = parts64_mul(&p1r, &p2r, s_f16); + tmp = parts64_muladd(&p1c, &p2c, &tmp, 0, s_f16); + t32 = float32_round_pack_canonical(&tmp, s_f16); } /* The final accumulation step is not fused. */ @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, uint32_t negx, bool ah_neg) { intptr_t row, col, oprsz = simd_maxsz(desc); - float_status fpst_odd = env->vfp.fp_status[FPST_ZA]; - - set_float_rounding_mode(float_round_to_odd, &fpst_odd); for (row = 0; row < oprsz; ) { uint16_t prow = pn[H2(row >> 4)]; @@ -XXX,XX +XXX,XX @@ static void do_fmopa_w_h(void *vza, void *vzn, void *vzm, uint16_t *pn, m = f16mop_adj_pair(m, pcol, 0); *a = f16_dotadd(*a, n, m, &env->vfp.fp_status[FPST_ZA_F16], - &env->vfp.fp_status[FPST_ZA], - &fpst_odd); + &env->vfp.fp_status[FPST_ZA]); } col += 4; pcol >>= 4; @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = vm; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < oprsz / sizeof(float32); ++i) { d[H4(i)] = f16_dotadd(a[H4(i)], n[H4(i)], m[H4(i)], - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fdot_idx_h)(void *vd, void *vn, void *vm, void *va, bool za = extract32(desc, SIMD_DATA_SHIFT + 2, 1); float_status *fpst_std = &env->vfp.fp_status[za ? FPST_ZA : FPST_A64]; float_status *fpst_f16 = &env->vfp.fp_status[za ? FPST_ZA_F16 : FPST_A64_F16]; - float_status fpst_odd = *fpst_std; float32 *d = vd, *a = va; uint32_t *n = vn, *m = (uint32_t *)vm + H4(idx); - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { d[H4(i + j)] = f16_dotadd(a[H4(i + j)], n[H4(i + j)], mm, - fpst_f16, fpst_std, &fpst_odd); + fpst_f16, fpst_std); } } } @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fvdot_idx_h)(void *vd, void *vn, void *vm, void *va, intptr_t eltspersegment = MIN(4, elements); int idx = extract32(desc, SIMD_DATA_SHIFT, 2); int sel = extract32(desc, SIMD_DATA_SHIFT + 2, 1); - float_status fpst_odd, *fpst_std, *fpst_f16; float32 *d = vd, *a = va; uint16_t *n0 = vn; uint16_t *n1 = vn + sizeof(ARMVectorReg); uint32_t *m = (uint32_t *)vm + H4(idx); - fpst_std = &env->vfp.fp_status[FPST_ZA]; - fpst_f16 = &env->vfp.fp_status[FPST_ZA_F16]; - fpst_odd = *fpst_std; - set_float_rounding_mode(float_round_to_odd, &fpst_odd); - for (i = 0; i < elements; i += eltspersegment) { uint32_t mm = m[i]; for (j = 0; j < eltspersegment; ++j) { uint32_t nn = (n0[H2(2 * (i + j) + sel)]) | (n1[H2(2 * (i + j) + sel)] << 16); d[i + H4(j)] = f16_dotadd(a[i + H4(j)], nn, mm, - fpst_f16, fpst_std, &fpst_odd); + &env->vfp.fp_status[FPST_ZA_F16], + &env->vfp.fp_status[FPST_ZA]); } } } -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Rename to TRANS_FEAT_STREAMING_IF and add a new parameter. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-5-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/translate-sve.c | 12 ++++++------ target/arm/tcg/translate.h | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_4_ptr * const sve2_famax_zpzz_fns[4] = { gen_helper_sve2_famax_s, gen_helper_sve2_famax_d }; -TRANS_FEAT_STREAMING_SME2(FAMAX, aa64_sme2_or_sve2_faminmax, - gen_gvec_fpst_arg_zpzz, - sve2_famax_zpzz_fns[a->esz], a) +TRANS_FEAT_STREAMING_IF(FAMAX, aa64_sme2_or_sve2_faminmax, aa64_sme2, + gen_gvec_fpst_arg_zpzz, + sve2_famax_zpzz_fns[a->esz], a) static gen_helper_gvec_4_ptr * const sve2_famin_zpzz_fns[4] = { NULL, @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_4_ptr * const sve2_famin_zpzz_fns[4] = { gen_helper_sve2_famin_s, gen_helper_sve2_famin_d }; -TRANS_FEAT_STREAMING_SME2(FAMIN, aa64_sme2_or_sve2_faminmax, - gen_gvec_fpst_arg_zpzz, - sve2_famin_zpzz_fns[a->esz], a) +TRANS_FEAT_STREAMING_IF(FAMIN, aa64_sme2_or_sve2_faminmax, aa64_sme2, + gen_gvec_fpst_arg_zpzz, + sve2_famin_zpzz_fns[a->esz], a) typedef void gen_helper_sve_fp2scalar(TCGv_ptr, TCGv_ptr, TCGv_ptr, TCGv_i64, TCGv_ptr, TCGv_i32); diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ static inline void gen_restore_rmode(TCGv_i32 old, TCGv_ptr fpst) /* * For SVE insns which are only valid in Streaming SVE mode when - * SME2 is implemented + * FEAT_STREAM is implemented. */ -#define TRANS_FEAT_STREAMING_SME2(NAME, FEAT, FUNC, ...) \ +#define TRANS_FEAT_STREAMING_IF(NAME, FEAT, FEAT_STREAM, FUNC, ...) \ static bool trans_##NAME(DisasContext *s, arg_##NAME *a) \ { \ - s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s); \ + s->is_nonstreaming = !dc_isar_feature(FEAT_STREAM, s); \ return dc_isar_feature(FEAT, s) && FUNC(s, __VA_ARGS__); \ } -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Create a function to set all default controls for a float_status. Other settings for specific FPST will be set afterward. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-6-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static void cp_reg_check_reset(gpointer key, gpointer value, gpointer opaque) assert(oldvalue == newvalue); } +static void arm_init_fp_status(float_status *s) +{ + memset(s, 0, sizeof(*s)); + arm_set_default_fp_behaviours(s); + /* We want 0 for all other settings. */ +} + static void arm_cpu_reset_hold(Object *obj, ResetType type) { CPUState *cs = CPU(obj); @@ -XXX,XX +XXX,XX @@ static void arm_cpu_reset_hold(Object *obj, ResetType type) env->sau.ctrl = 0; } + for (int i = 0; i < FPST_COUNT; i++) { + arm_init_fp_status(&env->vfp.fp_status[i]); + } + set_flush_to_zero(1, &env->vfp.fp_status[FPST_STD]); set_flush_inputs_to_zero(1, &env->vfp.fp_status[FPST_STD]); set_default_nan_mode(1, &env->vfp.fp_status[FPST_STD]); set_default_nan_mode(1, &env->vfp.fp_status[FPST_STD_F16]); set_default_nan_mode(1, &env->vfp.fp_status[FPST_ZA]); set_default_nan_mode(1, &env->vfp.fp_status[FPST_ZA_F16]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A32]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_ZA]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_STD]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A32_F16]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_A64_F16]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_ZA_F16]); - arm_set_default_fp_behaviours(&env->vfp.fp_status[FPST_STD_F16]); arm_set_ah_fp_behaviours(&env->vfp.fp_status[FPST_AH]); set_flush_to_zero(1, &env->vfp.fp_status[FPST_AH]); set_flush_inputs_to_zero(1, &env->vfp.fp_status[FPST_AH]); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> The unique e4m3 nan encoding is SNaN for Arm. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-7-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu.c | 1 + 1 file changed, 1 insertion(+) diff --git a/target/arm/cpu.c b/target/arm/cpu.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu.c +++ b/target/arm/cpu.c @@ -XXX,XX +XXX,XX @@ static void arm_init_fp_status(float_status *s) { memset(s, 0, sizeof(*s)); arm_set_default_fp_behaviours(s); + set_float_e4m3_nan_is_snan(true, s); /* We want 0 for all other settings. */ } -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> 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> --- target/arm/helper-fp8.h | 14 ++++ target/arm/tcg/a64.decode | 3 + target/arm/tcg/fp8_helper.c | 124 +++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 6 ++ target/arm/tcg/meson.build | 1 + target/arm/tcg/translate-a64.c | 34 +++++++++ target/arm/tcg/translate-a64.h | 1 + 7 files changed, 183 insertions(+) create mode 100644 target/arm/helper-fp8.h create mode 100644 target/arm/tcg/fp8_helper.c create mode 100644 target/arm/tcg/helper-fp8-defs.h diff --git a/target/arm/helper-fp8.h b/target/arm/helper-fp8.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/arm/helper-fp8.h @@ -XXX,XX +XXX,XX @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef HELPER_FP8_H +#define HELPER_FP8_H + +#include "exec/helper-proto-common.h" +#include "exec/helper-gen-common.h" + +#define HELPER_H "tcg/helper-fp8-defs.h" +#include "exec/helper-proto.h.inc" +#include "exec/helper-gen.h.inc" +#undef HELPER_H + +#endif /* HELPER_FP8_H */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ URSQRTE_v 0.10 1110 101 00001 11001 0 ..... ..... @qrr_s FCVTL_v 0.00 1110 0.1 00001 01111 0 ..... ..... @qrr_sd +BF1CVTL 0.10 1110 101 00001 01111 0 ..... ..... @qrr_h +BF2CVTL 0.10 1110 111 00001 01111 0 ..... ..... @qrr_h + &fcvt_q rd rn esz q shift @fcvtq_h . q:1 . ...... 001 .... ...... rn:5 rd:5 \ &fcvt_q esz=1 shift=%fcvt_f_sh_h diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ +/* + * AArch64 FP8 Operations + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "qemu/osdep.h" +#include "cpu.h" +#include "internals.h" +#include "tcg/tcg-gvec-desc.h" +#include "fpu/softfloat.h" +#include "fpu/softfloat-parts.h" +#include "helper-fp8.h" +#include "vec_internal.h" + +#define HELPER_H "tcg/helper-fp8-defs.h" +#include "exec/helper-info.c.inc" + +typedef enum FPMRType { + OFP8_E5M2 = 0, + OFP8_E4M3 = 1, +} FPMRType; + +typedef struct FP8Context { + float_status stat; + ARMFPStatusFlavour fpst; + FPMRType f8fmt; + int scale; + bool high; +} FP8Context; + +static FP8Context fp8_start(CPUARMState *env, uint32_t desc, + FPMRType f8fmt, int scale) +{ + ARMFPStatusFlavour fpst = extract32(desc, SIMD_DATA_SHIFT + 2, 4); + + FP8Context ret = { + .stat = env->vfp.fp_status[fpst], + .fpst = fpst, + .f8fmt = f8fmt, + .scale = scale, + .high = extract32(desc, SIMD_DATA_SHIFT + 1, 1), + }; + + set_flush_to_zero(0, &ret.stat); + set_flush_inputs_to_zero(0, &ret.stat); + set_default_nan_mode(true, &ret.stat); + set_float_rounding_mode(float_round_nearest_even, &ret.stat); + + return ret; +} + +static void fp8_cvt_finish(CPUARMState *env, FP8Context *c) +{ + /* FP8 convert insns don't update FPSR.IDC */ + int e = get_float_exception_flags(&c->stat); + float_raise(e & ~float_flag_input_denormal_used, + &env->vfp.fp_status[c->fpst]); +} + +static FP8Context fp8_src_start(CPUARMState *env, uint32_t desc, int scale_mask) +{ + bool issrc2 = extract32(desc, SIMD_DATA_SHIFT, 1); + uint64_t fpmr = env->vfp.fpmr; + FPMRType f8fmt = (issrc2 + ? FIELD_EX64(fpmr, FPMR, F8S2) + : FIELD_EX64(fpmr, FPMR, F8S1)); + int scale; + + scale = fpmr >> (issrc2 ? R_FPMR_LSCALE2_SHIFT : R_FPMR_LSCALE_SHIFT); + scale = -(scale & scale_mask); + + return fp8_start(env, desc, f8fmt, scale); +} + +/* + * Invalid input format: we could take one of the usual set of + * CONSTRAINED UNPREDICTABLE options for use of a reserved value, + * but choose to take the additional option provided by the FPMR + * register specification, of treating the input as if it were an SNaN. + * + * One of the uses of the input will convert to default nan (because + * all fp8 operations use default_nan_mode) and raise invalid (which + * the operation might suppress by not updating IOC). + */ +static FloatParts64 fp8_invalid_input(uint8_t x, float_status *s) +{ + return (FloatParts64){ .cls = float_class_snan }; +} + +typedef FloatParts64 fp8_input_fn(uint8_t x, float_status *s); + +static fp8_input_fn * const fp8_input_fmt[8] = { + [0 ... 7] = fp8_invalid_input, + [OFP8_E5M2] = float8_e5m2_unpack_canonical, + [OFP8_E4M3] = float8_e4m3_unpack_canonical, +}; + +static bfloat16 fcvt_fp8_to_b16(uint8_t x, fp8_input_fn *f8fmt, + int scale, float_status *s) +{ + FloatParts64 p = f8fmt(x, s); + p = parts64_scalbn(&p, scale, s); + return bfloat16_round_pack_canonical(&p, s); +} + +void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0x3f); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn, scratch[16]; + bfloat16 *d = vd; + + if (vd == vn) { + n = memcpy(scratch, vn, 16); + } + n += ctx.high * 8; + + for (size_t i = 0; i < 8; ++i) { + d[H2(i)] = fcvt_fp8_to_b16(n[H1(i)], input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); + clear_tail(vd, 16, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h new file mode 100644 index XXXXXXX..XXXXXXX --- /dev/null +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ +/* + * AArch64 FP8 helper definitions + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +DEF_HELPER_FLAGS_4(advsimd_bfcvtl, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/meson.build b/target/arm/tcg/meson.build index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/meson.build +++ b/target/arm/tcg/meson.build @@ -XXX,XX +XXX,XX @@ arm_ss.add(when: 'TARGET_AARCH64', if_true: files( 'sme_helper.c', 'sve_helper.c', 'vec_helper64.c', + 'fp8_helper.c', )) arm_common_system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('cpu-v7m.c')) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ #include "helper-a64.h" #include "helper-sme.h" #include "helper-sve.h" +#include "helper-fp8.h" #include "translate.h" #include "translate-a64.h" #include "tcg/tcg-op.h" @@ -XXX,XX +XXX,XX @@ static bool fp_access_check(DisasContext *s) return fp_access_check_only(s) && nonstreaming_check(s); } +/* + * Check that FPMR access is enabled, for an indirect reference by a + * vector instruction. See CheckFPMREnabled(). + */ +bool fpmr_access_check(DisasContext *s) +{ + if (s->fpmr_el) { + /* + * While denied direct access to the FPMR raises SystemRegisterTrap + * and targets a specific EL, denied indirect access to the FPMR + * results in a simple UNDEFINED to the default exception level. + */ + unallocated_encoding(s); + return false; + } + return true; +} + /* * Return <0 for non-supported element sizes, with MO_16 controlled by * FEAT_FP16; return 0 for fp disabled; otherwise return >0 for success. @@ -XXX,XX +XXX,XX @@ static bool trans_FCVTL_v(DisasContext *s, arg_qrr_e *a) return true; } +static bool do_f8cvt(DisasContext *s, arg_qrr_e *a, + gen_helper_gvec_2_ptr *fn, bool issrc2) +{ + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + tcg_env, 16, vec_full_reg_size(s), + issrc2 | (a->q << 1) | (FPST_A64 << 2), fn); + } + return true; +} + +TRANS_FEAT(BF1CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, false) +TRANS_FEAT(BF2CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, true) + static bool trans_OK(DisasContext *s, arg_OK *a) { return true; diff --git a/target/arm/tcg/translate-a64.h b/target/arm/tcg/translate-a64.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.h +++ b/target/arm/tcg/translate-a64.h @@ -XXX,XX +XXX,XX @@ TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf); void write_fp_dreg(DisasContext *s, int reg, TCGv_i64 v); bool logic_imm_decode_wmask(uint64_t *result, unsigned int immn, unsigned int imms, unsigned int immr); +bool fpmr_access_check(DisasContext *s); bool sve_access_check(DisasContext *s); bool sme_enabled_check(DisasContext *s); bool sme_enabled_check_with_svcr(DisasContext *s, unsigned); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-9-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 6 ++++++ target/arm/tcg/fp8_helper.c | 16 ++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/sve.decode | 6 ++++++ target/arm/tcg/translate-sve.c | 23 +++++++++++++++++++++++ 5 files changed, 52 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ isar_feature_aa64_sme2_or_sve2_faminmax(const ARMISARegisters *id) return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_faminmax(id); } +static inline bool +isar_feature_aa64_sme2_or_sve2_f8cvt(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_f8cvt(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); clear_tail(vd, 16, simd_maxsz(desc)); } + +void HELPER(sve2_bfcvt)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0x3f); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d = vd; + size_t nelem = simd_oprsz(desc) / 2; + + for (size_t i = 0; i < nelem; ++i) { + d[H2(i)] = fcvt_fp8_to_b16(n[H1(2 * i + ctx.high)], + input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ */ DEF_HELPER_FLAGS_4(advsimd_bfcvtl, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sve2_bfcvt, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ # Two operand @pd_pn ........ esz:2 .. .... ....... rn:4 . rd:4 &rr_esz @rd_rn ........ esz:2 ...... ...... rn:5 rd:5 &rr_esz +@rd_rn_e0 ........ .. ...... ...... rn:5 rd:5 &rr_esz esz=0 @rd_rnx2 ........ ... ..... ...... ..... rd:5 &rr_esz rn=%rn_ax2 # Two operand with governing predicate, flags setting @@ -XXX,XX +XXX,XX @@ FMINQV 01100100 .. 010 111 101 ... ..... ..... @rd_pg_rn FRECPE 01100101 .. 001 110 001100 ..... ..... @rd_rn FRSQRTE 01100101 .. 001 111 001100 ..... ..... @rd_rn +BF1CVT 01100101 00 001 000 001110 ..... ..... @rd_rn_e0 +BF2CVT 01100101 00 001 000 001111 ..... ..... @rd_rn_e0 +BF1CVTLT 01100101 00 001 001 001110 ..... ..... @rd_rn_e0 +BF2CVTLT 01100101 00 001 001 001111 ..... ..... @rd_rn_e0 + ### SVE FP Compare with Zero Group FCMGE_ppz0 01100101 .. 0100 00 001 ... ..... 0 .... @pd_pg_rn diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ #include "cpu.h" #include "helper-sme.h" #include "helper-sve.h" +#include "helper-fp8.h" #include "translate.h" #include "translate-a64.h" #include "tcg/tcg-op.h" @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(FRSQRTE, aa64_sme_or_sve, gen_gvec_fpst_ah_arg_zz, s->fpcr_ah && dc_isar_feature(aa64_rpres, s) ? frsqrte_rpres_fns[a->esz] : frsqrte_fns[a->esz], a, 0) +static bool do_f8cvt(DisasContext *s, arg_rr_esz *a, + gen_helper_gvec_2_ptr *fn, bool issrc2, bool isodd) +{ + if (fpmr_access_check(s) && sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + tcg_env, vsz, vsz, + issrc2 | (isodd << 1) | (FPST_A64 << 2), fn); + } + return true; +} + +TRANS_FEAT_STREAMING_IF(BF1CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_bfcvt, false, false) +TRANS_FEAT_STREAMING_IF(BF2CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_bfcvt, true, false) +TRANS_FEAT_STREAMING_IF(BF1CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_bfcvt, false, true) +TRANS_FEAT_STREAMING_IF(BF2CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_bfcvt, true, true) + /* *** SVE Floating Point Compare with Zero Group */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> The existing pattern is BFCVT (single-precision to BFloat16). In preparation for introducing more insns of the same name, append the operand sizes. Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-10-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/helper-sme-defs.h | 2 +- target/arm/tcg/sme.decode | 2 +- target/arm/tcg/sme_helper.c | 2 +- target/arm/tcg/translate-sme.c | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/target/arm/tcg/helper-sme-defs.h b/target/arm/tcg/helper-sme-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-sme-defs.h +++ b/target/arm/tcg/helper-sme-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(sme2_umlsll_idx_d, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, DEF_HELPER_FLAGS_5(sme2_usmlall_idx_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) DEF_HELPER_FLAGS_5(sme2_sumlall_idx_s, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, ptr, i32) -DEF_HELPER_FLAGS_4(sme2_bfcvt, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) +DEF_HELPER_FLAGS_4(sme2_bfcvt_hs, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_4(sme2_bfcvtn, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_4(sme2_fcvt_n, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) DEF_HELPER_FLAGS_4(sme2_fcvtn, TCG_CALL_NO_RWG, void, ptr, ptr, fpst, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ SUB_aaz_d 11000001 111 000010 .. 111 ...00 11 ... @az_4x4_o3 @zz_4x2_n1 ........ ... ..... ...... .... . ..... \ &zz_n n=1 zd=%zd_ax4 zn=%zn_ax2 -BFCVT 11000001 011 00000 111000 ....0 ..... @zz_1x2 +BFCVT_hs 11000001 011 00000 111000 ....0 ..... @zz_1x2 BFCVTN 11000001 011 00000 111000 ....1 ..... @zz_1x2 FCVT_n 11000001 001 00000 111000 ....0 ..... @zz_1x2 diff --git a/target/arm/tcg/sme_helper.c b/target/arm/tcg/sme_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme_helper.c +++ b/target/arm/tcg/sme_helper.c @@ -XXX,XX +XXX,XX @@ DO_MLALL_IDX(sme2_sumlall_idx_s, uint32_t, int8_t, uint8_t, H4, H1, +) #undef DO_MLALL_IDX /* Convert and compress */ -void HELPER(sme2_bfcvt)(void *vd, void *vs, float_status *fpst, uint32_t desc) +void HELPER(sme2_bfcvt_hs)(void *vd, void *vs, float_status *fpst, uint32_t desc) { ARMVectorReg scratch; size_t oprsz = simd_oprsz(desc); diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_zz_fpst(DisasContext *s, arg_zz_n *a, int data, return true; } -TRANS_FEAT(BFCVT, aa64_sme2, do_zz_fpst, a, 0, - s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvt) +TRANS_FEAT(BFCVT_hs, aa64_sme2, do_zz_fpst, a, 0, + s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvt_hs) TRANS_FEAT(BFCVTN, aa64_sme2, do_zz_fpst, a, 0, s->fpcr_ah ? FPST_AH : FPST_A64, gen_helper_sme2_bfcvtn) TRANS_FEAT(FCVT_n, aa64_sme2, do_zz_fpst, a, 0, -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-11-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 47 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sme.decode | 5 ++++ target/arm/tcg/translate-sme.c | 19 +++++++++++++ 4 files changed, 73 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sve2_bfcvt)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +void HELPER(sme2_bfcvt_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0x3f); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d0 = vd; + uint16_t *d1 = vd + sizeof(ARMVectorReg); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + ARMVectorReg scratch; + + if (vectors_overlap(vd, 2, vn, 1)) { + n = memcpy(&scratch, vn, oprsz); + } + + for (size_t i = 0; i < nelem; ++i) { + d0[H2(i)] = fcvt_fp8_to_b16(n[H1(i)], input_fmt, + ctx.scale, &ctx.stat); + } + for (size_t i = 0; i < nelem; ++i) { + d1[H2(i)] = fcvt_fp8_to_b16(n[H1(i + nelem)], input_fmt, + ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} + +void HELPER(sme2_bfcvtl_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0x3f); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d0 = vd; + uint16_t *d1 = vd + sizeof(ARMVectorReg); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + + for (size_t i = 0; i < nelem; ++i) { + uint8_t e0 = n[H1(2 * i + 0)]; + uint8_t e1 = n[H1(2 * i + 1)]; + d0[H2(i)] = fcvt_fp8_to_b16(e0, input_fmt, ctx.scale, &ctx.stat); + d1[H2(i)] = fcvt_fp8_to_b16(e1, input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(advsimd_bfcvtl, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_bfcvt, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_bfcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_bfcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ UUNPK_4bh 11000001 011 10101 111000 ....0 ...01 @zz_4x2_n1 UUNPK_4hs 11000001 101 10101 111000 ....0 ...01 @zz_4x2_n1 UUNPK_4sd 11000001 111 10101 111000 ....0 ...01 @zz_4x2_n1 +BF1CVT 11000001 011 00110 111000 ..... ....0 @zz_2x1 +BF2CVT 11000001 111 00110 111000 ..... ....0 @zz_2x1 +BF1CVTL 11000001 011 00110 111000 ..... ....1 @zz_2x1 +BF2CVTL 11000001 111 00110 111000 ..... ....1 @zz_2x1 + ZIP_4 11000001 esz:2 1 10110 111000 ...00 ... 00 \ &zz_e zd=%zd_ax4 zn=%zn_ax4 ZIP_4 11000001 001 10111 111000 ...00 ... 00 \ diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ #include "helper-a64.h" #include "helper-sme.h" #include "helper-sve.h" +#include "helper-fp8.h" #include "translate.h" #include "translate-a64.h" #include "tcg/tcg-op.h" @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(UUNPK_4bh, aa64_sme2, do_zz, a, 0, gen_helper_sme2_uunpk4_bh) TRANS_FEAT(UUNPK_4hs, aa64_sme2, do_zz, a, 0, gen_helper_sme2_uunpk4_hs) TRANS_FEAT(UUNPK_4sd, aa64_sme2, do_zz, a, 0, gen_helper_sme2_uunpk4_sd) +static bool do_f8cvt(DisasContext *s, arg_zz_n *a, + gen_helper_gvec_2_ptr *fn, bool issrc2) +{ + if (fpmr_access_check(s) && sme_sm_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + tcg_gen_gvec_2_ptr(vec_full_reg_offset(s, a->zd), + vec_full_reg_offset(s, a->zn), + tcg_env, svl, svl, + issrc2 | (FPST_ZA << 2), fn); + } + return true; +} + +TRANS_FEAT(BF1CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvt_hb, 0) +TRANS_FEAT(BF2CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvt_hb, 1) +TRANS_FEAT(BF1CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvtl_hb, 0) +TRANS_FEAT(BF2CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvtl_hb, 1) + static bool do_zipuzp_4(DisasContext *s, arg_zz_e *a, gen_helper_gvec_2 * const fn[5]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-12-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 3 +++ target/arm/tcg/fp8_helper.c | 29 +++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/translate-a64.c | 3 +++ 4 files changed, 37 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ URSQRTE_v 0.10 1110 101 00001 11001 0 ..... ..... @qrr_s FCVTL_v 0.00 1110 0.1 00001 01111 0 ..... ..... @qrr_sd +F1CVTL 0.10 1110 001 00001 01111 0 ..... ..... @qrr_h +F2CVTL 0.10 1110 011 00001 01111 0 ..... ..... @qrr_h + BF1CVTL 0.10 1110 101 00001 01111 0 ..... ..... @qrr_h BF2CVTL 0.10 1110 111 00001 01111 0 ..... ..... @qrr_h diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ static bfloat16 fcvt_fp8_to_b16(uint8_t x, fp8_input_fn *f8fmt, return bfloat16_round_pack_canonical(&p, s); } +static float16 fcvt_fp8_to_f16(uint8_t x, fp8_input_fn *f8fmt, + int scale, float_status *s) +{ + FloatParts64 p = f8fmt(x, s); + p = parts64_scalbn(&p, scale, s); + return float16_round_pack_canonical(&p, s); +} + void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); @@ -XXX,XX +XXX,XX @@ void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) clear_tail(vd, 16, simd_maxsz(desc)); } +void HELPER(advsimd_fcvtl_hb)(void *vd, void *vn, + CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0xf); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn, scratch[16]; + float16 *d = vd; + + if (vd == vn) { + n = memcpy(scratch, vn, 16); + } + n += ctx.high * 8; + + for (size_t i = 0; i < 8; ++i) { + d[H2(i)] = fcvt_fp8_to_f16(n[H1(i)], input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); + clear_tail(vd, 16, simd_maxsz(desc)); +} + void HELPER(sve2_bfcvt)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(advsimd_bfcvtl, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_bfcvt, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_bfcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_bfcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(advsimd_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_f8cvt(DisasContext *s, arg_qrr_e *a, return true; } +TRANS_FEAT(F1CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_fcvtl_hb, false) +TRANS_FEAT(F2CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_fcvtl_hb, true) + TRANS_FEAT(BF1CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, false) TRANS_FEAT(BF2CVTL, aa64_f8cvt, do_f8cvt, a, gen_helper_advsimd_bfcvtl, true) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-13-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 16 ++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/sve.decode | 5 +++++ target/arm/tcg/translate-sve.c | 9 +++++++++ 4 files changed, 31 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sve2_bfcvt)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } +void HELPER(sve2_fcvt_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0xf); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d = vd; + size_t nelem = simd_oprsz(desc) / 2; + + for (size_t i = 0; i < nelem; ++i) { + d[H2(i)] = fcvt_fp8_to_f16(n[H1(2 * i + ctx.high)], + input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} + void HELPER(sme2_bfcvt_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_bfcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_bfcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(advsimd_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sve2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ FMINQV 01100100 .. 010 111 101 ... ..... ..... @rd_pg_rn FRECPE 01100101 .. 001 110 001100 ..... ..... @rd_rn FRSQRTE 01100101 .. 001 111 001100 ..... ..... @rd_rn +F1CVT 01100101 00 001 000 001100 ..... ..... @rd_rn_e0 +F2CVT 01100101 00 001 000 001101 ..... ..... @rd_rn_e0 +F1CVTLT 01100101 00 001 001 001100 ..... ..... @rd_rn_e0 +F2CVTLT 01100101 00 001 001 001101 ..... ..... @rd_rn_e0 + BF1CVT 01100101 00 001 000 001110 ..... ..... @rd_rn_e0 BF2CVT 01100101 00 001 000 001111 ..... ..... @rd_rn_e0 BF1CVTLT 01100101 00 001 001 001110 ..... ..... @rd_rn_e0 diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool do_f8cvt(DisasContext *s, arg_rr_esz *a, return true; } +TRANS_FEAT_STREAMING_IF(F1CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvt_hb, false, false) +TRANS_FEAT_STREAMING_IF(F2CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvt_hb, true, false) +TRANS_FEAT_STREAMING_IF(F1CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvt_hb, false, true) +TRANS_FEAT_STREAMING_IF(F2CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvt_hb, true, true) + TRANS_FEAT_STREAMING_IF(BF1CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_bfcvt, false, false) TRANS_FEAT_STREAMING_IF(BF2CVT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-14-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 47 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sme.decode | 5 ++++ target/arm/tcg/translate-sme.c | 5 ++++ 4 files changed, 59 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_bfcvt_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } +void HELPER(sme2_fcvt_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0xf); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d0 = vd; + uint16_t *d1 = vd + sizeof(ARMVectorReg); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + ARMVectorReg scratch; + + if (vectors_overlap(vd, 2, vn, 1)) { + n = memcpy(&scratch, vn, oprsz); + } + + for (size_t i = 0; i < nelem; ++i) { + d0[H2(i)] = fcvt_fp8_to_f16(n[H1(i)], input_fmt, + ctx.scale, &ctx.stat); + } + for (size_t i = 0; i < nelem; ++i) { + d1[H2(i)] = fcvt_fp8_to_f16(n[H1(i + nelem)], input_fmt, + ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} + void HELPER(sme2_bfcvtl_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_bfcvtl_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +void HELPER(sme2_fcvtl_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_src_start(env, desc, 0xf); + fp8_input_fn *input_fmt = fp8_input_fmt[ctx.f8fmt]; + uint8_t *n = vn; + uint16_t *d0 = vd; + uint16_t *d1 = vd + sizeof(ARMVectorReg); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + + for (size_t i = 0; i < nelem; ++i) { + uint8_t e0 = n[H1(2 * i + 0)]; + uint8_t e1 = n[H1(2 * i + 1)]; + d0[H2(i)] = fcvt_fp8_to_f16(e0, input_fmt, ctx.scale, &ctx.stat); + d1[H2(i)] = fcvt_fp8_to_f16(e1, input_fmt, ctx.scale, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_bfcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(advsimd_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ UUNPK_4bh 11000001 011 10101 111000 ....0 ...01 @zz_4x2_n1 UUNPK_4hs 11000001 101 10101 111000 ....0 ...01 @zz_4x2_n1 UUNPK_4sd 11000001 111 10101 111000 ....0 ...01 @zz_4x2_n1 +F1CVT 11000001 001 00110 111000 ..... ....0 @zz_2x1 +F2CVT 11000001 101 00110 111000 ..... ....0 @zz_2x1 +F1CVTL 11000001 001 00110 111000 ..... ....1 @zz_2x1 +F2CVTL 11000001 101 00110 111000 ..... ....1 @zz_2x1 + BF1CVT 11000001 011 00110 111000 ..... ....0 @zz_2x1 BF2CVT 11000001 111 00110 111000 ..... ....0 @zz_2x1 BF1CVTL 11000001 011 00110 111000 ..... ....1 @zz_2x1 diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_f8cvt(DisasContext *s, arg_zz_n *a, return true; } +TRANS_FEAT(F1CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvt_hb, 0) +TRANS_FEAT(F2CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvt_hb, 1) +TRANS_FEAT(F1CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvtl_hb, 0) +TRANS_FEAT(F2CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvtl_hb, 1) + TRANS_FEAT(BF1CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvt_hb, 0) TRANS_FEAT(BF2CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvt_hb, 1) TRANS_FEAT(BF1CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvtl_hb, 0) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-15-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 92 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 + target/arm/tcg/sve.decode | 2 + target/arm/tcg/translate-sve.c | 3 ++ 4 files changed, 99 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ static FP8Context fp8_src_start(CPUARMState *env, uint32_t desc, int scale_mask) return fp8_start(env, desc, f8fmt, scale); } +static FP8Context fp8_dst_start(CPUARMState *env, uint32_t desc, bool is_f16) +{ + uint64_t fpmr = env->vfp.fpmr; + FPMRType f8fmt = FIELD_EX64(fpmr, FPMR, F8D); + int scale = (is_f16 + ? FIELD_SEX64(fpmr, FPMR, NSCALE_F16) + : FIELD_SEX64(fpmr, FPMR, NSCALE)); + + return fp8_start(env, desc, f8fmt, scale); +} + /* * Invalid input format: we could take one of the usual set of * CONSTRAINED UNPREDICTABLE options for use of a reserved value, @@ -XXX,XX +XXX,XX @@ static float16 fcvt_fp8_to_f16(uint8_t x, fp8_input_fn *f8fmt, return float16_round_pack_canonical(&p, s); } +/* + * Invalid output format: we could take one of the usual set of + * CONSTRAINED UNPREDICTABLE options for use of a reserved value, + * but choose to take the additional option provided by the FPMR + * register specification, of setting the result to 0xff and + * signaling Invalid Operation. + */ +static uint8_t fcvt_fp8_invalid_output(FloatParts64 *p, int scale, + bool saturate, float_status *s) +{ + float_raise(float_flag_invalid, s); + return 0xff; +} + +static uint8_t fcvt_fp8_e4m3_output(FloatParts64 *p, int scale, + bool saturate, float_status *s) +{ + *p = parts64_scalbn(p, scale, s); + /* + * Saturating Inf -> Max handled in uncanon_e4m3_overflow + * because there is no infinity encoding. + */ + return float8_e4m3_round_pack_canonical(p, s, saturate); +} + +static uint8_t fcvt_fp8_e5m2_output(FloatParts64 *p, int scale, + bool saturate, float_status *s) +{ + /* + * Because e5m2 has an infinity encoding, we need to handle + * saturation conversion of Inf -> Max manually. + */ + if (unlikely(p->cls == float_class_inf)) { + if (saturate) { + /* maximum or minimum normal value for E5M2 */ + return 0x7b | (p->sign << 7); + } + } else { + *p = parts64_scalbn(p, scale, s); + } + return float8_e5m2_round_pack_canonical(p, s, saturate); +} + +typedef uint8_t fcvt_fp8_output_fn(FloatParts64 *, int, bool, float_status *); + +static fcvt_fp8_output_fn * const fcvt_fp8_output_fmt[8] = { + [0 ... 7] = fcvt_fp8_invalid_output, + [OFP8_E5M2] = fcvt_fp8_e5m2_output, + [OFP8_E4M3] = fcvt_fp8_e4m3_output, +}; + +static uint8_t fcvt_b16_to_fp8(bfloat16 x, fcvt_fp8_output_fn *f8fmt, + int scale, bool saturate, float_status *s) +{ + FloatParts64 p = bfloat16_unpack_canonical(x, s); + return f8fmt(&p, scale, saturate, s); +} + void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fcvtl_hb)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +void HELPER(sve2_bfcvtn_bh)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint16_t *n0 = vn; + uint16_t *n1 = vn + sizeof(ARMVectorReg); + uint8_t *d = vd; + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + + for (size_t i = 0; i < nelem; ++i) { + bfloat16 e0 = n0[H2(i)]; + bfloat16 e1 = n1[H2(i)]; + d[H1(2 * i + 0)] = fcvt_b16_to_fp8(e0, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(2 * i + 1)] = fcvt_b16_to_fp8(e1, output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(advsimd_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(sve2_bfcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ BF2CVT 01100101 00 001 000 001111 ..... ..... @rd_rn_e0 BF1CVTLT 01100101 00 001 001 001110 ..... ..... @rd_rn_e0 BF2CVTLT 01100101 00 001 001 001111 ..... ..... @rd_rn_e0 +BFCVTN 01100101 00 001 010 001110 ....0 ..... @rd_rnx2 esz=1 + ### SVE FP Compare with Zero Group FCMGE_ppz0 01100101 .. 0100 00 001 ... ..... 0 .... @pd_pg_rn diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT_STREAMING_IF(BF1CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, TRANS_FEAT_STREAMING_IF(BF2CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_bfcvt, true, true) +TRANS_FEAT_STREAMING_IF(BFCVTN, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_bfcvtn_bh, false, false) + /* *** SVE Floating Point Compare with Zero Group */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-16-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 2 ++ target/arm/tcg/fp8_helper.c | 37 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/translate-a64.c | 15 +++++++++++++ 4 files changed, 56 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FAMIN 0.10 1110 1.1 ..... 11011 1 ..... ..... @qrrr_sd FSCALE 0.10 1110 110 ..... 00111 1 ..... ..... @qrrr_h FSCALE 0.10 1110 1.1 ..... 11111 1 ..... ..... @qrrr_sd +FCVTN_bh 0.00 1110 010 ..... 11110 1 ..... ..... @qrrr_h + ### Advanced SIMD scalar x indexed element FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ static uint8_t fcvt_b16_to_fp8(bfloat16 x, fcvt_fp8_output_fn *f8fmt, return f8fmt(&p, scale, saturate, s); } +static uint8_t fcvt_f16_to_fp8(float16 x, fcvt_fp8_output_fn *f8fmt, + int scale, bool saturate, float_status *s) +{ + FloatParts64 p = float16_unpack_canonical(x, s); + return f8fmt(&p, scale, saturate, s); +} + void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); @@ -XXX,XX +XXX,XX @@ void HELPER(sve2_bfcvtn_bh)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +void HELPER(gvec_fcvt_bh)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, true); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint16_t *n = vn; + uint16_t *m = vm; + uint8_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + ARMVectorReg scratch; + + if (vd == vm) { + m = memcpy(&scratch, vm, oprsz); + } + + for (size_t i = 0; i < nelem; ++i) { + d[H1(i)] = fcvt_f16_to_fp8(n[H2(i)], output_fmt, + ctx.scale, osc, &ctx.stat); + } + for (size_t i = 0; i < nelem; ++i) { + d[H1(i) + nelem] = fcvt_f16_to_fp8(m[H2(i)], output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_fcvt_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_bfcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fcvt_bh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static gen_helper_gvec_3_ptr * const f_vector_fscale[3] = { }; TRANS_FEAT(FSCALE, aa64_f8cvt, do_fp3_vector, a, 0, f_vector_fscale) +static bool trans_FCVTN_bh(DisasContext *s, arg_qrrr_e *a) +{ + if (!dc_isar_feature(aa64_f8cvt, s)) { + return false; + } + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, a->q ? 16 : 8, vec_full_reg_size(s), + FPST_A64 << 2, gen_helper_gvec_fcvt_bh); + } + return true; +} + static bool do_fmlal(DisasContext *s, arg_qrrr_e *a, bool is_s, bool is_2) { if (fp_access_check(s)) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-17-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 1 + target/arm/tcg/fp8_helper.c | 33 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/translate-a64.c | 16 ++++++++++++++++ 4 files changed, 52 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FSCALE 0.10 1110 110 ..... 00111 1 ..... ..... @qrrr_h FSCALE 0.10 1110 1.1 ..... 11111 1 ..... ..... @qrrr_sd FCVTN_bh 0.00 1110 010 ..... 11110 1 ..... ..... @qrrr_h +FCVTN_bs 0.00 1110 000 ..... 11110 1 ..... ..... @qrrr_h ### Advanced SIMD scalar x indexed element diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ static uint8_t fcvt_f16_to_fp8(float16 x, fcvt_fp8_output_fn *f8fmt, return f8fmt(&p, scale, saturate, s); } +static uint8_t fcvt_f32_to_fp8(float32 x, fcvt_fp8_output_fn *f8fmt, + int scale, bool saturate, float_status *s) +{ + FloatParts64 p = float32_unpack_canonical(x, s); + return f8fmt(&p, scale, saturate, s); +} + void HELPER(advsimd_bfcvtl)(void *vd, void *vn, CPUARMState *env, uint32_t desc) { FP8Context ctx = fp8_src_start(env, desc, 0x3f); @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fcvt_bh)(void *vd, void *vn, void *vm, fp8_cvt_finish(env, &ctx); clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(advsimd_fcvt_bs)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint32_t *n = vn, *m = vm, scratch[4]; + uint8_t *d = vd + 8 * ctx.high; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + + if (vd == vm) { + m = memcpy(scratch, vm, 16); + } + + for (size_t i = 0; i < 4; ++i) { + d[H1(i + 0)] = fcvt_f32_to_fp8(n[H4(i)], output_fmt, + ctx.scale, osc, &ctx.stat); + } + for (size_t i = 0; i < 4; ++i) { + d[H1(i + 4)] = fcvt_f32_to_fp8(m[H4(i)], output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); + clear_tail(vd, ctx.high ? 16 : 8, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_bfcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fcvt_bh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(advsimd_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_FCVTN_bh(DisasContext *s, arg_qrrr_e *a) return true; } +static bool trans_FCVTN_bs(DisasContext *s, arg_qrrr_e *a) +{ + if (!dc_isar_feature(aa64_f8cvt, s)) { + return false; + } + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, 16, vec_full_reg_size(s), + (a->q << 1) | FPST_A64 << 2, + gen_helper_advsimd_fcvt_bs); + } + return true; +} + static bool do_fmlal(DisasContext *s, arg_qrrr_e *a, bool is_s, bool is_2) { if (fp_access_check(s)) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-18-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 23 +++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/sve.decode | 1 + target/arm/tcg/translate-sve.c | 2 ++ 4 files changed, 27 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fcvt_bh)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } +void HELPER(sve2_fcvtn_bh)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, true); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint16_t *n0 = vn; + uint16_t *n1 = vn + sizeof(ARMVectorReg); + uint8_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + + for (size_t i = 0; i < nelem; ++i) { + float16 e0 = n0[H2(i)]; + float16 e1 = n1[H2(i)]; + d[H1(2 * i + 0)] = fcvt_f16_to_fp8(e0, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(2 * i + 1)] = fcvt_f16_to_fp8(e1, output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} + void HELPER(advsimd_fcvt_bs)(void *vd, void *vn, void *vm, CPUARMState *env, uint32_t desc) { diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_fcvtl_hb, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_bfcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fcvt_bh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sve2_fcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(advsimd_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ BF2CVT 01100101 00 001 000 001111 ..... ..... @rd_rn_e0 BF1CVTLT 01100101 00 001 001 001110 ..... ..... @rd_rn_e0 BF2CVTLT 01100101 00 001 001 001111 ..... ..... @rd_rn_e0 +FCVTN 01100101 00 001 010 001100 ....0 ..... @rd_rnx2 esz=1 BFCVTN 01100101 00 001 010 001110 ....0 ..... @rd_rnx2 esz=1 ### SVE FP Compare with Zero Group diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT_STREAMING_IF(BF1CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, TRANS_FEAT_STREAMING_IF(BF2CVTLT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_bfcvt, true, true) +TRANS_FEAT_STREAMING_IF(FCVTN, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvtn_bh, false, false) TRANS_FEAT_STREAMING_IF(BFCVTN, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_bfcvtn_bh, false, false) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-19-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 47 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sve.decode | 2 ++ target/arm/tcg/translate-sve.c | 4 +++ 4 files changed, 55 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(advsimd_fcvt_bs)(void *vd, void *vn, void *vm, fp8_cvt_finish(env, &ctx); clear_tail(vd, ctx.high ? 16 : 8, simd_maxsz(desc)); } + +void HELPER(sve2_fcvtnb_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint32_t *n0 = vn; + uint32_t *n1 = vn + sizeof(ARMVectorReg); + uint16_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + + for (size_t i = 0; i < nelem; ++i) { + float32 e0 = n0[H4(i)]; + float32 e1 = n1[H4(i)]; + /* Zero-extend uint8_t to clear the odd lanes. */ + d[H2(2 * i + 0)] = fcvt_f32_to_fp8(e0, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H2(2 * i + 1)] = fcvt_f32_to_fp8(e1, output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} + +void HELPER(sve2_fcvtnt_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint32_t *n0 = vn; + uint32_t *n1 = vn + sizeof(ARMVectorReg); + uint8_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + + for (size_t i = 0; i < nelem; ++i) { + float32 e0 = n0[H4(i)]; + float32 e1 = n1[H4(i)]; + d[H1(4 * i + 1)] = fcvt_f32_to_fp8(e0, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(4 * i + 3)] = fcvt_f32_to_fp8(e1, output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(gvec_fcvt_bh, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(advsimd_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sve2_fcvtnb_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sve2_fcvtnt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ BF2CVTLT 01100101 00 001 001 001111 ..... ..... @rd_rn_e0 FCVTN 01100101 00 001 010 001100 ....0 ..... @rd_rnx2 esz=1 BFCVTN 01100101 00 001 010 001110 ....0 ..... @rd_rnx2 esz=1 +FCVTNB 01100101 00 001 010 001101 ....0 ..... @rd_rnx2 esz=2 +FCVTNT 01100101 00 001 010 001111 ....0 ..... @rd_rnx2 esz=2 ### SVE FP Compare with Zero Group diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT_STREAMING_IF(FCVTN, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_fcvtn_bh, false, false) TRANS_FEAT_STREAMING_IF(BFCVTN, aa64_sme2_or_sve2_f8cvt, aa64_sme2, do_f8cvt, a, gen_helper_sve2_bfcvtn_bh, false, false) +TRANS_FEAT_STREAMING_IF(FCVTNB, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvtnb_bs, false, false) +TRANS_FEAT_STREAMING_IF(FCVTNT, aa64_sme2_or_sve2_f8cvt, aa64_sme2, + do_f8cvt, a, gen_helper_sve2_fcvtnt_bs, false, false) /* *** SVE Floating Point Compare with Zero Group -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-20-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/translate-sme.c | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ BF2CVT 11000001 111 00110 111000 ..... ....0 @zz_2x1 BF1CVTL 11000001 011 00110 111000 ..... ....1 @zz_2x1 BF2CVTL 11000001 111 00110 111000 ..... ....1 @zz_2x1 +FCVT_bh 11000001 001 00100 111000 ....0 ..... @zz_1x2 + ZIP_4 11000001 esz:2 1 10110 111000 ...00 ... 00 \ &zz_e zd=%zd_ax4 zn=%zn_ax4 ZIP_4 11000001 001 10111 111000 ...00 ... 00 \ diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(BF2CVT, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvt_hb, 1) TRANS_FEAT(BF1CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvtl_hb, 0) TRANS_FEAT(BF2CVTL, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_bfcvtl_hb, 1) +static bool trans_FCVT_bh(DisasContext *s, arg_zz_n *a) +{ + if (!dc_isar_feature(aa64_sme2_f8cvt, s)) { + return false; + } + if (fpmr_access_check(s) && sme_sm_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->zd), + vec_full_reg_offset(s, a->zn), + vec_full_reg_offset(s, a->zn + 1), + tcg_env, svl, svl, + FPST_ZA << 2, gen_helper_gvec_fcvt_bh); + } + return true; +} + static bool do_zipuzp_4(DisasContext *s, arg_zz_e *a, gen_helper_gvec_2 * const fn[5]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-21-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/fp8_helper.c | 59 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/sme.decode | 3 ++ target/arm/tcg/translate-sme.c | 3 ++ 4 files changed, 67 insertions(+) diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sve2_fcvtnt_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +void HELPER(sme2_fcvt_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + ARMVectorReg scratch[4]; + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint32_t *n = vn; + uint8_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + size_t stride = sizeof(ARMVectorReg) / 4; + + if (vectors_overlap(vd, 1, vn, 4)) { + n = memcpy(scratch, vn, sizeof(scratch)); + } + + for (size_t i = 0; i < nelem; i++) { + for (size_t j = 0; j < 4; j++) { + d[H1(i + nelem * j)] = fcvt_f32_to_fp8(n[H4(i) + stride * j], + output_fmt, ctx.scale, + osc, &ctx.stat); + } + } + + fp8_cvt_finish(env, &ctx); +} + +void HELPER(sme2_fcvtn_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) +{ + FP8Context ctx = fp8_dst_start(env, desc, false); + fcvt_fp8_output_fn *output_fmt = fcvt_fp8_output_fmt[ctx.f8fmt]; + uint32_t *n0 = vn; + uint32_t *n1 = vn + sizeof(ARMVectorReg); + uint32_t *n2 = vn + sizeof(ARMVectorReg) * 2; + uint32_t *n3 = vn + sizeof(ARMVectorReg) * 3; + uint8_t *d = vd; + bool osc = FIELD_EX64(env->vfp.fpmr, FPMR, OSC); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + + for (size_t i = 0; i < nelem; ++i) { + float32 e0 = n0[H4(i)]; + float32 e1 = n1[H4(i)]; + float32 e2 = n2[H4(i)]; + float32 e3 = n3[H4(i)]; + + d[H1(4 * i + 0)] = fcvt_f32_to_fp8(e0, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(4 * i + 1)] = fcvt_f32_to_fp8(e1, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(4 * i + 2)] = fcvt_f32_to_fp8(e2, output_fmt, + ctx.scale, osc, &ctx.stat); + d[H1(4 * i + 3)] = fcvt_f32_to_fp8(e3, output_fmt, + ctx.scale, osc, &ctx.stat); + } + + fp8_cvt_finish(env, &ctx); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sve2_fcvtn_bh, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(advsimd_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvtnb_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvtnt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_fcvtn_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ BF2CVTL 11000001 111 00110 111000 ..... ....1 @zz_2x1 FCVT_bh 11000001 001 00100 111000 ....0 ..... @zz_1x2 +FCVT_bs 11000001 001 10100 111000 ...00 ..... @zz_1x4 +FCVTN_bs 11000001 001 10100 111000 ...01 ..... @zz_1x4 + ZIP_4 11000001 esz:2 1 10110 111000 ...00 ... 00 \ &zz_e zd=%zd_ax4 zn=%zn_ax4 ZIP_4 11000001 001 10111 111000 ...00 ... 00 \ diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool trans_FCVT_bh(DisasContext *s, arg_zz_n *a) return true; } +TRANS_FEAT(FCVT_bs, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvt_bs, 0) +TRANS_FEAT(FCVTN_bs, aa64_sme2_f8cvt, do_f8cvt, a, gen_helper_sme2_fcvtn_bs, 0) + static bool do_zipuzp_4(DisasContext *s, arg_zz_e *a, gen_helper_gvec_2 * const fn[5]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-22-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 6 ++++ target/arm/tcg/helper-defs.h | 5 ++++ target/arm/tcg/translate-a64.c | 38 +++++++++++++++++++++++++ target/arm/tcg/vec_helper.c | 52 ++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ EXT_q 0110 1110 00 0 rm:5 0 imm:4 0 rn:5 rd:5 TBL_TBX 0 q:1 00 1110 000 rm:5 0 len:2 tbx:1 00 rn:5 rd:5 +LUTI2_1b 0100 1110 100 rm:5 0 idx:2 100 rn:5 rd:5 &rrx_e esz=0 +LUTI2_1h 0100 1110 110 rm:5 0 idx:3 00 rn:5 rd:5 &rrx_e esz=1 + +LUTI4_1b 0100 1110 010 rm:5 0 idx:1 1000 rn:5 rd:5 &rrx_e esz=0 +LUTI4_2h 0100 1110 010 rm:5 0 idx:2 100 rn:5 rd:5 &rrx_e esz=1 + # Advanced SIMD Permute UZP1 0.00 1110 .. 0 ..... 0 001 10 ..... ..... @qrrr_e diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_luti4_2s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_4h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_4s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_4(gvec_luti2_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_luti2_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_luti4_b, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) +DEF_HELPER_FLAGS_4(gvec_luti4_h, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool trans_TBL_TBX(DisasContext *s, arg_TBL_TBX *a) return true; } +static bool do_lut_1(DisasContext *s, arg_rrx_e *a, gen_helper_gvec_3 *fn) +{ + if (fp_access_check(s)) { + gen_gvec_op3_ool(s, true, a->rd, a->rn, a->rm, a->idx, fn); + } + return true; +} + +TRANS_FEAT(LUTI2_1b, aa64_lut, do_lut_1, a, gen_helper_gvec_luti2_b) +TRANS_FEAT(LUTI2_1h, aa64_lut, do_lut_1, a, gen_helper_gvec_luti2_h) +TRANS_FEAT(LUTI4_1b, aa64_lut, do_lut_1, a, gen_helper_gvec_luti4_b) + +static bool trans_LUTI4_2h(DisasContext *s, arg_rrx_e *a) +{ + if (!dc_isar_feature(aa64_lut, s)) { + return false; + } + if (fp_access_check(s)) { + /* + * (Ab)use preg_tmp to merge two disjoint 128-bit quantities + * into a sequential 256-bit table. + */ + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, vfp.preg_tmp) < 32); + unsigned tmp_ofs = offsetof(CPUARMState, vfp.preg_tmp); + unsigned rn0_ofs = vec_full_reg_offset(s, a->rn); + unsigned rn1_ofs = vec_full_reg_offset(s, (a->rn + 1) % 32); + + tcg_gen_gvec_mov(MO_64, tmp_ofs, rn0_ofs, 16, 16); + tcg_gen_gvec_mov(MO_64, tmp_ofs + 16, rn1_ofs, 16, 16); + + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), tmp_ofs, + vec_full_reg_offset(s, a->rm), + 16, vec_full_reg_size(s), + a->idx, gen_helper_gvec_luti4_h); + } + return true; +} + typedef int simd_permute_idx_fn(int i, int part, int elements); static bool do_simd_permute(DisasContext *s, arg_qrrr_e *a, diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ DO_SME2_LUT(4,4,h, 2) DO_SME2_LUT(4,4,s, 4) #undef DO_SME2_LUT + +void HELPER(gvec_luti2_b)(void *vd, void *vn, void *vm, uint32_t desc) +{ + unsigned part = simd_data(desc); + unsigned vl = simd_oprsz(desc); + unsigned elements = vl / 1; + unsigned ibase = elements * part; + ARMVectorReg scratch; + + do_lut_b(&scratch, vm, vn, elements, ibase, 0, 2, 8, 1); + memcpy(vd, &scratch, vl); + clear_tail(vd, vl, simd_maxsz(desc)); +} + +void HELPER(gvec_luti2_h)(void *vd, void *vn, void *vm, uint32_t desc) +{ + unsigned part = simd_data(desc); + unsigned vl = simd_oprsz(desc); + unsigned elements = vl / 2; + unsigned ibase = elements * part; + ARMVectorReg scratch; + + do_lut_h(&scratch, vm, vn, elements, ibase, 0, 2, 16, 1); + memcpy(vd, &scratch, vl); + clear_tail(vd, vl, simd_maxsz(desc)); +} + +void HELPER(gvec_luti4_b)(void *vd, void *vn, void *vm, uint32_t desc) +{ + unsigned part = simd_data(desc); + unsigned vl = simd_oprsz(desc); + unsigned elements = vl / 1; + unsigned ibase = elements * part; + ARMVectorReg scratch; + + do_lut_b(&scratch, vm, vn, elements, ibase, 0, 4, 8, 1); + memcpy(vd, &scratch, vl); + clear_tail(vd, vl, simd_maxsz(desc)); +} + +void HELPER(gvec_luti4_h)(void *vd, void *vn, void *vm, uint32_t desc) +{ + unsigned part = simd_data(desc); + unsigned vl = simd_oprsz(desc); + unsigned elements = vl / 2; + unsigned ibase = elements * part; + ARMVectorReg scratch; + + do_lut_h(&scratch, vm, vn, elements, ibase, 0, 4, 16, 1); + memcpy(vd, &scratch, vl); + clear_tail(vd, vl, simd_maxsz(desc)); +} -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-23-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 6 +++ target/arm/tcg/sve.decode | 11 +++++- target/arm/tcg/translate-a64.c | 1 + target/arm/tcg/translate-sve.c | 68 ++++++++++++++++++++++++++++++++++ target/arm/tcg/translate.h | 1 + 5 files changed, 86 insertions(+), 1 deletion(-) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ isar_feature_aa64_sme2_or_sve2_f8cvt(const ARMISARegisters *id) return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_f8cvt(id); } +static inline bool +isar_feature_aa64_sme2_or_sve2_lut(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme2_or_sve2(id) && isar_feature_aa64_lut(id); +} + /* * Feature tests for "does this exist in either 32-bit or 64-bit?" */ diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ %dtype_23_13 23:2 13:2 %index3_22_19 22:1 19:2 %index3_22_17 22:1 17:2 +%index3_22_12 22:2 12:1 %index3_19_11 19:2 11:1 %index2_20_11 20:1 11:1 @@ -XXX,XX +XXX,XX @@ RSUBHNT 01000101 .. 1 ..... 011 111 ..... ..... @rd_rn_rm MATCH 01000101 .. 1 ..... 100 ... ..... 0 .... @pd_pg_rn_rm NMATCH 01000101 .. 1 ..... 100 ... ..... 1 .... @pd_pg_rn_rm -### SVE2 Histogram Computation +### SVE2 Histogram Computation and Lookup Table HISTCNT 01000101 .. 1 ..... 110 ... ..... ..... @rd_pg_rn_rm HISTSEG 01000101 .. 1 ..... 101 000 ..... ..... @rd_rn_rm +LUTI2_1b 01000101 index:2 1 rm:5 101100 rn:5 rd:5 &rrx_esz esz=0 +LUTI2_1h 01000101 .. 1 rm:5 101.10 rn:5 rd:5 \ + &rrx_esz esz=1 index=%index3_22_12 + +LUTI4_1b 01000101 index:1 11 rm:5 101001 rn:5 rd:5 &rrx_esz esz=0 +LUTI4_1h 01000101 index:2 1 rm:5 101111 rn:5 rd:5 &rrx_esz esz=1 +LUTI4_2h 01000101 index:2 1 rm:5 101101 rn:5 rd:5 &rrx_esz esz=1 + ## SVE2 floating-point pairwise operations FADDP 01100100 .. 010 00 0 100 ... ..... ..... @rdn_pg_rm diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static void aarch64_tr_init_disas_context(DisasContextBase *dcbase, dc->vl = (EX_TBFLAG_A64(tb_flags, VL) + 1) * 16; dc->svl = (EX_TBFLAG_A64(tb_flags, SVL) + 1) * 16; dc->max_svl = arm_cpu->sme_max_vq * 16; + dc->max_any_vl = MAX(dc->max_svl, arm_cpu->sve_max_vq * 16); dc->pauth_active = EX_TBFLAG_A64(tb_flags, PAUTH_ACTIVE); dc->bt = EX_TBFLAG_A64(tb_flags, BT); dc->btype = EX_TBFLAG_A64(tb_flags, BTYPE); diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(LD1_zcrr_stride, aa64_sme2, gen_ldst_zcrr_c, a, false, true) TRANS_FEAT(LD1_zcri_stride, aa64_sme2, gen_ldst_zcri_c, a, false, true) TRANS_FEAT(ST1_zcrr_stride, aa64_sme2, gen_ldst_zcrr_c, a, true, true) TRANS_FEAT(ST1_zcri_stride, aa64_sme2, gen_ldst_zcri_c, a, true, true) + +TRANS_FEAT_STREAMING_IF(LUTI2_1b, aa64_sme2_or_sve2_lut, aa64_sme2, + gen_gvec_ool_zzz, gen_helper_gvec_luti2_b, + a->rd, a->rn, a->rm, a->index) +TRANS_FEAT_STREAMING_IF(LUTI2_1h, aa64_sme2_or_sve2_lut, aa64_sme2, + gen_gvec_ool_zzz, gen_helper_gvec_luti2_h, + a->rd, a->rn, a->rm, a->index) +TRANS_FEAT_STREAMING_IF(LUTI4_1b, aa64_sme2_or_sve2_lut, aa64_sme2, + gen_gvec_ool_zzz, gen_helper_gvec_luti4_b, + a->rd, a->rn, a->rm, a->index) + +static bool trans_LUTI4_1h(DisasContext *s, arg_LUTI4_1h *a) +{ + if (!dc_isar_feature(aa64_sme2_or_sve2_lut, s)) { + return false; + } + s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s); + + /* + * The MaxImplementedAnyVL check happens in the decode pseudocode, + * before the Check*SVEEnabled check in the operation pseudocode. + */ + if (s->max_any_vl < 32) { + unallocated_encoding(s); + } else if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + + /* Then there's a second check against CurrentVL. */ + if (vsz < 32) { + unallocated_encoding(s); + } else { + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + vsz, vsz, a->index, + gen_helper_gvec_luti4_h); + } + } + return true; +} + +static bool trans_LUTI4_2h(DisasContext *s, arg_LUTI4_2h *a) +{ + if (!dc_isar_feature(aa64_sme2_or_sve2_lut, s)) { + return false; + } + s->is_nonstreaming = !dc_isar_feature(aa64_sme2, s); + + if (sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + /* + * (Ab)use preg_tmp to merge two disjoint 128-bit quantities + * into a sequential 256-bit table. + */ + QEMU_BUILD_BUG_ON(sizeof_field(CPUARMState, vfp.preg_tmp) < 32); + unsigned tmp_ofs = offsetof(CPUARMState, vfp.preg_tmp); + unsigned rn0_ofs = vec_full_reg_offset(s, a->rn); + unsigned rn1_ofs = vec_full_reg_offset(s, (a->rn + 1) % 32); + + tcg_gen_gvec_mov(MO_64, tmp_ofs, rn0_ofs, 16, 16); + tcg_gen_gvec_mov(MO_64, tmp_ofs + 16, rn1_ofs, 16, 16); + + tcg_gen_gvec_3_ool(vec_full_reg_offset(s, a->rd), tmp_ofs, + vec_full_reg_offset(s, a->rm), + vsz, vsz, a->index, gen_helper_gvec_luti4_h); + } + return true; +} diff --git a/target/arm/tcg/translate.h b/target/arm/tcg/translate.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate.h +++ b/target/arm/tcg/translate.h @@ -XXX,XX +XXX,XX @@ typedef struct DisasContext { int vl; /* current vector length in bytes */ int svl; /* current streaming vector length in bytes */ int max_svl; /* maximum implemented streaming vector length */ + int max_any_vl; /* maximum implemented vector length */ bool vfp_enabled; /* FP enabled via FPSCR.EN */ int vec_len; int vec_stride; -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-24-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_LSE (Large System Extensions) - FEAT_LSE2 (Large System Extensions v2) - FEAT_LSE128 (128-bit Atomics) +- FEAT_LUT (Lookup table instructions with 2-bit and 4-bit indices) - FEAT_LVA (Large Virtual Address space) - FEAT_MEC (Memory Encryption Contexts) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) GET_FEATURE_ID(aa64_lse128, ARM_HWCAP2_A64_LSE128); GET_FEATURE_ID(aa64_faminmax, ARM_HWCAP2_A64_FAMINMAX); GET_FEATURE_ID(aa64_fpmr, ARM_HWCAP2_A64_FPMR); + GET_FEATURE_ID(aa64_lut, ARM_HWCAP2_A64_LUT); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64ISAR2, BC, 1); /* FEAT_HBC */ t = FIELD_DP64(t, ID_AA64ISAR2, WFXT, 2); /* FEAT_WFxT */ t = FIELD_DP64(t, ID_AA64ISAR2, CSSC, 2); /* FEAT_CSSC, FEAT_CMPBR */ + t = FIELD_DP64(t, ID_AA64ISAR2, LUT, 1); /* FEAT_LUT */ t = FIELD_DP64(t, ID_AA64ISAR2, ATS1A, 1); /* FEAT_ATS1A */ SET_IDREG(isar, ID_AA64ISAR2, t); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-25-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 3 +++ target/arm/tcg/cpu64.c | 6 ++++++ 3 files changed, 10 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_FHM (Floating-point half-precision multiplication instructions) - FEAT_FP (Floating Point extensions) - FEAT_FP16 (Half-precision floating-point data processing) +- FEAT_FP8 (FP8 convert instructions) - FEAT_FPAC (Faulting on AUT* instructions) - FEAT_FPACCOMBINE (Faulting on combined pointer authentication instructions) - FEAT_FPACC_SPEC (Speculative behavior of combined pointer authentication instructions) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) GET_FEATURE_ID(aa64_faminmax, ARM_HWCAP2_A64_FAMINMAX); GET_FEATURE_ID(aa64_fpmr, ARM_HWCAP2_A64_FPMR); GET_FEATURE_ID(aa64_lut, ARM_HWCAP2_A64_LUT); + GET_FEATURE_ID(aa64_f8cvt, ARM_HWCAP2_A64_F8CVT | + ARM_HWCAP2_A64_F8E4M3 | + ARM_HWCAP2_A64_F8E5M2); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ SET_IDREG(isar, ID_AA64SMFR0, t); + t = GET_IDREG(isar, ID_AA64FPFR0); + t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* FEAT_FP8 */ + SET_IDREG(isar, ID_AA64FPFR0, t); + /* Replicate the same data to the 32-bit id registers. */ aa32_max_features(cpu); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-26-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ FIELD(ID_AA64ZFR0, F16MM, 48, 4) FIELD(ID_AA64ZFR0, F32MM, 52, 4) FIELD(ID_AA64ZFR0, F64MM, 56, 4) +FIELD(ID_AA64SMFR0, SMOP4, 0, 1) +FIELD(ID_AA64SMFR0, STMOP, 16, 1) +FIELD(ID_AA64SMFR0, SFEXPA, 23, 1) +FIELD(ID_AA64SMFR0, AES, 24, 1) +FIELD(ID_AA64SMFR0, SBITPERM, 25, 1) +FIELD(ID_AA64SMFR0, SF8DP2, 28, 1) +FIELD(ID_AA64SMFR0, SF8DP4, 29, 1) +FIELD(ID_AA64SMFR0, SF8FMA, 30, 1) FIELD(ID_AA64SMFR0, F32F32, 32, 1) FIELD(ID_AA64SMFR0, BI32I32, 33, 1) FIELD(ID_AA64SMFR0, B16F32, 34, 1) FIELD(ID_AA64SMFR0, F16F32, 35, 1) FIELD(ID_AA64SMFR0, I8I32, 36, 4) +FIELD(ID_AA64SMFR0, F8F32, 40, 1) +FIELD(ID_AA64SMFR0, F8F16, 41, 1) FIELD(ID_AA64SMFR0, F16F16, 42, 1) FIELD(ID_AA64SMFR0, B16B16, 43, 1) FIELD(ID_AA64SMFR0, I16I32, 44, 4) FIELD(ID_AA64SMFR0, F64F64, 48, 1) FIELD(ID_AA64SMFR0, I16I64, 52, 4) FIELD(ID_AA64SMFR0, SMEVER, 56, 4) +FIELD(ID_AA64SMFR0, LUTv2, 60, 1) FIELD(ID_AA64SMFR0, FA64, 63, 1) FIELD(ID_AA64FPFR0, F8E5M2, 0, 1) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-27-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sme.decode | 2 ++ target/arm/tcg/translate-sme.c | 18 ++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme_fa64(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64SMFR0, FA64); } +static inline bool isar_feature_aa64_sme_lutv2(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, LUTv2); +} + static inline bool isar_feature_aa64_sme2(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SMEVER) != 0; diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ MOVAZ_zt4 11000000 11 00011 0 v:1 .. 00110 za:3 zr:3 00 \ MOVT_rzt 1100 0000 0100 1100 0 off:3 00 11111 rt:5 MOVT_ztr 1100 0000 0100 1110 0 off:3 00 11111 rt:5 +MOVT_ztz 1100 0000 0100 1111 00 off:2 00 11111 rt:5 + ### SME Memory &ldst esz rs pg rn rm za off v:bool st:bool diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ static bool do_movt(DisasContext *s, arg_MOVT_rzt *a, TRANS_FEAT(MOVT_rzt, aa64_sme2, do_movt, a, tcg_gen_ld_i64) TRANS_FEAT(MOVT_ztr, aa64_sme2, do_movt, a, tcg_gen_st_i64) +static bool trans_MOVT_ztz(DisasContext *s, arg_MOVT_ztz *a) +{ + if (!dc_isar_feature(aa64_sme_lutv2, s)) { + return false; + } + if (sme_sm_enabled_check(s) && sme2_zt0_enabled_check(s)) { + int svl = streaming_vec_reg_size(s); + int tsize = MIN(svl, 64); + int offset = (a->off % (64 / tsize)) * tsize; + + tcg_gen_gvec_mov(MO_64, + offsetof(CPUARMState, za_state.zt0) + offset, + vec_full_reg_offset(s, a->rt), tsize, + offset ? tsize : 64); + } + return true; +} + static bool trans_LDST1(DisasContext *s, arg_LDST1 *a) { typedef void GenLdSt1(TCGv_env, TCGv_ptr, TCGv_ptr, TCGv, TCGv_i64); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-28-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/helper-defs.h | 1 + target/arm/tcg/sme.decode | 6 ++++++ target/arm/tcg/translate-sme.c | 6 ++++++ target/arm/tcg/vec_helper.c | 14 ++++++++++++++ 5 files changed, 32 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sme2_f8cvt(const ARMISARegisters *id) return isar_feature_aa64_sme2(id) && isar_feature_aa64_f8cvt(id); } +static inline bool isar_feature_aa64_sme2p1_lutv2(const ARMISARegisters *id) +{ + return isar_feature_aa64_sme2p1(id) && isar_feature_aa64_sme_lutv2(id); +} + static inline bool isar_feature_aa64_sve_i8mm(const ARMISARegisters *id) { return isar_feature_aa64_sve(id) && isar_feature_aa64_sme_sve_i8mm(id); diff --git a/target/arm/tcg/helper-defs.h b/target/arm/tcg/helper-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-defs.h +++ b/target/arm/tcg/helper-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_luti4_2b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_2h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_2s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_4(sme2_luti4_4b, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_4h, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_luti4_4s, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) diff --git a/target/arm/tcg/sme.decode b/target/arm/tcg/sme.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sme.decode +++ b/target/arm/tcg/sme.decode @@ -XXX,XX +XXX,XX @@ LUTI4_c_2s 1100 0000 1000 101 idx:2 1 10 00 zn:5 .... 0 &lut zd=%zd_ax2 LUTI4_c_4h 1100 0000 1000 101 idx:1 10 01 00 zn:5 ... 00 &lut zd=%zd_ax4 LUTI4_c_4s 1100 0000 1000 101 idx:1 10 10 00 zn:5 ... 00 &lut zd=%zd_ax4 +LUTI4_c_4b 1100 0000 1000 101 1 00 00 00 ....0 ...00 \ + &lut zd=%zd_ax4 zn=%zn_ax2 idx=0 + # LUTI4, strided (must check zd alignment) LUTI4_s_2b 1100 0000 1001 101 idx:2 1 00 00 zn:5 zd:5 &lut LUTI4_s_2h 1100 0000 1001 101 idx:2 1 01 00 zn:5 zd:5 &lut LUTI4_s_4h 1100 0000 1001 101 idx:1 10 01 00 zn:5 zd:5 &lut + +LUTI4_s_4b 1100 0000 1001 101 1 00 00 00 ....0 zd:5 \ + &lut zn=%zn_ax2 idx=0 diff --git a/target/arm/tcg/translate-sme.c b/target/arm/tcg/translate-sme.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sme.c +++ b/target/arm/tcg/translate-sme.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(LUTI4_c_2s, aa64_sme2, do_lut, a, gen_helper_sme2_luti4_2s, false) TRANS_FEAT(LUTI4_c_4h, aa64_sme2, do_lut, a, gen_helper_sme2_luti4_4h, false) TRANS_FEAT(LUTI4_c_4s, aa64_sme2, do_lut, a, gen_helper_sme2_luti4_4s, false) +TRANS_FEAT(LUTI4_c_4b, aa64_sme_lutv2, do_lut, a, + gen_helper_sme2_luti4_4b, false) + static bool do_lut_s4(DisasContext *s, arg_lut *a, gen_helper_gvec_2_ptr *fn) { return !(a->zd & 0b01100) && do_lut(s, a, fn, true); @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(LUTI4_s_2b, aa64_sme2p1, do_lut_s8, a, gen_helper_sme2_luti4_2b) TRANS_FEAT(LUTI4_s_2h, aa64_sme2p1, do_lut_s8, a, gen_helper_sme2_luti4_2h) TRANS_FEAT(LUTI4_s_4h, aa64_sme2p1, do_lut_s4, a, gen_helper_sme2_luti4_4h) + +TRANS_FEAT(LUTI4_s_4b, aa64_sme2p1_lutv2, do_lut_s4, a, + gen_helper_sme2_luti4_4b) diff --git a/target/arm/tcg/vec_helper.c b/target/arm/tcg/vec_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/vec_helper.c +++ b/target/arm/tcg/vec_helper.c @@ -XXX,XX +XXX,XX @@ DO_SME2_LUT(4,4,s, 4) #undef DO_SME2_LUT +void helper_sme2_luti4_4b(void *zd, void *zn, CPUARMState *env, uint32_t desc) +{ + unsigned vl = simd_oprsz(desc); + unsigned strided = extract32(desc, SIMD_DATA_SHIFT, 1); + unsigned dstride = !strided ? 1 : 4; + uint64_t indexes[ARM_MAX_VQ * 4]; + + memcpy(&indexes, zn, vl); + memcpy((void *)&indexes + vl, zn + sizeof(ARMVectorReg), vl); + + do_lut_b(zd, indexes, (void *)env->za_state.zt0, vl, 0, + dstride * sizeof(ARMVectorReg), 4, 32, 4); +} + void HELPER(gvec_luti2_b)(void *vd, void *vn, void *vm, uint32_t desc) { unsigned part = simd_data(desc); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-29-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_F16F16 (Non-widening half-precision FP16 arithmetic for SME2) - FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) +- FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) - FEAT_SVE (Scalable Vector Extension) - FEAT_SVE_AES (Scalable Vector AES instructions) - FEAT_SVE_B16B16 (Non-widening BFloat16 arithmetic for SVE2) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) GET_FEATURE_ID(aa64_faminmax, ARM_HWCAP2_A64_FAMINMAX); GET_FEATURE_ID(aa64_fpmr, ARM_HWCAP2_A64_FPMR); GET_FEATURE_ID(aa64_lut, ARM_HWCAP2_A64_LUT); + GET_FEATURE_ID(aa64_sme2p1_lutv2, ARM_HWCAP2_A64_SME_LUTV2); GET_FEATURE_ID(aa64_f8cvt, ARM_HWCAP2_A64_F8CVT | ARM_HWCAP2_A64_F8E4M3 | ARM_HWCAP2_A64_F8E5M2); diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = FIELD_DP64(t, ID_AA64SMFR0, F64F64, 1); /* FEAT_SME_F64F64 */ t = FIELD_DP64(t, ID_AA64SMFR0, I16I64, 0xf); /* FEAT_SME_I16I64 */ t = FIELD_DP64(t, ID_AA64SMFR0, SMEVER, 2); /* FEAT_SME2p1 */ + t = FIELD_DP64(t, ID_AA64SMFR0, LUTv2, 1); /* FEAT_SME_LUTv2 */ t = FIELD_DP64(t, ID_AA64SMFR0, FA64, 1); /* FEAT_SME_FA64 */ SET_IDREG(isar, ID_AA64SMFR0, t); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-30-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++ target/arm/tcg/a64.decode | 8 +++ target/arm/tcg/fp8_helper.c | 106 +++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 3 + target/arm/tcg/translate-a64.c | 16 +++++ 5 files changed, 138 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8cvt(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8CVT); } +static inline bool isar_feature_aa64_f8fma(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8FMA); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ %esz_hsd 22:2 !function=xor_2 %hl 11:1 21:1 %hlm 11:1 20:2 +%hlm4 11:1 19:3 &r rn &rrr rd rn rm @@ -XXX,XX +XXX,XX @@ &rri_e rd rn imm esz &rrr_e rd rn rm esz &rrx_e rd rn rm idx esz +&rxx rd rn rm idxn idxm &rrrr_e rd rn rm ra esz &qrr_e q rd rn esz &qrri_e q rd rn imm esz @@ -XXX,XX +XXX,XX @@ FSCALE 0.10 1110 1.1 ..... 11111 1 ..... ..... @qrrr_sd FCVTN_bh 0.00 1110 010 ..... 11110 1 ..... ..... @qrrr_h FCVTN_bs 0.00 1110 000 ..... 11110 1 ..... ..... @qrrr_h +FMLAL_hb_v 0 idxn:1 00 1110 110 rm:5 11111 1 rn:5 rd:5 \ + &rxx idxm=0 + ### Advanced SIMD scalar x indexed element FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h @@ -XXX,XX +XXX,XX @@ SQDMLAL_vi 0.00 1111 10 . ..... 0011 . 0 ..... ..... @qrrx_s SQDMLSL_vi 0.00 1111 01 .. .... 0111 . 0 ..... ..... @qrrx_h SQDMLSL_vi 0.00 1111 10 . ..... 0111 . 0 ..... ..... @qrrx_s +FMLAL_hb_vi 0 idxn:1 00 1111 11 ... rm:3 0000 . 0 rn:5 rd:5 \ + &rxx idxm=%hlm4 + # Floating-point conditional select FCSEL 0001 1110 .. 1 rm:5 cond:4 11 rn:5 rd:5 esz=%esz_hsd diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(sme2_fcvtn_bs)(void *vd, void *vn, CPUARMState *env, uint32_t desc) fp8_cvt_finish(env, &ctx); } + +typedef struct FP8MulContext { + float_status stat; + fp8_input_fn *fmt1; + fp8_input_fn *fmt2; + int scale; +} FP8MulContext; + +static FP8MulContext fp8_mul_start(CPUARMState *env, int scale_mask) +{ + uint64_t fpmr = env->vfp.fpmr; + + FP8MulContext ret = { + .stat = env->vfp.fp_status[FPST_A64], + .fmt1 = fp8_input_fmt[FIELD_EX64(fpmr, FPMR, F8S1)], + .fmt2 = fp8_input_fmt[FIELD_EX64(fpmr, FPMR, F8S2)], + .scale = -(FIELD_EX64(fpmr, FPMR, LSCALE) & scale_mask), + }; + + set_flush_to_zero(0, &ret.stat); + set_flush_inputs_to_zero(0, &ret.stat); + set_default_nan_mode(true, &ret.stat); + set_float_rounding_mode(FIELD_EX64(fpmr, FPMR, OSM) + ? float_round_nearest_even_max + : float_round_nearest_even, &ret.stat); + + /* + * FP8 multiplies don't update any of the FPSR exception flags, + * so we do not need an fp8_mul_finish() to propagate status + * changes back from ret.stat into env->vfp.fp_status[]. + */ + return ret; +} + +static FloatParts64 f8dot(uint64_t a, uint64_t b, int n, FP8MulContext *ctx) +{ + /* + * Because of default_nan_mode, NaNs need no special handling. + * We'll simply get the default NaN out at the end of the sequence. + */ + FloatParts64 p0 = ctx->fmt1(a & 0xff, &ctx->stat); + FloatParts64 p1 = ctx->fmt2(b & 0xff, &ctx->stat); + FloatParts64 pr = parts64_mul(&p0, &p1, &ctx->stat); + + for (int i = 1; i < n; ++i) { + p0 = ctx->fmt1(extract64(a, i * 8, 8), &ctx->stat); + p1 = ctx->fmt2(extract64(b, i * 8, 8), &ctx->stat); + pr = parts64_muladd(&p0, &p1, &pr, 0, &ctx->stat); + } + return parts64_scalbn(&pr, ctx->scale, &ctx->stat); +} + +static float16 f8dotadd_h(uint64_t a, uint64_t b, int n, float16 c, + FP8MulContext *ctx) +{ + FloatParts64 p0 = f8dot(a, b, n, ctx); + FloatParts64 p1 = float16_unpack_canonical(c, &ctx->stat); + + p0 = parts64_addsub(&p0, &p1, &ctx->stat, false); + return float16_round_pack_canonical(&p0, &ctx->stat); +} + +void HELPER(gvec_fmla_hb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + bool high = extract32(desc, SIMD_DATA_SHIFT, 1); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + uint8_t *n = vn; + uint8_t *m = vm; + float16 *d = vd; + + for (size_t i = 0; i < nelem; i++) { + uint8_t e0 = n[H1(2 * i + high)]; + uint8_t e1 = m[H1(2 * i + high)]; + + d[H2(i)] = f8dotadd_h(e0, e1, 1, d[H2(i)], &ctx); + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fmla_idx_hb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + bool idx_n = extract32(desc, SIMD_DATA_SHIFT, 1); + size_t idx_m = extract32(desc, SIMD_DATA_SHIFT + 2, 4); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + uint8_t *n = vn; + uint8_t *m = vm; + float16 *d = vd; + size_t i = 0; + + do { + uint8_t e1 = m[2 * i + H1(idx_m)]; + do { + uint8_t e0 = n[H1(2 * i + idx_n)]; + d[H2(i)] = f8dotadd_h(e0, e1, 1, d[H2(i)], &ctx); + } while (++i % 8 != 0); + } while (i < nelem); + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sve2_fcvtnb_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sve2_fcvtnt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_fcvt_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_4(sme2_fcvtn_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fmla_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmla_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(FMLSL_vi, aa64_fhm, do_fmlal_idx, a, true, false) TRANS_FEAT(FMLAL2_vi, aa64_fhm, do_fmlal_idx, a, false, true) TRANS_FEAT(FMLSL2_vi, aa64_fhm, do_fmlal_idx, a, true, true) +static bool do_fmla_fp8(DisasContext *s, arg_rxx *a, + gen_helper_gvec_3_ptr *fn) +{ + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, 16, vec_full_reg_size(s), + a->idxn | (a->idxm << 2), fn); + } + return true; +} + +TRANS_FEAT(FMLAL_hb_v, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_hb) +TRANS_FEAT(FMLAL_hb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) + static bool do_int3_vector_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3 * const fns[2]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-31-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sve.decode | 7 +++++++ target/arm/tcg/translate-sve.c | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sve_b16b16(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64ZFR0, B16B16); } +static inline bool isar_feature_aa64_ssve_f8fma(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SF8FMA); +} + static inline bool isar_feature_aa64_sme_b16b16(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, B16B16); diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ %imm9_16_10 16:s6 10:3 %size_23 23:2 %dtype_23_13 23:2 13:2 +%index4_19_10 19:2 10:2 %index3_22_19 22:1 19:2 %index3_22_17 22:1 17:2 %index3_22_12 22:2 12:1 @@ -XXX,XX +XXX,XX @@ &rri rd rn imm &rr_dbm rd rn dbm &rrri rd rn rm imm +&rxx rd rn rm idxn idxm &rri_esz rd rn imm esz &rrri_esz rd rn rm imm esz &rrr_esz rd rn rm esz @@ -XXX,XX +XXX,XX @@ BFMLALT_zzzw 01100100 11 1 ..... 10 0 00 1 ..... ..... @rda_rn_rm_ex esz=2 BFMLSLB_zzzw 01100100 11 1 ..... 10 1 00 0 ..... ..... @rda_rn_rm_ex esz=2 BFMLSLT_zzzw 01100100 11 1 ..... 10 1 00 1 ..... ..... @rda_rn_rm_ex esz=2 +FMLAL_hb 01100100 10 1 rm:5 100 idxn:1 10 rn:5 rd:5 &rxx idxm=0 + ### SVE2 floating-point dot-product FDOT_zzzz 01100100 00 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 BFDOT_zzzz 01100100 01 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 @@ -XXX,XX +XXX,XX @@ BFMLALT_zzxw 01100100 11 1 ..... 0100.1 ..... ..... @rrxr_3a esz=2 BFMLSLB_zzxw 01100100 11 1 ..... 0110.0 ..... ..... @rrxr_3a esz=2 BFMLSLT_zzxw 01100100 11 1 ..... 0110.1 ..... ..... @rrxr_3a esz=2 +FMLAL_idx_hb 01100100 idxn:1 01 .. rm:3 0101 .. rn:5 rd:5 \ + &rxx idxm=%index4_19_10 + ### SVE2 floating-point dot-product (indexed) FDOT_zzxz 01100100 00 1 ..... 010000 ..... ..... @rrxr_2 esz=2 diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool trans_LUTI4_2h(DisasContext *s, arg_LUTI4_2h *a) } return true; } + +static bool do_fmla_fp8(DisasContext *s, arg_rxx *a, gen_helper_gvec_3_ptr *fn) +{ + bool fp8fma = dc_isar_feature(aa64_f8fma, s); + bool ssve_fp8fma = dc_isar_feature(aa64_ssve_f8fma, s); + bool ok = false; + + /* Feature detection and enabling are complex here. */ + if (!(ssve_fp8fma || (fp8fma && dc_isar_feature(aa64_sve2, s)))) { + return false; + } + if (fpmr_access_check(s)) { + if (fp8fma) { + s->is_nonstreaming = !ssve_fp8fma; + ok = sve_access_check(s); + } else { + ok = sme_sm_enabled_check(s); + } + } + + if (ok) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, vsz, vsz, + a->idxn | (a->idxm << 2), fn); + } + return true; +} + +TRANS(FMLAL_hb, do_fmla_fp8, a, gen_helper_gvec_fmla_hb) +TRANS(FMLAL_idx_hb, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-32-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/a64.decode | 7 ++++ target/arm/tcg/fp8_helper.c | 55 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 3 ++ target/arm/tcg/translate-a64.c | 3 ++ 4 files changed, 68 insertions(+) diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FCVTN_bs 0.00 1110 000 ..... 11110 1 ..... ..... @qrrr_h FMLAL_hb_v 0 idxn:1 00 1110 110 rm:5 11111 1 rn:5 rd:5 \ &rxx idxm=0 +%fmlall_idxn 30:1 22:1 +FMLALL_sb_v 0.00 1110 0.0 rm:5 110001 rn:5 rd:5 \ + &rxx idxm=0 idxn=%fmlall_idxn + ### Advanced SIMD scalar x indexed element FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h @@ -XXX,XX +XXX,XX @@ SQDMLSL_vi 0.00 1111 10 . ..... 0111 . 0 ..... ..... @qrrx_s FMLAL_hb_vi 0 idxn:1 00 1111 11 ... rm:3 0000 . 0 rn:5 rd:5 \ &rxx idxm=%hlm4 +FMLALL_sb_vi 0 . 10 1111 0 . ... rm:3 1000 . 0 rn:5 rd:5 \ + &rxx idxm=%hlm4 idxn=%fmlall_idxn + # Floating-point conditional select FCSEL 0001 1110 .. 1 rm:5 cond:4 11 rn:5 rd:5 esz=%esz_hsd diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ static float16 f8dotadd_h(uint64_t a, uint64_t b, int n, float16 c, return float16_round_pack_canonical(&p0, &ctx->stat); } +static float32 f8dotadd_s(uint64_t a, uint64_t b, int n, float32 c, + FP8MulContext *ctx) +{ + FloatParts64 p0 = f8dot(a, b, n, ctx); + FloatParts64 p1 = float32_unpack_canonical(c, &ctx->stat); + + p0 = parts64_addsub(&p0, &p1, &ctx->stat, false); + return float32_round_pack_canonical(&p0, &ctx->stat); +} + void HELPER(gvec_fmla_hb)(void *vd, void *vn, void *vm, CPUARMState *env, uint32_t desc) { @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fmla_idx_hb)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(gvec_fmla_sb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + size_t idx = extract32(desc, SIMD_DATA_SHIFT, 2); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + uint8_t *n = vn; + uint8_t *m = vm; + float32 *d = vd; + + for (size_t i = 0; i < nelem; i++) { + uint8_t e0 = n[H1(4 * i + idx)]; + uint8_t e1 = m[H1(4 * i + idx)]; + + d[H4(i)] = f8dotadd_s(e0, e1, 1, d[H4(i)], &ctx); + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fmla_idx_sb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + size_t idx_n = extract32(desc, SIMD_DATA_SHIFT, 2); + size_t idx_m = extract32(desc, SIMD_DATA_SHIFT + 2, 4); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + uint8_t *n = vn; + uint8_t *m = vm; + float32 *d = vd; + size_t i = 0; + + do { + uint8_t e1 = m[4 * i + H1(idx_m)]; + do { + uint8_t e0 = n[H1(4 * i + idx_n)]; + d[H4(i)] = f8dotadd_s(e0, e1, 1, d[H4(i)], &ctx); + } while (++i % 4 != 0); + } while (i < nelem); + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_4(sme2_fcvtn_bs, TCG_CALL_NO_RWG, void, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fmla_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fmla_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fmla_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmla_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_fmla_fp8(DisasContext *s, arg_rxx *a, TRANS_FEAT(FMLAL_hb_v, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_hb) TRANS_FEAT(FMLAL_hb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) +TRANS_FEAT(FMLALL_sb_v, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_sb) +TRANS_FEAT(FMLALL_sb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_sb) + static bool do_int3_vector_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3 * const fns[2]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-33-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/tcg/sve.decode | 5 +++++ target/arm/tcg/translate-sve.c | 3 +++ 2 files changed, 8 insertions(+) diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ BFMLSLT_zzzw 01100100 11 1 ..... 10 1 00 1 ..... ..... @rda_rn_rm_ex esz=2 FMLAL_hb 01100100 10 1 rm:5 100 idxn:1 10 rn:5 rd:5 &rxx idxm=0 +FMLALL_sb 01100100 00 1 rm:5 10 idxn:2 10 rn:5 rd:5 &rxx idxm=0 + ### SVE2 floating-point dot-product FDOT_zzzz 01100100 00 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 BFDOT_zzzz 01100100 01 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 @@ -XXX,XX +XXX,XX @@ BFMLSLT_zzxw 01100100 11 1 ..... 0110.1 ..... ..... @rrxr_3a esz=2 FMLAL_idx_hb 01100100 idxn:1 01 .. rm:3 0101 .. rn:5 rd:5 \ &rxx idxm=%index4_19_10 +FMLALL_idx_sb 01100100 idxn:2 1 .. rm:3 1100 .. rn:5 rd:5 \ + &rxx idxm=%index4_19_10 + ### SVE2 floating-point dot-product (indexed) FDOT_zzxz 01100100 00 1 ..... 010000 ..... ..... @rrxr_2 esz=2 diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool do_fmla_fp8(DisasContext *s, arg_rxx *a, gen_helper_gvec_3_ptr *fn) TRANS(FMLAL_hb, do_fmla_fp8, a, gen_helper_gvec_fmla_hb) TRANS(FMLAL_idx_hb, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) + +TRANS(FMLALL_sb, do_fmla_fp8, a, gen_helper_gvec_fmla_sb) +TRANS(FMLALL_idx_sb, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_sb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-34-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 2 ++ linux-user/aarch64/elfload.c | 2 ++ target/arm/tcg/cpu64.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_FP (Floating Point extensions) - FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP8 (FP8 convert instructions) +- FEAT_FP8FMA (FP8 multiply-accumulate to half-precision and single-precision instructions) - FEAT_FPAC (Faulting on AUT* instructions) - FEAT_FPACCOMBINE (Faulting on combined pointer authentication instructions) - FEAT_FPACC_SPEC (Speculative behavior of combined pointer authentication instructions) @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) +- FEAT_SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) - FEAT_SVE (Scalable Vector Extension) - FEAT_SVE_AES (Scalable Vector AES instructions) - FEAT_SVE_B16B16 (Non-widening BFloat16 arithmetic for SVE2) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) GET_FEATURE_ID(aa64_f8cvt, ARM_HWCAP2_A64_F8CVT | ARM_HWCAP2_A64_F8E4M3 | ARM_HWCAP2_A64_F8E5M2); + GET_FEATURE_ID(aa64_f8fma, ARM_HWCAP2_A64_F8FMA); + GET_FEATURE_ID(aa64_ssve_f8fma, ARM_HWCAP2_A64_SME_SF8FMA); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) SET_IDREG(isar, ID_AA64DFR0, t); t = GET_IDREG(isar, ID_AA64SMFR0); + t = FIELD_DP64(t, ID_AA64SMFR0, SF8FMA, 1); /* FEAT_SSVE_FP8FMA */ t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ t = FIELD_DP64(t, ID_AA64SMFR0, BI32I32, 1); /* FEAT_SME2 */ t = FIELD_DP64(t, ID_AA64SMFR0, B16F32, 1); /* FEAT_SME */ @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64FPFR0); t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* FEAT_FP8FMA */ t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* FEAT_FP8 */ SET_IDREG(isar, ID_AA64FPFR0, t); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-35-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/a64.decode | 4 ++++ target/arm/tcg/fp8_helper.c | 39 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 3 +++ target/arm/tcg/translate-a64.c | 30 ++++++++++++++++++++++++ 5 files changed, 81 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8fma(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8FMA); } +static inline bool isar_feature_aa64_f8dp4(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8DP4); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMLAL_hb_v 0 idxn:1 00 1110 110 rm:5 11111 1 rn:5 rd:5 \ FMLALL_sb_v 0.00 1110 0.0 rm:5 110001 rn:5 rd:5 \ &rxx idxm=0 idxn=%fmlall_idxn +FDOT_sb_v 0.00 1110 000 ..... 11111 1 ..... ..... @qrrr_s + ### Advanced SIMD scalar x indexed element FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h @@ -XXX,XX +XXX,XX @@ FMLAL_hb_vi 0 idxn:1 00 1111 11 ... rm:3 0000 . 0 rn:5 rd:5 \ FMLALL_sb_vi 0 . 10 1111 0 . ... rm:3 1000 . 0 rn:5 rd:5 \ &rxx idxm=%hlm4 idxn=%fmlall_idxn +FDOT_sb_vi 0.00 1111 00 . ..... 0000 . 0 ..... ..... @qrrx_s + # Floating-point conditional select FCSEL 0001 1110 .. 1 rm:5 cond:4 11 rn:5 rd:5 esz=%esz_hsd diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fmla_idx_sb)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(gvec_fdot_sb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + uint32_t *n = vn; + uint32_t *m = vm; + float32 *d = vd; + + for (size_t i = 0; i < nelem; i++) { + d[i] = f8dotadd_s(n[i], m[i], 4, d[i], &ctx); + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fdot_idx_sb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + size_t idx = simd_data(desc); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 4; + uint32_t *n = vn; + uint32_t *m = vm; + float32 *d = vd; + size_t i = 0; + + do { + uint32_t e1 = m[i + H4(idx)]; + do { + d[i] = f8dotadd_s(n[i], e1, 4, d[i], &ctx); + } while (++i % 4 != 0); + } while (i < nelem); + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(gvec_fmla_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_5(gvec_fmla_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fmla_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fdot_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fdot_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ TRANS_FEAT(FMLAL_hb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) TRANS_FEAT(FMLALL_sb_v, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_sb) TRANS_FEAT(FMLALL_sb_vi, aa64_f8fma, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_sb) +static bool do_f8dot(DisasContext *s, arg_qrrr_e *a, + gen_helper_gvec_3_ptr *fn) +{ + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, a->q ? 16 : 8, vec_full_reg_size(s), + 0, fn); + } + return true; +} + +TRANS_FEAT(FDOT_sb_v, aa64_f8dp4, do_f8dot, a, gen_helper_gvec_fdot_sb) + +static bool do_f8dot_idx(DisasContext *s, arg_qrrx_e *a, + gen_helper_gvec_3_ptr *fn) +{ + if (fpmr_access_check(s) && fp_access_check(s)) { + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, a->q ? 16 : 8, vec_full_reg_size(s), + a->idx, fn); + } + return true; +} + +TRANS_FEAT(FDOT_sb_vi, aa64_f8dp4, do_f8dot_idx, a, gen_helper_gvec_fdot_idx_sb) + static bool do_int3_vector_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3 * const fns[2]) { -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-36-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sve.decode | 4 ++++ target/arm/tcg/translate-sve.c | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ssve_f8fma(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SF8FMA); } +static inline bool isar_feature_aa64_ssve_f8dp4(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SF8DP4); +} + static inline bool isar_feature_aa64_sme_b16b16(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, B16B16); diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ FMLALL_sb 01100100 00 1 rm:5 10 idxn:2 10 rn:5 rd:5 &rxx idxm=0 FDOT_zzzz 01100100 00 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 BFDOT_zzzz 01100100 01 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 +FDOT_sb 01100100 01 1 ..... 10 0 00 1 ..... ..... @rda_rn_rm_ex esz=2 + ### SVE2 floating-point multiply-add long (indexed) FMLALB_zzxw 01100100 10 1 ..... 0100.0 ..... ..... @rrxr_3a esz=2 @@ -XXX,XX +XXX,XX @@ FMLALL_idx_sb 01100100 idxn:2 1 .. rm:3 1100 .. rn:5 rd:5 \ FDOT_zzxz 01100100 00 1 ..... 010000 ..... ..... @rrxr_2 esz=2 BFDOT_zzxz 01100100 01 1 ..... 010000 ..... ..... @rrxr_2 esz=2 +FDOT_idx_sb 01100100 01 1 ..... 010001 ..... ..... @rrxr_2 esz=2 + ### SVE broadcast predicate element &psel esz pd pn pm rv imm diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ TRANS(FMLAL_idx_hb, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_hb) TRANS(FMLALL_sb, do_fmla_fp8, a, gen_helper_gvec_fmla_sb) TRANS(FMLALL_idx_sb, do_fmla_fp8, a, gen_helper_gvec_fmla_idx_sb) + +static bool do_f8dp4(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int rm, int index) +{ + bool fp8dp4 = dc_isar_feature(aa64_f8dp4, s); + bool ssve_fp8dp4 = dc_isar_feature(aa64_ssve_f8dp4, s); + bool ok = false; + + /* Feature detection and enabling are complex here. */ + if (!(ssve_fp8dp4 || (fp8dp4 && dc_isar_feature(aa64_sve2, s)))) { + return false; + } + if (fpmr_access_check(s)) { + if (fp8dp4) { + s->is_nonstreaming = !ssve_fp8dp4; + ok = sve_access_check(s); + } else { + ok = sme_sm_enabled_check(s); + } + } + + if (ok) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + tcg_env, vsz, vsz, + index, fn); + } + return true; +} + +TRANS(FDOT_sb, do_f8dp4, gen_helper_gvec_fdot_sb, a->rd, a->rn, a->rm, 0) +TRANS(FDOT_idx_sb, do_f8dp4, gen_helper_gvec_fdot_idx_sb, + a->rd, a->rn, a->rm, a->index) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-37-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 2 ++ linux-user/aarch64/elfload.c | 2 ++ target/arm/tcg/cpu64.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_FP (Floating Point extensions) - FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP8 (FP8 convert instructions) +- FEAT_FP8DOT4 (FP8 4-way dot product to single-precision instructions) - FEAT_FP8FMA (FP8 multiply-accumulate to half-precision and single-precision instructions) - FEAT_FPAC (Faulting on AUT* instructions) - FEAT_FPACCOMBINE (Faulting on combined pointer authentication instructions) @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) +- FEAT_SSVE_FP8DOT4 (SVE2 FP8 4-way dot product to single-precision instructions in Streaming SVE mode) - FEAT_SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) - FEAT_SVE (Scalable Vector Extension) - FEAT_SVE_AES (Scalable Vector AES instructions) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) ARM_HWCAP2_A64_F8E4M3 | ARM_HWCAP2_A64_F8E5M2); GET_FEATURE_ID(aa64_f8fma, ARM_HWCAP2_A64_F8FMA); + GET_FEATURE_ID(aa64_f8dp4, ARM_HWCAP2_A64_F8DP4); GET_FEATURE_ID(aa64_ssve_f8fma, ARM_HWCAP2_A64_SME_SF8FMA); + GET_FEATURE_ID(aa64_ssve_f8dp4, ARM_HWCAP2_A64_SME_SF8DP4); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) SET_IDREG(isar, ID_AA64DFR0, t); t = GET_IDREG(isar, ID_AA64SMFR0); + t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP4, 1); /* FEAT_SSVE_FP8DOT4 */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8FMA, 1); /* FEAT_SSVE_FP8FMA */ t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ t = FIELD_DP64(t, ID_AA64SMFR0, BI32I32, 1); /* FEAT_SME2 */ @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64FPFR0); t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* FEAT_FP8DOT4 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* FEAT_FP8FMA */ t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* FEAT_FP8 */ SET_IDREG(isar, ID_AA64FPFR0, t); -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-38-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 ++++ target/arm/tcg/a64.decode | 2 ++ target/arm/tcg/fp8_helper.c | 39 ++++++++++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 3 +++ target/arm/tcg/translate-a64.c | 2 ++ 5 files changed, 51 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8dp4(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8DP4); } +static inline bool isar_feature_aa64_f8dp2(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8DP2); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMLALL_sb_v 0.00 1110 0.0 rm:5 110001 rn:5 rd:5 \ &rxx idxm=0 idxn=%fmlall_idxn FDOT_sb_v 0.00 1110 000 ..... 11111 1 ..... ..... @qrrr_s +FDOT_hb_v 0.00 1110 010 ..... 11111 1 ..... ..... @qrrr_h ### Advanced SIMD scalar x indexed element @@ -XXX,XX +XXX,XX @@ FMLALL_sb_vi 0 . 10 1111 0 . ... rm:3 1000 . 0 rn:5 rd:5 \ &rxx idxm=%hlm4 idxn=%fmlall_idxn FDOT_sb_vi 0.00 1111 00 . ..... 0000 . 0 ..... ..... @qrrx_s +FDOT_hb_vi 0.00 1111 01 .. .... 0000 . 0 ..... ..... @qrrx_h # Floating-point conditional select diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fdot_idx_sb)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(gvec_fdot_hb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + uint16_t *n = vn; + uint16_t *m = vm; + float16 *d = vd; + + for (size_t i = 0; i < nelem; i++) { + d[i] = f8dotadd_h(n[i], m[i], 2, d[i], &ctx); + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} + +void HELPER(gvec_fdot_idx_hb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + size_t idx = simd_data(desc); + size_t oprsz = simd_oprsz(desc); + size_t nelem = oprsz / 2; + uint16_t *n = vn; + uint16_t *m = vm; + float16 *d = vd; + size_t i = 0; + + do { + uint16_t e1 = m[i + H2(idx)]; + do { + d[i] = f8dotadd_h(n[i], e1, 2, d[i], &ctx); + } while (++i % 8 != 0); + } while (i < nelem); + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(gvec_fmla_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_5(gvec_fdot_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fdot_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fdot_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_f8dot(DisasContext *s, arg_qrrr_e *a, } TRANS_FEAT(FDOT_sb_v, aa64_f8dp4, do_f8dot, a, gen_helper_gvec_fdot_sb) +TRANS_FEAT(FDOT_hb_v, aa64_f8dp2, do_f8dot, a, gen_helper_gvec_fdot_hb) static bool do_f8dot_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3_ptr *fn) @@ -XXX,XX +XXX,XX @@ static bool do_f8dot_idx(DisasContext *s, arg_qrrx_e *a, } TRANS_FEAT(FDOT_sb_vi, aa64_f8dp4, do_f8dot_idx, a, gen_helper_gvec_fdot_idx_sb) +TRANS_FEAT(FDOT_hb_vi, aa64_f8dp2, do_f8dot_idx, a, gen_helper_gvec_fdot_idx_hb) static bool do_int3_vector_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3 * const fns[2]) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-39-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sve.decode | 2 ++ target/arm/tcg/translate-sve.c | 35 ++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_ssve_f8dp4(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SF8DP4); } +static inline bool isar_feature_aa64_ssve_f8dp2(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64SMFR0, SF8DP2); +} + static inline bool isar_feature_aa64_sme_b16b16(const ARMISARegisters *id) { return FIELD_EX64_IDREG(id, ID_AA64SMFR0, B16B16); diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ FDOT_zzzz 01100100 00 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 BFDOT_zzzz 01100100 01 1 ..... 10 0 00 0 ..... ..... @rda_rn_rm_ex esz=2 FDOT_sb 01100100 01 1 ..... 10 0 00 1 ..... ..... @rda_rn_rm_ex esz=2 +FDOT_hb 01100100 00 1 ..... 10 0 00 1 ..... ..... @rda_rn_rm_ex esz=1 ### SVE2 floating-point multiply-add long (indexed) @@ -XXX,XX +XXX,XX @@ FDOT_zzxz 01100100 00 1 ..... 010000 ..... ..... @rrxr_2 esz=2 BFDOT_zzxz 01100100 01 1 ..... 010000 ..... ..... @rrxr_2 esz=2 FDOT_idx_sb 01100100 01 1 ..... 010001 ..... ..... @rrxr_2 esz=2 +FDOT_idx_hb 01100100 00 1 ..... 0100.1 ..... ..... @rrx_3a esz=1 ### SVE broadcast predicate element diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool do_f8dp4(DisasContext *s, gen_helper_gvec_3_ptr *fn, TRANS(FDOT_sb, do_f8dp4, gen_helper_gvec_fdot_sb, a->rd, a->rn, a->rm, 0) TRANS(FDOT_idx_sb, do_f8dp4, gen_helper_gvec_fdot_idx_sb, a->rd, a->rn, a->rm, a->index) + +static bool do_f8dp2(DisasContext *s, gen_helper_gvec_3_ptr *fn, + int rd, int rn, int rm, int index) +{ + bool fp8dp2 = dc_isar_feature(aa64_f8dp2, s); + bool ssve_fp8dp2 = dc_isar_feature(aa64_ssve_f8dp2, s); + bool ok = false; + + /* Feature detection and enabling are complex here. */ + if (!(ssve_fp8dp2 || (fp8dp2 && dc_isar_feature(aa64_sve2, s)))) { + return false; + } + if (fpmr_access_check(s)) { + if (fp8dp2) { + s->is_nonstreaming = !ssve_fp8dp2; + ok = sve_access_check(s); + } else { + ok = sme_sm_enabled_check(s); + } + } + + if (ok) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, rd), + vec_full_reg_offset(s, rn), + vec_full_reg_offset(s, rm), + tcg_env, vsz, vsz, + index, fn); + } + return true; +} + +TRANS(FDOT_hb, do_f8dp2, gen_helper_gvec_fdot_hb, a->rd, a->rn, a->rm, 0) +TRANS(FDOT_idx_hb, do_f8dp2, gen_helper_gvec_fdot_idx_hb, + a->rd, a->rn, a->rm, a->index) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-40-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 2 ++ linux-user/aarch64/elfload.c | 2 ++ target/arm/tcg/cpu64.c | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_FP (Floating Point extensions) - FEAT_FP16 (Half-precision floating-point data processing) - FEAT_FP8 (FP8 convert instructions) +- FEAT_FP8DOT2 (FP8 2-way dot product to half-precision instructions) - FEAT_FP8DOT4 (FP8 4-way dot product to single-precision instructions) - FEAT_FP8FMA (FP8 multiply-accumulate to half-precision and single-precision instructions) - FEAT_FPAC (Faulting on AUT* instructions) @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_SME_F64F64 (Double-precision floating-point outer product instructions) - FEAT_SME_I16I64 (16-bit to 64-bit integer widening outer product instructions) - FEAT_SME_LUTv2 (Lookup table instructions with 4-bit indices and 8-bit elements) +- FEAT_SSVE_FP8DOT2 (SVE2 FP8 2-way dot product to half-precision instructions in Streaming SVE mode) - FEAT_SSVE_FP8DOT4 (SVE2 FP8 4-way dot product to single-precision instructions in Streaming SVE mode) - FEAT_SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) - FEAT_SVE (Scalable Vector Extension) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap2(CPUState *cs) ARM_HWCAP2_A64_F8E5M2); GET_FEATURE_ID(aa64_f8fma, ARM_HWCAP2_A64_F8FMA); GET_FEATURE_ID(aa64_f8dp4, ARM_HWCAP2_A64_F8DP4); + GET_FEATURE_ID(aa64_f8dp2, ARM_HWCAP2_A64_F8DP2); GET_FEATURE_ID(aa64_ssve_f8fma, ARM_HWCAP2_A64_SME_SF8FMA); GET_FEATURE_ID(aa64_ssve_f8dp4, ARM_HWCAP2_A64_SME_SF8DP4); + GET_FEATURE_ID(aa64_ssve_f8dp2, ARM_HWCAP2_A64_SME_SF8DP2); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) SET_IDREG(isar, ID_AA64DFR0, t); t = GET_IDREG(isar, ID_AA64SMFR0); + t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP2, 1); /* FEAT_SSVE_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8DP4, 1); /* FEAT_SSVE_FP8DOT4 */ t = FIELD_DP64(t, ID_AA64SMFR0, SF8FMA, 1); /* FEAT_SSVE_FP8FMA */ t = FIELD_DP64(t, ID_AA64SMFR0, F32F32, 1); /* FEAT_SME */ @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64FPFR0); t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8DP2, 1); /* FEAT_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* FEAT_FP8DOT4 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* FEAT_FP8FMA */ t = FIELD_DP64(t, ID_AA64FPFR0, F8CVT, 1); /* FEAT_FP8 */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-41-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/a64.decode | 2 ++ target/arm/tcg/fp8_helper.c | 25 +++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 2 ++ target/arm/tcg/translate-a64.c | 1 + 5 files changed, 35 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8dp2(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8DP2); } +static inline bool isar_feature_aa64_f8mm8(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8MM8); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FMLALL_sb_v 0.00 1110 0.0 rm:5 110001 rn:5 rd:5 \ FDOT_sb_v 0.00 1110 000 ..... 11111 1 ..... ..... @qrrr_s FDOT_hb_v 0.00 1110 010 ..... 11111 1 ..... ..... @qrrr_h +FMMLA_sb 0110 1110 100 ..... 11101 1 ..... ..... @rrr_q1e0 + ### Advanced SIMD scalar x indexed element FMUL_si 0101 1111 00 .. .... 1001 . 0 ..... ..... @rrx_h diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fdot_idx_hb)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(gvec_fmmla_sb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, -1); + size_t oprsz = simd_oprsz(desc); + size_t nseg = oprsz / 16; + uint64_t *n = vn; + uint64_t *m = vm; + float32 *d = vd; + + for (size_t seg = 0; seg < nseg; seg++, d += 4, n += 2, m += 2) { + float32 d0 = f8dotadd_s(n[0], m[0], 8, d[H4(0)], &ctx); + float32 d1 = f8dotadd_s(n[0], m[1], 8, d[H4(1)], &ctx); + float32 d2 = f8dotadd_s(n[1], m[0], 8, d[H4(2)], &ctx); + float32 d3 = f8dotadd_s(n[1], m[1], 8, d[H4(3)], &ctx); + + d[H4(0)] = d0; + d[H4(1)] = d1; + d[H4(2)] = d2; + d[H4(3)] = d3; + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(gvec_fdot_idx_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, DEF_HELPER_FLAGS_5(gvec_fdot_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) + +DEF_HELPER_FLAGS_5(gvec_fmmla_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_f8dot(DisasContext *s, arg_qrrr_e *a, TRANS_FEAT(FDOT_sb_v, aa64_f8dp4, do_f8dot, a, gen_helper_gvec_fdot_sb) TRANS_FEAT(FDOT_hb_v, aa64_f8dp2, do_f8dot, a, gen_helper_gvec_fdot_hb) +TRANS_FEAT(FMMLA_sb, aa64_f8mm8, do_f8dot, a, gen_helper_gvec_fmmla_sb) static bool do_f8dot_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3_ptr *fn) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-42-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sve.decode | 2 ++ target/arm/tcg/translate-sve.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sve_bf16(const ARMISARegisters *id) return isar_feature_aa64_sve(id) && isar_feature_aa64_sme_sve_bf16(id); } +static inline bool isar_feature_aa64_sve2_f8mm8(const ARMISARegisters *id) +{ + return isar_feature_aa64_sve2(id) && isar_feature_aa64_f8mm8(id); +} + static inline bool isar_feature_aa64_sme2_or_sve2_faminmax(const ARMISARegisters *id) { diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ BFMMLA 01100100 01 1 ..... 111 001 ..... ..... @rda_rn_rm_ex esz=1 FMMLA_s 01100100 10 1 ..... 111 001 ..... ..... @rda_rn_rm_ex esz=2 FMMLA_d 01100100 11 1 ..... 111 001 ..... ..... @rda_rn_rm_ex esz=3 +FMMLA_sb 01100100 00 1 ..... 111 000 ..... ..... @rda_rn_rm_ex esz=2 + ### SVE2 Memory Gather Load Group # SVE2 64-bit gather non-temporal load (scalar plus 64-bit unscaled offsets) diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool do_f8dp2(DisasContext *s, gen_helper_gvec_3_ptr *fn, TRANS(FDOT_hb, do_f8dp2, gen_helper_gvec_fdot_hb, a->rd, a->rn, a->rm, 0) TRANS(FDOT_idx_hb, do_f8dp2, gen_helper_gvec_fdot_idx_hb, a->rd, a->rn, a->rm, a->index) + +static bool do_fmmla_fp8(DisasContext *s, arg_rrrr_esz *a, + gen_helper_gvec_3_ptr *fn) +{ + if (fpmr_access_check(s) && sve_access_check(s)) { + unsigned vsz = vec_full_reg_size(s); + tcg_gen_gvec_3_ptr(vec_full_reg_offset(s, a->rd), + vec_full_reg_offset(s, a->rn), + vec_full_reg_offset(s, a->rm), + tcg_env, vsz, vsz, 0, fn); + } + return true; +} + +TRANS_FEAT_NONSTREAMING(FMMLA_sb, aa64_sve2_f8mm8, do_fmmla_fp8, a, + gen_helper_gvec_fmmla_sb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-43-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_EPAC (Enhanced pointer authentication) - FEAT_ETS2 (Enhanced Translation Synchronization) - FEAT_EVT (Enhanced Virtualization Traps) +- FEAT_F8F32MM (8-bit floating-point matrix multiply-accumulate to single-precision) - FEAT_F32MM (Single-precision Matrix Multiplication) - FEAT_F64MM (Double-precision Matrix Multiplication) - FEAT_FAMINMAX (Floating-point maximum and minimum absolute value instructions) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_rcpc_8_4, ARM_HWCAP_A64_ILRCPC); GET_FEATURE_ID(aa64_gcs, ARM_HWCAP_A64_GCS); GET_FEATURE_ID(aa64_cmpbr, ARM_HWCAP_A64_CMPBR); + GET_FEATURE_ID(aa64_f8mm8, ARM_HWCAP_A64_F8MM8); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64FPFR0); t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8MM8, 1); /* FEAT_F8F32MM */ t = FIELD_DP64(t, ID_AA64FPFR0, F8DP2, 1); /* FEAT_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* FEAT_FP8DOT4 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8FMA, 1); /* FEAT_FP8FMA */ -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-44-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/a64.decode | 1 + target/arm/tcg/fp8_helper.c | 25 +++++++++++++++++++++++++ target/arm/tcg/helper-fp8-defs.h | 1 + target/arm/tcg/translate-a64.c | 1 + 5 files changed, 33 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_f8mm8(const ARMISARegisters *id) return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8MM8); } +static inline bool isar_feature_aa64_f8mm4(const ARMISARegisters *id) +{ + return FIELD_EX64_IDREG(id, ID_AA64FPFR0, F8MM4); +} + /* * Combinations of feature tests, for ease of use with TRANS_FEAT. */ diff --git a/target/arm/tcg/a64.decode b/target/arm/tcg/a64.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/a64.decode +++ b/target/arm/tcg/a64.decode @@ -XXX,XX +XXX,XX @@ FDOT_sb_v 0.00 1110 000 ..... 11111 1 ..... ..... @qrrr_s FDOT_hb_v 0.00 1110 010 ..... 11111 1 ..... ..... @qrrr_h FMMLA_sb 0110 1110 100 ..... 11101 1 ..... ..... @rrr_q1e0 +FMMLA_hb 0110 1110 000 ..... 11101 1 ..... ..... @rrr_q1e0 ### Advanced SIMD scalar x indexed element diff --git a/target/arm/tcg/fp8_helper.c b/target/arm/tcg/fp8_helper.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/fp8_helper.c +++ b/target/arm/tcg/fp8_helper.c @@ -XXX,XX +XXX,XX @@ void HELPER(gvec_fmmla_sb)(void *vd, void *vn, void *vm, clear_tail(vd, oprsz, simd_maxsz(desc)); } + +void HELPER(gvec_fmmla_hb)(void *vd, void *vn, void *vm, + CPUARMState *env, uint32_t desc) +{ + FP8MulContext ctx = fp8_mul_start(env, 0xf); + size_t oprsz = simd_oprsz(desc); + size_t nseg = oprsz / 8; + uint32_t *n = vn; + uint32_t *m = vm; + float16 *d = vd; + + for (size_t seg = 0; seg < nseg; seg++, d += 4, n += 2, m += 2) { + float16 d0 = f8dotadd_h(n[H4(0)], m[H4(0)], 4, d[H2(0)], &ctx); + float16 d1 = f8dotadd_h(n[H4(0)], m[H4(1)], 4, d[H2(1)], &ctx); + float16 d2 = f8dotadd_h(n[H4(1)], m[H4(0)], 4, d[H2(2)], &ctx); + float16 d3 = f8dotadd_h(n[H4(1)], m[H4(1)], 4, d[H2(3)], &ctx); + + d[H2(0)] = d0; + d[H2(1)] = d1; + d[H2(2)] = d2; + d[H2(3)] = d3; + } + + clear_tail(vd, oprsz, simd_maxsz(desc)); +} diff --git a/target/arm/tcg/helper-fp8-defs.h b/target/arm/tcg/helper-fp8-defs.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/helper-fp8-defs.h +++ b/target/arm/tcg/helper-fp8-defs.h @@ -XXX,XX +XXX,XX @@ DEF_HELPER_FLAGS_5(gvec_fdot_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fdot_idx_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) DEF_HELPER_FLAGS_5(gvec_fmmla_sb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) +DEF_HELPER_FLAGS_5(gvec_fmmla_hb, TCG_CALL_NO_RWG, void, ptr, ptr, ptr, env, i32) diff --git a/target/arm/tcg/translate-a64.c b/target/arm/tcg/translate-a64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-a64.c +++ b/target/arm/tcg/translate-a64.c @@ -XXX,XX +XXX,XX @@ static bool do_f8dot(DisasContext *s, arg_qrrr_e *a, TRANS_FEAT(FDOT_sb_v, aa64_f8dp4, do_f8dot, a, gen_helper_gvec_fdot_sb) TRANS_FEAT(FDOT_hb_v, aa64_f8dp2, do_f8dot, a, gen_helper_gvec_fdot_hb) TRANS_FEAT(FMMLA_sb, aa64_f8mm8, do_f8dot, a, gen_helper_gvec_fmmla_sb) +TRANS_FEAT(FMMLA_hb, aa64_f8mm4, do_f8dot, a, gen_helper_gvec_fmmla_hb) static bool do_f8dot_idx(DisasContext *s, arg_qrrx_e *a, gen_helper_gvec_3_ptr *fn) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-45-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- target/arm/cpu-features.h | 5 +++++ target/arm/tcg/sve.decode | 1 + target/arm/tcg/translate-sve.c | 2 ++ 3 files changed, 8 insertions(+) diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h index XXXXXXX..XXXXXXX 100644 --- a/target/arm/cpu-features.h +++ b/target/arm/cpu-features.h @@ -XXX,XX +XXX,XX @@ static inline bool isar_feature_aa64_sve2_f8mm8(const ARMISARegisters *id) return isar_feature_aa64_sve2(id) && isar_feature_aa64_f8mm8(id); } +static inline bool isar_feature_aa64_sve2_f8mm4(const ARMISARegisters *id) +{ + return isar_feature_aa64_sve2(id) && isar_feature_aa64_f8mm4(id); +} + static inline bool isar_feature_aa64_sme2_or_sve2_faminmax(const ARMISARegisters *id) { diff --git a/target/arm/tcg/sve.decode b/target/arm/tcg/sve.decode index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/sve.decode +++ b/target/arm/tcg/sve.decode @@ -XXX,XX +XXX,XX @@ FMMLA_s 01100100 10 1 ..... 111 001 ..... ..... @rda_rn_rm_ex esz=2 FMMLA_d 01100100 11 1 ..... 111 001 ..... ..... @rda_rn_rm_ex esz=3 FMMLA_sb 01100100 00 1 ..... 111 000 ..... ..... @rda_rn_rm_ex esz=2 +FMMLA_hb 01100100 01 1 ..... 111 000 ..... ..... @rda_rn_rm_ex esz=1 ### SVE2 Memory Gather Load Group diff --git a/target/arm/tcg/translate-sve.c b/target/arm/tcg/translate-sve.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/translate-sve.c +++ b/target/arm/tcg/translate-sve.c @@ -XXX,XX +XXX,XX @@ static bool do_fmmla_fp8(DisasContext *s, arg_rrrr_esz *a, TRANS_FEAT_NONSTREAMING(FMMLA_sb, aa64_sve2_f8mm8, do_fmmla_fp8, a, gen_helper_gvec_fmmla_sb) +TRANS_FEAT_NONSTREAMING(FMMLA_hb, aa64_sve2_f8mm4, do_fmmla_fp8, a, + gen_helper_gvec_fmmla_hb) -- 2.43.0
From: Richard Henderson <richard.henderson@linaro.org> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20260609192110.752384-46-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org> --- docs/system/arm/emulation.rst | 1 + linux-user/aarch64/elfload.c | 1 + target/arm/tcg/cpu64.c | 1 + 3 files changed, 3 insertions(+) diff --git a/docs/system/arm/emulation.rst b/docs/system/arm/emulation.rst index XXXXXXX..XXXXXXX 100644 --- a/docs/system/arm/emulation.rst +++ b/docs/system/arm/emulation.rst @@ -XXX,XX +XXX,XX @@ the following architecture extensions: - FEAT_EPAC (Enhanced pointer authentication) - FEAT_ETS2 (Enhanced Translation Synchronization) - FEAT_EVT (Enhanced Virtualization Traps) +- FEAT_F8F16MM (8-bit floating-point matrix multiply-accumulate to half-precision) - FEAT_F8F32MM (8-bit floating-point matrix multiply-accumulate to single-precision) - FEAT_F32MM (Single-precision Matrix Multiplication) - FEAT_F64MM (Double-precision Matrix Multiplication) diff --git a/linux-user/aarch64/elfload.c b/linux-user/aarch64/elfload.c index XXXXXXX..XXXXXXX 100644 --- a/linux-user/aarch64/elfload.c +++ b/linux-user/aarch64/elfload.c @@ -XXX,XX +XXX,XX @@ abi_ulong get_elf_hwcap(CPUState *cs) GET_FEATURE_ID(aa64_gcs, ARM_HWCAP_A64_GCS); GET_FEATURE_ID(aa64_cmpbr, ARM_HWCAP_A64_CMPBR); GET_FEATURE_ID(aa64_f8mm8, ARM_HWCAP_A64_F8MM8); + GET_FEATURE_ID(aa64_f8mm4, ARM_HWCAP_A64_F8MM4); return hwcaps; } diff --git a/target/arm/tcg/cpu64.c b/target/arm/tcg/cpu64.c index XXXXXXX..XXXXXXX 100644 --- a/target/arm/tcg/cpu64.c +++ b/target/arm/tcg/cpu64.c @@ -XXX,XX +XXX,XX @@ void aarch64_max_tcg_initfn(Object *obj) t = GET_IDREG(isar, ID_AA64FPFR0); t = FIELD_DP64(t, ID_AA64FPFR0, F8E5M2, 1); /* FEAT_FP8 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8E4M3, 1); /* FEAT_FP8 */ + t = FIELD_DP64(t, ID_AA64FPFR0, F8MM4, 1); /* FEAT_F8F16MM */ t = FIELD_DP64(t, ID_AA64FPFR0, F8MM8, 1); /* FEAT_F8F32MM */ t = FIELD_DP64(t, ID_AA64FPFR0, F8DP2, 1); /* FEAT_FP8DOT2 */ t = FIELD_DP64(t, ID_AA64FPFR0, F8DP4, 1); /* FEAT_FP8DOT4 */ -- 2.43.0
v3->v4: Windows headers define an INT type which clashed with an enum value name in arm_gicv3_its.c... The following changes since commit eae587e8e3694b1aceab23239493fb4c7e1a80f5: Merge remote-tracking branch 'remotes/armbru/tags/pull-qapi-2021-09-13' into staging (2021-09-13 11:00:30 +0100) are available in the Git repository at: https://git.linaro.org/people/pmaydell/qemu-arm.git tags/pull-target-arm-20210913-3 for you to fetch changes up to 28e987a7e7edaa3ca7feeac65edca26145df8814: hw/arm/mps2.c: Mark internal-only I2C buses as 'full' (2021-09-13 21:01:08 +0100) ---------------------------------------------------------------- target-arm queue: * mark MPS2/MPS3 board-internal i2c buses as 'full' so that command line user-created devices are not plugged into them * Take an exception if PSTATE.IL is set * Support an emulated ITS in the virt board * Add support for kudo-bmc board * Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM * cadence_uart: Fix clock handling issues that prevented u-boot from running ---------------------------------------------------------------- Bin Meng (6): hw/misc: zynq_slcr: Correctly compute output clocks in the reset exit phase hw/char: cadence_uart: Disable transmit when input clock is disabled hw/char: cadence_uart: Move clock/reset check to uart_can_receive() hw/char: cadence_uart: Convert to memop_with_attrs() ops hw/char: cadence_uart: Ignore access when unclocked or in reset for uart_{read, write}() hw/char: cadence_uart: Log a guest error when device is unclocked or in reset Chris Rauer (1): hw/arm: Add support for kudo-bmc board. Marc Zyngier (1): hw/arm/virt: KVM: Probe for KVM_CAP_ARM_VM_IPA_SIZE when creating scratch VM Peter Maydell (5): target/arm: Take an exception if PSTATE.IL is set qdev: Support marking individual buses as 'full' hw/arm/mps2-tz.c: Add extra data parameter to MakeDevFn hw/arm/mps2-tz.c: Mark internal-only I2C buses as 'full' hw/arm/mps2.c: Mark internal-only I2C buses as 'full' Richard Henderson (1): target/arm: Merge disas_a64_insn into aarch64_tr_translate_insn Shashi Mallela (9): hw/intc: GICv3 ITS initial framework hw/intc: GICv3 ITS register definitions added hw/intc: GICv3 ITS command queue framework hw/intc: GICv3 ITS Command processing hw/intc: GICv3 ITS Feature enablement hw/intc: GICv3 redistributor ITS processing tests/data/acpi/virt: Add IORT files for ITS hw/arm/virt: add ITS support in virt GIC tests/data/acpi/virt: Update IORT files for ITS docs/system/arm/nuvoton.rst | 1 + hw/intc/gicv3_internal.h | 188 ++++- include/hw/arm/virt.h | 2 + include/hw/intc/arm_gicv3_common.h | 13 + include/hw/intc/arm_gicv3_its_common.h | 32 +- include/hw/qdev-core.h | 24 + target/arm/cpu.h | 1 + target/arm/kvm_arm.h | 4 +- target/arm/syndrome.h | 5 + target/arm/translate.h | 2 + hw/arm/mps2-tz.c | 92 ++- hw/arm/mps2.c | 12 +- hw/arm/npcm7xx_boards.c | 34 + hw/arm/virt.c | 29 +- hw/char/cadence_uart.c | 61 +- hw/intc/arm_gicv3.c | 14 + hw/intc/arm_gicv3_common.c | 13 + hw/intc/arm_gicv3_cpuif.c | 7 +- hw/intc/arm_gicv3_dist.c | 5 +- hw/intc/arm_gicv3_its.c | 1322 ++++++++++++++++++++++++++++++++ hw/intc/arm_gicv3_its_common.c | 7 +- hw/intc/arm_gicv3_its_kvm.c | 2 +- hw/intc/arm_gicv3_redist.c | 153 +++- hw/misc/zynq_slcr.c | 31 +- softmmu/qdev-monitor.c | 7 +- target/arm/helper-a64.c | 1 + target/arm/helper.c | 8 + target/arm/kvm.c | 7 +- target/arm/translate-a64.c | 255 +++--- target/arm/translate.c | 21 + hw/intc/meson.build | 1 + tests/data/acpi/virt/IORT | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.memhp | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.numamem | Bin 0 -> 124 bytes tests/data/acpi/virt/IORT.pxb | Bin 0 -> 124 bytes 35 files changed, 2144 insertions(+), 210 deletions(-) create mode 100644 hw/intc/arm_gicv3_its.c create mode 100644 tests/data/acpi/virt/IORT create mode 100644 tests/data/acpi/virt/IORT.memhp create mode 100644 tests/data/acpi/virt/IORT.numamem create mode 100644 tests/data/acpi/virt/IORT.pxb