[1/2] aarch64: Add support for (M)ADDPT and (M)SUBPT instructions

Message ID 02A8192E-9B74-4901-8F38-5AD423311B19@arm.com
State Committed
Headers
Series aarch64: Add support for CPA instructions |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_binutils_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_binutils_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_binutils_check--master-aarch64 fail Testing failed
linaro-tcwg-bot/tcwg_binutils_check--master-arm success Testing passed

Commit Message

Yury Khrustalev March 5, 2024, 1:54 p.m. UTC
  From 25d573b0e9b5b7e163f0cf0f72b64a1518445f94 Mon Sep 17 00:00:00 2001
From: Yury Khrustalev <yury.khrustalev@arm.com>
Date: Wed, 21 Feb 2024 12:52:23 +0000
Subject: [PATCH 1/2] aarch64: Add support for (M)ADDPT and (M)SUBPT
 instructions

The following instructions are added in this patch:

 - ADDPT and SUBPT - Add/Subtract checked pointer
 - MADDPT and MSUBPT - Multiply Add/Subtract checked pointer

These instructions are part of Checked Pointer Arithmetic extension.
This patch adds assembler and disassembler support for these instructions
with relevant checks. Tests are included as well.

A new flag "+cpa" added to documentation. This flag enables CPA extension.

Regression tested on the aarch64-none-linux-gnu target and no regressions
have been found.
---
 gas/config/tc-aarch64.c                    | 47 ++++++++++++++++++++
 gas/doc/c-aarch64.texi                     |  2 +
 gas/testsuite/gas/aarch64/cpa-addsub-bad.d |  4 ++
 gas/testsuite/gas/aarch64/cpa-addsub-bad.l | 50 ++++++++++++++++++++++
 gas/testsuite/gas/aarch64/cpa-addsub-bad.s | 29 +++++++++++++
 gas/testsuite/gas/aarch64/cpa-addsub-neg.d |  5 +++
 gas/testsuite/gas/aarch64/cpa-addsub-neg.l | 27 ++++++++++++
 gas/testsuite/gas/aarch64/cpa-addsub.d     | 39 +++++++++++++++++
 gas/testsuite/gas/aarch64/cpa-addsub.s     | 29 +++++++++++++
 include/opcode/aarch64.h                   |  3 ++
 opcodes/aarch64-asm.c                      | 15 +++++++
 opcodes/aarch64-asm.h                      |  1 +
 opcodes/aarch64-dis.c                      | 17 ++++++++
 opcodes/aarch64-dis.h                      |  1 +
 opcodes/aarch64-opc.c                      | 25 +++++++++++
 opcodes/aarch64-tbl.h                      | 20 ++++++++-
 16 files changed, 313 insertions(+), 1 deletion(-)
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub-bad.d
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub-bad.l
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub-bad.s
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub-neg.d
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub-neg.l
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub.d
 create mode 100644 gas/testsuite/gas/aarch64/cpa-addsub.s
  

Patch

diff --git a/gas/config/tc-aarch64.c b/gas/config/tc-aarch64.c
index 4380de3f87b..d6dab86e8a9 100644
--- a/gas/config/tc-aarch64.c
+++ b/gas/config/tc-aarch64.c
@@ -3748,6 +3748,41 @@  parse_shifter_operand (char **str, aarch64_opnd_info *operand,
   return parse_shifter_operand_imm (str, operand, mode);
 }
 
+static bool
+parse_reg_lsl_shifter_operand (char **str, aarch64_opnd_info *operand)
+{
+  aarch64_opnd_qualifier_t qualifier;
+  const reg_entry *reg = aarch64_reg_parse_32_64 (str, &qualifier);
+
+  if (reg)
+    {
+      if (!aarch64_check_reg_type (reg, REG_TYPE_R_ZR))
+	{
+	  set_expected_reg_error (REG_TYPE_R_ZR, reg, 0);
+	  return false;
+	}
+
+      operand->reg.regno = reg->number;
+      operand->qualifier = qualifier;
+
+      /* Accept optional LSL shift operation on register.  */
+      if (!skip_past_comma (str))
+	return true;
+
+      if (!parse_shift (str, operand, SHIFTED_LSL))
+	return false;
+
+      return true;
+    }
+  else
+    {
+      set_syntax_error
+	(_("integer register expected in the shifted operand "
+	   "register"));
+      return false;
+    }
+}
+
 /* Return TRUE on success; return FALSE otherwise.  */
 
 static bool
