From 5f7a8cf026a6ad4af484e43ac32b7e0c5f14e079 Mon Sep 17 00:00:00 2001 From: David Sherwood Date: Tue, 25 Oct 2022 15:56:40 +0000 Subject: [PATCH] [AArch64][SVE2] Add the SVE2.1 cntp instruction This patch adds the assembly/disassembly for the following instructions: cntp : Set scalar to count from predicate-as-counter The reference can be found here: https://developer.arm.com/documentation/ddi0602/2022-09 Differential Revision: https://reviews.llvm.org/D136747 --- llvm/lib/Target/AArch64/AArch64RegisterInfo.td | 15 +++ llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td | 1 + llvm/lib/Target/AArch64/AArch64SystemOperands.td | 16 +++ .../Target/AArch64/AsmParser/AArch64AsmParser.cpp | 48 +++++++++ .../AArch64/MCTargetDesc/AArch64InstPrinter.cpp | 15 +++ .../AArch64/MCTargetDesc/AArch64InstPrinter.h | 2 + llvm/lib/Target/AArch64/SVEInstrFormats.td | 43 ++++++++ llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp | 7 ++ llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h | 9 ++ llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s | 26 +++++ llvm/test/MC/AArch64/SVE2p1/cntp.s | 110 +++++++++++++++++++++ 11 files changed, 292 insertions(+) create mode 100644 llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s create mode 100644 llvm/test/MC/AArch64/SVE2p1/cntp.s diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td index 544d2e0..155a7c1 100644 --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td @@ -918,6 +918,21 @@ class PNRAsmOperand let ParserMethod = "tryParseSVEPredicateVector"; } +class PNRRegOp + : PPRRegOp { + let PrintMethod = "printPredicateAsCounter<" # EltSize # ">"; +} + +def PNRAsmOp8 : PNRAsmOperand<"PNPredicateB", "PPR", 8>; +def PNRAsmOp16 : PNRAsmOperand<"PNPredicateH", "PPR", 16>; +def PNRAsmOp32 : PNRAsmOperand<"PNPredicateS", "PPR", 32>; +def PNRAsmOp64 : PNRAsmOperand<"PNPredicateD", "PPR", 64>; + +def PNR8 : PNRRegOp<"b", PNRAsmOp8, 8, PPR>; +def PNR16 : PNRRegOp<"h", PNRAsmOp16, 16, PPR>; +def PNR32 : PNRRegOp<"s", PNRAsmOp32, 32, PPR>; +def PNR64 : PNRRegOp<"d", PNRAsmOp64, 64, PPR>; + class PNRP8to15RegOp : PPRRegOp { let PrintMethod = "printPredicateAsCounter<" # EltSize # ">"; diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td index db289c5..2c58734 100644 --- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -3589,6 +3589,7 @@ def UDOT_ZZZ_HtoS : sve2p1_two_way_dot_vv<"udot", 0b1>; def SDOT_ZZZI_HtoS : sve2p1_two_way_dot_vvi<"sdot", 0b0>; def UDOT_ZZZI_HtoS : sve2p1_two_way_dot_vvi<"udot", 0b1>; +defm CNTP_XCI : sve2p1_pcount_pn<"cntp", 0b000>; defm PEXT_PCI : sve2p1_pred_as_ctr_to_mask<"pext">; defm PTRUE_C : sve2p1_ptrue_pn<"ptrue">; diff --git a/llvm/lib/Target/AArch64/AArch64SystemOperands.td b/llvm/lib/Target/AArch64/AArch64SystemOperands.td index f378817..e9338da 100644 --- a/llvm/lib/Target/AArch64/AArch64SystemOperands.td +++ b/llvm/lib/Target/AArch64/AArch64SystemOperands.td @@ -314,6 +314,22 @@ def : SVEPREDPAT<"mul3", 0x1e>; def : SVEPREDPAT<"all", 0x1f>; //===----------------------------------------------------------------------===// +// SVE Predicate-as-counter patterns +//===----------------------------------------------------------------------===// + +class SVEVECLENSPECIFIER encoding> : SearchableTable { + let SearchableFields = ["Name", "Encoding"]; + let EnumValueField = "Encoding"; + + string Name = name; + bits<1> Encoding; + let Encoding = encoding; +} + +def : SVEVECLENSPECIFIER<"vlx2", 0x0>; +def : SVEVECLENSPECIFIER<"vlx4", 0x1>; + +//===----------------------------------------------------------------------===// // Exact FP Immediates. // // These definitions are used to create a lookup table with FP Immediates that diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 0a26e36..c51c9c1 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -273,6 +273,7 @@ private: bool ExpectMatch = false); OperandMatchResultTy tryParseMatrixTileList(OperandVector &Operands); OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands); + OperandMatchResultTy tryParseSVEVecLenSpecifier(OperandVector &Operands); OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands); OperandMatchResultTy tryParseImmRange(OperandVector &Operands); @@ -828,6 +829,18 @@ public: return DiagnosticPredicateTy::NearMatch; } + DiagnosticPredicate isSVEVecLenSpecifier() const { + if (!isImm()) + return DiagnosticPredicateTy::NoMatch; + auto *MCE = dyn_cast(getImm()); + if (!MCE) + return DiagnosticPredicateTy::NoMatch; + int64_t Val = MCE->getValue(); + if (Val >= 0 && Val <= 1) + return DiagnosticPredicateTy::Match; + return DiagnosticPredicateTy::NearMatch; + } + bool isSymbolicUImm12Offset(const MCExpr *Expr) const { AArch64MCExpr::VariantKind ELFRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind; @@ -5657,6 +5670,14 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode, case Match_InvalidSVEPNPredicateAny_p8to15Reg: return Error(Loc, "invalid restricted predicate-as-counter register " "expected pn8..pn15"); + case Match_InvalidSVEPNPredicateBReg: + case Match_InvalidSVEPNPredicateHReg: + case Match_InvalidSVEPNPredicateSReg: + case Match_InvalidSVEPNPredicateDReg: + return Error(Loc, "Invalid predicate register, expected PN in range " + "pn0..pn15 with element suffix."); + case Match_InvalidSVEVecLenSpecifier: + return Error(Loc, "Invalid vector length specifier, expected VLx2 or VLx4"); case Match_InvalidSVEExactFPImmOperandHalfOne: return Error(Loc, "Invalid floating point constant, expected 0.5 or 1.0."); case Match_InvalidSVEExactFPImmOperandHalfTwo: @@ -6226,6 +6247,7 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidZPR_4b64: case Match_InvalidSVEPredicateAnyReg: case Match_InvalidSVEPattern: + case Match_InvalidSVEVecLenSpecifier: case Match_InvalidSVEPredicateBReg: case Match_InvalidSVEPredicateHReg: case Match_InvalidSVEPredicateSReg: @@ -6236,6 +6258,10 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidSVEPNPredicateS_p8to15Reg: case Match_InvalidSVEPNPredicateD_p8to15Reg: case Match_InvalidSVEPNPredicateAny_p8to15Reg: + case Match_InvalidSVEPNPredicateBReg: + case Match_InvalidSVEPNPredicateHReg: + case Match_InvalidSVEPNPredicateSReg: + case Match_InvalidSVEPNPredicateDReg: case Match_InvalidSVEExactFPImmOperandHalfOne: case Match_InvalidSVEExactFPImmOperandHalfTwo: case Match_InvalidSVEExactFPImmOperandZeroOne: @@ -7433,6 +7459,28 @@ AArch64AsmParser::tryParseSVEPattern(OperandVector &Operands) { } OperandMatchResultTy +AArch64AsmParser::tryParseSVEVecLenSpecifier(OperandVector &Operands) { + int64_t Pattern; + SMLoc SS = getLoc(); + const AsmToken &TokE = getTok(); + // Parse the pattern + auto Pat = AArch64SVEVecLenSpecifier::lookupSVEVECLENSPECIFIERByName( + TokE.getString()); + if (!Pat) + return MatchOperand_NoMatch; + + Lex(); + Pattern = Pat->Encoding; + assert(Pattern >= 0 && Pattern <= 1 && "Pattern does not exist"); + + Operands.push_back( + AArch64Operand::CreateImm(MCConstantExpr::create(Pattern, getContext()), + SS, getLoc(), getContext())); + + return MatchOperand_Success; +} + +OperandMatchResultTy AArch64AsmParser::tryParseGPR64x8(OperandVector &Operands) { SMLoc SS = getLoc(); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp index a88d6de..f38ded6 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp @@ -1772,6 +1772,21 @@ void AArch64InstPrinter::printSVEPattern(const MCInst *MI, unsigned OpNum, O << markup(""); } +void AArch64InstPrinter::printSVEVecLenSpecifier(const MCInst *MI, + unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned Val = MI->getOperand(OpNum).getImm(); + // Pattern has only 1 bit + if (Val > 1) + llvm_unreachable("Invalid vector length specifier"); + if (auto Pat = + AArch64SVEVecLenSpecifier::lookupSVEVECLENSPECIFIERByEncoding(Val)) + O << Pat->Name; + else + llvm_unreachable("Invalid vector length specifier"); +} + template void AArch64InstPrinter::printSVERegOp(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h index ab58ac9..7bfb095b 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h @@ -201,6 +201,8 @@ protected: const MCSubtargetInfo &STI, raw_ostream &O); void printSVEPattern(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + void printSVEVecLenSpecifier(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, raw_ostream &O); template void printMatrixTileVector(const MCInst *MI, unsigned OpNum, diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td index 97a26aa..1d9f38a 100644 --- a/llvm/lib/Target/AArch64/SVEInstrFormats.td +++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -34,6 +34,22 @@ def sve_pred_enum : Operand, TImmLeaf, TImmLeaf { + + let PrintMethod = "printSVEVecLenSpecifier"; + let ParserMatchClass = SVEVecLenSpecifierOperand; +} + def SVEPrefetchOperand : AsmOperandClass { let Name = "SVEPrefetch"; let ParserMethod = "tryParsePrefetch"; @@ -9015,3 +9031,30 @@ multiclass sve2p1_mem_cst_si_4z msz, bit n, def : InstAlias(NAME) vector_ty:$Zt, PNRAny_p8to15:$PNg, GPR64sp:$Rn,0), 1>; } + +// SVE predicate count (predicate-as-counter) +class sve2p1_pcount_pn opc, bits<2> sz, PNRRegOp pnrty> + : I<(outs GPR64:$Rd), + (ins pnrty:$PNn, sve_vec_len_specifier_enum:$vl), + mnemonic, "\t$Rd, $PNn, $vl", + "", []>, Sched<[]> { + bits<5> Rd; + bits<4> PNn; + bits<1> vl; + let Inst{31-24} = 0b00100101; + let Inst{23-22} = sz; + let Inst{21-19} = 0b100; + let Inst{18-16} = opc; + let Inst{15-11} = 0b10000; + let Inst{10} = vl; + let Inst{9} = 0b1; + let Inst{8-5} = PNn; + let Inst{4-0} = Rd; +} + +multiclass sve2p1_pcount_pn opc> { + def _B : sve2p1_pcount_pn; + def _H : sve2p1_pcount_pn; + def _S : sve2p1_pcount_pn; + def _D : sve2p1_pcount_pn; +} diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp index 20aec47..3d237be 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -96,6 +96,13 @@ namespace llvm { } namespace llvm { +namespace AArch64SVEVecLenSpecifier { +#define GET_SVEVECLENSPECIFIER_IMPL +#include "AArch64GenSystemOperands.inc" +} // namespace AArch64SVEVecLenSpecifier +} // namespace llvm + +namespace llvm { namespace AArch64ExactFPImm { #define GET_EXACTFPIMM_IMPL #include "AArch64GenSystemOperands.inc" diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h index e893337..391db1d 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -490,6 +490,15 @@ namespace AArch64SVEPredPattern { #include "AArch64GenSystemOperands.inc" } +namespace AArch64SVEVecLenSpecifier { + struct SVEVECLENSPECIFIER { + const char *Name; + uint16_t Encoding; + }; +#define GET_SVEVECLENSPECIFIER_DECL +#include "AArch64GenSystemOperands.inc" +} // namespace AArch64SVEVecLenSpecifier + /// Return the number of active elements for VL1 to VL256 predicate pattern, /// zero for all other patterns. inline unsigned getNumElementsFromSVEPredPattern(unsigned Pattern) { diff --git a/llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s b/llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s new file mode 100644 index 0000000..667a8ae --- /dev/null +++ b/llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s @@ -0,0 +1,26 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2p1 2>&1 < %s | FileCheck %s + +// --------------------------------------------------------------------------// +// Invalid Pattern + +cntp x0, pn0.s, vlx1 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand +// CHECK-NEXT: cntp x0, pn0.s, vlx1 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +// --------------------------------------------------------------------------// +// Invalid use of predicate without suffix + +cntp x0, pn0, vlx2 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid predicate register, expected PN in range pn0..pn15 with element suffix. +// CHECK-NEXT: cntp x0, pn0, vlx2 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +// --------------------------------------------------------------------------// +// Invalid destination register type + +cntp w0, pn0.b, vlx2 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction +// CHECK-NEXT: cntp w0, pn0.b, vlx2 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + diff --git a/llvm/test/MC/AArch64/SVE2p1/cntp.s b/llvm/test/MC/AArch64/SVE2p1/cntp.s new file mode 100644 index 0000000..817c5f0 --- /dev/null +++ b/llvm/test/MC/AArch64/SVE2p1/cntp.s @@ -0,0 +1,110 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2 < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve2p1 < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2 < %s \ +// RUN: | llvm-objdump -d --mattr=+sme2 - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2 < %s \ +// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2 < %s \ +// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \ +// RUN: | llvm-mc -triple=aarch64 -mattr=+sme2 -disassemble -show-encoding \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST + +cntp x0, pn0.h, vlx2 // 00100101-01100000-10000010-00000000 +// CHECK-INST: cntp x0, pn0.h, vlx2 +// CHECK-ENCODING: [0x00,0x82,0x60,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25608200 + +cntp x21, pn10.h, vlx4 // 00100101-01100000-10000111-01010101 +// CHECK-INST: cntp x21, pn10.h, vlx4 +// CHECK-ENCODING: [0x55,0x87,0x60,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25608755 + +cntp x23, pn13.h, vlx4 // 00100101-01100000-10000111-10110111 +// CHECK-INST: cntp x23, pn13.h, vlx4 +// CHECK-ENCODING: [0xb7,0x87,0x60,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 256087b7 + +cntp xzr, pn15.h, vlx4 // 00100101-01100000-10000111-11111111 +// CHECK-INST: cntp xzr, pn15.h, vlx4 +// CHECK-ENCODING: [0xff,0x87,0x60,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 256087ff + +cntp x0, pn0.s, vlx2 // 00100101-10100000-10000010-00000000 +// CHECK-INST: cntp x0, pn0.s, vlx2 +// CHECK-ENCODING: [0x00,0x82,0xa0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25a08200 + +cntp x21, pn10.s, vlx4 // 00100101-10100000-10000111-01010101 +// CHECK-INST: cntp x21, pn10.s, vlx4 +// CHECK-ENCODING: [0x55,0x87,0xa0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25a08755 + +cntp x23, pn13.s, vlx4 // 00100101-10100000-10000111-10110111 +// CHECK-INST: cntp x23, pn13.s, vlx4 +// CHECK-ENCODING: [0xb7,0x87,0xa0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25a087b7 + +cntp xzr, pn15.s, vlx4 // 00100101-10100000-10000111-11111111 +// CHECK-INST: cntp xzr, pn15.s, vlx4 +// CHECK-ENCODING: [0xff,0x87,0xa0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25a087ff + +cntp x0, pn0.d, vlx2 // 00100101-11100000-10000010-00000000 +// CHECK-INST: cntp x0, pn0.d, vlx2 +// CHECK-ENCODING: [0x00,0x82,0xe0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25e08200 + +cntp x21, pn10.d, vlx4 // 00100101-11100000-10000111-01010101 +// CHECK-INST: cntp x21, pn10.d, vlx4 +// CHECK-ENCODING: [0x55,0x87,0xe0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25e08755 + +cntp x23, pn13.d, vlx4 // 00100101-11100000-10000111-10110111 +// CHECK-INST: cntp x23, pn13.d, vlx4 +// CHECK-ENCODING: [0xb7,0x87,0xe0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25e087b7 + +cntp xzr, pn15.d, vlx4 // 00100101-11100000-10000111-11111111 +// CHECK-INST: cntp xzr, pn15.d, vlx4 +// CHECK-ENCODING: [0xff,0x87,0xe0,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25e087ff + +cntp x0, pn0.b, vlx2 // 00100101-00100000-10000010-00000000 +// CHECK-INST: cntp x0, pn0.b, vlx2 +// CHECK-ENCODING: [0x00,0x82,0x20,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25208200 + +cntp x21, pn10.b, vlx4 // 00100101-00100000-10000111-01010101 +// CHECK-INST: cntp x21, pn10.b, vlx4 +// CHECK-ENCODING: [0x55,0x87,0x20,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 25208755 + +cntp x23, pn13.b, vlx4 // 00100101-00100000-10000111-10110111 +// CHECK-INST: cntp x23, pn13.b, vlx4 +// CHECK-ENCODING: [0xb7,0x87,0x20,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 252087b7 + +cntp xzr, pn15.b, vlx4 // 00100101-00100000-10000111-11111111 +// CHECK-INST: cntp xzr, pn15.b, vlx4 +// CHECK-ENCODING: [0xff,0x87,0x20,0x25] +// CHECK-ERROR: instruction requires: sme2 or sve2p1 +// CHECK-UNKNOWN: 252087ff -- 2.7.4