Index: llvm/lib/Target/AArch64/AArch64RegisterInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64RegisterInfo.td +++ llvm/lib/Target/AArch64/AArch64RegisterInfo.td @@ -918,6 +918,21 @@ let ParserMethod = "tryParseSVEPredicateAsCounter"; } +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 # ">"; Index: llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td =================================================================== --- llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -3587,6 +3587,7 @@ 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">; defm PEXT_PCI : sve2p1_pred_as_ctr_to_mask<"pext">; defm PTRUE_C : sve2p1_ptrue_pn<"ptrue">; Index: llvm/lib/Target/AArch64/AArch64SystemOperands.td =================================================================== --- llvm/lib/Target/AArch64/AArch64SystemOperands.td +++ llvm/lib/Target/AArch64/AArch64SystemOperands.td @@ -313,6 +313,22 @@ def : SVEPREDPAT<"mul3", 0x1e>; def : SVEPREDPAT<"all", 0x1f>; +//===----------------------------------------------------------------------===// +// SVE Predicate-as-counter patterns +//===----------------------------------------------------------------------===// + +class SVEPREDCNTPAT encoding> : SearchableTable { + let SearchableFields = ["Name", "Encoding"]; + let EnumValueField = "Encoding"; + + string Name = name; + bits<1> Encoding; + let Encoding = encoding; +} + +def : SVEPREDCNTPAT<"vlx2", 0x0>; +def : SVEPREDCNTPAT<"vlx4", 0x1>; + //===----------------------------------------------------------------------===// // Exact FP Immediates. // Index: llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -273,6 +273,8 @@ bool ExpectMatch = false); OperandMatchResultTy tryParseMatrixTileList(OperandVector &Operands); OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands); + template + OperandMatchResultTy tryParseSVECntPattern(OperandVector &Operands); OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands); OperandMatchResultTy tryParseImmRange(OperandVector &Operands); @@ -828,6 +830,18 @@ return DiagnosticPredicateTy::NearMatch; } + template DiagnosticPredicate isSVECntPattern() 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 << NumBits)) + return DiagnosticPredicateTy::Match; + return DiagnosticPredicateTy::NearMatch; + } + bool isSymbolicUImm12Offset(const MCExpr *Expr) const { AArch64MCExpr::VariantKind ELFRefKind; MCSymbolRefExpr::VariantKind DarwinRefKind; @@ -5690,6 +5704,16 @@ case Match_InvalidSVEPNPredicateAny_p8to15Reg: return Error(Loc, "invalid restricted predicate-as-counter register " "expected pn8..pn15"); + case Match_InvalidSVEPNPredicateBReg: + return Error(Loc, "Invalid predicate register. Expected pn0.b..pn15.b"); + case Match_InvalidSVEPNPredicateHReg: + return Error(Loc, "Invalid predicate register. Expected pn0.h..pn15.h"); + case Match_InvalidSVEPNPredicateSReg: + return Error(Loc, "Invalid predicate register. Expected pn0.s..pn15.s"); + case Match_InvalidSVEPNPredicateDReg: + return Error(Loc, "Invalid predicate register. Expected pn0.d..pn15.d"); + case Match_InvalidSVECntPattern: + return Error(Loc, "Invalid predicate-as-counter pattern"); case Match_InvalidSVEExactFPImmOperandHalfOne: return Error(Loc, "Invalid floating point constant, expected 0.5 or 1.0."); case Match_InvalidSVEExactFPImmOperandHalfTwo: @@ -6257,6 +6281,7 @@ case Match_InvalidZPR_4b64: case Match_InvalidSVEPredicateAnyReg: case Match_InvalidSVEPattern: + case Match_InvalidSVECntPattern: case Match_InvalidSVEPredicateBReg: case Match_InvalidSVEPredicateHReg: case Match_InvalidSVEPredicateSReg: @@ -6267,6 +6292,10 @@ 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: @@ -7463,6 +7492,31 @@ return MatchOperand_Success; } +template +OperandMatchResultTy +AArch64AsmParser::tryParseSVECntPattern(OperandVector &Operands) { + MCAsmParser &Parser = getParser(); + int64_t Pattern; + SMLoc SS = getLoc(); + const AsmToken &TokE = Parser.getTok(); + // Parse the pattern + auto Pat = + AArch64SVEPredCntPattern::lookupSVEPREDCNTPATByName(TokE.getString()); + if (!Pat) + return MatchOperand_NoMatch; + + Parser.Lex(); + Pattern = Pat->Encoding; + assert(Pattern >= 0 && Pattern < (1 << NumBits) && "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(); Index: llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h =================================================================== --- llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h +++ llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h @@ -201,6 +201,9 @@ const MCSubtargetInfo &STI, raw_ostream &O); void printSVEPattern(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + template + void printSVECntPattern(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, raw_ostream &O); template void printMatrixTileVector(const MCInst *MI, unsigned OpNum, Index: llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp =================================================================== --- llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp +++ llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp @@ -1772,6 +1772,22 @@ O << markup(""); } +template +void AArch64InstPrinter::printSVECntPattern(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned Val = MI->getOperand(OpNum).getImm(); + // Pattern has only 1 bit + if (NumBits == 1) { + if (Val > 1) + llvm_unreachable("Invalid Pattern"); + } + if (auto Pat = AArch64SVEPredCntPattern::lookupSVEPREDCNTPATByEncoding(Val)) + O << Pat->Name; + else + llvm_unreachable("Invalid Pattern"); +} + template void AArch64InstPrinter::printSVERegOp(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, Index: llvm/lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- llvm/lib/Target/AArch64/SVEInstrFormats.td +++ llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -34,6 +34,22 @@ let ParserMatchClass = SVEPatternOperand; } +class SVECntPatternOperand : AsmOperandClass { + let Name = "SVECntPattern" # NumBits; + let ParserMethod = "tryParseSVECntPattern<" # NumBits # ">"; + let PredicateMethod = "isSVECntPattern<" # NumBits # ">"; + let RenderMethod = "addImmOperands"; + let DiagnosticType = "InvalidSVECntPattern"; +} + +def sve_pred_cnt_enum_1b : Operand, TImmLeaf { + + let PrintMethod = "printSVECntPattern<1>"; + let ParserMatchClass = SVECntPatternOperand<1>; +} + def SVEPrefetchOperand : AsmOperandClass { let Name = "SVEPrefetch"; let ParserMethod = "tryParsePrefetch"; @@ -8990,3 +9006,28 @@ def : InstAlias(NAME) vector_ty:$Zt, PNRAny_p8to15:$PNg, GPR64sp:$Rn,0), 1>; } + + +class sve2p1_pcount_pn sz, PNRRegOp pnrty> + : I<(outs GPR64:$Rd), + (ins pnrty:$PNn, sve_pred_cnt_enum_1b:$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-11} = 0b10000010000; + let Inst{10} = vl; + let Inst{9} = 0b1; + let Inst{8-5} = PNn; + let Inst{4-0} = Rd; +} + +multiclass sve2p1_pcount_pn { + def _B : sve2p1_pcount_pn; + def _H : sve2p1_pcount_pn; + def _S : sve2p1_pcount_pn; + def _D : sve2p1_pcount_pn; +} Index: llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h =================================================================== --- llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -490,6 +490,15 @@ #include "AArch64GenSystemOperands.inc" } +namespace AArch64SVEPredCntPattern { +struct SVEPREDCNTPAT { + const char *Name; + uint16_t Encoding; +}; +#define GET_SVEPREDCNTPAT_DECL +#include "AArch64GenSystemOperands.inc" +} // namespace AArch64SVEPredCntPattern + /// Return the number of active elements for VL1 to VL256 predicate pattern, /// zero for all other patterns. inline unsigned getNumElementsFromSVEPredPattern(unsigned Pattern) { Index: llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp =================================================================== --- llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp +++ llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.cpp @@ -95,6 +95,13 @@ } } +namespace llvm { +namespace AArch64SVEPredCntPattern { +#define GET_SVEPREDCNTPAT_IMPL +#include "AArch64GenSystemOperands.inc" +} // namespace AArch64SVEPredCntPattern +} + namespace llvm { namespace AArch64ExactFPImm { #define GET_EXACTFPIMM_IMPL Index: llvm/test/MC/AArch64/SVE2p1/cntp-diagnostics.s =================================================================== --- /dev/null +++ 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 pn0.b..pn15.b +// 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]+}}: + Index: llvm/test/MC/AArch64/SVE2p1/cntp.s =================================================================== --- /dev/null +++ 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