@@ -6593,6 +6628,17 @@  parse_operands (char *str, const aarch64_opcode *opcode)
 	    }
 	  break;
 
+	case AARCH64_OPND_Rm_LSL:
+	  po_misc_or_fail (parse_reg_lsl_shifter_operand (&str, info));
+	  if (!info->shifter.operator_present)
+	    {
+	      /* Default to LSL #0 if not present. */
+	      gas_assert (info->shifter.kind == AARCH64_MOD_NONE);
+	      info->shifter.kind = AARCH64_MOD_LSL;
+	      info->shifter.amount = 0;
+	    }
+	  break;
+
 	case AARCH64_OPND_Fd:
 	case AARCH64_OPND_Fn:
 	case AARCH64_OPND_Fm:
@@ -10429,6 +10475,7 @@  static const struct aarch64_option_cpu_value_table aarch64_features[] = {
   {"sme2p1",		AARCH64_FEATURE (SME2p1), AARCH64_FEATURE (SME2)},
   {"sve2p1",		AARCH64_FEATURE (SVE2p1), AARCH64_FEATURE (SVE2)},
   {"rcpc3",		AARCH64_FEATURE (RCPC3), AARCH64_FEATURE (RCPC2)},
+  {"cpa",		AARCH64_FEATURE (CPA), AARCH64_NO_FEATURES},
   {NULL,		AARCH64_NO_FEATURES, AARCH64_NO_FEATURES},
 };
 
diff --git a/gas/doc/c-aarch64.texi b/gas/doc/c-aarch64.texi
index 4f97768206c..3756948bfb8 100644
--- a/gas/doc/c-aarch64.texi
+++ b/gas/doc/c-aarch64.texi
@@ -289,6 +289,8 @@  automatically cause those extensions to be disabled.
  @tab Enable @code{wfet} and @code{wfit} instructions.
 @item @code{xs} @tab
  @tab Enable the XS memory attribute extension.
