[PATCH v2 1/3] aarch64: Add support for POE2 instructions.

Srinath Parvathaneni srinath.parvathaneni@arm.com
Fri Dec 5 10:57:02 GMT 2025
This patch adds support for FEAT_S1POE2 feature enabled by "+poe2"
flag along with support for following instructions.

* TCHANGEB (immediate)
* TCHANGEB (register)
* TCHANGEF (immediate)
* TCHANGEF (register)

A new operand AARCH64_OPND_NOT_BALANCED is added to the code in this
patch to support the new optional argument "NB" (not_balanced) which
is a 1-bit field in the encoding for all the above mentioned
instructions.

Regression tested for aarch64-none-elf target and found no regressions.

Ok for binutils-master?

Regards,
Srinath

Co-authored-by:  Matthew Malcomson <matthew.malcomson@arm.com>
---
 gas/config/tc-aarch64.c                    | 29 ++++++++
 gas/doc/c-aarch64.texi                     |  2 +
 gas/testsuite/gas/aarch64/poe2-invalid-1.d |  4 ++
 gas/testsuite/gas/aarch64/poe2-invalid-1.l | 63 ++++++++++++++++++
 gas/testsuite/gas/aarch64/poe2-invalid-1.s | 77 ++++++++++++++++++++++
 gas/testsuite/gas/aarch64/poe2-invalid-2.d |  4 ++
 gas/testsuite/gas/aarch64/poe2-invalid-2.l | 61 +++++++++++++++++
 gas/testsuite/gas/aarch64/poe2.d           | 69 +++++++++++++++++++
 gas/testsuite/gas/aarch64/poe2.s           | 75 +++++++++++++++++++++
 include/opcode/aarch64.h                   |  5 ++
 opcodes/aarch64-asm-2.c                    |  1 +
 opcodes/aarch64-dis-2.c                    | 69 +++++++++++++++----
 opcodes/aarch64-opc-2.c                    |  1 +
 opcodes/aarch64-opc.c                      | 11 ++++
 opcodes/aarch64-opc.h                      |  1 +
 opcodes/aarch64-tbl-2.h                    |  4 ++
 opcodes/aarch64-tbl.h                      | 20 ++++++
 17 files changed, 482 insertions(+), 14 deletions(-)
 create mode 100644 gas/testsuite/gas/aarch64/poe2-invalid-1.d
 create mode 100644 gas/testsuite/gas/aarch64/poe2-invalid-1.l
 create mode 100644 gas/testsuite/gas/aarch64/poe2-invalid-1.s
 create mode 100644 gas/testsuite/gas/aarch64/poe2-invalid-2.d
 create mode 100644 gas/testsuite/gas/aarch64/poe2-invalid-2.l
 create mode 100644 gas/testsuite/gas/aarch64/poe2.d
 create mode 100644 gas/testsuite/gas/aarch64/poe2.s

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 0ca54c3bd40..5eae44b1b8a 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -6441,6 +6441,10 @@ process_omitted_operand (enum aarch64_opnd type, const aarch64_opcode *opcode,
       operand->hint_option = aarch64_hint_options + default_value;
       break;
 
+    case AARCH64_OPND_NOT_BALANCED:
+      operand->imm.value = default_value;
+      break;
+
     default:
       break;
     }
@@ -8173,6 +8177,20 @@ parse_operands (char *str, const aarch64_opcode *opcode)
 	  info->barrier = aarch64_barrier_dsb_nxs_options + val;
 	  break;
 
+	case AARCH64_OPND_NOT_BALANCED:
+	  val = parse_barrier (&str);
+	  if (val != PARSE_FAIL)
+	    info->imm.value = val;
+	  else
+	    {
+	      set_syntax_error (_("the specified operand is not accepted in"
+				  " TCHANGE instruction"));
+	      /* Turn off backtrack as this optional operand is present.  */
+	      backtrack_pos = 0;
+	      goto failure;
+	    }
+	  break;
+
 	case AARCH64_OPND_PRFOP:
 	  val = parse_pldop (&str);
 
@@ -10512,6 +10530,16 @@ md_begin (void)
 	}
     }
 
+  for (i = 0; i < ARRAY_SIZE (aarch64_nb_options); i++)
+    {
+      const char *name = aarch64_nb_options[i].name;
+      checked_hash_insert (aarch64_barrier_opt_hsh, name,
+			   aarch64_nb_options + i);
+      /* Also hash the name in the upper case.  */
+      checked_hash_insert (aarch64_barrier_opt_hsh, get_upper_str (name),
+			   aarch64_nb_options + i);
+    }
+
   for (i = 0; i < ARRAY_SIZE (aarch64_barrier_options); i++)
     {
       const char *name = aarch64_barrier_options[i].name;
@@ -10818,6 +10846,7 @@ static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"sb",		AARCH64_FEATURE (SB), AARCH64_NO_FEATURES},
   {"predres",		AARCH64_FEATURE (PREDRES), AARCH64_NO_FEATURES},
   {"predres2",		AARCH64_FEATURE (PREDRES2), AARCH64_FEATURE (PREDRES)},
