diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64RegisterInfo.td | 53 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td | 6 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp | 114 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp | 20 | ||||
-rw-r--r-- | llvm/lib/Target/AArch64/SVEInstrFormats.td | 62 |
5 files changed, 247 insertions, 8 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td index a9fb0200d80..39e3e33b0d2 100644 --- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td +++ b/llvm/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 <string Suffix, AsmOperandClass C, let ParserMatchClass = C; } +class PPRRegOp <string Suffix, AsmOperandClass C, + RegisterClass RC> : SVERegOp<Suffix, C, RC> {} class ZPRRegOp <string Suffix, AsmOperandClass C, RegisterClass RC> : SVERegOp<Suffix, C, RC> {} //****************************************************************************** +// SVE predicate register class. +def PPR : RegisterClass<"AArch64", + [nxv16i1, nxv8i1, nxv4i1, nxv2i1], + 16, (sequence "P%u", 0, 15)> { + let Size = 16; +} + +class PPRAsmOperand <string name, int Width>: 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 <string name, int Width>: 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/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td index 7da0b28d22d..bcd7b60875a 100644 --- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -14,4 +14,10 @@ let Predicates = [HasSVE] in { defm ADD_ZZZ : sve_int_bin_cons_arit_0<0b000, "add">; defm SUB_ZZZ : sve_int_bin_cons_arit_0<0b001, "sub">; + + defm ZIP1_ZZZ : sve_int_perm_bin_perm_zz<0b000, "zip1">; + defm ZIP2_ZZZ : sve_int_perm_bin_perm_zz<0b001, "zip2">; + + defm ZIP1_PPP : sve_int_perm_bin_perm_pp<0b000, "zip1">; + defm ZIP2_PPP : sve_int_perm_bin_perm_pp<0b001, "zip2">; } diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 83764aab905..6e63783e564 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/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 <bool ParseSuffix> OperandMatchResultTy tryParseSVEDataVector(OperandVector &Operands); + OperandMatchResultTy tryParseSVEPredicateVector(OperandVector &Operands); public: enum AArch64MatchResultTy { @@ -826,14 +832,26 @@ public: Reg.RegNum); } - template <unsigned Class = AArch64::ZPRRegClassID> - bool isSVEDataVectorReg() const { - return (Kind == k_Register && Reg.Kind == RegKind::SVEDataVector) && + template <unsigned Class> 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 <int ElementWidth> bool isSVEDataVectorRegOfWidth() const { - return isSVEDataVectorReg() && + template <int ElementWidth, unsigned Class> + bool isSVEVectorRegOfWidth() const { + return isSVEVectorReg<Class>() && (ElementWidth == -1 || Reg.ElementWidth == ElementWidth); } @@ -1926,6 +1944,27 @@ static unsigned matchSVEDataVectorRegName(StringRef Name) { .Default(0); } +static unsigned matchSVEPredicateVectorRegName(StringRef Name) { + return StringSwitch<unsigned>(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<bool>(Name.lower()) .Case(".b", true) @@ -1969,6 +2008,9 @@ unsigned AArch64AsmParser::matchRegisterNameAlias(StringRef Name, if ((RegNum = matchSVEDataVectorRegName(Name))) return Kind == RegKind::SVEDataVector ? RegNum : 0; + if ((RegNum = matchSVEPredicateVectorRegName(Name))) + return Kind == RegKind::SVEPredicateVector ? RegNum : 0; + if ((RegNum = MatchNeonVectorRegName(Name))) return Kind == RegKind::NeonVector ? RegNum : 0; @@ -2734,6 +2776,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<unsigned>(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(); @@ -2954,9 +3026,12 @@ AArch64AsmParser::tryParseGPR64sp0Operand(OperandVector &Operands) { bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode, bool invertCondCode) { MCAsmParser &Parser = getParser(); + + OperandMatchResultTy ResTy = + MatchOperandParserImpl(Operands, Mnemonic, /*ParseForAllFeatures=*/ true); + // Check if the current operand has a custom associated parser, if so, try to // custom parse the operand, or fallback to the general approach. - OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic); if (ResTy == MatchOperand_Success) return false; // If there wasn't a custom match, try the generic matcher below. Otherwise, @@ -3567,6 +3642,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!"); } @@ -3991,6 +4072,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()) @@ -4341,6 +4427,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/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp index aea1b4f2d2c..ae278caeda6 100644 --- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/llvm/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/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td index b4b46d731e3..15c1275f259 100644 --- a/llvm/lib/Target/AArch64/SVEInstrFormats.td +++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -39,3 +39,65 @@ multiclass sve_int_bin_cons_arit_0<bits<3> opc, string asm> { def _S : sve_int_bin_cons_arit_0<0b10, opc, asm, ZPR32>; def _D : sve_int_bin_cons_arit_0<0b11, opc, asm, ZPR64>; } + +//===----------------------------------------------------------------------===// +// SVE Permute - In Lane Group +//===----------------------------------------------------------------------===// + +class sve_int_perm_bin_perm_zz<bits<3> opc, bits<2> sz8_64, string asm, + ZPRRegOp zprty> +: I<(outs zprty:$Zd), (ins zprty:$Zn, zprty:$Zm), + asm, "\t$Zd, $Zn, $Zm", + "", + []>, Sched<[]> { + bits<5> Zd; + bits<5> Zm; + bits<5> Zn; + let Inst{31-24} = 0b00000101; + let Inst{23-22} = sz8_64; + let Inst{21} = 0b1; + let Inst{20-16} = Zm; + let Inst{15-13} = 0b011; + let Inst{12-10} = opc; + let Inst{9-5} = Zn; + let Inst{4-0} = Zd; +} + +multiclass sve_int_perm_bin_perm_zz<bits<3> opc, string asm> { + def _B : sve_int_perm_bin_perm_zz<opc, 0b00, asm, ZPR8>; + def _H : sve_int_perm_bin_perm_zz<opc, 0b01, asm, ZPR16>; + def _S : sve_int_perm_bin_perm_zz<opc, 0b10, asm, ZPR32>; + def _D : sve_int_perm_bin_perm_zz<opc, 0b11, asm, ZPR64>; +} + +//===----------------------------------------------------------------------===// +// SVE Permute - Predicates Group +//===----------------------------------------------------------------------===// + +class sve_int_perm_bin_perm_pp<bits<3> opc, bits<2> sz8_64, string asm, + PPRRegOp pprty> +: I<(outs pprty:$Pd), (ins pprty:$Pn, pprty:$Pm), + asm, "\t$Pd, $Pn, $Pm", + "", + []>, Sched<[]> { + bits<4> Pd; + bits<4> Pm; + bits<4> Pn; + let Inst{31-24} = 0b00000101; + let Inst{23-22} = sz8_64; + let Inst{21-20} = 0b10; + let Inst{19-16} = Pm; + let Inst{15-13} = 0b010; + let Inst{12-10} = opc; + let Inst{9} = 0b0; + let Inst{8-5} = Pn; + let Inst{4} = 0b0; + let Inst{3-0} = Pd; +} + +multiclass sve_int_perm_bin_perm_pp<bits<3> opc, string asm> { + def _B : sve_int_perm_bin_perm_pp<opc, 0b00, asm, PPR8>; + def _H : sve_int_perm_bin_perm_pp<opc, 0b01, asm, PPR16>; + def _S : sve_int_perm_bin_perm_pp<opc, 0b10, asm, PPR32>; + def _D : sve_int_perm_bin_perm_pp<opc, 0b11, asm, PPR64>; +}
\ No newline at end of file |