public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family
@ 2023-10-18 15:02 Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 1/7] aarch64: Sync system register information with Binutils Victor Do Nascimento
                   ` (6 more replies)
  0 siblings, 7 replies; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

This revision of the patch series addresses the following key pieces
of upstream feedback:

  * `aarch64-sys-regs.def', being identical in content to the file with
  the same name in Binutils, now retains the copyright header from
  Binutils.
  * We migrate away from the binary search handling of system-register
  lookups in favour of a hashmap approach, relaxing the requirement
  that all entries in `aarch64-sys-reg.def' be kept in alphabetical
  order.
  * A static selftest is added for sanity-checking of the contents of
  `aarch64-sys-regs.def'.  Given the move to a hashmap lookup mechanism,
  no testing is needed for the preservation of alphabetical order, but
  a test is added to detect spurious duplicate register definitions.

---

This patch series adds support for reading and writing to and from
system registers via the relevant ACLE-defined builtins [1].

The patch series makes a series of additions to the aarch64-specific
areas of the compiler to make this possible.

Firstly, a mechanism for defining system registers is established via a
new .def file and the new SYSREG macro.  This macro is the same as is
used in Binutils and system register entries are compatible with
either code-base.

Given the information contained in this system register definition
file, a compile-time validation mechanism is implemented, such that any
system register name passed as a string literal argument to these
builtins can be checked against known system registers and its use
for a given target architecture validated.

Finally, patterns for each of these builtins are added to the back-end
such that, if all validation criteria are met, the correct assembly is
emitted.

Thus, the following example of system register access is now valid for
GCC:

	long long old = __arm_rsr("trcseqstr");
	__arm_wsr("trcseqstr", new);

Testing:
 - Bootstrap/regtest on aarch64-linux-gnu done.

[1] https://arm-software.github.io/acle/main/acle.html

Victor Do Nascimento (7):
  aarch64: Sync system register information with Binutils
  aarch64: Add support for aarch64-sys-regs.def
  aarch64: Implement system register validation tools
  aarch64: Add basic target_print_operand support for CONST_STRING
  aarch64: Implement system register r/w arm ACLE intrinsic functions
  aarch64: Add front-end argument type checking for target builtins
  aarch64: Add system register duplication check selftest

 gcc/config/aarch64/aarch64-builtins.cc        |  233 ++++
 gcc/config/aarch64/aarch64-c.cc               |    4 +-
 gcc/config/aarch64/aarch64-protos.h           |    5 +
 gcc/config/aarch64/aarch64-sys-regs.def       | 1064 +++++++++++++++++
 gcc/config/aarch64/aarch64.cc                 |  243 ++++
 gcc/config/aarch64/aarch64.h                  |   36 +
 gcc/config/aarch64/aarch64.md                 |   17 +
 gcc/config/aarch64/arm_acle.h                 |   30 +
 gcc/config/aarch64/predicates.md              |    4 +
 .../gcc.target/aarch64/acle/rwsr-1.c          |   20 +
 .../gcc.target/aarch64/acle/rwsr-2.c          |   15 +
 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  |  144 +++
 12 files changed, 1813 insertions(+), 2 deletions(-)
 create mode 100644 gcc/config/aarch64/aarch64-sys-regs.def
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c

-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 1/7] aarch64: Sync system register information with Binutils
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def Victor Do Nascimento
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

This patch adds the `aarch64-sys-regs.def' file, originally written
for Binutils, to GCC. In so doing, it provides GCC with the necessary
information for teaching the compiler about system registers known to
the assembler and how these can be used.

By aligning the representation of data common to different parts of
the toolchain we can greatly reduce the duplication of work,
facilitating the maintenance of the aarch64 back-end across different
parts of the toolchain; By keeping both copies of the file in sync,
any `SYSREG (...)' that is added in one project is automatically added
to its counterpart.  This being the case, no change should be made in
the GCC copy of the file.  Any modifications should first be made in
Binutils and the resulting file copied over to GCC.

GCC does not implement the full range of ISA flags present in
Binutils.  Where this is the case, aliases must be added to aarch64.h
with the unknown architectural extension being mapped to its
associated base architecture, such that any flag present in Binutils
and used in system register definitions is understood in GCC.  Again,
this is done such that flags can be used interchangeably between
projects making use of the aarch64-system-regs.def file.  This is done
in the next patch in the series.

