diff --git a/lib/Target/AArch64/AArch64RegisterInfo.td b/lib/Target/AArch64/AArch64RegisterInfo.td index a9fb0200d80..39e3e33b0d2 100644 --- a/lib/Target/AArch64/AArch64RegisterInfo.td +++ b/lib/Target/AArch64/AArch64RegisterInfo.td @@ -652,6 +652,24 @@ def XSeqPairClassOperand : //===----- END: v8.1a atomic CASP register operands -----------------------===// +// SVE predicate registers +def P0 : AArch64Reg<0, "p0">, DwarfRegNum<[48]>; +def P1 : AArch64Reg<1, "p1">, DwarfRegNum<[49]>; +def P2 : AArch64Reg<2, "p2">, DwarfRegNum<[50]>; +def P3 : AArch64Reg<3, "p3">, DwarfRegNum<[51]>; +def P4 : AArch64Reg<4, "p4">, DwarfRegNum<[52]>; +def P5 : AArch64Reg<5, "p5">, DwarfRegNum<[53]>; +def P6 : AArch64Reg<6, "p6">, DwarfRegNum<[54]>; +def P7 : AArch64Reg<7, "p7">, DwarfRegNum<[55]>; +def P8 : AArch64Reg<8, "p8">, DwarfRegNum<[56]>; +def P9 : AArch64Reg<9, "p9">, DwarfRegNum<[57]>; +def P10 : AArch64Reg<10, "p10">, DwarfRegNum<[58]>; +def P11 : AArch64Reg<11, "p11">, DwarfRegNum<[59]>; +def P12 : AArch64Reg<12, "p12">, DwarfRegNum<[60]>; +def P13 : AArch64Reg<13, "p13">, DwarfRegNum<[61]>; +def P14 : AArch64Reg<14, "p14">, DwarfRegNum<[62]>; +def P15 : AArch64Reg<15, "p15">, DwarfRegNum<[63]>; + // The part of SVE registers that don't overlap Neon registers. // These are only used as part of clobber lists. def Z0_HI : AArch64Reg<0, "z0_hi">; @@ -731,11 +749,43 @@ class SVERegOp : SVERegOp {} class ZPRRegOp : SVERegOp {} //****************************************************************************** +// SVE predicate register class. +def PPR : RegisterClass<"AArch64", + [nxv16i1, nxv8i1, nxv4i1, nxv2i1], + 16, (sequence "P%u", 0, 15)> { + let Size = 16; +} + +class PPRAsmOperand : AsmOperandClass { + let Name = "SVE" # name # "Reg"; + let PredicateMethod = "isSVEVectorRegOfWidth<" + # Width # ", AArch64::PPRRegClassID>"; + let DiagnosticType = "InvalidSVE" # name # "Reg"; + let RenderMethod = "addRegOperands"; + let ParserMethod = "tryParseSVEPredicateVector"; +} + +def PPRAsmOpAny : PPRAsmOperand<"PredicateAny", -1>; +def PPRAsmOp8 : PPRAsmOperand<"PredicateB", 8>; +def PPRAsmOp16 : PPRAsmOperand<"PredicateH", 16>; +def PPRAsmOp32 : PPRAsmOperand<"PredicateS", 32>; +def PPRAsmOp64 : PPRAsmOperand<"PredicateD", 64>; + +def PPRAny : PPRRegOp<"", PPRAsmOpAny, PPR>; +def PPR8 : PPRRegOp<"b", PPRAsmOp8, PPR>; +def PPR16 : PPRRegOp<"h", PPRAsmOp16, PPR>; +def PPR32 : PPRRegOp<"s", PPRAsmOp32, PPR>; +def PPR64 : PPRRegOp<"d", PPRAsmOp64, PPR>; + +//****************************************************************************** + // SVE vector register class def ZPR : RegisterClass<"AArch64", [nxv16i8, nxv8i16, nxv4i32, nxv2i64, @@ -748,7 +798,8 @@ def ZPR : RegisterClass<"AArch64", class ZPRAsmOperand : AsmOperandClass { let Name = "SVE" # name # "Reg"; - let PredicateMethod = "isSVEDataVectorRegOfWidth<" # Width # ">"; + let PredicateMethod = "isSVEVectorRegOfWidth<" + # Width # ", AArch64::ZPRRegClassID>"; let RenderMethod = "addRegOperands"; let ParserMethod = "tryParseSVEDataVector<" # !if(!eq(Width, -1), "false", "true") # ">"; diff --git a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 2763a5b3a90..66d2a5d6a78 100644 --- a/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -59,7 +59,12 @@ using namespace llvm; namespace { -enum class RegKind {Scalar, NeonVector, SVEDataVector}; +enum class RegKind { + Scalar, + NeonVector, + SVEDataVector, + SVEPredicateVector +}; class AArch64AsmParser : public MCTargetAsmParser { private: @@ -134,6 +139,7 @@ private: OperandMatchResultTy tryParseGPRSeqPair(OperandVector &Operands); template OperandMatchResultTy tryParseSVEDataVector(OperandVector &Operands); + OperandMatchResultTy tryParseSVEPredicateVector(OperandVector &Operands); public: enum AArch64MatchResultTy { @@ -826,14 +832,26 @@ public: Reg.RegNum); } - template - bool isSVEDataVectorReg() const { - return (Kind == k_Register && Reg.Kind == RegKind::SVEDataVector) && + template bool isSVEVectorReg() const { + RegKind RK; + switch (Class) { + case AArch64::ZPRRegClassID: + RK = RegKind::SVEDataVector; + break; + case AArch64::PPRRegClassID: + RK = RegKind::SVEPredicateVector; + break; + default: + llvm_unreachable("Unsupport register class"); + } + + return (Kind == k_Register && Reg.Kind == RK) && AArch64MCRegisterClasses[Class].contains(getReg()); } - template bool isSVEDataVectorRegOfWidth() const { - return isSVEDataVectorReg() && + template + bool isSVEVectorRegOfWidth() const { + return isSVEVectorReg() && (ElementWidth == -1 || Reg.ElementWidth == ElementWidth); } @@ -1926,6 +1944,27 @@ static unsigned matchSVEDataVectorRegName(StringRef Name) { .Default(0); } +static unsigned matchSVEPredicateVectorRegName(StringRef Name) { + return StringSwitch(Name.lower()) + .Case("p0", AArch64::P0) + .Case("p1", AArch64::P1) + .Case("p2", AArch64::P2) + .Case("p3", AArch64::P3) + .Case("p4", AArch64::P4) + .Case("p5", AArch64::P5) + .Case("p6", AArch64::P6) + .Case("p7", AArch64::P7) + .Case("p8", AArch64::P8) + .Case("p9", AArch64::P9) + .Case("p10", AArch64::P10) + .Case("p11", AArch64::P11) + .Case("p12", AArch64::P12) + .Case("p13", AArch64::P13) + .Case("p14", AArch64::P14) + .Case("p15", AArch64::P15) + .Default(0); +} + static bool isValidSVEKind(StringRef Name) { return StringSwitch(Name.lower()) .Case(".b", true) @@ -1936,8 +1975,8 @@ static bool isValidSVEKind(StringRef Name) { .Default(false); } -static bool isSVEDataVectorRegister(StringRef Name) { - return Name[0] == 'z'; +static bool isSVERegister(StringRef Name) { + return Name[0] == 'z' || Name[0] == 'p'; } static void parseValidVectorKind(StringRef Name, unsigned &NumElements, @@ -1980,6 +2019,9 @@ unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name, case RegKind::SVEDataVector: RegNum = matchSVEDataVectorRegName(Name); break; + case RegKind::SVEPredicateVector: + RegNum = matchSVEPredicateVectorRegName(Name); + break; } if (!RegNum) { @@ -2007,7 +2049,7 @@ int AArch64AsmParser::tryParseRegister() { return -1; std::string lowerCase = Tok.getString().lower(); - if (isSVEDataVectorRegister(lowerCase)) + if (isSVERegister(lowerCase)) return -1; unsigned RegNum = matchRegisterNameAlias(lowerCase, RegKind::Scalar); @@ -2742,6 +2784,36 @@ AArch64AsmParser::tryParseSVERegister(int &Reg, StringRef &Kind, return MatchOperand_NoMatch; } +/// tryParseSVEPredicateVector - Parse a SVE predicate register operand. +OperandMatchResultTy +AArch64AsmParser::tryParseSVEPredicateVector(OperandVector &Operands) { + // Check for a SVE predicate register specifier first. + const SMLoc S = getLoc(); + StringRef Kind; + int RegNum = -1; + auto Res = tryParseSVERegister(RegNum, Kind, RegKind::SVEPredicateVector); + if (Res != MatchOperand_Success) + return Res; + + unsigned ElementWidth = StringSwitch(Kind.lower()) + .Case("", -1) + .Case(".b", 8) + .Case(".h", 16) + .Case(".s", 32) + .Case(".d", 64) + .Case(".q", 128) + .Default(0); + + if (!ElementWidth) + return MatchOperand_NoMatch; + + Operands.push_back( + AArch64Operand::CreateReg(RegNum, RegKind::SVEPredicateVector, + ElementWidth, S, getLoc(), getContext())); + + return MatchOperand_Success; +} + /// parseRegister - Parse a non-vector register operand. bool AArch64AsmParser::parseRegister(OperandVector &Operands) { SMLoc S = getLoc(); @@ -3575,6 +3647,12 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode, ComputeAvailableFeatures(STI->getFeatureBits())); return Error(Loc, "unrecognized instruction mnemonic" + Suggestion); } + case Match_InvalidSVEPredicateAnyReg: + case Match_InvalidSVEPredicateBReg: + case Match_InvalidSVEPredicateHReg: + case Match_InvalidSVEPredicateSReg: + case Match_InvalidSVEPredicateDReg: + return Error(Loc, "invalid predicate register."); default: llvm_unreachable("unexpected error code!"); } @@ -3974,6 +4052,11 @@ bool AArch64AsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, case Match_InvalidLabel: case Match_InvalidComplexRotationEven: case Match_InvalidComplexRotationOdd: + case Match_InvalidSVEPredicateAnyReg: + case Match_InvalidSVEPredicateBReg: + case Match_InvalidSVEPredicateHReg: + case Match_InvalidSVEPredicateSReg: + case Match_InvalidSVEPredicateDReg: case Match_MSR: case Match_MRS: { if (ErrorInfo >= Operands.size()) @@ -4324,6 +4407,20 @@ bool AArch64AsmParser::parseDirectiveReq(StringRef Name, SMLoc L) { "sve vector register without type specifier expected"); } + if (RegNum == -1) { + StringRef Kind; + RegisterKind = RegKind::SVEPredicateVector; + OperandMatchResultTy Res = + tryParseSVERegister(RegNum, Kind, RegKind::SVEPredicateVector); + + if (Res == MatchOperand_ParseFail) + return true; + + if (Res == MatchOperand_Success && !Kind.empty()) + return Error(SRegLoc, + "sve predicate register without type specifier expected"); + } + if (RegNum == -1) return Error(SRegLoc, "register name or alias expected"); diff --git a/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp index aea1b4f2d2c..ae278caeda6 100644 --- a/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -88,6 +88,9 @@ static DecodeStatus DecodeDDDDRegisterClass(MCInst &Inst, unsigned RegNo, static DecodeStatus DecodeZPRRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decode); +static DecodeStatus DecodePPRRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, + const void *Decode); static DecodeStatus DecodeFixedPointScaleImm32(MCInst &Inst, unsigned Imm, uint64_t Address, @@ -461,6 +464,23 @@ static DecodeStatus DecodeZPRRegisterClass(MCInst &Inst, unsigned RegNo, return Success; } +static const unsigned PPRDecoderTable[] = { + AArch64::P0, AArch64::P1, AArch64::P2, AArch64::P3, + AArch64::P4, AArch64::P5, AArch64::P6, AArch64::P7, + AArch64::P8, AArch64::P9, AArch64::P10, AArch64::P11, + AArch64::P12, AArch64::P13, AArch64::P14, AArch64::P15 +}; + +static DecodeStatus DecodePPRRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Addr, const void *Decoder) { + if (RegNo > 15) + return Fail; + + unsigned Register = PPRDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Register)); + return Success; +} + static const unsigned VectorDecoderTable[] = { AArch64::Q0, AArch64::Q1, AArch64::Q2, AArch64::Q3, AArch64::Q4, AArch64::Q5, AArch64::Q6, AArch64::Q7, AArch64::Q8, AArch64::Q9, diff --git a/test/MC/AArch64/SVE/dot-req-diagnostics.s b/test/MC/AArch64/SVE/dot-req-diagnostics.s new file mode 100644 index 00000000000..c6626940907 --- /dev/null +++ b/test/MC/AArch64/SVE/dot-req-diagnostics.s @@ -0,0 +1,20 @@ +// RUN: not llvm-mc -triple aarch64-none-linux-gnu -mattr=+sve < %s 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-ERROR %s + +foo: +// CHECK: error: sve predicate register without type specifier expected + pbarb .req p1.b +// CHECK: error: sve predicate register without type specifier expected + pbarh .req p1.h +// CHECK: error: sve predicate register without type specifier expected + pbars .req p1.s +// CHECK: error: sve predicate register without type specifier expected + pbard .req p1.d + +// CHECK: error: sve vector register without type specifier expected + zbarb .req z1.b +// CHECK: error: sve vector register without type specifier expected + zbarh .req z1.h +// CHECK: error: sve vector register without type specifier expected + zbars .req z1.s +// CHECK: error: sve vector register without type specifier expected + zbard .req z1.d diff --git a/test/MC/AArch64/SVE/dot-req.s b/test/MC/AArch64/SVE/dot-req.s new file mode 100644 index 00000000000..9bec12a6e61 --- /dev/null +++ b/test/MC/AArch64/SVE/dot-req.s @@ -0,0 +1,9 @@ +// RUN: llvm-mc -triple=aarch64-none-linux-gnu -mattr=+sve -show-encoding < %s 2>&1 | FileCheck %s + +foo: +// CHECK-NOT: error: + pbar .req p1 + +// CHECK: add z0.s, z1.s, z2.s + zbar .req z1 + add z0.s, zbar.s, z2.s