From: Paul Floyd Date: Sat, 16 May 2026 09:16:36 +0000 (+0200) Subject: Bug 487418 - [arm64] Cleanup M{SR,RS} instructions (part 2) X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;h=ffbfa6ce4fd5417d1c672abf9cfd9ccf4b669415;p=thirdparty%2Fvalgrind.git Bug 487418 - [arm64] Cleanup M{SR,RS} instructions (part 2) Extracts system register shift and mask macros to a new VEX public header libvex_guest_arm64_sysregs.h These macros are used in both VEX dirty helpers and coregrind VG_(machine_get_hwcaps). Mostly this is just refactoring the code. It should be more robust in the face of changes concerning future ARM CPU features. The id_aa64pfr0_el1 dirty helper has changed a bit - the code was wrong but the output was right (for what we currently support). --- diff --git a/VEX/Makefile.am b/VEX/Makefile.am index ca50e0df2..59ce63c15 100644 --- a/VEX/Makefile.am +++ b/VEX/Makefile.am @@ -23,6 +23,7 @@ pkginclude_HEADERS = \ pub/libvex_guest_ppc64.h \ pub/libvex_guest_arm.h \ pub/libvex_guest_arm64.h \ + pub/libvex_guest_arm64_sysregs.h \ pub/libvex_guest_s390x.h \ pub/libvex_guest_mips32.h \ pub/libvex_guest_mips64.h \ diff --git a/VEX/priv/guest_arm64_helpers.c b/VEX/priv/guest_arm64_helpers.c index 7bd99ec5f..d0f8b24b5 100644 --- a/VEX/priv/guest_arm64_helpers.c +++ b/VEX/priv/guest_arm64_helpers.c @@ -29,6 +29,7 @@ #include "libvex_basictypes.h" #include "libvex_emnote.h" #include "libvex_guest_arm64.h" +#include "libvex_guest_arm64_sysregs.h" #include "libvex_ir.h" #include "libvex.h" @@ -776,6 +777,7 @@ ULong arm64g_calc_crc32cx ( ULong acc, ULong bits ) return crc; } + /* CALLED FROM GENERATED CODE */ /* DIRTY HELPER (non-referentially-transparent) */ /* Horrible hack. On non-arm64 platforms, return 0. */ @@ -828,27 +830,18 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64PFR0_EL1 ( void ) ULong w = 0x5555555555555555ULL; /* overwritten */ __asm__ __volatile__("mrs %0, id_aa64pfr0_el1" : "=r"(w)); - // The control word uses the following nibbles (as seen on RPi) - // unsupported unless indicated - // 0 to 3 - EL0 to EL3 exception level handling - // 4 - FP includes half-precision (partial support) - // 5 - AdvSIMD also includes haf-precision - - /* If half-precision fp is present we fall back to normal - half precision implementation because of missing support in the emulation. - If no AdvSIMD and FP are implemented, we preserve the value */ - w = (w >> 16); - w &= 0xff; - switch(w) { - case 0x01: - w = 0x0; - break; - case 0xff: - w = (0xFF<<16); - break; - default: - w = 0x0; - break; + MASK_SYSTEM_REGISTER_FIELDS(w, + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_EL0_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_EL1_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_FP_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64PFR0_ADVSIMD_SHIFT)); + + if (SYSTEM_REGISTER_FIELD(w, ID_AA64PFR0_FP_SHIFT) != ID_AA64PFR0_FP_NOT_PRESENT) { + CLAMP_REGISTER_FIELD_INPLACE(w, ID_AA64PFR0_FP_SHIFT, ID_AA64PFR0_FP_NHP_SUPPORTED); + } + + if (SYSTEM_REGISTER_FIELD(w, ID_AA64PFR0_ADVSIMD_SHIFT) != ID_AA64PFR0_ADVSIMD_NOT_PRESENT) { + CLAMP_REGISTER_FIELD_INPLACE(w, ID_AA64PFR0_ADVSIMD_SHIFT, ID_AA64PFR0_ADVSIMD_NHP_SUPPORTED); } return w; @@ -880,8 +873,23 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64MMFR1_EL1 ( void ) ULong w = 0x5555555555555555ULL; /* overwritten */ __asm__ __volatile__("mrs %0, id_aa64mmfr1_el1" : "=r"(w)); - /* Clear VH and HAFDBS bits */ - w &= ~(0xF0F); + // FIXME PJF we were just filtering out ID_AA64MMFR1_HAFDB and ID_AA64MMFR1_VH + // do we really support all of these? + MASK_SYSTEM_REGISTER_FIELDS(w, + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_VMIDBITS_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_HPDS_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_LO_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_PAN_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_SPECSEI_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_XNX_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_TWED_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_ETS_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_HCX_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_AFP_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_NTLBPA_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_TIDCP1_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64MMFR1_CMOW_SHIFT)); + return w; # else return 0ULL; @@ -897,23 +905,14 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR0_EL1 ( void ) ULong w = 0x5555555555555555ULL; /* overwritten */ __asm__ __volatile__("mrs %0, id_aa64isar0_el1" : "=r"(w)); - // In the mask below, nibbles are (higher nibbles all unsupported) - // 0 - RES0 - // 1 - AES - // 2 - SHA1 - // 3 - SHA2 - // 4 - CRC32 - // 5 - Atomic bits - // 6 - TME (unsupported) - // 7 - RDM - // 8 - SHA3 (unsupported) - // 9 - SM3 (unsupported) - // 10 - SM4 (unsupported) - // 11 - DP - - // 10 - // 109876543210 - w &= 0xF000F0FFFFFF; + MASK_SYSTEM_REGISTER_FIELDS(w, + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_AES_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_SHA1_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_SHA2_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_CRC32_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_ATOMICS_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_RDM_SHIFT) | + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR0_DP_SHIFT)); return w; # else @@ -930,8 +929,8 @@ ULong arm64g_dirtyhelper_MRS_ID_AA64ISAR1_EL1 ( void ) ULong w = 0x5555555555555555ULL; /* overwritten */ __asm__ __volatile__("mrs %0, id_aa64isar1_el1" : "=r"(w)); - // only nibble 0 DBP - w &= 0xF; + MASK_SYSTEM_REGISTER_FIELDS(w, + MAKE_SYSTEM_REGISTER_MASK_FIELD(ID_AA64ISAR1_DPB_SHIFT)); return w; # else diff --git a/VEX/pub/libvex_guest_arm64_sysregs.h b/VEX/pub/libvex_guest_arm64_sysregs.h new file mode 100644 index 000000000..8b9f4974f --- /dev/null +++ b/VEX/pub/libvex_guest_arm64_sysregs.h @@ -0,0 +1,137 @@ +/*---------------------------------------------------------------*/ +/*--- begin libvex_guest_arm64_sysregs.h ---*/ +/*---------------------------------------------------------------*/ + +/* + This file is part of Valgrind, a dynamic binary instrumentation + framework. + + Copyright (C) 2026 Paul Floyd + pjfloyd@wanadoo.fr + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, see . + + The GNU General Public License is contained in the file COPYING. +*/ + +#ifndef __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H +#define __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H + +/*---------------------------------------------------------------*/ +/*--- arm64 system register field definitions ---*/ +/*---------------------------------------------------------------*/ + +/* These definitions are used when reading system registers + * to mask unsupported fields. They are also used by Valgrind + * during startup when determining hardware capabilities. */ + +/* ID_AA64ISAR0_EL1 Instruction set attribute register 0 fields */ +#define ID_AA64ISAR0_FHM_SHIFT 48 +#define ID_AA64ISAR0_DP_SHIFT 44 +#define ID_AA64ISAR0_SM4_SHIFT 40 +#define ID_AA64ISAR0_SM3_SHIFT 36 +#define ID_AA64ISAR0_SHA3_SHIFT 32 +#define ID_AA64ISAR0_RDM_SHIFT 28 +#define ID_AA64ISAR0_ATOMICS_SHIFT 20 +#define ID_AA64ISAR0_CRC32_SHIFT 16 +#define ID_AA64ISAR0_SHA2_SHIFT 12 +#define ID_AA64ISAR0_SHA1_SHIFT 8 +#define ID_AA64ISAR0_AES_SHIFT 4 +#define ID_AA64ISAR0_RES0_SHIFT 0 +/* Field values */ +#define ID_AA64ISAR0_FHM_SUPPORTED 0x1 +#define ID_AA64ISAR0_DP_SUPPORTED 0x1 +#define ID_AA64ISAR0_SM4_SUPPORTED 0x1 +#define ID_AA64ISAR0_SM3_SUPPORTED 0x1 +#define ID_AA64ISAR0_SHA3_SUPPORTED 0x1 +#define ID_AA64ISAR0_RDM_SUPPORTED 0x1 +#define ID_AA64ISAR0_ATOMICS_SUPPORTED 0x2 + +/* ID_AA64ISAR1_EL1 Instruction set attribute register 1 fields */ +#define ID_AA64ISAR1_I8MM_SHIFT 52 +#define ID_AA64ISAR1_BF16_SHIFT 44 +#define ID_AA64ISAR1_DPB_SHIFT 0 +/* Field values */ +#define ID_AA64ISAR1_I8MM_SUPPORTED 0x1 +#define ID_AA64ISAR1_BF16_SUPPORTED 0x1 +#define ID_AA64ISAR1_DPBCVAP_SUPPORTED 0x1 +#define ID_AA64ISAR1_DPBCVADP_SUPPORTED 0x2 + +/* ID_AA64PFR0_EL1 Processor feature register 0 fields */ +#define ID_AA64PFR0_CSV3_SHIFT 60 +#define ID_AA64PFR0_CSV2_SHIFT 56 +#define ID_AA64PFR0_RME_SHIFT 52 +#define ID_AA64PFR0_DIT_SHIFT 48 +#define ID_AA64PFR0_AMU_SHIFT 44 +#define ID_AA64PFR0_MPAM_SHIFT 40 +#define ID_AA64PFR0_SEL2_SHIFT 36 +#define ID_AA64PFR0_SVE_SHIFT 32 +#define ID_AA64PFR0_RAS_SHIFT 28 +#define ID_AA64PFR0_GIC_SHIFT 24 +#define ID_AA64PFR0_ADVSIMD_SHIFT 20 +#define ID_AA64PFR0_FP_SHIFT 16 +#define ID_AA64PFR0_EL3_SHIFT 12 +#define ID_AA64PFR0_EL2_SHIFT 8 +#define ID_AA64PFR0_EL1_SHIFT 4 +#define ID_AA64PFR0_EL0_SHIFT 0 +/* Field values */ +#define ID_AA64PFR0_FP_NHP_SUPPORTED 0x0 /* FP but no half precision */ +#define ID_AA64PFR0_FP_HP_SUPPORTED 0x1 /* FP and half precision */ +#define ID_AA64PFR0_FP_NOT_PRESENT 0xf /* no FP present */ +#define ID_AA64PFR0_ADVSIMD_NHP_SUPPORTED 0x0 +#define ID_AA64PFR0_ADVSIMD_HP_SUPPORTED 0x1 +#define ID_AA64PFR0_ADVSIMD_NOT_PRESENT 0xf + +/* ID_AA64MMFR1_EL1 memory model feature register */ +#define ID_AA64MMFR1_RES0_SHIFT 60 +#define ID_AA64MMFR1_CMOW_SHIFT 56 +#define ID_AA64MMFR1_TIDCP1_SHIFT 52 +#define ID_AA64MMFR1_NTLBPA_SHIFT 48 +#define ID_AA64MMFR1_AFP_SHIFT 44 +#define ID_AA64MMFR1_HCX_SHIFT 40 +#define ID_AA64MMFR1_ETS_SHIFT 36 +#define ID_AA64MMFR1_TWED_SHIFT 32 +#define ID_AA64MMFR1_XNX_SHIFT 28 +#define ID_AA64MMFR1_SPECSEI_SHIFT 24 +#define ID_AA64MMFR1_PAN_SHIFT 20 +#define ID_AA64MMFR1_LO_SHIFT 16 +#define ID_AA64MMFR1_HPDS_SHIFT 12 +#define ID_AA64MMFR1_VH_SHIFT 8 +#define ID_AA64MMFR1_VMIDBITS_SHIFT 4 +#define ID_AA64MMFR1_HAFDBS_SHIFT 0 + +#define SYSTEM_REGISTER_FIELD(val, shift) ((((val) >> (shift)) & 0xfULL)) + +/* Feature support is specified in nibbles. That gives 16 possible + * levels. Usually 0 means no support. After that each successive + * level is a superset of the previous one. That means that if we do + * not fully support a level then we need to clamp to the previous + * level. */ +#define CLAMP_REGISTER_FIELD_INPLACE(val, shift, limit) \ + do { \ + if (SYSTEM_REGISTER_FIELD(val, shift) > (ULong)(limit)) { \ + val &= ~(0xfULL << (shift)); \ + val |= ((ULong)(limit) << (shift)); \ + } \ + } while (0) + +#define MAKE_SYSTEM_REGISTER_MASK_FIELD(shift) (0xfULL << (shift)) +#define MASK_SYSTEM_REGISTER_FIELDS(val, mask) (val) &= (mask) + +#endif /* ifndef __LIBVEX_PUB_GUEST_ARM64_SYSREGS_H */ + + +/*---------------------------------------------------------------*/ +/*--- libvex_guest_arm64_sysregs.h ---*/ +/*---------------------------------------------------------------*/ diff --git a/coregrind/m_machine.c b/coregrind/m_machine.c index 15227efcf..0feb0bdbe 100644 --- a/coregrind/m_machine.c +++ b/coregrind/m_machine.c @@ -40,6 +40,8 @@ #include "pub_core_libcsignal.h" // for ppc32 messing with SIGILL and SIGFPE #include "pub_core_debuglog.h" +#include "libvex_guest_arm64_sysregs.h" + #define INSTR_PTR(regs) ((regs).vex.VG_INSTR_PTR) #define STACK_PTR(regs) ((regs).vex.VG_STACK_PTR) @@ -1859,100 +1861,58 @@ Bool VG_(machine_get_hwcaps)( void ) if (is_base_v8) return True; - /* ID_AA64ISAR0_EL1 Instruction set attribute register 0 fields */ - #define ID_AA64ISAR0_FHM_SHIFT 48 - #define ID_AA64ISAR0_DP_SHIFT 44 - #define ID_AA64ISAR0_SM4_SHIFT 40 - #define ID_AA64ISAR0_SM3_SHIFT 36 - #define ID_AA64ISAR0_SHA3_SHIFT 32 - #define ID_AA64ISAR0_RDM_SHIFT 28 - #define ID_AA64ISAR0_ATOMICS_SHIFT 20 - /* Field values */ - #define ID_AA64ISAR0_FHM_SUPPORTED 0x1 - #define ID_AA64ISAR0_DP_SUPPORTED 0x1 - #define ID_AA64ISAR0_SM4_SUPPORTED 0x1 - #define ID_AA64ISAR0_SM3_SUPPORTED 0x1 - #define ID_AA64ISAR0_SHA3_SUPPORTED 0x1 - #define ID_AA64ISAR0_RDM_SUPPORTED 0x1 - #define ID_AA64ISAR0_ATOMICS_SUPPORTED 0x2 - - /* ID_AA64ISAR1_EL1 Instruction set attribute register 1 fields */ - #define ID_AA64ISAR1_I8MM_SHIFT 52 - #define ID_AA64ISAR1_BF16_SHIFT 44 - #define ID_AA64ISAR1_DPB_SHIFT 0 - /* Field values */ - #define ID_AA64ISAR1_I8MM_SUPPORTED 0x1 - #define ID_AA64ISAR1_BF16_SUPPORTED 0x1 - #define ID_AA64ISAR1_DPBCVAP_SUPPORTED 0x1 - #define ID_AA64ISAR1_DPBCVADP_SUPPORTED 0x2 - - /* ID_AA64PFR0_EL1 Processor feature register 0 fields */ - #define ID_AA64PFR0_VFP16_SHIFT 20 - #define ID_AA64PFR0_FP16_SHIFT 16 - /* Field values */ - #define ID_AA64PFR0_VFP16_SUPPORTED 0x1 - #define ID_AA64PFR0_FP16_SUPPORTED 0x1 - - #define get_cpu_ftr(id) ({ \ - unsigned long val; \ + + #define get_cpu_ftr(id, val) ({ \ asm("mrs %0, "#id : "=r" (val)); \ VG_(debugLog)(1, "machine", "ARM64: %-20s: 0x%016lx\n", #id, val); \ }) - get_cpu_ftr(ID_AA64ISAR0_EL1); - get_cpu_ftr(ID_AA64ISAR1_EL1); - get_cpu_ftr(ID_AA64PFR0_EL1); - - #define get_ftr(id, ftr, fval, have_ftr) ({ \ - unsigned long rval; \ - asm("mrs %0, "#id : "=r" (rval)); \ - have_ftr = (fval & ((rval >> ftr) & 0xf)) >= fval ? True : False; \ - }) + + unsigned long isar0; + unsigned long isar1; + unsigned long pfr0; + + get_cpu_ftr(ID_AA64ISAR0_EL1, isar0); + get_cpu_ftr(ID_AA64ISAR1_EL1, isar1); + get_cpu_ftr(ID_AA64PFR0_EL1, pfr0); /* Read ID_AA64ISAR0_EL1 attributes */ /* FHM indicates support for FMLAL and FMLSL instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, - ID_AA64ISAR0_FHM_SUPPORTED, have_fhm); + have_fhm = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_FHM_SHIFT) >= ID_AA64ISAR0_FHM_SUPPORTED; /* DP indicates support for UDOT and SDOT instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, - ID_AA64ISAR0_DP_SUPPORTED, have_dp); + have_dp = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_DP_SHIFT) >= ID_AA64ISAR0_DP_SUPPORTED; /* SM4 indicates support for SM4E and SM4EKEY instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, - ID_AA64ISAR0_SM4_SUPPORTED, have_sm4); + have_sm4 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SM4_SHIFT) >= ID_AA64ISAR0_SM4_SUPPORTED; /* SM3 indicates support for SM3SS1, SM3TT1A, SM3TT1B, SM3TT2A, * SM3TT2B, * SM3PARTW1, and SM3PARTW2 instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT, - ID_AA64ISAR0_SM3_SUPPORTED, have_sm3); + have_sm3 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SM3_SHIFT) >= ID_AA64ISAR0_SM3_SUPPORTED; /* SHA3 indicates support for EOR3, RAX1, XAR, and BCAX instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT, - ID_AA64ISAR0_SHA3_SUPPORTED, have_sha3); + have_sha3 = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_SHA3_SHIFT) >= ID_AA64ISAR0_SHA3_SUPPORTED; /* RDM indicates support for SQRDMLAH and SQRDMLSH instructions. * Mandatory from v8.1 onwards. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, - ID_AA64ISAR0_RDM_SUPPORTED, have_rdm); + have_rdm = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_RDM_SHIFT) >= ID_AA64ISAR0_RDM_SUPPORTED; /* v8.1 ATOMICS indicates support for LDADD, LDCLR, LDEOR, LDSET, LDSMAX, * LDSMIN, LDUMAX, LDUMIN, CAS, CASP, and SWP instructions. * Mandatory from v8.1 onwards. */ - get_ftr(ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, - ID_AA64ISAR0_ATOMICS_SUPPORTED, have_atomics); + have_atomics = SYSTEM_REGISTER_FIELD(isar0, ID_AA64ISAR0_ATOMICS_SHIFT) >= ID_AA64ISAR0_ATOMICS_SUPPORTED; /* Read ID_AA64ISAR1_EL1 attributes */ @@ -1960,41 +1920,41 @@ Bool VG_(machine_get_hwcaps)( void ) * instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_I8MM_SHIFT, - ID_AA64ISAR1_I8MM_SUPPORTED, have_i8mm); + have_i8mm = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_I8MM_SHIFT) >= ID_AA64ISAR1_I8MM_SUPPORTED; /* BF16 indicates support for BFDOT, BFMLAL, BFMLAL2, BFMMLA, BFCVT, and * BFCVT2 instructions. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_BF16_SHIFT, - ID_AA64ISAR1_BF16_SUPPORTED, have_bf16); + have_bf16 = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_BF16_SHIFT) >= ID_AA64ISAR1_BF16_SUPPORTED; /* DPB indicates support for DC CVAP instruction. * Mandatory for v8.2 onwards. */ - get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, - ID_AA64ISAR1_DPBCVAP_SUPPORTED, have_dpbcvap); + have_dpbcvap = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_DPB_SHIFT) >= ID_AA64ISAR1_DPBCVAP_SUPPORTED; /* DPB indicates support for DC CVADP instruction. * Optional for v8.2. */ - get_ftr(ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, - ID_AA64ISAR1_DPBCVADP_SUPPORTED, have_dpbcvadp); + have_dpbcvadp = SYSTEM_REGISTER_FIELD(isar1, ID_AA64ISAR1_DPB_SHIFT) >= ID_AA64ISAR1_DPBCVADP_SUPPORTED; /* Read ID_AA64PFR0_EL1 attributes */ /* VFP16 indicates support for half-precision vector arithmetic. - * Optional for v8.2. Must be the same value as FP16. + * Optional for v8.2. Must be the same value as FP16. fp and + * advsimd are different to the usual isa/fp in that 0 means + * that the base features are present and 0xf means that the + * features are absent. Normally 0 means that the feature is absent. */ - get_ftr(ID_AA64PFR0_EL1, ID_AA64PFR0_VFP16_SHIFT, - ID_AA64PFR0_VFP16_SUPPORTED, have_vfp16); + unsigned long advsimd = SYSTEM_REGISTER_FIELD(pfr0, ID_AA64PFR0_ADVSIMD_SHIFT); + have_vfp16 = advsimd >= ID_AA64PFR0_ADVSIMD_HP_SUPPORTED && advsimd != ID_AA64PFR0_ADVSIMD_NOT_PRESENT; /* FP16 indicates support for half-precision scalar arithmetic. * Optional for v8.2. Must be the same value as VFP16. */ - get_ftr(ID_AA64PFR0_EL1, ID_AA64PFR0_FP16_SHIFT, - ID_AA64PFR0_FP16_SUPPORTED, have_fp16); + unsigned long fp = SYSTEM_REGISTER_FIELD(pfr0, ID_AA64PFR0_FP_SHIFT); + vg_assert(fp == advsimd); + have_fp16 = fp >= ID_AA64PFR0_FP_HP_SUPPORTED && fp != ID_AA64PFR0_FP_NOT_PRESENT; if (have_fhm) vai.hwcaps |= VEX_HWCAPS_ARM64_FHM; if (have_dpbcvap) vai.hwcaps |= VEX_HWCAPS_ARM64_DPBCVAP; @@ -2010,7 +1970,6 @@ Bool VG_(machine_get_hwcaps)( void ) if (have_vfp16) vai.hwcaps |= VEX_HWCAPS_ARM64_VFP16; #undef get_cpu_ftr - #undef get_ftr return True; }