+  {"poe2",		AARCH64_FEATURE (S1POE2), AARCH64_NO_FEATURES},
   {"aes",		AARCH64_FEATURE (AES), AARCH64_FEATURE (SIMD)},
   {"sm4",		AARCH64_FEATURE (SM4), AARCH64_FEATURE (SIMD)},
   {"sha3",		AARCH64_FEATURE (SHA3), AARCH64_FEATURE (SHA2)},
diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
index 9683d411ce9..2064d22706b 100644
--- a/gas/doc/c-aarch64.texi
+++ b/gas/doc/c-aarch64.texi
@@ -267,6 +267,8 @@ automatically cause those extensions to be disabled.
  @tab Enable additional prediction restriction instructions.
 @item @code{profile} @tab
  @tab Enable statistical profiling extensions.
+@item @code{poe2} @tab
+ @tab Enable Permission overlays extension 2.
 @item @code{ras} @tab
  @tab Enable the Reliability, Availability and Serviceability extension.
 @item @code{rasv2} @tab @code{ras}
diff --git a/gas/testsuite/gas/aarch64/poe2-invalid-1.d b/gas/testsuite/gas/aarch64/poe2-invalid-1.d
new file mode 100644
index 00000000000..7aa529ce244
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2-invalid-1.d
@@ -0,0 +1,4 @@
+#name: Invalid poe2 TCHANGE instructions.
+#source: poe2-invalid-1.s
+#as: -march=armv8-a+poe2
+#error_output: poe2-invalid-1.l
diff --git a/gas/testsuite/gas/aarch64/poe2-invalid-1.l b/gas/testsuite/gas/aarch64/poe2-invalid-1.l
new file mode 100644
index 00000000000..df536613fde
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2-invalid-1.l
@@ -0,0 +1,63 @@
+.*: Assembler messages:
+.*: Error: constant expression required at operand 2 -- `tchangef x0,x31'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef x31,x3'
+.*: Error: comma expected between operands at operand 2 -- `tchangef x7'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x15,x30,'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x30,x0,x10'
+.*: Error: comma expected between operands at operand 2 -- `tchangef x10 x0'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef #1,#100'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef #10,x0'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x0,x1,nbb'
+.*: Error: comma expected between operands at operand 3 -- `tchangef x1,x3 nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x3,x7,n'
+.*: Error: unexpected characters following instruction at operand 3 -- `tchangef x7,x15,nb,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x15,x30,Nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x30,x0,nB'
+.*: Error: constant expression required at operand 2 -- `tchangef x10,NB,NB'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef NB,x10,NB'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangef x0,#-10'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangef x0,#128'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangef x1,#3111'
+.*: Error: missing immediate expression at operand 2 -- `tchangef x3,#'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef x31,#15'
+.*: Error: constant expression required at operand 2 -- `tchangef x10,nb,#127'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangef x0,#-10,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x0,#1,nB'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x1,#3,Nb'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangef x3,#777,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangef x7,#15,nbb'
+.*: Error: comma expected between operands at operand 3 -- `tchangef x15,#31 NB'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef x31,#63,nb'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangef NB,x10,#127'
+.*: Error: constant expression required at operand 2 -- `tchangef x10,NB,#128'
+.*: Error: constant expression required at operand 2 -- `tchangeb x0,x31'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb x31,x3'
+.*: Error: comma expected between operands at operand 2 -- `tchangeb x7'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x15,x30,'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x30,x0,x10'
+.*: Error: comma expected between operands at operand 2 -- `tchangeb x10 x0'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb #1,#100'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb #10,x0'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x0,x1,nbb'
+.*: Error: comma expected between operands at operand 3 -- `tchangeb x1,x3 nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x3,x7,n'
+.*: Error: unexpected characters following instruction at operand 3 -- `tchangeb x7,x15,nb,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x15,x30,Nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x30,x0,nB'
+.*: Error: constant expression required at operand 2 -- `tchangeb x10,NB,NB'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb NB,x10,NB'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangeb x0,#-10'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangeb x0,#128'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangeb x1,#3111'
+.*: Error: missing immediate expression at operand 2 -- `tchangeb x3,#'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb x31,#15'
+.*: Error: constant expression required at operand 2 -- `tchangeb x10,nb,#127'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangeb x0,#-10,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x0,#1,nB'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x1,#3,Nb'
+.*: Error: immediate value out of range 0 to 127 at operand 2 -- `tchangeb x3,#777,nb'
+.*: Error: the specified operand is not accepted in TCHANGE instruction at operand 3 -- `tchangeb x7,#15,nbb'
+.*: Error: comma expected between operands at operand 3 -- `tchangeb x15,#31 NB'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb x31,#63,nb'
+.*: Error: expected an integer or zero register at operand 1 -- `tchangeb NB,x10,#127'
+.*: Error: constant expression required at operand 2 -- `tchangeb x10,NB,#128'
diff --git a/gas/testsuite/gas/aarch64/poe2-invalid-1.s b/gas/testsuite/gas/aarch64/poe2-invalid-1.s
new file mode 100644
index 00000000000..8c214466b52
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2-invalid-1.s
@@ -0,0 +1,77 @@
+#TCHANGEF (register) instructions
+	tchangef x0, x31
+        tchangef x31, x3
+        tchangef x7
+        tchangef x15, x30,
+        tchangef x30, x0, x10
+	tchangef x10 x0
+	tchangef #1, #100
+	tchangef #10, x0
+
+#TCHANGEF (register) instructions with not_balanced
+        tchangef x0, x1, nbb
+        tchangef x1, x3 nb
+        tchangef x3, x7, n
+        tchangef x7, x15, nb, nb
+        tchangef x15, x30, Nb
+        tchangef x30, x0, nB
+	tchangef x10, NB, NB
+	tchangef NB, x10, NB
+
+#TCHANGEF (immediate) instructions
+        tchangef x0, #-10
+        tchangef x0, #128
+        tchangef x1, #3111
+        tchangef x3, #
+        tchangef x31, #15
+	tchangef x10, nb, #127
+
+#TCHANGEF (immediate) instructions with not_balanced
+        tchangef x0, #-10, nb
+        tchangef x0, #1, nB
+        tchangef x1, #3, Nb
+        tchangef x3, #777, nb
+        tchangef x7, #15, nbb
+        tchangef x15, #31 NB
+        tchangef x31, #63, nb
+	tchangef NB, x10, #127
+	tchangef x10, NB, #128
+
+#TCHANGEB (register) instructions
+	tchangeb x0, x31
+        tchangeb x31, x3
+        tchangeb x7
+        tchangeb x15, x30,
+        tchangeb x30, x0, x10
+	tchangeb x10 x0
+	tchangeb #1, #100
+	tchangeb #10, x0
+
+#TCHANGEB (register) instructions with not_balanced
+        tchangeb x0, x1, nbb
+        tchangeb x1, x3 nb
+        tchangeb x3, x7, n
+        tchangeb x7, x15, nb, nb
+        tchangeb x15, x30, Nb
+        tchangeb x30, x0, nB
+	tchangeb x10, NB, NB
+	tchangeb NB, x10, NB
+
+#TCHANGEB (immediate) instructions
+        tchangeb x0, #-10
+        tchangeb x0, #128
+        tchangeb x1, #3111
+        tchangeb x3, #
+        tchangeb x31, #15
+	tchangeb x10, nb, #127
+
+#TCHANGEB (immediate) instructions with not_balanced
+        tchangeb x0, #-10, nb
+        tchangeb x0, #1, nB
+        tchangeb x1, #3, Nb
+        tchangeb x3, #777, nb
+        tchangeb x7, #15, nbb
+        tchangeb x15, #31 NB
+        tchangeb x31, #63, nb
+	tchangeb NB, x10, #127
+	tchangeb x10, NB, #128
diff --git a/gas/testsuite/gas/aarch64/poe2-invalid-2.d b/gas/testsuite/gas/aarch64/poe2-invalid-2.d
new file mode 100644
index 00000000000..e6ac680b2a3
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2-invalid-2.d
@@ -0,0 +1,4 @@
+#name: TCHANGE instructions without +poe2 flag.
+#source: poe2.s
+#as: -march=armv8-a
+#error_output: poe2-invalid-2.l
diff --git a/gas/testsuite/gas/aarch64/poe2-invalid-2.l b/gas/testsuite/gas/aarch64/poe2-invalid-2.l
new file mode 100644
index 00000000000..c88442521be
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2-invalid-2.l
@@ -0,0 +1,61 @@
+.*: Assembler messages:
+.*: Error: selected processor does not support `tchangef x0,x1'
+.*: Error: selected processor does not support `tchangef x1,x3'
+.*: Error: selected processor does not support `tchangef x3,x7'
+.*: Error: selected processor does not support `tchangef x7,x15'
+.*: Error: selected processor does not support `tchangef x15,x30'
+.*: Error: selected processor does not support `tchangef x30,x0'
+.*: Error: selected processor does not support `tchangef x10,x5'
+.*: Error: selected processor does not support `tchangef x0,x1,nb'
+.*: Error: selected processor does not support `tchangef x1,x3,nb'
+.*: Error: selected processor does not support `tchangef x3,x7,nb'
+.*: Error: selected processor does not support `tchangef x7,x15,nb'
+.*: Error: selected processor does not support `tchangef x15,x30,NB'
+.*: Error: selected processor does not support `tchangef x30,x0,nb'
+.*: Error: selected processor does not support `tchangef x10,x5,NB'
+.*: Error: selected processor does not support `tchangef x0,#0'
+.*: Error: selected processor does not support `tchangef x0,#1'
+.*: Error: selected processor does not support `tchangef x1,#3'
+.*: Error: selected processor does not support `tchangef x3,#7'
+.*: Error: selected processor does not support `tchangef x7,#15'
+.*: Error: selected processor does not support `tchangef x15,#31'
+.*: Error: selected processor does not support `tchangef x30,#63'
+.*: Error: selected processor does not support `tchangef x10,#127'
+.*: Error: selected processor does not support `tchangef x0,#0,nb'
+.*: Error: selected processor does not support `tchangef x0,#1,nb'
+.*: Error: selected processor does not support `tchangef x1,#3,nb'
+.*: Error: selected processor does not support `tchangef x3,#7,nb'
+.*: Error: selected processor does not support `tchangef x7,#15,nb'
+.*: Error: selected processor does not support `tchangef x15,#31,NB'
+.*: Error: selected processor does not support `tchangef x30,#63,nb'
+.*: Error: selected processor does not support `tchangef x10,#127,NB'
+.*: Error: selected processor does not support `tchangeb x0,x1'
+.*: Error: selected processor does not support `tchangeb x1,x3'
+.*: Error: selected processor does not support `tchangeb x3,x7'
+.*: Error: selected processor does not support `tchangeb x7,x15'
+.*: Error: selected processor does not support `tchangeb x15,x30'
+.*: Error: selected processor does not support `tchangeb x30,x0'
+.*: Error: selected processor does not support `tchangeb x10,x5'
+.*: Error: selected processor does not support `tchangeb x0,x1,nb'
+.*: Error: selected processor does not support `tchangeb x1,x3,nb'
+.*: Error: selected processor does not support `tchangeb x3,x7,nb'
+.*: Error: selected processor does not support `tchangeb x7,x15,nb'
+.*: Error: selected processor does not support `tchangeb x15,x30,NB'
+.*: Error: selected processor does not support `tchangeb x30,x0,nb'
+.*: Error: selected processor does not support `tchangeb x10,x5,NB'
+.*: Error: selected processor does not support `tchangeb x0,#0'
+.*: Error: selected processor does not support `tchangeb x0,#1'
+.*: Error: selected processor does not support `tchangeb x1,#3'
+.*: Error: selected processor does not support `tchangeb x3,#7'
+.*: Error: selected processor does not support `tchangeb x7,#15'
+.*: Error: selected processor does not support `tchangeb x15,#31'
+.*: Error: selected processor does not support `tchangeb x30,#63'
+.*: Error: selected processor does not support `tchangeb x10,#127'
+.*: Error: selected processor does not support `tchangeb x0,#0,nb'
+.*: Error: selected processor does not support `tchangeb x0,#1,nb'
+.*: Error: selected processor does not support `tchangeb x1,#3,nb'
+.*: Error: selected processor does not support `tchangeb x3,#7,nb'
+.*: Error: selected processor does not support `tchangeb x7,#15,nb'
+.*: Error: selected processor does not support `tchangeb x15,#31,NB'
+.*: Error: selected processor does not support `tchangeb x30,#63,nb'
+.*: Error: selected processor does not support `tchangeb x10,#127,NB'
diff --git a/gas/testsuite/gas/aarch64/poe2.d b/gas/testsuite/gas/aarch64/poe2.d
new file mode 100644
index 00000000000..709565729e1
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2.d
@@ -0,0 +1,69 @@
+#objdump: -dr
+#as: -march=armv8-a+poe2
+
+[^:]+:     file format .*
+
+
+[^:]+:
+
+[^:]+:
+.*:	d5800020 	tchangef	x0, x1
+.*:	d5800061 	tchangef	x1, x3
+.*:	d58000e3 	tchangef	x3, x7
+.*:	d58001e7 	tchangef	x7, x15
+.*:	d58003cf 	tchangef	x15, x30
+.*:	d580001e 	tchangef	x30, x0
+.*:	d58000aa 	tchangef	x10, x5
+.*:	d5820020 	tchangef	x0, x1, nb
+.*:	d5820061 	tchangef	x1, x3, nb
+.*:	d58200e3 	tchangef	x3, x7, nb
+.*:	d58201e7 	tchangef	x7, x15, nb
+.*:	d58203cf 	tchangef	x15, x30, nb
+.*:	d582001e 	tchangef	x30, x0, nb
+.*:	d58200aa 	tchangef	x10, x5, nb
+.*:	d5900000 	tchangef	x0, #0x0
+.*:	d5900020 	tchangef	x0, #0x1
+.*:	d5900061 	tchangef	x1, #0x3
+.*:	d59000e3 	tchangef	x3, #0x7
+.*:	d59001e7 	tchangef	x7, #0xf
+.*:	d59003ef 	tchangef	x15, #0x1f
+.*:	d59007fe 	tchangef	x30, #0x3f
+.*:	d5900fea 	tchangef	x10, #0x7f
+.*:	d5920000 	tchangef	x0, #0x0, nb
+.*:	d5920020 	tchangef	x0, #0x1, nb
+.*:	d5920061 	tchangef	x1, #0x3, nb
+.*:	d59200e3 	tchangef	x3, #0x7, nb
+.*:	d59201e7 	tchangef	x7, #0xf, nb
+.*:	d59203ef 	tchangef	x15, #0x1f, nb
+.*:	d59207fe 	tchangef	x30, #0x3f, nb
+.*:	d5920fea 	tchangef	x10, #0x7f, nb
+.*:	d5840020 	tchangeb	x0, x1
+.*:	d5840061 	tchangeb	x1, x3
+.*:	d58400e3 	tchangeb	x3, x7
+.*:	d58401e7 	tchangeb	x7, x15
+.*:	d58403cf 	tchangeb	x15, x30
+.*:	d584001e 	tchangeb	x30, x0
+.*:	d58400aa 	tchangeb	x10, x5
+.*:	d5860020 	tchangeb	x0, x1, nb
+.*:	d5860061 	tchangeb	x1, x3, nb
+.*:	d58600e3 	tchangeb	x3, x7, nb
+.*:	d58601e7 	tchangeb	x7, x15, nb
+.*:	d58603cf 	tchangeb	x15, x30, nb
+.*:	d586001e 	tchangeb	x30, x0, nb
+.*:	d58600aa 	tchangeb	x10, x5, nb
+.*:	d5940000 	tchangeb	x0, #0x0
+.*:	d5940020 	tchangeb	x0, #0x1
+.*:	d5940061 	tchangeb	x1, #0x3
+.*:	d59400e3 	tchangeb	x3, #0x7
+.*:	d59401e7 	tchangeb	x7, #0xf
+.*:	d59403ef 	tchangeb	x15, #0x1f
+.*:	d59407fe 	tchangeb	x30, #0x3f
+.*:	d5940fea 	tchangeb	x10, #0x7f
+.*:	d5960000 	tchangeb	x0, #0x0, nb
+.*:	d5960020 	tchangeb	x0, #0x1, nb
+.*:	d5960061 	tchangeb	x1, #0x3, nb
+.*:	d59600e3 	tchangeb	x3, #0x7, nb
+.*:	d59601e7 	tchangeb	x7, #0xf, nb
+.*:	d59603ef 	tchangeb	x15, #0x1f, nb
+.*:	d59607fe 	tchangeb	x30, #0x3f, nb
+.*:	d5960fea 	tchangeb	x10, #0x7f, nb
diff --git a/gas/testsuite/gas/aarch64/poe2.s b/gas/testsuite/gas/aarch64/poe2.s
new file mode 100644
index 00000000000..3b9353c5c98
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/poe2.s
@@ -0,0 +1,75 @@
+#TCHANGEF (register) instructions
+        tchangef x0, x1
+        tchangef x1, x3
+        tchangef x3, x7
+        tchangef x7, x15
+        tchangef x15, x30
+        tchangef x30, x0
+	tchangef x10, x5
+
+#TCHANGEF (register) instructions with not_balanced
+        tchangef x0, x1, nb
+        tchangef x1, x3, nb
+        tchangef x3, x7, nb
+        tchangef x7, x15, nb
+        tchangef x15, x30, NB
+        tchangef x30, x0, nb
+	tchangef x10, x5, NB
+
+#TCHANGEF (immediate) instructions
+        tchangef x0, #0
+        tchangef x0, #1
+        tchangef x1, #3
+        tchangef x3, #7
+        tchangef x7, #15
+        tchangef x15, #31
+        tchangef x30, #63
+	tchangef x10, #127
+
+#TCHANGEF (immediate) instructions with not_balanced
+        tchangef x0, #0, nb
+        tchangef x0, #1, nb
+        tchangef x1, #3, nb
+        tchangef x3, #7, nb
+        tchangef x7, #15, nb
+        tchangef x15, #31, NB
+        tchangef x30, #63, nb
+	tchangef x10, #127, NB
+
+#TCHANGEB (register) instructions
+        tchangeb x0, x1
+        tchangeb x1, x3
+        tchangeb x3, x7
+        tchangeb x7, x15
+        tchangeb x15, x30
+        tchangeb x30, x0
+	tchangeb x10, x5
+
+#TCHANGEB (register) instructions with not_balanced
+        tchangeb x0, x1, nb
+        tchangeb x1, x3, nb
+        tchangeb x3, x7, nb
+        tchangeb x7, x15, nb
+        tchangeb x15, x30, NB
+        tchangeb x30, x0, nb
+	tchangeb x10, x5, NB
+
+#TCHANGEB (immediate) instructions
+        tchangeb x0, #0
+        tchangeb x0, #1
+        tchangeb x1, #3
+        tchangeb x3, #7
+        tchangeb x7, #15
+        tchangeb x15, #31
+        tchangeb x30, #63
+	tchangeb x10, #127
+
+#TCHANGEB (immediate) instructions with not_balanced
+        tchangeb x0, #0, nb
+        tchangeb x0, #1, nb
+        tchangeb x1, #3, nb
+        tchangeb x3, #7, nb
+        tchangeb x7, #15, nb
+        tchangeb x15, #31, NB
+        tchangeb x30, #63, nb
+	tchangeb x10, #127, NB
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index 68a181c531f..e7c6ed601b1 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -263,6 +263,8 @@ enum aarch64_feature_bit {
   AARCH64_FEATURE_SME_TMOP,
   /* SME MOP4 instructions.  */
   AARCH64_FEATURE_SME_MOP4,
+  /* POE2 instructions.  */
+  AARCH64_FEATURE_S1POE2,
 
   /* Virtual features.  These are used to gate instructions that are enabled
      by either of two (or more) sets of command line flags.  */
@@ -673,6 +675,7 @@ enum aarch64_opnd
   AARCH64_OPND_UNDEFINED,/* imm16 operand in undefined instruction. */
   AARCH64_OPND_CCMP_IMM,/* Immediate in conditional compare instructions.  */
   AARCH64_OPND_SIMM5,	/* 5-bit signed immediate in the imm5 field.  */
+  AARCH64_OPND_NOT_BALANCED, /* a 1-bit not_balanced optional operand.  */ 
   AARCH64_OPND_NZCV,	/* Flag bit specifier giving an alternative value for
 			   each condition flag.  */
 
@@ -1132,6 +1135,7 @@ enum aarch64_insn_class
   lse128_atomic,
   movewide,
   pcreladdr,
+  s1poe2,
   ic_system,
   sme_fp_sd,
   sme_int_sd,
@@ -1599,6 +1603,7 @@ struct aarch64_name_value_pair
 };
 
 extern const struct aarch64_name_value_pair aarch64_operand_modifiers [];
+extern const struct aarch64_name_value_pair aarch64_nb_options [1];
 extern const struct aarch64_name_value_pair aarch64_barrier_options [16];
 extern const struct aarch64_name_value_pair aarch64_barrier_dsb_nxs_options [4];
 extern const struct aarch64_name_value_pair aarch64_prfops [32];
diff --git a/opcodes/aarch64-asm-2.c b/opcodes/aarch64-asm-2.c
index b0611654ead..c93447742f8 100644
--- a/opcodes/aarch64-asm-2.c
+++ b/opcodes/aarch64-asm-2.c
@@ -930,6 +930,7 @@ aarch64_insert_operand (const aarch64_operand *self,
     case AARCH64_OPND_UNDEFINED:
     case AARCH64_OPND_CCMP_IMM:
     case AARCH64_OPND_SIMM5:
+    case AARCH64_OPND_NOT_BALANCED:
     case AARCH64_OPND_NZCV:
     case AARCH64_OPND_ADDR_PCREL9:
     case AARCH64_OPND_ADDR_PCREL14:
diff --git a/opcodes/aarch64-dis-2.c b/opcodes/aarch64-dis-2.c
index ecaea2d2fdb..657e1ec4f37 100644
--- a/opcodes/aarch64-dis-2.c
+++ b/opcodes/aarch64-dis-2.c
@@ -26541,28 +26541,68 @@ aarch64_opcode_lookup_1 (uint32_t word)
                             {
                               if (((word >> 22) & 0x1) == 0)
                                 {
-                                  if (((word >> 25) & 0x1) == 0)
+                                  if (((word >> 23) & 0x1) == 0)
                                     {
-                                      /* 33222222222211111111110000000000
-                                         10987654321098765432109876543210
-                                         x1010101x00xxxxxxxxxxxxxxxxxxxxx.  */
-                                      return A64_OPID_d500403f_xaflag;
+                                      if (((word >> 25) & 0x1) == 0)
+                                        {
+                                          /* 33222222222211111111110000000000
+                                             10987654321098765432109876543210
+                                             x1010101000xxxxxxxxxxxxxxxxxxxxx.  */
+                                          return A64_OPID_d500403f_xaflag;
+                                        }
+                                      else
+                                        {
+                                          if (((word >> 10) & 0x1) == 0)
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x1010111000xxxxxxxxxx0xxxxxxxxxx.  */
+                                              return A64_OPID_d71f0800_braa_Rn_Rd_SP;
+                                            }
+                                          else
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x1010111000xxxxxxxxxx1xxxxxxxxxx.  */
+                                              return A64_OPID_d71f0c00_brab_Rn_Rd_SP;
+                                            }
+                                        }
                                     }
                                   else
                                     {
-                                      if (((word >> 10) & 0x1) == 0)
+                                      if (((word >> 18) & 0x1) == 0)
                                         {
-                                          /* 33222222222211111111110000000000
-                                             10987654321098765432109876543210
-                                             x1010111x00xxxxxxxxxx0xxxxxxxxxx.  */
-                                          return A64_OPID_d71f0800_braa_Rn_Rd_SP;
+                                          if (((word >> 20) & 0x1) == 0)
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x10101x11000x0xxxxxxxxxxxxxxxxxx.  */
+                                              return A64_OPID_d5800000_tchangef_Rd_Rn_NOT_BALANCED;
+                                            }
+                                          else
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x10101x11001x0xxxxxxxxxxxxxxxxxx.  */
+                                              return A64_OPID_d5900000_tchangef_Rd_UIMM7_NOT_BALANCED;
+                                            }
                                         }
                                       else
                                         {
-                                          /* 33222222222211111111110000000000
-                                             10987654321098765432109876543210
-                                             x1010111x00xxxxxxxxxx1xxxxxxxxxx.  */
-                                          return A64_OPID_d71f0c00_brab_Rn_Rd_SP;
+                                          if (((word >> 20) & 0x1) == 0)
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x10101x11000x1xxxxxxxxxxxxxxxxxx.  */
+                                              return A64_OPID_d5840000_tchangeb_Rd_Rn_NOT_BALANCED;
+                                            }
+                                          else
+                                            {
+                                              /* 33222222222211111111110000000000
+                                                 10987654321098765432109876543210
+                                                 x10101x11001x1xxxxxxxxxxxxxxxxxx.  */
+                                              return A64_OPID_d5940000_tchangeb_Rd_UIMM7_NOT_BALANCED;
+                                            }
                                         }
                                     }
                                 }
@@ -37357,6 +37397,7 @@ aarch64_extract_operand (const aarch64_operand *self,
     case AARCH64_OPND_UNDEFINED:
     case AARCH64_OPND_CCMP_IMM:
     case AARCH64_OPND_SIMM5:
+    case AARCH64_OPND_NOT_BALANCED:
     case AARCH64_OPND_NZCV:
     case AARCH64_OPND_ADDR_ADRP:
     case AARCH64_OPND_ADDR_PCREL9:
diff --git a/opcodes/aarch64-opc-2.c b/opcodes/aarch64-opc-2.c
index 7f3b25eae38..fc88fe82ed3 100644
--- a/opcodes/aarch64-opc-2.c
+++ b/opcodes/aarch64-opc-2.c
@@ -104,6 +104,7 @@ const struct aarch64_operand aarch64_operands[] =
   {AARCH64_OPND_CLASS_IMMEDIATE, "UNDEFINED", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm16_0}, "a 16-bit unsigned immediate"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "CCMP_IMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm5}, "a 5-bit unsigned immediate"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "SIMM5", OPD_F_SEXT | OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm5}, "a 5-bit signed immediate"},
+  {AARCH64_OPND_CLASS_IMMEDIATE, "NOT_BALANCED", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_imm1_17}, "a 1-bit not_balanced optional operand"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "NZCV", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_nzcv}, "a flag bit specifier giving an alternative value for each flag"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "LIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_N,FLD_immr,FLD_imms}, "Logical immediate"},
   {AARCH64_OPND_CLASS_IMMEDIATE, "AIMM", OPD_F_HAS_INSERTER | OPD_F_HAS_EXTRACTOR, {FLD_shift,FLD_imm12}, "a 12-bit unsigned immediate with optional left shift of 12 bits"},
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index c501b9b35e5..623fd7a4272 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -361,6 +361,7 @@ const aarch64_field aarch64_fields[] =
     AARCH64_FIELD (14, 1), /* imm1_14: general immediate in bits [14].  */
     AARCH64_FIELD (15, 1), /* imm1_15: general immediate in bits [15].  */
     AARCH64_FIELD (16, 1), /* imm1_16: general immediate in bits [16].  */
+    AARCH64_FIELD (17, 1), /* imm1_17: op1[0] in the TCHANGE instruction.  */
     AARCH64_FIELD ( 0, 2), /* imm2_0: general immediate in bits [1:0].  */
     AARCH64_FIELD ( 1, 2), /* imm2_1: general immediate in bits [2:1].  */
     AARCH64_FIELD ( 2, 2), /* imm2_2: general immediate in bits [3:2].  */
@@ -559,6 +560,11 @@ aarch64_shift_operator_p (enum aarch64_modifier_kind kind)
   return kind >= AARCH64_MOD_ROR && kind <= AARCH64_MOD_LSL;
 }
 
+const struct aarch64_name_value_pair aarch64_nb_options[1] =
+{
+    { "nb", 1 },
+};
+
 const struct aarch64_name_value_pair aarch64_barrier_options[16] =
 {
     { "#0x00", 0x0 },
@@ -5153,6 +5159,11 @@ aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
       snprintf (buf, size, "%s", style_sub_mnem (styler, "dsync"));
       break;
 
+    case AARCH64_OPND_NOT_BALANCED:
+      if (opnd->imm.value)
+	snprintf (buf, size, "%s", style_sub_mnem (styler, "nb"));
+      break;
+
     case AARCH64_OPND_BTI_TARGET:
       if ((HINT_FLAG (opnd->hint_option->value) & HINT_OPD_F_NOPRINT) == 0)
 	snprintf (buf, size, "%s",
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 5d544d53baf..376aacb8312 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -165,6 +165,7 @@ enum aarch64_field_kind
   FLD_imm1_14,
   FLD_imm1_15,
   FLD_imm1_16,
+  FLD_imm1_17,
   FLD_imm2_0,
   FLD_imm2_1,
   FLD_imm2_2,
diff --git a/opcodes/aarch64-tbl-2.h b/opcodes/aarch64-tbl-2.h
index 1263f1f9bd8..16b3448c828 100644
--- a/opcodes/aarch64-tbl-2.h
+++ b/opcodes/aarch64-tbl-2.h
@@ -3995,5 +3995,9 @@ enum aarch64_opcode_idx
   A64_OPID_a1c00018_usmop4s_SME_ZAda_3b_SME_Zn_6_3_SME_Zm_17_3,
   A64_OPID_a1c00218_usmop4s_SME_ZAda_3b_SME_Znx2_6_3_SME_Zm_17_3,
   A64_OPID_a1d00218_usmop4s_SME_ZAda_3b_SME_Znx2_6_3_SME_Zmx2_17_3,
+  A64_OPID_d5800000_tchangef_Rd_Rn_NOT_BALANCED,
+  A64_OPID_d5900000_tchangef_Rd_UIMM7_NOT_BALANCED,
+  A64_OPID_d5840000_tchangeb_Rd_Rn_NOT_BALANCED,
+  A64_OPID_d5940000_tchangeb_Rd_UIMM7_NOT_BALANCED,
   A64_OPID_MAX,
 };
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 2fc69c27791..572385621db 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -64,6 +64,12 @@
   QLF2(X,NIL),			\
 }
 
+/* e.g. TCHANGEF <Xd>, #<imm>{, <nb>}.  */
+#define QL_DST_X1		\
+{				\
+  QLF3(X,NIL,NIL),		\
+}
+
 /* e.g. MRRS <Xt>, <Xt2>, <systemreg>.  */
 #define QL_DST_X2		\
 {				\
@@ -2808,6 +2814,7 @@
 {		      \
   QLF3(V_4S, V_8H, S_H),	\
 }
+
 
 /* Opcode table.  */
 
@@ -3057,6 +3064,8 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_f8f32 =
   AARCH64_FEATURES (2, SME_MOP4, SME_F8F32);
 static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
   AARCH64_FEATURES (2, SME_MOP4, SME_I16I64);
+static const aarch64_feature_set aarch64_feature_s1poe2 =
+  AARCH64_FEATURE (S1POE2);
 
 #define CORE		&aarch64_feature_v8
 #define FP		&aarch64_feature_fp
@@ -3181,6 +3190,7 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
 #define SME_MOP4_F8F16	&aarch64_feature_sme_mop4_f8f16
 #define SME_MOP4_F8F32	&aarch64_feature_sme_mop4_f8f32
 #define SME_MOP4_I16I64	&aarch64_feature_sme_mop4_i16i64
+#define S1POE2	&aarch64_feature_s1poe2
 
 #define CORE_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, OP, CORE, OPS, QUALS, FLAGS | F_INVALID_IMM_SYMS_1, 0, 0, NULL }
@@ -3510,6 +3520,8 @@ static const aarch64_feature_set aarch64_feature_sme_mop4_i16i64 =
 #define SME_MOP4_I16I64_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS,TIED) \
   { NAME, OPCODE, MASK, CLASS, 0, SME_MOP4_I16I64, OPS, QUALS, \
     FLAGS | F_STRICT, 0, TIED, NULL }
+#define S1POE2_INSN(NAME,OPCODE,MASK,OPS,QUALS, FLAGS) \
+  { NAME, OPCODE, MASK, s1poe2, 0, S1POE2, OPS, QUALS, FLAGS | F_INVALID_IMM_SYMS_1, 0, 0, NULL }
 
 #define MOPS_CPY_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS) \
   MOPS_INSN (NAME, OPCODE, MASK, 0, \
@@ -7738,6 +7750,12 @@ const struct aarch64_opcode aarch64_opcode_table[] =
   SME_MOP4_I16I64_INSN ("usmop4s", 0xa1c00218, 0xfff1fe38, sme_misc, OP3 (SME_ZAda_3b, SME_Znx2_6_3, SME_Zm_17_3), OP_SVE_DHH, 0, 0),
   SME_MOP4_I16I64_INSN ("usmop4s", 0xa1d00218, 0xfff1fe38, sme_misc, OP3 (SME_ZAda_3b, SME_Znx2_6_3, SME_Zmx2_17_3), OP_SVE_DHH, 0, 0),
 
+  /* POE2 instructions.  */
+  S1POE2_INSN("tchangef", 0xd5800000, 0xfffdfc00, OP3 (Rd, Rn, NOT_BALANCED), QL_DST_X2, F_OPD2_OPT | F_DEFAULT (0x0)),
+  S1POE2_INSN("tchangef", 0xd5900000, 0xfffdf000, OP3 (Rd, UIMM7, NOT_BALANCED), QL_DST_X1, F_OPD2_OPT | F_DEFAULT (0x0)),
+  S1POE2_INSN("tchangeb", 0xd5840000, 0xfffdfc00, OP3 (Rd, Rn, NOT_BALANCED), QL_DST_X2, F_OPD2_OPT | F_DEFAULT (0x0)),
+  S1POE2_INSN("tchangeb", 0xd5940000, 0xfffdf000, OP3 (Rd, UIMM7, NOT_BALANCED), QL_DST_X1, F_OPD2_OPT | F_DEFAULT (0x0)),
+
   {0, 0, 0, 0, 0, 0, {}, {}, 0, 0, 0, NULL},
 };
 
@@ -7890,6 +7908,8 @@ const struct aarch64_opcode aarch64_opcode_table[] =
       "a 5-bit unsigned immediate")					\
     Y(IMMEDIATE, imm, "SIMM5", OPD_F_SEXT, F(FLD_imm5),			\
       "a 5-bit signed immediate")					\
+    Y(IMMEDIATE, imm, "NOT_BALANCED", 0, F(FLD_imm1_17),		\
+      "a 1-bit not_balanced optional operand")				\
     Y(IMMEDIATE, imm, "NZCV", 0, F(FLD_nzcv),				\
       "a flag bit specifier giving an alternative value for each flag")	\
     Y(IMMEDIATE, limm, "LIMM", 0, F(FLD_N,FLD_immr,FLD_imms),		\
-- 
2.25.1



More information about the Binutils mailing list