+@item @code{cpa} @tab
+ @tab Enable the Checked Pointer Arithmetic extension.
 @end multitable
 
 @multitable @columnfractions .20 .80
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub-bad.d b/gas/testsuite/gas/aarch64/cpa-addsub-bad.d
new file mode 100644
index 00000000000..0fbcfe395e9
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub-bad.d
@@ -0,0 +1,4 @@ 
+#name: Incorrect input test for CPA instructions ((M)ADDPT and (M)SUBPT).
+#as: -march=armv8-a+cpa
+#source: cpa-addsub-bad.s
+#error_output: cpa-addsub-bad.l
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub-bad.l b/gas/testsuite/gas/aarch64/cpa-addsub-bad.l
new file mode 100644
index 00000000000..f5e8967662c
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub-bad.l
@@ -0,0 +1,50 @@ 
+.*: Assembler messages:
+.*: Error: operand mismatch -- `addpt w5,w8,w0'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+addpt x5, x8, x0
+.*: Error: only 'LSL' shift is permitted at operand 3 -- `addpt x5,x8,x0,asr#6'
+.*: Error: shift amount out of range 0 to 7 at operand 3 -- `addpt x5,x8,x0,lsl#9'
+.*: Error: expected an integer or zero register at operand 3 -- `addpt x5,x8,sp,lsl#5'
+.*: Error: expected an integer or stack pointer register at operand 1 -- `addpt xzr,x8,x0,lsl#3'
+
+.*: Error: operand mismatch -- `subpt w5,w8,w0'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+subpt x5, x8, x0
+.*: Error: only 'LSL' shift is permitted at operand 3 -- `subpt x5,x8,x0,asr#6'
+.*: Error: shift amount out of range 0 to 7 at operand 3 -- `subpt x5,x8,x0,lsl#9'
+.*: Error: expected an integer or zero register at operand 3 -- `subpt x5,x8,sp,lsl#5'
+.*: Error: expected an integer or stack pointer register at operand 1 -- `subpt xzr,x8,x0,lsl#3'
+
+.*: Error: operand mismatch -- `maddpt w1,x2,x3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+maddpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `maddpt x1,w2,x3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+maddpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `maddpt x1,x2,w3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+maddpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `maddpt x1,x2,x3,w4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+maddpt x1, x2, x3, x4
+.*: Error: expected an integer or zero register at operand 1 -- `maddpt sp,x2,x3,x4'
+.*: Error: expected an integer or zero register at operand 2 -- `maddpt x1,sp,x3,x4'
+.*: Error: expected an integer or zero register at operand 3 -- `maddpt x1,x2,sp,x4'
+.*: Error: expected an integer or zero register at operand 4 -- `maddpt x1,x2,x3,sp'
+
+.*: Error: operand mismatch -- `msubpt w1,x2,x3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+msubpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `msubpt x1,w2,x3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+msubpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `msubpt x1,x2,w3,x4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+msubpt x1, x2, x3, x4
+.*: Error: operand mismatch -- `msubpt x1,x2,x3,w4'
+.*: Info:\s+did you mean this\?
+.*: Info:\s+msubpt x1, x2, x3, x4
+.*: Error: expected an integer or zero register at operand 1 -- `msubpt sp,x2,x3,x4'
+.*: Error: expected an integer or zero register at operand 2 -- `msubpt x1,sp,x3,x4'
+.*: Error: expected an integer or zero register at operand 3 -- `msubpt x1,x2,sp,x4'
+.*: Error: expected an integer or zero register at operand 4 -- `msubpt x1,x2,x3,sp'
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub-bad.s b/gas/testsuite/gas/aarch64/cpa-addsub-bad.s
new file mode 100644
index 00000000000..dec18c35139
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub-bad.s
@@ -0,0 +1,29 @@ 
+addpt	w5, w8, w0
+addpt	x5, x8, x0, asr #6
+addpt	x5, x8, x0, lsl #9
+addpt	x5, x8, sp, lsl #5
+addpt	xzr, x8, x0, lsl #3
+
+subpt	w5, w8, w0
+subpt	x5, x8, x0, asr #6
+subpt	x5, x8, x0, lsl #9
+subpt	x5, x8, sp, lsl #5
+subpt	xzr, x8, x0, lsl #3
+
+maddpt	w1, x2, x3, x4
+maddpt	x1, w2, x3, x4
+maddpt	x1, x2, w3, x4
+maddpt	x1, x2, x3, w4
+maddpt	sp, x2, x3, x4
+maddpt	x1, sp, x3, x4
+maddpt	x1, x2, sp, x4
+maddpt	x1, x2, x3, sp
+
+msubpt	w1, x2, x3, x4
+msubpt	x1, w2, x3, x4
+msubpt	x1, x2, w3, x4
+msubpt	x1, x2, x3, w4
+msubpt	sp, x2, x3, x4
+msubpt	x1, sp, x3, x4
+msubpt	x1, x2, sp, x4
+msubpt	x1, x2, x3, sp
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub-neg.d b/gas/testsuite/gas/aarch64/cpa-addsub-neg.d
new file mode 100644
index 00000000000..0a1d1185dab
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub-neg.d
@@ -0,0 +1,5 @@ 
+#name: Negative test for CPA instructions ((M)ADDPT and (M)SUBPT).
+#as: -march=armv8-a
+#as: -march=armv9-a
+#source: cpa-addsub.s
+#error_output: cpa-addsub-neg.l
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub-neg.l b/gas/testsuite/gas/aarch64/cpa-addsub-neg.l
new file mode 100644
index 00000000000..44a7236f38f
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub-neg.l
@@ -0,0 +1,27 @@ 
+.*: Assembler messages:
+.*: Error: selected processor does not support `addpt x0,x0,x0'
+.*: Error: selected processor does not support `addpt sp,x0,x0'
+.*: Error: selected processor does not support `addpt x0,sp,x0'
+.*: Error: selected processor does not support `addpt x0,x0,xzr'
+.*: Error: selected processor does not support `addpt x0,x0,x0,lsl#0'
+.*: Error: selected processor does not support `addpt x0,x0,x0,lsl#7'
+.*: Error: selected processor does not support `addpt x8,x13,x29,lsl#5'
+.*: Error: selected processor does not support `subpt x0,x0,x0'
+.*: Error: selected processor does not support `subpt sp,x0,x0'
+.*: Error: selected processor does not support `subpt x0,sp,x0'
+.*: Error: selected processor does not support `subpt x0,x0,xzr'
+.*: Error: selected processor does not support `subpt x0,x0,x0,lsl#0'
+.*: Error: selected processor does not support `subpt x0,x0,x0,lsl#7'
+.*: Error: selected processor does not support `subpt x1,x10,x22,lsl#2'
+.*: Error: selected processor does not support `maddpt x0,x0,x0,x0'
+.*: Error: selected processor does not support `maddpt xzr,x0,x0,x0'
+.*: Error: selected processor does not support `maddpt x0,xzr,x0,x0'
+.*: Error: selected processor does not support `maddpt x0,x0,xzr,x0'
+.*: Error: selected processor does not support `maddpt x0,x0,x0,xzr'
+.*: Error: selected processor does not support `maddpt x19,x10,x1,x28'
+.*: Error: selected processor does not support `msubpt x0,x0,x0,x0'
+.*: Error: selected processor does not support `msubpt xzr,x0,x0,x0'
+.*: Error: selected processor does not support `msubpt x0,xzr,x0,x0'
+.*: Error: selected processor does not support `msubpt x0,x0,xzr,x0'
+.*: Error: selected processor does not support `msubpt x0,x0,x0,xzr'
+.*: Error: selected processor does not support `msubpt x4,x13,x9,x21'
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub.d b/gas/testsuite/gas/aarch64/cpa-addsub.d
new file mode 100644
index 00000000000..73e9ea28604
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub.d
@@ -0,0 +1,39 @@ 
+#name: Tests for CPA instructions ((M)ADDPT and (M)SUBPT).
+#as: -march=armv8-a+cpa
+#objdump: -dr
+
+[^:]+:     file format .*
+
+
+[^:]+:
+
+[^:]+:
+.*:	9a002000 	addpt	x0, x0, x0
+.*:	9a00201f 	addpt	sp, x0, x0
+.*:	9a0023e0 	addpt	x0, sp, x0
+.*:	9a1f2000 	addpt	x0, x0, xzr
+.*:	9a002000 	addpt	x0, x0, x0
+.*:	9a003c00 	addpt	x0, x0, x0, lsl #7
+.*:	9a1d35a8 	addpt	x8, x13, x29, lsl #5
+
+.*:	da002000 	subpt	x0, x0, x0
+.*:	da00201f 	subpt	sp, x0, x0
+.*:	da0023e0 	subpt	x0, sp, x0
+.*:	da1f2000 	subpt	x0, x0, xzr
+.*:	da002000 	subpt	x0, x0, x0
+.*:	da003c00 	subpt	x0, x0, x0, lsl #7
+.*:	da162941 	subpt	x1, x10, x22, lsl #2
+
+.*:	9b600000 	maddpt	x0, x0, x0, x0
+.*:	9b60001f 	maddpt	xzr, x0, x0, x0
+.*:	9b6003e0 	maddpt	x0, xzr, x0, x0
+.*:	9b7f0000 	maddpt	x0, x0, xzr, x0
+.*:	9b607c00 	maddpt	x0, x0, x0, xzr
+.*:	9b617153 	maddpt	x19, x10, x1, x28
+
+.*:	9b608000 	msubpt	x0, x0, x0, x0
+.*:	9b60801f 	msubpt	xzr, x0, x0, x0
+.*:	9b6083e0 	msubpt	x0, xzr, x0, x0
+.*:	9b7f8000 	msubpt	x0, x0, xzr, x0
+.*:	9b60fc00 	msubpt	x0, x0, x0, xzr
+.*:	9b69d5a4 	msubpt	x4, x13, x9, x21
diff --git a/gas/testsuite/gas/aarch64/cpa-addsub.s b/gas/testsuite/gas/aarch64/cpa-addsub.s
new file mode 100644
index 00000000000..8d64dd8dc62
--- /dev/null
+++ b/gas/testsuite/gas/aarch64/cpa-addsub.s
@@ -0,0 +1,29 @@ 
+addpt   x0, x0, x0
+addpt   sp, x0, x0
+addpt   x0, sp, x0
+addpt   x0, x0, xzr
+addpt   x0, x0, x0, lsl #0
+addpt   x0, x0, x0, lsl #7
+addpt   x8, x13, x29, lsl #5
+
+subpt   x0, x0, x0
+subpt   sp, x0, x0
+subpt   x0, sp, x0
+subpt   x0, x0, xzr
+subpt   x0, x0, x0, lsl #0
+subpt   x0, x0, x0, lsl #7
+subpt   x1, x10, x22, lsl #2
+
+maddpt  x0, x0, x0, x0
+maddpt  xzr, x0, x0, x0
+maddpt  x0, xzr, x0, x0
+maddpt  x0, x0, xzr, x0
+maddpt  x0, x0, x0, xzr
+maddpt  x19, x10, x1, x28
+
+msubpt  x0, x0, x0, x0
+msubpt  xzr, x0, x0, x0
+msubpt  x0, xzr, x0, x0
+msubpt  x0, x0, xzr, x0
+msubpt  x0, x0, x0, xzr
+msubpt  x4, x13, x9, x21
diff --git a/include/opcode/aarch64.h b/include/opcode/aarch64.h
index f585265aa62..1e134a61b80 100644
--- a/include/opcode/aarch64.h
+++ b/include/opcode/aarch64.h
@@ -228,6 +228,8 @@  enum aarch64_feature_bit {
   AARCH64_FEATURE_SVE2p1,
   /* RCPC3 instructions.  */
   AARCH64_FEATURE_RCPC3,
+  /* Checked Pointer Arithmetic instructions. */
+  AARCH64_FEATURE_CPA,
   AARCH64_NUM_FEATURES
 };
 
