[llvm] [LLVM][AArch64] Add assembly/disassembly for SME2p2 ftmopa and bftmopa (PR #112876)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 21 06:57:09 PDT 2024
https://github.com/SpencerAbson updated https://github.com/llvm/llvm-project/pull/112876
>From ee68d1fbb742818a6b3e94448edd787d1c9a26c9 Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Tue, 8 Oct 2024 13:32:12 +0000
Subject: [PATCH 1/7] [LLVM][AArch64] Add register classes for Armv9.6 assembly
Add new register classes/operands and their encoder/decoder behaviour required for the new Armv9.6
instructions (see https://developer.arm.com/documentation/109697/2024_09/Feature-descriptions/The-Armv9-6-architecture-extension).
This work is the basis ofthe 2024 Armv9.6 architecture update effort for SME.
Co-authored-by: Caroline Concatto caroline.concatto at arm.com
Co-authored-by: Marian Lukac marian.lukac at arm.com
Co-authored-by: Momchil Velikov momchil.velikov at arm.com
---
.../lib/Target/AArch64/AArch64RegisterInfo.td | 147 ++++++++++++++----
.../AArch64/AsmParser/AArch64AsmParser.cpp | 108 ++++++++++---
.../Disassembler/AArch64Disassembler.cpp | 41 ++++-
.../MCTargetDesc/AArch64MCCodeEmitter.cpp | 29 +++-
.../AArch64/GlobalISel/regbank-inlineasm.mir | 8 +-
.../emit_fneg_with_non_register_operand.mir | 8 +-
llvm/test/CodeGen/AArch64/fmlal-loreg.ll | 2 +-
.../CodeGen/AArch64/peephole-insvigpr.mir | 4 +-
8 files changed, 280 insertions(+), 67 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index f754c32e1176d1..ed9610edfe8325 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -923,10 +923,9 @@ class ZPRRegOp <string Suffix, AsmOperandClass C, ElementSizeEnum Size,
//******************************************************************************
// SVE predicate register classes.
-class PPRClass<int firstreg, int lastreg> : RegisterClass<
- "AArch64",
+class PPRClass<int firstreg, int lastreg, int step = 1> : RegisterClass<"AArch64",
[ nxv16i1, nxv8i1, nxv4i1, nxv2i1, nxv1i1 ], 16,
- (sequence "P%u", firstreg, lastreg)> {
+ (sequence "P%u", firstreg, lastreg, step)> {
let Size = 16;
}
@@ -940,6 +939,8 @@ def PPR_p8to15 : PPRClass<8, 15> {
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::PNRRegClassID, 8, 8>";
}
+def PPRMul2 : PPRClass<0, 14, 2>;
+
class PPRAsmOperand <string name, string RegClass, int Width>: AsmOperandClass {
let Name = "SVE" # name # "Reg";
let PredicateMethod = "isSVEPredicateVectorRegOfWidth<"
@@ -1098,10 +1099,11 @@ class PPRVectorListMul<int ElementWidth, int NumRegs> : PPRVectorList<ElementWid
let DiagnosticType = "Invalid" # Name;
let PredicateMethod =
"isTypedVectorListMultiple<RegKind::SVEPredicateVector, " # NumRegs # ", 0, "
- # ElementWidth # ">";
+ # ElementWidth #
+ ", AArch64::PPRMul2RegClassID>";
}
-let EncoderMethod = "EncodeRegAsMultipleOf<2>",
+let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 14>",
DecoderMethod = "DecodePPR2Mul2RegisterClass" in {
def PP_b_mul_r : RegisterOperand<PPR2Mul2, "printTypedVectorList<0,'b'>"> {
let ParserMatchClass = PPRVectorListMul<8, 2>;
@@ -1124,23 +1126,28 @@ let EncoderMethod = "EncodeRegAsMultipleOf<2>",
//******************************************************************************
// SVE vector register classes
-class ZPRClass<int lastreg> : RegisterClass<"AArch64",
+class ZPRClass<int firstreg, int lastreg, int step = 1> : RegisterClass<"AArch64",
[nxv16i8, nxv8i16, nxv4i32, nxv2i64,
nxv2f16, nxv4f16, nxv8f16,
nxv2bf16, nxv4bf16, nxv8bf16,
nxv2f32, nxv4f32,
nxv2f64],
- 128, (sequence "Z%u", 0, lastreg)> {
+ 128, (sequence "Z%u", firstreg, lastreg, step)> {
let Size = 128;
}
-def ZPR : ZPRClass<31> {
+def ZPRMul2 : ZPRClass<0, 30, 2>;
+def ZPRMul4 : ZPRClass<0, 28, 4>;
+def ZPRMul2_Lo : ZPRClass<0, 14, 2>;
+def ZPRMul2_Hi : ZPRClass<16, 30, 2>;
+
+def ZPR : ZPRClass<0, 31> {
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPRRegClassID, 0, 32>";
}
-def ZPR_4b : ZPRClass<15> { // Restricted 4 bit SVE vector register class.
+def ZPR_4b : ZPRClass<0, 15> { // Restricted 4 bit SVE vector register class.
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPRRegClassID, 0, 16>";
}
-def ZPR_3b : ZPRClass<7> { // Restricted 3 bit SVE vector register class.
+def ZPR_3b : ZPRClass<0, 7> { // Restricted 3 bit SVE vector register class.
let DecoderMethod = "DecodeSimpleRegisterClass<AArch64::ZPRRegClassID, 0, 8>";
}
@@ -1188,6 +1195,40 @@ def ZPR4b16 : ZPRRegOp<"h", ZPRAsmOp4b16, ElementSizeH, ZPR_4b>;
def ZPR4b32 : ZPRRegOp<"s", ZPRAsmOp4b32, ElementSizeS, ZPR_4b>;
def ZPR4b64 : ZPRRegOp<"d", ZPRAsmOp4b64, ElementSizeD, ZPR_4b>;
+class ZPRMul2_MinToMaxRegOp<string Suffix, AsmOperandClass C, int Min, int Max, ElementSizeEnum Width, RegisterClass RC>
+ : ZPRRegOp<Suffix, C, Width, RC> {
+ let EncoderMethod = "EncodeRegMul_MinMax<2," # Min # ", " # Max # ">";
+ let DecoderMethod = "DecodeZPRMul2_MinMax<" # Min # ", " # Max # ">";
+}
+
+def ZPRMul2AsmOp8_Lo : ZPRAsmOperand<"VectorB_Lo", 8, "Mul2_Lo">;
+def ZPRMul2AsmOp8_Hi : ZPRAsmOperand<"VectorB_Hi", 8, "Mul2_Hi">;
+def ZPRMul2AsmOp16_Lo : ZPRAsmOperand<"VectorH_Lo", 16, "Mul2_Lo">;
+def ZPRMul2AsmOp16_Hi : ZPRAsmOperand<"VectorH_Hi", 16, "Mul2_Hi">;
+def ZPRMul2AsmOp32_Lo : ZPRAsmOperand<"VectorS_Lo", 32, "Mul2_Lo">;
+def ZPRMul2AsmOp32_Hi : ZPRAsmOperand<"VectorS_Hi", 32, "Mul2_Hi">;
+def ZPRMul2AsmOp64_Lo : ZPRAsmOperand<"VectorD_Lo", 64, "Mul2_Lo">;
+def ZPRMul2AsmOp64_Hi : ZPRAsmOperand<"VectorD_Hi", 64, "Mul2_Hi">;
+
+def ZPR_K : RegisterClass<"AArch64", [untyped], 128,
+ (add Z20, Z21, Z22, Z23, Z28, Z29, Z30, Z31)>;
+
+let EncoderMethod = "EncodeZK",
+ DecoderMethod = "DecodeZK" in {
+ def ZK : RegisterOperand<ZPR_K, "printSVERegOp<>">{
+ let ParserMatchClass = ZPRAsmOperand<"Vector_20to23or28to31", 0, "_K">;
+ }
+}
+
+def ZPR8Mul2_Lo : ZPRMul2_MinToMaxRegOp<"b", ZPRMul2AsmOp8_Lo, 0, 14, ElementSizeB, ZPRMul2_Lo>;
+def ZPR8Mul2_Hi : ZPRMul2_MinToMaxRegOp<"b", ZPRMul2AsmOp8_Hi, 16, 30, ElementSizeB, ZPRMul2_Hi>;
+def ZPR16Mul2_Lo : ZPRMul2_MinToMaxRegOp<"h", ZPRMul2AsmOp16_Lo, 0, 14, ElementSizeH, ZPRMul2_Lo>;
+def ZPR16Mul2_Hi : ZPRMul2_MinToMaxRegOp<"h", ZPRMul2AsmOp16_Hi, 16, 30, ElementSizeH, ZPRMul2_Hi>;
+def ZPR32Mul2_Lo : ZPRMul2_MinToMaxRegOp<"s", ZPRMul2AsmOp32_Lo, 0, 14, ElementSizeS, ZPRMul2_Lo>;
+def ZPR32Mul2_Hi : ZPRMul2_MinToMaxRegOp<"s", ZPRMul2AsmOp32_Hi, 16, 30, ElementSizeS, ZPRMul2_Hi>;
+def ZPR64Mul2_Lo : ZPRMul2_MinToMaxRegOp<"d", ZPRMul2AsmOp64_Lo, 0, 14, ElementSizeD, ZPRMul2_Lo>;
+def ZPR64Mul2_Hi : ZPRMul2_MinToMaxRegOp<"d", ZPRMul2AsmOp64_Hi, 16, 30, ElementSizeD, ZPRMul2_Hi>;
+
class FPRasZPR<int Width> : AsmOperandClass{
let Name = "FPR" # Width # "asZPR";
let PredicateMethod = "isFPRasZPR<AArch64::FPR" # Width # "RegClassID>";
@@ -1327,64 +1368,116 @@ def ZPR4Mul4 : RegisterClass<"AArch64", [untyped], 128, (add (decimate ZSeqQuads
let Size = 512;
}
-class ZPRVectorListMul<int ElementWidth, int NumRegs> : ZPRVectorList<ElementWidth, NumRegs> {
- let Name = "SVEVectorListMul" # NumRegs # "x" # ElementWidth;
+class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = "">
+ : ZPRVectorList<ElementWidth, NumRegs> {
+ let Name = "SVEVectorList" # NumRegs # "x" # ElementWidth # RegClassSuffix;
let DiagnosticType = "Invalid" # Name;
let PredicateMethod =
- "isTypedVectorListMultiple<RegKind::SVEDataVector, " # NumRegs # ", 0, "
- # ElementWidth # ">";
+ "isTypedVectorListMultiple<RegKind::SVEDataVector, "
+ # NumRegs # ", 0, "
+ # ElementWidth # ", "
+ # "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
}
-let EncoderMethod = "EncodeRegAsMultipleOf<2>",
+let EncoderMethod = "EncodeRegMul_MinMax<2>",
DecoderMethod = "DecodeZPR2Mul2RegisterClass" in {
def ZZ_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,0>"> {
- let ParserMatchClass = ZPRVectorListMul<0, 2>;
+ let ParserMatchClass = ZPRVectorListMul<0, 2, "Mul2">;
}
def ZZ_b_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'b'>"> {
- let ParserMatchClass = ZPRVectorListMul<8, 2>;
+ let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2">;
}
def ZZ_h_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'h'>"> {
- let ParserMatchClass = ZPRVectorListMul<16, 2>;
+ let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2">;
}
def ZZ_s_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'s'>"> {
- let ParserMatchClass = ZPRVectorListMul<32, 2>;
+ let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2">;
}
def ZZ_d_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'d'>"> {
- let ParserMatchClass = ZPRVectorListMul<64, 2>;
+ let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2">;
}
def ZZ_q_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,'q'>"> {
- let ParserMatchClass = ZPRVectorListMul<128, 2>;
+ let ParserMatchClass = ZPRVectorListMul<128, 2, "Mul2">;
}
} // end let EncoderMethod/DecoderMethod
-let EncoderMethod = "EncodeRegAsMultipleOf<4>",
+let EncoderMethod = "EncodeRegMul_MinMax<4, 0, 28>",
DecoderMethod = "DecodeZPR4Mul4RegisterClass" in {
def ZZZZ_b_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'b'>"> {
- let ParserMatchClass = ZPRVectorListMul<8, 4>;
+ let ParserMatchClass = ZPRVectorListMul<8, 4, "Mul4">;
}
def ZZZZ_h_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'h'>"> {
- let ParserMatchClass = ZPRVectorListMul<16, 4>;
+ let ParserMatchClass = ZPRVectorListMul<16, 4, "Mul4">;
}
def ZZZZ_s_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'s'>"> {
- let ParserMatchClass = ZPRVectorListMul<32, 4>;
+ let ParserMatchClass = ZPRVectorListMul<32, 4, "Mul4">;
}
def ZZZZ_d_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'d'>"> {
- let ParserMatchClass = ZPRVectorListMul<64, 4>;
+ let ParserMatchClass = ZPRVectorListMul<64, 4, "Mul4">;
}
def ZZZZ_q_mul_r : RegisterOperand<ZPR4Mul4, "printTypedVectorList<0,'q'>"> {
- let ParserMatchClass = ZPRVectorListMul<128, 4>;
+ let ParserMatchClass = ZPRVectorListMul<128, 4, "Mul4">;
}
} // end let EncoderMethod/DecoderMethod
+// Pairs of ZPR, sarting with an even register, split into Lo=0-14 and Hi=16-30
+def ZPR2Mul2_Lo : RegisterClass<"AArch64", [untyped], 128,
+ (trunc (decimate ZSeqPairs, 2), 8)> {
+ let Size = 256;
+}
+
+def ZPR2Mul2_Hi : RegisterClass<"AArch64", [untyped], 128,
+ (trunc (rotr (decimate ZSeqPairs, 2), 8), 8)> {
+ let Size = 256;
+}
+
+let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 14>",
+ DecoderMethod = "DecodeZPR2Mul2RegisterClass<0, 16>" in {
+ def ZZ_b_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'b'>"> {
+ let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2_Lo">;
+ }
+
+ def ZZ_h_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'h'>"> {
+ let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2_Lo">;
+ }
+
+ def ZZ_s_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'s'>"> {
+ let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2_Lo">;
+ }
+
+ def ZZ_d_mul_r_Lo : RegisterOperand<ZPR2Mul2_Lo, "printTypedVectorList<0,'d'>"> {
+ let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2_Lo">;
+ }
+}
+
+let EncoderMethod = "EncodeRegMul_MinMax<2, 16>",
+ DecoderMethod = "DecodeZPR2Mul2RegisterClass<16, 31>" in {
+ def ZZ_b_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'b'>"> {
+ let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2_Hi">;
+ }
+
+ def ZZ_h_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'h'>"> {
+ let ParserMatchClass = ZPRVectorListMul<16, 2, "Mul2_Hi">;
+ }
+
+ def ZZ_s_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'s'>"> {
+ let ParserMatchClass = ZPRVectorListMul<32, 2, "Mul2_Hi">;
+ }
+
+ def ZZ_d_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'d'>"> {
+ let ParserMatchClass = ZPRVectorListMul<64, 2, "Mul2_Hi">;
+ }
+ } // end let EncoderMethod/DecoderMethod
+
// SME2 strided multi-vector operands
// ZStridedPairs
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index a5165d45893f3e..d0d2fda23a580b 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -1262,6 +1262,9 @@ class AArch64Operand : public MCParsedAsmOperand {
case AArch64::ZPRRegClassID:
case AArch64::ZPR_3bRegClassID:
case AArch64::ZPR_4bRegClassID:
+ case AArch64::ZPRMul2_LoRegClassID:
+ case AArch64::ZPRMul2_HiRegClassID:
+ case AArch64::ZPR_KRegClassID:
RK = RegKind::SVEDataVector;
break;
case AArch64::PPRRegClassID:
@@ -1442,13 +1445,13 @@ class AArch64Operand : public MCParsedAsmOperand {
}
template <RegKind VectorKind, unsigned NumRegs, unsigned NumElements,
- unsigned ElementWidth>
+ unsigned ElementWidth, unsigned RegClass>
DiagnosticPredicate isTypedVectorListMultiple() const {
bool Res =
isTypedVectorList<VectorKind, NumRegs, NumElements, ElementWidth>();
if (!Res)
return DiagnosticPredicateTy::NoMatch;
- if (((VectorList.RegNum - AArch64::Z0) % NumRegs) != 0)
+ if (!AArch64MCRegisterClasses[RegClass].contains(VectorList.RegNum))
return DiagnosticPredicateTy::NearMatch;
return DiagnosticPredicateTy::Match;
}
@@ -6092,6 +6095,33 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "Invalid restricted vector register, expected z0.s..z15.s");
case Match_InvalidZPR_4b64:
return Error(Loc, "Invalid restricted vector register, expected z0.d..z15.d");
+ case Match_InvalidZPRMul2_Lo8:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z0.b..z14.b");
+ case Match_InvalidZPRMul2_Hi8:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z16.b..z30.b");
+ case Match_InvalidZPRMul2_Lo16:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z0.h..z14.h");
+ case Match_InvalidZPRMul2_Hi16:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z16.h..z30.h");
+ case Match_InvalidZPRMul2_Lo32:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z0.s..z14.s");
+ case Match_InvalidZPRMul2_Hi32:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z16.s..z30.s");
+ case Match_InvalidZPRMul2_Lo64:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z0.d..z14.d");
+ case Match_InvalidZPRMul2_Hi64:
+ return Error(Loc, "Invalid restricted vector register, expected even "
+ "register in z16.d..z30.d");
+ case Match_InvalidZPR_K0:
+ return Error(Loc, "invalid restricted vector register, expected register "
+ "in z20..z23 or z28..z31");
case Match_InvalidSVEPattern:
return Error(Loc, "invalid predicate pattern");
case Match_InvalidSVEPPRorPNRAnyReg:
@@ -6171,19 +6201,36 @@ bool AArch64AsmParser::showMatchError(SMLoc Loc, unsigned ErrCode,
return Error(Loc, "operand must be a register in range [w12, w15]");
case Match_InvalidMatrixIndexGPR32_8_11:
return Error(Loc, "operand must be a register in range [w8, w11]");
- case Match_InvalidSVEVectorListMul2x8:
- case Match_InvalidSVEVectorListMul2x16:
- case Match_InvalidSVEVectorListMul2x32:
- case Match_InvalidSVEVectorListMul2x64:
- case Match_InvalidSVEVectorListMul2x128:
+ case Match_InvalidSVEVectorList2x8Mul2:
+ case Match_InvalidSVEVectorList2x16Mul2:
+ case Match_InvalidSVEVectorList2x32Mul2:
+ case Match_InvalidSVEVectorList2x64Mul2:
+ case Match_InvalidSVEVectorList2x128Mul2:
return Error(Loc, "Invalid vector list, expected list with 2 consecutive "
"SVE vectors, where the first vector is a multiple of 2 "
"and with matching element types");
- case Match_InvalidSVEVectorListMul4x8:
- case Match_InvalidSVEVectorListMul4x16:
- case Match_InvalidSVEVectorListMul4x32:
- case Match_InvalidSVEVectorListMul4x64:
- case Match_InvalidSVEVectorListMul4x128:
+ case Match_InvalidSVEVectorList2x8Mul2_Lo:
+ case Match_InvalidSVEVectorList2x16Mul2_Lo:
+ case Match_InvalidSVEVectorList2x32Mul2_Lo:
+ case Match_InvalidSVEVectorList2x64Mul2_Lo:
+ return Error(Loc, "Invalid vector list, expected list with 2 consecutive "
+ "SVE vectors in the range z0-z14, where the first vector "
+ "is a multiple of 2 "
+ "and with matching element types");
+ case Match_InvalidSVEVectorList2x8Mul2_Hi:
+ case Match_InvalidSVEVectorList2x16Mul2_Hi:
+ case Match_InvalidSVEVectorList2x32Mul2_Hi:
+ case Match_InvalidSVEVectorList2x64Mul2_Hi:
+ return Error(Loc,
+ "Invalid vector list, expected list with 2 consecutive "
+ "SVE vectors in the range z16-z30, where the first vector "
+ "is a multiple of 2 "
+ "and with matching element types");
+ case Match_InvalidSVEVectorList4x8Mul4:
+ case Match_InvalidSVEVectorList4x16Mul4:
+ case Match_InvalidSVEVectorList4x32Mul4:
+ case Match_InvalidSVEVectorList4x64Mul4:
+ case Match_InvalidSVEVectorList4x128Mul4:
return Error(Loc, "Invalid vector list, expected list with 4 consecutive "
"SVE vectors, where the first vector is a multiple of 4 "
"and with matching element types");
@@ -6776,16 +6823,33 @@ bool AArch64AsmParser::matchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
case Match_InvalidMatrixIndexGPR32_12_15:
case Match_InvalidMatrixIndexGPR32_8_11:
case Match_InvalidLookupTable:
- case Match_InvalidSVEVectorListMul2x8:
- case Match_InvalidSVEVectorListMul2x16:
- case Match_InvalidSVEVectorListMul2x32:
- case Match_InvalidSVEVectorListMul2x64:
- case Match_InvalidSVEVectorListMul2x128:
- case Match_InvalidSVEVectorListMul4x8:
- case Match_InvalidSVEVectorListMul4x16:
- case Match_InvalidSVEVectorListMul4x32:
- case Match_InvalidSVEVectorListMul4x64:
- case Match_InvalidSVEVectorListMul4x128:
+ case Match_InvalidZPRMul2_Lo8:
+ case Match_InvalidZPRMul2_Hi8:
+ case Match_InvalidZPRMul2_Lo16:
+ case Match_InvalidZPRMul2_Hi16:
+ case Match_InvalidZPRMul2_Lo32:
+ case Match_InvalidZPRMul2_Hi32:
+ case Match_InvalidZPRMul2_Lo64:
+ case Match_InvalidZPRMul2_Hi64:
+ case Match_InvalidZPR_K0:
+ case Match_InvalidSVEVectorList2x8Mul2:
+ case Match_InvalidSVEVectorList2x16Mul2:
+ case Match_InvalidSVEVectorList2x32Mul2:
+ case Match_InvalidSVEVectorList2x64Mul2:
+ case Match_InvalidSVEVectorList2x128Mul2:
+ case Match_InvalidSVEVectorList4x8Mul4:
+ case Match_InvalidSVEVectorList4x16Mul4:
+ case Match_InvalidSVEVectorList4x32Mul4:
+ case Match_InvalidSVEVectorList4x64Mul4:
+ case Match_InvalidSVEVectorList4x128Mul4:
+ case Match_InvalidSVEVectorList2x8Mul2_Lo:
+ case Match_InvalidSVEVectorList2x16Mul2_Lo:
+ case Match_InvalidSVEVectorList2x32Mul2_Lo:
+ case Match_InvalidSVEVectorList2x64Mul2_Lo:
+ case Match_InvalidSVEVectorList2x8Mul2_Hi:
+ case Match_InvalidSVEVectorList2x16Mul2_Hi:
+ case Match_InvalidSVEVectorList2x32Mul2_Hi:
+ case Match_InvalidSVEVectorList2x64Mul2_Hi:
case Match_InvalidSVEVectorListStrided2x8:
case Match_InvalidSVEVectorListStrided2x16:
case Match_InvalidSVEVectorListStrided2x32:
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index b97f00c9931122..d57f782f3173c8 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -45,6 +45,13 @@ static DecodeStatus DecodeSimpleRegisterClass(MCInst &Inst, unsigned RegNo,
static DecodeStatus
DecodeGPR64x8ClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder);
+template <unsigned Min, unsigned Max>
+static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder);
+static DecodeStatus DecodeZK(MCInst &Inst, unsigned RegNo, uint64_t Address,
+ const MCDisassembler *Decoder);
+template <unsigned Min = 0, unsigned Max = 30>
static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder);
@@ -355,13 +362,43 @@ DecodeGPR64x8ClassRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
return Success;
}
+template <unsigned Min, unsigned Max>
+static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ unsigned Reg = RegNo * 2 + Min;
+ if (Reg < Min || Reg > Max || (Reg & 1))
+ return Fail;
+ unsigned Register =
+ AArch64MCRegisterClasses[AArch64::ZPRRegClassID].getRegister(Reg);
+ Inst.addOperand(MCOperand::createReg(Register));
+ return Success;
+}
+
+template <unsigned Min, unsigned Max>
static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
- if (RegNo * 2 > 30)
+ if ((RegNo * 2) + Min > Max)
+ return Fail;
+ unsigned Register =
+ AArch64MCRegisterClasses[AArch64::ZPR2RegClassID].getRegister(RegNo * 2 +
+ Min);
+ Inst.addOperand(MCOperand::createReg(Register));
+ return Success;
+}
+
+// Zk Is the name of the control vector register Z20-Z23 or Z28-Z31, encoded in
+// the "K:Zk" fields. Z20-Z23 = 000, 001,010, 011 and Z28-Z31 = 100, 101, 110,
+// 111
+static DecodeStatus DecodeZK(MCInst &Inst, unsigned RegNo, uint64_t Address,
+ const MCDisassembler *Decoder) {
+ // (Z28 => RegNo = 4) Z28 = 4 => Z28 + 24 = 28
+ unsigned Reg = (RegNo > 3) ? (RegNo + 24) : (RegNo + 20);
+ if (!(Reg >= 20 && Reg <= 23) && !(Reg >= 28 && Reg <= 31))
return Fail;
unsigned Register =
- AArch64MCRegisterClasses[AArch64::ZPR2RegClassID].getRegister(RegNo * 2);
+ AArch64MCRegisterClasses[AArch64::ZPRRegClassID].getRegister(Reg);
Inst.addOperand(MCOperand::createReg(Register));
return Success;
}
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index c3e12b6d8024e9..5a26c4c941d34f 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -191,10 +191,13 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
unsigned fixOneOperandFPComparison(const MCInst &MI, unsigned EncodedValue,
const MCSubtargetInfo &STI) const;
- template <unsigned Multiple>
- uint32_t EncodeRegAsMultipleOf(const MCInst &MI, unsigned OpIdx,
+ template <unsigned Multiple, unsigned Min = 0, unsigned Max = 30>
+ uint32_t EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
+ uint32_t EncodeZK(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
uint32_t EncodePNR_p8to15(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -561,15 +564,31 @@ AArch64MCCodeEmitter::getVecShiftL8OpValue(const MCInst &MI, unsigned OpIdx,
return MO.getImm() - 8;
}
-template <unsigned Multiple>
+template <unsigned Multiple, unsigned Min, unsigned Max>
uint32_t
-AArch64MCCodeEmitter::EncodeRegAsMultipleOf(const MCInst &MI, unsigned OpIdx,
+AArch64MCCodeEmitter::EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const {
assert(llvm::isPowerOf2_32(Multiple) && "Multiple is not a power of 2");
auto RegOpnd = MI.getOperand(OpIdx).getReg();
unsigned RegVal = Ctx.getRegisterInfo()->getEncodingValue(RegOpnd);
- return RegVal / Multiple;
+ assert(RegVal >= Min && RegVal <= Max && (RegVal & Multiple - 1) == 0);
+ return (RegVal - Min) / Multiple;
+}
+
+// Zk Is the name of the control vector register Z20-Z23 or Z28-Z31, encoded in
+// the "K:Zk" fields. Z20-Z23 = 000, 001,010, 011 and Z28-Z31 = 100, 101, 110,
+// 111
+uint32_t AArch64MCCodeEmitter::EncodeZK(const MCInst &MI, unsigned OpIdx,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ auto RegOpnd = MI.getOperand(OpIdx).getReg();
+ unsigned RegVal = Ctx.getRegisterInfo()->getEncodingValue(RegOpnd);
+ // Z28 => RegVal = 28 (28 - 24 = 4) Z28 = 4
+ if (RegOpnd > AArch64::Z27)
+ return (RegVal - 24);
+ // Z20 => RegVal = 20 (20 -20 = 0) Z20 = 0
+ return (RegVal - 20);
}
uint32_t
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/regbank-inlineasm.mir b/llvm/test/CodeGen/AArch64/GlobalISel/regbank-inlineasm.mir
index 2ffb7856806850..f1d1b691fe1aa5 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/regbank-inlineasm.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/regbank-inlineasm.mir
@@ -57,11 +57,11 @@ tracksRegLiveness: true
body: |
bb.1:
; CHECK-LABEL: name: inlineasm_virt_reg_output
- ; CHECK: INLINEASM &"mov ${0:w}, 7", 0 /* attdialect */, 1769482 /* regdef:GPR32common */, def %0
+ ; CHECK: INLINEASM &"mov ${0:w}, 7", 0 /* attdialect */, 2490378 /* regdef:GPR32common */, def %0
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr(s32) = COPY %0
; CHECK-NEXT: $w0 = COPY [[COPY]](s32)
; CHECK-NEXT: RET_ReallyLR implicit $w0
- INLINEASM &"mov ${0:w}, 7", 0 /* attdialect */, 1769482 /* regdef:GPR32common */, def %0:gpr32common
+ INLINEASM &"mov ${0:w}, 7", 0 /* attdialect */, 2490378 /* regdef:GPR32common */, def %0:gpr32common
%1:_(s32) = COPY %0
$w0 = COPY %1(s32)
RET_ReallyLR implicit $w0
@@ -75,12 +75,12 @@ tracksRegLiveness: true
body: |
bb.1:
; CHECK-LABEL: name: inlineasm_virt_mixed_types
- ; CHECK: INLINEASM &"mov $0, #0; mov $1, #0", 0 /* attdialect */, 1769482 /* regdef:GPR32common */, def %0, {{[0-9]+}} /* regdef:FPR64 */, def %1
+ ; CHECK: INLINEASM &"mov $0, #0; mov $1, #0", 0 /* attdialect */, 2490378 /* regdef:GPR32common */, def %0, 3342346 /* regdef:FPR64 */, def %1
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr(s32) = COPY %0
; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr(s64) = COPY %1
; CHECK-NEXT: $d0 = COPY [[COPY1]](s64)
; CHECK-NEXT: RET_ReallyLR implicit $d0
- INLINEASM &"mov $0, #0; mov $1, #0", 0 /* attdialect */, 1769482 /* regdef:GPR32common */, def %0:gpr32common, 2621450 /* regdef:FPR64 */, def %1:fpr64
+ INLINEASM &"mov $0, #0; mov $1, #0", 0 /* attdialect */, 2490378 /* regdef:GPR32common */, def %0:gpr32common, 3342346 /* regdef:FPR64 */, def %1:fpr64
%3:_(s32) = COPY %0
%4:_(s64) = COPY %1
$d0 = COPY %4(s64)
diff --git a/llvm/test/CodeGen/AArch64/emit_fneg_with_non_register_operand.mir b/llvm/test/CodeGen/AArch64/emit_fneg_with_non_register_operand.mir
index 2be7aba2a3df89..ffa7453e48b4f0 100644
--- a/llvm/test/CodeGen/AArch64/emit_fneg_with_non_register_operand.mir
+++ b/llvm/test/CodeGen/AArch64/emit_fneg_with_non_register_operand.mir
@@ -91,10 +91,10 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: [[LOADgot:%[0-9]+]]:gpr64common = LOADgot target-flags(aarch64-got) @c
; CHECK-NEXT: [[LDRDui:%[0-9]+]]:fpr64 = LDRDui [[LOADgot]], 0 :: (dereferenceable load (s64) from @c)
- ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */, 2621450 /* regdef:FPR64 */, def %2, 2147483657 /* reguse tiedto:$0 */, [[LDRDui]](tied-def 3)
+ ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */, 3342346 /* regdef:FPR64 */, def %2, 2147483657 /* reguse tiedto:$0 */, [[LDRDui]](tied-def 3)
; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY %2
; CHECK-NEXT: [[LDRDui1:%[0-9]+]]:fpr64 = LDRDui [[LOADgot]], 0 :: (dereferenceable load (s64) from @c)
- ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */, 2621450 /* regdef:FPR64 */, def %4, 2147483657 /* reguse tiedto:$0 */, [[LDRDui1]](tied-def 3)
+ ; CHECK-NEXT: INLINEASM &"", 1 /* sideeffect attdialect */, 3342346 /* regdef:FPR64 */, def %4, 2147483657 /* reguse tiedto:$0 */, [[LDRDui1]](tied-def 3)
; CHECK-NEXT: [[FNEGDr:%[0-9]+]]:fpr64 = FNEGDr %2
; CHECK-NEXT: nofpexcept FCMPDrr %4, killed [[FNEGDr]], implicit-def $nzcv, implicit $fpcr
; CHECK-NEXT: Bcc 1, %bb.2, implicit $nzcv
@@ -111,10 +111,10 @@ body: |
%6:gpr64common = LOADgot target-flags(aarch64-got) @c
%3:fpr64 = LDRDui %6, 0 :: (dereferenceable load (s64) from @c)
- INLINEASM &"", 1 /* sideeffect attdialect */, 2621450 /* regdef:FPR64 */, def %2, 2147483657 /* reguse tiedto:$0 */, %3(tied-def 3)
+ INLINEASM &"", 1 /* sideeffect attdialect */, 3342346 /* regdef:FPR64 */, def %2, 2147483657 /* reguse tiedto:$0 */, %3(tied-def 3)
%0:fpr64 = COPY %2
%5:fpr64 = LDRDui %6, 0 :: (dereferenceable load (s64) from @c)
- INLINEASM &"", 1 /* sideeffect attdialect */, 2621450 /* regdef:FPR64 */, def %4, 2147483657 /* reguse tiedto:$0 */, %5(tied-def 3)
+ INLINEASM &"", 1 /* sideeffect attdialect */, 3342346 /* regdef:FPR64 */, def %4, 2147483657 /* reguse tiedto:$0 */, %5(tied-def 3)
%7:fpr64 = FNEGDr %2
nofpexcept FCMPDrr %4, killed %7, implicit-def $nzcv, implicit $fpcr
Bcc 1, %bb.2, implicit $nzcv
diff --git a/llvm/test/CodeGen/AArch64/fmlal-loreg.ll b/llvm/test/CodeGen/AArch64/fmlal-loreg.ll
index 20737a73183944..31ead890ba8ac7 100644
--- a/llvm/test/CodeGen/AArch64/fmlal-loreg.ll
+++ b/llvm/test/CodeGen/AArch64/fmlal-loreg.ll
@@ -11,8 +11,8 @@ define <4 x float> @test(ptr %lhs_panel, ptr %rhs_panel, <4 x float> %a) {
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: .cfi_offset b8, -16
; CHECK-NEXT: fmov x8, d0
-; CHECK-NEXT: ldr q8, [x0]
; CHECK-NEXT: ldr q16, [x1]
+; CHECK-NEXT: ldr q8, [x0]
; CHECK-NEXT: lsr x9, x8, #32
; CHECK-NEXT: //APP
; CHECK-NEXT: nop
diff --git a/llvm/test/CodeGen/AArch64/peephole-insvigpr.mir b/llvm/test/CodeGen/AArch64/peephole-insvigpr.mir
index 5dd29cf39c0ead..f8af5b96370178 100644
--- a/llvm/test/CodeGen/AArch64/peephole-insvigpr.mir
+++ b/llvm/test/CodeGen/AArch64/peephole-insvigpr.mir
@@ -487,7 +487,7 @@ body: |
; CHECK-NEXT: [[COPY:%[0-9]+]]:gpr64common = COPY $x0
; CHECK-NEXT: [[DEF:%[0-9]+]]:gpr64all = IMPLICIT_DEF
; CHECK-NEXT: [[COPY1:%[0-9]+]]:gpr64sp = COPY [[DEF]]
- ; CHECK-NEXT: INLINEASM &"ldr ${0:s}, $1", 8 /* mayload attdialect */, 2621450 /* regdef:FPR64 */, def %1, 262158 /* mem:m */, killed [[COPY1]]
+ ; CHECK-NEXT: INLINEASM &"ldr ${0:s}, $1", 8 /* mayload attdialect */, 3342346 /* regdef:FPR64 */, def %1, 262158 /* mem:m */, killed [[COPY1]]
; CHECK-NEXT: [[MOVIv2d_ns:%[0-9]+]]:fpr128 = MOVIv2d_ns 0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:fpr64 = COPY [[MOVIv2d_ns]].dsub
; CHECK-NEXT: [[DEF1:%[0-9]+]]:fpr128 = IMPLICIT_DEF
@@ -505,7 +505,7 @@ body: |
%0:gpr64common = COPY $x0
%2:gpr64all = IMPLICIT_DEF
%3:gpr64sp = COPY %2
- INLINEASM &"ldr ${0:s}, $1", 8 /* mayload attdialect */, 2621450 /* regdef:FPR64 */, def %1, 262158 /* mem:m */, killed %3
+ INLINEASM &"ldr ${0:s}, $1", 8 /* mayload attdialect */, 3342346 /* regdef:FPR64 */, def %1, 262158 /* mem:m */, killed %3
%4:fpr128 = MOVIv2d_ns 0
%5:fpr64 = COPY %4.dsub
%7:fpr128 = IMPLICIT_DEF
>From 85612cba9fa2cff52b4a0821bcdebf2d56252b38 Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Wed, 9 Oct 2024 17:25:34 +0000
Subject: [PATCH 2/7] [NFC] Fix format
---
.../Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index 5a26c4c941d34f..d8e486eeb82e52 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -193,8 +193,8 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
template <unsigned Multiple, unsigned Min = 0, unsigned Max = 30>
uint32_t EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const;
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
uint32_t EncodeZK(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -567,8 +567,8 @@ AArch64MCCodeEmitter::getVecShiftL8OpValue(const MCInst &MI, unsigned OpIdx,
template <unsigned Multiple, unsigned Min, unsigned Max>
uint32_t
AArch64MCCodeEmitter::EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
- SmallVectorImpl<MCFixup> &Fixups,
- const MCSubtargetInfo &STI) const {
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
assert(llvm::isPowerOf2_32(Multiple) && "Multiple is not a power of 2");
auto RegOpnd = MI.getOperand(OpIdx).getReg();
unsigned RegVal = Ctx.getRegisterInfo()->getEncodingValue(RegOpnd);
>From b5709d1de612dc0df47678ede84fa607677aa6ba Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Mon, 14 Oct 2024 19:13:40 +0000
Subject: [PATCH 3/7] [Fixup] Improve comments/consistency and remove default
template args
---
llvm/lib/Target/AArch64/AArch64RegisterInfo.td | 15 +++++++--------
.../AArch64/Disassembler/AArch64Disassembler.cpp | 16 +++++++++-------
.../MCTargetDesc/AArch64MCCodeEmitter.cpp | 4 ++--
3 files changed, 18 insertions(+), 17 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index ed9610edfe8325..3593615a1fc204 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1213,11 +1213,10 @@ def ZPRMul2AsmOp64_Hi : ZPRAsmOperand<"VectorD_Hi", 64, "Mul2_Hi">;
def ZPR_K : RegisterClass<"AArch64", [untyped], 128,
(add Z20, Z21, Z22, Z23, Z28, Z29, Z30, Z31)>;
-let EncoderMethod = "EncodeZK",
- DecoderMethod = "DecodeZK" in {
- def ZK : RegisterOperand<ZPR_K, "printSVERegOp<>">{
- let ParserMatchClass = ZPRAsmOperand<"Vector_20to23or28to31", 0, "_K">;
- }
+def ZK : RegisterOperand<ZPR_K, "printSVERegOp<>">{
+ let EncoderMethod = "EncodeZK";
+ let DecoderMethod = "DecodeZK";
+ let ParserMatchClass = ZPRAsmOperand<"Vector_20to23or28to31", 0, "_K">;
}
def ZPR8Mul2_Lo : ZPRMul2_MinToMaxRegOp<"b", ZPRMul2AsmOp8_Lo, 0, 14, ElementSizeB, ZPRMul2_Lo>;
@@ -1379,8 +1378,8 @@ class ZPRVectorListMul<int ElementWidth, int NumRegs, string RegClassSuffix = ""
# "AArch64::ZPR" # RegClassSuffix # "RegClassID" # ">";
}
-let EncoderMethod = "EncodeRegMul_MinMax<2>",
- DecoderMethod = "DecodeZPR2Mul2RegisterClass" in {
+let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 30>",
+ DecoderMethod = "DecodeZPR2Mul2RegisterClass<0, 30>" in {
def ZZ_mul_r : RegisterOperand<ZPR2Mul2, "printTypedVectorList<0,0>"> {
let ParserMatchClass = ZPRVectorListMul<0, 2, "Mul2">;
}
@@ -1459,7 +1458,7 @@ let EncoderMethod = "EncodeRegMul_MinMax<2, 0, 14>",
}
}
-let EncoderMethod = "EncodeRegMul_MinMax<2, 16>",
+let EncoderMethod = "EncodeRegMul_MinMax<2, 16, 30>",
DecoderMethod = "DecodeZPR2Mul2RegisterClass<16, 31>" in {
def ZZ_b_mul_r_Hi : RegisterOperand<ZPR2Mul2_Hi, "printTypedVectorList<0,'b'>"> {
let ParserMatchClass = ZPRVectorListMul<8, 2, "Mul2_Hi">;
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index d57f782f3173c8..b265c80941be4f 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -51,7 +51,7 @@ static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
const MCDisassembler *Decoder);
static DecodeStatus DecodeZK(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder);
-template <unsigned Min = 0, unsigned Max = 30>
+template <unsigned Min, unsigned Max>
static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder);
@@ -366,7 +366,7 @@ template <unsigned Min, unsigned Max>
static DecodeStatus DecodeZPRMul2_MinMax(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
- unsigned Reg = RegNo * 2 + Min;
+ unsigned Reg = (RegNo * 2) + Min;
if (Reg < Min || Reg > Max || (Reg & 1))
return Fail;
unsigned Register =
@@ -379,11 +379,12 @@ template <unsigned Min, unsigned Max>
static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
- if ((RegNo * 2) + Min > Max)
+ unsigned Reg = (RegNo * 2) + Min;
+ if(Reg < Min || Reg > Max || (Reg & 1))
return Fail;
+
unsigned Register =
- AArch64MCRegisterClasses[AArch64::ZPR2RegClassID].getRegister(RegNo * 2 +
- Min);
+ AArch64MCRegisterClasses[AArch64::ZPR2RegClassID].getRegister(Reg);
Inst.addOperand(MCOperand::createReg(Register));
return Success;
}
@@ -393,8 +394,9 @@ static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
// 111
static DecodeStatus DecodeZK(MCInst &Inst, unsigned RegNo, uint64_t Address,
const MCDisassembler *Decoder) {
- // (Z28 => RegNo = 4) Z28 = 4 => Z28 + 24 = 28
- unsigned Reg = (RegNo > 3) ? (RegNo + 24) : (RegNo + 20);
+ // RegNo < 4 => Reg is in Z20-Z23 (offset 20)
+ // RegNo >= 4 => Reg is in Z28-Z31 (offset 24)
+ unsigned Reg = (RegNo < 4) ? (RegNo + 20) : (RegNo + 24);
if (!(Reg >= 20 && Reg <= 23) && !(Reg >= 28 && Reg <= 31))
return Fail;
unsigned Register =
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index d8e486eeb82e52..85ffb8639dadf5 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -191,7 +191,7 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
unsigned fixOneOperandFPComparison(const MCInst &MI, unsigned EncodedValue,
const MCSubtargetInfo &STI) const;
- template <unsigned Multiple, unsigned Min = 0, unsigned Max = 30>
+ template <unsigned Multiple, unsigned Min, unsigned Max>
uint32_t EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
SmallVectorImpl<MCFixup> &Fixups,
const MCSubtargetInfo &STI) const;
@@ -572,7 +572,7 @@ AArch64MCCodeEmitter::EncodeRegMul_MinMax(const MCInst &MI, unsigned OpIdx,
assert(llvm::isPowerOf2_32(Multiple) && "Multiple is not a power of 2");
auto RegOpnd = MI.getOperand(OpIdx).getReg();
unsigned RegVal = Ctx.getRegisterInfo()->getEncodingValue(RegOpnd);
- assert(RegVal >= Min && RegVal <= Max && (RegVal & Multiple - 1) == 0);
+ assert(RegVal >= Min && RegVal <= Max && (RegVal & (Multiple - 1)) == 0);
return (RegVal - Min) / Multiple;
}
>From 6b3eb5a2a3168bb9d58afe69d605340eeae46541 Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Mon, 14 Oct 2024 19:23:30 +0000
Subject: [PATCH 4/7] [NFC] Fix format
---
llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index b265c80941be4f..4a4b89da718884 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -380,7 +380,7 @@ static DecodeStatus DecodeZPR2Mul2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const void *Decoder) {
unsigned Reg = (RegNo * 2) + Min;
- if(Reg < Min || Reg > Max || (Reg & 1))
+ if (Reg < Min || Reg > Max || (Reg & 1))
return Fail;
unsigned Register =
>From a1b39b513588fb2fdf79d58db991300bf65f7c2b Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Thu, 17 Oct 2024 15:02:32 +0000
Subject: [PATCH 5/7] Rebase and update new sve-asm test
---
llvm/test/CodeGen/AArch64/aarch64-sve-asm.ll | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/aarch64-sve-asm.ll b/llvm/test/CodeGen/AArch64/aarch64-sve-asm.ll
index 068e194779c153..9f8897575b3d58 100644
--- a/llvm/test/CodeGen/AArch64/aarch64-sve-asm.ll
+++ b/llvm/test/CodeGen/AArch64/aarch64-sve-asm.ll
@@ -13,7 +13,7 @@ define <vscale x 16 x i8> @test_svadd_i8(<vscale x 16 x i8> %Zn, <vscale x 16 x
; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY3:%[0-9]+]]:zpr_3b = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"add $0.b, $1.b, $2.b", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %2, 5046281 /* reguse:ZPR */, [[COPY2]], 5373961 /* reguse:ZPR_3b */, [[COPY3]]
+ ; CHECK-NEXT: INLINEASM &"add $0.b, $1.b, $2.b", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %2, 5767177 /* reguse:ZPR */, [[COPY2]], 6357001 /* reguse:ZPR_3b */, [[COPY3]]
; CHECK-NEXT: $z0 = COPY %2
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 16 x i8> asm "add $0.b, $1.b, $2.b", "=w,w,y"(<vscale x 16 x i8> %Zn, <vscale x 16 x i8> %Zm)
@@ -29,7 +29,7 @@ define <vscale x 2 x i64> @test_svsub_i64(<vscale x 2 x i64> %Zn, <vscale x 2 x
; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY3:%[0-9]+]]:zpr_4b = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"sub $0.d, $1.d, $2.d", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %2, 5046281 /* reguse:ZPR */, [[COPY2]], 5242889 /* reguse:ZPR_4b */, [[COPY3]]
+ ; CHECK-NEXT: INLINEASM &"sub $0.d, $1.d, $2.d", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %2, 5767177 /* reguse:ZPR */, [[COPY2]], 6029321 /* reguse:ZPR_4b */, [[COPY3]]
; CHECK-NEXT: $z0 = COPY %2
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 2 x i64> asm "sub $0.d, $1.d, $2.d", "=w,w,x"(<vscale x 2 x i64> %Zn, <vscale x 2 x i64> %Zm)
@@ -45,7 +45,7 @@ define <vscale x 8 x half> @test_svfmul_f16(<vscale x 8 x half> %Zn, <vscale x 8
; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY3:%[0-9]+]]:zpr_3b = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"fmul $0.h, $1.h, $2.h", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %2, 5046281 /* reguse:ZPR */, [[COPY2]], 5373961 /* reguse:ZPR_3b */, [[COPY3]]
+ ; CHECK-NEXT: INLINEASM &"fmul $0.h, $1.h, $2.h", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %2, 5767177 /* reguse:ZPR */, [[COPY2]], 6357001 /* reguse:ZPR_3b */, [[COPY3]]
; CHECK-NEXT: $z0 = COPY %2
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 8 x half> asm "fmul $0.h, $1.h, $2.h", "=w,w,y"(<vscale x 8 x half> %Zn, <vscale x 8 x half> %Zm)
@@ -61,7 +61,7 @@ define <vscale x 4 x float> @test_svfmul_f(<vscale x 4 x float> %Zn, <vscale x 4
; CHECK-NEXT: [[COPY1:%[0-9]+]]:zpr = COPY $z0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY3:%[0-9]+]]:zpr_4b = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"fmul $0.s, $1.s, $2.s", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %2, 5046281 /* reguse:ZPR */, [[COPY2]], 5242889 /* reguse:ZPR_4b */, [[COPY3]]
+ ; CHECK-NEXT: INLINEASM &"fmul $0.s, $1.s, $2.s", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %2, 5767177 /* reguse:ZPR */, [[COPY2]], 6029321 /* reguse:ZPR_4b */, [[COPY3]]
; CHECK-NEXT: $z0 = COPY %2
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 4 x float> asm "fmul $0.s, $1.s, $2.s", "=w,w,x"(<vscale x 4 x float> %Zn, <vscale x 4 x float> %Zm)
@@ -79,7 +79,7 @@ define <vscale x 8 x half> @test_svfadd_f16(<vscale x 16 x i1> %Pg, <vscale x 8
; CHECK-NEXT: [[COPY3:%[0-9]+]]:ppr_3b = COPY [[COPY2]]
; CHECK-NEXT: [[COPY4:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY5:%[0-9]+]]:zpr = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"fadd $0.h, $1/m, $2.h, $3.h", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %3, 589833 /* reguse:PPR_3b */, [[COPY3]], 5046281 /* reguse:ZPR */, [[COPY4]], 5046281 /* reguse:ZPR */, [[COPY5]]
+ ; CHECK-NEXT: INLINEASM &"fadd $0.h, $1/m, $2.h, $3.h", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %3, 720905 /* reguse:PPR_3b */, [[COPY3]], 5767177 /* reguse:ZPR */, [[COPY4]], 5767177 /* reguse:ZPR */, [[COPY5]]
; CHECK-NEXT: $z0 = COPY %3
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 8 x half> asm "fadd $0.h, $1/m, $2.h, $3.h", "=w, at 3Upl,w,w"(<vscale x 16 x i1> %Pg, <vscale x 8 x half> %Zn, <vscale x 8 x half> %Zm)
@@ -95,7 +95,7 @@ define <vscale x 4 x i32> @test_incp(<vscale x 16 x i1> %Pg, <vscale x 4 x i32>
; CHECK-NEXT: [[COPY1:%[0-9]+]]:ppr = COPY $p0
; CHECK-NEXT: [[COPY2:%[0-9]+]]:ppr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY3:%[0-9]+]]:zpr = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"incp $0.s, $1", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %2, 393225 /* reguse:PPR */, [[COPY2]], 2147483657 /* reguse tiedto:$0 */, [[COPY3]](tied-def 3)
+ ; CHECK-NEXT: INLINEASM &"incp $0.s, $1", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %2, 458761 /* reguse:PPR */, [[COPY2]], 2147483657 /* reguse tiedto:$0 */, [[COPY3]](tied-def 3)
; CHECK-NEXT: $z0 = COPY %2
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 4 x i32> asm "incp $0.s, $1", "=w, at 3Upa,0"(<vscale x 16 x i1> %Pg, <vscale x 4 x i32> %Zn)
@@ -113,7 +113,7 @@ define <vscale x 8 x half> @test_svfadd_f16_Uph_constraint(<vscale x 16 x i1> %P
; CHECK-NEXT: [[COPY3:%[0-9]+]]:ppr_p8to15 = COPY [[COPY2]]
; CHECK-NEXT: [[COPY4:%[0-9]+]]:zpr = COPY [[COPY1]]
; CHECK-NEXT: [[COPY5:%[0-9]+]]:zpr = COPY [[COPY]]
- ; CHECK-NEXT: INLINEASM &"fadd $0.h, $1/m, $2.h, $3.h", 0 /* attdialect */, 5046282 /* regdef:ZPR */, def %3, 655369 /* reguse:PPR_p8to15 */, [[COPY3]], 5046281 /* reguse:ZPR */, [[COPY4]], 5046281 /* reguse:ZPR */, [[COPY5]]
+ ; CHECK-NEXT: INLINEASM &"fadd $0.h, $1/m, $2.h, $3.h", 0 /* attdialect */, 5767178 /* regdef:ZPR */, def %3, 786441 /* reguse:PPR_p8to15 */, [[COPY3]], 5767177 /* reguse:ZPR */, [[COPY4]], 5767177 /* reguse:ZPR */, [[COPY5]]
; CHECK-NEXT: $z0 = COPY %3
; CHECK-NEXT: RET_ReallyLR implicit $z0
%1 = tail call <vscale x 8 x half> asm "fadd $0.h, $1/m, $2.h, $3.h", "=w, at 3Uph,w,w"(<vscale x 16 x i1> %Pg, <vscale x 8 x half> %Zn, <vscale x 8 x half> %Zm)
>From 0a5011e21a4a5f90b99f87d200ff33dbe0d45978 Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Fri, 18 Oct 2024 13:29:07 +0000
Subject: [PATCH 6/7] [NFC] Update comment
---
llvm/lib/Target/AArch64/AArch64RegisterInfo.td | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 3593615a1fc204..8516ab2c7dd71c 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1428,7 +1428,8 @@ let EncoderMethod = "EncodeRegMul_MinMax<4, 0, 28>",
}
} // end let EncoderMethod/DecoderMethod
-// Pairs of ZPR, sarting with an even register, split into Lo=0-14 and Hi=16-30
+// Pairs of consecutive ZPR, starting with an even register, split into
+// Lo=0-14 and Hi=16-30.
def ZPR2Mul2_Lo : RegisterClass<"AArch64", [untyped], 128,
(trunc (decimate ZSeqPairs, 2), 8)> {
let Size = 256;
>From e861d84ff18f9346f2dffeceb6d2730dfb45c813 Mon Sep 17 00:00:00 2001
From: Spencer Abson <Spencer.Abson at arm.com>
Date: Thu, 17 Oct 2024 14:44:07 +0000
Subject: [PATCH 7/7] [LLVM][AArch64] Add assembly/disassembly for SME2p2
ftmopa and bftmopa
This patch adds assembly/disassembly for the following SME2p2 instructions (part of the 2024 AArch64 ISA update)
- BFTMOPA (widening) - FEAT_SME2p2
- BFTMOPA (non-widening) - FEAT_SME2p2 & FEAT_SME_B16B16
- FTMOPA (4-way) - FEAT_SME2p2 & FEAT_SME_F8F32
- FTMOPA (2-way, 8-to-16) - FEAT_SME2p2 & FEAT_SME_F8F16
- FTMOPA (2-way, 16-to-32) - FEAT_SME2p2
- FTMOPA (non-widening, f16) - FEAT_SME2p2 & FEAT_SME_F16F16
- FTMOPA (non-widening, f32) - FEAT_SME2p2
- It also introduces .arch assembler tests for the new sme2p2 feature
In accordance with: https://developer.arm.com/documentation/ddi0602/latest/
Co-authored-by: Marian Lukac marian.lukac at arm.com
---
.../lib/Target/AArch64/AArch64SMEInstrInfo.td | 21 ++
llvm/lib/Target/AArch64/SMEInstrFormats.td | 62 +++++
.../MC/AArch64/SME2p2/bftmopa-diagnostics.s | 114 ++++++++++
llvm/test/MC/AArch64/SME2p2/bftmopa.s | 53 +++++
.../AArch64/SME2p2/directive-arch-negative.s | 7 +
llvm/test/MC/AArch64/SME2p2/directive-arch.s | 5 +
.../directive-arch_extension-negative.s | 7 +
.../AArch64/SME2p2/directive-arch_extension.s | 5 +
.../MC/AArch64/SME2p2/ftmopa-diagnostics.s | 212 ++++++++++++++++++
llvm/test/MC/AArch64/SME2p2/ftmopa.s | 113 ++++++++++
10 files changed, 599 insertions(+)
create mode 100644 llvm/test/MC/AArch64/SME2p2/bftmopa-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/bftmopa.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/directive-arch-negative.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/directive-arch.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/directive-arch_extension-negative.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/directive-arch_extension.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/ftmopa-diagnostics.s
create mode 100644 llvm/test/MC/AArch64/SME2p2/ftmopa.s
diff --git a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
index 802797a14ee42d..6044b5bb7d8151 100644
--- a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
@@ -1000,3 +1000,24 @@ defm FMOPA_MPPZZ_BtoS : sme_outer_product_fp32<0b0, 0b01, ZPR8, "fmopa", null_fr
} //[HasSMEF8F32]
+let Predicates = [HasSME2p2] in {
+ def FTMOPA_M2ZZZI_HtoS : sme_tmopa_32b<0b11000, ZZ_h_mul_r, ZPR16, "ftmopa">;
+ def FTMOPA_M2ZZZI_StoS : sme_tmopa_32b<0b00000, ZZ_s_mul_r, ZPR32, "ftmopa">;
+ def BFTMOPA_M2ZZZI_HtoS : sme_tmopa_32b<0b10000, ZZ_h_mul_r, ZPR16, "bftmopa">;
+} // [HasSME2p2]
+
+let Predicates = [HasSME2p2, HasSMEB16B16] in {
+ def BFTMOPA_M2ZZZI_HtoH : sme_tmopa_16b<0b11001, ZZ_h_mul_r, ZPR16, "bftmopa">;
+} // [HasSME2p2, HasSMEB16B16]
+
+let Predicates = [HasSME2p2, HasSMEF8F32], Uses = [FPMR, FPCR] in {
+ def FTMOPA_M2ZZZI_BtoS : sme_tmopa_32b<0b01000, ZZ_b_mul_r, ZPR8, "ftmopa">;
+} // [HasSME2p2, HasSMEF8F32], Uses = [FPMR, FPCR]
+
+let Predicates = [HasSME2p2, HasSMEF8F16], Uses = [FPMR, FPCR] in {
+ def FTMOPA_M2ZZZI_BtoH : sme_tmopa_16b<0b01001, ZZ_b_mul_r, ZPR8, "ftmopa">;
+} // [HasSME2p2, HasSMEF8F16], Uses = [FPMR, FPCR]
+
+let Predicates = [HasSME2p2, HasSMEF16F16] in {
+ def FTMOPA_M2ZZZI_HtoH : sme_tmopa_16b<0b10001, ZZ_h_mul_r, ZPR16, "ftmopa">;
+} // [HasSME2p2, HasSMEF16F16]
diff --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index 38d256c8234118..08929ed5616b2c 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -3192,6 +3192,68 @@ multiclass sme2_int_bmopx_tile<string mnemonic, bits<3> op, SDPatternOperator i
def : SME_ZA_Tile_TwoPred_TwoVec_Pat<NAME, intrinsic, timm32_0_3, nxv4i1, nxv4i32>;
}
+//===----------------------------------------------------------------------===//
+// SME2 Sparse Outer Product and Accumulate
+
+class sme_tmopa_16b<bits<5> opc, RegisterOperand zn_ty, RegisterOperand zm_ty, string mnemonic>
+ : I<(outs TileOp16:$ZAda),
+ (ins TileOp16:$_ZAda, zn_ty:$Zn, zm_ty:$Zm, ZK:$Zk, VectorIndexS32b:$imm),
+ mnemonic, "\t$ZAda, $Zn, $Zm, $Zk$imm",
+ "", []>,
+ Sched<[]> {
+ bit ZAda;
+ bits<4> Zn;
+ bits<5> Zm;
+ bits<3> Zk;
+ bits<2> imm;
+ let Inst{31-25} = 0b1000000;
+ let Inst{24} = opc{4};
+ let Inst{23-22} = 0b01;
+ let Inst{21} = opc{3};
+ let Inst{20-16} = Zm;
+ let Inst{15} = opc{2};
+ let Inst{14} = 0b0;
+ let Inst{13} = opc{1};
+ let Inst{12-10} = Zk;
+ let Inst{9-6} = Zn;
+ let Inst{5-4} = imm;
+ let Inst{3} = opc{0};
+ let Inst{2-1} = 0b00;
+ let Inst{0} = ZAda;
+
+ let Constraints = "$ZAda = $_ZAda";
+}
+
+class sme_tmopa_32b<bits<5> opc, RegisterOperand zn_ty, RegisterOperand zm_ty, string mnemonic>
+ : I<(outs TileOp32:$ZAda),
+ (ins TileOp32:$_ZAda, zn_ty:$Zn, zm_ty:$Zm, ZK:$Zk, VectorIndexS32b:$imm),
+ mnemonic, "\t$ZAda, $Zn, $Zm, $Zk$imm",
+ "", []>,
+ Sched<[]> {
+ bits<2> ZAda;
+ bits<4> Zn;
+ bits<5> Zm;
+ bits<3> Zk;
+ bits<2> imm;
+ let Inst{31-25} = 0b1000000;
+ let Inst{24} = opc{4};
+ let Inst{23-22} = 0b01;
+ let Inst{21} = opc{3};
+ let Inst{20-16} = Zm;
+ let Inst{15} = opc{2};
+ let Inst{14} = 0b0;
+ let Inst{13} = opc{1};
+ let Inst{12-10} = Zk;
+ let Inst{9-6} = Zn;
+ let Inst{5-4} = imm;
+ let Inst{3} = opc{0};
+ let Inst{2} = 0b0;
+ let Inst{1-0} = ZAda;
+
+ let Constraints = "$ZAda = $_ZAda";
+}
+
+
//===----------------------------------------------------------------------===///
// SME2 Zero Lookup Table.
class sme2_zero_zt<string mnemonic, bits<4> opc>
diff --git a/llvm/test/MC/AArch64/SME2p2/bftmopa-diagnostics.s b/llvm/test/MC/AArch64/SME2p2/bftmopa-diagnostics.s
new file mode 100644
index 00000000000000..2577a286354c95
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/bftmopa-diagnostics.s
@@ -0,0 +1,114 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-b16b16 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid ZA register (range)
+
+bftmopa za2.h, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za2.h, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za4.s, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za4.s, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid ZA register (type-suffix)
+
+bftmopa za3.d, {z28.h-z29.h}, z31.h, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid matrix operand, expected za[0-3].s
+// CHECK-NEXT: bftmopa za3.d, {z28.h-z29.h}, z31.h, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector list operand
+
+bftmopa za0.h, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.h, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: bftmopa za0.h, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.s, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za0.s, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: bftmopa za3.s, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid ZK register
+
+bftmopa za0.h, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.h, {z28.h-z29.h}, z31.h, z24[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z29.h}, z31.h, z24[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za3.s, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z28.h-z29.h}, z31.h, z27[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za3.s, {z28.h-z29.h}, z31.h, z27[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.h, {z28.h-z29.h}, z31.h, z21.h[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z29.h}, z31.h, z21.h[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.s, {z28.h-z29.h}, z31.h, z30.h[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: bftmopa za0.s, {z28.h-z29.h}, z31.h, z30.h[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid immediate
+
+bftmopa za0.h, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3]
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3]
+// CHECK-NEXT: bftmopa za3.s, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid ZPR type suffix
+
+bftmopa za0.h, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: bftmopa za0.h, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za0.h, {z28.b-z29.b}, z31.b, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za0.h, {z28.b-z29.b}, z31.b, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: bftmopa za3.s, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+bftmopa za3.s, {z28.s-z29.s}, z31.s, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: bftmopa za3.s, {z28.s-z29.s}, z31.s, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
diff --git a/llvm/test/MC/AArch64/SME2p2/bftmopa.s b/llvm/test/MC/AArch64/SME2p2/bftmopa.s
new file mode 100644
index 00000000000000..dc7b5456ddab33
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/bftmopa.s
@@ -0,0 +1,53 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-b16b16 < %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=+sme2p2,+sme-b16b16 < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2p2,+sme-b16b16 --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2p2,+sme-b16b16 < %s \
+// RUN: | llvm-objdump -d --mattr=-sme2p2 --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-b16b16 < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+sme2p2,+sme-b16b16 -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// non-widening
+
+bftmopa za0.h, {z0.h-z1.h}, z0.h, z20[0] // 10000001-01100000-00000000-00001000
+// CHECK-INST: bftmopa za0.h, { z0.h, z1.h }, z0.h, z20[0]
+// CHECK-ENCODING: [0x08,0x00,0x60,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-b16b16
+// CHECK-UNKNOWN: 81600008 <unknown>
+
+bftmopa za1.h, {z12.h-z13.h}, z8.h, z23[3] // 10000001-01101000-00001101-10111001
+// CHECK-INST: bftmopa za1.h, { z12.h, z13.h }, z8.h, z23[3]
+// CHECK-ENCODING: [0xb9,0x0d,0x68,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-b16b16
+// CHECK-UNKNOWN: 81680db9 <unknown>
+
+bftmopa za1.h, {z30.h-z31.h}, z31.h, z31[3] // 10000001-01111111-00011111-11111001
+// CHECK-INST: bftmopa za1.h, { z30.h, z31.h }, z31.h, z31[3]
+// CHECK-ENCODING: [0xf9,0x1f,0x7f,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-b16b16
+// CHECK-UNKNOWN: 817f1ff9 <unknown>
+
+// widening
+
+bftmopa za0.s, {z0.h-z1.h}, z0.h, z20[0] // 10000001-01000000-00000000-00000000
+// CHECK-INST: bftmopa za0.s, { z0.h, z1.h }, z0.h, z20[0]
+// CHECK-ENCODING: [0x00,0x00,0x40,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 81400000 <unknown>
+
+bftmopa za3.s, {z12.h-z13.h}, z8.h, z23[3] // 10000001-01001000-00001101-10110011
+// CHECK-INST: bftmopa za3.s, { z12.h, z13.h }, z8.h, z23[3]
+// CHECK-ENCODING: [0xb3,0x0d,0x48,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 81480db3 <unknown>
+
+bftmopa za3.s, {z30.h-z31.h}, z31.h, z31[3] // 10000001-01011111-00011111-11110011
+// CHECK-INST: bftmopa za3.s, { z30.h, z31.h }, z31.h, z31[3]
+// CHECK-ENCODING: [0xf3,0x1f,0x5f,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 815f1ff3 <unknown>
diff --git a/llvm/test/MC/AArch64/SME2p2/directive-arch-negative.s b/llvm/test/MC/AArch64/SME2p2/directive-arch-negative.s
new file mode 100644
index 00000000000000..27169bac8133e7
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/directive-arch-negative.s
@@ -0,0 +1,7 @@
+// RUN: not llvm-mc -triple aarch64 -filetype asm -o - %s 2>&1 | FileCheck %s
+
+.arch armv9-a+sme2p2
+.arch armv9-a+nosme2p2
+ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
+// CHECK: error: instruction requires: sme2p2
+// CHECK: ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
\ No newline at end of file
diff --git a/llvm/test/MC/AArch64/SME2p2/directive-arch.s b/llvm/test/MC/AArch64/SME2p2/directive-arch.s
new file mode 100644
index 00000000000000..bb4e943a88478e
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/directive-arch.s
@@ -0,0 +1,5 @@
+// RUN: llvm-mc -triple aarch64 -o - %s 2>&1 | FileCheck %s
+
+.arch armv9-a+sme2p2
+ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
+// CHECK: ftmopa za0.s, { z0.s, z1.s }, z0.s, z20[0]
diff --git a/llvm/test/MC/AArch64/SME2p2/directive-arch_extension-negative.s b/llvm/test/MC/AArch64/SME2p2/directive-arch_extension-negative.s
new file mode 100644
index 00000000000000..68784db1c6272b
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/directive-arch_extension-negative.s
@@ -0,0 +1,7 @@
+// RUN: not llvm-mc -triple aarch64 -filetype asm -o - %s 2>&1 | FileCheck %s
+
+.arch_extension sme2p2
+.arch_extension nosme2p2
+ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
+// CHECK: error: instruction requires: sme2p2
+// CHECK: ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
diff --git a/llvm/test/MC/AArch64/SME2p2/directive-arch_extension.s b/llvm/test/MC/AArch64/SME2p2/directive-arch_extension.s
new file mode 100644
index 00000000000000..2e281e13f8ddb9
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/directive-arch_extension.s
@@ -0,0 +1,5 @@
+// RUN: llvm-mc -triple aarch64 -filetype asm -o - %s 2>&1 | FileCheck %s
+
+.arch_extension sme2p2
+ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0]
+// CHECK: ftmopa za0.s, { z0.s, z1.s }, z0.s, z20[0]
diff --git a/llvm/test/MC/AArch64/SME2p2/ftmopa-diagnostics.s b/llvm/test/MC/AArch64/SME2p2/ftmopa-diagnostics.s
new file mode 100644
index 00000000000000..e1f328819a9167
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/ftmopa-diagnostics.s
@@ -0,0 +1,212 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Invalid ZA register (range)
+
+ftmopa za2.h, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za2.h, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za2.h, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za2.h, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za4.s, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za4.s, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za4.s, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za4.s, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za4.s, {z30.s-z31.s}, z31.s, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za4.s, {z30.s-z31.s}, z31.s, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid ZA register (type suffix)
+
+ftmopa za0.b, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid matrix operand, expected za[0-3].s
+// CHECK-NEXT: ftmopa za0.b, {z30.b-z31.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.d, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid matrix operand, expected za[0-3].s
+// CHECK-NEXT: ftmopa za0.d, {z30.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z30.s-z31.s}, z31.s, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za0.h, {z30.s-z31.s}, z31.s, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid vector list operand
+
+ftmopa za0.h, {z28.b-z31.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za0.h, {z28.b-z31.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z29.b-z30.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: ftmopa za0.h, {z29.b-z30.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za0.h, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: ftmopa za0.h, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.b-z31.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za3.s, {z28.b-z31.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z29.b-z30.b}, z31.b, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: ftmopa za3.s, {z29.b-z30.b}, z31.b, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za3.s, {z28.h-z31.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: ftmopa za3.s, {z29.h-z30.h}, z31.h, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.s-z31.s}, z31.s, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: ftmopa za3.s, {z28.s-z31.s}, z31.s, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z29.s-z30.s}, z31.s, z31[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: Invalid vector list, expected list with 2 consecutive SVE vectors, where the first vector is a multiple of 2 and with matching element types
+// CHECK-NEXT: ftmopa za3.s, {z29.s-z30.s}, z31.s, z31[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+
+// --------------------------------------------------------------------------//
+// Invalid ZK register
+
+ftmopa za0.h, {z28.b-z29.b}, z31.b, z27[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za0.h, {z28.b-z29.b}, z31.b, z27[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.b-z29.b}, z31.b, z21.b[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za0.h, {z28.b-z29.b}, z31.b, z21.b[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za0.h, {z28.h-z29.h}, z31.h, z19[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.h-z29.h}, z31.h, z30.h[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za0.h, {z28.h-z29.h}, z31.h, z30.h[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.b-z29.b}, z31.b, z27[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.b-z29.b}, z31.b, z27[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.b-z29.b}, z31.b, z29.b[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.b-z29.b}, z31.b, z29.b[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.h-z29.h}, z31.h, z24[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.h-z29.h}, z31.h, z24[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.h-z29.h}, z31.h, z21.h[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.h-z29.h}, z31.h, z21.h[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.s-z29.s}, z31.s, z19[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.s-z29.s}, z31.s, z19[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.s-z29.s}, z31.s, z30.s[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid restricted vector register, expected register in z20..z23 or z28..z31
+// CHECK-NEXT: ftmopa za3.s, {z28.s-z29.s}, z31.s, z30.s[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid immediate
+
+ftmopa za0.h, {z28.b-z29.b}, z31.b, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: ftmopa za0.h, {z28.b-z29.b}, z31.b, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: ftmopa za0.h, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.b-z29.b}, z31.b, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: ftmopa za3.s, {z28.b-z29.b}, z31.b, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: ftmopa za3.s, {z28.h-z29.h}, z31.h, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za3.s, {z28.s-z29.s}, z31.s, z20[4]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: vector lane must be an integer in range [0, 3].
+// CHECK-NEXT: ftmopa za3.s, {z28.s-z29.s}, z31.s, z20[4]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid ZPR type suffix
+
+ftmopa za0.h, {z28.b-z29.b}, z31.h, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: ftmopa za0.h, {z28.b-z29.b}, z31.h, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.h, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: ftmopa za0.h, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.s, {z28.b-z29.b}, z31.h, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: ftmopa za0.s, {z28.b-z29.b}, z31.h, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.s, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: ftmopa za0.s, {z28.h-z29.h}, z31.s, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+ftmopa za0.s, {z28.s-z29.s}, z31.h, z20[3]
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid element width
+// CHECK-NEXT: ftmopa za0.s, {z28.s-z29.s}, z31.h, z20[3]
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+
diff --git a/llvm/test/MC/AArch64/SME2p2/ftmopa.s b/llvm/test/MC/AArch64/SME2p2/ftmopa.s
new file mode 100644
index 00000000000000..6944b94e6a812c
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME2p2/ftmopa.s
@@ -0,0 +1,113 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 < %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=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 < %s \
+// RUN: | llvm-objdump -d --mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 < %s \
+// RUN: | llvm-objdump -d --mattr=-sme2p2 --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 < %s \
+// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN: | llvm-mc -triple=aarch64 -mattr=+sme2p2,+sme-f8f32,+sme-f8f16,+sme-f16f16 -disassemble -show-encoding \
+// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+// 2-way (fp8-to-fp16)
+
+ftmopa za0.h, {z0.b-z1.b}, z0.b, z20[0] // 10000000-01100000-00000000-00001000
+// CHECK-INST: ftmopa za0.h, { z0.b, z1.b }, z0.b, z20[0]
+// CHECK-ENCODING: [0x08,0x00,0x60,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f16
+// CHECK-UNKNOWN: 80600008 <unknown>
+
+ftmopa za1.h, {z10.b-z11.b}, z21.b, z29[1] // 10000000-01110101-00010101-01011001
+// CHECK-INST: ftmopa za1.h, { z10.b, z11.b }, z21.b, z29[1]
+// CHECK-ENCODING: [0x59,0x15,0x75,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f16
+// CHECK-UNKNOWN: 80751559 <unknown>
+
+ftmopa za1.h, {z30.b-z31.b}, z31.b, z31[3] // 10000000-01111111-00011111-11111001
+// CHECK-INST: ftmopa za1.h, { z30.b, z31.b }, z31.b, z31[3]
+// CHECK-ENCODING: [0xf9,0x1f,0x7f,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f16
+// CHECK-UNKNOWN: 807f1ff9 <unknown>
+
+// 2-way, (fp16-to-fp32)
+
+ftmopa za0.s, {z0.h-z1.h}, z0.h, z20[0] // 10000001-01100000-00000000-00000000
+// CHECK-INST: ftmopa za0.s, { z0.h, z1.h }, z0.h, z20[0]
+// CHECK-ENCODING: [0x00,0x00,0x60,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 81600000 <unknown>
+
+ftmopa za3.s, {z12.h-z13.h}, z8.h, z23[3] // 10000001-01101000-00001101-10110011
+// CHECK-INST: ftmopa za3.s, { z12.h, z13.h }, z8.h, z23[3]
+// CHECK-ENCODING: [0xb3,0x0d,0x68,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 81680db3 <unknown>
+
+ftmopa za3.s, {z30.h-z31.h}, z31.h, z31[3] // 10000001-01111111-00011111-11110011
+// CHECK-INST: ftmopa za3.s, { z30.h, z31.h }, z31.h, z31[3]
+// CHECK-ENCODING: [0xf3,0x1f,0x7f,0x81]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 817f1ff3 <unknown>
+
+// 4-way
+
+ftmopa za0.s, {z0.b-z1.b}, z0.b, z20[0] // 10000000-01100000-00000000-00000000
+// CHECK-INST: ftmopa za0.s, { z0.b, z1.b }, z0.b, z20[0]
+// CHECK-ENCODING: [0x00,0x00,0x60,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f32
+// CHECK-UNKNOWN: 80600000 <unknown>
+
+ftmopa za3.s, {z12.b-z13.b}, z8.b, z23[3] // 10000000-01101000-00001101-10110011
+// CHECK-INST: ftmopa za3.s, { z12.b, z13.b }, z8.b, z23[3]
+// CHECK-ENCODING: [0xb3,0x0d,0x68,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f32
+// CHECK-UNKNOWN: 80680db3 <unknown>
+
+ftmopa za3.s, {z30.b-z31.b}, z31.b, z31[3] // 10000000-01111111-00011111-11110011
+// CHECK-INST: ftmopa za3.s, { z30.b, z31.b }, z31.b, z31[3]
+// CHECK-ENCODING: [0xf3,0x1f,0x7f,0x80]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f8f32
+// CHECK-UNKNOWN: 807f1ff3 <unknown>
+
+// non-widening (half-precision)
+
+ftmopa za0.h, {z0.h-z1.h}, z0.h, z20[0] // 10000001-01000000-00000000-00001000
+// CHECK-INST: ftmopa za0.h, { z0.h, z1.h }, z0.h, z20[0]
+// CHECK-ENCODING: [0x08,0x00,0x40,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f16f16
+// CHECK-UNKNOWN: 81400008 <unknown>
+
+ftmopa za1.h, {z12.h-z13.h}, z8.h, z23[3] // 10000001-01001000-00001101-10111001
+// CHECK-INST: ftmopa za1.h, { z12.h, z13.h }, z8.h, z23[3]
+// CHECK-ENCODING: [0xb9,0x0d,0x48,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f16f16
+// CHECK-UNKNOWN: 81480db9 <unknown>
+
+ftmopa za1.h, {z30.h-z31.h}, z31.h, z31[3] // 10000001-01011111-00011111-11111011
+// CHECK-INST: ftmopa za1.h, { z30.h, z31.h }, z31.h, z31[3]
+// CHECK-ENCODING: [0xf9,0x1f,0x5f,0x81]
+// CHECK-ERROR: instruction requires: sme2p2 sme-f16f16
+// CHECK-UNKNOWN: 815f1ff9 <unknown>
+
+// non-widening (single-precision)
+
+ftmopa za0.s, {z0.s-z1.s}, z0.s, z20[0] // 10000000-01000000-00000000-00000000
+// CHECK-INST: ftmopa za0.s, { z0.s, z1.s }, z0.s, z20[0]
+// CHECK-ENCODING: [0x00,0x00,0x40,0x80]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 80400000 <unknown>
+
+ftmopa za3.s, {z12.s-z13.s}, z8.s, z23[3] // 10000000-01001000-00001101-10110011
+// CHECK-INST: ftmopa za3.s, { z12.s, z13.s }, z8.s, z23[3]
+// CHECK-ENCODING: [0xb3,0x0d,0x48,0x80]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 80480db3 <unknown>
+
+ftmopa za3.s, {z30.s-z31.s}, z31.s, z31[3] // 10000000-01011111-00011111-11110011
+// CHECK-INST: ftmopa za3.s, { z30.s, z31.s }, z31.s, z31[3]
+// CHECK-ENCODING: [0xf3,0x1f,0x5f,0x80]
+// CHECK-ERROR: instruction requires: sme2p2
+// CHECK-UNKNOWN: 805f1ff3 <unknown>
\ No newline at end of file
More information about the llvm-commits
mailing list