aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLucas Duarte Prates <lucas.prates@arm.com>2023-11-30 10:08:12 +0000
committerLucas Prates <lucas.prates@arm.com>2023-12-20 15:43:17 +0000
commitd43fc5a6ad2f6092ac82b76590951235ec46f6e2 (patch)
treeae94b8d11e95994db88255284630adacaf23621b
parent688fa35df0e3dcb460db00db0b65faa02c1ed458 (diff)
downloadllvm-d43fc5a6ad2f6092ac82b76590951235ec46f6e2.zip
llvm-d43fc5a6ad2f6092ac82b76590951235ec46f6e2.tar.gz
llvm-d43fc5a6ad2f6092ac82b76590951235ec46f6e2.tar.bz2
Reland: [AArch64] Assembly support for the Checked Pointer Arithmetic Extension (#73777)
This introduces assembly support for the Checked Pointer Arithmetic Extension (FEAT_CPA), annouced as part of the Armv9.5-A architecture version. The changes include: * New subtarget feature for FEAT_CPA * New scalar instruction for pointer arithmetic * ADDPT, SUBPT, MADDPT, and MSUBPT * New SVE instructions for pointer arithmetic * ADDPT (vectors, predicated), ADDPT (vectors, unpredicated) * SUBPT (vectors, predicated), SUBPT (vectors, unpredicated) * MADPT and MLAPT * New ID_AA64ISAR3_EL1 system register Mode details about the extension can be found at: * https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-developments-2023 * https://developer.arm.com/documentation/ddi0602/2023-09/ Co-authored-by: Rodolfo Wottrich <rodolfo.wottrich@arm.com>
-rw-r--r--clang/test/Driver/aarch64-v95a.c5
-rw-r--r--llvm/include/llvm/TargetParser/AArch64TargetParser.h5
-rw-r--r--llvm/lib/Target/AArch64/AArch64.td5
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrFormats.td52
-rw-r--r--llvm/lib/Target/AArch64/AArch64InstrInfo.td19
-rw-r--r--llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td21
-rw-r--r--llvm/lib/Target/AArch64/AArch64SchedA64FX.td3
-rw-r--r--llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td2
-rw-r--r--llvm/lib/Target/AArch64/AArch64SchedNeoverseV1.td2
-rw-r--r--llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td2
-rw-r--r--llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp18
-rw-r--r--llvm/lib/Target/AArch64/SVEInstrFormats.td31
-rw-r--r--llvm/test/MC/AArch64/SVE/armv9.5a-cpa.s69
-rw-r--r--llvm/test/MC/AArch64/armv9.5a-cpa.s50
-rw-r--r--llvm/test/MC/AArch64/basic-a64-diagnostics.s8
-rw-r--r--llvm/test/MC/AArch64/basic-a64-instructions.s4
-rw-r--r--llvm/test/MC/Disassembler/AArch64/armv9.5a-cpa.txt42
-rw-r--r--llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt2
-rw-r--r--llvm/unittests/TargetParser/TargetParserTest.cpp4
19 files changed, 337 insertions, 7 deletions
diff --git a/clang/test/Driver/aarch64-v95a.c b/clang/test/Driver/aarch64-v95a.c
index 6044a4f..366cade 100644
--- a/clang/test/Driver/aarch64-v95a.c
+++ b/clang/test/Driver/aarch64-v95a.c
@@ -13,3 +13,8 @@
// RUN: %clang -target aarch64_be -mbig-endian -march=armv9.5-a -### -c %s 2>&1 | FileCheck -check-prefix=GENERICV95A-BE %s
// GENERICV95A-BE: "-cc1"{{.*}} "-triple" "aarch64_be{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a"
+// ===== Features supported on aarch64 =====
+
+// RUN: %clang -target aarch64 -march=armv9.5a+cpa -### -c %s 2>&1 | FileCheck -check-prefix=V95A-CPA %s
+// RUN: %clang -target aarch64 -march=armv9.5-a+cpa -### -c %s 2>&1 | FileCheck -check-prefix=V95A-CPA %s
+// V95A-CPA: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+neon" "-target-feature" "+v9.5a" "-target-feature" "+cpa"
diff --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index 56c32fa..f0b3579 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -173,6 +173,7 @@ enum ArchExtKind : unsigned {
AEK_SMEF8F16 = 69, // FEAT_SME_F8F16
AEK_SMEF8F32 = 70, // FEAT_SME_F8F32
AEK_SMEFA64 = 71, // FEAT_SME_FA64
+ AEK_CPA = 72, // FEAT_CPA
AEK_NUM_EXTENSIONS
};
using ExtensionBitset = Bitset<AEK_NUM_EXTENSIONS>;
@@ -295,6 +296,7 @@ inline constexpr ExtensionInfo Extensions[] = {
{"sme-f8f16", AArch64::AEK_SMEF8F16, "+sme-f8f16", "-sme-f8f16", FEAT_INIT, "+sme2,+fp8", 0},
{"sme-f8f32", AArch64::AEK_SMEF8F32, "+sme-f8f32", "-sme-f8f32", FEAT_INIT, "+sme2,+fp8", 0},
{"sme-fa64", AArch64::AEK_SMEFA64, "+sme-fa64", "-sme-fa64", FEAT_INIT, "", 0},
+ {"cpa", AArch64::AEK_CPA, "+cpa", "-cpa", FEAT_INIT, "", 0},
// Special cases
{"none", AArch64::AEK_NONE, {}, {}, FEAT_INIT, "", ExtensionInfo::MaxFMVPriority},
};
@@ -378,7 +380,8 @@ inline constexpr ArchInfo ARMV9_3A = { VersionTuple{9, 3}, AProfile, "armv9.3-a
AArch64::ExtensionBitset({AArch64::AEK_MOPS, AArch64::AEK_HBC}))};
inline constexpr ArchInfo ARMV9_4A = { VersionTuple{9, 4}, AProfile, "armv9.4-a", "+v9.4a", (ARMV9_3A.DefaultExts |
AArch64::ExtensionBitset({AArch64::AEK_SPECRES2, AArch64::AEK_CSSC, AArch64::AEK_RASv2}))};
-inline constexpr ArchInfo ARMV9_5A = { VersionTuple{9, 5}, AProfile, "armv9.5-a", "+v9.5a", (ARMV9_4A.DefaultExts)};
+inline constexpr ArchInfo ARMV9_5A = { VersionTuple{9, 5}, AProfile, "armv9.5-a", "+v9.5a", (ARMV9_4A.DefaultExts |
+ AArch64::ExtensionBitset({AArch64::AEK_CPA}))};
// For v8-R, we do not enable crypto and align with GCC that enables a more minimal set of optional architecture extensions.
inline constexpr ArchInfo ARMV8R = { VersionTuple{8, 0}, RProfile, "armv8-r", "+v8r", (ARMV8_5A.DefaultExts |
AArch64::ExtensionBitset({AArch64::AEK_SSBS,
diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index 234f983..db92a94 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -622,6 +622,9 @@ def FeatureLdpAlignedOnly : SubtargetFeature<"ldp-aligned-only", "HasLdpAlignedO
def FeatureStpAlignedOnly : SubtargetFeature<"stp-aligned-only", "HasStpAlignedOnly",
"true", "In order to emit stp, first check if the store will be aligned to 2 * element_size">;
+def FeatureCPA : SubtargetFeature<"cpa", "HasCPA", "true",
+ "Enable ARMv9.5-A Checked Pointer Arithmetic (FEAT_CPA)">;
+
//===----------------------------------------------------------------------===//
// Architectures.
//
@@ -692,7 +695,7 @@ def HasV9_4aOps : SubtargetFeature<
def HasV9_5aOps : SubtargetFeature<
"v9.5a", "HasV9_5aOps", "true", "Support ARM v9.5a instructions",
- [HasV9_4aOps]>;
+ [HasV9_4aOps, FeatureCPA]>;
def HasV8_0rOps : SubtargetFeature<
"v8r", "HasV8_0rOps", "true", "Support ARM v8r instructions",
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 68e87f4..690ac0d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -12446,6 +12446,58 @@ class SystemPXtI<bit L, string asm> :
BaseSYSPEncoding<L, asm, "\t$op1, $Cn, $Cm, $op2, $Rt", (outs),
(ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2, XSeqPairClassOperand:$Rt)>;
+//----------------------------------------------------------------------------
+// 2023 Armv9.5 Extensions
+//----------------------------------------------------------------------------
+
+//---
+// Checked Pointer Arithmetic (FEAT_CPA)
+//---
+
+def LSLImm3ShiftOperand : AsmOperandClass {
+ let SuperClasses = [ExtendOperandLSL64];
+ let Name = "LSLImm3Shift";
+ let RenderMethod = "addLSLImm3ShifterOperands";
+ let DiagnosticType = "AddSubLSLImm3ShiftLarge";
+}
+
+def lsl_imm3_shift_operand : Operand<i32> {
+ let PrintMethod = "printShifter";
+ let ParserMatchClass = LSLImm3ShiftOperand;
+}
+
+// Base CPA scalar add/subtract with lsl #imm3 shift
+class BaseAddSubCPA<bit isSub, string asm> : I<(outs GPR64sp:$Rd),
+ (ins GPR64sp:$Rn, GPR64:$Rm, lsl_imm3_shift_operand:$shift_imm),
+ asm, "\t$Rd, $Rn, $Rm$shift_imm", "", []>, Sched<[]> {
+ bits<5> Rd;
+ bits<5> Rn;
+ bits<5> Rm;
+ bits<3> shift_imm;
+ let Inst{31} = 0b1;
+ let Inst{30} = isSub;
+ let Inst{29-21} = 0b011010000;
+ let Inst{20-16} = Rm;
+ let Inst{15-13} = 0b001;
+ let Inst{12-10} = shift_imm;
+ let Inst{9-5} = Rn;
+ let Inst{4-0} = Rd;
+}
+
+// Alias for CPA scalar add/subtract with no shift
+class AddSubCPAAlias<string asm, Instruction inst>
+ : InstAlias<asm#"\t$Rd, $Rn, $Rm",
+ (inst GPR64sp:$Rd, GPR64sp:$Rn, GPR64:$Rm, 0)>;
+
+multiclass AddSubCPA<bit isSub, string asm> {
+ def _shift : BaseAddSubCPA<isSub, asm>;
+ def _noshift : AddSubCPAAlias<asm, !cast<Instruction>(NAME#"_shift")>;
+}
+
+class MulAccumCPA<bit isSub, string asm>
+ : BaseMulAccum<isSub, 0b011, GPR64, GPR64, asm, []>, Sched<[]> {
+ let Inst{31} = 0b1;
+}
//----------------------------------------------------------------------------
// Allow the size specifier tokens to be upper case, not just lower.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 44b0337..bdb38f0c 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -289,6 +289,8 @@ def HasCHK : Predicate<"Subtarget->hasCHK()">,
AssemblerPredicateWithAll<(all_of FeatureCHK), "chk">;
def HasGCS : Predicate<"Subtarget->hasGCS()">,
AssemblerPredicateWithAll<(all_of FeatureGCS), "gcs">;
+def HasCPA : Predicate<"Subtarget->hasCPA()">,
+ AssemblerPredicateWithAll<(all_of FeatureCPA), "cpa">;
def IsLE : Predicate<"Subtarget->isLittleEndian()">;
def IsBE : Predicate<"!Subtarget->isLittleEndian()">;
def IsWindows : Predicate<"Subtarget->isTargetWindows()">;
@@ -9402,6 +9404,10 @@ let Predicates = [HasD128] in {
}
}
+//===----------------------------===//
+// 2023 Architecture Extensions:
+//===----------------------------===//
+
let Predicates = [HasFP8] in {
defm F1CVTL : SIMDMixedTwoVectorFP8<0b00, "f1cvtl">;
defm F2CVTL : SIMDMixedTwoVectorFP8<0b01, "f2cvtl">;
@@ -9443,6 +9449,19 @@ let Predicates = [HasFP8DOT4] in {
defm FDOT : SIMDThreeSameVectorDOT4<"fdot">;
} // End let Predicates = [HasFP8DOT4]
+//===----------------------------------------------------------------------===//
+// Checked Pointer Arithmetic (FEAT_CPA)
+//===----------------------------------------------------------------------===//
+let Predicates = [HasCPA] in {
+ // Scalar add/subtract
+ defm ADDPT : AddSubCPA<0, "addpt">;
+ defm SUBPT : AddSubCPA<1, "subpt">;
+
+ // Scalar multiply-add/subtract
+ def MADDPT : MulAccumCPA<0, "maddpt">;
+ def MSUBPT : MulAccumCPA<1, "msubpt">;
+}
+
include "AArch64InstrAtomics.td"
include "AArch64SVEInstrInfo.td"
include "AArch64SMEInstrInfo.td"
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
index 15b47f6..3dae6f7 100644
--- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td
@@ -4183,3 +4183,24 @@ let Predicates = [HasSVE2orSME2, HasLUT] in {
// LUTI4 (two contiguous registers)
defm LUTI4_Z2ZZI : sve2_luti4_vector_vg2_index<"luti4">;
} // End HasSVE2orSME2, HasLUT
+
+//===----------------------------------------------------------------------===//
+// Checked Pointer Arithmetic (FEAT_CPA)
+//===----------------------------------------------------------------------===//
+let Predicates = [HasSVE, HasCPA] in {
+ // Add/subtract (vectors, unpredicated)
+ def ADD_ZZZ_CPA : sve_int_bin_cons_arit_0<0b11, 0b010, "addpt", ZPR64>;
+ def SUB_ZZZ_CPA : sve_int_bin_cons_arit_0<0b11, 0b011, "subpt", ZPR64>;
+
+ // Add/subtract (vectors, predicated)
+ let DestructiveInstType = DestructiveBinaryComm in {
+ def ADD_ZPmZ_CPA : sve_int_bin_pred_arit_log<0b11, 0b00, 0b100, "addpt", ZPR64>;
+ def SUB_ZPmZ_CPA : sve_int_bin_pred_arit_log<0b11, 0b00, 0b101, "subpt", ZPR64>;
+ }
+
+ // Multiply-add vectors, writing multiplicand
+ def MAD_CPA : sve_int_mad_cpa<"madpt">;
+
+ // Multiply-add vectors, writing addend
+ def MLA_CPA : sve_int_mla_cpa<"mlapt">;
+}
diff --git a/llvm/lib/Target/AArch64/AArch64SchedA64FX.td b/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
index b3d8c99..813b4a3 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedA64FX.td
@@ -21,7 +21,8 @@ def A64FXModel : SchedMachineModel {
let CompleteModel = 1;
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F, SVEUnsupported.F,
- [HasMTE, HasMatMulInt8, HasBF16, HasPAuth]);
+ [HasMTE, HasMatMulInt8, HasBF16,
+ HasPAuth, HasCPA]);
let FullInstRWOverlapCheck = 0;
}
diff --git a/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td b/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
index 503de3b..53cf725 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedNeoverseN2.td
@@ -19,7 +19,7 @@ def NeoverseN2Model : SchedMachineModel {
let CompleteModel = 1;
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
- [HasSVE2p1]);
+ [HasSVE2p1, HasCPA]);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV1.td b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV1.td
index 726be1a..75fbb85 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV1.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV1.td
@@ -28,7 +28,7 @@ def NeoverseV1Model : SchedMachineModel {
list<Predicate> UnsupportedFeatures = !listconcat(SVE2Unsupported.F,
SMEUnsupported.F,
- [HasMTE]);
+ [HasMTE, HasCPA]);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td
index 3367d5d..658d7cd 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedNeoverseV2.td
@@ -22,7 +22,7 @@ def NeoverseV2Model : SchedMachineModel {
let CompleteModel = 1;
list<Predicate> UnsupportedFeatures = !listconcat(SMEUnsupported.F,
- [HasSVE2p1]);
+ [HasSVE2p1, HasCPA]);
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 238269c..74afa41 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1541,6 +1541,13 @@ public:
getShiftExtendAmount() <= 4;
}
+ bool isLSLImm3Shift() const {
+ if (!isShiftExtend())
+ return false;
+ AArch64_AM::ShiftExtendType ET = getShiftExtendType();
+ return ET == AArch64_AM::LSL && getShiftExtendAmount() <= 7;
+ }
+
template<int Width> bool isMemXExtend() const {
if (!isExtend())
return false;
@@ -2091,6 +2098,12 @@ public:
Inst.addOperand(MCOperand::createImm(Imm));
}
+ void addLSLImm3ShifterOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ unsigned Imm = getShiftExtendAmount();
+ Inst.addOperand(MCOperand::createImm(Imm));
+ }
+
void addSyspXzrPairOperand(MCInst &Inst, unsigned N) const {
assert(N == 1 && "Invalid number of operands!");
@@ -3664,6 +3677,7 @@ static const struct Extension {
{"sme-f8f16", {AArch64::FeatureSMEF8F16}},
{"sme-f8f32", {AArch64::FeatureSMEF8F32}},
{"sme-fa64", {AArch64::FeatureSMEFA64}},
+ {"cpa", {AArch64::FeatureCPA}},
};
static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) {
@@ -6064,6 +6078,9 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
"Invalid vector list, expected list with each SVE vector in the list "
"4 registers apart, and the first register in the range [z0, z3] or "
"[z16, z19] and with correct element type");
+ case Match_AddSubLSLImm3ShiftLarge:
+ return Error(Loc,
+ "expected 'lsl' with optional integer in range [0, 7]");
default:
llvm_unreachable("unexpected error code!");
}
@@ -6448,6 +6465,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidMemoryIndexed8:
case Match_InvalidMemoryIndexed16:
case Match_InvalidCondCode:
+ case Match_AddSubLSLImm3ShiftLarge:
case Match_AddSubRegExtendSmall:
case Match_AddSubRegExtendLarge:
case Match_AddSubSecondSource:
diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td
index 9edf260..b755254 100644
--- a/llvm/lib/Target/AArch64/SVEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td
@@ -10433,3 +10433,34 @@ multiclass sve2_luti4_vector_vg2_index<string mnemonic> {
let Inst{23-22} = idx;
}
}
+
+//===----------------------------------------------------------------------===//
+// Checked Pointer Arithmetic (FEAT_CPA)
+//===----------------------------------------------------------------------===//
+class sve_int_mad_cpa<string asm>
+ : I<(outs ZPR64:$Zdn), (ins ZPR64:$_Zdn, ZPR64:$Zm, ZPR64:$Za),
+ asm, "\t$Zdn, $Zm, $Za", "", []>, Sched<[]> {
+ bits<5> Zdn;
+ bits<5> Zm;
+ bits<5> Za;
+ let Inst{31-24} = 0b01000100;
+ let Inst{23-22} = 0b11; // sz
+ let Inst{21} = 0b0;
+ let Inst{20-16} = Zm;
+ let Inst{15} = 0b1;
+ let Inst{14-10} = 0b10110; // opc
+ let Inst{9-5} = Za;
+ let Inst{4-0} = Zdn;
+
+ let Constraints = "$Zdn = $_Zdn";
+ let DestructiveInstType = DestructiveOther;
+ let ElementSize = ZPR64.ElementSize;
+ let hasSideEffects = 0;
+}
+
+class sve_int_mla_cpa<string asm>
+ : sve2_int_mla<0b11, 0b10100, asm, ZPR64, ZPR64> {
+ let Inst{15} = 0b1;
+
+ let ElementSize = ZPR64.ElementSize;
+}
diff --git a/llvm/test/MC/AArch64/SVE/armv9.5a-cpa.s b/llvm/test/MC/AArch64/SVE/armv9.5a-cpa.s
new file mode 100644
index 0000000..2d6708b
--- /dev/null
+++ b/llvm/test/MC/AArch64/SVE/armv9.5a-cpa.s
@@ -0,0 +1,69 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve -mattr=+cpa < %s \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme -mattr=+cpa < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ERROR-NO-SVE
+// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+cpa < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR-NO-SVE
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR-NO-CPA
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme < %s 2>&1 \
+// RUN: | FileCheck %s --check-prefix=CHECK-ERROR
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve -mattr=+cpa < %s \
+// RUN: | llvm-objdump -d --mattr=+sve --mattr=+cpa - \
+// RUN: | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve -mattr=+cpa < %s \
+// RUN: | llvm-objdump -d --mattr=+sve --mattr=-cpa - \
+// RUN: | FileCheck %s --check-prefix=CHECK-UNKNOWN
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve -mattr=+cpa < %s \
+// RUN: | llvm-objdump -d --mattr=-sve --mattr=+cpa - \
+// RUN: | FileCheck %s --check-prefix=CHECK-UNKNOWN
+
+addpt z23.d, z13.d, z8.d
+// CHECK-INST: addpt z23.d, z13.d, z8.d
+// CHECK-ENCODING: [0xb7,0x09,0xe8,0x04]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 04e809b7 <unknown>
+
+addpt z23.d, p3/m, z23.d, z13.d
+// CHECK-INST: addpt z23.d, p3/m, z23.d, z13.d
+// CHECK-ENCODING: [0xb7,0x0d,0xc4,0x04]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 04c40db7 <unknown>
+
+subpt z23.d, z13.d, z8.d
+// CHECK-INST: subpt z23.d, z13.d, z8.d
+// CHECK-ENCODING: [0xb7,0x0d,0xe8,0x04]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 04e80db7 <unknown>
+
+subpt z23.d, p3/m, z23.d, z13.d
+// CHECK-INST: subpt z23.d, p3/m, z23.d, z13.d
+// CHECK-ENCODING: [0xb7,0x0d,0xc5,0x04]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 04c50db7 <unknown>
+
+madpt z0.d, z1.d, z31.d
+// CHECK-INST: madpt z0.d, z1.d, z31.d
+// CHECK-ENCODING: [0xe0,0xdb,0xc1,0x44]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 44c1dbe0 <unknown>
+
+mlapt z0.d, z1.d, z31.d
+// CHECK-INST: mlapt z0.d, z1.d, z31.d
+// CHECK-ENCODING: [0x20,0xd0,0xdf,0x44]
+// CHECK-ERROR: instruction requires: cpa sve
+// CHECK-ERROR-NO-SVE: instruction requires: sve
+// CHECK-ERROR-NO-CPA: instruction requires: cpa
+// CHECK-UNKNOWN: 44dfd020 <unknown>
diff --git a/llvm/test/MC/AArch64/armv9.5a-cpa.s b/llvm/test/MC/AArch64/armv9.5a-cpa.s
new file mode 100644
index 0000000..1c338ec
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.5a-cpa.s
@@ -0,0 +1,50 @@
+// RUN: llvm-mc -triple aarch64 -show-encoding -mattr=+cpa < %s | FileCheck %s
+// RUN: not llvm-mc -triple aarch64 < %s 2>&1 | FileCheck --check-prefix=ERROR-NO-CPA %s
+
+addpt x0, x1, x2
+// CHECK: addpt x0, x1, x2 // encoding: [0x20,0x20,0x02,0x9a]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+addpt sp, sp, x2
+// CHECK: addpt sp, sp, x2 // encoding: [0xff,0x23,0x02,0x9a]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+addpt x0, x1, x2, lsl #0
+// CHECK: addpt x0, x1, x2 // encoding: [0x20,0x20,0x02,0x9a]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+addpt x0, x1, x2, lsl #7
+// CHECK: addpt x0, x1, x2, lsl #7 // encoding: [0x20,0x3c,0x02,0x9a]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+addpt sp, sp, x2, lsl #7
+// CHECK: addpt sp, sp, x2, lsl #7 // encoding: [0xff,0x3f,0x02,0x9a]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+subpt x0, x1, x2
+// CHECK: subpt x0, x1, x2 // encoding: [0x20,0x20,0x02,0xda]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+subpt sp, sp, x2
+// CHECK: subpt sp, sp, x2 // encoding: [0xff,0x23,0x02,0xda]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+subpt x0, x1, x2, lsl #0
+// CHECK: subpt x0, x1, x2 // encoding: [0x20,0x20,0x02,0xda]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+subpt x0, x1, x2, lsl #7
+// CHECK: subpt x0, x1, x2, lsl #7 // encoding: [0x20,0x3c,0x02,0xda]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+subpt sp, sp, x2, lsl #7
+// CHECK: subpt sp, sp, x2, lsl #7 // encoding: [0xff,0x3f,0x02,0xda]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+maddpt x0, x1, x2, x3
+// CHECK: maddpt x0, x1, x2, x3 // encoding: [0x20,0x0c,0x62,0x9b]
+// ERROR-NO-CPA: error: instruction requires: cpa
+
+msubpt x0, x1, x2, x3
+// CHECK: msubpt x0, x1, x2, x3 // encoding: [0x20,0x8c,0x62,0x9b]
+// ERROR-NO-CPA: error: instruction requires: cpa
diff --git a/llvm/test/MC/AArch64/basic-a64-diagnostics.s b/llvm/test/MC/AArch64/basic-a64-diagnostics.s
index a7dc310..a59861e 100644
--- a/llvm/test/MC/AArch64/basic-a64-diagnostics.s
+++ b/llvm/test/MC/AArch64/basic-a64-diagnostics.s
@@ -3604,6 +3604,8 @@
msr ID_AA64AFR1_EL1, x12
msr ID_AA64ISAR0_EL1, x12
msr ID_AA64ISAR1_EL1, x12
+ msr ID_AA64ISAR2_EL1, x12
+ msr ID_AA64ISAR3_EL1, x12
msr ID_AA64MMFR0_EL1, x12
msr ID_AA64MMFR1_EL1, x12
msr ID_AA64MMFR2_EL1, x12
@@ -3753,6 +3755,12 @@
// CHECK-ERROR-NEXT: msr ID_AA64ISAR1_EL1, x12
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: expected writable system register or pstate
+// CHECK-ERROR-NEXT: msr ID_AA64ISAR2_EL1, x12
+// CHECK-ERROR-NEXT: ^
+// CHECK-ERROR-NEXT: error: expected writable system register or pstate
+// CHECK-ERROR-NEXT: msr ID_AA64ISAR3_EL1, x12
+// CHECK-ERROR-NEXT: ^
+// CHECK-ERROR-NEXT: error: expected writable system register or pstate
// CHECK-ERROR-NEXT: msr ID_AA64MMFR0_EL1, x12
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: expected writable system register or pstate
diff --git a/llvm/test/MC/AArch64/basic-a64-instructions.s b/llvm/test/MC/AArch64/basic-a64-instructions.s
index 227b6d5..0ae23d6 100644
--- a/llvm/test/MC/AArch64/basic-a64-instructions.s
+++ b/llvm/test/MC/AArch64/basic-a64-instructions.s
@@ -4374,6 +4374,8 @@ _func:
mrs x9, ID_AA64AFR1_EL1
mrs x9, ID_AA64ISAR0_EL1
mrs x9, ID_AA64ISAR1_EL1
+ mrs x9, ID_AA64ISAR2_EL1
+ mrs x9, ID_AA64ISAR3_EL1
mrs x9, ID_AA64MMFR0_EL1
mrs x9, ID_AA64MMFR1_EL1
mrs x9, ID_AA64MMFR2_EL1
@@ -4712,6 +4714,8 @@ _func:
// CHECK: mrs x9, {{id_aa64afr1_el1|ID_AA64AFR1_EL1}} // encoding: [0xa9,0x05,0x38,0xd5]
// CHECK: mrs x9, {{id_aa64isar0_el1|ID_AA64ISAR0_EL1}} // encoding: [0x09,0x06,0x38,0xd5]
// CHECK: mrs x9, {{id_aa64isar1_el1|ID_AA64ISAR1_EL1}} // encoding: [0x29,0x06,0x38,0xd5]
+// CHECK: mrs x9, {{id_aa64isar2_el1|ID_AA64ISAR2_EL1}} // encoding: [0x49,0x06,0x38,0xd5]
+// CHECK: mrs x9, {{id_aa64isar3_el1|ID_AA64ISAR3_EL1}} // encoding: [0x69,0x06,0x38,0xd5]
// CHECK: mrs x9, {{id_aa64mmfr0_el1|ID_AA64MMFR0_EL1}} // encoding: [0x09,0x07,0x38,0xd5]
// CHECK: mrs x9, {{id_aa64mmfr1_el1|ID_AA64MMFR1_EL1}} // encoding: [0x29,0x07,0x38,0xd5]
// CHECK: mrs x9, {{id_aa64mmfr2_el1|ID_AA64MMFR2_EL1}} // encoding: [0x49,0x07,0x38,0xd5]
diff --git a/llvm/test/MC/Disassembler/AArch64/armv9.5a-cpa.txt b/llvm/test/MC/Disassembler/AArch64/armv9.5a-cpa.txt
new file mode 100644
index 0000000..bf61782
--- /dev/null
+++ b/llvm/test/MC/Disassembler/AArch64/armv9.5a-cpa.txt
@@ -0,0 +1,42 @@
+# RUN: llvm-mc -triple aarch64 -disassemble -mattr=+cpa < %s | FileCheck %s
+# RUN: not llvm-mc -triple aarch64 -disassemble < %s 2>&1 | FileCheck --check-prefix=NO-CPA %s
+
+[0x20,0x20,0x02,0x9a]
+# CHECK: addpt x0, x1, x2
+# NO-CPA: warning: invalid instruction encoding
+
+[0xff,0x23,0x02,0x9a]
+# CHECK: addpt sp, sp, x2
+# NO-CPA: warning: invalid instruction encoding
+
+[0x20,0x3c,0x02,0x9a]
+# CHECK: addpt x0, x1, x2, lsl #7
+# NO-CPA: warning: invalid instruction encoding
+
+[0xff,0x3f,0x02,0x9a]
+# CHECK: addpt sp, sp, x2, lsl #7
+# NO-CPA: warning: invalid instruction encoding
+
+[0x20,0x20,0x02,0xda]
+# CHECK: subpt x0, x1, x2
+# NO-CPA: warning: invalid instruction encoding
+
+[0xff,0x23,0x02,0xda]
+# CHECK: subpt sp, sp, x2
+# NO-CPA: warning: invalid instruction encoding
+
+[0x20,0x3c,0x02,0xda]
+# CHECK: subpt x0, x1, x2, lsl #7
+# NO-CPA: warning: invalid instruction encoding
+
+[0xff,0x3f,0x02,0xda]
+# CHECK: subpt sp, sp, x2, lsl #7
+# NO-CPA: warning: invalid instruction encoding
+
+[0x20,0x0c,0x62,0x9b]
+# CHECK: maddpt x0, x1, x2, x3
+# NO-CPA: warning: invalid instruction encoding
+
+[0x20,0x8c,0x62,0x9b]
+# CHECK: msubpt x0, x1, x2, x3
+# NO-CPA: warning: invalid instruction encoding
diff --git a/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt b/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt
index 55e4acc..c76bb0b 100644
--- a/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt
+++ b/llvm/test/MC/Disassembler/AArch64/basic-a64-instructions.txt
@@ -3565,6 +3565,7 @@
# CHECK: mrs x9, {{id_aa64isar0_el1|ID_AA64ISAR0_EL1}}
# CHECK: mrs x9, {{id_aa64isar1_el1|ID_AA64ISAR1_EL1}}
# CHECK: mrs x9, {{id_aa64isar2_el1|ID_AA64ISAR2_EL1}}
+# CHECK: mrs x9, {{id_aa64isar2_el1|ID_AA64ISAR3_EL1}}
# CHECK: mrs x9, {{id_aa64mmfr0_el1|ID_AA64MMFR0_EL1}}
# CHECK: mrs x9, {{id_aa64mmfr1_el1|ID_AA64MMFR1_EL1}}
# CHECK: mrs x9, {{id_aa64mmfr2_el1|ID_AA64MMFR2_EL1}}
@@ -4188,6 +4189,7 @@
0x9 0x6 0x38 0xd5
0x29 0x6 0x38 0xd5
0x49 0x06 0x38 0xd5
+0x69 0x06 0x38 0xd5
0x9 0x7 0x38 0xd5
0x29 0x7 0x38 0xd5
0x49 0x7 0x38 0xd5
diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index e2b9712..30e60ad 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1811,7 +1811,8 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
AArch64::AEK_SSVE_FP8DOT2, AArch64::AEK_FP8DOT4,
AArch64::AEK_SSVE_FP8DOT4, AArch64::AEK_LUT,
AArch64::AEK_SME_LUTv2, AArch64::AEK_SMEF8F16,
- AArch64::AEK_SMEF8F32, AArch64::AEK_SMEFA64};
+ AArch64::AEK_SMEF8F32, AArch64::AEK_SMEFA64,
+ AArch64::AEK_CPA};
std::vector<StringRef> Features;
@@ -1897,6 +1898,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
EXPECT_TRUE(llvm::is_contained(Features, "+sme-f8f16"));
EXPECT_TRUE(llvm::is_contained(Features, "+sme-f8f32"));
EXPECT_TRUE(llvm::is_contained(Features, "+sme-fa64"));
+ EXPECT_TRUE(llvm::is_contained(Features, "+cpa"));
// Assuming we listed every extension above, this should produce the same
// result. (note that AEK_NONE doesn't have a name so it won't be in the