@@ -490,6 +492,7 @@  enum aarch64_opnd
   AARCH64_OPND_PAIRREG_OR_XZR,	/* Paired register operand, optionally xzr.  */
   AARCH64_OPND_Rm_EXT,	/* Integer Rm extended.  */
   AARCH64_OPND_Rm_SFT,	/* Integer Rm shifted.  */
+  AARCH64_OPND_Rm_LSL,	/* Integer Rm shifted (LSL-only).  */
 
   AARCH64_OPND_Fd,	/* Floating-point Fd.  */
   AARCH64_OPND_Fn,	/* Floating-point Fn.  */
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 29e96e244bb..5a55ca2f86d 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -1020,6 +1020,21 @@  aarch64_ins_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return true;
 }
 
+/* Encode the LSL-shifted register operand for e.g.
+     ADDPT <Xd|SP>, <Xn|SP>, <Xm>{, LSL #<amount>}.  */
+bool
+aarch64_ins_reg_lsl_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
+			     const aarch64_opnd_info *info, aarch64_insn *code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED,
+			     aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+  /* Rm */
+  insert_field (FLD_Rm, code, info->reg.regno, 0);
+  /* imm3 */
+  insert_field (FLD_imm3_10, code, info->shifter.amount, 0);
+  return true;
+}
+
 /* Encode an SVE address [<base>, #<simm4>*<factor>, MUL VL],
    where <simm4> is a 4-bit signed value and where <factor> is 1 plus
    SELF's operand-dependent value.  fields[0] specifies the field that
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index c6dde1c4d1b..88e389bfebd 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -75,6 +75,7 @@  AARCH64_DECL_OPD_INSERTER (ins_hint);
 AARCH64_DECL_OPD_INSERTER (ins_prfop);
 AARCH64_DECL_OPD_INSERTER (ins_reg_extended);
 AARCH64_DECL_OPD_INSERTER (ins_reg_shifted);
+AARCH64_DECL_OPD_INSERTER (ins_reg_lsl_shifted);
 AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s4);
 AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s4xvl);
 AARCH64_DECL_OPD_INSERTER (ins_sve_addr_ri_s6xvl);
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 82d2f8f8251..96f42ae862a 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -1526,6 +1526,23 @@  aarch64_ext_reg_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
   return true;
 }
 
+/* Decode the LSL-shifted register operand for e.g.
+     ADDPT <Xd|SP>, <Xn|SP>, <Xm>{, LSL #<amount>}.  */
+bool
+aarch64_ext_reg_lsl_shifted (const aarch64_operand *self ATTRIBUTE_UNUSED,
+			     aarch64_opnd_info *info,
+			     aarch64_insn code,
+			     const aarch64_inst *inst ATTRIBUTE_UNUSED,
+			     aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+  /* Rm */
+  info->reg.regno = extract_field (FLD_Rm, code, 0);
+  /* imm3 */
+  info->shifter.kind = AARCH64_MOD_LSL;
+  info->shifter.amount = extract_field (FLD_imm3_10, code,  0);
+  return true;
+}
+
 /* Decode an SVE address [<base>, #<offset>*<factor>, MUL VL],
    where <offset> is given by the OFFSET parameter and where <factor> is
    1 plus SELF's operand-dependent value.  fields[0] specifies the field
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 6ed6776b679..86494cc3093 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -99,6 +99,7 @@  AARCH64_DECL_OPD_EXTRACTOR (ext_hint);
 AARCH64_DECL_OPD_EXTRACTOR (ext_prfop);
 AARCH64_DECL_OPD_EXTRACTOR (ext_reg_extended);
 AARCH64_DECL_OPD_EXTRACTOR (ext_reg_shifted);
+AARCH64_DECL_OPD_EXTRACTOR (ext_reg_lsl_shifted);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s4);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s4xvl);
 AARCH64_DECL_OPD_EXTRACTOR (ext_sve_addr_ri_s6xvl);
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 965c1c0698c..e88c616f4a9 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -3270,6 +3270,17 @@  operand_general_constraint_met_p (const aarch64_opnd_info *opnds, int idx,
 	    }
 	  break;
 
+	case AARCH64_OPND_Rm_LSL:
+	  /* We expect here that opnd->shifter.kind != AARCH64_MOD_LSL
+	     because the parser already restricts the type of shift to LSL only,
+	     so another check of shift kind would be redundant.  */
+	  if (!value_in_range_p (opnd->shifter.amount, 0, 7))
+	    {
+	      set_sft_amount_out_of_range_error (mismatch_detail, idx, 0, 7);
+	      return 0;
+	    }
+	  break;
+
 	default:
 	  break;
 	}
