diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td +++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td @@ -711,6 +711,32 @@ //===----- END: v8.1a atomic CASP register operands -----------------------===// +//===----------------------------------------------------------------------===// +// Armv8.7a accelerator extension register operands: 8 consecutive GPRs +// starting with an even one + +let Namespace = "AArch64" in { + foreach i = 0-7 in + def "x8sub_"#i : SubRegIndex<64, !mul(64, i)>; +} + +def Tuples8X : RegisterTuples< + !foreach(i, [0,1,2,3,4,5,6,7], !cast("x8sub_"#i)), + !foreach(i, [0,1,2,3,4,5,6,7], (trunc (decimate (rotl GPR64, i), 2), 12))>; + +def GPR64x8Class : RegisterClass<"AArch64", [i64], 64, (trunc Tuples8X, 12)>; +def GPR64x8AsmOp : AsmOperandClass { + let Name = "GPR64x8"; + let ParserMethod = "tryParseGPR64x8"; + let RenderMethod = "addRegOperands"; +} +def GPR64x8 : RegisterOperand { + let ParserMatchClass = GPR64x8AsmOp; + let PrintMethod = "printGPR64x8"; +} + +//===----- END: v8.7a accelerator extension register operands -------------===// + // SVE predicate registers def P0 : AArch64Reg<0, "p0">, DwarfRegNum<[48]>; def P1 : AArch64Reg<1, "p1">, DwarfRegNum<[49]>; diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -257,6 +257,7 @@ OperandMatchResultTy tryParseVectorList(OperandVector &Operands, bool ExpectMatch = false); OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands); + OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands); public: enum AArch64MatchResultTy { @@ -1170,6 +1171,12 @@ AArch64MCRegisterClasses[AArch64::GPR32RegClassID].contains(Reg.RegNum); } + bool isGPR64x8() const { + return Kind == k_Register && Reg.Kind == RegKind::Scalar && + AArch64MCRegisterClasses[AArch64::GPR64x8ClassRegClassID].contains( + Reg.RegNum); + } + bool isWSeqPair() const { return Kind == k_Register && Reg.Kind == RegKind::Scalar && AArch64MCRegisterClasses[AArch64::WSeqPairsClassRegClassID].contains( @@ -6291,3 +6298,26 @@ return MatchOperand_Success; } + +OperandMatchResultTy +AArch64AsmParser::tryParseGPR64x8(OperandVector &Operands) { + SMLoc SS = getLoc(); + + unsigned XReg; + if (tryParseScalarRegister(XReg) != MatchOperand_Success) + return MatchOperand_NoMatch; + + MCContext &ctx = getContext(); + const MCRegisterInfo *RI = ctx.getRegisterInfo(); + int X8Reg = RI->getMatchingSuperReg( + XReg, AArch64::x8sub_0, + &AArch64MCRegisterClasses[AArch64::GPR64x8ClassRegClassID]); + if (!X8Reg) { + Error(SS, "expected an even-numbered x-register in the range [x0,x22]"); + return MatchOperand_ParseFail; + } + + Operands.push_back( + AArch64Operand::CreateReg(X8Reg, RegKind::Scalar, SS, getLoc(), ctx)); + return MatchOperand_Success; +} diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp --- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -62,6 +62,10 @@ static DecodeStatus DecodeGPR64RegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeGPR64x8ClassRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder); static DecodeStatus DecodeGPR64spRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder); @@ -457,6 +461,34 @@ return Success; } +static const unsigned GPR64x8DecoderTable[] = { + AArch64::X0_X1_X2_X3_X4_X5_X6_X7, + AArch64::X2_X3_X4_X5_X6_X7_X8_X9, + AArch64::X4_X5_X6_X7_X8_X9_X10_X11, + AArch64::X6_X7_X8_X9_X10_X11_X12_X13, + AArch64::X8_X9_X10_X11_X12_X13_X14_X15, + AArch64::X10_X11_X12_X13_X14_X15_X16_X17, + AArch64::X12_X13_X14_X15_X16_X17_X18_X19, + AArch64::X14_X15_X16_X17_X18_X19_X20_X21, + AArch64::X16_X17_X18_X19_X20_X21_X22_X23, + AArch64::X18_X19_X20_X21_X22_X23_X24_X25, + AArch64::X20_X21_X22_X23_X24_X25_X26_X27, +}; + +static DecodeStatus DecodeGPR64x8ClassRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 22) + return Fail; + if (RegNo & 1) + return Fail; + + unsigned Register = GPR64x8DecoderTable[RegNo >> 1]; + Inst.addOperand(MCOperand::createReg(Register)); + return Success; +} + static DecodeStatus DecodeGPR64spRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Addr, const void *Decoder) { diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h @@ -190,6 +190,8 @@ const MCSubtargetInfo &STI, raw_ostream &O); void printGPR64as32(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + void printGPR64x8(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, raw_ostream &O); template void printZPRasFPR(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp @@ -1644,3 +1644,10 @@ unsigned Reg = MI->getOperand(OpNum).getReg(); O << getRegisterName(getWRegFromXReg(Reg)); } + +void AArch64InstPrinter::printGPR64x8(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + unsigned Reg = MI->getOperand(OpNum).getReg(); + O << getRegisterName(MRI.getSubReg(Reg, AArch64::x8sub_0)); +}