[llvm] [LLVM][AArch64] Add assembly/disassembly for SME2p2 ftmopa and bftmopa (PR #112876)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Oct 18 03:11:04 PDT 2024
https://github.com/SpencerAbson created https://github.com/llvm/llvm-project/pull/112876
**note** This work is based off of another change which adds the register classes and operands seen here, it is currently in review: https://github.com/llvm/llvm-project/pull/111717. This work has been pushed early to provide verification for the implementation of the ZK register operand, which the above patch could not provide in isolation. Thanks.
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
In accordance with: https://developer.arm.com/documentation/ddi0602/latest/
It also introduces .arch assembler tests for the new sme2p2 feature.
Co-authored-by: Marian Lukac marian.lukac at arm.com
>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/6] [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/6] [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/6] [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/6] [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/6] 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 ce8cee9ed92089f69ab303c284156c98a1a750ed 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 6/6] [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