`.arch' directives missing from the emitted assembly files as a
consequence of this aliasing are accounted for by the compiler using
the S<op0>_<op1>_<Cn>_<Cm>_<op2> encoding of system registers when
issuing mrs/msr instructions.  This design choice ensures the
assembler will accept anything that was deemed acceptable by the
compiler.

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64-system-regs.def: New.
---
 gcc/config/aarch64/aarch64-sys-regs.def | 1064 +++++++++++++++++++++++
 1 file changed, 1064 insertions(+)
 create mode 100644 gcc/config/aarch64/aarch64-sys-regs.def

diff --git a/gcc/config/aarch64/aarch64-sys-regs.def b/gcc/config/aarch64/aarch64-sys-regs.def
new file mode 100644
index 00000000000..d24a2455503
--- /dev/null
+++ b/gcc/config/aarch64/aarch64-sys-regs.def
@@ -0,0 +1,1064 @@
+/* aarch64-system-regs.def -- AArch64 opcode support.
+   Copyright (C) 2009-2023 Free Software Foundation, Inc.
+   Contributed by ARM Ltd.
+
+   This file is part of the GNU opcodes library.
+
+   This library 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, or (at your option)
+   any later version.
+
+   It 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; see the file COPYING3.  If not,
+   see <http://www.gnu.org/licenses/>.  */
+
+/* Array of system registers and their associated arch features.
+
+   This file is also used by GCC.  Where necessary, any updates should
+   be made in Binutils and the updated file copied across to GCC, such
+   that the two projects are kept in sync at all times.
+
+   Before using #include to read this file, define a macro:
+
+     SYSREG (name, encoding, flags, features)
+
+  The NAME is the system register name, as recognized by the
+  assembler.  ENCODING provides the necessary information for the binary
+  encoding of the system register.  The FLAGS field is a bitmask of
+  relevant behavior information pertaining to the particular register.
+  For example: is it read/write-only? does it alias another register?
+  The FEATURES field maps onto ISA flags and specifies the architectural
+  feature requirements of the system register.  */
+
+  SYSREG ("accdata_el1",	CPENC (3,0,13,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("actlr_el1",		CPENC (3,0,1,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("actlr_el2",		CPENC (3,4,1,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("actlr_el3",		CPENC (3,6,1,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr0_el1",		CPENC (3,0,5,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr0_el12",		CPENC (3,5,5,1,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("afsr0_el2",		CPENC (3,4,5,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr0_el3",		CPENC (3,6,5,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr1_el1",		CPENC (3,0,5,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr1_el12",		CPENC (3,5,5,1,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("afsr1_el2",		CPENC (3,4,5,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("afsr1_el3",		CPENC (3,6,5,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("aidr_el1",		CPENC (3,1,0,0,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("allint",		CPENC (3,0,4,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_8A))
+  SYSREG ("amair_el1",		CPENC (3,0,10,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("amair_el12",		CPENC (3,5,10,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("amair_el2",		CPENC (3,4,10,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("amair_el3",		CPENC (3,6,10,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("amcfgr_el0",		CPENC (3,3,13,2,1),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcg1idr_el0",	CPENC (3,3,13,2,6),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_6A))
+  SYSREG ("amcgcr_el0",		CPENC (3,3,13,2,2),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcntenclr0_el0",	CPENC (3,3,13,2,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcntenclr1_el0",	CPENC (3,3,13,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcntenset0_el0",	CPENC (3,3,13,2,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcntenset1_el0",	CPENC (3,3,13,3,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amcr_el0",		CPENC (3,3,13,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr00_el0",	CPENC (3,3,13,4,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr01_el0",	CPENC (3,3,13,4,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr02_el0",	CPENC (3,3,13,4,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr03_el0",	CPENC (3,3,13,4,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr10_el0",	CPENC (3,3,13,12,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr110_el0",	CPENC (3,3,13,13,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr111_el0",	CPENC (3,3,13,13,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr112_el0",	CPENC (3,3,13,13,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr113_el0",	CPENC (3,3,13,13,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr114_el0",	CPENC (3,3,13,13,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr115_el0",	CPENC (3,3,13,13,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr11_el0",	CPENC (3,3,13,12,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr12_el0",	CPENC (3,3,13,12,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr13_el0",	CPENC (3,3,13,12,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr14_el0",	CPENC (3,3,13,12,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr15_el0",	CPENC (3,3,13,12,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr16_el0",	CPENC (3,3,13,12,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr17_el0",	CPENC (3,3,13,12,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr18_el0",	CPENC (3,3,13,13,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntr19_el0",	CPENC (3,3,13,13,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevcntvoff00_el2",	CPENC (3,4,13,8,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff010_el2",	CPENC (3,4,13,9,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff011_el2",	CPENC (3,4,13,9,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff012_el2",	CPENC (3,4,13,9,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff013_el2",	CPENC (3,4,13,9,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff014_el2",	CPENC (3,4,13,9,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff015_el2",	CPENC (3,4,13,9,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff01_el2",	CPENC (3,4,13,8,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff02_el2",	CPENC (3,4,13,8,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff03_el2",	CPENC (3,4,13,8,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff04_el2",	CPENC (3,4,13,8,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff05_el2",	CPENC (3,4,13,8,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff06_el2",	CPENC (3,4,13,8,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff07_el2",	CPENC (3,4,13,8,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff08_el2",	CPENC (3,4,13,9,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff09_el2",	CPENC (3,4,13,9,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff10_el2",	CPENC (3,4,13,10,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff110_el2",	CPENC (3,4,13,11,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff111_el2",	CPENC (3,4,13,11,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff112_el2",	CPENC (3,4,13,11,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff113_el2",	CPENC (3,4,13,11,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff114_el2",	CPENC (3,4,13,11,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff115_el2",	CPENC (3,4,13,11,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff11_el2",	CPENC (3,4,13,10,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff12_el2",	CPENC (3,4,13,10,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff13_el2",	CPENC (3,4,13,10,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff14_el2",	CPENC (3,4,13,10,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff15_el2",	CPENC (3,4,13,10,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff16_el2",	CPENC (3,4,13,10,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff17_el2",	CPENC (3,4,13,10,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff18_el2",	CPENC (3,4,13,11,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevcntvoff19_el2",	CPENC (3,4,13,11,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("amevtyper00_el0",	CPENC (3,3,13,6,0),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper01_el0",	CPENC (3,3,13,6,1),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper02_el0",	CPENC (3,3,13,6,2),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper03_el0",	CPENC (3,3,13,6,3),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper10_el0",	CPENC (3,3,13,14,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper110_el0",	CPENC (3,3,13,15,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper111_el0",	CPENC (3,3,13,15,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper112_el0",	CPENC (3,3,13,15,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper113_el0",	CPENC (3,3,13,15,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper114_el0",	CPENC (3,3,13,15,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper115_el0",	CPENC (3,3,13,15,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper11_el0",	CPENC (3,3,13,14,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper12_el0",	CPENC (3,3,13,14,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper13_el0",	CPENC (3,3,13,14,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper14_el0",	CPENC (3,3,13,14,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper15_el0",	CPENC (3,3,13,14,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper16_el0",	CPENC (3,3,13,14,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper17_el0",	CPENC (3,3,13,14,7),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper18_el0",	CPENC (3,3,13,15,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amevtyper19_el0",	CPENC (3,3,13,15,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("amuserenr_el0",	CPENC (3,3,13,2,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("apdakeyhi_el1",	CPENC (3,0,2,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apdakeylo_el1",	CPENC (3,0,2,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apdbkeyhi_el1",	CPENC (3,0,2,2,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apdbkeylo_el1",	CPENC (3,0,2,2,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apgakeyhi_el1",	CPENC (3,0,2,3,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apgakeylo_el1",	CPENC (3,0,2,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apiakeyhi_el1",	CPENC (3,0,2,1,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apiakeylo_el1",	CPENC (3,0,2,1,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apibkeyhi_el1",	CPENC (3,0,2,1,3),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("apibkeylo_el1",	CPENC (3,0,2,1,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_3A))
+  SYSREG ("brbcr_el1",		CPENC (2,1,9,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbcr_el12",		CPENC (2,5,9,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbcr_el2",		CPENC (2,4,9,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbfcr_el1",		CPENC (2,1,9,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbidr0_el1",	CPENC (2,1,9,2,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf0_el1",	CPENC (2,1,8,0,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf10_el1",	CPENC (2,1,8,10,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf11_el1",	CPENC (2,1,8,11,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf12_el1",	CPENC (2,1,8,12,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf13_el1",	CPENC (2,1,8,13,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf14_el1",	CPENC (2,1,8,14,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf15_el1",	CPENC (2,1,8,15,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf16_el1",	CPENC (2,1,8,0,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf17_el1",	CPENC (2,1,8,1,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf18_el1",	CPENC (2,1,8,2,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf19_el1",	CPENC (2,1,8,3,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf1_el1",	CPENC (2,1,8,1,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf20_el1",	CPENC (2,1,8,4,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf21_el1",	CPENC (2,1,8,5,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf22_el1",	CPENC (2,1,8,6,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf23_el1",	CPENC (2,1,8,7,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf24_el1",	CPENC (2,1,8,8,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf25_el1",	CPENC (2,1,8,9,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf26_el1",	CPENC (2,1,8,10,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf27_el1",	CPENC (2,1,8,11,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf28_el1",	CPENC (2,1,8,12,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf29_el1",	CPENC (2,1,8,13,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf2_el1",	CPENC (2,1,8,2,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf30_el1",	CPENC (2,1,8,14,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf31_el1",	CPENC (2,1,8,15,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf3_el1",	CPENC (2,1,8,3,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf4_el1",	CPENC (2,1,8,4,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf5_el1",	CPENC (2,1,8,5,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf6_el1",	CPENC (2,1,8,6,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf7_el1",	CPENC (2,1,8,7,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf8_el1",	CPENC (2,1,8,8,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinf9_el1",	CPENC (2,1,8,9,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbinfinj_el1",	CPENC (2,1,9,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc0_el1",	CPENC (2,1,8,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc10_el1",	CPENC (2,1,8,10,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc11_el1",	CPENC (2,1,8,11,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc12_el1",	CPENC (2,1,8,12,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc13_el1",	CPENC (2,1,8,13,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc14_el1",	CPENC (2,1,8,14,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc15_el1",	CPENC (2,1,8,15,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc16_el1",	CPENC (2,1,8,0,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc17_el1",	CPENC (2,1,8,1,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc18_el1",	CPENC (2,1,8,2,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc19_el1",	CPENC (2,1,8,3,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc1_el1",	CPENC (2,1,8,1,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc20_el1",	CPENC (2,1,8,4,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc21_el1",	CPENC (2,1,8,5,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc22_el1",	CPENC (2,1,8,6,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc23_el1",	CPENC (2,1,8,7,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc24_el1",	CPENC (2,1,8,8,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc25_el1",	CPENC (2,1,8,9,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc26_el1",	CPENC (2,1,8,10,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc27_el1",	CPENC (2,1,8,11,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc28_el1",	CPENC (2,1,8,12,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc29_el1",	CPENC (2,1,8,13,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc2_el1",	CPENC (2,1,8,2,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc30_el1",	CPENC (2,1,8,14,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc31_el1",	CPENC (2,1,8,15,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc3_el1",	CPENC (2,1,8,3,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc4_el1",	CPENC (2,1,8,4,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc5_el1",	CPENC (2,1,8,5,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc6_el1",	CPENC (2,1,8,6,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc7_el1",	CPENC (2,1,8,7,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc8_el1",	CPENC (2,1,8,8,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrc9_el1",	CPENC (2,1,8,9,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbsrcinj_el1",	CPENC (2,1,9,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt0_el1",	CPENC (2,1,8,0,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt10_el1",	CPENC (2,1,8,10,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt11_el1",	CPENC (2,1,8,11,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt12_el1",	CPENC (2,1,8,12,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt13_el1",	CPENC (2,1,8,13,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt14_el1",	CPENC (2,1,8,14,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt15_el1",	CPENC (2,1,8,15,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt16_el1",	CPENC (2,1,8,0,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt17_el1",	CPENC (2,1,8,1,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt18_el1",	CPENC (2,1,8,2,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt19_el1",	CPENC (2,1,8,3,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt1_el1",	CPENC (2,1,8,1,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt20_el1",	CPENC (2,1,8,4,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt21_el1",	CPENC (2,1,8,5,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt22_el1",	CPENC (2,1,8,6,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt23_el1",	CPENC (2,1,8,7,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt24_el1",	CPENC (2,1,8,8,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt25_el1",	CPENC (2,1,8,9,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt26_el1",	CPENC (2,1,8,10,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt27_el1",	CPENC (2,1,8,11,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt28_el1",	CPENC (2,1,8,12,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt29_el1",	CPENC (2,1,8,13,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt2_el1",	CPENC (2,1,8,2,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt30_el1",	CPENC (2,1,8,14,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt31_el1",	CPENC (2,1,8,15,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt3_el1",	CPENC (2,1,8,3,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt4_el1",	CPENC (2,1,8,4,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt5_el1",	CPENC (2,1,8,5,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt6_el1",	CPENC (2,1,8,6,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt7_el1",	CPENC (2,1,8,7,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt8_el1",	CPENC (2,1,8,8,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgt9_el1",	CPENC (2,1,8,9,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("brbtgtinj_el1",	CPENC (2,1,9,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("brbts_el1",		CPENC (2,1,9,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ccsidr2_el1",	CPENC (3,1,0,0,2),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_3A))
+  SYSREG ("ccsidr_el1",		CPENC (3,1,0,0,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("clidr_el1",		CPENC (3,1,0,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("cntfrq_el0",		CPENC (3,3,14,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cnthctl_el2",	CPENC (3,4,14,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cnthp_ctl_el2",	CPENC (3,4,14,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cnthp_cval_el2",	CPENC (3,4,14,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cnthp_tval_el2",	CPENC (3,4,14,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cnthps_ctl_el2",	CPENC (3,4,14,5,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cnthps_cval_el2",	CPENC (3,4,14,5,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cnthps_tval_el2",	CPENC (3,4,14,5,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cnthv_ctl_el2",	CPENC (3,4,14,3,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cnthv_cval_el2",	CPENC (3,4,14,3,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cnthv_tval_el2",	CPENC (3,4,14,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cnthvs_ctl_el2",	CPENC (3,4,14,4,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cnthvs_cval_el2",	CPENC (3,4,14,4,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cnthvs_tval_el2",	CPENC (3,4,14,4,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("cntkctl_el1",	CPENC (3,0,14,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntkctl_el12",	CPENC (3,5,14,1,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntp_ctl_el0",	CPENC (3,3,14,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntp_ctl_el02",	CPENC (3,5,14,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntp_cval_el0",	CPENC (3,3,14,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntp_cval_el02",	CPENC (3,5,14,2,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntp_tval_el0",	CPENC (3,3,14,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntp_tval_el02",	CPENC (3,5,14,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntpct_el0",		CPENC (3,3,14,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("cntpctss_el0",	CPENC (3,3,14,0,5),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_6A))
+  SYSREG ("cntpoff_el2",	CPENC (3,4,14,0,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("cntps_ctl_el1",	CPENC (3,7,14,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntps_cval_el1",	CPENC (3,7,14,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntps_tval_el1",	CPENC (3,7,14,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntv_ctl_el0",	CPENC (3,3,14,3,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntv_ctl_el02",	CPENC (3,5,14,3,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntv_cval_el0",	CPENC (3,3,14,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntv_cval_el02",	CPENC (3,5,14,3,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntv_tval_el0",	CPENC (3,3,14,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cntv_tval_el02",	CPENC (3,5,14,3,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cntvct_el0",		CPENC (3,3,14,0,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("cntvctss_el0",	CPENC (3,3,14,0,6),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_6A))
+  SYSREG ("cntvoff_el2",	CPENC (3,4,14,0,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("contextidr_el1",	CPENC (3,0,13,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("contextidr_el12",	CPENC (3,5,13,0,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("contextidr_el2",	CPENC (3,4,13,0,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cpacr_el1",		CPENC (3,0,1,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cpacr_el12",		CPENC (3,5,1,0,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("cptr_el2",		CPENC (3,4,1,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("cptr_el3",		CPENC (3,6,1,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrcr_el0",		CPENC (2,3,8,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrcr_el1",		CPENC (2,0,8,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrcr_el12",		CPENC (2,5,8,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrcr_el2",		CPENC (2,4,8,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csridr_el0",		CPENC (2,3,8,0,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("csrptr_el0",		CPENC (2,3,8,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrptr_el1",		CPENC (2,0,8,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrptr_el12",	CPENC (2,5,8,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrptr_el2",		CPENC (2,4,8,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("csrptridx_el0",	CPENC (2,3,8,0,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("csrptridx_el1",	CPENC (2,0,8,0,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("csrptridx_el2",	CPENC (2,4,8,0,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("csselr_el1",		CPENC (3,2,0,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ctr_el0",		CPENC (3,3,0,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("currentel",		CPENC (3,0,4,2,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("dacr32_el2",		CPENC (3,4,3,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("daif",		CPENC (3,3,4,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgauthstatus_el1",	CPENC (2,0,7,14,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr0_el1",	CPENC (2,0,0,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr10_el1",	CPENC (2,0,0,10,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr11_el1",	CPENC (2,0,0,11,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr12_el1",	CPENC (2,0,0,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr13_el1",	CPENC (2,0,0,13,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr14_el1",	CPENC (2,0,0,14,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr15_el1",	CPENC (2,0,0,15,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr1_el1",	CPENC (2,0,0,1,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr2_el1",	CPENC (2,0,0,2,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr3_el1",	CPENC (2,0,0,3,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr4_el1",	CPENC (2,0,0,4,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr5_el1",	CPENC (2,0,0,5,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr6_el1",	CPENC (2,0,0,6,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr7_el1",	CPENC (2,0,0,7,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr8_el1",	CPENC (2,0,0,8,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbcr9_el1",	CPENC (2,0,0,9,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr0_el1",	CPENC (2,0,0,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr10_el1",	CPENC (2,0,0,10,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr11_el1",	CPENC (2,0,0,11,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr12_el1",	CPENC (2,0,0,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr13_el1",	CPENC (2,0,0,13,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr14_el1",	CPENC (2,0,0,14,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr15_el1",	CPENC (2,0,0,15,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr1_el1",	CPENC (2,0,0,1,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr2_el1",	CPENC (2,0,0,2,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr3_el1",	CPENC (2,0,0,3,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr4_el1",	CPENC (2,0,0,4,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr5_el1",	CPENC (2,0,0,5,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr6_el1",	CPENC (2,0,0,6,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr7_el1",	CPENC (2,0,0,7,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr8_el1",	CPENC (2,0,0,8,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgbvr9_el1",	CPENC (2,0,0,9,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgclaimclr_el1",	CPENC (2,0,7,9,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgclaimset_el1",	CPENC (2,0,7,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgdtr_el0",		CPENC (2,3,0,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgdtrrx_el0",	CPENC (2,3,0,5,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("dbgdtrtx_el0",	CPENC (2,3,0,5,0),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("dbgprcr_el1",	CPENC (2,0,1,4,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgvcr32_el2",	CPENC (2,4,0,7,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr0_el1",	CPENC (2,0,0,0,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr10_el1",	CPENC (2,0,0,10,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr11_el1",	CPENC (2,0,0,11,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr12_el1",	CPENC (2,0,0,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr13_el1",	CPENC (2,0,0,13,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr14_el1",	CPENC (2,0,0,14,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr15_el1",	CPENC (2,0,0,15,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr1_el1",	CPENC (2,0,0,1,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr2_el1",	CPENC (2,0,0,2,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr3_el1",	CPENC (2,0,0,3,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr4_el1",	CPENC (2,0,0,4,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr5_el1",	CPENC (2,0,0,5,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr6_el1",	CPENC (2,0,0,6,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr7_el1",	CPENC (2,0,0,7,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr8_el1",	CPENC (2,0,0,8,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwcr9_el1",	CPENC (2,0,0,9,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr0_el1",	CPENC (2,0,0,0,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr10_el1",	CPENC (2,0,0,10,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr11_el1",	CPENC (2,0,0,11,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr12_el1",	CPENC (2,0,0,12,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr13_el1",	CPENC (2,0,0,13,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr14_el1",	CPENC (2,0,0,14,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr15_el1",	CPENC (2,0,0,15,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr1_el1",	CPENC (2,0,0,1,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr2_el1",	CPENC (2,0,0,2,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr3_el1",	CPENC (2,0,0,3,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr4_el1",	CPENC (2,0,0,4,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr5_el1",	CPENC (2,0,0,5,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr6_el1",	CPENC (2,0,0,6,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr7_el1",	CPENC (2,0,0,7,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr8_el1",	CPENC (2,0,0,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dbgwvr9_el1",	CPENC (2,0,0,9,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dczid_el0",		CPENC (3,3,0,0,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("disr_el1",		CPENC (3,0,12,1,1),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("dit",		CPENC (3,3,4,2,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("dlr_el0",		CPENC (3,3,4,5,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("dspsr_el0",		CPENC (3,3,4,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("elr_el1",		CPENC (3,0,4,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("elr_el12",		CPENC (3,5,4,0,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("elr_el2",		CPENC (3,4,4,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("elr_el3",		CPENC (3,6,4,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("erridr_el1",		CPENC (3,0,5,3,0),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (RAS))
+  SYSREG ("errselr_el1",	CPENC (3,0,5,3,1),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxaddr_el1",	CPENC (3,0,5,4,3),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxctlr_el1",	CPENC (3,0,5,4,1),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxfr_el1",		CPENC (3,0,5,4,0),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (RAS))
+  SYSREG ("erxmisc0_el1",	CPENC (3,0,5,5,0),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxmisc1_el1",	CPENC (3,0,5,5,1),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxmisc2_el1",	CPENC (3,0,5,5,2),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxmisc3_el1",	CPENC (3,0,5,5,3),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxpfgcdn_el1",	CPENC (3,0,5,4,6),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxpfgctl_el1",	CPENC (3,0,5,4,5),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("erxpfgf_el1",	CPENC (3,0,5,4,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (RAS))
+  SYSREG ("erxstatus_el1",	CPENC (3,0,5,4,2),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("esr_el1",		CPENC (3,0,5,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("esr_el12",		CPENC (3,5,5,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("esr_el2",		CPENC (3,4,5,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("esr_el3",		CPENC (3,6,5,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("far_el1",		CPENC (3,0,6,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("far_el12",		CPENC (3,5,6,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("far_el2",		CPENC (3,4,6,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("far_el3",		CPENC (3,6,6,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("fpcr",		CPENC (3,3,4,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("fpexc32_el2",	CPENC (3,4,5,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("fpsr",		CPENC (3,3,4,4,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("gcr_el1",		CPENC (3,0,1,0,6),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("gmid_el1",		CPENC (3,1,0,0,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (MEMTAG))
+  SYSREG ("gpccr_el3",		CPENC (3,6,2,1,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("gptbr_el3",		CPENC (3,6,2,1,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("hacr_el2",		CPENC (3,4,1,1,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("hafgrtr_el2",	CPENC (3,4,3,1,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hcr_el2",		CPENC (3,4,1,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("hcrx_el2",		CPENC (3,4,1,2,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_7A))
+  SYSREG ("hdfgrtr_el2",	CPENC (3,4,3,1,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hdfgwtr_el2",	CPENC (3,4,3,1,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hfgitr_el2",		CPENC (3,4,1,1,6),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hfgrtr_el2",		CPENC (3,4,1,1,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hfgwtr_el2",		CPENC (3,4,1,1,5),	F_ARCHEXT,		AARCH64_FEATURE (V8_6A))
+  SYSREG ("hpfar_el2",		CPENC (3,4,6,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("hstr_el2",		CPENC (3,4,1,1,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap0r0_el1",	CPENC (3,0,12,8,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap0r1_el1",	CPENC (3,0,12,8,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap0r2_el1",	CPENC (3,0,12,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap0r3_el1",	CPENC (3,0,12,8,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap1r0_el1",	CPENC (3,0,12,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap1r1_el1",	CPENC (3,0,12,9,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap1r2_el1",	CPENC (3,0,12,9,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ap1r3_el1",	CPENC (3,0,12,9,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_asgi1r_el1",	CPENC (3,0,12,11,6),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_bpr0_el1",	CPENC (3,0,12,8,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_bpr1_el1",	CPENC (3,0,12,12,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ctlr_el1",	CPENC (3,0,12,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_ctlr_el3",	CPENC (3,6,12,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_dir_el1",	CPENC (3,0,12,11,1),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_eoir0_el1",	CPENC (3,0,12,8,1),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_eoir1_el1",	CPENC (3,0,12,12,1),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_hppir0_el1",	CPENC (3,0,12,8,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_hppir1_el1",	CPENC (3,0,12,12,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_iar0_el1",	CPENC (3,0,12,8,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_iar1_el1",	CPENC (3,0,12,12,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_igrpen0_el1",	CPENC (3,0,12,12,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_igrpen1_el1",	CPENC (3,0,12,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_igrpen1_el3",	CPENC (3,6,12,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_nmiar1_el1",	CPENC (3,0,12,9,5),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_8A))
+  SYSREG ("icc_pmr_el1",	CPENC (3,0,4,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_rpr_el1",	CPENC (3,0,12,11,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_sgi0r_el1",	CPENC (3,0,12,11,7),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_sgi1r_el1",	CPENC (3,0,12,11,5),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("icc_sre_el1",	CPENC (3,0,12,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_sre_el2",	CPENC (3,4,12,9,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("icc_sre_el3",	CPENC (3,6,12,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap0r0_el2",	CPENC (3,4,12,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap0r1_el2",	CPENC (3,4,12,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap0r2_el2",	CPENC (3,4,12,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap0r3_el2",	CPENC (3,4,12,8,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap1r0_el2",	CPENC (3,4,12,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap1r1_el2",	CPENC (3,4,12,9,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap1r2_el2",	CPENC (3,4,12,9,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_ap1r3_el2",	CPENC (3,4,12,9,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_eisr_el2",	CPENC (3,4,12,11,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("ich_elrsr_el2",	CPENC (3,4,12,11,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("ich_hcr_el2",	CPENC (3,4,12,11,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr0_el2",	CPENC (3,4,12,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr10_el2",	CPENC (3,4,12,13,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr11_el2",	CPENC (3,4,12,13,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr12_el2",	CPENC (3,4,12,13,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr13_el2",	CPENC (3,4,12,13,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr14_el2",	CPENC (3,4,12,13,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr15_el2",	CPENC (3,4,12,13,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr1_el2",	CPENC (3,4,12,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr2_el2",	CPENC (3,4,12,12,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr3_el2",	CPENC (3,4,12,12,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr4_el2",	CPENC (3,4,12,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr5_el2",	CPENC (3,4,12,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr6_el2",	CPENC (3,4,12,12,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr7_el2",	CPENC (3,4,12,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr8_el2",	CPENC (3,4,12,13,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_lr9_el2",	CPENC (3,4,12,13,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_misr_el2",	CPENC (3,4,12,11,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("ich_vmcr_el2",	CPENC (3,4,12,11,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ich_vtr_el2",	CPENC (3,4,12,11,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64afr0_el1",	CPENC (3,0,0,5,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64afr1_el1",	CPENC (3,0,0,5,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64dfr0_el1",	CPENC (3,0,0,5,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64dfr1_el1",	CPENC (3,0,0,5,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64isar0_el1",	CPENC (3,0,0,6,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64isar1_el1",	CPENC (3,0,0,6,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64isar2_el1",	CPENC (3,0,0,6,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64mmfr0_el1",	CPENC (3,0,0,7,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64mmfr1_el1",	CPENC (3,0,0,7,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64mmfr2_el1",	CPENC (3,0,0,7,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64pfr0_el1",	CPENC (3,0,0,4,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64pfr1_el1",	CPENC (3,0,0,4,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_aa64smfr0_el1",	CPENC (3,0,0,4,5),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (SME))
+  SYSREG ("id_aa64zfr0_el1",	CPENC (3,0,0,4,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (SVE))
+  SYSREG ("id_afr0_el1",	CPENC (3,0,0,1,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_dfr0_el1",	CPENC (3,0,0,1,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_dfr1_el1",	CPENC (3,0,0,3,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar0_el1",	CPENC (3,0,0,2,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar1_el1",	CPENC (3,0,0,2,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar2_el1",	CPENC (3,0,0,2,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar3_el1",	CPENC (3,0,0,2,3),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar4_el1",	CPENC (3,0,0,2,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar5_el1",	CPENC (3,0,0,2,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_isar6_el1",	CPENC (3,0,0,2,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr0_el1",	CPENC (3,0,0,1,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr1_el1",	CPENC (3,0,0,1,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr2_el1",	CPENC (3,0,0,1,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr3_el1",	CPENC (3,0,0,1,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr4_el1",	CPENC (3,0,0,2,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_mmfr5_el1",	CPENC (3,0,0,3,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_pfr0_el1",	CPENC (3,0,0,1,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_pfr1_el1",	CPENC (3,0,0,1,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("id_pfr2_el1",	CPENC (3,0,0,3,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (ID_PFR2))
+  SYSREG ("ifsr32_el2",		CPENC (3,4,5,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("isr_el1",		CPENC (3,0,12,1,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("lorc_el1",		CPENC (3,0,10,4,3),	F_ARCHEXT,		AARCH64_FEATURE (LOR))
+  SYSREG ("lorea_el1",		CPENC (3,0,10,4,1),	F_ARCHEXT,		AARCH64_FEATURE (LOR))
+  SYSREG ("lorid_el1",		CPENC (3,0,10,4,7),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (LOR))
+  SYSREG ("lorn_el1",		CPENC (3,0,10,4,2),	F_ARCHEXT,		AARCH64_FEATURE (LOR))
+  SYSREG ("lorsa_el1",		CPENC (3,0,10,4,0),	F_ARCHEXT,		AARCH64_FEATURE (LOR))
+  SYSREG ("mair_el1",		CPENC (3,0,10,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mair_el12",		CPENC (3,5,10,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("mair_el2",		CPENC (3,4,10,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mair_el3",		CPENC (3,6,10,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mdccint_el1",	CPENC (2,0,0,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mdccsr_el0",		CPENC (2,3,0,1,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mdcr_el2",		CPENC (3,4,1,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mdcr_el3",		CPENC (3,6,1,3,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mdrar_el1",		CPENC (2,0,1,0,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mdscr_el1",		CPENC (2,0,0,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecid_a0_el2",	CPENC (3,4,10,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecid_a1_el2",	CPENC (3,4,10,8,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecid_p0_el2",	CPENC (3,4,10,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecid_p1_el2",	CPENC (3,4,10,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecid_rl_a_el3",	CPENC (3,6,10,10,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mecidr_el2",		CPENC (3,4,10,8,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mfar_el3",		CPENC (3,6,6,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("midr_el1",		CPENC (3,0,0,0,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mpam0_el1",		CPENC (3,0,10,5,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpam1_el1",		CPENC (3,0,10,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpam1_el12",		CPENC (3,5,10,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpam2_el2",		CPENC (3,4,10,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpam3_el3",		CPENC (3,6,10,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamhcr_el2",	CPENC (3,4,10,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamidr_el1",	CPENC (3,0,10,4,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mpamsm_el1",		CPENC (3,0,10,5,3),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("mpamvpm0_el2",	CPENC (3,4,10,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm1_el2",	CPENC (3,4,10,6,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm2_el2",	CPENC (3,4,10,6,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm3_el2",	CPENC (3,4,10,6,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm4_el2",	CPENC (3,4,10,6,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm5_el2",	CPENC (3,4,10,6,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm6_el2",	CPENC (3,4,10,6,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpm7_el2",	CPENC (3,4,10,6,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpamvpmv_el2",	CPENC (3,4,10,4,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("mpidr_el1",		CPENC (3,0,0,0,5),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mpuir_el1",		CPENC (3,0,0,0,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8R))
+  SYSREG ("mpuir_el2",		CPENC (3,4,0,0,4),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8R))
+  SYSREG ("mvfr0_el1",		CPENC (3,0,0,3,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mvfr1_el1",		CPENC (3,0,0,3,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("mvfr2_el1",		CPENC (3,0,0,3,2),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("nzcv",		CPENC (3,3,4,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("osdlr_el1",		CPENC (2,0,1,3,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("osdtrrx_el1",	CPENC (2,0,0,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("osdtrtx_el1",	CPENC (2,0,0,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("oseccr_el1",		CPENC (2,0,0,6,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("oslar_el1",		CPENC (2,0,1,0,4),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("oslsr_el1",		CPENC (2,0,1,1,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("pan",		CPENC (3,0,4,2,3),	F_ARCHEXT,		AARCH64_FEATURE (PAN))
+  SYSREG ("par_el1",		CPENC (3,0,7,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmbidr_el1",		CPENC (3,0,9,10,7),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmblimitr_el1",	CPENC (3,0,9,10,0),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmbptr_el1",		CPENC (3,0,9,10,1),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmbsr_el1",		CPENC (3,0,9,10,3),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmccfiltr_el0",	CPENC (3,3,14,15,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmccntr_el0",	CPENC (3,3,9,13,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmceid0_el0",	CPENC (3,3,9,12,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("pmceid1_el0",	CPENC (3,3,9,12,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("pmcntenclr_el0",	CPENC (3,3,9,12,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmcntenset_el0",	CPENC (3,3,9,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmcr_el0",		CPENC (3,3,9,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr0_el0",	CPENC (3,3,14,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr10_el0",	CPENC (3,3,14,9,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr11_el0",	CPENC (3,3,14,9,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr12_el0",	CPENC (3,3,14,9,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr13_el0",	CPENC (3,3,14,9,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr14_el0",	CPENC (3,3,14,9,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr15_el0",	CPENC (3,3,14,9,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr16_el0",	CPENC (3,3,14,10,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr17_el0",	CPENC (3,3,14,10,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr18_el0",	CPENC (3,3,14,10,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr19_el0",	CPENC (3,3,14,10,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr1_el0",	CPENC (3,3,14,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr20_el0",	CPENC (3,3,14,10,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr21_el0",	CPENC (3,3,14,10,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr22_el0",	CPENC (3,3,14,10,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr23_el0",	CPENC (3,3,14,10,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr24_el0",	CPENC (3,3,14,11,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr25_el0",	CPENC (3,3,14,11,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr26_el0",	CPENC (3,3,14,11,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr27_el0",	CPENC (3,3,14,11,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr28_el0",	CPENC (3,3,14,11,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr29_el0",	CPENC (3,3,14,11,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr2_el0",	CPENC (3,3,14,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr30_el0",	CPENC (3,3,14,11,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr3_el0",	CPENC (3,3,14,8,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr4_el0",	CPENC (3,3,14,8,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr5_el0",	CPENC (3,3,14,8,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr6_el0",	CPENC (3,3,14,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr7_el0",	CPENC (3,3,14,8,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr8_el0",	CPENC (3,3,14,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevcntr9_el0",	CPENC (3,3,14,9,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper0_el0",	CPENC (3,3,14,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper10_el0",	CPENC (3,3,14,13,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper11_el0",	CPENC (3,3,14,13,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper12_el0",	CPENC (3,3,14,13,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper13_el0",	CPENC (3,3,14,13,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper14_el0",	CPENC (3,3,14,13,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper15_el0",	CPENC (3,3,14,13,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper16_el0",	CPENC (3,3,14,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper17_el0",	CPENC (3,3,14,14,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper18_el0",	CPENC (3,3,14,14,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper19_el0",	CPENC (3,3,14,14,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper1_el0",	CPENC (3,3,14,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper20_el0",	CPENC (3,3,14,14,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper21_el0",	CPENC (3,3,14,14,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper22_el0",	CPENC (3,3,14,14,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper23_el0",	CPENC (3,3,14,14,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper24_el0",	CPENC (3,3,14,15,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper25_el0",	CPENC (3,3,14,15,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper26_el0",	CPENC (3,3,14,15,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper27_el0",	CPENC (3,3,14,15,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper28_el0",	CPENC (3,3,14,15,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper29_el0",	CPENC (3,3,14,15,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper2_el0",	CPENC (3,3,14,12,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper30_el0",	CPENC (3,3,14,15,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper3_el0",	CPENC (3,3,14,12,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper4_el0",	CPENC (3,3,14,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper5_el0",	CPENC (3,3,14,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper6_el0",	CPENC (3,3,14,12,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper7_el0",	CPENC (3,3,14,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper8_el0",	CPENC (3,3,14,13,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmevtyper9_el0",	CPENC (3,3,14,13,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmintenclr_el1",	CPENC (3,0,9,14,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmintenset_el1",	CPENC (3,0,9,14,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmmir_el1",		CPENC (3,0,9,14,6),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (V8_4A))
+  SYSREG ("pmovsclr_el0",	CPENC (3,3,9,12,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmovsset_el0",	CPENC (3,3,9,14,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmscr_el1",		CPENC (3,0,9,9,0),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmscr_el12",		CPENC (3,5,9,9,0),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmscr_el2",		CPENC (3,4,9,9,0),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmselr_el0",		CPENC (3,3,9,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmsevfr_el1",	CPENC (3,0,9,9,5),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmsfcr_el1",		CPENC (3,0,9,9,4),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmsicr_el1",		CPENC (3,0,9,9,2),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmsidr_el1",		CPENC (3,0,9,9,7),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmsirr_el1",		CPENC (3,0,9,9,3),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmslatfr_el1",	CPENC (3,0,9,9,6),	F_ARCHEXT,		AARCH64_FEATURE (PROFILE))
+  SYSREG ("pmsnevfr_el1",	CPENC (3,0,9,9,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_7A))
+  SYSREG ("pmswinc_el0",	CPENC (3,3,9,12,4),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("pmuserenr_el0",	CPENC (3,3,9,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmxevcntr_el0",	CPENC (3,3,9,13,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("pmxevtyper_el0",	CPENC (3,3,9,13,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("prbar10_el1",	CPENC (3,0,6,13,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar10_el2",	CPENC (3,4,6,13,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar11_el1",	CPENC (3,0,6,13,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar11_el2",	CPENC (3,4,6,13,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar12_el1",	CPENC (3,0,6,14,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar12_el2",	CPENC (3,4,6,14,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar13_el1",	CPENC (3,0,6,14,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar13_el2",	CPENC (3,4,6,14,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar14_el1",	CPENC (3,0,6,15,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar14_el2",	CPENC (3,4,6,15,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar15_el1",	CPENC (3,0,6,15,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar15_el2",	CPENC (3,4,6,15,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar1_el1",		CPENC (3,0,6,8,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar1_el2",		CPENC (3,4,6,8,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar2_el1",		CPENC (3,0,6,9,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar2_el2",		CPENC (3,4,6,9,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar3_el1",		CPENC (3,0,6,9,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar3_el2",		CPENC (3,4,6,9,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar4_el1",		CPENC (3,0,6,10,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar4_el2",		CPENC (3,4,6,10,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar5_el1",		CPENC (3,0,6,10,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar5_el2",		CPENC (3,4,6,10,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar6_el1",		CPENC (3,0,6,11,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar6_el2",		CPENC (3,4,6,11,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar7_el1",		CPENC (3,0,6,11,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar7_el2",		CPENC (3,4,6,11,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar8_el1",		CPENC (3,0,6,12,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar8_el2",		CPENC (3,4,6,12,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar9_el1",		CPENC (3,0,6,12,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar9_el2",		CPENC (3,4,6,12,4),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar_el1",		CPENC (3,0,6,8,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prbar_el2",		CPENC (3,4,6,8,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prenr_el1",		CPENC (3,0,6,1,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prenr_el2",		CPENC (3,4,6,1,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar10_el1",	CPENC (3,0,6,13,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar10_el2",	CPENC (3,4,6,13,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar11_el1",	CPENC (3,0,6,13,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar11_el2",	CPENC (3,4,6,13,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar12_el1",	CPENC (3,0,6,14,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar12_el2",	CPENC (3,4,6,14,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar13_el1",	CPENC (3,0,6,14,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar13_el2",	CPENC (3,4,6,14,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar14_el1",	CPENC (3,0,6,15,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar14_el2",	CPENC (3,4,6,15,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar15_el1",	CPENC (3,0,6,15,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar15_el2",	CPENC (3,4,6,15,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar1_el1",		CPENC (3,0,6,8,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar1_el2",		CPENC (3,4,6,8,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar2_el1",		CPENC (3,0,6,9,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar2_el2",		CPENC (3,4,6,9,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar3_el1",		CPENC (3,0,6,9,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar3_el2",		CPENC (3,4,6,9,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar4_el1",		CPENC (3,0,6,10,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar4_el2",		CPENC (3,4,6,10,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar5_el1",		CPENC (3,0,6,10,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar5_el2",		CPENC (3,4,6,10,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar6_el1",		CPENC (3,0,6,11,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar6_el2",		CPENC (3,4,6,11,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar7_el1",		CPENC (3,0,6,11,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar7_el2",		CPENC (3,4,6,11,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar8_el1",		CPENC (3,0,6,12,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar8_el2",		CPENC (3,4,6,12,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar9_el1",		CPENC (3,0,6,12,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar9_el2",		CPENC (3,4,6,12,5),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar_el1",		CPENC (3,0,6,8,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prlar_el2",		CPENC (3,4,6,8,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prselr_el1",		CPENC (3,0,6,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("prselr_el2",		CPENC (3,4,6,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("revidr_el1",		CPENC (3,0,0,0,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("rgsr_el1",		CPENC (3,0,1,0,5),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("rmr_el1",		CPENC (3,0,12,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("rmr_el2",		CPENC (3,4,12,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("rmr_el3",		CPENC (3,6,12,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("rndr",		CPENC (3,3,2,4,0),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (RNG))
+  SYSREG ("rndrrs",		CPENC (3,3,2,4,1),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (RNG))
+  SYSREG ("rvbar_el1",		CPENC (3,0,12,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("rvbar_el2",		CPENC (3,4,12,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("rvbar_el3",		CPENC (3,6,12,0,1),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("scr_el3",		CPENC (3,6,1,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("sctlr_el1",		CPENC (3,0,1,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("sctlr_el12",		CPENC (3,5,1,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("sctlr_el2",		CPENC (3,4,1,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("sctlr_el3",		CPENC (3,6,1,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("scxtnum_el0",	CPENC (3,3,13,0,7),	F_ARCHEXT,		AARCH64_FEATURE (SCXTNUM))
+  SYSREG ("scxtnum_el1",	CPENC (3,0,13,0,7),	F_ARCHEXT,		AARCH64_FEATURE (SCXTNUM))
+  SYSREG ("scxtnum_el12",	CPENC (3,5,13,0,7),	F_ARCHEXT,		AARCH64_FEATURE (SCXTNUM))
+  SYSREG ("scxtnum_el2",	CPENC (3,4,13,0,7),	F_ARCHEXT,		AARCH64_FEATURE (SCXTNUM))
+  SYSREG ("scxtnum_el3",	CPENC (3,6,13,0,7),	F_ARCHEXT,		AARCH64_FEATURE (SCXTNUM))
+  SYSREG ("sder32_el2",		CPENC (3,4,1,3,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("sder32_el3",		CPENC (3,6,1,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("smcr_el1",		CPENC (3,0,1,2,6),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("smcr_el12",		CPENC (3,5,1,2,6),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("smcr_el2",		CPENC (3,4,1,2,6),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("smcr_el3",		CPENC (3,6,1,2,6),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("smidr_el1",		CPENC (3,1,0,0,6),	F_REG_READ|F_ARCHEXT,	AARCH64_FEATURE (SME))
+  SYSREG ("smpri_el1",		CPENC (3,0,1,2,4),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("smprimap_el2",	CPENC (3,4,1,2,5),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("sp_el0",		CPENC (3,0,4,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("sp_el1",		CPENC (3,4,4,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("sp_el2",		CPENC (3,6,4,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsel",		CPENC (3,0,4,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_abt",		CPENC (3,4,4,3,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_el1",		CPENC (3,0,4,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_el12",		CPENC (3,5,4,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("spsr_el2",		CPENC (3,4,4,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_el3",		CPENC (3,6,4,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_fiq",		CPENC (3,4,4,3,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_hyp",		CPENC (3,4,4,0,0),	F_DEPRECATED,		AARCH64_NO_FEATURES)
+  SYSREG ("spsr_irq",		CPENC (3,4,4,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("spsr_svc",		CPENC (3,0,4,0,0),	F_DEPRECATED,		AARCH64_NO_FEATURES)
+  SYSREG ("spsr_und",		CPENC (3,4,4,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ssbs",		CPENC (3,3,4,2,6),	F_ARCHEXT,		AARCH64_FEATURE (SSBS))
+  SYSREG ("svcr",		CPENC (3,3,4,2,2),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("tco",		CPENC (3,3,4,2,7),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tcr_el1",		CPENC (3,0,2,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tcr_el12",		CPENC (3,5,2,0,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("tcr_el2",		CPENC (3,4,2,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tcr_el3",		CPENC (3,6,2,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("teecr32_el1",	CPENC (2,2,0,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("teehbr32_el1",	CPENC (2,2,1,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tfsr_el1",		CPENC (3,0,5,6,0),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tfsr_el12",		CPENC (3,5,5,6,0),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tfsr_el2",		CPENC (3,4,5,6,0),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tfsr_el3",		CPENC (3,6,5,6,0),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tfsre0_el1",		CPENC (3,0,5,6,1),	F_ARCHEXT,		AARCH64_FEATURE (MEMTAG))
+  SYSREG ("tpidr2_el0",		CPENC (3,3,13,0,5),	F_ARCHEXT,		AARCH64_FEATURE (SME))
+  SYSREG ("tpidr_el0",		CPENC (3,3,13,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tpidr_el1",		CPENC (3,0,13,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tpidr_el2",		CPENC (3,4,13,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tpidr_el3",		CPENC (3,6,13,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("tpidrro_el0",	CPENC (3,3,13,0,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbbaser_el1",	CPENC (3,0,9,11,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbidr_el1",		CPENC (3,0,9,11,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trblimitr_el1",	CPENC (3,0,9,11,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbmar_el1",		CPENC (3,0,9,11,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbptr_el1",		CPENC (3,0,9,11,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbsr_el1",		CPENC (3,0,9,11,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trbtrg_el1",		CPENC (3,0,9,11,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr0",		CPENC (2,1,2,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr1",		CPENC (2,1,2,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr10",		CPENC (2,1,2,4,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr11",		CPENC (2,1,2,6,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr12",		CPENC (2,1,2,8,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr13",		CPENC (2,1,2,10,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr14",		CPENC (2,1,2,12,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr15",		CPENC (2,1,2,14,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr2",		CPENC (2,1,2,4,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr3",		CPENC (2,1,2,6,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr4",		CPENC (2,1,2,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr5",		CPENC (2,1,2,10,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr6",		CPENC (2,1,2,12,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr7",		CPENC (2,1,2,14,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr8",		CPENC (2,1,2,0,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacatr9",		CPENC (2,1,2,2,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr0",		CPENC (2,1,2,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr1",		CPENC (2,1,2,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr10",		CPENC (2,1,2,4,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr11",		CPENC (2,1,2,6,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr12",		CPENC (2,1,2,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr13",		CPENC (2,1,2,10,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr14",		CPENC (2,1,2,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr15",		CPENC (2,1,2,14,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr2",		CPENC (2,1,2,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr3",		CPENC (2,1,2,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr4",		CPENC (2,1,2,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr5",		CPENC (2,1,2,10,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr6",		CPENC (2,1,2,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr7",		CPENC (2,1,2,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr8",		CPENC (2,1,2,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcacvr9",		CPENC (2,1,2,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcauthstatus",	CPENC (2,1,7,14,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcauxctlr",		CPENC (2,1,0,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcbbctlr",		CPENC (2,1,0,15,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcccctlr",		CPENC (2,1,0,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcctlr0",	CPENC (2,1,3,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcctlr1",	CPENC (2,1,3,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr0",		CPENC (2,1,3,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr1",		CPENC (2,1,3,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr2",		CPENC (2,1,3,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr3",		CPENC (2,1,3,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr4",		CPENC (2,1,3,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr5",		CPENC (2,1,3,10,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr6",		CPENC (2,1,3,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidcvr7",		CPENC (2,1,3,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccidr0",		CPENC (2,1,7,12,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trccidr1",		CPENC (2,1,7,13,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trccidr2",		CPENC (2,1,7,14,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trccidr3",		CPENC (2,1,7,15,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcclaimclr",	CPENC (2,1,7,9,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcclaimset",	CPENC (2,1,7,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntctlr0",	CPENC (2,1,0,4,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntctlr1",	CPENC (2,1,0,5,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntctlr2",	CPENC (2,1,0,6,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntctlr3",	CPENC (2,1,0,7,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntrldvr0",	CPENC (2,1,0,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntrldvr1",	CPENC (2,1,0,1,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntrldvr2",	CPENC (2,1,0,2,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntrldvr3",	CPENC (2,1,0,3,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntvr0",		CPENC (2,1,0,8,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntvr1",		CPENC (2,1,0,9,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntvr2",		CPENC (2,1,0,10,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trccntvr3",		CPENC (2,1,0,11,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcconfigr",		CPENC (2,1,0,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdevaff0",		CPENC (2,1,7,10,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcdevaff1",		CPENC (2,1,7,11,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcdevarch",		CPENC (2,1,7,15,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcdevid",		CPENC (2,1,7,2,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcdevtype",		CPENC (2,1,7,3,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr0",		CPENC (2,1,2,0,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr1",		CPENC (2,1,2,4,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr2",		CPENC (2,1,2,8,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr3",		CPENC (2,1,2,12,6),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr4",		CPENC (2,1,2,0,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr5",		CPENC (2,1,2,4,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr6",		CPENC (2,1,2,8,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcmr7",		CPENC (2,1,2,12,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr0",		CPENC (2,1,2,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr1",		CPENC (2,1,2,4,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr2",		CPENC (2,1,2,8,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr3",		CPENC (2,1,2,12,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr4",		CPENC (2,1,2,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr5",		CPENC (2,1,2,4,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr6",		CPENC (2,1,2,8,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcdvcvr7",		CPENC (2,1,2,12,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trceventctl0r",	CPENC (2,1,0,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trceventctl1r",	CPENC (2,1,0,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcextinselr",	CPENC (2,1,0,8,4),	F_REG_ALIAS,		AARCH64_NO_FEATURES)
+  SYSREG ("trcextinselr0",	CPENC (2,1,0,8,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcextinselr1",	CPENC (2,1,0,9,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcextinselr2",	CPENC (2,1,0,10,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcextinselr3",	CPENC (2,1,0,11,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcidr0",		CPENC (2,1,0,8,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr1",		CPENC (2,1,0,9,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr10",		CPENC (2,1,0,2,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr11",		CPENC (2,1,0,3,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr12",		CPENC (2,1,0,4,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr13",		CPENC (2,1,0,5,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr2",		CPENC (2,1,0,10,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr3",		CPENC (2,1,0,11,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr4",		CPENC (2,1,0,12,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr5",		CPENC (2,1,0,13,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr6",		CPENC (2,1,0,14,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr7",		CPENC (2,1,0,15,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr8",		CPENC (2,1,0,0,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcidr9",		CPENC (2,1,0,1,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec0",		CPENC (2,1,0,0,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec1",		CPENC (2,1,0,1,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec2",		CPENC (2,1,0,2,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec3",		CPENC (2,1,0,3,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec4",		CPENC (2,1,0,4,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec5",		CPENC (2,1,0,5,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec6",		CPENC (2,1,0,6,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcimspec7",		CPENC (2,1,0,7,7),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcitctrl",		CPENC (2,1,7,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trclar",		CPENC (2,1,7,12,6),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("trclsr",		CPENC (2,1,7,13,6),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcoslar",		CPENC (2,1,1,0,4),	F_REG_WRITE,		AARCH64_NO_FEATURES)
+  SYSREG ("trcoslsr",		CPENC (2,1,1,1,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpdcr",		CPENC (2,1,1,4,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcpdsr",		CPENC (2,1,1,5,4),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr0",		CPENC (2,1,7,8,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr1",		CPENC (2,1,7,9,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr2",		CPENC (2,1,7,10,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr3",		CPENC (2,1,7,11,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr4",		CPENC (2,1,7,4,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr5",		CPENC (2,1,7,5,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr6",		CPENC (2,1,7,6,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcpidr7",		CPENC (2,1,7,7,7),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcprgctlr",		CPENC (2,1,0,1,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcprocselr",	CPENC (2,1,0,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcqctlr",		CPENC (2,1,0,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr10",	CPENC (2,1,1,10,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr11",	CPENC (2,1,1,11,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr12",	CPENC (2,1,1,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr13",	CPENC (2,1,1,13,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr14",	CPENC (2,1,1,14,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr15",	CPENC (2,1,1,15,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr16",	CPENC (2,1,1,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr17",	CPENC (2,1,1,1,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr18",	CPENC (2,1,1,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr19",	CPENC (2,1,1,3,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr2",		CPENC (2,1,1,2,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr20",	CPENC (2,1,1,4,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr21",	CPENC (2,1,1,5,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr22",	CPENC (2,1,1,6,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr23",	CPENC (2,1,1,7,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr24",	CPENC (2,1,1,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr25",	CPENC (2,1,1,9,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr26",	CPENC (2,1,1,10,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr27",	CPENC (2,1,1,11,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr28",	CPENC (2,1,1,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr29",	CPENC (2,1,1,13,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr3",		CPENC (2,1,1,3,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr30",	CPENC (2,1,1,14,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr31",	CPENC (2,1,1,15,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr4",		CPENC (2,1,1,4,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr5",		CPENC (2,1,1,5,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr6",		CPENC (2,1,1,6,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr7",		CPENC (2,1,1,7,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr8",		CPENC (2,1,1,8,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsctlr9",		CPENC (2,1,1,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcrsr",		CPENC (2,1,0,10,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcseqevr0",		CPENC (2,1,0,0,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcseqevr1",		CPENC (2,1,0,1,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcseqevr2",		CPENC (2,1,0,2,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcseqrstevr",	CPENC (2,1,0,6,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcseqstr",		CPENC (2,1,0,7,4),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr0",		CPENC (2,1,1,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr1",		CPENC (2,1,1,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr2",		CPENC (2,1,1,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr3",		CPENC (2,1,1,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr4",		CPENC (2,1,1,4,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr5",		CPENC (2,1,1,5,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr6",		CPENC (2,1,1,6,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcssccr7",		CPENC (2,1,1,7,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr0",		CPENC (2,1,1,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr1",		CPENC (2,1,1,9,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr2",		CPENC (2,1,1,10,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr3",		CPENC (2,1,1,11,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr4",		CPENC (2,1,1,12,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr5",		CPENC (2,1,1,13,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr6",		CPENC (2,1,1,14,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsscsr7",		CPENC (2,1,1,15,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr0",	CPENC (2,1,1,0,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr1",	CPENC (2,1,1,1,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr2",	CPENC (2,1,1,2,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr3",	CPENC (2,1,1,3,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr4",	CPENC (2,1,1,4,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr5",	CPENC (2,1,1,5,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr6",	CPENC (2,1,1,6,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcsspcicr7",	CPENC (2,1,1,7,3),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcstallctlr",	CPENC (2,1,0,11,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcstatr",		CPENC (2,1,0,3,0),	F_REG_READ,		AARCH64_NO_FEATURES)
+  SYSREG ("trcsyncpr",		CPENC (2,1,0,13,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trctraceidr",	CPENC (2,1,0,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trctsctlr",		CPENC (2,1,0,12,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvdarcctlr",	CPENC (2,1,0,10,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvdctlr",		CPENC (2,1,0,8,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvdsacctlr",	CPENC (2,1,0,9,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvictlr",		CPENC (2,1,0,0,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcviiectlr",	CPENC (2,1,0,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvipcssctlr",	CPENC (2,1,0,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvissctlr",	CPENC (2,1,0,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcctlr0",	CPENC (2,1,3,2,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcctlr1",	CPENC (2,1,3,3,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr0",	CPENC (2,1,3,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr1",	CPENC (2,1,3,2,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr2",	CPENC (2,1,3,4,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr3",	CPENC (2,1,3,6,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr4",	CPENC (2,1,3,8,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr5",	CPENC (2,1,3,10,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr6",	CPENC (2,1,3,12,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trcvmidcvr7",	CPENC (2,1,3,14,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("trfcr_el1",		CPENC (3,0,1,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("trfcr_el12",		CPENC (3,5,1,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("trfcr_el2",		CPENC (3,4,1,2,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("ttbr0_el1",		CPENC (3,0,2,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ttbr0_el12",		CPENC (3,5,2,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("ttbr0_el2",		CPENC (3,4,2,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8A))
+  SYSREG ("ttbr0_el3",		CPENC (3,6,2,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ttbr1_el1",		CPENC (3,0,2,0,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("ttbr1_el12",		CPENC (3,5,2,0,1),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("ttbr1_el2",		CPENC (3,4,2,0,1),	F_ARCHEXT,		AARCH64_FEATURES (2, V8A, V8_1A))
+  SYSREG ("uao",		CPENC (3,0,4,2,4),	F_ARCHEXT,		AARCH64_FEATURE (V8_2A))
+  SYSREG ("vbar_el1",		CPENC (3,0,12,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vbar_el12",		CPENC (3,5,12,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_1A))
+  SYSREG ("vbar_el2",		CPENC (3,4,12,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vbar_el3",		CPENC (3,6,12,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vdisr_el2",		CPENC (3,4,12,1,1),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("vmecid_a_el2",	CPENC (3,4,10,9,1),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vmecid_p_el2",	CPENC (3,4,10,9,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vmpidr_el2",		CPENC (3,4,0,0,5),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vncr_el2",		CPENC (3,4,2,2,0),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("vpidr_el2",		CPENC (3,4,0,0,0),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vsctlr_el2",		CPENC (3,4,2,0,0),	F_ARCHEXT,		AARCH64_FEATURE (V8R))
+  SYSREG ("vsesr_el2",		CPENC (3,4,5,2,3),	F_ARCHEXT,		AARCH64_FEATURE (RAS))
+  SYSREG ("vstcr_el2",		CPENC (3,4,2,6,2),	F_ARCHEXT,		AARCH64_FEATURE (V8_4A))
+  SYSREG ("vsttbr_el2",		CPENC (3,4,2,6,0),	F_ARCHEXT,		AARCH64_FEATURES (2, V8A, V8_4A))
+  SYSREG ("vtcr_el2",		CPENC (3,4,2,1,2),	0,			AARCH64_NO_FEATURES)
+  SYSREG ("vttbr_el2",		CPENC (3,4,2,1,0),	F_ARCHEXT,		AARCH64_FEATURE (V8A))
+  SYSREG ("zcr_el1",		CPENC (3,0,1,2,0),	F_ARCHEXT,		AARCH64_FEATURE (SVE))
+  SYSREG ("zcr_el12",		CPENC (3,5,1,2,0),	F_ARCHEXT,		AARCH64_FEATURE (SVE))
+  SYSREG ("zcr_el2",		CPENC (3,4,1,2,0),	F_ARCHEXT,		AARCH64_FEATURE (SVE))
+  SYSREG ("zcr_el3",		CPENC (3,6,1,2,0),	F_ARCHEXT,		AARCH64_FEATURE (SVE))
\ No newline at end of file
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 1/7] aarch64: Sync system register information with Binutils Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 21:07   ` Richard Sandiford
  2023-10-18 15:02 ` [PATCH V2 3/7] aarch64: Implement system register validation tools Victor Do Nascimento
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

This patch defines the structure of a new .def file used for
representing the aarch64 system registers, what information it should
hold and the basic framework in GCC to process this file.

Entries in the aarch64-system-regs.def file should be as follows:

  SYSREG (NAME, CPENC (sn,op1,cn,cm,op2), FLAG1 | ... | FLAGn, ARCH)

Where the arguments to SYSREG correspond to:
  - NAME:  The system register name, as used in the assembly language.
  - CPENC: The system register encoding, mapping to:

    	       s<sn>_<op1>_c<cn>_c<cm>_<op2>

  - FLAG: The entries in the FLAGS field are bitwise-OR'd together to
    	  encode extra information required to ensure proper use of
	  the system register.  For example, a read-only system
	  register will have the flag F_REG_READ, while write-only
	  registers will be labeled F_REG_WRITE.  Such flags are
	  tested against at compile-time.
  - ARCH: The architectural features the system register is associated
    	  with.  This is encoded via one of three possible macros:
	  1. When a system register is universally implemented, we say
	  it has no feature requirements, so we tag it with the
	  AARCH64_NO_FEATURES macro.
	  2. When a register is only implemented for a single
	  architectural extension EXT, the AARCH64_FEATURE (EXT), is
	  used.
	  3. When a given system register is made available by any of N
	  possible architectural extensions, the AARCH64_FEATURES(N, ...)
	  macro is used to combine them accordingly.

In order to enable proper interpretation of the SYSREG entries by the
compiler, flags defining system register behavior such as `F_REG_READ'
and `F_REG_WRITE' are also defined here, so they can later be used for
the validation of system register properties.

Finally, any architectural feature flags from Binutils missing from GCC
have appropriate aliases defined here so as to ensure
cross-compatibility of SYSREG entries across the toolchain.

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64.cc (sysreg_t): New.
	(sysreg_structs): Likewise.
	(nsysreg): Likewise.
	(AARCH64_FEATURE): Likewise.
	(AARCH64_FEATURES): Likewise.
	(AARCH64_NO_FEATURES): Likewise.
	* gcc/config/aarch64/aarch64.h (AARCH64_ISA_V8A): Add missing
	ISA flag.
	(AARCH64_ISA_V8_1A): Likewise.
	(AARCH64_ISA_V8_7A): Likewise.
	(AARCH64_ISA_V8_8A): Likewise.
	(AARCH64_NO_FEATURES): Likewise.
	(AARCH64_FL_RAS): New ISA flag alias.
	(AARCH64_FL_LOR): Likewise.
	(AARCH64_FL_PAN): Likewise.
	(AARCH64_FL_AMU): Likewise.
	(AARCH64_FL_SCXTNUM): Likewise.
	(AARCH64_FL_ID_PFR2): Likewise.
	(F_DEPRECATED): New.
	(F_REG_READ): Likewise.
	(F_REG_WRITE): Likewise.
	(F_ARCHEXT): Likewise.
	(F_REG_ALIAS): Likewise.
---
 gcc/config/aarch64/aarch64.cc | 38 +++++++++++++++++++++++++++++++++++
 gcc/config/aarch64/aarch64.h  | 36 +++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 9fbfc548a89..69de2366424 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -2807,6 +2807,44 @@ static const struct processor all_cores[] =
   {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
 };
 
+typedef struct {
+  const char* name;
+  const char* encoding;
+  const unsigned properties;
+  const unsigned long long arch_reqs;
+} sysreg_t;
+
+/* An aarch64_feature_set initializer for a single feature,
+   AARCH64_FEATURE_<FEAT>.  */
+#define AARCH64_FEATURE(FEAT) AARCH64_FL_##FEAT
+
+/* Used by AARCH64_FEATURES.  */
+#define AARCH64_OR_FEATURES_1(X, F1) \
+  AARCH64_FEATURE (F1)
+#define AARCH64_OR_FEATURES_2(X, F1, F2) \
+  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_1 (X, F2))
+#define AARCH64_OR_FEATURES_3(X, F1, ...) \
+  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_2 (X, __VA_ARGS__))
+
+/* An aarch64_feature_set initializer for the N features listed in "...".  */
+#define AARCH64_FEATURES(N, ...) \
+  AARCH64_OR_FEATURES_##N (0, __VA_ARGS__)
+
+/* Database of system registers, their encodings and architectural
+   requirements.  */
+const sysreg_t sysreg_structs[] =
+{
+#define CPENC(SN, OP1, CN, CM, OP2) "s"#SN"_"#OP1"_c"#CN"_c"#CM"_"#OP2
+#define SYSREG(NAME, ENC, FLAGS, ARCH) \
+  { NAME, ENC, FLAGS, ARCH },
+#include "aarch64-sys-regs.def"
+#undef CPENC
+};
+
+#define TOTAL_ITEMS (sizeof sysreg_structs / sizeof sysreg_structs[0])
+const unsigned nsysreg = TOTAL_ITEMS;
+#undef TOTAL_ITEMS
+
 /* The current tuning set.  */
 struct tune_params aarch64_tune_params = generic_tunings;
 
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index d74e9116fc5..cf3969a11aa 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -179,6 +179,8 @@ enum class aarch64_feature : unsigned char {
 
 /* Macros to test ISA flags.  */
 
+#define AARCH64_ISA_V8A		   (aarch64_isa_flags & AARCH64_FL_V8A)
+#define AARCH64_ISA_V8_1A	   (aarch64_isa_flags & AARCH64_FL_V8_1A)
 #define AARCH64_ISA_CRC            (aarch64_isa_flags & AARCH64_FL_CRC)
 #define AARCH64_ISA_CRYPTO         (aarch64_isa_flags & AARCH64_FL_CRYPTO)
 #define AARCH64_ISA_FP             (aarch64_isa_flags & AARCH64_FL_FP)
@@ -215,6 +217,8 @@ enum class aarch64_feature : unsigned char {
 #define AARCH64_ISA_SB		   (aarch64_isa_flags & AARCH64_FL_SB)
 #define AARCH64_ISA_V8R		   (aarch64_isa_flags & AARCH64_FL_V8R)
 #define AARCH64_ISA_PAUTH	   (aarch64_isa_flags & AARCH64_FL_PAUTH)
+#define AARCH64_ISA_V8_7A	   (aarch64_isa_flags & AARCH64_FL_V8_7A)
+#define AARCH64_ISA_V8_8A	   (aarch64_isa_flags & AARCH64_FL_V8_8A)
 #define AARCH64_ISA_V9A		   (aarch64_isa_flags & AARCH64_FL_V9A)
 #define AARCH64_ISA_V9_1A          (aarch64_isa_flags & AARCH64_FL_V9_1A)
 #define AARCH64_ISA_V9_2A          (aarch64_isa_flags & AARCH64_FL_V9_2A)
@@ -223,6 +227,38 @@ enum class aarch64_feature : unsigned char {
 #define AARCH64_ISA_LS64	   (aarch64_isa_flags & AARCH64_FL_LS64)
 #define AARCH64_ISA_CSSC	   (aarch64_isa_flags & AARCH64_FL_CSSC)
 
+/* AARCH64_FL options necessary for system register implementation.  */
+
+/* Mask for core system registers.  System registers requiring no architectural
+   extensions set up a feature-checking mask which returns any passed flags
+   unchanged when ANDd with.  */
+#define AARCH64_NO_FEATURES	   (uint64_t)-1
+
+/* Define AARCH64_FL aliases for architectural features which are protected
+   by -march flags in binutils but which receive no special treatment by GCC.
+
+   Such flags are inherited from the Binutils definition of system registers
+   and are mapped to the architecture in which the feature is implemented.  */
+#define AARCH64_FL_RAS		   AARCH64_FL_V8A
+#define AARCH64_FL_LOR		   AARCH64_FL_V8_1A
+#define AARCH64_FL_PAN		   AARCH64_FL_V8_1A
+#define AARCH64_FL_AMU		   AARCH64_FL_V8_4A
+#define AARCH64_FL_SCXTNUM	   AARCH64_FL_V8_5A
+#define AARCH64_FL_ID_PFR2	   AARCH64_FL_V8_5A
+
+/* Define AARCH64_FL aliases for features note yet implemented in GCC.
+   Accept them unconditionally.  */
+#define AARCH64_FL_SME		   -1
+
+/* Flags associated with the properties of system registers.  It mainly serves
+   to mark particular registers as read or write only.  */
+#define F_DEPRECATED		   (1 << 1)
+#define F_REG_READ		   (1 << 2)
+#define F_REG_WRITE		   (1 << 3)
+#define F_ARCHEXT		   (1 << 4)
+/* Flag indicating register name is alias for another system register.  */
+#define F_REG_ALIAS		   (1 << 5)
+
 /* Crypto is an optional extension to AdvSIMD.  */
 #define TARGET_CRYPTO (AARCH64_ISA_CRYPTO)
 
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 3/7] aarch64: Implement system register validation tools
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 1/7] aarch64: Sync system register information with Binutils Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 19:07   ` Richard Sandiford
  2023-10-18 15:02 ` [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING Victor Do Nascimento
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

Given the implementation of a mechanism of encoding system registers
into GCC, this patch provides the mechanism of validating their use by
the compiler.  In particular, this involves:

  1. Ensuring a supplied string corresponds to a known system
     register name.  System registers can be accessed either via their
     name (e.g. `SPSR_EL1') or their encoding (e.g. `S3_0_C4_C0_0').
     Register names are validated using a hash map, mapping known
     system register names to its corresponding `sysreg_t' struct,
     which is populated from the `aarch64_system_regs.def' file.
     Register name validation is done via `lookup_sysreg_map', while
     the encoding naming convention is validated via a parser
     implemented in this patch - `is_implem_def_reg'.
  2. Once a given register name is deemed to be valid, it is checked
     against a further 2 criteria:
       a. Is the referenced register implemented in the target
          architecture?  This is achieved by comparing the ARCH field
	  in the relevant SYSREG entry from `aarch64_system_regs.def'
	  against `aarch64_feature_flags' flags set at compile-time.
       b. Is the register being used correctly?  Check the requested
       	  operation against the FLAGS specified in SYSREG.
	  This prevents operations like writing to a read-only system
	  register.

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64-protos.h (aarch64_valid_sysreg_name_p): New.
	(aarch64_retrieve_sysreg): Likewise.
	* gcc/config/aarch64/aarch64.cc (is_implem_def_reg): Likewise.
	(aarch64_valid_sysreg_name_p): Likewise.
	(aarch64_retrieve_sysreg): Likewise.
	(aarch64_register_sysreg): Likewise.
	(aarch64_init_sysregs): Likewise.
	(aarch64_lookup_sysreg_map): Likewise.
	* gcc/config/aarch64/predicates.md (aarch64_sysreg_string): New.