@@ -4005,6 +4016,20 @@  aarch64_print_operand (char *buf, size_t size, bfd_vma pc,
 		  style_imm (styler, "#%" PRIi64, opnd->shifter.amount));
       break;
 
+    case AARCH64_OPND_Rm_LSL:
+      assert (opnd->qualifier == AARCH64_OPND_QLF_X);
+      assert (opnd->shifter.kind == AARCH64_MOD_LSL);
+      if (opnd->shifter.amount == 0)
+	snprintf (buf, size, "%s",
+		  style_reg (styler, get_int_reg_name (opnd->reg.regno,
+						       opnd->qualifier, 0)));
+      else
+	snprintf (buf, size, "%s, %s %s",
+		  style_reg (styler, get_int_reg_name (opnd->reg.regno, opnd->qualifier, 0)),
+		  style_sub_mnem (styler, aarch64_operand_modifiers[opnd->shifter.kind].name),
+		  style_imm (styler, "#%" PRIi64, opnd->shifter.amount));
+      break;
+
     case AARCH64_OPND_Fd:
     case AARCH64_OPND_Fn:
     case AARCH64_OPND_Fm:
diff --git a/opcodes/aarch64-tbl.h b/opcodes/aarch64-tbl.h
index 0f84832523e..7232d6a9f35 100644
--- a/opcodes/aarch64-tbl.h
+++ b/opcodes/aarch64-tbl.h
@@ -240,6 +240,12 @@ 
   QLF4(X,X,X,X),		\
 }
 
