* [PULL 00/71] target-arm queue
@ 2026-06-10 16:10 Peter Maydell
2026-06-10 16:10 ` [PULL 01/71] hw/core/qdev-clock: Fix potential null pointer dereference Peter Maydell
` (71 more replies)
0 siblings, 72 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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
^ permalink raw reply [flat|nested] 73+ messages in thread
* [PULL 01/71] hw/core/qdev-clock: Fix potential null pointer dereference
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 02/71] target/arm: implement MTE_PERM Peter Maydell
` (70 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 6e2967e433..861f78f94c 100644
--- a/hw/core/qdev-clock.c
+++ b/hw/core/qdev-clock.c
@@ -157,7 +157,14 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 02/71] target/arm: implement MTE_PERM
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
2026-06-10 16:10 ` [PULL 01/71] hw/core/qdev-clock: Fix potential null pointer dereference Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 03/71] target/arm: add TCSO bitmasks to SCTLR Peter Maydell
` (69 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 38a695ded7..83897365ad 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1191,6 +1191,11 @@ 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 0a5201763a..6cb0fe5645 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -3415,7 +3415,7 @@ 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;
@@ -3425,6 +3425,18 @@ 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 */
@@ -3456,9 +3468,16 @@ 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 a9fb979f63..bf35dc10ce 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -58,6 +58,27 @@ 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,
@@ -117,8 +138,21 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 03/71] target/arm: add TCSO bitmasks to SCTLR
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
2026-06-10 16:10 ` [PULL 01/71] hw/core/qdev-clock: Fix potential null pointer dereference Peter Maydell
2026-06-10 16:10 ` [PULL 02/71] target/arm: implement MTE_PERM Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 04/71] target/arm: mte_check unemitted on STORE_ONLY load Peter Maydell
` (68 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 83897365ad..92400df649 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1196,6 +1196,11 @@ 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 85552b573c..d9c03c9c2e 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -1468,6 +1468,8 @@ 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 9dd8fdfa41..bb77cbae51 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -3300,12 +3300,20 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 04/71] target/arm: mte_check unemitted on STORE_ONLY load
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (2 preceding siblings ...)
2026-06-10 16:10 ` [PULL 03/71] target/arm: add TCSO bitmasks to SCTLR Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 05/71] linux-user: add MTE_STORE_ONLY to prctl Peter Maydell
` (67 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 d9c03c9c2e..08f04a57af 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2534,6 +2534,8 @@ 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 794cdf00b2..6be84b68ab 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -461,6 +461,15 @@ 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. */
@@ -470,6 +479,9 @@ 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 3c091ccc56..5165d964ab 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -302,7 +302,8 @@ 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;
@@ -334,7 +335,8 @@ 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;
@@ -10805,6 +10807,8 @@ 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 d4bcc5bad4..551c6ff347 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -140,6 +140,8 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 05/71] linux-user: add MTE_STORE_ONLY to prctl
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (3 preceding siblings ...)
2026-06-10 16:10 ` [PULL 04/71] target/arm: mte_check unemitted on STORE_ONLY load Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 06/71] target/arm: emit tag check when MTX without TBI Peter Maydell
` (66 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 a5b1c8503b..b5c4dafcda 100644
--- a/linux-user/aarch64/mte_user_helper.c
+++ b/linux-user/aarch64/mte_user_helper.c
@@ -10,7 +10,7 @@
#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].
@@ -32,4 +32,13 @@ 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 0c53abda22..8a46f743f4 100644
--- a/linux-user/aarch64/mte_user_helper.h
+++ b/linux-user/aarch64/mte_user_helper.h
@@ -20,15 +20,19 @@
# 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 621be5727f..d91e75d60d 100644
--- a/linux-user/aarch64/target_prctl.h
+++ b/linux-user/aarch64/target_prctl.h
@@ -168,6 +168,9 @@ 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) {
@@ -176,7 +179,7 @@ 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].
@@ -185,6 +188,7 @@ 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 a4fa740caf..0c3e5b30bd 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -684,7 +684,7 @@ 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 0805676b11..17b932f3f1 100644
--- a/tests/tcg/aarch64/mte.h
+++ b/tests/tcg/aarch64/mte.h
@@ -20,6 +20,9 @@
#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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 06/71] target/arm: emit tag check when MTX without TBI
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (4 preceding siblings ...)
2026-06-10 16:10 ` [PULL 05/71] linux-user: add MTE_STORE_ONLY to prctl Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 07/71] target/arm: add MTX to MTEDESC and DisasContext Peter Maydell
` (65 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 92400df649..13453bd8f4 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1201,6 +1201,11 @@ 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 bb77cbae51..b989acd0f5 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9661,6 +9661,16 @@ 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 f39a992012..3b60e4a469 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1445,6 +1445,7 @@ 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);
@@ -1586,7 +1587,8 @@ 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);
@@ -1656,10 +1658,11 @@ 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. */
@@ -1693,7 +1696,7 @@ 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 093c697e05..a0f9215f1c 100644
--- a/target/arm/tcg/helper-a64.c
+++ b/target/arm/tcg/helper-a64.c
@@ -1054,7 +1054,7 @@ 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)
@@ -1062,12 +1062,13 @@ 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 6be84b68ab..d9d783489c 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -283,13 +283,16 @@ 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);
@@ -441,14 +444,14 @@ 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);
@@ -474,7 +477,7 @@ 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 bf35dc10ce..61cdf92c54 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -823,8 +823,11 @@ 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;
}
@@ -965,7 +968,7 @@ 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 0055e97a2b..2bfb12c086 100644
--- a/target/arm/tcg/sme_helper.c
+++ b/target/arm/tcg/sme_helper.c
@@ -674,7 +674,7 @@ 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;
}
@@ -856,7 +856,7 @@ 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 a002006ea5..d05d8addfd 100644
--- a/target/arm/tcg/sve_helper.c
+++ b/target/arm/tcg/sve_helper.c
@@ -6388,7 +6388,7 @@ 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;
}
@@ -6750,7 +6750,7 @@ 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;
}
@@ -7005,7 +7005,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 07/71] target/arm: add MTX to MTEDESC and DisasContext
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (5 preceding siblings ...)
2026-06-10 16:10 ` [PULL 06/71] target/arm: emit tag check when MTX without TBI Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:10 ` [PULL 08/71] target/arm: add canonical tag check helper Peter Maydell
` (64 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 08f04a57af..dd939ab22b 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -2536,6 +2536,7 @@ 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 d9d783489c..0716ca98fd 100644
--- a/target/arm/tcg/hflags.c
+++ b/target/arm/tcg/hflags.c
@@ -500,6 +500,8 @@ 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 5165d964ab..b5c9c9c166 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -312,6 +312,7 @@ 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();
@@ -345,6 +346,7 @@ 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();
@@ -3093,6 +3095,7 @@ 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,
@@ -4960,6 +4963,7 @@ 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 */
@@ -5014,11 +5018,13 @@ 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);
@@ -10809,6 +10815,7 @@ 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 551c6ff347..37a7268b32 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -82,6 +82,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 08/71] target/arm: add canonical tag check helper
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (6 preceding siblings ...)
2026-06-10 16:10 ` [PULL 07/71] target/arm: add MTX to MTEDESC and DisasContext Peter Maydell
@ 2026-06-10 16:10 ` Peter Maydell
2026-06-10 16:11 ` [PULL 09/71] target/arm: add canonical MTE check logic Peter Maydell
` (63 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:10 UTC (permalink / raw)
To: qemu-devel
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 3b60e4a469..b91cde1795 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1665,6 +1665,12 @@ 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)
{
@@ -1672,7 +1678,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 09/71] target/arm: add canonical MTE check logic
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (7 preceding siblings ...)
2026-06-10 16:10 ` [PULL 08/71] target/arm: add canonical tag check helper Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 10/71] target/arm: load on canonical tag loads ext bits Peter Maydell
` (62 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b91cde1795..f8cbefec7a 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1658,6 +1658,12 @@ 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 61cdf92c54..d35e3ef04d 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -858,6 +858,14 @@ 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. */
@@ -873,18 +881,24 @@ 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);
}
}
@@ -999,6 +1013,14 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 10/71] target/arm: load on canonical tag loads ext bits
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (8 preceding siblings ...)
2026-06-10 16:11 ` [PULL 09/71] target/arm: add canonical MTE check logic Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 11/71] target/arm: fault on tag store to canonical tag Peter Maydell
` (61 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 cae543a7a1..c268b8c3cc 100644
--- a/target/arm/tcg/helper-a64-defs.h
+++ b/target/arm/tcg/helper-a64-defs.h
@@ -102,14 +102,14 @@ 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 d35e3ef04d..c382f0149f 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -304,7 +304,7 @@ 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;
@@ -317,6 +317,9 @@ 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);
@@ -458,7 +461,7 @@ 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();
@@ -476,6 +479,13 @@ 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 b5c9c9c166..c472917f05 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -4801,7 +4801,7 @@ 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;
@@ -4836,7 +4836,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 11/71] target/arm: fault on tag store to canonical tag
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (9 preceding siblings ...)
2026-06-10 16:11 ` [PULL 10/71] target/arm: load on canonical tag loads ext bits Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 12/71] target/arm: skip tag bit bounds check if MTX is on Peter Maydell
` (60 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 c268b8c3cc..0e56e00f45 100644
--- a/target/arm/tcg/helper-a64-defs.h
+++ b/target/arm/tcg/helper-a64-defs.h
@@ -103,15 +103,15 @@ 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 c382f0149f..dca4ef5a94 100644
--- a/target/arm/tcg/mte_helper.c
+++ b/target/arm/tcg/mte_helper.c
@@ -231,6 +231,19 @@ 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,
@@ -360,7 +373,7 @@ 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;
@@ -374,17 +387,20 @@ 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)
@@ -397,7 +413,7 @@ 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);
@@ -420,9 +436,13 @@ 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. */
@@ -431,18 +451,22 @@ 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)
@@ -528,7 +552,7 @@ 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();
@@ -548,6 +572,10 @@ 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;
}
@@ -577,7 +605,8 @@ 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);
@@ -601,6 +630,8 @@ 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 c472917f05..092a979198 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -3121,7 +3121,8 @@ 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;
@@ -3138,7 +3139,8 @@ 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;
@@ -3955,9 +3957,11 @@ 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));
}
}
@@ -4737,7 +4741,7 @@ 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,
@@ -4769,7 +4773,7 @@ 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;
@@ -4885,15 +4889,17 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 12/71] target/arm: skip tag bit bounds check if MTX is on
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (10 preceding siblings ...)
2026-06-10 16:11 ` [PULL 11/71] target/arm: fault on tag store to canonical tag Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 13/71] target/arm: tag is not a part of PAuth with MTX Peter Maydell
` (59 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b989acd0f5..c9536d2d10 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -9795,7 +9795,7 @@ 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);
@@ -9832,6 +9832,7 @@ 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;
@@ -9847,6 +9848,7 @@ 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));
@@ -9854,6 +9856,7 @@ 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);
@@ -9953,6 +9956,7 @@ 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 f8cbefec7a..cd93499307 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1430,6 +1430,7 @@ 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 6cb0fe5645..8b54018c98 100644
--- a/target/arm/ptw.c
+++ b/target/arm/ptw.c
@@ -1951,9 +1951,18 @@ 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;
}
@@ -3514,15 +3523,31 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 13/71] target/arm: tag is not a part of PAuth with MTX
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (11 preceding siblings ...)
2026-06-10 16:11 ` [PULL 12/71] target/arm: skip tag bit bounds check if MTX is on Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 14/71] docs: add MTE4 features to docs Peter Maydell
` (58 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 cd93499307..21cbd2b1db 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1840,7 +1840,17 @@ 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 67c0d59d9e..3d83ca4c3c 100644
--- a/target/arm/tcg/pauth_helper.c
+++ b/target/arm/tcg/pauth_helper.c
@@ -342,9 +342,16 @@ 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);
@@ -377,6 +384,11 @@ 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));
@@ -424,6 +436,10 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 14/71] docs: add MTE4 features to docs
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (12 preceding siblings ...)
2026-06-10 16:11 ` [PULL 13/71] target/arm: tag is not a part of PAuth with MTX Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 15/71] tests/tcg: add test for MTE FAR Peter Maydell
` (57 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 18c6355967..df82b7f44b 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -114,6 +114,11 @@ 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 1a4f50486d..c7b1dd2e90 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1296,10 +1296,15 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 15/71] tests/tcg: add test for MTE FAR
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (13 preceding siblings ...)
2026-06-10 16:11 ` [PULL 14/71] docs: add MTE4 features to docs Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 16/71] tests/tcg: add test for MTE_STORE_ONLY Peter Maydell
` (56 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 9fa8687453..b491cfb5e1 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -64,7 +64,7 @@ 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 0000000000..9626a90c13
--- /dev/null
+++ b/tests/tcg/aarch64/mte-9.c
@@ -0,0 +1,48 @@
+/*
+ * 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 16/71] tests/tcg: add test for MTE_STORE_ONLY
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (14 preceding siblings ...)
2026-06-10 16:11 ` [PULL 15/71] tests/tcg: add test for MTE FAR Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 17/71] hw/usb/hcd-ohci: Assert isochronous TDs are never deferred Peter Maydell
` (55 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b491cfb5e1..6203ac9b51 100644
--- a/tests/tcg/aarch64/Makefile.target
+++ b/tests/tcg/aarch64/Makefile.target
@@ -64,7 +64,7 @@ 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 0000000000..46d26fe97f
--- /dev/null
+++ b/tests/tcg/aarch64/mte-10.c
@@ -0,0 +1,49 @@
+/*
+ * 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 17b932f3f1..7093b93dc7 100644
--- a/tests/tcg/aarch64/mte.h
+++ b/tests/tcg/aarch64/mte.h
@@ -40,10 +40,10 @@
# 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 17/71] hw/usb/hcd-ohci: Assert isochronous TDs are never deferred
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (15 preceding siblings ...)
2026-06-10 16:11 ` [PULL 16/71] tests/tcg: add test for MTE_STORE_ONLY Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 18/71] hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet Peter Maydell
` (54 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 6ed8046fc2..8f4de0066e 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -746,11 +746,10 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 18/71] hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (16 preceding siblings ...)
2026-06-10 16:11 ` [PULL 17/71] hw/usb/hcd-ohci: Assert isochronous TDs are never deferred Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 19/71] target/arm: fix WFET typo in syndrome Peter Maydell
` (53 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 8f4de0066e..40ebafb4dd 100644
--- a/hw/usb/hcd-ohci.c
+++ b/hw/usb/hcd-ohci.c
@@ -755,6 +755,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 19/71] target/arm: fix WFET typo in syndrome
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (17 preceding siblings ...)
2026-06-10 16:11 ` [PULL 18/71] hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 20/71] target/arm: teach arm_cpu_has_work about halting reasons Peter Maydell
` (52 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 4d1f1c529e..0eb54c15ce 100644
--- a/target/arm/syndrome.h
+++ b/target/arm/syndrome.h
@@ -674,7 +674,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 20/71] target/arm: teach arm_cpu_has_work about halting reasons
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (18 preceding siblings ...)
2026-06-10 16:11 ` [PULL 19/71] target/arm: fix WFET typo in syndrome Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 21/71] target/arm: redefine event stream fields Peter Maydell
` (51 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 a788376d1d..a06be5cc99 100644
--- a/target/arm/arm-powerctl.c
+++ b/target/arm/arm-powerctl.c
@@ -78,7 +78,7 @@ 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,
@@ -186,7 +186,7 @@ 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)
@@ -239,7 +239,7 @@ 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 a13e6dae2a..8771b695d9 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -145,18 +145,36 @@ 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 */
@@ -327,7 +345,7 @@ 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 dd939ab22b..31a5567c95 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -224,6 +224,19 @@ 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];
@@ -746,6 +759,9 @@ 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 21cbd2b1db..b2035b9417 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -2063,4 +2063,15 @@ 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 7d194ea112..a54ef51ec2 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -1149,11 +1149,12 @@ 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 58f8dfd53c..fde3b3e8d7 100644
--- a/target/arm/machine.c
+++ b/target/arm/machine.c
@@ -916,7 +916,7 @@ 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 e8f0996ed3..504526153a 100644
--- a/target/arm/tcg/op_helper.c
+++ b/target/arm/tcg/op_helper.c
@@ -402,6 +402,7 @@ 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);
@@ -463,6 +464,7 @@ 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);
@@ -507,6 +509,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 21/71] target/arm: redefine event stream fields
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (19 preceding siblings ...)
2026-06-10 16:11 ` [PULL 20/71] target/arm: teach arm_cpu_has_work about halting reasons Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 22/71] target/arm: ensure aarch64 DISAS_WFE will exit Peter Maydell
` (50 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 c9536d2d10..22e71a2804 100644
--- a/target/arm/helper.c
+++ b/target/arm/helper.c
@@ -1772,9 +1772,9 @@ 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 |
@@ -1789,7 +1789,7 @@ 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 b2035b9417..f7a57d3ea7 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -272,14 +272,17 @@ 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)
@@ -289,7 +292,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 22/71] target/arm: ensure aarch64 DISAS_WFE will exit
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (20 preceding siblings ...)
2026-06-10 16:11 ` [PULL 21/71] target/arm: redefine event stream fields Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 23/71] hw/intc/exynos4210_combiner: Avoid hw_error for guest errors Peter Maydell
` (49 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 092a979198..21ec3a5de7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -11042,25 +11042,25 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 23/71] hw/intc/exynos4210_combiner: Avoid hw_error for guest errors
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (21 preceding siblings ...)
2026-06-10 16:11 ` [PULL 22/71] target/arm: ensure aarch64 DISAS_WFE will exit Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 24/71] hw/dma/pl080: Don't use hw_error() for unimplemented features Peter Maydell
` (48 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 e8cac331e4..dbbdee4d31 100644
--- a/hw/intc/exynos4210_combiner.c
+++ b/hw/intc/exynos4210_combiner.c
@@ -28,12 +28,12 @@
*/
#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"
@@ -119,8 +119,10 @@ 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];
}
@@ -183,20 +185,24 @@ 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;
@@ -245,8 +251,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 24/71] hw/dma/pl080: Don't use hw_error() for unimplemented features
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (22 preceding siblings ...)
2026-06-10 16:11 ` [PULL 23/71] hw/intc/exynos4210_combiner: Avoid hw_error for guest errors Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 25/71] fpu: Handle all rounding modes in partsN_uncanon_normal Peter Maydell
` (47 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 4a90c7bb27..f9f1e3e931 100644
--- a/hw/dma/pl080.c
+++ b/hw/dma/pl080.c
@@ -13,7 +13,6 @@
#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"
@@ -132,8 +131,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 25/71] fpu: Handle all rounding modes in partsN_uncanon_normal
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (23 preceding siblings ...)
2026-06-10 16:11 ` [PULL 24/71] hw/dma/pl080: Don't use hw_error() for unimplemented features Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 26/71] fpu: Handle all rounding modes in partsN_round_to_int_normal Peter Maydell
` (46 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 a154faf32b..c86fc9ccc5 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -437,6 +437,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 26/71] fpu: Handle all rounding modes in partsN_round_to_int_normal
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (24 preceding siblings ...)
2026-06-10 16:11 ` [PULL 25/71] fpu: Handle all rounding modes in partsN_uncanon_normal Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 27/71] target/arm: Use FloatParts64 in bfdotadd_ebf Peter Maydell
` (45 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 c86fc9ccc5..deb712e092 100644
--- a/fpu/softfloat-parts.c.inc
+++ b/fpu/softfloat-parts.c.inc
@@ -1127,6 +1127,7 @@ 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;
@@ -1149,6 +1150,7 @@ 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:
@@ -1195,6 +1197,7 @@ 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:
@@ -1210,6 +1213,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 27/71] target/arm: Use FloatParts64 in bfdotadd_ebf
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (25 preceding siblings ...)
2026-06-10 16:11 ` [PULL 26/71] fpu: Handle all rounding modes in partsN_round_to_int_normal Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 28/71] target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf Peter Maydell
` (44 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 91e98d28ae..12fb62958f 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -22,6 +22,7 @@
#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"
@@ -2895,61 +2896,62 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 28/71] target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (26 preceding siblings ...)
2026-06-10 16:11 ` [PULL 27/71] target/arm: Use FloatParts64 in bfdotadd_ebf Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 29/71] target/arm: Use FloatParts64 in f16_dotadd Peter Maydell
` (43 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 2bfb12c086..a1c08c91d8 100644
--- a/target/arm/tcg/sme_helper.c
+++ b/target/arm/tcg/sme_helper.c
@@ -1429,9 +1429,9 @@ 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 {
@@ -1452,7 +1452,7 @@ 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 12fb62958f..bd8ae5d6a4 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -2845,7 +2845,7 @@ 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.
@@ -2865,11 +2865,7 @@ 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);
@@ -2893,8 +2889,7 @@ 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;
@@ -2964,11 +2959,11 @@ 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) {
@@ -2987,14 +2982,14 @@ 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 {
@@ -3021,17 +3016,16 @@ 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 {
@@ -3054,9 +3048,9 @@ 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;
@@ -3068,20 +3062,20 @@ 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 84f7f15228..06fef2a209 100644
--- a/target/arm/tcg/vec_internal.h
+++ b/target/arm/tcg/vec_internal.h
@@ -271,7 +271,6 @@ 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
@@ -280,23 +279,20 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 29/71] target/arm: Use FloatParts64 in f16_dotadd
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (27 preceding siblings ...)
2026-06-10 16:11 ` [PULL 28/71] target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 30/71] target/arm: Generalize TRANS_FEAT_STREAMING_SME2 Peter Maydell
` (42 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 a1c08c91d8..bd207de755 100644
--- a/target/arm/tcg/sme_helper.c
+++ b/target/arm/tcg/sme_helper.c
@@ -27,6 +27,7 @@
#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"
@@ -1221,18 +1222,15 @@ 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;
@@ -1240,48 +1238,48 @@ 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. */
@@ -1293,9 +1291,6 @@ 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)];
@@ -1319,8 +1314,7 @@ 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;
@@ -1357,15 +1351,12 @@ 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);
}
}
@@ -1379,17 +1370,14 @@ 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);
}
}
}
@@ -1402,24 +1390,19 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 30/71] target/arm: Generalize TRANS_FEAT_STREAMING_SME2
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (28 preceding siblings ...)
2026-06-10 16:11 ` [PULL 29/71] target/arm: Use FloatParts64 in f16_dotadd Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 31/71] target/arm: Introduce arm_init_fp_status Peter Maydell
` (41 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 fb9d379184..997d6b0451 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -4261,9 +4261,9 @@ 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,
@@ -4271,9 +4271,9 @@ 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 37a7268b32..ae3897b456 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -880,12 +880,12 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 31/71] target/arm: Introduce arm_init_fp_status
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (29 preceding siblings ...)
2026-06-10 16:11 ` [PULL 30/71] target/arm: Generalize TRANS_FEAT_STREAMING_SME2 Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 32/71] target/arm: Set e4m3_nan_is_snan Peter Maydell
` (40 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 8771b695d9..10daca0ad6 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -322,6 +322,13 @@ 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);
@@ -644,20 +651,16 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 32/71] target/arm: Set e4m3_nan_is_snan
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (30 preceding siblings ...)
2026-06-10 16:11 ` [PULL 31/71] target/arm: Introduce arm_init_fp_status Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 33/71] target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD Peter Maydell
` (39 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 10daca0ad6..419e0b3ed4 100644
--- a/target/arm/cpu.c
+++ b/target/arm/cpu.c
@@ -326,6 +326,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 33/71] target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (31 preceding siblings ...)
2026-06-10 16:11 ` [PULL 32/71] target/arm: Set e4m3_nan_is_snan Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 34/71] target/arm: Implement BF1CVT, BF1CVTLT, BF2CVT, BF2CVTLT for SVE Peter Maydell
` (38 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 0000000000..c45211ba22
--- /dev/null
+++ b/target/arm/helper-fp8.h
@@ -0,0 +1,14 @@
+/* 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 d8a3269573..e30c7e5ca9 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1921,6 +1921,9 @@ 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 0000000000..bb3e8dae5f
--- /dev/null
+++ b/target/arm/tcg/fp8_helper.c
@@ -0,0 +1,124 @@
+/*
+ * 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 0000000000..0caaf63749
--- /dev/null
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -0,0 +1,6 @@
+/*
+ * 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 9b859892ed..573e8b5af4 100644
--- a/target/arm/tcg/meson.build
+++ b/target/arm/tcg/meson.build
@@ -41,6 +41,7 @@ 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 21ec3a5de7..5e8c86235b 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -22,6 +22,7 @@
#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"
@@ -1461,6 +1462,24 @@ 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.
@@ -10709,6 +10728,21 @@ 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 9c45f89305..35f8d4f82e 100644
--- a/target/arm/tcg/translate-a64.h
+++ b/target/arm/tcg/translate-a64.h
@@ -25,6 +25,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 34/71] target/arm: Implement BF1CVT, BF1CVTLT, BF2CVT, BF2CVTLT for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (32 preceding siblings ...)
2026-06-10 16:11 ` [PULL 33/71] target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 35/71] target/arm: Rename SME BFCVT patterns to BFCVT_hs Peter Maydell
` (37 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 13453bd8f4..e285f57d25 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1668,6 +1668,12 @@ 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 bb3e8dae5f..c62fb2ffd6 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -122,3 +122,19 @@ 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 0caaf63749..18ff483bb0 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -4,3 +4,4 @@
*/
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 078a085a79..e7984fa8e0 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -108,6 +108,7 @@
# 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
@@ -1090,6 +1091,11 @@ 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 997d6b0451..718a21de70 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -21,6 +21,7 @@
#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"
@@ -4068,6 +4069,28 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 35/71] target/arm: Rename SME BFCVT patterns to BFCVT_hs
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (33 preceding siblings ...)
2026-06-10 16:11 ` [PULL 34/71] target/arm: Implement BF1CVT, BF1CVTLT, BF2CVT, BF2CVTLT for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 36/71] target/arm: Implement BF1CVT, BF1CVTL, BF2CVT, BF2CVTL for SME Peter Maydell
` (36 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 c551797c6f..01aad4c231 100644
--- a/target/arm/tcg/helper-sme-defs.h
+++ b/target/arm/tcg/helper-sme-defs.h
@@ -250,7 +250,7 @@ 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 ee874be1a6..7a8e1abb59 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -789,7 +789,7 @@ 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 bd207de755..8e8e6c00ca 100644
--- a/target/arm/tcg/sme_helper.c
+++ b/target/arm/tcg/sme_helper.c
@@ -1725,7 +1725,7 @@ 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 82aa14131b..652a72e972 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1448,8 +1448,8 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 36/71] target/arm: Implement BF1CVT, BF1CVTL, BF2CVT, BF2CVTL for SME
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (34 preceding siblings ...)
2026-06-10 16:11 ` [PULL 35/71] target/arm: Rename SME BFCVT patterns to BFCVT_hs Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 37/71] target/arm: Implement F1CVTL, F1CVTL2, F2CVTL, F2CVTL2 for AdvSIMD Peter Maydell
` (35 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 c62fb2ffd6..aad03b0817 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -138,3 +138,50 @@ 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 18ff483bb0..966f83d796 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -5,3 +5,5 @@
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 7a8e1abb59..df9586c1a5 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -853,6 +853,11 @@ 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 652a72e972..19a13a6506 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -22,6 +22,7 @@
#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"
@@ -1532,6 +1533,24 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 37/71] target/arm: Implement F1CVTL, F1CVTL2, F2CVTL, F2CVTL2 for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (35 preceding siblings ...)
2026-06-10 16:11 ` [PULL 36/71] target/arm: Implement BF1CVT, BF1CVTL, BF2CVT, BF2CVTL for SME Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 38/71] target/arm: Implement F1CVT, F1CVTLT, F2CVT, F2CVTLT for SVE Peter Maydell
` (34 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 e30c7e5ca9..3c806259f9 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1921,6 +1921,9 @@ 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 aad03b0817..0f3c279696 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -103,6 +103,14 @@ 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);
@@ -123,6 +131,27 @@ 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 966f83d796..718463422b 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -7,3 +7,5 @@ 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 5e8c86235b..439a405064 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10740,6 +10740,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 38/71] target/arm: Implement F1CVT, F1CVTLT, F2CVT, F2CVTLT for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (36 preceding siblings ...)
2026-06-10 16:11 ` [PULL 37/71] target/arm: Implement F1CVTL, F1CVTL2, F2CVTL, F2CVTL2 for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 39/71] target/arm: Implement F1CVT, F1CVTL, F2CVT, F2CVTL for SME Peter Maydell
` (33 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 0f3c279696..75c89203fe 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -168,6 +168,22 @@ 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 718463422b..3021dafd44 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -9,3 +9,4 @@ 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 e7984fa8e0..ca110f4bc1 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1091,6 +1091,11 @@ 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 718a21de70..c47e79637e 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -4082,6 +4082,15 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 39/71] target/arm: Implement F1CVT, F1CVTL, F2CVT, F2CVTL for SME
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (37 preceding siblings ...)
2026-06-10 16:11 ` [PULL 38/71] target/arm: Implement F1CVT, F1CVTLT, F2CVT, F2CVTLT for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 40/71] target/arm: Implement BFCVTN for SVE Peter Maydell
` (32 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 75c89203fe..e2330177ec 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -211,6 +211,33 @@ 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);
@@ -230,3 +257,23 @@ 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 3021dafd44..b5dc2b7064 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -10,3 +10,5 @@ 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 df9586c1a5..d6192eb59d 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -853,6 +853,11 @@ 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 19a13a6506..c0fe77242b 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1546,6 +1546,11 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 40/71] target/arm: Implement BFCVTN for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (38 preceding siblings ...)
2026-06-10 16:11 ` [PULL 39/71] target/arm: Implement F1CVT, F1CVTL, F2CVT, F2CVTL for SME Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 41/71] target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD Peter Maydell
` (31 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 e2330177ec..ffeaf02f97 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -72,6 +72,17 @@ 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,
@@ -111,6 +122,64 @@ 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);
@@ -277,3 +346,26 @@ 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 b5dc2b7064..bbc8d69e28 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -12,3 +12,5 @@ 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 ca110f4bc1..b6ef8ed8de 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1101,6 +1101,8 @@ 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 c47e79637e..6b2875a451 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -4100,6 +4100,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 41/71] target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (39 preceding siblings ...)
2026-06-10 16:11 ` [PULL 40/71] target/arm: Implement BFCVTN for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 42/71] target/arm: Implement FCVTN, FCVTN2 (32- " Peter Maydell
` (30 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 3c806259f9..b08895d917 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1212,6 +1212,8 @@ 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 ffeaf02f97..8e7982a888 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -180,6 +180,13 @@ 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);
@@ -369,3 +376,33 @@ 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 bbc8d69e28..6530d1a6da 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -14,3 +14,5 @@ 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 439a405064..538b318415 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -6619,6 +6619,21 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 42/71] target/arm: Implement FCVTN, FCVTN2 (32- to 8-bit fp) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (40 preceding siblings ...)
2026-06-10 16:11 ` [PULL 41/71] target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 43/71] target/arm: Implement FCVTN (16- to 8-bit fp) for SVE Peter Maydell
` (29 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b08895d917..610047846f 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1213,6 +1213,7 @@ 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 8e7982a888..0b86ed9eb9 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -187,6 +187,13 @@ 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);
@@ -406,3 +413,29 @@ 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 6530d1a6da..023a49e12f 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -16,3 +16,5 @@ 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 538b318415..5606f610c8 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -6634,6 +6634,22 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 43/71] target/arm: Implement FCVTN (16- to 8-bit fp) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (41 preceding siblings ...)
2026-06-10 16:11 ` [PULL 42/71] target/arm: Implement FCVTN, FCVTN2 (32- " Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 44/71] target/arm: Implement FCVTNB, FCVTNT " Peter Maydell
` (28 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 0b86ed9eb9..8295725b83 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -414,6 +414,29 @@ 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 023a49e12f..e67fb191c2 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -16,5 +16,6 @@ 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 b6ef8ed8de..806953bc35 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1101,6 +1101,7 @@ 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 6b2875a451..446fedb5b9 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -4100,6 +4100,8 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 44/71] target/arm: Implement FCVTNB, FCVTNT for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (42 preceding siblings ...)
2026-06-10 16:11 ` [PULL 43/71] target/arm: Implement FCVTN (16- to 8-bit fp) for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 45/71] target/arm: Implement FCVT (FP16 to FP8) for SME Peter Maydell
` (27 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 8295725b83..3bd57ff350 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -462,3 +462,50 @@ 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 e67fb191c2..5863a6dbb8 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -19,3 +19,5 @@ 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 806953bc35..72755b27af 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1103,6 +1103,8 @@ 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 446fedb5b9..065f16d899 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -4104,6 +4104,10 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 45/71] target/arm: Implement FCVT (FP16 to FP8) for SME
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (43 preceding siblings ...)
2026-06-10 16:11 ` [PULL 44/71] target/arm: Implement FCVTNB, FCVTNT " Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 46/71] target/arm: Implement FCVT, FCVTN (FP32 " Peter Maydell
` (26 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 d6192eb59d..a02bcc0e22 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -863,6 +863,8 @@ 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 c0fe77242b..49eee95d88 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1556,6 +1556,22 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 46/71] target/arm: Implement FCVT, FCVTN (FP32 to FP8) for SME
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (44 preceding siblings ...)
2026-06-10 16:11 ` [PULL 45/71] target/arm: Implement FCVT (FP16 to FP8) for SME Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 47/71] target/arm: Implement LUTI2, LUTI4 for AdvSIMD Peter Maydell
` (25 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 3bd57ff350..a39dc6f859 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -509,3 +509,62 @@ 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 5863a6dbb8..36ae977431 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -21,3 +21,5 @@ 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 a02bcc0e22..2b9e41a75a 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -865,6 +865,9 @@ 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 49eee95d88..76bbacfb6e 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1572,6 +1572,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 47/71] target/arm: Implement LUTI2, LUTI4 for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (45 preceding siblings ...)
2026-06-10 16:11 ` [PULL 46/71] target/arm: Implement FCVT, FCVTN (FP32 " Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 48/71] target/arm: Implement LUTI2, LUTI4 for SVE Peter Maydell
` (24 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 610047846f..2d06f14e1d 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1355,6 +1355,12 @@ 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 a05f2258f2..05ccf795e8 100644
--- a/target/arm/tcg/helper-defs.h
+++ b/target/arm/tcg/helper-defs.h
@@ -1122,3 +1122,8 @@ 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 5606f610c8..ffd505601c 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -5502,6 +5502,44 @@ 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 bd8ae5d6a4..f4ff56e034 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -3344,3 +3344,55 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 48/71] target/arm: Implement LUTI2, LUTI4 for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (46 preceding siblings ...)
2026-06-10 16:11 ` [PULL 47/71] target/arm: Implement LUTI2, LUTI4 for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 49/71] target/arm: Enable FEAT_LUT for -cpu max Peter Maydell
` (23 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 e285f57d25..8770fce2fa 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1674,6 +1674,12 @@ 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 72755b27af..e2106fc7f5 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -31,6 +31,7 @@
%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
@@ -1737,11 +1738,19 @@ 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 ffd505601c..25579d4ba0 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -10917,6 +10917,7 @@ 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 065f16d899..0e0bc4cbfe 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8287,3 +8287,71 @@ 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 ae3897b456..462d4c1c74 100644
--- a/target/arm/tcg/translate.h
+++ b/target/arm/tcg/translate.h
@@ -91,6 +91,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 49/71] target/arm: Enable FEAT_LUT for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (47 preceding siblings ...)
2026-06-10 16:11 ` [PULL 48/71] target/arm: Implement LUTI2, LUTI4 for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 50/71] target/arm: Enable FEAT_FP8 " Peter Maydell
` (22 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 df82b7f44b..1328cce15c 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -102,6 +102,7 @@ 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 228b593316..5ed7a7badb 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -221,6 +221,7 @@ 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 c7b1dd2e90..234368ba7a 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1263,6 +1263,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 50/71] target/arm: Enable FEAT_FP8 for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (48 preceding siblings ...)
2026-06-10 16:11 ` [PULL 49/71] target/arm: Enable FEAT_LUT for -cpu max Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 51/71] target/arm: Update ID_AA64SMFR0_EL1 fields to ARM M.b Peter Maydell
` (21 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 1328cce15c..b8f452f2f9 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -75,6 +75,7 @@ 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 5ed7a7badb..1c0c404b7c 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -222,6 +222,9 @@ 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 234368ba7a..7a6f1c6601 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1397,6 +1397,12 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 51/71] target/arm: Update ID_AA64SMFR0_EL1 fields to ARM M.b
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (49 preceding siblings ...)
2026-06-10 16:11 ` [PULL 50/71] target/arm: Enable FEAT_FP8 " Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 52/71] target/arm: Implement MOVT (vector to table) Peter Maydell
` (20 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 8770fce2fa..f85368a002 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -397,17 +397,28 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 52/71] target/arm: Implement MOVT (vector to table)
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (50 preceding siblings ...)
2026-06-10 16:11 ` [PULL 51/71] target/arm: Update ID_AA64SMFR0_EL1 fields to ARM M.b Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 53/71] target/arm: Implement LUTI4 (four registers, 8-bit) Peter Maydell
` (19 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 f85368a002..db1bdb4786 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1595,6 +1595,11 @@ 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 2b9e41a75a..339de72b8a 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -141,6 +141,8 @@ 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 76bbacfb6e..c4bede2ae3 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -391,6 +391,24 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 53/71] target/arm: Implement LUTI4 (four registers, 8-bit)
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (51 preceding siblings ...)
2026-06-10 16:11 ` [PULL 52/71] target/arm: Implement MOVT (vector to table) Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 54/71] target/arm: Enable FEAT_SME_LUTv2 for -cpu max Peter Maydell
` (18 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 db1bdb4786..11e8c7a57c 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1668,6 +1668,11 @@ 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 05ccf795e8..8ec6c16319 100644
--- a/target/arm/tcg/helper-defs.h
+++ b/target/arm/tcg/helper-defs.h
@@ -1120,6 +1120,7 @@ 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 339de72b8a..495330aed7 100644
--- a/target/arm/tcg/sme.decode
+++ b/target/arm/tcg/sme.decode
@@ -1014,8 +1014,14 @@ 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 c4bede2ae3..98d3d18791 100644
--- a/target/arm/tcg/translate-sme.c
+++ b/target/arm/tcg/translate-sme.c
@@ -1846,6 +1846,9 @@ 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);
@@ -1866,3 +1869,6 @@ 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 f4ff56e034..3c06e93e02 100644
--- a/target/arm/tcg/vec_helper.c
+++ b/target/arm/tcg/vec_helper.c
@@ -3345,6 +3345,20 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 54/71] target/arm: Enable FEAT_SME_LUTv2 for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (52 preceding siblings ...)
2026-06-10 16:11 ` [PULL 53/71] target/arm: Implement LUTI4 (four registers, 8-bit) Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 55/71] target/arm: Implement FMLALB, FMLALT for AdvSIMD Peter Maydell
` (17 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b8f452f2f9..9ff4473154 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -165,6 +165,7 @@ 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 1c0c404b7c..06c14e82ea 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -222,6 +222,7 @@ 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 7a6f1c6601..7f79ee645b 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1394,6 +1394,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 55/71] target/arm: Implement FMLALB, FMLALT for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (53 preceding siblings ...)
2026-06-10 16:11 ` [PULL 54/71] target/arm: Enable FEAT_SME_LUTv2 for -cpu max Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 56/71] target/arm: Implement FMLALB, FMLALT (FP8 to FP16) for SVE Peter Maydell
` (16 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 11e8c7a57c..b905ec1bdc 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1615,6 +1615,11 @@ 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 2d06f14e1d..715d5f05d8 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -25,6 +25,7 @@
%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
@@ -38,6 +39,7 @@
&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
@@ -1215,6 +1217,9 @@ 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
@@ -1333,6 +1338,9 @@ 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 a39dc6f859..71d30aa33a 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -568,3 +568,109 @@ 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 36ae977431..7aa8366d94 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -23,3 +23,6 @@ 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 25579d4ba0..30715cbd65 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7481,6 +7481,22 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 56/71] target/arm: Implement FMLALB, FMLALT (FP8 to FP16) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (54 preceding siblings ...)
2026-06-10 16:11 ` [PULL 55/71] target/arm: Implement FMLALB, FMLALT for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 57/71] target/arm: Implement FMLALL{BB, BT, TB, TT} for AdvSIMD Peter Maydell
` (15 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 b905ec1bdc..9af4ab239c 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1570,6 +1570,11 @@ 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 e2106fc7f5..71ec09393c 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -29,6 +29,7 @@
%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
@@ -73,6 +74,7 @@
&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
@@ -1864,6 +1866,8 @@ 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
@@ -1880,6 +1884,9 @@ 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 0e0bc4cbfe..453bae3a0e 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8355,3 +8355,36 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 57/71] target/arm: Implement FMLALL{BB, BT, TB, TT} for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (55 preceding siblings ...)
2026-06-10 16:11 ` [PULL 56/71] target/arm: Implement FMLALB, FMLALT (FP8 to FP16) for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 58/71] target/arm: Implement FMLALL{BB,BT,TB,TT} for SVE Peter Maydell
` (14 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 715d5f05d8..ee7391a13c 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1220,6 +1220,10 @@ 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
@@ -1341,6 +1345,9 @@ 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 71d30aa33a..ceeb96b9cc 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -630,6 +630,16 @@ 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)
{
@@ -674,3 +684,48 @@ 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 7aa8366d94..802a3b430e 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -26,3 +26,6 @@ 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 30715cbd65..dcc6b5ae6d 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7497,6 +7497,9 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 58/71] target/arm: Implement FMLALL{BB,BT,TB,TT} for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (56 preceding siblings ...)
2026-06-10 16:11 ` [PULL 57/71] target/arm: Implement FMLALL{BB, BT, TB, TT} for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 59/71] target/arm: Enable FEAT_FP8FMA, FEAT_SSVE_FP8FMA for -cpu max Peter Maydell
` (13 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 71ec09393c..06bbd7fa63 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1868,6 +1868,8 @@ 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
@@ -1887,6 +1889,9 @@ 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 453bae3a0e..9f207a32b9 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8388,3 +8388,6 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 59/71] target/arm: Enable FEAT_FP8FMA, FEAT_SSVE_FP8FMA for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (57 preceding siblings ...)
2026-06-10 16:11 ` [PULL 58/71] target/arm: Implement FMLALL{BB,BT,TB,TT} for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 60/71] target/arm: Implement FDOT (FP8 to FP32) for AdvSIMD Peter Maydell
` (12 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 9ff4473154..e46f5fdcd1 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -76,6 +76,7 @@ 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)
@@ -166,6 +167,7 @@ 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 06c14e82ea..a82d65a681 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -226,6 +226,8 @@ 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 7f79ee645b..38c0f0eafd 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1383,6 +1383,7 @@ 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 */
@@ -1401,6 +1402,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 60/71] target/arm: Implement FDOT (FP8 to FP32) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (58 preceding siblings ...)
2026-06-10 16:11 ` [PULL 59/71] target/arm: Enable FEAT_FP8FMA, FEAT_SSVE_FP8FMA for -cpu max Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 61/71] target/arm: Implement FDOT (FP8 to FP32) for SVE Peter Maydell
` (11 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 9af4ab239c..cea1c56cd3 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1625,6 +1625,11 @@ 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 ee7391a13c..08c493c11e 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1224,6 +1224,8 @@ 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
@@ -1348,6 +1350,8 @@ 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 ceeb96b9cc..f54acb03f3 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -729,3 +729,42 @@ 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 802a3b430e..ee6f2e9236 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -29,3 +29,6 @@ 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 dcc6b5ae6d..ce29176cb7 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7500,6 +7500,36 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 61/71] target/arm: Implement FDOT (FP8 to FP32) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (59 preceding siblings ...)
2026-06-10 16:11 ` [PULL 60/71] target/arm: Implement FDOT (FP8 to FP32) for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 62/71] target/arm: Enable FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4 for -cpu max Peter Maydell
` (10 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 cea1c56cd3..911819bbb0 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1575,6 +1575,11 @@ 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 06bbd7fa63..c49e992f10 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1874,6 +1874,8 @@ 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
@@ -1897,6 +1899,8 @@ 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 9f207a32b9..582471b380 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8391,3 +8391,38 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 62/71] target/arm: Enable FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4 for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (60 preceding siblings ...)
2026-06-10 16:11 ` [PULL 61/71] target/arm: Implement FDOT (FP8 to FP32) for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 63/71] target/arm: Implement FDOT (FP8 to FP16) for AdvSIMD Peter Maydell
` (9 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 e46f5fdcd1..f13721c327 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -76,6 +76,7 @@ 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)
@@ -167,6 +168,7 @@ 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 a82d65a681..be33fede6b 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -227,7 +227,9 @@ 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 38c0f0eafd..831b190b21 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1383,6 +1383,7 @@ 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 */
@@ -1402,6 +1403,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 63/71] target/arm: Implement FDOT (FP8 to FP16) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (61 preceding siblings ...)
2026-06-10 16:11 ` [PULL 62/71] target/arm: Enable FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4 for -cpu max Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 64/71] target/arm: Implement FDOT (FP8 to FP16) for SVE Peter Maydell
` (8 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 911819bbb0..caae3e51f3 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1635,6 +1635,11 @@ 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 08c493c11e..a3e404e7fe 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1225,6 +1225,7 @@ 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
@@ -1351,6 +1352,7 @@ 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 f54acb03f3..065df24b84 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -768,3 +768,42 @@ 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 ee6f2e9236..5995d77577 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -32,3 +32,6 @@ 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 ce29176cb7..e4c539fb18 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7514,6 +7514,7 @@ 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)
@@ -7529,6 +7530,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 64/71] target/arm: Implement FDOT (FP8 to FP16) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (62 preceding siblings ...)
2026-06-10 16:11 ` [PULL 63/71] target/arm: Implement FDOT (FP8 to FP16) for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 65/71] target/arm: Enable FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2 for -cpu max Peter Maydell
` (7 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 caae3e51f3..1745989bce 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1580,6 +1580,11 @@ 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 c49e992f10..26b3c7697a 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1875,6 +1875,7 @@ 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)
@@ -1900,6 +1901,7 @@ 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 582471b380..2cc5e129e9 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8426,3 +8426,38 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 65/71] target/arm: Enable FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2 for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (63 preceding siblings ...)
2026-06-10 16:11 ` [PULL 64/71] target/arm: Implement FDOT (FP8 to FP16) for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 66/71] target/arm: Implement FMMLA (FP8 to FP32) for AdvSIMD Peter Maydell
` (6 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 f13721c327..0bcd707fc1 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -76,6 +76,7 @@ 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)
@@ -168,6 +169,7 @@ 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 be33fede6b..d40e39169b 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -228,8 +228,10 @@ 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 831b190b21..3d73977f1e 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1383,6 +1383,7 @@ 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 */
@@ -1403,6 +1404,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 66/71] target/arm: Implement FMMLA (FP8 to FP32) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (64 preceding siblings ...)
2026-06-10 16:11 ` [PULL 65/71] target/arm: Enable FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2 for -cpu max Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 67/71] target/arm: Implement FMMLA (FP8 to FP32) for SVE Peter Maydell
` (5 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 1745989bce..be3db5300f 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1645,6 +1645,11 @@ 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 a3e404e7fe..6922e91010 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1227,6 +1227,8 @@ 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 065df24b84..b9d4ba3b6a 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -807,3 +807,28 @@ 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 5995d77577..3c74f02022 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -35,3 +35,5 @@ 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 e4c539fb18..ffe59b9471 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7515,6 +7515,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 67/71] target/arm: Implement FMMLA (FP8 to FP32) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (65 preceding siblings ...)
2026-06-10 16:11 ` [PULL 66/71] target/arm: Implement FMMLA (FP8 to FP32) for AdvSIMD Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:11 ` [PULL 68/71] target/arm: Enable FEAT_F8F32MM for -cpu max Peter Maydell
` (4 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 be3db5300f..67e9c3bd33 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1718,6 +1718,11 @@ 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 26b3c7697a..6610432528 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1808,6 +1808,8 @@ 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 2cc5e129e9..f6705ee95d 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8461,3 +8461,19 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 68/71] target/arm: Enable FEAT_F8F32MM for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (66 preceding siblings ...)
2026-06-10 16:11 ` [PULL 67/71] target/arm: Implement FMMLA (FP8 to FP32) for SVE Peter Maydell
@ 2026-06-10 16:11 ` Peter Maydell
2026-06-10 16:12 ` [PULL 69/71] target/arm: Implement FMMLA (FP8 to FP16) for AdvSIMD Peter Maydell
` (3 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:11 UTC (permalink / raw)
To: qemu-devel
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 0bcd707fc1..56da6baed9 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -67,6 +67,7 @@ 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 d40e39169b..7864765ba0 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -171,6 +171,7 @@ 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 3d73977f1e..0f2ce592d1 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1404,6 +1404,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 69/71] target/arm: Implement FMMLA (FP8 to FP16) for AdvSIMD
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (67 preceding siblings ...)
2026-06-10 16:11 ` [PULL 68/71] target/arm: Enable FEAT_F8F32MM for -cpu max Peter Maydell
@ 2026-06-10 16:12 ` Peter Maydell
2026-06-10 16:12 ` [PULL 70/71] target/arm: Implement FMMLA (FP8 to FP16) for SVE Peter Maydell
` (2 subsequent siblings)
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:12 UTC (permalink / raw)
To: qemu-devel
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 67e9c3bd33..753799008c 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1650,6 +1650,11 @@ 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 6922e91010..28cd1faf61 100644
--- a/target/arm/tcg/a64.decode
+++ b/target/arm/tcg/a64.decode
@@ -1228,6 +1228,7 @@ 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 b9d4ba3b6a..bd0877071b 100644
--- a/target/arm/tcg/fp8_helper.c
+++ b/target/arm/tcg/fp8_helper.c
@@ -832,3 +832,28 @@ 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 3c74f02022..e942308af4 100644
--- a/target/arm/tcg/helper-fp8-defs.h
+++ b/target/arm/tcg/helper-fp8-defs.h
@@ -37,3 +37,4 @@ 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 ffe59b9471..227719ef25 100644
--- a/target/arm/tcg/translate-a64.c
+++ b/target/arm/tcg/translate-a64.c
@@ -7516,6 +7516,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 70/71] target/arm: Implement FMMLA (FP8 to FP16) for SVE
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (68 preceding siblings ...)
2026-06-10 16:12 ` [PULL 69/71] target/arm: Implement FMMLA (FP8 to FP16) for AdvSIMD Peter Maydell
@ 2026-06-10 16:12 ` Peter Maydell
2026-06-10 16:12 ` [PULL 71/71] target/arm: Enable FEAT_F8F16MM for -cpu max Peter Maydell
2026-06-11 19:16 ` [PULL 00/71] target-arm queue Stefan Hajnoczi
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:12 UTC (permalink / raw)
To: qemu-devel
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 753799008c..9e70d30964 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -1728,6 +1728,11 @@ 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 6610432528..b53fe6a58f 100644
--- a/target/arm/tcg/sve.decode
+++ b/target/arm/tcg/sve.decode
@@ -1809,6 +1809,7 @@ 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 f6705ee95d..a85558bdaa 100644
--- a/target/arm/tcg/translate-sve.c
+++ b/target/arm/tcg/translate-sve.c
@@ -8477,3 +8477,5 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* [PULL 71/71] target/arm: Enable FEAT_F8F16MM for -cpu max
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (69 preceding siblings ...)
2026-06-10 16:12 ` [PULL 70/71] target/arm: Implement FMMLA (FP8 to FP16) for SVE Peter Maydell
@ 2026-06-10 16:12 ` Peter Maydell
2026-06-11 19:16 ` [PULL 00/71] target-arm queue Stefan Hajnoczi
71 siblings, 0 replies; 73+ messages in thread
From: Peter Maydell @ 2026-06-10 16:12 UTC (permalink / raw)
To: qemu-devel
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 56da6baed9..a8072ddb67 100644
--- a/docs/system/arm/emulation.rst
+++ b/docs/system/arm/emulation.rst
@@ -67,6 +67,7 @@ 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 7864765ba0..4887a3a7b7 100644
--- a/linux-user/aarch64/elfload.c
+++ b/linux-user/aarch64/elfload.c
@@ -172,6 +172,7 @@ 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 0f2ce592d1..f7a920a202 100644
--- a/target/arm/tcg/cpu64.c
+++ b/target/arm/tcg/cpu64.c
@@ -1404,6 +1404,7 @@ 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
^ permalink raw reply related [flat|nested] 73+ messages in thread
* Re: [PULL 00/71] target-arm queue
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
` (70 preceding siblings ...)
2026-06-10 16:12 ` [PULL 71/71] target/arm: Enable FEAT_F8F16MM for -cpu max Peter Maydell
@ 2026-06-11 19:16 ` Stefan Hajnoczi
71 siblings, 0 replies; 73+ messages in thread
From: Stefan Hajnoczi @ 2026-06-11 19:16 UTC (permalink / raw)
To: Peter Maydell; +Cc: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 116 bytes --]
Applied, thanks.
Please update the changelog at https://wiki.qemu.org/ChangeLog/11.1 for any user-visible changes.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 73+ messages in thread
end of thread, other threads:[~2026-06-11 19:17 UTC | newest]
Thread overview: 73+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-10 16:10 [PULL 00/71] target-arm queue Peter Maydell
2026-06-10 16:10 ` [PULL 01/71] hw/core/qdev-clock: Fix potential null pointer dereference Peter Maydell
2026-06-10 16:10 ` [PULL 02/71] target/arm: implement MTE_PERM Peter Maydell
2026-06-10 16:10 ` [PULL 03/71] target/arm: add TCSO bitmasks to SCTLR Peter Maydell
2026-06-10 16:10 ` [PULL 04/71] target/arm: mte_check unemitted on STORE_ONLY load Peter Maydell
2026-06-10 16:10 ` [PULL 05/71] linux-user: add MTE_STORE_ONLY to prctl Peter Maydell
2026-06-10 16:10 ` [PULL 06/71] target/arm: emit tag check when MTX without TBI Peter Maydell
2026-06-10 16:10 ` [PULL 07/71] target/arm: add MTX to MTEDESC and DisasContext Peter Maydell
2026-06-10 16:10 ` [PULL 08/71] target/arm: add canonical tag check helper Peter Maydell
2026-06-10 16:11 ` [PULL 09/71] target/arm: add canonical MTE check logic Peter Maydell
2026-06-10 16:11 ` [PULL 10/71] target/arm: load on canonical tag loads ext bits Peter Maydell
2026-06-10 16:11 ` [PULL 11/71] target/arm: fault on tag store to canonical tag Peter Maydell
2026-06-10 16:11 ` [PULL 12/71] target/arm: skip tag bit bounds check if MTX is on Peter Maydell
2026-06-10 16:11 ` [PULL 13/71] target/arm: tag is not a part of PAuth with MTX Peter Maydell
2026-06-10 16:11 ` [PULL 14/71] docs: add MTE4 features to docs Peter Maydell
2026-06-10 16:11 ` [PULL 15/71] tests/tcg: add test for MTE FAR Peter Maydell
2026-06-10 16:11 ` [PULL 16/71] tests/tcg: add test for MTE_STORE_ONLY Peter Maydell
2026-06-10 16:11 ` [PULL 17/71] hw/usb/hcd-ohci: Assert isochronous TDs are never deferred Peter Maydell
2026-06-10 16:11 ` [PULL 18/71] hw/usb/hcd-ohci: Clean up USBPacket before freeing ISO TD packet Peter Maydell
2026-06-10 16:11 ` [PULL 19/71] target/arm: fix WFET typo in syndrome Peter Maydell
2026-06-10 16:11 ` [PULL 20/71] target/arm: teach arm_cpu_has_work about halting reasons Peter Maydell
2026-06-10 16:11 ` [PULL 21/71] target/arm: redefine event stream fields Peter Maydell
2026-06-10 16:11 ` [PULL 22/71] target/arm: ensure aarch64 DISAS_WFE will exit Peter Maydell
2026-06-10 16:11 ` [PULL 23/71] hw/intc/exynos4210_combiner: Avoid hw_error for guest errors Peter Maydell
2026-06-10 16:11 ` [PULL 24/71] hw/dma/pl080: Don't use hw_error() for unimplemented features Peter Maydell
2026-06-10 16:11 ` [PULL 25/71] fpu: Handle all rounding modes in partsN_uncanon_normal Peter Maydell
2026-06-10 16:11 ` [PULL 26/71] fpu: Handle all rounding modes in partsN_round_to_int_normal Peter Maydell
2026-06-10 16:11 ` [PULL 27/71] target/arm: Use FloatParts64 in bfdotadd_ebf Peter Maydell
2026-06-10 16:11 ` [PULL 28/71] target/arm: Drop oddstatus from is_ebf and bfdotadd_ebf Peter Maydell
2026-06-10 16:11 ` [PULL 29/71] target/arm: Use FloatParts64 in f16_dotadd Peter Maydell
2026-06-10 16:11 ` [PULL 30/71] target/arm: Generalize TRANS_FEAT_STREAMING_SME2 Peter Maydell
2026-06-10 16:11 ` [PULL 31/71] target/arm: Introduce arm_init_fp_status Peter Maydell
2026-06-10 16:11 ` [PULL 32/71] target/arm: Set e4m3_nan_is_snan Peter Maydell
2026-06-10 16:11 ` [PULL 33/71] target/arm: Implement BF1CVTL, BF1CVTL2, BF2CVTL, BF2CVTL2 for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 34/71] target/arm: Implement BF1CVT, BF1CVTLT, BF2CVT, BF2CVTLT for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 35/71] target/arm: Rename SME BFCVT patterns to BFCVT_hs Peter Maydell
2026-06-10 16:11 ` [PULL 36/71] target/arm: Implement BF1CVT, BF1CVTL, BF2CVT, BF2CVTL for SME Peter Maydell
2026-06-10 16:11 ` [PULL 37/71] target/arm: Implement F1CVTL, F1CVTL2, F2CVTL, F2CVTL2 for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 38/71] target/arm: Implement F1CVT, F1CVTLT, F2CVT, F2CVTLT for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 39/71] target/arm: Implement F1CVT, F1CVTL, F2CVT, F2CVTL for SME Peter Maydell
2026-06-10 16:11 ` [PULL 40/71] target/arm: Implement BFCVTN for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 41/71] target/arm: Implement FCVTN (16- to 8-bit fp) for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 42/71] target/arm: Implement FCVTN, FCVTN2 (32- " Peter Maydell
2026-06-10 16:11 ` [PULL 43/71] target/arm: Implement FCVTN (16- to 8-bit fp) for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 44/71] target/arm: Implement FCVTNB, FCVTNT " Peter Maydell
2026-06-10 16:11 ` [PULL 45/71] target/arm: Implement FCVT (FP16 to FP8) for SME Peter Maydell
2026-06-10 16:11 ` [PULL 46/71] target/arm: Implement FCVT, FCVTN (FP32 " Peter Maydell
2026-06-10 16:11 ` [PULL 47/71] target/arm: Implement LUTI2, LUTI4 for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 48/71] target/arm: Implement LUTI2, LUTI4 for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 49/71] target/arm: Enable FEAT_LUT for -cpu max Peter Maydell
2026-06-10 16:11 ` [PULL 50/71] target/arm: Enable FEAT_FP8 " Peter Maydell
2026-06-10 16:11 ` [PULL 51/71] target/arm: Update ID_AA64SMFR0_EL1 fields to ARM M.b Peter Maydell
2026-06-10 16:11 ` [PULL 52/71] target/arm: Implement MOVT (vector to table) Peter Maydell
2026-06-10 16:11 ` [PULL 53/71] target/arm: Implement LUTI4 (four registers, 8-bit) Peter Maydell
2026-06-10 16:11 ` [PULL 54/71] target/arm: Enable FEAT_SME_LUTv2 for -cpu max Peter Maydell
2026-06-10 16:11 ` [PULL 55/71] target/arm: Implement FMLALB, FMLALT for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 56/71] target/arm: Implement FMLALB, FMLALT (FP8 to FP16) for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 57/71] target/arm: Implement FMLALL{BB, BT, TB, TT} for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 58/71] target/arm: Implement FMLALL{BB,BT,TB,TT} for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 59/71] target/arm: Enable FEAT_FP8FMA, FEAT_SSVE_FP8FMA for -cpu max Peter Maydell
2026-06-10 16:11 ` [PULL 60/71] target/arm: Implement FDOT (FP8 to FP32) for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 61/71] target/arm: Implement FDOT (FP8 to FP32) for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 62/71] target/arm: Enable FEAT_FP8DOT4, FEAT_SSVE_FP8DOT4 for -cpu max Peter Maydell
2026-06-10 16:11 ` [PULL 63/71] target/arm: Implement FDOT (FP8 to FP16) for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 64/71] target/arm: Implement FDOT (FP8 to FP16) for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 65/71] target/arm: Enable FEAT_FP8DOT2, FEAT_SSVE_FP8DOT2 for -cpu max Peter Maydell
2026-06-10 16:11 ` [PULL 66/71] target/arm: Implement FMMLA (FP8 to FP32) for AdvSIMD Peter Maydell
2026-06-10 16:11 ` [PULL 67/71] target/arm: Implement FMMLA (FP8 to FP32) for SVE Peter Maydell
2026-06-10 16:11 ` [PULL 68/71] target/arm: Enable FEAT_F8F32MM for -cpu max Peter Maydell
2026-06-10 16:12 ` [PULL 69/71] target/arm: Implement FMMLA (FP8 to FP16) for AdvSIMD Peter Maydell
2026-06-10 16:12 ` [PULL 70/71] target/arm: Implement FMMLA (FP8 to FP16) for SVE Peter Maydell
2026-06-10 16:12 ` [PULL 71/71] target/arm: Enable FEAT_F8F16MM for -cpu max Peter Maydell
2026-06-11 19:16 ` [PULL 00/71] target-arm queue Stefan Hajnoczi
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.