---
 gcc/config/aarch64/aarch64-protos.h |   2 +
 gcc/config/aarch64/aarch64.cc       | 146 ++++++++++++++++++++++++++++
 gcc/config/aarch64/predicates.md    |   4 +
 3 files changed, 152 insertions(+)

diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index 60a55f4bc19..a134e2fcf8e 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -830,6 +830,8 @@ bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool);
 bool aarch64_sve_ptrue_svpattern_p (rtx, struct simd_immediate_info *);
 bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *,
 			enum simd_immediate_check w = AARCH64_CHECK_MOV);
+bool aarch64_valid_sysreg_name_p (const char *);
+const char *aarch64_retrieve_sysreg (char *, bool);
 rtx aarch64_check_zero_based_sve_index_immediate (rtx);
 bool aarch64_sve_index_immediate_p (rtx);
 bool aarch64_sve_arith_immediate_p (machine_mode, rtx, bool);
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 69de2366424..816c4b69fc8 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -85,6 +85,7 @@
 #include "config/arm/aarch-common.h"
 #include "config/arm/aarch-common-protos.h"
 #include "ssa.h"
+#include "hash-map.h"
 
 /* This file should be included last.  */
 #include "target-def.h"
@@ -2845,6 +2846,52 @@ const sysreg_t sysreg_structs[] =
 const unsigned nsysreg = TOTAL_ITEMS;
 #undef TOTAL_ITEMS
 
+using sysreg_map_t = hash_map<nofree_string_hash, const sysreg_t *>;
+static sysreg_map_t *sysreg_map = nullptr;
+
+/* Map system register names to their hardware metadata: Encoding,
+   feature flags and architectural feature requirements, all of which
+   are encoded in a sysreg_t struct.  */
+void
+aarch64_register_sysreg (const char *name, const sysreg_t *metadata)
+{
+  bool dup = sysreg_map->put (name, metadata);
+  gcc_checking_assert (!dup);
+}
+
+/* Lazily initialize hash table for system register validation,
+   checking the validity of supplied register name and returning
+   register's associated metadata.  */
+static void
+aarch64_init_sysregs (void)
+{
+  gcc_assert (!sysreg_map);
+  sysreg_map = new sysreg_map_t;
+  gcc_assert (sysreg_map);
+
+  for (unsigned i = 0; i < nsysreg; i++)
+    {
+      const sysreg_t *reg = sysreg_structs + i;
+      aarch64_register_sysreg (reg->name , reg);
+    }
+}
+
+/* No direct access to the sysreg hash-map should be made.  Doing so
+   risks trying to acess an unitialized hash-map and dereferencing the
+   returned double pointer without due care risks dereferencing a
+   null-pointer.  */
+const sysreg_t *
+aarch64_lookup_sysreg_map (const char *regname)
+{
+  if (!sysreg_map)
+    aarch64_init_sysregs ();
+
+  const sysreg_t **sysreg_entry = sysreg_map->get (regname);
+  if (sysreg_entry != NULL)
+    return *sysreg_entry;
+  return NULL;
+}
+
 /* The current tuning set.  */
 struct tune_params aarch64_tune_params = generic_tunings;
 
@@ -28053,6 +28100,105 @@ aarch64_pars_overlap_p (rtx par1, rtx par2)
   return false;
 }
 
+/* Parse an implementation-defined system register name of
+   the form S[0-3]_[0-7]_C[0-15]_C[0-15]_[1-7].
+   Return true if name matched against above pattern, false
+   otherwise.  */
+bool
+is_implem_def_reg (const char *regname)
+{
+    /* Check for implementation-defined system registers.  */
+  int name_len = strlen (regname);
+  if (name_len < 12 || name_len > 14)
+    return false;
+
+  int pos = 0, i = 0, j = 0;
+  char n[3] = {0}, m[3] = {0};
+  if (regname[pos] != 's' && regname[pos] != 'S')
+    return false;
+  pos++;
+  if (regname[pos] < '0' || regname[pos] > '3')
+    return false;
+  pos++;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] < '0' || regname[pos] > '7')
+    return false;
+  pos++;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] != 'c' && regname[pos] != 'C')
+    return false;
+  pos++;
+  while (regname[pos] != '_')
+    {
+      if (i > 2)
+	return false;
+      if (!ISDIGIT (regname[pos]))
+	return false;
+      n[i++] = regname[pos++];
+    }
+  if (atoi (n) > 15)
+    return false;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] != 'c' && regname[pos] != 'C')
+    return false;
+  pos++;
+  while (regname[pos] != '_')
+    {
+      if (j > 2)
+	return false;
+      if (!ISDIGIT (regname[pos]))
+	return false;
+      m[j++] = regname[pos++];
+    }
+  if (atoi (m) > 15)
+    return false;
+  if (regname[pos++] != '_')
+    return false;
+  if (regname[pos] < '0' || regname[pos] > '7')
+    return false;
+  return true;
+}
+
+/* Validate REGNAME against the permitted system register names, or a
+   generic sysreg specification.  For use in back-end predicate
+   `aarch64_sysreg_string'.  */
+bool
+aarch64_valid_sysreg_name_p (const char *regname)
+{
+  const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
+  if (sysreg == NULL)
+    return is_implem_def_reg (regname);
+  return (aarch64_isa_flags & sysreg->arch_reqs);
+}
+
+/* Validate REGNAME against the permitted system register names, or a
+   generic sysreg specification.  WRITE_P is true iff the register is
+   being written to.  */
+const char *
+aarch64_retrieve_sysreg (char *regname, bool write_p)
+{
+  const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
+  if (sysreg == NULL)
+    {
+      if (is_implem_def_reg (regname))
+	return (const char *) regname;
+      else
+	return NULL;
+    }
+  if ((write_p && (sysreg->properties & F_REG_READ))
+      || (!write_p && (sysreg->properties & F_REG_WRITE)))
+    return NULL;
+  if (aarch64_isa_flags & sysreg->arch_reqs)
+    {
+      if (sysreg->encoding)
+	return sysreg->encoding;
+    }
+  return NULL;
+}
+
 /* Target-specific selftests.  */
 
 #if CHECKING_P
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 01de4743974..5f0d242e4a8 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -20,6 +20,10 @@
 
 (include "../arm/common.md")
 