+/* e.g. MADDPT <Xd>, <Xn>, <Xm>, <Xa>.  */
+#define QL_I4SAMEX		\
+{				\
+  QLF4(X,X,X,X),		\
+}
+
 /* e.g. SMADDL <Xd>, <Wn>, <Wm>, <Xa>.  */
 #define QL_I3SAMEL		\
 {				\
@@ -2649,7 +2655,8 @@  static const aarch64_feature_set aarch64_feature_sve2p1 =
   AARCH64_FEATURE (SVE2p1);
 static const aarch64_feature_set aarch64_feature_rcpc3 =
   AARCH64_FEATURE (RCPC3);
-
+static const aarch64_feature_set aarch64_feature_cpa =
+  AARCH64_FEATURE (CPA);
 
 #define CORE		&aarch64_feature_v8
 #define FP		&aarch64_feature_fp
@@ -2716,6 +2723,7 @@  static const aarch64_feature_set aarch64_feature_rcpc3 =
 #define SME2p1  &aarch64_feature_sme2p1
 #define SVE2p1  &aarch64_feature_sve2p1
 #define RCPC3	  &aarch64_feature_rcpc3
+#define CPA	  &aarch64_feature_cpa
 
 #define CORE_INSN(NAME,OPCODE,MASK,CLASS,OP,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, OP, CORE, OPS, QUALS, FLAGS, 0, 0, NULL }
@@ -2888,6 +2896,8 @@  static const aarch64_feature_set aarch64_feature_rcpc3 =
   { NAME, OPCODE, MASK, the, 0, D128_THE, OPS, QUALS, FLAGS, 0, 0, NULL }
 #define RCPC3_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS,FLAGS) \
   { NAME, OPCODE, MASK, CLASS, 0, RCPC3, OPS, QUALS, FLAGS, 0, 0, NULL }
+#define CPA_INSN(NAME,OPCODE,MASK,CLASS,OPS,QUALS) \
+  { NAME, OPCODE, MASK, CLASS, 0, CPA, OPS, QUALS, 0, 0, 0, NULL }
 
 #define MOPS_CPY_OP1_OP2_PME_INSN(NAME, OPCODE, MASK, FLAGS, CONSTRAINTS) \
   MOPS_INSN (NAME, OPCODE, MASK, 0, \
@@ -6392,6 +6402,12 @@  const struct aarch64_opcode aarch64_opcode_table[] =
   SVE2p1_INSNC("st3q",0xe4a00000, 0xffe0e000, sve_misc, 0, OP3 (SME_Zt3, SVE_Pg3, SVE_ADDR_RR_LSL4), OP_SVE_QUU, 0, C_SCAN_MOVPRFX, 0),
   SVE2p1_INSNC("st4q",0xe4e00000, 0xffe0e000, sve_misc, 0, OP3 (SME_Zt4, SVE_Pg3, SVE_ADDR_RR_LSL4), OP_SVE_QUU, 0, C_SCAN_MOVPRFX, 0),
 
+/* Checked Pointer Arithmetic Instructions.  */
+  CPA_INSN ("addpt",  0x9a002000, 0xffe0e000, aarch64_misc, OP3 (Rd_SP, Rn_SP, Rm_LSL), QL_I3SAMEX),
+  CPA_INSN ("subpt",  0xda002000, 0xffe0e000, aarch64_misc, OP3 (Rd_SP, Rn_SP, Rm_LSL), QL_I3SAMEX),
+  CPA_INSN ("maddpt", 0x9b600000, 0xffe08000, aarch64_misc, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEX),
+  CPA_INSN ("msubpt", 0x9b608000, 0xffe08000, aarch64_misc, OP4 (Rd, Rn, Rm, Ra), QL_I4SAMEX),
+
   {0, 0, 0, 0, 0, 0, {}, {}, 0, 0, 0, NULL},
 };
 
@@ -6440,6 +6456,8 @@  const struct aarch64_opcode aarch64_opcode_table[] =
       "an integer register with optional extension")			\
     Y(MODIFIED_REG, reg_shifted, "Rm_SFT", 0, F(),			\
       "an integer register with optional shift")			\
+    Y(MODIFIED_REG, reg_lsl_shifted, "Rm_LSL", 0, F(),			\
+      "an integer register with optional LSL shift")			\
     Y(FP_REG, regno, "Fd", 0, F(FLD_Rd), "a floating-point register")	\
     Y(FP_REG, regno, "Fn", 0, F(FLD_Rn), "a floating-point register")	\
     Y(FP_REG, regno, "Fm", 0, F(FLD_Rm), "a floating-point register")	\