mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
[AArch64][SVE] Asm: Add SVE predicate register definitions and parsing support
Summary: Patch [1/4] in a series to add parsing of predicates and properly parse SVE ZIP1/ZIP2 instructions. Reviewers: rengolin, kristof.beyls, fhahn, mcrosier, evandro, echristo, efriedma Reviewed By: fhahn Subscribers: aemerson, javed.absar, llvm-commits, tschuett Differential Revision: https://reviews.llvm.org/D40360 llvm-svn: 319315
This commit is contained in:
parent
ded22a182d
commit
a1e07e5345
@ -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") # ">";
|
||||
|
@ -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)
|
||||
@ -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<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();
|
||||
@ -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");
|
||||
|
||||
|
@ -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,
|
||||
|
20
test/MC/AArch64/SVE/dot-req-diagnostics.s
Normal file
20
test/MC/AArch64/SVE/dot-req-diagnostics.s
Normal file
@ -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
|
9
test/MC/AArch64/SVE/dot-req.s
Normal file
9
test/MC/AArch64/SVE/dot-req.s
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user