+(define_predicate "aarch64_sysreg_string"
+  (and (match_code "const_string")
+       (match_test "aarch64_valid_sysreg_name_p (XSTR (op, 0))")))
+
 (define_special_predicate "cc_register"
   (and (match_code "reg")
        (and (match_test "REGNO (op) == CC_REGNUM")
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
                   ` (2 preceding siblings ...)
  2023-10-18 15:02 ` [PATCH V2 3/7] aarch64: Implement system register validation tools Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 21:09   ` Richard Sandiford
  2023-10-18 15:02 ` [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions Victor Do Nascimento
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

Motivated by the need to print system register names in output
assembly, this patch adds the required logic to
`aarch64_print_operand' to accept rtxs of type CONST_STRING and
process these accordingly.

Consequently, an rtx such as:

  (set (reg/i:DI 0 x0)
         (unspec:DI [(const_string ("s3_3_c13_c2_2"))])

can now be output correctly using the following output pattern when
composing `define_insn's:

  "mrs\t%x0, %1"

gcc/ChangeLog

	* gcc/config/aarch64/aarch64.cc (aarch64_print_operand): Add
	support for CONST_STRING.
---
 gcc/config/aarch64/aarch64.cc | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 816c4b69fc8..d187e171beb 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -12430,6 +12430,12 @@ aarch64_print_operand (FILE *f, rtx x, int code)
 
       switch (GET_CODE (x))
 	{
+	case CONST_STRING:
+	  {
+	    const char *output_op = XSTR (x, 0);
+	    asm_fprintf (f, "%s", output_op);
+	    break;
+	  }
 	case REG:
 	  if (aarch64_sve_data_mode_p (GET_MODE (x)))
 	    {
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
                   ` (3 preceding siblings ...)
  2023-10-18 15:02 ` [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 20:39   ` Richard Sandiford
  2023-10-18 15:02 ` [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins Victor Do Nascimento
  2023-10-18 15:02 ` [PATCH V2 7/7] aarch64: Add system register duplication check selftest Victor Do Nascimento
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

Implement the aarch64 intrinsics for reading and writing system
registers with the following signatures:

	uint32_t __arm_rsr(const char *special_register);
	uint64_t __arm_rsr64(const char *special_register);
	void* __arm_rsrp(const char *special_register);
	float __arm_rsrf(const char *special_register);
	double __arm_rsrf64(const char *special_register);
	void __arm_wsr(const char *special_register, uint32_t value);
	void __arm_wsr64(const char *special_register, uint64_t value);
	void __arm_wsrp(const char *special_register, const void *value);
	void __arm_wsrf(const char *special_register, float value);
	void __arm_wsrf64(const char *special_register, double value);

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
	Add enums for new builtins.
	(aarch64_init_rwsr_builtins): New.
	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
	(aarch64_expand_rwsr_builtin):  New.
	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
	(write_sysregdi): Likewise.
	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
	(__arm_rsrp): Likewise.
	(__arm_rsr64): Likewise.
	(__arm_rsrf): Likewise.
	(__arm_rsrf64): Likewise.
	(__arm_wsr): Likewise.
	(__arm_wsrp): Likewise.
	(__arm_wsr64): Likewise.
	(__arm_wsrf): Likewise.
	(__arm_wsrf64): Likewise.

gcc/testsuite/ChangeLog:

	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
---
 gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
 gcc/config/aarch64/aarch64.md                 |  17 ++
 gcc/config/aarch64/arm_acle.h                 |  30 +++
 .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
 5 files changed, 411 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c

diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index 04f59fd9a54..d8bb2a989a5 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -808,6 +808,17 @@ enum aarch64_builtins
   AARCH64_RBIT,
   AARCH64_RBITL,
   AARCH64_RBITLL,
+  /* System register builtins.  */
+  AARCH64_RSR,
+  AARCH64_RSRP,
+  AARCH64_RSR64,
+  AARCH64_RSRF,
+  AARCH64_RSRF64,
+  AARCH64_WSR,
+  AARCH64_WSRP,
+  AARCH64_WSR64,
+  AARCH64_WSRF,
+  AARCH64_WSRF64,
   AARCH64_BUILTIN_MAX
 };
 
@@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
 				   AARCH64_BUILTIN_RNG_RNDRRS);
 }
 
+/* Add builtins for reading system register.  */
+static void
+aarch64_init_rwsr_builtins (void)
+{
+  tree fntype = NULL;
+  tree const_char_ptr_type
+    = build_pointer_type (build_type_variant (char_type_node, true, false));
+
+#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
+  aarch64_builtin_decls[AARCH64_##F] \
+    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
+
+  fntype
+    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
+
+  fntype
+    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
+
+  fntype
+    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
+
+  fntype
+    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
+
+  fntype
+    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
+
+  fntype
+    = build_function_type_list (void_type_node, const_char_ptr_type,
+				uint32_type_node, NULL);
+
+  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
+
+  fntype
+    = build_function_type_list (void_type_node, const_char_ptr_type,
+				const_ptr_type_node, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
+
+  fntype
+    = build_function_type_list (void_type_node, const_char_ptr_type,
+				uint64_type_node, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
+
+  fntype
+    = build_function_type_list (void_type_node, const_char_ptr_type,
+				float_type_node, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
+
+  fntype
+    = build_function_type_list (void_type_node, const_char_ptr_type,
+				double_type_node, NULL);
+  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
+}
+
 /* Initialize the memory tagging extension (MTE) builtins.  */
 struct
 {
@@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
   aarch64_init_rng_builtins ();
   aarch64_init_data_intrinsics ();
 
+  aarch64_init_rwsr_builtins ();
+
   tree ftype_jcvt
     = build_function_type_list (intSI_type_node, double_type_node, NULL);
   aarch64_builtin_decls[AARCH64_JSCVT]
@@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
   return target;
 }
 
+/* Expand the read/write system register builtin EXPs.  */
+rtx
+aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
+{
+  tree arg0, arg1;
+  rtx const_str, input_val, subreg;
+  enum machine_mode mode;
+  class expand_operand ops[2];
+
+  arg0 = CALL_EXPR_ARG (exp, 0);
+
+  bool write_op = (fcode == AARCH64_WSR
+		   || fcode == AARCH64_WSRP
+		   || fcode == AARCH64_WSR64
+		   || fcode == AARCH64_WSRF
+		   || fcode == AARCH64_WSRF64);
+  bool read_op = (fcode == AARCH64_RSR
+		  || fcode == AARCH64_RSRP
+		  || fcode == AARCH64_RSR64
+		  || fcode == AARCH64_RSRF
+		  || fcode == AARCH64_RSRF64);
+
+  /* Argument 0 (system register name) must be a string literal.  */
+  gcc_assert (!SSA_VAR_P (arg0)
+	      && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
+	      && TREE_CODE (TREE_OPERAND (arg0,0)) == STRING_CST);
+
+  const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
+  size_t len = strlen (name_input);
+
+  if (len == 0)
+    {
+      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
+      return const0_rtx;
+    }
+
+  char *sysreg_name = (char *) alloca (len + 1);
+  strcpy (sysreg_name, name_input);
+
+  for (unsigned pos = 0; pos <= len; pos++)
+    sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
+
+  const char* name_output = aarch64_retrieve_sysreg (sysreg_name, write_op);
+  if (name_output == NULL)
+    {
+      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
+      return const0_rtx;
+    }
+
+  /* Assign the string corresponding to the system register name to an RTX.  */
+  const_str = rtx_alloc (CONST_STRING);
+  PUT_CODE (const_str, CONST_STRING);
+  XSTR (const_str, 0) = xstrdup (name_output);
+
+  /* Set up expander operands and call instruction expansion.  */
+  if (read_op)
+    {
+
+      /* Emit the initial read_sysregdi rtx.  */
+      create_output_operand (&ops[0], target, DImode);
+      create_fixed_operand (&ops[1], const_str);
+      expand_insn (CODE_FOR_aarch64_read_sysregdi, 2, ops);
+      target = ops[0].value;
+
+      /* Do any necessary post-processing on the result.  */
+      switch (fcode)
+	{
+	case AARCH64_RSR:
+	  return gen_lowpart_SUBREG (SImode, target);
+	case AARCH64_RSRP:
+	case AARCH64_RSR64:
+	  return target;
+	case AARCH64_RSRF:
+	  subreg = gen_reg_rtx (SImode);
+	  subreg = gen_lowpart_SUBREG (SImode, target);
+	  return gen_lowpart_SUBREG (SFmode, subreg);
+	case AARCH64_RSRF64:
+	  return gen_lowpart_SUBREG (DFmode, target);
+	}
+    }
+  if (write_op)
+    {
+
+      arg1 = CALL_EXPR_ARG (exp, 1);
+      mode = TYPE_MODE (TREE_TYPE (arg1));
+      input_val = copy_to_mode_reg (mode, expand_normal (arg1));
+
+      switch (fcode)
+	{
+	case AARCH64_WSR:
+	  subreg = gen_lowpart_SUBREG (DImode, input_val);
+	  break;
+	case AARCH64_WSRP:
+	case AARCH64_WSR64:
+	  subreg = input_val;
+	  break;
+	case AARCH64_WSRF:
+	  subreg = gen_lowpart_SUBREG (SImode, input_val);
+	  subreg = gen_lowpart_SUBREG (DImode, subreg);
+	  break;
+	case AARCH64_WSRF64:
+	  subreg = gen_lowpart_SUBREG (DImode, input_val);
+	  break;
+	}
+
+      create_fixed_operand (&ops[0], const_str);
+      create_input_operand (&ops[1], subreg, DImode);
+      expand_insn (CODE_FOR_aarch64_write_sysregdi, 2, ops);
+
+      return target;
+    }
+
+  error_at (EXPR_LOCATION (exp),
+	    "Malformed call to read/write system register builtin");
+  return target;
+}
+
 /* Expand an expression EXP that calls a MEMTAG built-in FCODE
    with result going to TARGET.  */
 static rtx
@@ -2832,6 +3021,17 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
     case AARCH64_BUILTIN_RNG_RNDR:
     case AARCH64_BUILTIN_RNG_RNDRRS:
       return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
+    case AARCH64_RSR:
+    case AARCH64_RSRP:
+    case AARCH64_RSR64:
+    case AARCH64_RSRF:
+    case AARCH64_RSRF64:
+    case AARCH64_WSR:
+    case AARCH64_WSRP:
+    case AARCH64_WSR64:
+    case AARCH64_WSRF:
+    case AARCH64_WSRF64:
+      return aarch64_expand_rwsr_builtin (exp, target, fcode);
     }
 
   if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index 32c7adc8928..80da30bc30c 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -281,6 +281,8 @@
     UNSPEC_UPDATE_FFRT
     UNSPEC_RDFFR
     UNSPEC_WRFFR
+    UNSPEC_SYSREG_RDI
+    UNSPEC_SYSREG_WDI
     ;; Represents an SVE-style lane index, in which the indexing applies
     ;; within the containing 128-bit block.
     UNSPEC_SVE_LANE_SELECT
@@ -476,6 +478,21 @@
 ;; Jumps and other miscellaneous insns
 ;; -------------------------------------------------------------------
 
+(define_insn "aarch64_read_sysregdi"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec_volatile:DI [(match_operand 1 "aarch64_sysreg_string" "")]
+		  UNSPEC_SYSREG_RDI))]
+ ""
+ "mrs\t%x0, %1"
+ )
+
+(define_insn "aarch64_write_sysregdi"
+ [(unspec_volatile:DI [(match_operand 0 "aarch64_sysreg_string" "")
+	      (match_operand:DI 1 "register_operand" "r")] UNSPEC_SYSREG_WDI)]
+ ""
+ "msr\t%0, %x1"
+ )
+
 (define_insn "indirect_jump"
   [(set (pc) (match_operand:DI 0 "register_operand" "r"))]
   ""
diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
index 7599a32301d..71ada878299 100644
--- a/gcc/config/aarch64/arm_acle.h
+++ b/gcc/config/aarch64/arm_acle.h
@@ -314,6 +314,36 @@ __rndrrs (uint64_t *__res)
 
 #pragma GCC pop_options
 
+#define __arm_rsr(__regname) \
+  __builtin_aarch64_rsr (__regname)
+
+#define __arm_rsrp(__regname) \
+  __builtin_aarch64_rsrp (__regname)
+
+#define __arm_rsr64(__regname) \
+  __builtin_aarch64_rsr64 (__regname)
+
+#define __arm_rsrf(__regname) \
+  __builtin_aarch64_rsrf (__regname)
+
+#define __arm_rsrf64(__regname) \
+  __builtin_aarch64_rsrf64 (__regname)
+
+#define __arm_wsr(__regname, __value) \
+  __builtin_aarch64_wsr (__regname, __value)
+
+#define __arm_wsrp(__regname, __value) \
+  __builtin_aarch64_wsrp (__regname, __value)
+
+#define __arm_wsr64(__regname, __value) \
+  __builtin_aarch64_wsr64 (__regname, __value)
+
+#define __arm_wsrf(__regname, __value) \
+  __builtin_aarch64_wsrf (__regname, __value)
+
+#define __arm_wsrf64(__regname, __value) \
+  __builtin_aarch64_wsrf64 (__regname, __value)
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
new file mode 100644
index 00000000000..bc9db098f16
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
@@ -0,0 +1,20 @@
+/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
+/* Ensure that illegal behavior is rejected by the compiler.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=armv8.4-a" } */
+
+#include <arm_acle.h>
+
+/* Ensure that read/write-only register attributes are respected by the compiler.  */
+void
+test_rwsr_read_write_only ()
+{
+  /* Attempt to write to read-only registers.  */
+  long long a = __arm_rsr64 ("aidr_el1");  /* Read ok.  */
+  __arm_wsr64 ("aidr_el1", a); /* { dg-error {invalid system register name provided} } */
+
+  /* Attempt to read from write-only registers.  */
+  __arm_wsr64("icc_asgi1r_el1", a);            /* Write ok.  */
+  long long b = __arm_rsr64("icc_asgi1r_el1"); /* { dg-error {invalid system register name provided} } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
new file mode 100644
index 00000000000..3af4b960306
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
@@ -0,0 +1,144 @@
+/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
+/* Check that function variants for different data types handle types correctly.  */
+/* { dg-do compile } */
+/* { dg-options "-O1 -march=armv8.4-a" } */
+/* { dg-final { check-function-bodies "**" "" } } */
+
+#include <arm_acle.h>
+
+/*
+** get_rsr:
+** ...
+** 	mrs	x([0-9]+), s2_1_c0_c7_4
+** 	add	w\1, w\1, 1
+** ...
+*/
+int
+get_rsr ()
+{
+  int a =  __arm_rsr("trcseqstr");
+  return a+1;
+}
+
+/*
+** get_rsrf:
+** 	mrs	x([0-9]+), s2_1_c0_c7_4
+** 	fmov	s[0-9]+, w\1
+** ...
+*/
+float
+get_rsrf ()
+{
+  return __arm_rsrf("trcseqstr");
+}
+
+/*
+** get_rsrp:
+** 	mrs	x0, s2_1_c0_c7_4
+** 	ret
+*/
+void *
+get_rsrp ()
+{
+  return __arm_rsrp("trcseqstr");
+}
+
+/*
+** get_rsr64:
+** 	mrs	x0, s2_1_c0_c7_4
+** 	ret
+*/
+long long
+get_rsr64 ()
+{
+  return __arm_rsr64("trcseqstr");
+}
+
+/*
+** get_rsrf64:
+** 	mrs	x([0-9]+), s2_1_c0_c7_4
+** 	fmov	d[0-9]+, x\1
+** ...
+*/
+double
+get_rsrf64 ()
+{
+  return __arm_rsrf64("trcseqstr");
+}
+
+/*
+** set_wsr32:
+** ...
+** 	add	w([0-9]+), w\1, 1
+** 	msr	s2_1_c0_c7_4, x\1
+** ...
+*/
+void
+set_wsr32 (int a)
+{
+  __arm_wsr("trcseqstr", a+1);
+}
+
+/*
+** set_wsrp:
+** ...
+** 	msr	s2_1_c0_c7_4, x[0-9]+
+** ...
+*/
+void
+set_wsrp (void *a)
+{
+  __arm_wsrp("trcseqstr", a);
+}
+
+/*
+** set_wsr64:
+** ...
+** 	msr	s2_1_c0_c7_4, x[0-9]+
+** ...
+*/
+void
+set_wsr64 (long long a)
+{
+  __arm_wsr64("trcseqstr", a);
+}
+
+/*
+** set_wsrf32:
+** ...
+** 	fmov	w([0-9]+), s[0-9]+
+** 	msr	s2_1_c0_c7_4, x\1
+** ...
+*/
+void
+set_wsrf32 (float a)
+{
+  __arm_wsrf("trcseqstr", a);
+}
+
+/*
+** set_wsrf64:
+** ...
+** 	fmov	x([0-9]+), d[0-9]+
+** 	msr	s2_1_c0_c7_4, x\1
+** ...
+*/
+void
+set_wsrf64(double a)
+{
+  __arm_wsrf64("trcseqstr", a);
+}
+
+/*
+** set_custom:
+** ...
+** 	mrs	x0, s1_2_c3_c4_5
+** ...
+** 	msr	s1_2_c3_c4_5, x0
+** ...
+*/
+void set_custom()
+{
+  __uint64_t b = __arm_rsr64("S1_2_C3_C4_5");
+  __arm_wsr64("S1_2_C3_C4_5", b);
+}
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
                   ` (4 preceding siblings ...)
  2023-10-18 15:02 ` [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 21:20   ` Richard Sandiford
  2023-10-18 15:02 ` [PATCH V2 7/7] aarch64: Add system register duplication check selftest Victor Do Nascimento
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

In implementing the ACLE read/write system register builtins it was
observed that leaving argument type checking to be done at expand-time
meant that poorly-formed function calls were being "fixed" by certain
optimization passes, meaning bad code wasn't being properly picked up
in checking.

Example:

  const char *regname = "amcgcr_el0";
  long long a = __builtin_aarch64_rsr64 (regname);

is reduced by the ccp1 pass to

  long long a = __builtin_aarch64_rsr64 ("amcgcr_el0");

As these functions require an argument of STRING_CST type, there needs
to be a check carried out by the front-end capable of picking this up.

The introduced `check_general_builtin_call' function will be called by
the TARGET_CHECK_BUILTIN_CALL hook whenever a call to a builtin
belonging to the AARCH64_BUILTIN_GENERAL category is encountered,
carrying out any appropriate checks associated with a particular
builtin function code.

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64-builtins.cc (check_general_builtin_call):
	New.
	* gcc/config/aarch64/aarch64-c.cc (aarch64_check_builtin_call):
	Add check_general_builtin_call call.
	* gcc/config/aarch64/aarch64-protos.h (check_general_builtin_call):
	New.

gcc/testsuite/ChangeLog:

	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c: New.
---
 gcc/config/aarch64/aarch64-builtins.cc        | 33 +++++++++++++++++++
 gcc/config/aarch64/aarch64-c.cc               |  4 +--
 gcc/config/aarch64/aarch64-protos.h           |  3 ++
 .../gcc.target/aarch64/acle/rwsr-2.c          | 15 +++++++++
 4 files changed, 53 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c

diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
index d8bb2a989a5..6734361f4f4 100644
--- a/gcc/config/aarch64/aarch64-builtins.cc
+++ b/gcc/config/aarch64/aarch64-builtins.cc
@@ -2126,6 +2126,39 @@ aarch64_general_builtin_decl (unsigned code, bool)
   return aarch64_builtin_decls[code];
 }
 
+bool
+check_general_builtin_call (location_t location, vec<location_t>,
+			    unsigned int code, tree fndecl,
+			    unsigned int nargs ATTRIBUTE_UNUSED, tree *args)
+{
+  switch (code)
+    {
+    case AARCH64_RSR:
+    case AARCH64_RSRP:
+    case AARCH64_RSR64:
+    case AARCH64_RSRF:
+    case AARCH64_RSRF64:
+    case AARCH64_WSR:
+    case AARCH64_WSRP:
+    case AARCH64_WSR64:
+    case AARCH64_WSRF:
+    case AARCH64_WSRF64:
+      if (TREE_CODE (args[0]) == VAR_DECL
+	  || TREE_CODE (TREE_TYPE (args[0])) != POINTER_TYPE
+	      || TREE_CODE (TREE_OPERAND (TREE_OPERAND (args[0], 0) , 0))
+		  != STRING_CST)
+	{
+	  const char  *fn_name, *err_msg;
+	  fn_name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
+	  err_msg = "first argument to %<%s%> must be a string literal";
+	  error_at (location, err_msg, fn_name);
+	  return false;
+	}
+    }
+  /* Default behavior.  */
+  return true;
+}
+
 typedef enum
 {
   SIMD_ARG_COPY_TO_REG,
diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc
index ab8844f6049..c2a9a59df73 100644
--- a/gcc/config/aarch64/aarch64-c.cc
+++ b/gcc/config/aarch64/aarch64-c.cc
@@ -339,8 +339,8 @@ aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc,
   switch (code & AARCH64_BUILTIN_CLASS)
     {
     case AARCH64_BUILTIN_GENERAL:
-      return true;
-
+      return check_general_builtin_call (loc, arg_loc, subcode, orig_fndecl,
+					 nargs, args);
     case AARCH64_BUILTIN_SVE:
       return aarch64_sve::check_builtin_call (loc, arg_loc, subcode,
 					      orig_fndecl, nargs, args);
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index a134e2fcf8e..9ef96ff511f 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -990,6 +990,9 @@ tree aarch64_general_builtin_rsqrt (unsigned int);
 void handle_arm_acle_h (void);
 void handle_arm_neon_h (void);
 
+bool check_general_builtin_call (location_t, vec<location_t>, unsigned int,
+			      tree, unsigned int, tree *);
+
 namespace aarch64_sve {
   void init_builtins ();
   void handle_arm_sve_h ();
diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
new file mode 100644
index 00000000000..72e5fb75b21
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
@@ -0,0 +1,15 @@
+/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
+/* Ensure that illegal behavior is rejected by the compiler.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=armv8.4-a" } */
+
+#include <arm_acle.h>
+
+void
+test_non_const_sysreg_name ()
+{
+  const char *regname = "trcseqstr";
+  long long a = __arm_rsr64 (regname); /* { dg-error "first argument to '__builtin_aarch64_rsr64' must be a string literal" } */
+  __arm_wsr64 (regname, a); /* { dg-error "first argument to '__builtin_aarch64_wsr64' must be a string literal" } */
+}
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH V2 7/7] aarch64: Add system register duplication check selftest
  2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
                   ` (5 preceding siblings ...)
  2023-10-18 15:02 ` [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins Victor Do Nascimento
@ 2023-10-18 15:02 ` Victor Do Nascimento
  2023-10-18 21:30   ` Richard Sandiford
  6 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-18 15:02 UTC (permalink / raw)
  To: gcc-patches
  Cc: kyrylo.tkachov, richard.sandiford, Richard.Earnshaw,
	Victor Do Nascimento

Add a build-time test to check whether system register data, as
imported from `aarch64-sys-reg.def' has any duplicate entries.

Duplicate entries are defined as any two SYSREG entries in the .def
file which share the same encoding values (as specified by its `CPENC'
field) and where the relationship amongst the two does not fit into
one of the following categories:

	* Simple aliasing: In some cases, it is observed that one
	register name serves as an alias to another.  One example of
	this is where TRCEXTINSELR aliases TRCEXTINSELR0.
	* Expressing intent: It is possible that when a given register
	serves two distinct functions depending on how it is used, it
	is given two distinct names whose use should match the context
	under which it is being used.  Example:  Debug Data Transfer
	Register. When used to receive data, it should be accessed as
	DBGDTRRX_EL0 while when transmitting data it should be
	accessed via DBGDTRTX_EL0.
	* Register depreciation: Some register names have been
	deprecated and should no longer be used, but backwards-
	compatibility requires that such names continue to be
	recognized, as is the case for the SPSR_EL1 register, whose
	access via the SPSR_SVC name is now deprecated.
	* Same encoding different target: Some encodings are given
	different meaning depending on the target architecture and, as
	such, are given different names in each of theses contexts.
	We see an example of this for CPENC(3,4,2,0,0), which
	corresponds to TTBR0_EL2 for Armv8-A targets and VSCTLR_EL2
	in Armv8-R targets.

A consequence of these observations is that `CPENC' duplication is
acceptable iff at least one of the `properties' or `arch_reqs' fields
of the `sysreg_t' structs associated with the two registers in
question differ and it's this condition that is checked by the new
`aarch64_test_sysreg_encoding_clashes' function.

gcc/ChangeLog:

	* gcc/config/aarch64/aarch64.cc
	(aarch64_test_sysreg_encoding_clashes): New.
	(aarch64_run_selftests): add call to
	aarch64_test_sysreg_encoding_clashes selftest.
---
 gcc/config/aarch64/aarch64.cc | 53 +++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index d187e171beb..e0be2877ede 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -22,6 +22,7 @@
 
 #define INCLUDE_STRING
 #define INCLUDE_ALGORITHM
+#define INCLUDE_VECTOR
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
@@ -28332,6 +28333,57 @@ aarch64_test_fractional_cost ()
   ASSERT_EQ (cf (1, 2).as_double (), 0.5);
 }
 
+/* Calculate whether our system register data, as imported from
+   `aarch64-sys-reg.def' has any duplicate entries.  */
+static void
+aarch64_test_sysreg_encoding_clashes (void)
+{
+  using dup_counters_t = hash_map<nofree_string_hash, unsigned>;
+  using dup_instances_t = hash_map<nofree_string_hash,
+				   std::vector<const sysreg_t*>>;
+
+  dup_counters_t duplicate_counts;
+  dup_instances_t duplicate_instances;
+
+  /* Every time an encoding is established to come up more than once
+  we add it to a "clash-analysis queue", which is then used to extract
+  necessary information from our hash map when establishing whether
+  repeated encodings are valid.  */
+
+  /* 1) Collect recurrence information.  */
+  std::vector<const char*> testqueue;
+
+  for (unsigned i = 0; i < nsysreg; i++)
+    {
+      const sysreg_t *reg = sysreg_structs + i;
+
+      unsigned *tbl_entry = &duplicate_counts.get_or_insert (reg->encoding);
+      *tbl_entry += 1;
+
+      std::vector<const sysreg_t*> *tmp
+	= &duplicate_instances.get_or_insert (reg->encoding);
+
+      tmp->push_back (reg);
+      if (*tbl_entry > 1)
+	  testqueue.push_back (reg->encoding);
+    }
+
+  /* 2) Carry out analysis on collected data.  */
+  for (auto enc : testqueue)
+    {
+      unsigned nrep = *duplicate_counts.get (enc);
+      for (unsigned i = 0; i < nrep; i++)
+	for (unsigned j = i+1; j < nrep; j++)
+	  {
+	    std::vector<const sysreg_t*> *tmp2 = duplicate_instances.get (enc);
+	    const sysreg_t *a = (*tmp2)[i];
+	    const sysreg_t *b = (*tmp2)[j];
+	    ASSERT_TRUE ((a->properties != b->properties)
+			 || (a->arch_reqs != b->arch_reqs));
+	  }
+    }
+}
+
 /* Run all target-specific selftests.  */
 
 static void
@@ -28339,6 +28391,7 @@ aarch64_run_selftests (void)
 {
   aarch64_test_loading_full_dump ();
   aarch64_test_fractional_cost ();
+  aarch64_test_sysreg_encoding_clashes ();
 }
 
 } // namespace selftest
-- 
2.41.0


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 3/7] aarch64: Implement system register validation tools
  2023-10-18 15:02 ` [PATCH V2 3/7] aarch64: Implement system register validation tools Victor Do Nascimento
@ 2023-10-18 19:07   ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 19:07 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Generally looks really good.  Some comments below.

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> Given the implementation of a mechanism of encoding system registers
> into GCC, this patch provides the mechanism of validating their use by
> the compiler.  In particular, this involves:
>
>   1. Ensuring a supplied string corresponds to a known system
>      register name.  System registers can be accessed either via their
>      name (e.g. `SPSR_EL1') or their encoding (e.g. `S3_0_C4_C0_0').
>      Register names are validated using a hash map, mapping known
>      system register names to its corresponding `sysreg_t' struct,
>      which is populated from the `aarch64_system_regs.def' file.
>      Register name validation is done via `lookup_sysreg_map', while
>      the encoding naming convention is validated via a parser
>      implemented in this patch - `is_implem_def_reg'.
>   2. Once a given register name is deemed to be valid, it is checked
>      against a further 2 criteria:
>        a. Is the referenced register implemented in the target
>           architecture?  This is achieved by comparing the ARCH field
> 	  in the relevant SYSREG entry from `aarch64_system_regs.def'
> 	  against `aarch64_feature_flags' flags set at compile-time.
>        b. Is the register being used correctly?  Check the requested
>        	  operation against the FLAGS specified in SYSREG.
> 	  This prevents operations like writing to a read-only system
> 	  register.
>
> gcc/ChangeLog:
>
> 	* gcc/config/aarch64/aarch64-protos.h (aarch64_valid_sysreg_name_p): New.
> 	(aarch64_retrieve_sysreg): Likewise.
> 	* gcc/config/aarch64/aarch64.cc (is_implem_def_reg): Likewise.
> 	(aarch64_valid_sysreg_name_p): Likewise.
> 	(aarch64_retrieve_sysreg): Likewise.
> 	(aarch64_register_sysreg): Likewise.
> 	(aarch64_init_sysregs): Likewise.
> 	(aarch64_lookup_sysreg_map): Likewise.
> 	* gcc/config/aarch64/predicates.md (aarch64_sysreg_string): New.
> ---
>  gcc/config/aarch64/aarch64-protos.h |   2 +
>  gcc/config/aarch64/aarch64.cc       | 146 ++++++++++++++++++++++++++++
>  gcc/config/aarch64/predicates.md    |   4 +
>  3 files changed, 152 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
> index 60a55f4bc19..a134e2fcf8e 100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -830,6 +830,8 @@ bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool);
>  bool aarch64_sve_ptrue_svpattern_p (rtx, struct simd_immediate_info *);
>  bool aarch64_simd_valid_immediate (rtx, struct simd_immediate_info *,
>  			enum simd_immediate_check w = AARCH64_CHECK_MOV);
> +bool aarch64_valid_sysreg_name_p (const char *);
> +const char *aarch64_retrieve_sysreg (char *, bool);
>  rtx aarch64_check_zero_based_sve_index_immediate (rtx);
>  bool aarch64_sve_index_immediate_p (rtx);
>  bool aarch64_sve_arith_immediate_p (machine_mode, rtx, bool);
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 69de2366424..816c4b69fc8 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -85,6 +85,7 @@
>  #include "config/arm/aarch-common.h"
>  #include "config/arm/aarch-common-protos.h"
>  #include "ssa.h"
> +#include "hash-map.h"
>  
>  /* This file should be included last.  */
>  #include "target-def.h"
> @@ -2845,6 +2846,52 @@ const sysreg_t sysreg_structs[] =
>  const unsigned nsysreg = TOTAL_ITEMS;
>  #undef TOTAL_ITEMS
>  
> +using sysreg_map_t = hash_map<nofree_string_hash, const sysreg_t *>;
> +static sysreg_map_t *sysreg_map = nullptr;

One concern with static, non-GTY, runtime-initialised data is "does it
work with PCH?".  I suspect it does, since all uses of the map go through
aarch64_lookup_sysreg_map, and since nothing seems to rely on persistent
pointer values.  But it would be good to have a PCH test just to make sure.

I'm thinking of something like the tests in gcc/testsuite/gcc.dg/pch.
The header file (.hs) would define a function that does sysreg reads
and writes.  When the .hs is included from the .c file, the reads and
writes would be imported through a PCH load, rather than through the
normal frontend route.

> +
> +/* Map system register names to their hardware metadata: Encoding,

s/Encoding/encoding/

> +   feature flags and architectural feature requirements, all of which
> +   are encoded in a sysreg_t struct.  */
> +void
> +aarch64_register_sysreg (const char *name, const sysreg_t *metadata)
> +{
> +  bool dup = sysreg_map->put (name, metadata);
> +  gcc_checking_assert (!dup);
> +}
> +
> +/* Lazily initialize hash table for system register validation,
> +   checking the validity of supplied register name and returning
> +   register's associated metadata.  */
> +static void
> +aarch64_init_sysregs (void)
> +{
> +  gcc_assert (!sysreg_map);
> +  sysreg_map = new sysreg_map_t;
> +  gcc_assert (sysreg_map);

This assert seems redundant.  new should abort with std::bad_alloc if
allocation fails.

> +
> +  for (unsigned i = 0; i < nsysreg; i++)
> +    {
> +      const sysreg_t *reg = sysreg_structs + i;
> +      aarch64_register_sysreg (reg->name , reg);

Nit: the coding convention adds no space before ",".

> +    }
> +}
> +
> +/* No direct access to the sysreg hash-map should be made.  Doing so
> +   risks trying to acess an unitialized hash-map and dereferencing the
> +   returned double pointer without due care risks dereferencing a
> +   null-pointer.  */
> +const sysreg_t *
> +aarch64_lookup_sysreg_map (const char *regname)
> +{
> +  if (!sysreg_map)
> +    aarch64_init_sysregs ();
> +
> +  const sysreg_t **sysreg_entry = sysreg_map->get (regname);
> +  if (sysreg_entry != NULL)
> +    return *sysreg_entry;
> +  return NULL;
> +}
> +
>  /* The current tuning set.  */
>  struct tune_params aarch64_tune_params = generic_tunings;
>  
> @@ -28053,6 +28100,105 @@ aarch64_pars_overlap_p (rtx par1, rtx par2)
>    return false;
>  }
>  
> +/* Parse an implementation-defined system register name of
> +   the form S[0-3]_[0-7]_C[0-15]_C[0-15]_[1-7].
> +   Return true if name matched against above pattern, false
> +   otherwise.  */
> +bool
> +is_implem_def_reg (const char *regname)
> +{
> +    /* Check for implementation-defined system registers.  */

Nit: too much indentation.  But I think this comment is redundant
with the one above the function.

> +  int name_len = strlen (regname);
> +  if (name_len < 12 || name_len > 14)
> +    return false;
> +
> +  int pos = 0, i = 0, j = 0;
> +  char n[3] = {0}, m[3] = {0};
> +  if (regname[pos] != 's' && regname[pos] != 'S')
> +    return false;
> +  pos++;
> +  if (regname[pos] < '0' || regname[pos] > '3')
> +    return false;
> +  pos++;
> +  if (regname[pos++] != '_')
> +    return false;
> +  if (regname[pos] < '0' || regname[pos] > '7')
> +    return false;
> +  pos++;
> +  if (regname[pos++] != '_')
> +    return false;
> +  if (regname[pos] != 'c' && regname[pos] != 'C')
> +    return false;
> +  pos++;
> +  while (regname[pos] != '_')
> +    {
> +      if (i > 2)
> +	return false;
> +      if (!ISDIGIT (regname[pos]))
> +	return false;
> +      n[i++] = regname[pos++];
> +    }
> +  if (atoi (n) > 15)
> +    return false;

It looks like this will accept C00 to C09 as a synonym of C0 to C9.
Unfortunately the tools seem a bit inconsistent on this.  GAS allows
any number of leading 0s (C0000000000000001: not a problem), whereas
Clang forbids any leading zeros.

I suppose we should avoid introducing a third variation in GCC.
Given that the code is already checking lengths, it probably makes
sense to follow Clang's behaviour.

> +  if (regname[pos++] != '_')
> +    return false;
> +  if (regname[pos] != 'c' && regname[pos] != 'C')
> +    return false;
> +  pos++;
> +  while (regname[pos] != '_')
> +    {
> +      if (j > 2)
> +	return false;
> +      if (!ISDIGIT (regname[pos]))
> +	return false;
> +      m[j++] = regname[pos++];
> +    }
> +  if (atoi (m) > 15)
> +    return false;

It'd be good to avoid the duplication here.  Maybe worth putting
the "C..." parsing into a lambda?

> +  if (regname[pos++] != '_')
> +    return false;
> +  if (regname[pos] < '0' || regname[pos] > '7')
> +    return false;
> +  return true;
> +}
> +
> +/* Validate REGNAME against the permitted system register names, or a
> +   generic sysreg specification.  For use in back-end predicate
> +   `aarch64_sysreg_string'.  */

"Return true if ..." might be a better construct here.  "Validate ..."
can imply error reporting.

> +bool
> +aarch64_valid_sysreg_name_p (const char *regname)
> +{
> +  const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
> +  if (sysreg == NULL)
> +    return is_implem_def_reg (regname);
> +  return (aarch64_isa_flags & sysreg->arch_reqs);
> +}
> +
> +/* Validate REGNAME against the permitted system register names, or a
> +   generic sysreg specification.  WRITE_P is true iff the register is
> +   being written to.  */

The comment should describe the return value, which AIUI is the
generic specification.

> +const char *
> +aarch64_retrieve_sysreg (char *regname, bool write_p)

What requires regname to be a non-const char *?

> +{
> +  const sysreg_t *sysreg = aarch64_lookup_sysreg_map (regname);
> +  if (sysreg == NULL)
> +    {
> +      if (is_implem_def_reg (regname))
> +	return (const char *) regname;
> +      else
> +	return NULL;
> +    }
> +  if ((write_p && (sysreg->properties & F_REG_READ))
> +      || (!write_p && (sysreg->properties & F_REG_WRITE)))
> +    return NULL;
> +  if (aarch64_isa_flags & sysreg->arch_reqs)
> +    {
> +      if (sysreg->encoding)
> +	return sysreg->encoding;

Could you explain the purpose of the "if (sysreg->encoding)" statement?
It looked odd that we could find a matching entry but still return null.
If possible, it would be good to assert that the encoding is nonnull
instead.

Thanks,
Richard

> +    }
> +  return NULL;
> +}
> +
>  /* Target-specific selftests.  */
>  
>  #if CHECKING_P
> diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
> index 01de4743974..5f0d242e4a8 100644
> --- a/gcc/config/aarch64/predicates.md
> +++ b/gcc/config/aarch64/predicates.md
> @@ -20,6 +20,10 @@
>  
>  (include "../arm/common.md")
>  
> +(define_predicate "aarch64_sysreg_string"
> +  (and (match_code "const_string")
> +       (match_test "aarch64_valid_sysreg_name_p (XSTR (op, 0))")))
> +
>  (define_special_predicate "cc_register"
>    (and (match_code "reg")
>         (and (match_test "REGNO (op) == CC_REGNUM")

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-18 15:02 ` [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions Victor Do Nascimento
@ 2023-10-18 20:39   ` Richard Sandiford
  2023-10-26 15:06     ` Victor Do Nascimento
  0 siblings, 1 reply; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 20:39 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> Implement the aarch64 intrinsics for reading and writing system
> registers with the following signatures:
>
> 	uint32_t __arm_rsr(const char *special_register);
> 	uint64_t __arm_rsr64(const char *special_register);
> 	void* __arm_rsrp(const char *special_register);
> 	float __arm_rsrf(const char *special_register);
> 	double __arm_rsrf64(const char *special_register);
> 	void __arm_wsr(const char *special_register, uint32_t value);
> 	void __arm_wsr64(const char *special_register, uint64_t value);
> 	void __arm_wsrp(const char *special_register, const void *value);
> 	void __arm_wsrf(const char *special_register, float value);
> 	void __arm_wsrf64(const char *special_register, double value);
>
> gcc/ChangeLog:
>
> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
> 	Add enums for new builtins.
> 	(aarch64_init_rwsr_builtins): New.
> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
> 	(aarch64_expand_rwsr_builtin):  New.
> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
> 	(write_sysregdi): Likewise.
> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
> 	(__arm_rsrp): Likewise.
> 	(__arm_rsr64): Likewise.
> 	(__arm_rsrf): Likewise.
> 	(__arm_rsrf64): Likewise.
> 	(__arm_wsr): Likewise.
> 	(__arm_wsrp): Likewise.
> 	(__arm_wsr64): Likewise.
> 	(__arm_wsrf): Likewise.
> 	(__arm_wsrf64): Likewise.
>
> gcc/testsuite/ChangeLog:
>
> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
> ---
>  gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
>  gcc/config/aarch64/aarch64.md                 |  17 ++
>  gcc/config/aarch64/arm_acle.h                 |  30 +++
>  .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
>  gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
>  5 files changed, 411 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>
> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
> index 04f59fd9a54..d8bb2a989a5 100644
> --- a/gcc/config/aarch64/aarch64-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-builtins.cc
> @@ -808,6 +808,17 @@ enum aarch64_builtins
>    AARCH64_RBIT,
>    AARCH64_RBITL,
>    AARCH64_RBITLL,
> +  /* System register builtins.  */
> +  AARCH64_RSR,
> +  AARCH64_RSRP,
> +  AARCH64_RSR64,
> +  AARCH64_RSRF,
> +  AARCH64_RSRF64,
> +  AARCH64_WSR,
> +  AARCH64_WSRP,
> +  AARCH64_WSR64,
> +  AARCH64_WSRF,
> +  AARCH64_WSRF64,
>    AARCH64_BUILTIN_MAX
>  };
>  
> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
>  				   AARCH64_BUILTIN_RNG_RNDRRS);
>  }
>  
> +/* Add builtins for reading system register.  */
> +static void
> +aarch64_init_rwsr_builtins (void)
> +{
> +  tree fntype = NULL;
> +  tree const_char_ptr_type
> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
> +
> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
> +  aarch64_builtin_decls[AARCH64_##F] \
> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
> +
> +  fntype
> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
> +
> +  fntype
> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
> +
> +  fntype
> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
> +
> +  fntype
> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
> +
> +  fntype
> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
> +
> +  fntype
> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> +				uint32_type_node, NULL);
> +
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
> +
> +  fntype
> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> +				const_ptr_type_node, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
> +
> +  fntype
> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> +				uint64_type_node, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
> +
> +  fntype
> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> +				float_type_node, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
> +
> +  fntype
> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> +				double_type_node, NULL);
> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
> +}
> +
>  /* Initialize the memory tagging extension (MTE) builtins.  */
>  struct
>  {
> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
>    aarch64_init_rng_builtins ();
>    aarch64_init_data_intrinsics ();
>  
> +  aarch64_init_rwsr_builtins ();
> +
>    tree ftype_jcvt
>      = build_function_type_list (intSI_type_node, double_type_node, NULL);
>    aarch64_builtin_decls[AARCH64_JSCVT]
> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
>    return target;
>  }
>  
> +/* Expand the read/write system register builtin EXPs.  */
> +rtx
> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
> +{
> +  tree arg0, arg1;
> +  rtx const_str, input_val, subreg;
> +  enum machine_mode mode;
> +  class expand_operand ops[2];
> +
> +  arg0 = CALL_EXPR_ARG (exp, 0);
> +
> +  bool write_op = (fcode == AARCH64_WSR
> +		   || fcode == AARCH64_WSRP
> +		   || fcode == AARCH64_WSR64
> +		   || fcode == AARCH64_WSRF
> +		   || fcode == AARCH64_WSRF64);
> +  bool read_op = (fcode == AARCH64_RSR
> +		  || fcode == AARCH64_RSRP
> +		  || fcode == AARCH64_RSR64
> +		  || fcode == AARCH64_RSRF
> +		  || fcode == AARCH64_RSRF64);

Instead of this, how about using:

  if (call_expr_nargs (exp) == 1)

for the read path?  

> +
> +  /* Argument 0 (system register name) must be a string literal.  */
> +  gcc_assert (!SSA_VAR_P (arg0)
> +	      && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
> +	      && TREE_CODE (TREE_OPERAND (arg0,0)) == STRING_CST);

It looks like this requires arg0 to be an ADDR_EXPR.  It would be good
to check that rather than !SSA_VAR_P.

Minor formatting nit: should be a space after the comma.

> +
> +  const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
> +  size_t len = strlen (name_input);

This can use TREE_STRING_LENGTH.  That's preferable since it copes
with embedded nuls, e.g. "foo\0bar".

> +
> +  if (len == 0)
> +    {
> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
> +      return const0_rtx;
> +    }

Is this check necessary?  It looks like the following code would
correctly reject empty strings.

> +
> +  char *sysreg_name = (char *) alloca (len + 1);
> +  strcpy (sysreg_name, name_input);

We shouldn't use alloca for user input that hasn't been verified yet,
since it could be arbitrarily long.  Libiberty provides an xmemdup that
might be useful.  (xmemdup rather than xstrdup to cope with the embedded
nuls mentioned above.  Or perhaps we should just reject embedded nuls
immediately, so that later code doesn't need to worry about them.)

> +
> +  for (unsigned pos = 0; pos <= len; pos++)
> +    sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
> +
> +  const char* name_output = aarch64_retrieve_sysreg (sysreg_name, write_op);

Does this TOLOWERing make the checks for capital letters in
is_implem_def_reg redundant?

BTW, I forgot to say, but it'd be better to add an "aarch64_" prefix to
is_implem_def_reg, to avoid accidental clashes with target-independent code.

> +  if (name_output == NULL)
> +    {
> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
> +      return const0_rtx;
> +    }
> +
> +  /* Assign the string corresponding to the system register name to an RTX.  */
> +  const_str = rtx_alloc (CONST_STRING);
> +  PUT_CODE (const_str, CONST_STRING);
> +  XSTR (const_str, 0) = xstrdup (name_output);

I think this needs to use ggc_strdup rather than xstrdup, since the
memory is managed by the garbage collector.

> +
> +  /* Set up expander operands and call instruction expansion.  */
> +  if (read_op)
> +    {
> +

Nit: redundant blank line.


> +      /* Emit the initial read_sysregdi rtx.  */
> +      create_output_operand (&ops[0], target, DImode);
> +      create_fixed_operand (&ops[1], const_str);
> +      expand_insn (CODE_FOR_aarch64_read_sysregdi, 2, ops);
> +      target = ops[0].value;
> +
> +      /* Do any necessary post-processing on the result.  */
> +      switch (fcode)
> +	{
> +	case AARCH64_RSR:
> +	  return gen_lowpart_SUBREG (SImode, target);
> +	case AARCH64_RSRP:
> +	case AARCH64_RSR64:
> +	  return target;

RSRP would return a 32-bit value for -mabi=ilp32.  It might be easier
to do:

	case AARCH64_RSR:
	case AARCH64_RSRP:
	case AARCH64_RSR64:
	case AARCH64_RSRF64:
	  return lowpart_subreg (TYPE_MODE (TREE_TYPE (exp)), target, DImode);

lowpart_subreg is a no-op if the new mode is the same as the old mode.

> +	case AARCH64_RSRF:
> +	  subreg = gen_reg_rtx (SImode);

This line looks redundant.

> +	  subreg = gen_lowpart_SUBREG (SImode, target);
> +	  return gen_lowpart_SUBREG (SFmode, subreg);
> +	case AARCH64_RSRF64:
> +	  return gen_lowpart_SUBREG (DFmode, target);
> +	}

If we do go for my:

call_expr_nargs (exp) == 1

suggestion above, this switch should probably have a:

  default:
    gcc_unreachable ();

to catch unexpected ops.

> +    }
> +  if (write_op)
> +    {
> +
> +      arg1 = CALL_EXPR_ARG (exp, 1);
> +      mode = TYPE_MODE (TREE_TYPE (arg1));
> +      input_val = copy_to_mode_reg (mode, expand_normal (arg1));
> +
> +      switch (fcode)
> +	{
> +	case AARCH64_WSR:
> +	  subreg = gen_lowpart_SUBREG (DImode, input_val);
> +	  break;
> +	case AARCH64_WSRP:
> +	case AARCH64_WSR64:
> +	  subreg = input_val;
> +	  break;
> +	case AARCH64_WSRF:
> +	  subreg = gen_lowpart_SUBREG (SImode, input_val);
> +	  subreg = gen_lowpart_SUBREG (DImode, subreg);
> +	  break;
> +	case AARCH64_WSRF64:
> +	  subreg = gen_lowpart_SUBREG (DImode, input_val);
> +	  break;
> +	}

Similarly here, I think all cases except AARCH64_WSRF could use:

	input_val = lowpart_subreg (DImode, input_value, mode);

> +
> +      create_fixed_operand (&ops[0], const_str);
> +      create_input_operand (&ops[1], subreg, DImode);
> +      expand_insn (CODE_FOR_aarch64_write_sysregdi, 2, ops);
> +
> +      return target;
> +    }
> +
> +  error_at (EXPR_LOCATION (exp),
> +	    "Malformed call to read/write system register builtin");
> +  return target;
> +}
> +
>  /* Expand an expression EXP that calls a MEMTAG built-in FCODE
>     with result going to TARGET.  */
>  static rtx
> @@ -2832,6 +3021,17 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
>      case AARCH64_BUILTIN_RNG_RNDR:
>      case AARCH64_BUILTIN_RNG_RNDRRS:
>        return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
> +    case AARCH64_RSR:
> +    case AARCH64_RSRP:
> +    case AARCH64_RSR64:
> +    case AARCH64_RSRF:
> +    case AARCH64_RSRF64:
> +    case AARCH64_WSR:
> +    case AARCH64_WSRP:
> +    case AARCH64_WSR64:
> +    case AARCH64_WSRF:
> +    case AARCH64_WSRF64:
> +      return aarch64_expand_rwsr_builtin (exp, target, fcode);
>      }
>  
>    if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
> index 32c7adc8928..80da30bc30c 100644
> --- a/gcc/config/aarch64/aarch64.md
> +++ b/gcc/config/aarch64/aarch64.md
> @@ -281,6 +281,8 @@
>      UNSPEC_UPDATE_FFRT
>      UNSPEC_RDFFR
>      UNSPEC_WRFFR
> +    UNSPEC_SYSREG_RDI
> +    UNSPEC_SYSREG_WDI
>      ;; Represents an SVE-style lane index, in which the indexing applies
>      ;; within the containing 128-bit block.
>      UNSPEC_SVE_LANE_SELECT
> @@ -476,6 +478,21 @@
>  ;; Jumps and other miscellaneous insns
>  ;; -------------------------------------------------------------------
>  
> +(define_insn "aarch64_read_sysregdi"
> + [(set (match_operand:DI 0 "register_operand" "=r")
> +       (unspec_volatile:DI [(match_operand 1 "aarch64_sysreg_string" "")]
> +		  UNSPEC_SYSREG_RDI))]
> + ""
> + "mrs\t%x0, %1"
> + )
> +
> +(define_insn "aarch64_write_sysregdi"
> + [(unspec_volatile:DI [(match_operand 0 "aarch64_sysreg_string" "")
> +	      (match_operand:DI 1 "register_operand" "r")] UNSPEC_SYSREG_WDI)]
> + ""
> + "msr\t%0, %x1"
> + )

I think the write pattern should accept rZ (x0-x30 + xzr) rather than just r.

Minor formatting nit, but other patterns are indented by 2 spaces
rather than 1, with the closing ")" not indented.

Thanks,
Richard

> +
>  (define_insn "indirect_jump"
>    [(set (pc) (match_operand:DI 0 "register_operand" "r"))]
>    ""
> diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
> index 7599a32301d..71ada878299 100644
> --- a/gcc/config/aarch64/arm_acle.h
> +++ b/gcc/config/aarch64/arm_acle.h
> @@ -314,6 +314,36 @@ __rndrrs (uint64_t *__res)
>  
>  #pragma GCC pop_options
>  
> +#define __arm_rsr(__regname) \
> +  __builtin_aarch64_rsr (__regname)
> +
> +#define __arm_rsrp(__regname) \
> +  __builtin_aarch64_rsrp (__regname)
> +
> +#define __arm_rsr64(__regname) \
> +  __builtin_aarch64_rsr64 (__regname)
> +
> +#define __arm_rsrf(__regname) \
> +  __builtin_aarch64_rsrf (__regname)
> +
> +#define __arm_rsrf64(__regname) \
> +  __builtin_aarch64_rsrf64 (__regname)
> +
> +#define __arm_wsr(__regname, __value) \
> +  __builtin_aarch64_wsr (__regname, __value)
> +
> +#define __arm_wsrp(__regname, __value) \
> +  __builtin_aarch64_wsrp (__regname, __value)
> +
> +#define __arm_wsr64(__regname, __value) \
> +  __builtin_aarch64_wsr64 (__regname, __value)
> +
> +#define __arm_wsrf(__regname, __value) \
> +  __builtin_aarch64_wsrf (__regname, __value)
> +
> +#define __arm_wsrf64(__regname, __value) \
> +  __builtin_aarch64_wsrf64 (__regname, __value)
> +
>  #ifdef __cplusplus
>  }
>  #endif
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
> new file mode 100644
> index 00000000000..bc9db098f16
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
> @@ -0,0 +1,20 @@
> +/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
> +/* Ensure that illegal behavior is rejected by the compiler.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -march=armv8.4-a" } */
> +
> +#include <arm_acle.h>
> +
> +/* Ensure that read/write-only register attributes are respected by the compiler.  */
> +void
> +test_rwsr_read_write_only ()
> +{
> +  /* Attempt to write to read-only registers.  */
> +  long long a = __arm_rsr64 ("aidr_el1");  /* Read ok.  */
> +  __arm_wsr64 ("aidr_el1", a); /* { dg-error {invalid system register name provided} } */
> +
> +  /* Attempt to read from write-only registers.  */
> +  __arm_wsr64("icc_asgi1r_el1", a);            /* Write ok.  */
> +  long long b = __arm_rsr64("icc_asgi1r_el1"); /* { dg-error {invalid system register name provided} } */
> +}
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
> new file mode 100644
> index 00000000000..3af4b960306
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
> @@ -0,0 +1,144 @@
> +/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
> +/* Check that function variants for different data types handle types correctly.  */
> +/* { dg-do compile } */
> +/* { dg-options "-O1 -march=armv8.4-a" } */
> +/* { dg-final { check-function-bodies "**" "" } } */
> +
> +#include <arm_acle.h>
> +
> +/*
> +** get_rsr:
> +** ...
> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
> +** 	add	w\1, w\1, 1
> +** ...
> +*/
> +int
> +get_rsr ()
> +{
> +  int a =  __arm_rsr("trcseqstr");
> +  return a+1;
> +}
> +
> +/*
> +** get_rsrf:
> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
> +** 	fmov	s[0-9]+, w\1
> +** ...
> +*/
> +float
> +get_rsrf ()
> +{
> +  return __arm_rsrf("trcseqstr");
> +}
> +
> +/*
> +** get_rsrp:
> +** 	mrs	x0, s2_1_c0_c7_4
> +** 	ret
> +*/
> +void *
> +get_rsrp ()
> +{
> +  return __arm_rsrp("trcseqstr");
> +}
> +
> +/*
> +** get_rsr64:
> +** 	mrs	x0, s2_1_c0_c7_4
> +** 	ret
> +*/
> +long long
> +get_rsr64 ()
> +{
> +  return __arm_rsr64("trcseqstr");
> +}
> +
> +/*
> +** get_rsrf64:
> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
> +** 	fmov	d[0-9]+, x\1
> +** ...
> +*/
> +double
> +get_rsrf64 ()
> +{
> +  return __arm_rsrf64("trcseqstr");
> +}
> +
> +/*
> +** set_wsr32:
> +** ...
> +** 	add	w([0-9]+), w\1, 1
> +** 	msr	s2_1_c0_c7_4, x\1
> +** ...
> +*/
> +void
> +set_wsr32 (int a)
> +{
> +  __arm_wsr("trcseqstr", a+1);
> +}
> +
> +/*
> +** set_wsrp:
> +** ...
> +** 	msr	s2_1_c0_c7_4, x[0-9]+
> +** ...
> +*/
> +void
> +set_wsrp (void *a)
> +{
> +  __arm_wsrp("trcseqstr", a);
> +}
> +
> +/*
> +** set_wsr64:
> +** ...
> +** 	msr	s2_1_c0_c7_4, x[0-9]+
> +** ...
> +*/
> +void
> +set_wsr64 (long long a)
> +{
> +  __arm_wsr64("trcseqstr", a);
> +}
> +
> +/*
> +** set_wsrf32:
> +** ...
> +** 	fmov	w([0-9]+), s[0-9]+
> +** 	msr	s2_1_c0_c7_4, x\1
> +** ...
> +*/
> +void
> +set_wsrf32 (float a)
> +{
> +  __arm_wsrf("trcseqstr", a);
> +}
> +
> +/*
> +** set_wsrf64:
> +** ...
> +** 	fmov	x([0-9]+), d[0-9]+
> +** 	msr	s2_1_c0_c7_4, x\1
> +** ...
> +*/
> +void
> +set_wsrf64(double a)
> +{
> +  __arm_wsrf64("trcseqstr", a);
> +}
> +
> +/*
> +** set_custom:
> +** ...
> +** 	mrs	x0, s1_2_c3_c4_5
> +** ...
> +** 	msr	s1_2_c3_c4_5, x0
> +** ...
> +*/
> +void set_custom()
> +{
> +  __uint64_t b = __arm_rsr64("S1_2_C3_C4_5");
> +  __arm_wsr64("S1_2_C3_C4_5", b);
> +}

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def
  2023-10-18 15:02 ` [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def Victor Do Nascimento
@ 2023-10-18 21:07   ` Richard Sandiford
  2023-10-26 14:48     ` Victor Do Nascimento
  0 siblings, 1 reply; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 21:07 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> This patch defines the structure of a new .def file used for
> representing the aarch64 system registers, what information it should
> hold and the basic framework in GCC to process this file.
>
> Entries in the aarch64-system-regs.def file should be as follows:
>
>   SYSREG (NAME, CPENC (sn,op1,cn,cm,op2), FLAG1 | ... | FLAGn, ARCH)
>
> Where the arguments to SYSREG correspond to:
>   - NAME:  The system register name, as used in the assembly language.
>   - CPENC: The system register encoding, mapping to:
>
>     	       s<sn>_<op1>_c<cn>_c<cm>_<op2>
>
>   - FLAG: The entries in the FLAGS field are bitwise-OR'd together to
>     	  encode extra information required to ensure proper use of
> 	  the system register.  For example, a read-only system
> 	  register will have the flag F_REG_READ, while write-only
> 	  registers will be labeled F_REG_WRITE.  Such flags are
> 	  tested against at compile-time.
>   - ARCH: The architectural features the system register is associated
>     	  with.  This is encoded via one of three possible macros:
> 	  1. When a system register is universally implemented, we say
> 	  it has no feature requirements, so we tag it with the
> 	  AARCH64_NO_FEATURES macro.
> 	  2. When a register is only implemented for a single
> 	  architectural extension EXT, the AARCH64_FEATURE (EXT), is
> 	  used.
> 	  3. When a given system register is made available by any of N
> 	  possible architectural extensions, the AARCH64_FEATURES(N, ...)
> 	  macro is used to combine them accordingly.
>
> In order to enable proper interpretation of the SYSREG entries by the
> compiler, flags defining system register behavior such as `F_REG_READ'
> and `F_REG_WRITE' are also defined here, so they can later be used for
> the validation of system register properties.
>
> Finally, any architectural feature flags from Binutils missing from GCC
> have appropriate aliases defined here so as to ensure
> cross-compatibility of SYSREG entries across the toolchain.
>
> gcc/ChangeLog:
>
> 	* gcc/config/aarch64/aarch64.cc (sysreg_t): New.
> 	(sysreg_structs): Likewise.
> 	(nsysreg): Likewise.
> 	(AARCH64_FEATURE): Likewise.
> 	(AARCH64_FEATURES): Likewise.
> 	(AARCH64_NO_FEATURES): Likewise.
> 	* gcc/config/aarch64/aarch64.h (AARCH64_ISA_V8A): Add missing
> 	ISA flag.
> 	(AARCH64_ISA_V8_1A): Likewise.
> 	(AARCH64_ISA_V8_7A): Likewise.
> 	(AARCH64_ISA_V8_8A): Likewise.
> 	(AARCH64_NO_FEATURES): Likewise.
> 	(AARCH64_FL_RAS): New ISA flag alias.
> 	(AARCH64_FL_LOR): Likewise.
> 	(AARCH64_FL_PAN): Likewise.
> 	(AARCH64_FL_AMU): Likewise.
> 	(AARCH64_FL_SCXTNUM): Likewise.
> 	(AARCH64_FL_ID_PFR2): Likewise.
> 	(F_DEPRECATED): New.
> 	(F_REG_READ): Likewise.
> 	(F_REG_WRITE): Likewise.
> 	(F_ARCHEXT): Likewise.
> 	(F_REG_ALIAS): Likewise.
> ---
>  gcc/config/aarch64/aarch64.cc | 38 +++++++++++++++++++++++++++++++++++
>  gcc/config/aarch64/aarch64.h  | 36 +++++++++++++++++++++++++++++++++
>  2 files changed, 74 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 9fbfc548a89..69de2366424 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -2807,6 +2807,44 @@ static const struct processor all_cores[] =
>    {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
>  };
>  
> +typedef struct {
> +  const char* name;
> +  const char* encoding;

Formatting nit, but GCC style is:

  const char *foo

rather than:

  const char* foo;

> +  const unsigned properties;
> +  const unsigned long long arch_reqs;

I don't think these two should be const.  There's no reason in principle
why a sysreg_t can't be created and modified dynamically.

It would be useful to have some comments above the fields to say what
they represent.  E.g. the definition on its own doesn't make clear what
"properties" refers to.

arch_reqs should use aarch64_feature_flags rather than unsigned long long.
We're running out of feature flags in GCC too, so aarch64_feature_flags
is soon likely to be a C++ class.

> +} sysreg_t;
> +
> +/* An aarch64_feature_set initializer for a single feature,
> +   AARCH64_FEATURE_<FEAT>.  */
> +#define AARCH64_FEATURE(FEAT) AARCH64_FL_##FEAT
> +
> +/* Used by AARCH64_FEATURES.  */
> +#define AARCH64_OR_FEATURES_1(X, F1) \
> +  AARCH64_FEATURE (F1)
> +#define AARCH64_OR_FEATURES_2(X, F1, F2) \
> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_1 (X, F2))
> +#define AARCH64_OR_FEATURES_3(X, F1, ...) \
> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_2 (X, __VA_ARGS__))
> +
> +/* An aarch64_feature_set initializer for the N features listed in "...".  */
> +#define AARCH64_FEATURES(N, ...) \
> +  AARCH64_OR_FEATURES_##N (0, __VA_ARGS__)
> +
> +/* Database of system registers, their encodings and architectural
> +   requirements.  */
> +const sysreg_t sysreg_structs[] =
> +{
> +#define CPENC(SN, OP1, CN, CM, OP2) "s"#SN"_"#OP1"_c"#CN"_c"#CM"_"#OP2
> +#define SYSREG(NAME, ENC, FLAGS, ARCH) \
> +  { NAME, ENC, FLAGS, ARCH },
> +#include "aarch64-sys-regs.def"
> +#undef CPENC
> +};
> +
> +#define TOTAL_ITEMS (sizeof sysreg_structs / sizeof sysreg_structs[0])
> +const unsigned nsysreg = TOTAL_ITEMS;

There's an ARRAY_SIZE macro for this.

> +#undef TOTAL_ITEMS
> +
>  /* The current tuning set.  */
>  struct tune_params aarch64_tune_params = generic_tunings;
>  
> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
> index d74e9116fc5..cf3969a11aa 100644
> --- a/gcc/config/aarch64/aarch64.h
> +++ b/gcc/config/aarch64/aarch64.h
> @@ -179,6 +179,8 @@ enum class aarch64_feature : unsigned char {
>  
>  /* Macros to test ISA flags.  */
>  
> +#define AARCH64_ISA_V8A		   (aarch64_isa_flags & AARCH64_FL_V8A)
> +#define AARCH64_ISA_V8_1A	   (aarch64_isa_flags & AARCH64_FL_V8_1A)
>  #define AARCH64_ISA_CRC            (aarch64_isa_flags & AARCH64_FL_CRC)
>  #define AARCH64_ISA_CRYPTO         (aarch64_isa_flags & AARCH64_FL_CRYPTO)
>  #define AARCH64_ISA_FP             (aarch64_isa_flags & AARCH64_FL_FP)
> @@ -215,6 +217,8 @@ enum class aarch64_feature : unsigned char {
>  #define AARCH64_ISA_SB		   (aarch64_isa_flags & AARCH64_FL_SB)
>  #define AARCH64_ISA_V8R		   (aarch64_isa_flags & AARCH64_FL_V8R)
>  #define AARCH64_ISA_PAUTH	   (aarch64_isa_flags & AARCH64_FL_PAUTH)
> +#define AARCH64_ISA_V8_7A	   (aarch64_isa_flags & AARCH64_FL_V8_7A)
> +#define AARCH64_ISA_V8_8A	   (aarch64_isa_flags & AARCH64_FL_V8_8A)
>  #define AARCH64_ISA_V9A		   (aarch64_isa_flags & AARCH64_FL_V9A)
>  #define AARCH64_ISA_V9_1A          (aarch64_isa_flags & AARCH64_FL_V9_1A)
>  #define AARCH64_ISA_V9_2A          (aarch64_isa_flags & AARCH64_FL_V9_2A)
> @@ -223,6 +227,38 @@ enum class aarch64_feature : unsigned char {
>  #define AARCH64_ISA_LS64	   (aarch64_isa_flags & AARCH64_FL_LS64)
>  #define AARCH64_ISA_CSSC	   (aarch64_isa_flags & AARCH64_FL_CSSC)
>  
> +/* AARCH64_FL options necessary for system register implementation.  */
> +
> +/* Mask for core system registers.  System registers requiring no architectural
> +   extensions set up a feature-checking mask which returns any passed flags
> +   unchanged when ANDd with.  */
> +#define AARCH64_NO_FEATURES	   (uint64_t)-1

I think this one should only be defined before including the .def file,
and undefined afterwards.  It's not something that general GCC code
should use.

Is -1 right though?  3/7 uses:

  if (aarch64_isa_flags & sysreg->arch_reqs)

which requires at least one of the features in sysreg->arch_reqs to be
available.  But binutils uses AARCH64_CPU_HAS_ALL_FEATURES, which requires
all of the features to be available.

At least, it seems odd that AARCH64_NO_FEATURES is all-ones here
but all-zeros in binutils.

> +
> +/* Define AARCH64_FL aliases for architectural features which are protected
> +   by -march flags in binutils but which receive no special treatment by GCC.
> +
> +   Such flags are inherited from the Binutils definition of system registers
> +   and are mapped to the architecture in which the feature is implemented.  */
> +#define AARCH64_FL_RAS		   AARCH64_FL_V8A
> +#define AARCH64_FL_LOR		   AARCH64_FL_V8_1A
> +#define AARCH64_FL_PAN		   AARCH64_FL_V8_1A
> +#define AARCH64_FL_AMU		   AARCH64_FL_V8_4A
> +#define AARCH64_FL_SCXTNUM	   AARCH64_FL_V8_5A
> +#define AARCH64_FL_ID_PFR2	   AARCH64_FL_V8_5A
> +
> +/* Define AARCH64_FL aliases for features note yet implemented in GCC.
> +   Accept them unconditionally.  */
> +#define AARCH64_FL_SME		   -1

I think disallowing them would be better.  Otherwise we'd go from
accepting a register without +sme to not accepting it, which might
seem like a regression to users.

Of course, in the particular case of SME, this problem should go
away very soon :)  And once this sysreg work goes in, it should
probably become a principle that GCC should accept feature flags as
soon as it knows about associated system registers (as a sufficient
but not necessary condition).

So we can probably leave this as-is on the basis that it will only
be around for a few weeks.

> +
> +/* Flags associated with the properties of system registers.  It mainly serves
> +   to mark particular registers as read or write only.  */
> +#define F_DEPRECATED		   (1 << 1)
> +#define F_REG_READ		   (1 << 2)
> +#define F_REG_WRITE		   (1 << 3)
> +#define F_ARCHEXT		   (1 << 4)
> +/* Flag indicating register name is alias for another system register.  */
> +#define F_REG_ALIAS		   (1 << 5)
> +

Since the definition of sysreg_t is local to aarch64.cc (good!),
could these flags be defined there rather than in aarch64.h?

Thanks,
Richard

>  /* Crypto is an optional extension to AdvSIMD.  */
>  #define TARGET_CRYPTO (AARCH64_ISA_CRYPTO)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING
  2023-10-18 15:02 ` [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING Victor Do Nascimento
@ 2023-10-18 21:09   ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 21:09 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> Motivated by the need to print system register names in output
> assembly, this patch adds the required logic to
> `aarch64_print_operand' to accept rtxs of type CONST_STRING and
> process these accordingly.
>
> Consequently, an rtx such as:
>
>   (set (reg/i:DI 0 x0)
>          (unspec:DI [(const_string ("s3_3_c13_c2_2"))])
>
> can now be output correctly using the following output pattern when
> composing `define_insn's:
>
>   "mrs\t%x0, %1"
>
> gcc/ChangeLog
>
> 	* gcc/config/aarch64/aarch64.cc (aarch64_print_operand): Add
> 	support for CONST_STRING.
> ---
>  gcc/config/aarch64/aarch64.cc | 6 ++++++
>  1 file changed, 6 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 816c4b69fc8..d187e171beb 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -12430,6 +12430,12 @@ aarch64_print_operand (FILE *f, rtx x, int code)
>  
>        switch (GET_CODE (x))
>  	{
> +	case CONST_STRING:
> +	  {
> +	    const char *output_op = XSTR (x, 0);
> +	    asm_fprintf (f, "%s", output_op);
> +	    break;
> +	  }

LGTM, but it seems slightly neater to avoid the temporary:

	case CONST_STRING:
	  asm_fprintf (f, "%s", XSTR (x, 0));
	  break;

(Sorry for the micro-comment.)

Thanks,
Richard

>  	case REG:
>  	  if (aarch64_sve_data_mode_p (GET_MODE (x)))
>  	    {

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins
  2023-10-18 15:02 ` [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins Victor Do Nascimento
@ 2023-10-18 21:20   ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 21:20 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> In implementing the ACLE read/write system register builtins it was
> observed that leaving argument type checking to be done at expand-time
> meant that poorly-formed function calls were being "fixed" by certain
> optimization passes, meaning bad code wasn't being properly picked up
> in checking.
>
> Example:
>
>   const char *regname = "amcgcr_el0";
>   long long a = __builtin_aarch64_rsr64 (regname);
>
> is reduced by the ccp1 pass to
>
>   long long a = __builtin_aarch64_rsr64 ("amcgcr_el0");
>
> As these functions require an argument of STRING_CST type, there needs
> to be a check carried out by the front-end capable of picking this up.
>
> The introduced `check_general_builtin_call' function will be called by
> the TARGET_CHECK_BUILTIN_CALL hook whenever a call to a builtin
> belonging to the AARCH64_BUILTIN_GENERAL category is encountered,
> carrying out any appropriate checks associated with a particular
> builtin function code.
>
> gcc/ChangeLog:
>
> 	* gcc/config/aarch64/aarch64-builtins.cc (check_general_builtin_call):
> 	New.
> 	* gcc/config/aarch64/aarch64-c.cc (aarch64_check_builtin_call):
> 	Add check_general_builtin_call call.
> 	* gcc/config/aarch64/aarch64-protos.h (check_general_builtin_call):
> 	New.
>
> gcc/testsuite/ChangeLog:
>
> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c: New.
> ---
>  gcc/config/aarch64/aarch64-builtins.cc        | 33 +++++++++++++++++++
>  gcc/config/aarch64/aarch64-c.cc               |  4 +--
>  gcc/config/aarch64/aarch64-protos.h           |  3 ++
>  .../gcc.target/aarch64/acle/rwsr-2.c          | 15 +++++++++
>  4 files changed, 53 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
>
> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
> index d8bb2a989a5..6734361f4f4 100644
> --- a/gcc/config/aarch64/aarch64-builtins.cc
> +++ b/gcc/config/aarch64/aarch64-builtins.cc
> @@ -2126,6 +2126,39 @@ aarch64_general_builtin_decl (unsigned code, bool)
>    return aarch64_builtin_decls[code];
>  }
>  
> +bool
> +check_general_builtin_call (location_t location, vec<location_t>,
> +			    unsigned int code, tree fndecl,
> +			    unsigned int nargs ATTRIBUTE_UNUSED, tree *args)
> +{

How about aarch64_general_check_builtin_call?  It's better to use
aarch64_* prefixes where possible.

> +  switch (code)
> +    {
> +    case AARCH64_RSR:
> +    case AARCH64_RSRP:
> +    case AARCH64_RSR64:
> +    case AARCH64_RSRF:
> +    case AARCH64_RSRF64:
> +    case AARCH64_WSR:
> +    case AARCH64_WSRP:
> +    case AARCH64_WSR64:
> +    case AARCH64_WSRF:
> +    case AARCH64_WSRF64:
> +      if (TREE_CODE (args[0]) == VAR_DECL
> +	  || TREE_CODE (TREE_TYPE (args[0])) != POINTER_TYPE
> +	      || TREE_CODE (TREE_OPERAND (TREE_OPERAND (args[0], 0) , 0))
> +		  != STRING_CST)

Similarly to the expand code in 5/7, I think this should check
positively for specific tree codes rather than negatively for a
VAR_DECL.  That is, we should ensure TREE_CODE (x) is something
(rather than isn't something) before accessing TREE_OPERAND (x, 0).

> +	{
> +	  const char  *fn_name, *err_msg;
> +	  fn_name = IDENTIFIER_POINTER (DECL_NAME (fndecl));
> +	  err_msg = "first argument to %<%s%> must be a string literal";
> +	  error_at (location, err_msg, fn_name);

The error message needs to remain part of the error_at call,
since being in error_at ensures that it gets picked up for translation.
It's simpler to use %qD rather than %<%s%>, and pass fndecl directly.

> +	  return false;
> +	}
> +    }
> +  /* Default behavior.  */
> +  return true;
> +}
> +
>  typedef enum
>  {
>    SIMD_ARG_COPY_TO_REG,
> diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc
> index ab8844f6049..c2a9a59df73 100644
> --- a/gcc/config/aarch64/aarch64-c.cc
> +++ b/gcc/config/aarch64/aarch64-c.cc
> @@ -339,8 +339,8 @@ aarch64_check_builtin_call (location_t loc, vec<location_t> arg_loc,
>    switch (code & AARCH64_BUILTIN_CLASS)
>      {
>      case AARCH64_BUILTIN_GENERAL:
> -      return true;
> -
> +      return check_general_builtin_call (loc, arg_loc, subcode, orig_fndecl,
> +					 nargs, args);
>      case AARCH64_BUILTIN_SVE:
>        return aarch64_sve::check_builtin_call (loc, arg_loc, subcode,
>  					      orig_fndecl, nargs, args);
> diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
> index a134e2fcf8e..9ef96ff511f 100644
> --- a/gcc/config/aarch64/aarch64-protos.h
> +++ b/gcc/config/aarch64/aarch64-protos.h
> @@ -990,6 +990,9 @@ tree aarch64_general_builtin_rsqrt (unsigned int);
>  void handle_arm_acle_h (void);
>  void handle_arm_neon_h (void);
>  
> +bool check_general_builtin_call (location_t, vec<location_t>, unsigned int,
> +			      tree, unsigned int, tree *);
> +
>  namespace aarch64_sve {
>    void init_builtins ();
>    void handle_arm_sve_h ();
> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
> new file mode 100644
> index 00000000000..72e5fb75b21
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-2.c
> @@ -0,0 +1,15 @@
> +/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
> +/* Ensure that illegal behavior is rejected by the compiler.  */
> +
> +/* { dg-do compile } */
> +/* { dg-options "-O3 -march=armv8.4-a" } */
> +
> +#include <arm_acle.h>
> +
> +void
> +test_non_const_sysreg_name ()
> +{
> +  const char *regname = "trcseqstr";
> +  long long a = __arm_rsr64 (regname); /* { dg-error "first argument to '__builtin_aarch64_rsr64' must be a string literal" } */
> +  __arm_wsr64 (regname, a); /* { dg-error "first argument to '__builtin_aarch64_wsr64' must be a string literal" } */
> +}

It would be good to have a check with a nullptr argument too.  That'll
need -std=c2x.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 7/7] aarch64: Add system register duplication check selftest
  2023-10-18 15:02 ` [PATCH V2 7/7] aarch64: Add system register duplication check selftest Victor Do Nascimento
@ 2023-10-18 21:30   ` Richard Sandiford
  2023-10-26 15:13     ` Victor Do Nascimento
  0 siblings, 1 reply; 23+ messages in thread
From: Richard Sandiford @ 2023-10-18 21:30 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <victor.donascimento@arm.com> writes:
> Add a build-time test to check whether system register data, as
> imported from `aarch64-sys-reg.def' has any duplicate entries.
>
> Duplicate entries are defined as any two SYSREG entries in the .def
> file which share the same encoding values (as specified by its `CPENC'
> field) and where the relationship amongst the two does not fit into
> one of the following categories:
>
> 	* Simple aliasing: In some cases, it is observed that one
> 	register name serves as an alias to another.  One example of
> 	this is where TRCEXTINSELR aliases TRCEXTINSELR0.
> 	* Expressing intent: It is possible that when a given register
> 	serves two distinct functions depending on how it is used, it
> 	is given two distinct names whose use should match the context
> 	under which it is being used.  Example:  Debug Data Transfer
> 	Register. When used to receive data, it should be accessed as
> 	DBGDTRRX_EL0 while when transmitting data it should be
> 	accessed via DBGDTRTX_EL0.
> 	* Register depreciation: Some register names have been
> 	deprecated and should no longer be used, but backwards-
> 	compatibility requires that such names continue to be
> 	recognized, as is the case for the SPSR_EL1 register, whose
> 	access via the SPSR_SVC name is now deprecated.
> 	* Same encoding different target: Some encodings are given
> 	different meaning depending on the target architecture and, as
> 	such, are given different names in each of theses contexts.
> 	We see an example of this for CPENC(3,4,2,0,0), which
> 	corresponds to TTBR0_EL2 for Armv8-A targets and VSCTLR_EL2
> 	in Armv8-R targets.
>
> A consequence of these observations is that `CPENC' duplication is
> acceptable iff at least one of the `properties' or `arch_reqs' fields
> of the `sysreg_t' structs associated with the two registers in
> question differ and it's this condition that is checked by the new
> `aarch64_test_sysreg_encoding_clashes' function.
>
> gcc/ChangeLog:
>
> 	* gcc/config/aarch64/aarch64.cc
> 	(aarch64_test_sysreg_encoding_clashes): New.
> 	(aarch64_run_selftests): add call to
> 	aarch64_test_sysreg_encoding_clashes selftest.
> ---
>  gcc/config/aarch64/aarch64.cc | 53 +++++++++++++++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index d187e171beb..e0be2877ede 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -22,6 +22,7 @@
>  
>  #define INCLUDE_STRING
>  #define INCLUDE_ALGORITHM
> +#define INCLUDE_VECTOR
>  #include "config.h"
>  #include "system.h"
>  #include "coretypes.h"
> @@ -28332,6 +28333,57 @@ aarch64_test_fractional_cost ()
>    ASSERT_EQ (cf (1, 2).as_double (), 0.5);
>  }
>  
> +/* Calculate whether our system register data, as imported from
> +   `aarch64-sys-reg.def' has any duplicate entries.  */
> +static void
> +aarch64_test_sysreg_encoding_clashes (void)
> +{
> +  using dup_counters_t = hash_map<nofree_string_hash, unsigned>;
> +  using dup_instances_t = hash_map<nofree_string_hash,
> +				   std::vector<const sysreg_t*>>;
> +
> +  dup_counters_t duplicate_counts;
> +  dup_instances_t duplicate_instances;
> +
> +  /* Every time an encoding is established to come up more than once
> +  we add it to a "clash-analysis queue", which is then used to extract
> +  necessary information from our hash map when establishing whether
> +  repeated encodings are valid.  */

Formatting nit, sorry, but second and subsequent lines should be
indented to line up with the "E".

> +
> +  /* 1) Collect recurrence information.  */
> +  std::vector<const char*> testqueue;
> +
> +  for (unsigned i = 0; i < nsysreg; i++)
> +    {
> +      const sysreg_t *reg = sysreg_structs + i;
> +
> +      unsigned *tbl_entry = &duplicate_counts.get_or_insert (reg->encoding);
> +      *tbl_entry += 1;
> +
> +      std::vector<const sysreg_t*> *tmp
> +	= &duplicate_instances.get_or_insert (reg->encoding);
> +
> +      tmp->push_back (reg);
> +      if (*tbl_entry > 1)
> +	  testqueue.push_back (reg->encoding);
> +    }

Do we need two hash maps here?  It looks like the length of the vector
is always equal to the count.  Also...

> +
> +  /* 2) Carry out analysis on collected data.  */
> +  for (auto enc : testqueue)

...hash_map itself is iterable.  We could iterate over that instead,
which would avoid the need for the queue.

> +    {
> +      unsigned nrep = *duplicate_counts.get (enc);
> +      for (unsigned i = 0; i < nrep; i++)
> +	for (unsigned j = i+1; j < nrep; j++)

Formatting nit, but "i + 1" rather than "i+1".

Overall, it looks like really nice work.  Thanks for doing this.

Richard

> +	  {
> +	    std::vector<const sysreg_t*> *tmp2 = duplicate_instances.get (enc);
> +	    const sysreg_t *a = (*tmp2)[i];
> +	    const sysreg_t *b = (*tmp2)[j];
> +	    ASSERT_TRUE ((a->properties != b->properties)
> +			 || (a->arch_reqs != b->arch_reqs));
> +	  }
> +    }
> +}
> +
>  /* Run all target-specific selftests.  */
>  
>  static void
> @@ -28339,6 +28391,7 @@ aarch64_run_selftests (void)
>  {
>    aarch64_test_loading_full_dump ();
>    aarch64_test_fractional_cost ();
> +  aarch64_test_sysreg_encoding_clashes ();
>  }
>  
>  } // namespace selftest

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def
  2023-10-18 21:07   ` Richard Sandiford
@ 2023-10-26 14:48     ` Victor Do Nascimento
  2023-10-26 15:14       ` Richard Sandiford
  0 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-26 14:48 UTC (permalink / raw)
  To: gcc-patches, kyrylo.tkachov, Richard.Earnshaw, richard.sandiford



On 10/18/23 22:07, Richard Sandiford wrote:
> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>> This patch defines the structure of a new .def file used for
>> representing the aarch64 system registers, what information it should
>> hold and the basic framework in GCC to process this file.
>>
>> Entries in the aarch64-system-regs.def file should be as follows:
>>
>>    SYSREG (NAME, CPENC (sn,op1,cn,cm,op2), FLAG1 | ... | FLAGn, ARCH)
>>
>> Where the arguments to SYSREG correspond to:
>>    - NAME:  The system register name, as used in the assembly language.
>>    - CPENC: The system register encoding, mapping to:
>>
>>      	       s<sn>_<op1>_c<cn>_c<cm>_<op2>
>>
>>    - FLAG: The entries in the FLAGS field are bitwise-OR'd together to
>>      	  encode extra information required to ensure proper use of
>> 	  the system register.  For example, a read-only system
>> 	  register will have the flag F_REG_READ, while write-only
>> 	  registers will be labeled F_REG_WRITE.  Such flags are
>> 	  tested against at compile-time.
>>    - ARCH: The architectural features the system register is associated
>>      	  with.  This is encoded via one of three possible macros:
>> 	  1. When a system register is universally implemented, we say
>> 	  it has no feature requirements, so we tag it with the
>> 	  AARCH64_NO_FEATURES macro.
>> 	  2. When a register is only implemented for a single
>> 	  architectural extension EXT, the AARCH64_FEATURE (EXT), is
>> 	  used.
>> 	  3. When a given system register is made available by any of N
>> 	  possible architectural extensions, the AARCH64_FEATURES(N, ...)
>> 	  macro is used to combine them accordingly.
>>
>> In order to enable proper interpretation of the SYSREG entries by the
>> compiler, flags defining system register behavior such as `F_REG_READ'
>> and `F_REG_WRITE' are also defined here, so they can later be used for
>> the validation of system register properties.
>>
>> Finally, any architectural feature flags from Binutils missing from GCC
>> have appropriate aliases defined here so as to ensure
>> cross-compatibility of SYSREG entries across the toolchain.
>>
>> gcc/ChangeLog:
>>
>> 	* gcc/config/aarch64/aarch64.cc (sysreg_t): New.
>> 	(sysreg_structs): Likewise.
>> 	(nsysreg): Likewise.
>> 	(AARCH64_FEATURE): Likewise.
>> 	(AARCH64_FEATURES): Likewise.
>> 	(AARCH64_NO_FEATURES): Likewise.
>> 	* gcc/config/aarch64/aarch64.h (AARCH64_ISA_V8A): Add missing
>> 	ISA flag.
>> 	(AARCH64_ISA_V8_1A): Likewise.
>> 	(AARCH64_ISA_V8_7A): Likewise.
>> 	(AARCH64_ISA_V8_8A): Likewise.
>> 	(AARCH64_NO_FEATURES): Likewise.
>> 	(AARCH64_FL_RAS): New ISA flag alias.
>> 	(AARCH64_FL_LOR): Likewise.
>> 	(AARCH64_FL_PAN): Likewise.
>> 	(AARCH64_FL_AMU): Likewise.
>> 	(AARCH64_FL_SCXTNUM): Likewise.
>> 	(AARCH64_FL_ID_PFR2): Likewise.
>> 	(F_DEPRECATED): New.
>> 	(F_REG_READ): Likewise.
>> 	(F_REG_WRITE): Likewise.
>> 	(F_ARCHEXT): Likewise.
>> 	(F_REG_ALIAS): Likewise.
>> ---
>>   gcc/config/aarch64/aarch64.cc | 38 +++++++++++++++++++++++++++++++++++
>>   gcc/config/aarch64/aarch64.h  | 36 +++++++++++++++++++++++++++++++++
>>   2 files changed, 74 insertions(+)
>>
>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>> index 9fbfc548a89..69de2366424 100644
>> --- a/gcc/config/aarch64/aarch64.cc
>> +++ b/gcc/config/aarch64/aarch64.cc
>> @@ -2807,6 +2807,44 @@ static const struct processor all_cores[] =
>>     {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
>>   };
>>   
>> +typedef struct {
>> +  const char* name;
>> +  const char* encoding;
> 
> Formatting nit, but GCC style is:
> 
>    const char *foo
> 
> rather than:
> 
>    const char* foo;
> 
>> +  const unsigned properties;
>> +  const unsigned long long arch_reqs;
> 
> I don't think these two should be const.  There's no reason in principle
> why a sysreg_t can't be created and modified dynamically.
> 
> It would be useful to have some comments above the fields to say what
> they represent.  E.g. the definition on its own doesn't make clear what
> "properties" refers to.
> 
> arch_reqs should use aarch64_feature_flags rather than unsigned long long.
> We're running out of feature flags in GCC too, so aarch64_feature_flags
> is soon likely to be a C++ class.
> 
>> +} sysreg_t;
>> +
>> +/* An aarch64_feature_set initializer for a single feature,
>> +   AARCH64_FEATURE_<FEAT>.  */
>> +#define AARCH64_FEATURE(FEAT) AARCH64_FL_##FEAT
>> +
>> +/* Used by AARCH64_FEATURES.  */
>> +#define AARCH64_OR_FEATURES_1(X, F1) \
>> +  AARCH64_FEATURE (F1)
>> +#define AARCH64_OR_FEATURES_2(X, F1, F2) \
>> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_1 (X, F2))
>> +#define AARCH64_OR_FEATURES_3(X, F1, ...) \
>> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_2 (X, __VA_ARGS__))
>> +
>> +/* An aarch64_feature_set initializer for the N features listed in "...".  */
>> +#define AARCH64_FEATURES(N, ...) \
>> +  AARCH64_OR_FEATURES_##N (0, __VA_ARGS__)
>> +
>> +/* Database of system registers, their encodings and architectural
>> +   requirements.  */
>> +const sysreg_t sysreg_structs[] =
>> +{
>> +#define CPENC(SN, OP1, CN, CM, OP2) "s"#SN"_"#OP1"_c"#CN"_c"#CM"_"#OP2
>> +#define SYSREG(NAME, ENC, FLAGS, ARCH) \
>> +  { NAME, ENC, FLAGS, ARCH },
>> +#include "aarch64-sys-regs.def"
>> +#undef CPENC
>> +};
>> +
>> +#define TOTAL_ITEMS (sizeof sysreg_structs / sizeof sysreg_structs[0])
>> +const unsigned nsysreg = TOTAL_ITEMS;
> 
> There's an ARRAY_SIZE macro for this.
> 
>> +#undef TOTAL_ITEMS
>> +
>>   /* The current tuning set.  */
>>   struct tune_params aarch64_tune_params = generic_tunings;
>>   
>> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
>> index d74e9116fc5..cf3969a11aa 100644
>> --- a/gcc/config/aarch64/aarch64.h
>> +++ b/gcc/config/aarch64/aarch64.h
>> @@ -179,6 +179,8 @@ enum class aarch64_feature : unsigned char {
>>   
>>   /* Macros to test ISA flags.  */
>>   
>> +#define AARCH64_ISA_V8A		   (aarch64_isa_flags & AARCH64_FL_V8A)
>> +#define AARCH64_ISA_V8_1A	   (aarch64_isa_flags & AARCH64_FL_V8_1A)
>>   #define AARCH64_ISA_CRC            (aarch64_isa_flags & AARCH64_FL_CRC)
>>   #define AARCH64_ISA_CRYPTO         (aarch64_isa_flags & AARCH64_FL_CRYPTO)
>>   #define AARCH64_ISA_FP             (aarch64_isa_flags & AARCH64_FL_FP)
>> @@ -215,6 +217,8 @@ enum class aarch64_feature : unsigned char {
>>   #define AARCH64_ISA_SB		   (aarch64_isa_flags & AARCH64_FL_SB)
>>   #define AARCH64_ISA_V8R		   (aarch64_isa_flags & AARCH64_FL_V8R)
>>   #define AARCH64_ISA_PAUTH	   (aarch64_isa_flags & AARCH64_FL_PAUTH)
>> +#define AARCH64_ISA_V8_7A	   (aarch64_isa_flags & AARCH64_FL_V8_7A)
>> +#define AARCH64_ISA_V8_8A	   (aarch64_isa_flags & AARCH64_FL_V8_8A)
>>   #define AARCH64_ISA_V9A		   (aarch64_isa_flags & AARCH64_FL_V9A)
>>   #define AARCH64_ISA_V9_1A          (aarch64_isa_flags & AARCH64_FL_V9_1A)
>>   #define AARCH64_ISA_V9_2A          (aarch64_isa_flags & AARCH64_FL_V9_2A)
>> @@ -223,6 +227,38 @@ enum class aarch64_feature : unsigned char {
>>   #define AARCH64_ISA_LS64	   (aarch64_isa_flags & AARCH64_FL_LS64)
>>   #define AARCH64_ISA_CSSC	   (aarch64_isa_flags & AARCH64_FL_CSSC)
>>   
>> +/* AARCH64_FL options necessary for system register implementation.  */
>> +
>> +/* Mask for core system registers.  System registers requiring no architectural
>> +   extensions set up a feature-checking mask which returns any passed flags
>> +   unchanged when ANDd with.  */
>> +#define AARCH64_NO_FEATURES	   (uint64_t)-1
> 
> I think this one should only be defined before including the .def file,
> and undefined afterwards.  It's not something that general GCC code
> should use.
> 
> Is -1 right though?  3/7 uses:
> 
>    if (aarch64_isa_flags & sysreg->arch_reqs)
> 
> which requires at least one of the features in sysreg->arch_reqs to be
> available.  But binutils uses AARCH64_CPU_HAS_ALL_FEATURES, which requires
> all of the features to be available.
> 
> At least, it seems odd that AARCH64_NO_FEATURES is all-ones here
> but all-zeros in binutils.

Good point.

Functionally, this worked. I could not see where `aarch64_isa_flags' 
would ever be all zeros, so an all-ones's mask would cause the above 
expression to always evaluate to true and thus allow for any 
`aarch64_isa_flags' configuration to be accepted.

Nonetheless, I very much agree with your point that all-ones is more 
indicative of AARCH64_CPU_HAS_ALL_FEATURES and, as such, having -1 map 
onto AARCH64_NO_FEATURES was misleading insofar as signifying intent and 
felt like bad code.

I've modified things such that we now have AARCH64_NO_FEATURES mapping 
to 0 and, where appropriate, replacing

   if (aarch64_isa_flags & sysreg->arch_reqs)

with something to the effect of:

   if (sysreg->arch_reqs
       && (aarch64_isa_flags & sysreg->arch_reqs)),

thus saying "if the system register has any special architectural 
requirements, then and only then compare those requirement with 
`aarch64_isa_flags'".

> 
>> +
>> +/* Define AARCH64_FL aliases for architectural features which are protected
>> +   by -march flags in binutils but which receive no special treatment by GCC.
>> +
>> +   Such flags are inherited from the Binutils definition of system registers
>> +   and are mapped to the architecture in which the feature is implemented.  */
>> +#define AARCH64_FL_RAS		   AARCH64_FL_V8A
>> +#define AARCH64_FL_LOR		   AARCH64_FL_V8_1A
>> +#define AARCH64_FL_PAN		   AARCH64_FL_V8_1A
>> +#define AARCH64_FL_AMU		   AARCH64_FL_V8_4A
>> +#define AARCH64_FL_SCXTNUM	   AARCH64_FL_V8_5A
>> +#define AARCH64_FL_ID_PFR2	   AARCH64_FL_V8_5A
>> +
>> +/* Define AARCH64_FL aliases for features note yet implemented in GCC.
>> +   Accept them unconditionally.  */
>> +#define AARCH64_FL_SME		   -1
> 
> I think disallowing them would be better.  Otherwise we'd go from
> accepting a register without +sme to not accepting it, which might
> seem like a regression to users.
> 
Naturally, this makes sense.
Agreed.

Thanks,
V.

> Of course, in the particular case of SME, this problem should go
> away very soon :)  And once this sysreg work goes in, it should
> probably become a principle that GCC should accept feature flags as
> soon as it knows about associated system registers (as a sufficient
> but not necessary condition).
> 
> So we can probably leave this as-is on the basis that it will only
> be around for a few weeks.
> 
>> +
>> +/* Flags associated with the properties of system registers.  It mainly serves
>> +   to mark particular registers as read or write only.  */
>> +#define F_DEPRECATED		   (1 << 1)
>> +#define F_REG_READ		   (1 << 2)
>> +#define F_REG_WRITE		   (1 << 3)
>> +#define F_ARCHEXT		   (1 << 4)
>> +/* Flag indicating register name is alias for another system register.  */
>> +#define F_REG_ALIAS		   (1 << 5)
>> +
> 
> Since the definition of sysreg_t is local to aarch64.cc (good!),
> could these flags be defined there rather than in aarch64.h?
> 
> Thanks,
> Richard
> 
>>   /* Crypto is an optional extension to AdvSIMD.  */
>>   #define TARGET_CRYPTO (AARCH64_ISA_CRYPTO)

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-18 20:39   ` Richard Sandiford
@ 2023-10-26 15:06     ` Victor Do Nascimento
  2023-10-26 15:23       ` Richard Sandiford
  0 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-26 15:06 UTC (permalink / raw)
  To: gcc-patches, kyrylo.tkachov, Richard.Earnshaw, richard.sandiford



On 10/18/23 21:39, Richard Sandiford wrote:
> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>> Implement the aarch64 intrinsics for reading and writing system
>> registers with the following signatures:
>>
>> 	uint32_t __arm_rsr(const char *special_register);
>> 	uint64_t __arm_rsr64(const char *special_register);
>> 	void* __arm_rsrp(const char *special_register);
>> 	float __arm_rsrf(const char *special_register);
>> 	double __arm_rsrf64(const char *special_register);
>> 	void __arm_wsr(const char *special_register, uint32_t value);
>> 	void __arm_wsr64(const char *special_register, uint64_t value);
>> 	void __arm_wsrp(const char *special_register, const void *value);
>> 	void __arm_wsrf(const char *special_register, float value);
>> 	void __arm_wsrf64(const char *special_register, double value);
>>
>> gcc/ChangeLog:
>>
>> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
>> 	Add enums for new builtins.
>> 	(aarch64_init_rwsr_builtins): New.
>> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
>> 	(aarch64_expand_rwsr_builtin):  New.
>> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
>> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
>> 	(write_sysregdi): Likewise.
>> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
>> 	(__arm_rsrp): Likewise.
>> 	(__arm_rsr64): Likewise.
>> 	(__arm_rsrf): Likewise.
>> 	(__arm_rsrf64): Likewise.
>> 	(__arm_wsr): Likewise.
>> 	(__arm_wsrp): Likewise.
>> 	(__arm_wsr64): Likewise.
>> 	(__arm_wsrf): Likewise.
>> 	(__arm_wsrf64): Likewise.
>>
>> gcc/testsuite/ChangeLog:
>>
>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
>> ---
>>   gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
>>   gcc/config/aarch64/aarch64.md                 |  17 ++
>>   gcc/config/aarch64/arm_acle.h                 |  30 +++
>>   .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
>>   gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
>>   5 files changed, 411 insertions(+)
>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>>
>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>> index 04f59fd9a54..d8bb2a989a5 100644
>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>> @@ -808,6 +808,17 @@ enum aarch64_builtins
>>     AARCH64_RBIT,
>>     AARCH64_RBITL,
>>     AARCH64_RBITLL,
>> +  /* System register builtins.  */
>> +  AARCH64_RSR,
>> +  AARCH64_RSRP,
>> +  AARCH64_RSR64,
>> +  AARCH64_RSRF,
>> +  AARCH64_RSRF64,
>> +  AARCH64_WSR,
>> +  AARCH64_WSRP,
>> +  AARCH64_WSR64,
>> +  AARCH64_WSRF,
>> +  AARCH64_WSRF64,
>>     AARCH64_BUILTIN_MAX
>>   };
>>   
>> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
>>   				   AARCH64_BUILTIN_RNG_RNDRRS);
>>   }
>>   
>> +/* Add builtins for reading system register.  */
>> +static void
>> +aarch64_init_rwsr_builtins (void)
>> +{
>> +  tree fntype = NULL;
>> +  tree const_char_ptr_type
>> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
>> +
>> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
>> +  aarch64_builtin_decls[AARCH64_##F] \
>> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
>> +
>> +  fntype
>> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>> +				uint32_type_node, NULL);
>> +
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>> +				const_ptr_type_node, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>> +				uint64_type_node, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>> +				float_type_node, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
>> +
>> +  fntype
>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>> +				double_type_node, NULL);
>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
>> +}
>> +
>>   /* Initialize the memory tagging extension (MTE) builtins.  */
>>   struct
>>   {
>> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
>>     aarch64_init_rng_builtins ();
>>     aarch64_init_data_intrinsics ();
>>   
>> +  aarch64_init_rwsr_builtins ();
>> +
>>     tree ftype_jcvt
>>       = build_function_type_list (intSI_type_node, double_type_node, NULL);
>>     aarch64_builtin_decls[AARCH64_JSCVT]
>> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
>>     return target;
>>   }
>>   
>> +/* Expand the read/write system register builtin EXPs.  */
>> +rtx
>> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
>> +{
>> +  tree arg0, arg1;
>> +  rtx const_str, input_val, subreg;
>> +  enum machine_mode mode;
>> +  class expand_operand ops[2];
>> +
>> +  arg0 = CALL_EXPR_ARG (exp, 0);
>> +
>> +  bool write_op = (fcode == AARCH64_WSR
>> +		   || fcode == AARCH64_WSRP
>> +		   || fcode == AARCH64_WSR64
>> +		   || fcode == AARCH64_WSRF
>> +		   || fcode == AARCH64_WSRF64);
>> +  bool read_op = (fcode == AARCH64_RSR
>> +		  || fcode == AARCH64_RSRP
>> +		  || fcode == AARCH64_RSR64
>> +		  || fcode == AARCH64_RSRF
>> +		  || fcode == AARCH64_RSRF64);
> 
> Instead of this, how about using:
> 
>    if (call_expr_nargs (exp) == 1)
> 
> for the read path?
> 

Personally, I don't like that.  It's a `read_op' because of the fcode it 
has, the fact they share the same number of arguments is accidental. 
With this implementation, we outline very early on exactly what 
constitutes both a valid write and a valid read operation.

I'm happy to change things around if you feel strongly enough about it 
or see some material advantage to doing things your way that I've missed :).

>> +
>> +  /* Argument 0 (system register name) must be a string literal.  */
>> +  gcc_assert (!SSA_VAR_P (arg0)
>> +	      && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
>> +	      && TREE_CODE (TREE_OPERAND (arg0,0)) == STRING_CST);
> 
> It looks like this requires arg0 to be an ADDR_EXPR.  It would be good
> to check that rather than !SSA_VAR_P.
> 
> Minor formatting nit: should be a space after the comma.
> 
>> +
>> +  const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
>> +  size_t len = strlen (name_input);
> 
> This can use TREE_STRING_LENGTH.  That's preferable since it copes
> with embedded nuls, e.g. "foo\0bar".
> 
>> +
>> +  if (len == 0)
>> +    {
>> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
>> +      return const0_rtx;
>> +    }
> 
> Is this check necessary?  It looks like the following code would
> correctly reject empty strings.
> 

Not necessary.  As the code evolved, some checks I added early on in 
development went on to become redundant, this being on example.  Thanks 
for picking up on it.

>> +
>> +  char *sysreg_name = (char *) alloca (len + 1);
>> +  strcpy (sysreg_name, name_input);
> 
> We shouldn't use alloca for user input that hasn't been verified yet,
> since it could be arbitrarily long.  Libiberty provides an xmemdup that
> might be useful.  (xmemdup rather than xstrdup to cope with the embedded
> nuls mentioned above.  Or perhaps we should just reject embedded nuls
> immediately, so that later code doesn't need to worry about them.)
> 
>> +
>> +  for (unsigned pos = 0; pos <= len; pos++)
>> +    sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
>> +
>> +  const char* name_output = aarch64_retrieve_sysreg (sysreg_name, write_op);
> 
> Does this TOLOWERing make the checks for capital letters in
> is_implem_def_reg redundant?
> 

Potentially.

The quesion is, do we want  this explicit dependence of 
`is_implem_def_reg' on this TOLOWERing?

My intention was to keep things fairly independent so they could be 
reused elsewhere as easily as possible, should this need arise.  This 
meant I didn't want `is_implem_def_reg' to rely on the passed input 
having been pre-processed in any way, keeping it as general-purpose as 
possible.

Thanks,
V.

> BTW, I forgot to say, but it'd be better to add an "aarch64_" prefix to
> is_implem_def_reg, to avoid accidental clashes with target-independent code.
> 
>> +  if (name_output == NULL)
>> +    {
>> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
>> +      return const0_rtx;
>> +    }
>> +
>> +  /* Assign the string corresponding to the system register name to an RTX.  */
>> +  const_str = rtx_alloc (CONST_STRING);
>> +  PUT_CODE (const_str, CONST_STRING);
>> +  XSTR (const_str, 0) = xstrdup (name_output);
> 
> I think this needs to use ggc_strdup rather than xstrdup, since the
> memory is managed by the garbage collector.
> 
>> +
>> +  /* Set up expander operands and call instruction expansion.  */
>> +  if (read_op)
>> +    {
>> +
> 
> Nit: redundant blank line.
> 
> 
>> +      /* Emit the initial read_sysregdi rtx.  */
>> +      create_output_operand (&ops[0], target, DImode);
>> +      create_fixed_operand (&ops[1], const_str);
>> +      expand_insn (CODE_FOR_aarch64_read_sysregdi, 2, ops);
>> +      target = ops[0].value;
>> +
>> +      /* Do any necessary post-processing on the result.  */
>> +      switch (fcode)
>> +	{
>> +	case AARCH64_RSR:
>> +	  return gen_lowpart_SUBREG (SImode, target);
>> +	case AARCH64_RSRP:
>> +	case AARCH64_RSR64:
>> +	  return target;
> 
> RSRP would return a 32-bit value for -mabi=ilp32.  It might be easier
> to do:
> 
> 	case AARCH64_RSR:
> 	case AARCH64_RSRP:
> 	case AARCH64_RSR64:
> 	case AARCH64_RSRF64:
> 	  return lowpart_subreg (TYPE_MODE (TREE_TYPE (exp)), target, DImode);
> 
> lowpart_subreg is a no-op if the new mode is the same as the old mode.
> 
>> +	case AARCH64_RSRF:
>> +	  subreg = gen_reg_rtx (SImode);
> 
> This line looks redundant.
> 
>> +	  subreg = gen_lowpart_SUBREG (SImode, target);
>> +	  return gen_lowpart_SUBREG (SFmode, subreg);
>> +	case AARCH64_RSRF64:
>> +	  return gen_lowpart_SUBREG (DFmode, target);
>> +	}
> 
> If we do go for my:
> 
> call_expr_nargs (exp) == 1
> 
> suggestion above, this switch should probably have a:
> 
>    default:
>      gcc_unreachable ();
> 
> to catch unexpected ops.
> 
>> +    }
>> +  if (write_op)
>> +    {
>> +
>> +      arg1 = CALL_EXPR_ARG (exp, 1);
>> +      mode = TYPE_MODE (TREE_TYPE (arg1));
>> +      input_val = copy_to_mode_reg (mode, expand_normal (arg1));
>> +
>> +      switch (fcode)
>> +	{
>> +	case AARCH64_WSR:
>> +	  subreg = gen_lowpart_SUBREG (DImode, input_val);
>> +	  break;
>> +	case AARCH64_WSRP:
>> +	case AARCH64_WSR64:
>> +	  subreg = input_val;
>> +	  break;
>> +	case AARCH64_WSRF:
>> +	  subreg = gen_lowpart_SUBREG (SImode, input_val);
>> +	  subreg = gen_lowpart_SUBREG (DImode, subreg);
>> +	  break;
>> +	case AARCH64_WSRF64:
>> +	  subreg = gen_lowpart_SUBREG (DImode, input_val);
>> +	  break;
>> +	}
> 
> Similarly here, I think all cases except AARCH64_WSRF could use:
> 
> 	input_val = lowpart_subreg (DImode, input_value, mode);
> 
>> +
>> +      create_fixed_operand (&ops[0], const_str);
>> +      create_input_operand (&ops[1], subreg, DImode);
>> +      expand_insn (CODE_FOR_aarch64_write_sysregdi, 2, ops);
>> +
>> +      return target;
>> +    }
>> +
>> +  error_at (EXPR_LOCATION (exp),
>> +	    "Malformed call to read/write system register builtin");
>> +  return target;
>> +}
>> +
>>   /* Expand an expression EXP that calls a MEMTAG built-in FCODE
>>      with result going to TARGET.  */
>>   static rtx
>> @@ -2832,6 +3021,17 @@ aarch64_general_expand_builtin (unsigned int fcode, tree exp, rtx target,
>>       case AARCH64_BUILTIN_RNG_RNDR:
>>       case AARCH64_BUILTIN_RNG_RNDRRS:
>>         return aarch64_expand_rng_builtin (exp, target, fcode, ignore);
>> +    case AARCH64_RSR:
>> +    case AARCH64_RSRP:
>> +    case AARCH64_RSR64:
>> +    case AARCH64_RSRF:
>> +    case AARCH64_RSRF64:
>> +    case AARCH64_WSR:
>> +    case AARCH64_WSRP:
>> +    case AARCH64_WSR64:
>> +    case AARCH64_WSRF:
>> +    case AARCH64_WSRF64:
>> +      return aarch64_expand_rwsr_builtin (exp, target, fcode);
>>       }
>>   
>>     if (fcode >= AARCH64_SIMD_BUILTIN_BASE && fcode <= AARCH64_SIMD_BUILTIN_MAX)
>> diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
>> index 32c7adc8928..80da30bc30c 100644
>> --- a/gcc/config/aarch64/aarch64.md
>> +++ b/gcc/config/aarch64/aarch64.md
>> @@ -281,6 +281,8 @@
>>       UNSPEC_UPDATE_FFRT
>>       UNSPEC_RDFFR
>>       UNSPEC_WRFFR
>> +    UNSPEC_SYSREG_RDI
>> +    UNSPEC_SYSREG_WDI
>>       ;; Represents an SVE-style lane index, in which the indexing applies
>>       ;; within the containing 128-bit block.
>>       UNSPEC_SVE_LANE_SELECT
>> @@ -476,6 +478,21 @@
>>   ;; Jumps and other miscellaneous insns
>>   ;; -------------------------------------------------------------------
>>   
>> +(define_insn "aarch64_read_sysregdi"
>> + [(set (match_operand:DI 0 "register_operand" "=r")
>> +       (unspec_volatile:DI [(match_operand 1 "aarch64_sysreg_string" "")]
>> +		  UNSPEC_SYSREG_RDI))]
>> + ""
>> + "mrs\t%x0, %1"
>> + )
>> +
>> +(define_insn "aarch64_write_sysregdi"
>> + [(unspec_volatile:DI [(match_operand 0 "aarch64_sysreg_string" "")
>> +	      (match_operand:DI 1 "register_operand" "r")] UNSPEC_SYSREG_WDI)]
>> + ""
>> + "msr\t%0, %x1"
>> + )
> 
> I think the write pattern should accept rZ (x0-x30 + xzr) rather than just r.
> 
> Minor formatting nit, but other patterns are indented by 2 spaces
> rather than 1, with the closing ")" not indented.
> 
> Thanks,
> Richard
> 
>> +
>>   (define_insn "indirect_jump"
>>     [(set (pc) (match_operand:DI 0 "register_operand" "r"))]
>>     ""
>> diff --git a/gcc/config/aarch64/arm_acle.h b/gcc/config/aarch64/arm_acle.h
>> index 7599a32301d..71ada878299 100644
>> --- a/gcc/config/aarch64/arm_acle.h
>> +++ b/gcc/config/aarch64/arm_acle.h
>> @@ -314,6 +314,36 @@ __rndrrs (uint64_t *__res)
>>   
>>   #pragma GCC pop_options
>>   
>> +#define __arm_rsr(__regname) \
>> +  __builtin_aarch64_rsr (__regname)
>> +
>> +#define __arm_rsrp(__regname) \
>> +  __builtin_aarch64_rsrp (__regname)
>> +
>> +#define __arm_rsr64(__regname) \
>> +  __builtin_aarch64_rsr64 (__regname)
>> +
>> +#define __arm_rsrf(__regname) \
>> +  __builtin_aarch64_rsrf (__regname)
>> +
>> +#define __arm_rsrf64(__regname) \
>> +  __builtin_aarch64_rsrf64 (__regname)
>> +
>> +#define __arm_wsr(__regname, __value) \
>> +  __builtin_aarch64_wsr (__regname, __value)
>> +
>> +#define __arm_wsrp(__regname, __value) \
>> +  __builtin_aarch64_wsrp (__regname, __value)
>> +
>> +#define __arm_wsr64(__regname, __value) \
>> +  __builtin_aarch64_wsr64 (__regname, __value)
>> +
>> +#define __arm_wsrf(__regname, __value) \
>> +  __builtin_aarch64_wsrf (__regname, __value)
>> +
>> +#define __arm_wsrf64(__regname, __value) \
>> +  __builtin_aarch64_wsrf64 (__regname, __value)
>> +
>>   #ifdef __cplusplus
>>   }
>>   #endif
>> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>> new file mode 100644
>> index 00000000000..bc9db098f16
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>> @@ -0,0 +1,20 @@
>> +/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
>> +/* Ensure that illegal behavior is rejected by the compiler.  */
>> +
>> +/* { dg-do compile } */
>> +/* { dg-options "-O3 -march=armv8.4-a" } */
>> +
>> +#include <arm_acle.h>
>> +
>> +/* Ensure that read/write-only register attributes are respected by the compiler.  */
>> +void
>> +test_rwsr_read_write_only ()
>> +{
>> +  /* Attempt to write to read-only registers.  */
>> +  long long a = __arm_rsr64 ("aidr_el1");  /* Read ok.  */
>> +  __arm_wsr64 ("aidr_el1", a); /* { dg-error {invalid system register name provided} } */
>> +
>> +  /* Attempt to read from write-only registers.  */
>> +  __arm_wsr64("icc_asgi1r_el1", a);            /* Write ok.  */
>> +  long long b = __arm_rsr64("icc_asgi1r_el1"); /* { dg-error {invalid system register name provided} } */
>> +}
>> diff --git a/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>> new file mode 100644
>> index 00000000000..3af4b960306
>> --- /dev/null
>> +++ b/gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>> @@ -0,0 +1,144 @@
>> +/* Test the __arm_[r,w]sr ACLE intrinsics family.  */
>> +/* Check that function variants for different data types handle types correctly.  */
>> +/* { dg-do compile } */
>> +/* { dg-options "-O1 -march=armv8.4-a" } */
>> +/* { dg-final { check-function-bodies "**" "" } } */
>> +
>> +#include <arm_acle.h>
>> +
>> +/*
>> +** get_rsr:
>> +** ...
>> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
>> +** 	add	w\1, w\1, 1
>> +** ...
>> +*/
>> +int
>> +get_rsr ()
>> +{
>> +  int a =  __arm_rsr("trcseqstr");
>> +  return a+1;
>> +}
>> +
>> +/*
>> +** get_rsrf:
>> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
>> +** 	fmov	s[0-9]+, w\1
>> +** ...
>> +*/
>> +float
>> +get_rsrf ()
>> +{
>> +  return __arm_rsrf("trcseqstr");
>> +}
>> +
>> +/*
>> +** get_rsrp:
>> +** 	mrs	x0, s2_1_c0_c7_4
>> +** 	ret
>> +*/
>> +void *
>> +get_rsrp ()
>> +{
>> +  return __arm_rsrp("trcseqstr");
>> +}
>> +
>> +/*
>> +** get_rsr64:
>> +** 	mrs	x0, s2_1_c0_c7_4
>> +** 	ret
>> +*/
>> +long long
>> +get_rsr64 ()
>> +{
>> +  return __arm_rsr64("trcseqstr");
>> +}
>> +
>> +/*
>> +** get_rsrf64:
>> +** 	mrs	x([0-9]+), s2_1_c0_c7_4
>> +** 	fmov	d[0-9]+, x\1
>> +** ...
>> +*/
>> +double
>> +get_rsrf64 ()
>> +{
>> +  return __arm_rsrf64("trcseqstr");
>> +}
>> +
>> +/*
>> +** set_wsr32:
>> +** ...
>> +** 	add	w([0-9]+), w\1, 1
>> +** 	msr	s2_1_c0_c7_4, x\1
>> +** ...
>> +*/
>> +void
>> +set_wsr32 (int a)
>> +{
>> +  __arm_wsr("trcseqstr", a+1);
>> +}
>> +
>> +/*
>> +** set_wsrp:
>> +** ...
>> +** 	msr	s2_1_c0_c7_4, x[0-9]+
>> +** ...
>> +*/
>> +void
>> +set_wsrp (void *a)
>> +{
>> +  __arm_wsrp("trcseqstr", a);
>> +}
>> +
>> +/*
>> +** set_wsr64:
>> +** ...
>> +** 	msr	s2_1_c0_c7_4, x[0-9]+
>> +** ...
>> +*/
>> +void
>> +set_wsr64 (long long a)
>> +{
>> +  __arm_wsr64("trcseqstr", a);
>> +}
>> +
>> +/*
>> +** set_wsrf32:
>> +** ...
>> +** 	fmov	w([0-9]+), s[0-9]+
>> +** 	msr	s2_1_c0_c7_4, x\1
>> +** ...
>> +*/
>> +void
>> +set_wsrf32 (float a)
>> +{
>> +  __arm_wsrf("trcseqstr", a);
>> +}
>> +
>> +/*
>> +** set_wsrf64:
>> +** ...
>> +** 	fmov	x([0-9]+), d[0-9]+
>> +** 	msr	s2_1_c0_c7_4, x\1
>> +** ...
>> +*/
>> +void
>> +set_wsrf64(double a)
>> +{
>> +  __arm_wsrf64("trcseqstr", a);
>> +}
>> +
>> +/*
>> +** set_custom:
>> +** ...
>> +** 	mrs	x0, s1_2_c3_c4_5
>> +** ...
>> +** 	msr	s1_2_c3_c4_5, x0
>> +** ...
>> +*/
>> +void set_custom()
>> +{
>> +  __uint64_t b = __arm_rsr64("S1_2_C3_C4_5");
>> +  __arm_wsr64("S1_2_C3_C4_5", b);
>> +}

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 7/7] aarch64: Add system register duplication check selftest
  2023-10-18 21:30   ` Richard Sandiford
@ 2023-10-26 15:13     ` Victor Do Nascimento
  2023-10-26 15:31       ` Richard Sandiford
  0 siblings, 1 reply; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-26 15:13 UTC (permalink / raw)
  To: gcc-patches, kyrylo.tkachov, Richard.Earnshaw, richard.sandiford



On 10/18/23 22:30, Richard Sandiford wrote:
> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>> Add a build-time test to check whether system register data, as
>> imported from `aarch64-sys-reg.def' has any duplicate entries.
>>
>> Duplicate entries are defined as any two SYSREG entries in the .def
>> file which share the same encoding values (as specified by its `CPENC'
>> field) and where the relationship amongst the two does not fit into
>> one of the following categories:
>>
>> 	* Simple aliasing: In some cases, it is observed that one
>> 	register name serves as an alias to another.  One example of
>> 	this is where TRCEXTINSELR aliases TRCEXTINSELR0.
>> 	* Expressing intent: It is possible that when a given register
>> 	serves two distinct functions depending on how it is used, it
>> 	is given two distinct names whose use should match the context
>> 	under which it is being used.  Example:  Debug Data Transfer
>> 	Register. When used to receive data, it should be accessed as
>> 	DBGDTRRX_EL0 while when transmitting data it should be
>> 	accessed via DBGDTRTX_EL0.
>> 	* Register depreciation: Some register names have been
>> 	deprecated and should no longer be used, but backwards-
>> 	compatibility requires that such names continue to be
>> 	recognized, as is the case for the SPSR_EL1 register, whose
>> 	access via the SPSR_SVC name is now deprecated.
>> 	* Same encoding different target: Some encodings are given
>> 	different meaning depending on the target architecture and, as
>> 	such, are given different names in each of theses contexts.
>> 	We see an example of this for CPENC(3,4,2,0,0), which
>> 	corresponds to TTBR0_EL2 for Armv8-A targets and VSCTLR_EL2
>> 	in Armv8-R targets.
>>
>> A consequence of these observations is that `CPENC' duplication is
>> acceptable iff at least one of the `properties' or `arch_reqs' fields
>> of the `sysreg_t' structs associated with the two registers in
>> question differ and it's this condition that is checked by the new
>> `aarch64_test_sysreg_encoding_clashes' function.
>>
>> gcc/ChangeLog:
>>
>> 	* gcc/config/aarch64/aarch64.cc
>> 	(aarch64_test_sysreg_encoding_clashes): New.
>> 	(aarch64_run_selftests): add call to
>> 	aarch64_test_sysreg_encoding_clashes selftest.
>> ---
>>   gcc/config/aarch64/aarch64.cc | 53 +++++++++++++++++++++++++++++++++++
>>   1 file changed, 53 insertions(+)
>>
>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>> index d187e171beb..e0be2877ede 100644
>> --- a/gcc/config/aarch64/aarch64.cc
>> +++ b/gcc/config/aarch64/aarch64.cc
>> @@ -22,6 +22,7 @@
>>   
>>   #define INCLUDE_STRING
>>   #define INCLUDE_ALGORITHM
>> +#define INCLUDE_VECTOR
>>   #include "config.h"
>>   #include "system.h"
>>   #include "coretypes.h"
>> @@ -28332,6 +28333,57 @@ aarch64_test_fractional_cost ()
>>     ASSERT_EQ (cf (1, 2).as_double (), 0.5);
>>   }
>>   
>> +/* Calculate whether our system register data, as imported from
>> +   `aarch64-sys-reg.def' has any duplicate entries.  */
>> +static void
>> +aarch64_test_sysreg_encoding_clashes (void)
>> +{
>> +  using dup_counters_t = hash_map<nofree_string_hash, unsigned>;
>> +  using dup_instances_t = hash_map<nofree_string_hash,
>> +				   std::vector<const sysreg_t*>>;
>> +
>> +  dup_counters_t duplicate_counts;
>> +  dup_instances_t duplicate_instances;
>> +
>> +  /* Every time an encoding is established to come up more than once
>> +  we add it to a "clash-analysis queue", which is then used to extract
>> +  necessary information from our hash map when establishing whether
>> +  repeated encodings are valid.  */
> 
> Formatting nit, sorry, but second and subsequent lines should be
> indented to line up with the "E".
> 
>> +
>> +  /* 1) Collect recurrence information.  */
>> +  std::vector<const char*> testqueue;
>> +
>> +  for (unsigned i = 0; i < nsysreg; i++)
>> +    {
>> +      const sysreg_t *reg = sysreg_structs + i;
>> +
>> +      unsigned *tbl_entry = &duplicate_counts.get_or_insert (reg->encoding);
>> +      *tbl_entry += 1;
>> +
>> +      std::vector<const sysreg_t*> *tmp
>> +	= &duplicate_instances.get_or_insert (reg->encoding);
>> +
>> +      tmp->push_back (reg);
>> +      if (*tbl_entry > 1)
>> +	  testqueue.push_back (reg->encoding);
>> +    }
> 
> Do we need two hash maps here?  It looks like the length of the vector
> is always equal to the count.  Also...
> 

You're right.  Addressed in next iteration of patch series.

>> +
>> +  /* 2) Carry out analysis on collected data.  */
>> +  for (auto enc : testqueue)
> 
> ...hash_map itself is iterable.  We could iterate over that instead,
> which would avoid the need for the queue.
> 

My rationale here is that I prefer to take up the extra little bit of 
memory to save on execution time.

`duplicate_instances' is an iterable of vectors, with one such vector 
for each encountered encoding value, irrespective of whether or not that 
encoding is duplicated.  Thus to iterate over this, we'd have to 1. 
iterate through every possible vector and 2. check each one's length. 
By having our `testqueue', we know immediately which encodings have 
duplicate sysreg entries and thus we can jump immediately to analyzing 
those and only those.

Many thanks,
V.


>> +    {
>> +      unsigned nrep = *duplicate_counts.get (enc);
>> +      for (unsigned i = 0; i < nrep; i++)
>> +	for (unsigned j = i+1; j < nrep; j++)
> 
> Formatting nit, but "i + 1" rather than "i+1".
> 
> Overall, it looks like really nice work.  Thanks for doing this.
> 
> Richard
> 
>> +	  {
>> +	    std::vector<const sysreg_t*> *tmp2 = duplicate_instances.get (enc);
>> +	    const sysreg_t *a = (*tmp2)[i];
>> +	    const sysreg_t *b = (*tmp2)[j];
>> +	    ASSERT_TRUE ((a->properties != b->properties)
>> +			 || (a->arch_reqs != b->arch_reqs));
>> +	  }
>> +    }
>> +}
>> +
>>   /* Run all target-specific selftests.  */
>>   
>>   static void
>> @@ -28339,6 +28391,7 @@ aarch64_run_selftests (void)
>>   {
>>     aarch64_test_loading_full_dump ();
>>     aarch64_test_fractional_cost ();
>> +  aarch64_test_sysreg_encoding_clashes ();
>>   }
>>   
>>   } // namespace selftest

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def
  2023-10-26 14:48     ` Victor Do Nascimento
@ 2023-10-26 15:14       ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-26 15:14 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Thanks for the updates.

Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
> On 10/18/23 22:07, Richard Sandiford wrote:
>> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>>> This patch defines the structure of a new .def file used for
>>> representing the aarch64 system registers, what information it should
>>> hold and the basic framework in GCC to process this file.
>>>
>>> Entries in the aarch64-system-regs.def file should be as follows:
>>>
>>>    SYSREG (NAME, CPENC (sn,op1,cn,cm,op2), FLAG1 | ... | FLAGn, ARCH)
>>>
>>> Where the arguments to SYSREG correspond to:
>>>    - NAME:  The system register name, as used in the assembly language.
>>>    - CPENC: The system register encoding, mapping to:
>>>
>>>      	       s<sn>_<op1>_c<cn>_c<cm>_<op2>
>>>
>>>    - FLAG: The entries in the FLAGS field are bitwise-OR'd together to
>>>      	  encode extra information required to ensure proper use of
>>> 	  the system register.  For example, a read-only system
>>> 	  register will have the flag F_REG_READ, while write-only
>>> 	  registers will be labeled F_REG_WRITE.  Such flags are
>>> 	  tested against at compile-time.
>>>    - ARCH: The architectural features the system register is associated
>>>      	  with.  This is encoded via one of three possible macros:
>>> 	  1. When a system register is universally implemented, we say
>>> 	  it has no feature requirements, so we tag it with the
>>> 	  AARCH64_NO_FEATURES macro.
>>> 	  2. When a register is only implemented for a single
>>> 	  architectural extension EXT, the AARCH64_FEATURE (EXT), is
>>> 	  used.
>>> 	  3. When a given system register is made available by any of N
>>> 	  possible architectural extensions, the AARCH64_FEATURES(N, ...)
>>> 	  macro is used to combine them accordingly.
>>>
>>> In order to enable proper interpretation of the SYSREG entries by the
>>> compiler, flags defining system register behavior such as `F_REG_READ'
>>> and `F_REG_WRITE' are also defined here, so they can later be used for
>>> the validation of system register properties.
>>>
>>> Finally, any architectural feature flags from Binutils missing from GCC
>>> have appropriate aliases defined here so as to ensure
>>> cross-compatibility of SYSREG entries across the toolchain.
>>>
>>> gcc/ChangeLog:
>>>
>>> 	* gcc/config/aarch64/aarch64.cc (sysreg_t): New.
>>> 	(sysreg_structs): Likewise.
>>> 	(nsysreg): Likewise.
>>> 	(AARCH64_FEATURE): Likewise.
>>> 	(AARCH64_FEATURES): Likewise.
>>> 	(AARCH64_NO_FEATURES): Likewise.
>>> 	* gcc/config/aarch64/aarch64.h (AARCH64_ISA_V8A): Add missing
>>> 	ISA flag.
>>> 	(AARCH64_ISA_V8_1A): Likewise.
>>> 	(AARCH64_ISA_V8_7A): Likewise.
>>> 	(AARCH64_ISA_V8_8A): Likewise.
>>> 	(AARCH64_NO_FEATURES): Likewise.
>>> 	(AARCH64_FL_RAS): New ISA flag alias.
>>> 	(AARCH64_FL_LOR): Likewise.
>>> 	(AARCH64_FL_PAN): Likewise.
>>> 	(AARCH64_FL_AMU): Likewise.
>>> 	(AARCH64_FL_SCXTNUM): Likewise.
>>> 	(AARCH64_FL_ID_PFR2): Likewise.
>>> 	(F_DEPRECATED): New.
>>> 	(F_REG_READ): Likewise.
>>> 	(F_REG_WRITE): Likewise.
>>> 	(F_ARCHEXT): Likewise.
>>> 	(F_REG_ALIAS): Likewise.
>>> ---
>>>   gcc/config/aarch64/aarch64.cc | 38 +++++++++++++++++++++++++++++++++++
>>>   gcc/config/aarch64/aarch64.h  | 36 +++++++++++++++++++++++++++++++++
>>>   2 files changed, 74 insertions(+)
>>>
>>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>>> index 9fbfc548a89..69de2366424 100644
>>> --- a/gcc/config/aarch64/aarch64.cc
>>> +++ b/gcc/config/aarch64/aarch64.cc
>>> @@ -2807,6 +2807,44 @@ static const struct processor all_cores[] =
>>>     {NULL, aarch64_none, aarch64_none, aarch64_no_arch, 0, NULL}
>>>   };
>>>   
>>> +typedef struct {
>>> +  const char* name;
>>> +  const char* encoding;
>> 
>> Formatting nit, but GCC style is:
>> 
>>    const char *foo
>> 
>> rather than:
>> 
>>    const char* foo;
>> 
>>> +  const unsigned properties;
>>> +  const unsigned long long arch_reqs;
>> 
>> I don't think these two should be const.  There's no reason in principle
>> why a sysreg_t can't be created and modified dynamically.
>> 
>> It would be useful to have some comments above the fields to say what
>> they represent.  E.g. the definition on its own doesn't make clear what
>> "properties" refers to.
>> 
>> arch_reqs should use aarch64_feature_flags rather than unsigned long long.
>> We're running out of feature flags in GCC too, so aarch64_feature_flags
>> is soon likely to be a C++ class.
>> 
>>> +} sysreg_t;
>>> +
>>> +/* An aarch64_feature_set initializer for a single feature,
>>> +   AARCH64_FEATURE_<FEAT>.  */
>>> +#define AARCH64_FEATURE(FEAT) AARCH64_FL_##FEAT
>>> +
>>> +/* Used by AARCH64_FEATURES.  */
>>> +#define AARCH64_OR_FEATURES_1(X, F1) \
>>> +  AARCH64_FEATURE (F1)
>>> +#define AARCH64_OR_FEATURES_2(X, F1, F2) \
>>> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_1 (X, F2))
>>> +#define AARCH64_OR_FEATURES_3(X, F1, ...) \
>>> +  (AARCH64_FEATURE (F1) | AARCH64_OR_FEATURES_2 (X, __VA_ARGS__))
>>> +
>>> +/* An aarch64_feature_set initializer for the N features listed in "...".  */
>>> +#define AARCH64_FEATURES(N, ...) \
>>> +  AARCH64_OR_FEATURES_##N (0, __VA_ARGS__)
>>> +
>>> +/* Database of system registers, their encodings and architectural
>>> +   requirements.  */
>>> +const sysreg_t sysreg_structs[] =
>>> +{
>>> +#define CPENC(SN, OP1, CN, CM, OP2) "s"#SN"_"#OP1"_c"#CN"_c"#CM"_"#OP2
>>> +#define SYSREG(NAME, ENC, FLAGS, ARCH) \
>>> +  { NAME, ENC, FLAGS, ARCH },
>>> +#include "aarch64-sys-regs.def"
>>> +#undef CPENC
>>> +};
>>> +
>>> +#define TOTAL_ITEMS (sizeof sysreg_structs / sizeof sysreg_structs[0])
>>> +const unsigned nsysreg = TOTAL_ITEMS;
>> 
>> There's an ARRAY_SIZE macro for this.
>> 
>>> +#undef TOTAL_ITEMS
>>> +
>>>   /* The current tuning set.  */
>>>   struct tune_params aarch64_tune_params = generic_tunings;
>>>   
>>> diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
>>> index d74e9116fc5..cf3969a11aa 100644
>>> --- a/gcc/config/aarch64/aarch64.h
>>> +++ b/gcc/config/aarch64/aarch64.h
>>> @@ -179,6 +179,8 @@ enum class aarch64_feature : unsigned char {
>>>   
>>>   /* Macros to test ISA flags.  */
>>>   
>>> +#define AARCH64_ISA_V8A		   (aarch64_isa_flags & AARCH64_FL_V8A)
>>> +#define AARCH64_ISA_V8_1A	   (aarch64_isa_flags & AARCH64_FL_V8_1A)
>>>   #define AARCH64_ISA_CRC            (aarch64_isa_flags & AARCH64_FL_CRC)
>>>   #define AARCH64_ISA_CRYPTO         (aarch64_isa_flags & AARCH64_FL_CRYPTO)
>>>   #define AARCH64_ISA_FP             (aarch64_isa_flags & AARCH64_FL_FP)
>>> @@ -215,6 +217,8 @@ enum class aarch64_feature : unsigned char {
>>>   #define AARCH64_ISA_SB		   (aarch64_isa_flags & AARCH64_FL_SB)
>>>   #define AARCH64_ISA_V8R		   (aarch64_isa_flags & AARCH64_FL_V8R)
>>>   #define AARCH64_ISA_PAUTH	   (aarch64_isa_flags & AARCH64_FL_PAUTH)
>>> +#define AARCH64_ISA_V8_7A	   (aarch64_isa_flags & AARCH64_FL_V8_7A)
>>> +#define AARCH64_ISA_V8_8A	   (aarch64_isa_flags & AARCH64_FL_V8_8A)
>>>   #define AARCH64_ISA_V9A		   (aarch64_isa_flags & AARCH64_FL_V9A)
>>>   #define AARCH64_ISA_V9_1A          (aarch64_isa_flags & AARCH64_FL_V9_1A)
>>>   #define AARCH64_ISA_V9_2A          (aarch64_isa_flags & AARCH64_FL_V9_2A)
>>> @@ -223,6 +227,38 @@ enum class aarch64_feature : unsigned char {
>>>   #define AARCH64_ISA_LS64	   (aarch64_isa_flags & AARCH64_FL_LS64)
>>>   #define AARCH64_ISA_CSSC	   (aarch64_isa_flags & AARCH64_FL_CSSC)
>>>   
>>> +/* AARCH64_FL options necessary for system register implementation.  */
>>> +
>>> +/* Mask for core system registers.  System registers requiring no architectural
>>> +   extensions set up a feature-checking mask which returns any passed flags
>>> +   unchanged when ANDd with.  */
>>> +#define AARCH64_NO_FEATURES	   (uint64_t)-1
>> 
>> I think this one should only be defined before including the .def file,
>> and undefined afterwards.  It's not something that general GCC code
>> should use.
>> 
>> Is -1 right though?  3/7 uses:
>> 
>>    if (aarch64_isa_flags & sysreg->arch_reqs)
>> 
>> which requires at least one of the features in sysreg->arch_reqs to be
>> available.  But binutils uses AARCH64_CPU_HAS_ALL_FEATURES, which requires
>> all of the features to be available.
>> 
>> At least, it seems odd that AARCH64_NO_FEATURES is all-ones here
>> but all-zeros in binutils.
>
> Good point.
>
> Functionally, this worked. I could not see where `aarch64_isa_flags' 
> would ever be all zeros, so an all-ones's mask would cause the above 
> expression to always evaluate to true and thus allow for any 
> `aarch64_isa_flags' configuration to be accepted.
>
> Nonetheless, I very much agree with your point that all-ones is more 
> indicative of AARCH64_CPU_HAS_ALL_FEATURES and, as such, having -1 map 
> onto AARCH64_NO_FEATURES was misleading insofar as signifying intent and 
> felt like bad code.
>
> I've modified things such that we now have AARCH64_NO_FEATURES mapping 
> to 0 and, where appropriate, replacing
>
>    if (aarch64_isa_flags & sysreg->arch_reqs)
>
> with something to the effect of:
>
>    if (sysreg->arch_reqs
>        && (aarch64_isa_flags & sysreg->arch_reqs)),
>
> thus saying "if the system register has any special architectural 
> requirements, then and only then compare those requirement with 
> `aarch64_isa_flags'".

I think it should instead be:

  if ((aarch64_isa_flags & sysreg->arch_reqs) == sysreg->arch_reqs)

or (equivalently)

  if ((~aarch64_isa_flags & sysreg->arch_reqs) == 0)

which requires all of the flags in arch_reqs to be present.
That matches what AARCH64_CPU_HAS_ALL_FEATURES does, and is always
true when sysreg->arch_reqs is zero.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-26 15:06     ` Victor Do Nascimento
@ 2023-10-26 15:23       ` Richard Sandiford
  2023-10-26 15:56         ` Victor Do Nascimento
  2023-10-27 13:18         ` Alex Coplan
  0 siblings, 2 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-26 15:23 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
> On 10/18/23 21:39, Richard Sandiford wrote:
>> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>>> Implement the aarch64 intrinsics for reading and writing system
>>> registers with the following signatures:
>>>
>>> 	uint32_t __arm_rsr(const char *special_register);
>>> 	uint64_t __arm_rsr64(const char *special_register);
>>> 	void* __arm_rsrp(const char *special_register);
>>> 	float __arm_rsrf(const char *special_register);
>>> 	double __arm_rsrf64(const char *special_register);
>>> 	void __arm_wsr(const char *special_register, uint32_t value);
>>> 	void __arm_wsr64(const char *special_register, uint64_t value);
>>> 	void __arm_wsrp(const char *special_register, const void *value);
>>> 	void __arm_wsrf(const char *special_register, float value);
>>> 	void __arm_wsrf64(const char *special_register, double value);
>>>
>>> gcc/ChangeLog:
>>>
>>> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
>>> 	Add enums for new builtins.
>>> 	(aarch64_init_rwsr_builtins): New.
>>> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
>>> 	(aarch64_expand_rwsr_builtin):  New.
>>> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
>>> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
>>> 	(write_sysregdi): Likewise.
>>> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
>>> 	(__arm_rsrp): Likewise.
>>> 	(__arm_rsr64): Likewise.
>>> 	(__arm_rsrf): Likewise.
>>> 	(__arm_rsrf64): Likewise.
>>> 	(__arm_wsr): Likewise.
>>> 	(__arm_wsrp): Likewise.
>>> 	(__arm_wsr64): Likewise.
>>> 	(__arm_wsrf): Likewise.
>>> 	(__arm_wsrf64): Likewise.
>>>
>>> gcc/testsuite/ChangeLog:
>>>
>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
>>> ---
>>>   gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
>>>   gcc/config/aarch64/aarch64.md                 |  17 ++
>>>   gcc/config/aarch64/arm_acle.h                 |  30 +++
>>>   .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
>>>   gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
>>>   5 files changed, 411 insertions(+)
>>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>>>
>>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>>> index 04f59fd9a54..d8bb2a989a5 100644
>>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>>> @@ -808,6 +808,17 @@ enum aarch64_builtins
>>>     AARCH64_RBIT,
>>>     AARCH64_RBITL,
>>>     AARCH64_RBITLL,
>>> +  /* System register builtins.  */
>>> +  AARCH64_RSR,
>>> +  AARCH64_RSRP,
>>> +  AARCH64_RSR64,
>>> +  AARCH64_RSRF,
>>> +  AARCH64_RSRF64,
>>> +  AARCH64_WSR,
>>> +  AARCH64_WSRP,
>>> +  AARCH64_WSR64,
>>> +  AARCH64_WSRF,
>>> +  AARCH64_WSRF64,
>>>     AARCH64_BUILTIN_MAX
>>>   };
>>>   
>>> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
>>>   				   AARCH64_BUILTIN_RNG_RNDRRS);
>>>   }
>>>   
>>> +/* Add builtins for reading system register.  */
>>> +static void
>>> +aarch64_init_rwsr_builtins (void)
>>> +{
>>> +  tree fntype = NULL;
>>> +  tree const_char_ptr_type
>>> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
>>> +
>>> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
>>> +  aarch64_builtin_decls[AARCH64_##F] \
>>> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>> +				uint32_type_node, NULL);
>>> +
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>> +				const_ptr_type_node, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>> +				uint64_type_node, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>> +				float_type_node, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
>>> +
>>> +  fntype
>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>> +				double_type_node, NULL);
>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
>>> +}
>>> +
>>>   /* Initialize the memory tagging extension (MTE) builtins.  */
>>>   struct
>>>   {
>>> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
>>>     aarch64_init_rng_builtins ();
>>>     aarch64_init_data_intrinsics ();
>>>   
>>> +  aarch64_init_rwsr_builtins ();
>>> +
>>>     tree ftype_jcvt
>>>       = build_function_type_list (intSI_type_node, double_type_node, NULL);
>>>     aarch64_builtin_decls[AARCH64_JSCVT]
>>> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
>>>     return target;
>>>   }
>>>   
>>> +/* Expand the read/write system register builtin EXPs.  */
>>> +rtx
>>> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
>>> +{
>>> +  tree arg0, arg1;
>>> +  rtx const_str, input_val, subreg;
>>> +  enum machine_mode mode;
>>> +  class expand_operand ops[2];
>>> +
>>> +  arg0 = CALL_EXPR_ARG (exp, 0);
>>> +
>>> +  bool write_op = (fcode == AARCH64_WSR
>>> +		   || fcode == AARCH64_WSRP
>>> +		   || fcode == AARCH64_WSR64
>>> +		   || fcode == AARCH64_WSRF
>>> +		   || fcode == AARCH64_WSRF64);
>>> +  bool read_op = (fcode == AARCH64_RSR
>>> +		  || fcode == AARCH64_RSRP
>>> +		  || fcode == AARCH64_RSR64
>>> +		  || fcode == AARCH64_RSRF
>>> +		  || fcode == AARCH64_RSRF64);
>> 
>> Instead of this, how about using:
>> 
>>    if (call_expr_nargs (exp) == 1)
>> 
>> for the read path?
>> 
>
> Personally, I don't like that.  It's a `read_op' because of the fcode it 
> has, the fact they share the same number of arguments is accidental. 
> With this implementation, we outline very early on exactly what 
> constitutes both a valid write and a valid read operation.

I don't agree that it's accidental. :)  But fair enough, I won't push it.

> I'm happy to change things around if you feel strongly enough about it 
> or see some material advantage to doing things your way that I've missed :).
>
>>> +
>>> +  /* Argument 0 (system register name) must be a string literal.  */
>>> +  gcc_assert (!SSA_VAR_P (arg0)
>>> +	      && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
>>> +	      && TREE_CODE (TREE_OPERAND (arg0,0)) == STRING_CST);
>> 
>> It looks like this requires arg0 to be an ADDR_EXPR.  It would be good
>> to check that rather than !SSA_VAR_P.
>> 
>> Minor formatting nit: should be a space after the comma.
>> 
>>> +
>>> +  const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
>>> +  size_t len = strlen (name_input);
>> 
>> This can use TREE_STRING_LENGTH.  That's preferable since it copes
>> with embedded nuls, e.g. "foo\0bar".
>> 
>>> +
>>> +  if (len == 0)
>>> +    {
>>> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
>>> +      return const0_rtx;
>>> +    }
>> 
>> Is this check necessary?  It looks like the following code would
>> correctly reject empty strings.
>> 
>
> Not necessary.  As the code evolved, some checks I added early on in 
> development went on to become redundant, this being on example.  Thanks 
> for picking up on it.
>
>>> +
>>> +  char *sysreg_name = (char *) alloca (len + 1);
>>> +  strcpy (sysreg_name, name_input);
>> 
>> We shouldn't use alloca for user input that hasn't been verified yet,
>> since it could be arbitrarily long.  Libiberty provides an xmemdup that
>> might be useful.  (xmemdup rather than xstrdup to cope with the embedded
>> nuls mentioned above.  Or perhaps we should just reject embedded nuls
>> immediately, so that later code doesn't need to worry about them.)
>> 
>>> +
>>> +  for (unsigned pos = 0; pos <= len; pos++)
>>> +    sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
>>> +
>>> +  const char* name_output = aarch64_retrieve_sysreg (sysreg_name, write_op);
>> 
>> Does this TOLOWERing make the checks for capital letters in
>> is_implem_def_reg redundant?
>> 
>
> Potentially.
>
> The quesion is, do we want  this explicit dependence of 
> `is_implem_def_reg' on this TOLOWERing?
>
> My intention was to keep things fairly independent so they could be 
> reused elsewhere as easily as possible, should this need arise.  This 
> meant I didn't want `is_implem_def_reg' to rely on the passed input 
> having been pre-processed in any way, keeping it as general-purpose as 
> possible.

I think it's good if we have a canonical form internally.  And it looks
like the patches do have a canonical form, thanks to these TOLOWER calls.
IMO it's better to embrace that rather than support the possibility of
having multiple representations of the same thing in future.

Also, aarch64_lookup_sysreg_map requires the argument to be lower case
if it specifies a predefined register name, since we (rightly) don't
add every case variation of a register name to the hash table.  So it
seems more consistent to have the same precondition for both types of
register name, rather than requiring one to be lower case and allowing
the other to be mixed case.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 7/7] aarch64: Add system register duplication check selftest
  2023-10-26 15:13     ` Victor Do Nascimento
@ 2023-10-26 15:31       ` Richard Sandiford
  0 siblings, 0 replies; 23+ messages in thread
From: Richard Sandiford @ 2023-10-26 15:31 UTC (permalink / raw)
  To: Victor Do Nascimento; +Cc: gcc-patches, kyrylo.tkachov, Richard.Earnshaw

Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
> On 10/18/23 22:30, Richard Sandiford wrote:
>> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>>> Add a build-time test to check whether system register data, as
>>> imported from `aarch64-sys-reg.def' has any duplicate entries.
>>>
>>> Duplicate entries are defined as any two SYSREG entries in the .def
>>> file which share the same encoding values (as specified by its `CPENC'
>>> field) and where the relationship amongst the two does not fit into
>>> one of the following categories:
>>>
>>> 	* Simple aliasing: In some cases, it is observed that one
>>> 	register name serves as an alias to another.  One example of
>>> 	this is where TRCEXTINSELR aliases TRCEXTINSELR0.
>>> 	* Expressing intent: It is possible that when a given register
>>> 	serves two distinct functions depending on how it is used, it
>>> 	is given two distinct names whose use should match the context
>>> 	under which it is being used.  Example:  Debug Data Transfer
>>> 	Register. When used to receive data, it should be accessed as
>>> 	DBGDTRRX_EL0 while when transmitting data it should be
>>> 	accessed via DBGDTRTX_EL0.
>>> 	* Register depreciation: Some register names have been
>>> 	deprecated and should no longer be used, but backwards-
>>> 	compatibility requires that such names continue to be
>>> 	recognized, as is the case for the SPSR_EL1 register, whose
>>> 	access via the SPSR_SVC name is now deprecated.
>>> 	* Same encoding different target: Some encodings are given
>>> 	different meaning depending on the target architecture and, as
>>> 	such, are given different names in each of theses contexts.
>>> 	We see an example of this for CPENC(3,4,2,0,0), which
>>> 	corresponds to TTBR0_EL2 for Armv8-A targets and VSCTLR_EL2
>>> 	in Armv8-R targets.
>>>
>>> A consequence of these observations is that `CPENC' duplication is
>>> acceptable iff at least one of the `properties' or `arch_reqs' fields
>>> of the `sysreg_t' structs associated with the two registers in
>>> question differ and it's this condition that is checked by the new
>>> `aarch64_test_sysreg_encoding_clashes' function.
>>>
>>> gcc/ChangeLog:
>>>
>>> 	* gcc/config/aarch64/aarch64.cc
>>> 	(aarch64_test_sysreg_encoding_clashes): New.
>>> 	(aarch64_run_selftests): add call to
>>> 	aarch64_test_sysreg_encoding_clashes selftest.
>>> ---
>>>   gcc/config/aarch64/aarch64.cc | 53 +++++++++++++++++++++++++++++++++++
>>>   1 file changed, 53 insertions(+)
>>>
>>> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
>>> index d187e171beb..e0be2877ede 100644
>>> --- a/gcc/config/aarch64/aarch64.cc
>>> +++ b/gcc/config/aarch64/aarch64.cc
>>> @@ -22,6 +22,7 @@
>>>   
>>>   #define INCLUDE_STRING
>>>   #define INCLUDE_ALGORITHM
>>> +#define INCLUDE_VECTOR
>>>   #include "config.h"
>>>   #include "system.h"
>>>   #include "coretypes.h"
>>> @@ -28332,6 +28333,57 @@ aarch64_test_fractional_cost ()
>>>     ASSERT_EQ (cf (1, 2).as_double (), 0.5);
>>>   }
>>>   
>>> +/* Calculate whether our system register data, as imported from
>>> +   `aarch64-sys-reg.def' has any duplicate entries.  */
>>> +static void
>>> +aarch64_test_sysreg_encoding_clashes (void)
>>> +{
>>> +  using dup_counters_t = hash_map<nofree_string_hash, unsigned>;
>>> +  using dup_instances_t = hash_map<nofree_string_hash,
>>> +				   std::vector<const sysreg_t*>>;
>>> +
>>> +  dup_counters_t duplicate_counts;
>>> +  dup_instances_t duplicate_instances;
>>> +
>>> +  /* Every time an encoding is established to come up more than once
>>> +  we add it to a "clash-analysis queue", which is then used to extract
>>> +  necessary information from our hash map when establishing whether
>>> +  repeated encodings are valid.  */
>> 
>> Formatting nit, sorry, but second and subsequent lines should be
>> indented to line up with the "E".
>> 
>>> +
>>> +  /* 1) Collect recurrence information.  */
>>> +  std::vector<const char*> testqueue;
>>> +
>>> +  for (unsigned i = 0; i < nsysreg; i++)
>>> +    {
>>> +      const sysreg_t *reg = sysreg_structs + i;
>>> +
>>> +      unsigned *tbl_entry = &duplicate_counts.get_or_insert (reg->encoding);
>>> +      *tbl_entry += 1;
>>> +
>>> +      std::vector<const sysreg_t*> *tmp
>>> +	= &duplicate_instances.get_or_insert (reg->encoding);
>>> +
>>> +      tmp->push_back (reg);
>>> +      if (*tbl_entry > 1)
>>> +	  testqueue.push_back (reg->encoding);
>>> +    }
>> 
>> Do we need two hash maps here?  It looks like the length of the vector
>> is always equal to the count.  Also...
>> 
>
> You're right.  Addressed in next iteration of patch series.
>
>>> +
>>> +  /* 2) Carry out analysis on collected data.  */
>>> +  for (auto enc : testqueue)
>> 
>> ...hash_map itself is iterable.  We could iterate over that instead,
>> which would avoid the need for the queue.
>> 
>
> My rationale here is that I prefer to take up the extra little bit of 
> memory to save on execution time.
>
> `duplicate_instances' is an iterable of vectors, with one such vector 
> for each encountered encoding value, irrespective of whether or not that 
> encoding is duplicated.  Thus to iterate over this, we'd have to 1. 
> iterate through every possible vector and 2. check each one's length. 
> By having our `testqueue', we know immediately which encodings have 
> duplicate sysreg entries and thus we can jump immediately to analyzing 
> those and only those.

Yeah, but creating testqueue has its own overhead, with its own
memory allocations (which aren't free).  This is also run-once
self-test code, iterating over a fairly small, fixed-size, static array.
So I'm not sure the extra code is really paying for itself in practice.

I won't push it though, since I agree the code is correct.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-26 15:23       ` Richard Sandiford
@ 2023-10-26 15:56         ` Victor Do Nascimento
  2023-10-27 13:18         ` Alex Coplan
  1 sibling, 0 replies; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-26 15:56 UTC (permalink / raw)
  To: gcc-patches, kyrylo.tkachov, Richard.Earnshaw, richard.sandiford



On 10/26/23 16:23, Richard Sandiford wrote:
> Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
>> On 10/18/23 21:39, Richard Sandiford wrote:
>>> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>>>> Implement the aarch64 intrinsics for reading and writing system
>>>> registers with the following signatures:
>>>>
>>>> 	uint32_t __arm_rsr(const char *special_register);
>>>> 	uint64_t __arm_rsr64(const char *special_register);
>>>> 	void* __arm_rsrp(const char *special_register);
>>>> 	float __arm_rsrf(const char *special_register);
>>>> 	double __arm_rsrf64(const char *special_register);
>>>> 	void __arm_wsr(const char *special_register, uint32_t value);
>>>> 	void __arm_wsr64(const char *special_register, uint64_t value);
>>>> 	void __arm_wsrp(const char *special_register, const void *value);
>>>> 	void __arm_wsrf(const char *special_register, float value);
>>>> 	void __arm_wsrf64(const char *special_register, double value);
>>>>
>>>> gcc/ChangeLog:
>>>>
>>>> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
>>>> 	Add enums for new builtins.
>>>> 	(aarch64_init_rwsr_builtins): New.
>>>> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
>>>> 	(aarch64_expand_rwsr_builtin):  New.
>>>> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
>>>> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
>>>> 	(write_sysregdi): Likewise.
>>>> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
>>>> 	(__arm_rsrp): Likewise.
>>>> 	(__arm_rsr64): Likewise.
>>>> 	(__arm_rsrf): Likewise.
>>>> 	(__arm_rsrf64): Likewise.
>>>> 	(__arm_wsr): Likewise.
>>>> 	(__arm_wsrp): Likewise.
>>>> 	(__arm_wsr64): Likewise.
>>>> 	(__arm_wsrf): Likewise.
>>>> 	(__arm_wsrf64): Likewise.
>>>>
>>>> gcc/testsuite/ChangeLog:
>>>>
>>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
>>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
>>>> ---
>>>>    gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
>>>>    gcc/config/aarch64/aarch64.md                 |  17 ++
>>>>    gcc/config/aarch64/arm_acle.h                 |  30 +++
>>>>    .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
>>>>    gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
>>>>    5 files changed, 411 insertions(+)
>>>>    create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>>>>    create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>>>>
>>>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>>>> index 04f59fd9a54..d8bb2a989a5 100644
>>>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>>>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>>>> @@ -808,6 +808,17 @@ enum aarch64_builtins
>>>>      AARCH64_RBIT,
>>>>      AARCH64_RBITL,
>>>>      AARCH64_RBITLL,
>>>> +  /* System register builtins.  */
>>>> +  AARCH64_RSR,
>>>> +  AARCH64_RSRP,
>>>> +  AARCH64_RSR64,
>>>> +  AARCH64_RSRF,
>>>> +  AARCH64_RSRF64,
>>>> +  AARCH64_WSR,
>>>> +  AARCH64_WSRP,
>>>> +  AARCH64_WSR64,
>>>> +  AARCH64_WSRF,
>>>> +  AARCH64_WSRF64,
>>>>      AARCH64_BUILTIN_MAX
>>>>    };
>>>>    
>>>> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
>>>>    				   AARCH64_BUILTIN_RNG_RNDRRS);
>>>>    }
>>>>    
>>>> +/* Add builtins for reading system register.  */
>>>> +static void
>>>> +aarch64_init_rwsr_builtins (void)
>>>> +{
>>>> +  tree fntype = NULL;
>>>> +  tree const_char_ptr_type
>>>> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
>>>> +
>>>> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
>>>> +  aarch64_builtin_decls[AARCH64_##F] \
>>>> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>> +				uint32_type_node, NULL);
>>>> +
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>> +				const_ptr_type_node, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>> +				uint64_type_node, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>> +				float_type_node, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
>>>> +
>>>> +  fntype
>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>> +				double_type_node, NULL);
>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
>>>> +}
>>>> +
>>>>    /* Initialize the memory tagging extension (MTE) builtins.  */
>>>>    struct
>>>>    {
>>>> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
>>>>      aarch64_init_rng_builtins ();
>>>>      aarch64_init_data_intrinsics ();
>>>>    
>>>> +  aarch64_init_rwsr_builtins ();
>>>> +
>>>>      tree ftype_jcvt
>>>>        = build_function_type_list (intSI_type_node, double_type_node, NULL);
>>>>      aarch64_builtin_decls[AARCH64_JSCVT]
>>>> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
>>>>      return target;
>>>>    }
>>>>    
>>>> +/* Expand the read/write system register builtin EXPs.  */
>>>> +rtx
>>>> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
>>>> +{
>>>> +  tree arg0, arg1;
>>>> +  rtx const_str, input_val, subreg;
>>>> +  enum machine_mode mode;
>>>> +  class expand_operand ops[2];
>>>> +
>>>> +  arg0 = CALL_EXPR_ARG (exp, 0);
>>>> +
>>>> +  bool write_op = (fcode == AARCH64_WSR
>>>> +		   || fcode == AARCH64_WSRP
>>>> +		   || fcode == AARCH64_WSR64
>>>> +		   || fcode == AARCH64_WSRF
>>>> +		   || fcode == AARCH64_WSRF64);
>>>> +  bool read_op = (fcode == AARCH64_RSR
>>>> +		  || fcode == AARCH64_RSRP
>>>> +		  || fcode == AARCH64_RSR64
>>>> +		  || fcode == AARCH64_RSRF
>>>> +		  || fcode == AARCH64_RSRF64);
>>>
>>> Instead of this, how about using:
>>>
>>>     if (call_expr_nargs (exp) == 1)
>>>
>>> for the read path?
>>>
>>
>> Personally, I don't like that.  It's a `read_op' because of the fcode it
>> has, the fact they share the same number of arguments is accidental.
>> With this implementation, we outline very early on exactly what
>> constitutes both a valid write and a valid read operation.
> 
> I don't agree that it's accidental. :)  But fair enough, I won't push it.
> 

Iff your objection is not so big so as to you letting me have my way, 
then I shall not complain!  Thanks.

>> I'm happy to change things around if you feel strongly enough about it
>> or see some material advantage to doing things your way that I've missed :).
>>
>>>> +
>>>> +  /* Argument 0 (system register name) must be a string literal.  */
>>>> +  gcc_assert (!SSA_VAR_P (arg0)
>>>> +	      && TREE_CODE (TREE_TYPE (arg0)) == POINTER_TYPE
>>>> +	      && TREE_CODE (TREE_OPERAND (arg0,0)) == STRING_CST);
>>>
>>> It looks like this requires arg0 to be an ADDR_EXPR.  It would be good
>>> to check that rather than !SSA_VAR_P.
>>>
>>> Minor formatting nit: should be a space after the comma.
>>>
>>>> +
>>>> +  const char *name_input = TREE_STRING_POINTER (TREE_OPERAND (arg0, 0));
>>>> +  size_t len = strlen (name_input);
>>>
>>> This can use TREE_STRING_LENGTH.  That's preferable since it copes
>>> with embedded nuls, e.g. "foo\0bar".

I figured that `c_strlen', as defined in `builtins.cc' would be helpful 
here, having logic to handle "odd" strings, both those which contain an 
embedded null and those lacking a null terminator altogether, returning 
NULL_TREE in both scenarios.  This allows us to deal with embedded nulls 
early on, rejecting them straight away.

Any thoughts on this?

Many thanks,
V.

>>>
>>>> +
>>>> +  if (len == 0)
>>>> +    {
>>>> +      error_at (EXPR_LOCATION (exp), "invalid system register name provided");
>>>> +      return const0_rtx;
>>>> +    }
>>>
>>> Is this check necessary?  It looks like the following code would
>>> correctly reject empty strings.
>>>
>>
>> Not necessary.  As the code evolved, some checks I added early on in
>> development went on to become redundant, this being on example.  Thanks
>> for picking up on it.
>>
>>>> +
>>>> +  char *sysreg_name = (char *) alloca (len + 1);
>>>> +  strcpy (sysreg_name, name_input);
>>>
>>> We shouldn't use alloca for user input that hasn't been verified yet,
>>> since it could be arbitrarily long.  Libiberty provides an xmemdup that
>>> might be useful.  (xmemdup rather than xstrdup to cope with the embedded
>>> nuls mentioned above.  Or perhaps we should just reject embedded nuls
>>> immediately, so that later code doesn't need to worry about them.)
>>>
>>>> +
>>>> +  for (unsigned pos = 0; pos <= len; pos++)
>>>> +    sysreg_name[pos] = TOLOWER (sysreg_name[pos]);
>>>> +
>>>> +  const char* name_output = aarch64_retrieve_sysreg (sysreg_name, write_op);
>>>
>>> Does this TOLOWERing make the checks for capital letters in
>>> is_implem_def_reg redundant?
>>>
>>
>> Potentially.
>>
>> The quesion is, do we want  this explicit dependence of
>> `is_implem_def_reg' on this TOLOWERing?
>>
>> My intention was to keep things fairly independent so they could be
>> reused elsewhere as easily as possible, should this need arise.  This
>> meant I didn't want `is_implem_def_reg' to rely on the passed input
>> having been pre-processed in any way, keeping it as general-purpose as
>> possible.
> 
> I think it's good if we have a canonical form internally.  And it looks
> like the patches do have a canonical form, thanks to these TOLOWER calls.
> IMO it's better to embrace that rather than support the possibility of
> having multiple representations of the same thing in future.
> 
> Also, aarch64_lookup_sysreg_map requires the argument to be lower case
> if it specifies a predefined register name, since we (rightly) don't
> add every case variation of a register name to the hash table.  So it
> seems more consistent to have the same precondition for both types of
> register name, rather than requiring one to be lower case and allowing
> the other to be mixed case.
> 

I see your point!

> Thanks,
> Richard

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-26 15:23       ` Richard Sandiford
  2023-10-26 15:56         ` Victor Do Nascimento
@ 2023-10-27 13:18         ` Alex Coplan
  2023-10-27 13:51           ` Victor Do Nascimento
  1 sibling, 1 reply; 23+ messages in thread
From: Alex Coplan @ 2023-10-27 13:18 UTC (permalink / raw)
  To: Victor Do Nascimento, gcc-patches, kyrylo.tkachov,
	Richard.Earnshaw, richard.sandiford

On 26/10/2023 16:23, Richard Sandiford wrote:
> Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
> > On 10/18/23 21:39, Richard Sandiford wrote:
> >> Victor Do Nascimento <victor.donascimento@arm.com> writes:
> >>> Implement the aarch64 intrinsics for reading and writing system
> >>> registers with the following signatures:
> >>>
> >>> 	uint32_t __arm_rsr(const char *special_register);
> >>> 	uint64_t __arm_rsr64(const char *special_register);
> >>> 	void* __arm_rsrp(const char *special_register);
> >>> 	float __arm_rsrf(const char *special_register);
> >>> 	double __arm_rsrf64(const char *special_register);
> >>> 	void __arm_wsr(const char *special_register, uint32_t value);
> >>> 	void __arm_wsr64(const char *special_register, uint64_t value);
> >>> 	void __arm_wsrp(const char *special_register, const void *value);
> >>> 	void __arm_wsrf(const char *special_register, float value);
> >>> 	void __arm_wsrf64(const char *special_register, double value);
> >>>
> >>> gcc/ChangeLog:
> >>>
> >>> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
> >>> 	Add enums for new builtins.
> >>> 	(aarch64_init_rwsr_builtins): New.
> >>> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
> >>> 	(aarch64_expand_rwsr_builtin):  New.
> >>> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
> >>> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
> >>> 	(write_sysregdi): Likewise.
> >>> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
> >>> 	(__arm_rsrp): Likewise.
> >>> 	(__arm_rsr64): Likewise.
> >>> 	(__arm_rsrf): Likewise.
> >>> 	(__arm_rsrf64): Likewise.
> >>> 	(__arm_wsr): Likewise.
> >>> 	(__arm_wsrp): Likewise.
> >>> 	(__arm_wsr64): Likewise.
> >>> 	(__arm_wsrf): Likewise.
> >>> 	(__arm_wsrf64): Likewise.
> >>>
> >>> gcc/testsuite/ChangeLog:
> >>>
> >>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
> >>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
> >>> ---
> >>>   gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
> >>>   gcc/config/aarch64/aarch64.md                 |  17 ++
> >>>   gcc/config/aarch64/arm_acle.h                 |  30 +++
> >>>   .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
> >>>   gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
> >>>   5 files changed, 411 insertions(+)
> >>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
> >>>   create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
> >>>
> >>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
> >>> index 04f59fd9a54..d8bb2a989a5 100644
> >>> --- a/gcc/config/aarch64/aarch64-builtins.cc
> >>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
> >>> @@ -808,6 +808,17 @@ enum aarch64_builtins
> >>>     AARCH64_RBIT,
> >>>     AARCH64_RBITL,
> >>>     AARCH64_RBITLL,
> >>> +  /* System register builtins.  */
> >>> +  AARCH64_RSR,
> >>> +  AARCH64_RSRP,
> >>> +  AARCH64_RSR64,
> >>> +  AARCH64_RSRF,
> >>> +  AARCH64_RSRF64,
> >>> +  AARCH64_WSR,
> >>> +  AARCH64_WSRP,
> >>> +  AARCH64_WSR64,
> >>> +  AARCH64_WSRF,
> >>> +  AARCH64_WSRF64,
> >>>     AARCH64_BUILTIN_MAX
> >>>   };
> >>>   
> >>> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
> >>>   				   AARCH64_BUILTIN_RNG_RNDRRS);
> >>>   }
> >>>   
> >>> +/* Add builtins for reading system register.  */
> >>> +static void
> >>> +aarch64_init_rwsr_builtins (void)
> >>> +{
> >>> +  tree fntype = NULL;
> >>> +  tree const_char_ptr_type
> >>> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
> >>> +
> >>> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
> >>> +  aarch64_builtin_decls[AARCH64_##F] \
> >>> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> >>> +				uint32_type_node, NULL);
> >>> +
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> >>> +				const_ptr_type_node, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> >>> +				uint64_type_node, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> >>> +				float_type_node, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
> >>> +
> >>> +  fntype
> >>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
> >>> +				double_type_node, NULL);
> >>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
> >>> +}
> >>> +
> >>>   /* Initialize the memory tagging extension (MTE) builtins.  */
> >>>   struct
> >>>   {
> >>> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
> >>>     aarch64_init_rng_builtins ();
> >>>     aarch64_init_data_intrinsics ();
> >>>   
> >>> +  aarch64_init_rwsr_builtins ();
> >>> +
> >>>     tree ftype_jcvt
> >>>       = build_function_type_list (intSI_type_node, double_type_node, NULL);
> >>>     aarch64_builtin_decls[AARCH64_JSCVT]
> >>> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
> >>>     return target;
> >>>   }
> >>>   
> >>> +/* Expand the read/write system register builtin EXPs.  */
> >>> +rtx
> >>> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
> >>> +{
> >>> +  tree arg0, arg1;
> >>> +  rtx const_str, input_val, subreg;
> >>> +  enum machine_mode mode;
> >>> +  class expand_operand ops[2];
> >>> +
> >>> +  arg0 = CALL_EXPR_ARG (exp, 0);
> >>> +
> >>> +  bool write_op = (fcode == AARCH64_WSR
> >>> +		   || fcode == AARCH64_WSRP
> >>> +		   || fcode == AARCH64_WSR64
> >>> +		   || fcode == AARCH64_WSRF
> >>> +		   || fcode == AARCH64_WSRF64);
> >>> +  bool read_op = (fcode == AARCH64_RSR
> >>> +		  || fcode == AARCH64_RSRP
> >>> +		  || fcode == AARCH64_RSR64
> >>> +		  || fcode == AARCH64_RSRF
> >>> +		  || fcode == AARCH64_RSRF64);
> >> 
> >> Instead of this, how about using:
> >> 
> >>    if (call_expr_nargs (exp) == 1)
> >> 
> >> for the read path?
> >> 
> >
> > Personally, I don't like that.  It's a `read_op' because of the fcode it 
> > has, the fact they share the same number of arguments is accidental. 
> > With this implementation, we outline very early on exactly what 
> > constitutes both a valid write and a valid read operation.
> 
> I don't agree that it's accidental. :)  But fair enough, I won't push it.

FWIW I agree with Richard that it isn't accidental that reads have one argument
and writes have two, it's an inherent property of how the operations work.
I think it would be better to use call_expr_nargs (exp) == 1 as suggested
above.

IIUC, presumably the operation must either be a read or a write so having two
separate booleans (read_op and write_op) doesn't make much sense either?

> 
> > I'm happy to change things around if you feel strongly enough about it 
> > or see some material advantage to doing things your way that I've missed :).

Thanks,
Alex

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions
  2023-10-27 13:18         ` Alex Coplan
@ 2023-10-27 13:51           ` Victor Do Nascimento
  0 siblings, 0 replies; 23+ messages in thread
From: Victor Do Nascimento @ 2023-10-27 13:51 UTC (permalink / raw)
  To: Alex Coplan, gcc-patches, kyrylo.tkachov, Richard.Earnshaw,
	richard.sandiford



On 10/27/23 14:18, Alex Coplan wrote:
> On 26/10/2023 16:23, Richard Sandiford wrote:
>> Victor Do Nascimento <Victor.DoNascimento@arm.com> writes:
>>> On 10/18/23 21:39, Richard Sandiford wrote:
>>>> Victor Do Nascimento <victor.donascimento@arm.com> writes:
>>>>> Implement the aarch64 intrinsics for reading and writing system
>>>>> registers with the following signatures:
>>>>>
>>>>> 	uint32_t __arm_rsr(const char *special_register);
>>>>> 	uint64_t __arm_rsr64(const char *special_register);
>>>>> 	void* __arm_rsrp(const char *special_register);
>>>>> 	float __arm_rsrf(const char *special_register);
>>>>> 	double __arm_rsrf64(const char *special_register);
>>>>> 	void __arm_wsr(const char *special_register, uint32_t value);
>>>>> 	void __arm_wsr64(const char *special_register, uint64_t value);
>>>>> 	void __arm_wsrp(const char *special_register, const void *value);
>>>>> 	void __arm_wsrf(const char *special_register, float value);
>>>>> 	void __arm_wsrf64(const char *special_register, double value);
>>>>>
>>>>> gcc/ChangeLog:
>>>>>
>>>>> 	* gcc/config/aarch64/aarch64-builtins.cc (enum aarch64_builtins):
>>>>> 	Add enums for new builtins.
>>>>> 	(aarch64_init_rwsr_builtins): New.
>>>>> 	(aarch64_general_init_builtins): Call aarch64_init_rwsr_builtins.
>>>>> 	(aarch64_expand_rwsr_builtin):  New.
>>>>> 	(aarch64_general_expand_builtin): Call aarch64_general_expand_builtin.
>>>>> 	* gcc/config/aarch64/aarch64.md (read_sysregdi): New insn_and_split.
>>>>> 	(write_sysregdi): Likewise.
>>>>> 	* gcc/config/aarch64/arm_acle.h (__arm_rsr): New.
>>>>> 	(__arm_rsrp): Likewise.
>>>>> 	(__arm_rsr64): Likewise.
>>>>> 	(__arm_rsrf): Likewise.
>>>>> 	(__arm_rsrf64): Likewise.
>>>>> 	(__arm_wsr): Likewise.
>>>>> 	(__arm_wsrp): Likewise.
>>>>> 	(__arm_wsr64): Likewise.
>>>>> 	(__arm_wsrf): Likewise.
>>>>> 	(__arm_wsrf64): Likewise.
>>>>>
>>>>> gcc/testsuite/ChangeLog:
>>>>>
>>>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr.c: New.
>>>>> 	* gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c: Likewise.
>>>>> ---
>>>>>    gcc/config/aarch64/aarch64-builtins.cc        | 200 ++++++++++++++++++
>>>>>    gcc/config/aarch64/aarch64.md                 |  17 ++
>>>>>    gcc/config/aarch64/arm_acle.h                 |  30 +++
>>>>>    .../gcc.target/aarch64/acle/rwsr-1.c          |  20 ++
>>>>>    gcc/testsuite/gcc.target/aarch64/acle/rwsr.c  | 144 +++++++++++++
>>>>>    5 files changed, 411 insertions(+)
>>>>>    create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr-1.c
>>>>>    create mode 100644 gcc/testsuite/gcc.target/aarch64/acle/rwsr.c
>>>>>
>>>>> diff --git a/gcc/config/aarch64/aarch64-builtins.cc b/gcc/config/aarch64/aarch64-builtins.cc
>>>>> index 04f59fd9a54..d8bb2a989a5 100644
>>>>> --- a/gcc/config/aarch64/aarch64-builtins.cc
>>>>> +++ b/gcc/config/aarch64/aarch64-builtins.cc
>>>>> @@ -808,6 +808,17 @@ enum aarch64_builtins
>>>>>      AARCH64_RBIT,
>>>>>      AARCH64_RBITL,
>>>>>      AARCH64_RBITLL,
>>>>> +  /* System register builtins.  */
>>>>> +  AARCH64_RSR,
>>>>> +  AARCH64_RSRP,
>>>>> +  AARCH64_RSR64,
>>>>> +  AARCH64_RSRF,
>>>>> +  AARCH64_RSRF64,
>>>>> +  AARCH64_WSR,
>>>>> +  AARCH64_WSRP,
>>>>> +  AARCH64_WSR64,
>>>>> +  AARCH64_WSRF,
>>>>> +  AARCH64_WSRF64,
>>>>>      AARCH64_BUILTIN_MAX
>>>>>    };
>>>>>    
>>>>> @@ -1798,6 +1809,65 @@ aarch64_init_rng_builtins (void)
>>>>>    				   AARCH64_BUILTIN_RNG_RNDRRS);
>>>>>    }
>>>>>    
>>>>> +/* Add builtins for reading system register.  */
>>>>> +static void
>>>>> +aarch64_init_rwsr_builtins (void)
>>>>> +{
>>>>> +  tree fntype = NULL;
>>>>> +  tree const_char_ptr_type
>>>>> +    = build_pointer_type (build_type_variant (char_type_node, true, false));
>>>>> +
>>>>> +#define AARCH64_INIT_RWSR_BUILTINS_DECL(F, N, T) \
>>>>> +  aarch64_builtin_decls[AARCH64_##F] \
>>>>> +    = aarch64_general_add_builtin ("__builtin_aarch64_"#N, T, AARCH64_##F);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (uint32_type_node, const_char_ptr_type, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR, rsr, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (ptr_type_node, const_char_ptr_type, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRP, rsrp, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (uint64_type_node, const_char_ptr_type, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSR64, rsr64, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (float_type_node, const_char_ptr_type, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF, rsrf, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (double_type_node, const_char_ptr_type, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (RSRF64, rsrf64, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>>> +				uint32_type_node, NULL);
>>>>> +
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR, wsr, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>>> +				const_ptr_type_node, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRP, wsrp, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>>> +				uint64_type_node, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSR64, wsr64, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>>> +				float_type_node, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF, wsrf, fntype);
>>>>> +
>>>>> +  fntype
>>>>> +    = build_function_type_list (void_type_node, const_char_ptr_type,
>>>>> +				double_type_node, NULL);
>>>>> +  AARCH64_INIT_RWSR_BUILTINS_DECL (WSRF64, wsrf64, fntype);
>>>>> +}
>>>>> +
>>>>>    /* Initialize the memory tagging extension (MTE) builtins.  */
>>>>>    struct
>>>>>    {
>>>>> @@ -2019,6 +2089,8 @@ aarch64_general_init_builtins (void)
>>>>>      aarch64_init_rng_builtins ();
>>>>>      aarch64_init_data_intrinsics ();
>>>>>    
>>>>> +  aarch64_init_rwsr_builtins ();
>>>>> +
>>>>>      tree ftype_jcvt
>>>>>        = build_function_type_list (intSI_type_node, double_type_node, NULL);
>>>>>      aarch64_builtin_decls[AARCH64_JSCVT]
>>>>> @@ -2599,6 +2671,123 @@ aarch64_expand_rng_builtin (tree exp, rtx target, int fcode, int ignore)
>>>>>      return target;
>>>>>    }
>>>>>    
>>>>> +/* Expand the read/write system register builtin EXPs.  */
>>>>> +rtx
>>>>> +aarch64_expand_rwsr_builtin (tree exp, rtx target, int fcode)
>>>>> +{
>>>>> +  tree arg0, arg1;
>>>>> +  rtx const_str, input_val, subreg;
>>>>> +  enum machine_mode mode;
>>>>> +  class expand_operand ops[2];
>>>>> +
>>>>> +  arg0 = CALL_EXPR_ARG (exp, 0);
>>>>> +
>>>>> +  bool write_op = (fcode == AARCH64_WSR
>>>>> +		   || fcode == AARCH64_WSRP
>>>>> +		   || fcode == AARCH64_WSR64
>>>>> +		   || fcode == AARCH64_WSRF
>>>>> +		   || fcode == AARCH64_WSRF64);
>>>>> +  bool read_op = (fcode == AARCH64_RSR
>>>>> +		  || fcode == AARCH64_RSRP
>>>>> +		  || fcode == AARCH64_RSR64
>>>>> +		  || fcode == AARCH64_RSRF
>>>>> +		  || fcode == AARCH64_RSRF64);
>>>>
>>>> Instead of this, how about using:
>>>>
>>>>     if (call_expr_nargs (exp) == 1)
>>>>
>>>> for the read path?
>>>>
>>>
>>> Personally, I don't like that.  It's a `read_op' because of the fcode it
>>> has, the fact they share the same number of arguments is accidental.
>>> With this implementation, we outline very early on exactly what
>>> constitutes both a valid write and a valid read operation.
>>
>> I don't agree that it's accidental. :)  But fair enough, I won't push it.
> 
> FWIW I agree with Richard that it isn't accidental that reads have one argument
> and writes have two, it's an inherent property of how the operations work.
> I think it would be better to use call_expr_nargs (exp) == 1 as suggested
> above.
> 

For the record, I do mean accidental in the "subsidiary" sense of the 
word, if that makes sense.  They are primarily RSR operations associated 
with the mrs instruction.  The number of args simply follows on from 
this fact.

If in some hypothetical scenario, another single-operand expression was 
to make it to `aarch64_expand_rwsr_builtin' with an fcode not covered by 
those in `read_op', being single-operand alone wouldn't be a strong 
enough condition for it to be classified a "read system register" operation.

That's the scenario that is guarded against by Richard's comment a 
little further down:

"If we do go for my:

   call_expr_nargs (exp) == 1

suggestion above, this switch should probably have a:
this switch should probably have a:

   default:
     gcc_unreachable ();"

> IIUC, presumably the operation must either be a read or a write so having two
> separate booleans (read_op and write_op) doesn't make much sense either?
>

In all fairness, you're 100% right here and I had thought about this in 
the past.  Assuming no stray fcode makes it into this function, read_op 
is just !write_op.  I did things this way to be nice and explicit early 
on abouut what consistutes a valid read operation.

Happy to simplify.

Cheers,
V.

>>
>>> I'm happy to change things around if you feel strongly enough about it
>>> or see some material advantage to doing things your way that I've missed :).
> 
> Thanks,
> Alex

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2023-10-27 13:51 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-18 15:02 [PATCH V2 0/7] aarch64: Add support for __arm_rsr and __arm_wsr ACLE function family Victor Do Nascimento
2023-10-18 15:02 ` [PATCH V2 1/7] aarch64: Sync system register information with Binutils Victor Do Nascimento
2023-10-18 15:02 ` [PATCH V2 2/7] aarch64: Add support for aarch64-sys-regs.def Victor Do Nascimento
2023-10-18 21:07   ` Richard Sandiford
2023-10-26 14:48     ` Victor Do Nascimento
2023-10-26 15:14       ` Richard Sandiford
2023-10-18 15:02 ` [PATCH V2 3/7] aarch64: Implement system register validation tools Victor Do Nascimento
2023-10-18 19:07   ` Richard Sandiford
2023-10-18 15:02 ` [PATCH V2 4/7] aarch64: Add basic target_print_operand support for CONST_STRING Victor Do Nascimento
2023-10-18 21:09   ` Richard Sandiford
2023-10-18 15:02 ` [PATCH V2 5/7] aarch64: Implement system register r/w arm ACLE intrinsic functions Victor Do Nascimento
2023-10-18 20:39   ` Richard Sandiford
2023-10-26 15:06     ` Victor Do Nascimento
2023-10-26 15:23       ` Richard Sandiford
2023-10-26 15:56         ` Victor Do Nascimento
2023-10-27 13:18         ` Alex Coplan
2023-10-27 13:51           ` Victor Do Nascimento
2023-10-18 15:02 ` [PATCH V2 6/7] aarch64: Add front-end argument type checking for target builtins Victor Do Nascimento
2023-10-18 21:20   ` Richard Sandiford
2023-10-18 15:02 ` [PATCH V2 7/7] aarch64: Add system register duplication check selftest Victor Do Nascimento
2023-10-18 21:30   ` Richard Sandiford
2023-10-26 15:13     ` Victor Do Nascimento
2023-10-26 15:31       ` Richard Sandiford

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).