[llvm] 2e27c4e - [AArch64][SME] Add zero instruction

Cullen Rhodes via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 27 01:36:28 PDT 2021


Author: Cullen Rhodes
Date: 2021-07-27T08:35:45Z
New Revision: 2e27c4e1f187446c84220f75e492f16807d21b12

URL: https://github.com/llvm/llvm-project/commit/2e27c4e1f187446c84220f75e492f16807d21b12
DIFF: https://github.com/llvm/llvm-project/commit/2e27c4e1f187446c84220f75e492f16807d21b12.diff

LOG: [AArch64][SME] Add zero instruction

This patch adds the zero instruction for zeroing a list of 64-bit
element ZA tiles. The instruction takes a list of up to eight tiles
ZA0.D-ZA7.D, which must be in order, e.g.

  zero {za0.d,za1.d,za2.d,za3.d,za4.d,za5.d,za6.d,za7.d}
  zero {za1.d,za3.d,za5.d,za7.d}

The assembler also accepts 32-bit, 16-bit and 8-bit element tiles which
are mapped to corresponding 64-bit element tiles in accordance with the
architecturally defined mapping between different element size tiles,
e.g.

  * Zeroing ZA0.B, or the entire array name ZA, is equivalent to zeroing
    all eight 64-bit element tiles ZA0.D to ZA7.D.
  * Zeroing ZA0.S is equivalent to zeroing ZA0.D and ZA4.D.

The preferred disassembly of this instruction uses the shortest list of
tile names that represent the encoded immediate mask, e.g.

  * An immediate which encodes 64-bit element tiles ZA0.D, ZA1.D, ZA4.D and
    ZA5.D is disassembled as {ZA0.S, ZA1.S}.
  * An immediate which encodes 64-bit element tiles ZA0.D, ZA2.D, ZA4.D and
    ZA6.D is disassembled as {ZA0.H}.
  * An all-ones immediate is disassembled as {ZA}.
  * An all-zeros immediate is disassembled as an empty list {}.

This patch adds the MatrixTileList asm operand and related parsing to support
this.

Depends on D105570.

The reference can be found here:
https://developer.arm.com/documentation/ddi0602/2021-06

Reviewed By: david-arm

Differential Revision: https://reviews.llvm.org/D105575

Added: 
    llvm/test/MC/AArch64/SME/zero-diagnostics.s
    llvm/test/MC/AArch64/SME/zero.s

Modified: 
    llvm/lib/Target/AArch64/AArch64RegisterInfo.td
    llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
    llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
    llvm/lib/Target/AArch64/SMEInstrFormats.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
index 9d689a588d39a..07dee3ce1fbc4 100644
--- a/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64RegisterInfo.td
@@ -1352,6 +1352,22 @@ class MatrixOperand<RegisterClass RC, int EltSize> : RegisterOperand<RC> {
 
 def MatrixOp : MatrixOperand<MPR, 0>;
 
+class MatrixTileListAsmOperand : AsmOperandClass {
+  let Name = "MatrixTileList";
+  let ParserMethod = "tryParseMatrixTileList";
+  let RenderMethod = "addMatrixTileListOperands";
+  let PredicateMethod = "isMatrixTileList";
+}
+
+class MatrixTileListOperand : Operand<i8> {
+  let ParserMatchClass = MatrixTileListAsmOperand<>;
+  let DecoderMethod = "DecodeMatrixTileListRegisterClass";
+  let EncoderMethod = "EncodeMatrixTileListRegisterClass";
+  let PrintMethod = "printMatrixTileList";
+}
+
+def MatrixTileList : MatrixTileListOperand<>;
+
 def MatrixIndexGPR32_12_15 : RegisterClass<"AArch64", [i32], 32, (sequence "W%u", 12, 15)> {
   let DiagnosticType = "InvalidMatrixIndexGPR32_12_15";
 }

diff  --git a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
index 2ef3e9e805334..6a0fa2fc4f4e0 100644
--- a/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64SMEInstrInfo.td
@@ -88,6 +88,12 @@ defm STR_ZA : sme_spill<"str">;
 defm INSERT_MXIPZ  : sme_vector_to_tile<"mova">;
 defm EXTRACT_ZPMXI : sme_tile_to_vector<"mova">;
 
+//===----------------------------------------------------------------------===//
+// Zero instruction
+//===----------------------------------------------------------------------===//
+
+defm ZERO_M : sme_zero<"zero">;
+
 //===----------------------------------------------------------------------===//
 // Mode selection and state access instructions
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index edbab0a00301f..f27e9b2ef0f04 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -18,6 +18,7 @@
 #include "llvm/ADT/APInt.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/ADT/StringMap.h"
@@ -262,6 +263,7 @@ class AArch64AsmParser : public MCTargetAsmParser {
   template <RegKind VectorKind>
   OperandMatchResultTy tryParseVectorList(OperandVector &Operands,
                                           bool ExpectMatch = false);
+  OperandMatchResultTy tryParseMatrixTileList(OperandVector &Operands);
   OperandMatchResultTy tryParseSVEPattern(OperandVector &Operands);
   OperandMatchResultTy tryParseGPR64x8(OperandVector &Operands);
 
@@ -322,6 +324,7 @@ class AArch64Operand : public MCParsedAsmOperand {
     k_CondCode,
     k_Register,
     k_MatrixRegister,
+    k_MatrixTileList,
     k_SVCR,
     k_VectorList,
     k_VectorIndex,
@@ -383,6 +386,10 @@ class AArch64Operand : public MCParsedAsmOperand {
     MatrixKind Kind;
   };
 
+  struct MatrixTileListOp {
+    unsigned RegMask = 0;
+  };
+
   struct VectorListOp {
     unsigned RegNum;
     unsigned Count;
@@ -460,6 +467,7 @@ class AArch64Operand : public MCParsedAsmOperand {
     struct TokOp Tok;
     struct RegOp Reg;
     struct MatrixRegOp MatrixReg;
+    struct MatrixTileListOp MatrixTileList;
     struct VectorListOp VectorList;
     struct VectorIndexOp VectorIndex;
     struct ImmOp Imm;
@@ -512,6 +520,9 @@ class AArch64Operand : public MCParsedAsmOperand {
     case k_MatrixRegister:
       MatrixReg = o.MatrixReg;
       break;
+    case k_MatrixTileList:
+      MatrixTileList = o.MatrixTileList;
+      break;
     case k_VectorList:
       VectorList = o.VectorList;
       break;
@@ -622,6 +633,11 @@ class AArch64Operand : public MCParsedAsmOperand {
     return MatrixReg.Kind;
   }
 
+  unsigned getMatrixTileListRegMask() const {
+    assert(isMatrixTileList() && "Invalid access!");
+    return MatrixTileList.RegMask;
+  }
+
   RegConstraintEqualityTy getRegEqualityTy() const {
     assert(Kind == k_Register && "Invalid access!");
     return Reg.EqualityTy;
@@ -1143,6 +1159,7 @@ class AArch64Operand : public MCParsedAsmOperand {
   }
 
   bool isMatrix() const { return Kind == k_MatrixRegister; }
+  bool isMatrixTileList() const { return Kind == k_MatrixTileList; }
 
   template <unsigned Class> bool isSVEVectorReg() const {
     RegKind RK;
@@ -1643,6 +1660,13 @@ class AArch64Operand : public MCParsedAsmOperand {
                                          FirstRegs[(unsigned)RegTy][0]));
   }
 
+  void addMatrixTileListOperands(MCInst &Inst, unsigned N) const {
+    assert(N == 1 && "Invalid number of operands!");
+    unsigned RegMask = getMatrixTileListRegMask();
+    assert(RegMask <= 0xFF && "Invalid mask!");
+    Inst.addOperand(MCOperand::createImm(RegMask));
+  }
+
   void addVectorIndexOperands(MCInst &Inst, unsigned N) const {
     assert(N == 1 && "Invalid number of operands!");
     Inst.addOperand(MCOperand::createImm(getVectorIndex()));
@@ -2012,6 +2036,45 @@ class AArch64Operand : public MCParsedAsmOperand {
     return Op;
   }
 
+  static std::unique_ptr<AArch64Operand>
+  CreateMatrixTileList(unsigned RegMask, SMLoc S, SMLoc E, MCContext &Ctx) {
+    auto Op = std::make_unique<AArch64Operand>(k_MatrixTileList, Ctx);
+    Op->MatrixTileList.RegMask = RegMask;
+    Op->StartLoc = S;
+    Op->EndLoc = E;
+    return Op;
+  }
+
+  static void ComputeRegsForAlias(unsigned Reg, SmallSet<unsigned, 8> &OutRegs,
+                                  const unsigned ElementWidth) {
+    static std::map<std::pair<unsigned, unsigned>, std::vector<unsigned>>
+        RegMap = {
+            {{0, AArch64::ZAB0},
+             {AArch64::ZAD0, AArch64::ZAD1, AArch64::ZAD2, AArch64::ZAD3,
+              AArch64::ZAD4, AArch64::ZAD5, AArch64::ZAD6, AArch64::ZAD7}},
+            {{8, AArch64::ZAB0},
+             {AArch64::ZAD0, AArch64::ZAD1, AArch64::ZAD2, AArch64::ZAD3,
+              AArch64::ZAD4, AArch64::ZAD5, AArch64::ZAD6, AArch64::ZAD7}},
+            {{16, AArch64::ZAH0},
+             {AArch64::ZAD0, AArch64::ZAD2, AArch64::ZAD4, AArch64::ZAD6}},
+            {{16, AArch64::ZAH1},
+             {AArch64::ZAD1, AArch64::ZAD3, AArch64::ZAD5, AArch64::ZAD7}},
+            {{32, AArch64::ZAS0}, {AArch64::ZAD0, AArch64::ZAD4}},
+            {{32, AArch64::ZAS1}, {AArch64::ZAD1, AArch64::ZAD5}},
+            {{32, AArch64::ZAS2}, {AArch64::ZAD2, AArch64::ZAD6}},
+            {{32, AArch64::ZAS3}, {AArch64::ZAD3, AArch64::ZAD7}},
+        };
+
+    if (ElementWidth == 64)
+      OutRegs.insert(Reg);
+    else {
+      std::vector<unsigned> Regs = RegMap[std::make_pair(ElementWidth, Reg)];
+      assert(!Regs.empty() && "Invalid tile or element width!");
+      for (auto OutReg : Regs)
+        OutRegs.insert(OutReg);
+    }
+  }
+
   static std::unique_ptr<AArch64Operand> CreateImm(const MCExpr *Val, SMLoc S,
                                                    SMLoc E, MCContext &Ctx) {
     auto Op = std::make_unique<AArch64Operand>(k_Immediate, Ctx);
@@ -2235,6 +2298,15 @@ void AArch64Operand::print(raw_ostream &OS) const {
   case k_MatrixRegister:
     OS << "<matrix " << getMatrixReg() << ">";
     break;
+  case k_MatrixTileList: {
+    OS << "<matrixlist ";
+    unsigned RegMask = getMatrixTileListRegMask();
+    unsigned MaxBits = 8;
+    for (unsigned I = MaxBits; I > 0; --I)
+      OS << ((RegMask & (1 << (I - 1))) >> (I - 1));
+    OS << '>';
+    break;
+  }
   case k_SVCR: {
     OS << getSVCR();
     break;
@@ -2418,6 +2490,26 @@ static unsigned matchSVEPredicateVectorRegName(StringRef Name) {
       .Default(0);
 }
 
+static unsigned matchMatrixTileListRegName(StringRef Name) {
+  return StringSwitch<unsigned>(Name.lower())
+      .Case("za0.d", AArch64::ZAD0)
+      .Case("za1.d", AArch64::ZAD1)
+      .Case("za2.d", AArch64::ZAD2)
+      .Case("za3.d", AArch64::ZAD3)
+      .Case("za4.d", AArch64::ZAD4)
+      .Case("za5.d", AArch64::ZAD5)
+      .Case("za6.d", AArch64::ZAD6)
+      .Case("za7.d", AArch64::ZAD7)
+      .Case("za0.s", AArch64::ZAS0)
+      .Case("za1.s", AArch64::ZAS1)
+      .Case("za2.s", AArch64::ZAS2)
+      .Case("za3.s", AArch64::ZAS3)
+      .Case("za0.h", AArch64::ZAH0)
+      .Case("za1.h", AArch64::ZAH1)
+      .Case("za0.b", AArch64::ZAB0)
+      .Default(0);
+}
+
 static unsigned matchMatrixRegName(StringRef Name) {
   return StringSwitch<unsigned>(Name.lower())
       .Case("za", AArch64::ZA)
@@ -3763,6 +3855,120 @@ bool AArch64AsmParser::parseSymbolicImmVal(const MCExpr *&ImmVal) {
   return false;
 }
 
+OperandMatchResultTy
+AArch64AsmParser::tryParseMatrixTileList(OperandVector &Operands) {
+  MCAsmParser &Parser = getParser();
+
+  if (Parser.getTok().isNot(AsmToken::LCurly))
+    return MatchOperand_NoMatch;
+
+  auto ParseMatrixTile = [this, &Parser](unsigned &Reg,
+                                         unsigned &ElementWidth) {
+    StringRef Name = Parser.getTok().getString();
+    size_t DotPosition = Name.find('.');
+    if (DotPosition == StringRef::npos)
+      return MatchOperand_NoMatch;
+
+    unsigned RegNum = matchMatrixTileListRegName(Name);
+    if (!RegNum)
+      return MatchOperand_NoMatch;
+
+    StringRef Tail = Name.drop_front(DotPosition);
+    const Optional<std::pair<int, int>> &KindRes =
+        parseVectorKind(Tail, RegKind::Matrix);
+    if (!KindRes) {
+      TokError("Expected the register to be followed by element width suffix");
+      return MatchOperand_ParseFail;
+    }
+    ElementWidth = KindRes->second;
+    Reg = RegNum;
+    Parser.Lex(); // Eat the register.
+    return MatchOperand_Success;
+  };
+
+  SMLoc S = getLoc();
+  auto LCurly = Parser.getTok();
+  Parser.Lex(); // Eat left bracket token.
+
+  // Empty matrix list
+  if (parseOptionalToken(AsmToken::RCurly)) {
+    Operands.push_back(AArch64Operand::CreateMatrixTileList(
+        /*RegMask=*/0, S, getLoc(), getContext()));
+    return MatchOperand_Success;
+  }
+
+  // Try parse {za} alias early
+  if (Parser.getTok().getString().equals_insensitive("za")) {
+    Parser.Lex(); // Eat 'za'
+
+    if (parseToken(AsmToken::RCurly, "'}' expected"))
+      return MatchOperand_ParseFail;
+
+    Operands.push_back(AArch64Operand::CreateMatrixTileList(
+        /*RegMask=*/0xFF, S, getLoc(), getContext()));
+    return MatchOperand_Success;
+  }
+
+  SMLoc TileLoc = getLoc();
+
+  unsigned FirstReg, ElementWidth;
+  auto ParseRes = ParseMatrixTile(FirstReg, ElementWidth);
+  if (ParseRes != MatchOperand_Success) {
+    Parser.getLexer().UnLex(LCurly);
+    return ParseRes;
+  }
+
+  const MCRegisterInfo *RI = getContext().getRegisterInfo();
+
+  unsigned PrevReg = FirstReg;
+  unsigned Count = 1;
+
+  SmallSet<unsigned, 8> DRegs;
+  AArch64Operand::ComputeRegsForAlias(FirstReg, DRegs, ElementWidth);
+
+  SmallSet<unsigned, 8> SeenRegs;
+  SeenRegs.insert(FirstReg);
+
+  while (parseOptionalToken(AsmToken::Comma)) {
+    TileLoc = getLoc();
+    unsigned Reg, NextElementWidth;
+    ParseRes = ParseMatrixTile(Reg, NextElementWidth);
+    if (ParseRes != MatchOperand_Success)
+      return ParseRes;
+
+    // Element size must match on all regs in the list.
+    if (ElementWidth != NextElementWidth) {
+      Error(TileLoc, "mismatched register size suffix");
+      return MatchOperand_ParseFail;
+    }
+
+    if (RI->getEncodingValue(Reg) <= (RI->getEncodingValue(PrevReg)))
+      Warning(TileLoc, "tile list not in ascending order");
+
+    if (SeenRegs.contains(Reg))
+      Warning(TileLoc, "duplicate tile in list");
+    else {
+      SeenRegs.insert(Reg);
+      AArch64Operand::ComputeRegsForAlias(Reg, DRegs, ElementWidth);
+    }
+
+    PrevReg = Reg;
+    ++Count;
+  }
+
+  if (parseToken(AsmToken::RCurly, "'}' expected"))
+    return MatchOperand_ParseFail;
+
+  unsigned RegMask = 0;
+  for (auto Reg : DRegs)
+    RegMask |= 0x1 << (RI->getEncodingValue(Reg) -
+                       RI->getEncodingValue(AArch64::ZAD0));
+  Operands.push_back(
+      AArch64Operand::CreateMatrixTileList(RegMask, S, getLoc(), getContext()));
+
+  return MatchOperand_Success;
+}
+
 template <RegKind VectorKind>
 OperandMatchResultTy
 AArch64AsmParser::tryParseVectorList(OperandVector &Operands,

diff  --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index 2f68dbcb078ff..1ed8a80a46005 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -118,6 +118,10 @@ static DecodeStatus DecodeZPR4RegisterClass(MCInst &Inst, unsigned RegNo,
 template <unsigned NumBitsForTile>
 static DecodeStatus DecodeMatrixTile(MCInst &Inst, unsigned RegNo,
                                      uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeMatrixTileListRegisterClass(MCInst &Inst,
+                                                      unsigned RegMask,
+                                                      uint64_t Address,
+                                                      const void *Decoder);
 static DecodeStatus DecodePPRRegisterClass(MCInst &Inst, unsigned RegNo,
                                            uint64_t Address,
                                            const void *Decoder);
@@ -704,6 +708,16 @@ static DecodeStatus DecodeZPR4RegisterClass(MCInst &Inst, unsigned RegNo,
   return Success;
 }
 
+static DecodeStatus DecodeMatrixTileListRegisterClass(MCInst &Inst,
+                                                      unsigned RegMask,
+                                                      uint64_t Address,
+                                                      const void *Decoder) {
+  if (RegMask > 0xFF)
+    return Fail;
+  Inst.addOperand(MCOperand::createImm(RegMask));
+  return Success;
+}
+
 static const SmallVector<SmallVector<unsigned, 16>, 5>
     MatrixZATileDecoderTable = {
         {AArch64::ZAB0},

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 1e0980515ae3c..cd1bfed9d40d0 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1340,6 +1340,36 @@ void AArch64InstPrinter::printGPRSeqPairsClassOperand(const MCInst *MI,
   O << getRegisterName(Even) << ", " << getRegisterName(Odd);
 }
 
+static const unsigned MatrixZADRegisterTable[] = {
+  AArch64::ZAD0, AArch64::ZAD1, AArch64::ZAD2, AArch64::ZAD3,
+  AArch64::ZAD4, AArch64::ZAD5, AArch64::ZAD6, AArch64::ZAD7
+};
+
+void AArch64InstPrinter::printMatrixTileList(const MCInst *MI, unsigned OpNum,
+                                             const MCSubtargetInfo &STI,
+                                             raw_ostream &O) {
+  unsigned MaxRegs = 8;
+  unsigned RegMask = MI->getOperand(OpNum).getImm();
+
+  unsigned NumRegs = 0;
+  for (unsigned I = 0; I < MaxRegs; ++I)
+    if ((RegMask & (1 << I)) != 0)
+      ++NumRegs;
+
+  O << "{";
+  unsigned Printed = 0;
+  for (unsigned I = 0; I < MaxRegs; ++I) {
+    unsigned Reg = RegMask & (1 << I);
+    if (Reg == 0)
+      continue;
+    O << getRegisterName(MatrixZADRegisterTable[I]);
+    if (Printed + 1 != NumRegs)
+      O << ", ";
+    ++Printed;
+  }
+  O << "}";
+}
+
 void AArch64InstPrinter::printVectorList(const MCInst *MI, unsigned OpNum,
                                          const MCSubtargetInfo &STI,
                                          raw_ostream &O,

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
index 566a946d521ab..9ec74a1bc7b65 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.h
@@ -146,6 +146,9 @@ class AArch64InstPrinter : public MCInstPrinter {
                        const MCSubtargetInfo &STI, raw_ostream &O,
                        StringRef LayoutSuffix);
 
+  void printMatrixTileList(const MCInst *MI, unsigned OpNum,
+                           const MCSubtargetInfo &STI, raw_ostream &O);
+
   /// Print a list of vector registers where the type suffix is implicit
   /// (i.e. attached to the instruction rather than the registers).
   void printImplicitlyTypedVectorList(const MCInst *MI, unsigned OpNum,

diff  --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
index 67a8359057218..ad97071434df3 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64MCCodeEmitter.cpp
@@ -186,6 +186,9 @@ class AArch64MCCodeEmitter : public MCCodeEmitter {
   unsigned fixOneOperandFPComparison(const MCInst &MI, unsigned EncodedValue,
                                      const MCSubtargetInfo &STI) const;
 
+  uint32_t EncodeMatrixTileListRegisterClass(const MCInst &MI, unsigned OpIdx,
+                                             SmallVectorImpl<MCFixup> &Fixups,
+                                             const MCSubtargetInfo &STI) const;
   uint32_t encodeMatrixIndexGPR32(const MCInst &MI, unsigned OpIdx,
                                   SmallVectorImpl<MCFixup> &Fixups,
                                   const MCSubtargetInfo &STI) const;
@@ -520,6 +523,14 @@ AArch64MCCodeEmitter::getVecShiftL8OpValue(const MCInst &MI, unsigned OpIdx,
   return MO.getImm() - 8;
 }
 
+uint32_t AArch64MCCodeEmitter::EncodeMatrixTileListRegisterClass(
+    const MCInst &MI, unsigned OpIdx, SmallVectorImpl<MCFixup> &Fixups,
+    const MCSubtargetInfo &STI) const {
+  unsigned RegMask = MI.getOperand(OpIdx).getImm();
+  assert(RegMask <= 0xFF && "Invalid register mask!");
+  return RegMask;
+}
+
 uint32_t
 AArch64MCCodeEmitter::encodeMatrixIndexGPR32(const MCInst &MI, unsigned OpIdx,
                                              SmallVectorImpl<MCFixup> &Fixups,

diff  --git a/llvm/lib/Target/AArch64/SMEInstrFormats.td b/llvm/lib/Target/AArch64/SMEInstrFormats.td
index 6dee95edda5db..62089166f4b75 100644
--- a/llvm/lib/Target/AArch64/SMEInstrFormats.td
+++ b/llvm/lib/Target/AArch64/SMEInstrFormats.td
@@ -653,6 +653,38 @@ multiclass sme_tile_to_vector<string mnemonic> {
   defm _V : sme_tile_to_vector_v<mnemonic, /*is_col=*/0b1>;
 }
 
+//===----------------------------------------------------------------------===//
+// SME Zero
+//===----------------------------------------------------------------------===//
+
+class sme_zero_inst<string mnemonic>
+    : I<(outs MatrixTileList:$imm), (ins),
+        mnemonic, "\t$imm", "", []>, Sched<[]> {
+  bits<8> imm;
+  let Inst{31-8} = 0b110000000000100000000000;
+  let Inst{7-0}  = imm;
+}
+
+multiclass sme_zero<string mnemonic> {
+  def NAME : sme_zero_inst<mnemonic>;
+
+  def : InstAlias<"zero\t\\{za\\}", (!cast<Instruction>(NAME) 0b11111111), 1>;
+  def : InstAlias<"zero\t\\{za0.h\\}", (!cast<Instruction>(NAME) 0b01010101), 1>;
+  def : InstAlias<"zero\t\\{za1.h\\}", (!cast<Instruction>(NAME) 0b10101010), 1>;
+  def : InstAlias<"zero\t\\{za0.s\\}", (!cast<Instruction>(NAME) 0b00010001), 1>;
+  def : InstAlias<"zero\t\\{za1.s\\}", (!cast<Instruction>(NAME) 0b00100010), 1>;
+  def : InstAlias<"zero\t\\{za2.s\\}", (!cast<Instruction>(NAME) 0b01000100), 1>;
+  def : InstAlias<"zero\t\\{za3.s\\}", (!cast<Instruction>(NAME) 0b10001000), 1>;
+  def : InstAlias<"zero\t\\{za0.s,za1.s\\}", (!cast<Instruction>(NAME) 0b00110011), 1>;
+  def : InstAlias<"zero\t\\{za0.s,za3.s\\}", (!cast<Instruction>(NAME) 0b10011001), 1>;
+  def : InstAlias<"zero\t\\{za1.s,za2.s\\}", (!cast<Instruction>(NAME) 0b01100110), 1>;
+  def : InstAlias<"zero\t\\{za2.s,za3.s\\}", (!cast<Instruction>(NAME) 0b11001100), 1>;
+  def : InstAlias<"zero\t\\{za0.s,za1.s,za2.s\\}", (!cast<Instruction>(NAME) 0b01110111), 1>;
+  def : InstAlias<"zero\t\\{za0.s,za1.s,za3.s\\}", (!cast<Instruction>(NAME) 0b10111011), 1>;
+  def : InstAlias<"zero\t\\{za0.s,za2.s,za3.s\\}", (!cast<Instruction>(NAME) 0b11011101), 1>;
+  def : InstAlias<"zero\t\\{za1.s,za2.s,za3.s\\}", (!cast<Instruction>(NAME) 0b11101110), 1>;
+}
+
 //===----------------------------------------------------------------------===//
 // SVE2 Instructions
 //===----------------------------------------------------------------------===//

diff  --git a/llvm/test/MC/AArch64/SME/zero-diagnostics.s b/llvm/test/MC/AArch64/SME/zero-diagnostics.s
new file mode 100644
index 0000000000000..44a3e462bbb78
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME/zero-diagnostics.s
@@ -0,0 +1,82 @@
+// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sme 2>&1 < %s| FileCheck %s
+
+// --------------------------------------------------------------------------//
+// Registers list not in ascending order
+
+zero    {za1.s, za0.s}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: warning: tile list not in ascending order
+// CHECK-NEXT: zero {za1.s, za0.s}
+// CHECK-NEXT:              ^
+
+zero    {za0.d, za1.d, za4.d, za3.d}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: warning: tile list not in ascending order
+// CHECK-NEXT: zero {za0.d, za1.d, za4.d, za3.d}
+// CHECK-NEXT:                            ^
+
+// --------------------------------------------------------------------------//
+// Duplicate tile
+
+zero    {za0.s, za0.s}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: warning: duplicate tile in list
+// CHECK-NEXT: zero {za0.s, za0.s}
+// CHECK-NEXT:              ^
+
+zero    {za0.d, za1.d, za2.d, za2.d, za3.d}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: warning: duplicate tile in list
+// CHECK-NEXT: zero {za0.d, za1.d, za2.d, za2.d, za3.d}
+// CHECK-NEXT:                            ^
+
+// --------------------------------------------------------------------------//
+// Mismatched register size suffix
+
+zero    {za0.b, za5.d}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: mismatched register size suffix
+// CHECK-NEXT: zero {za0.b, za5.d}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Missing '}'
+
+zero    {za
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: '}' expected
+// CHECK-NEXT: zero {za
+// CHECK-NEXT:         ^
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+// --------------------------------------------------------------------------//
+// Invalid matrix tile
+
+zero    {za0.b, za1.b}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero    {za0.b, za1.b}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za2.h}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero    {za2.h}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za0.s, za1.s, za2.s, za3.s, za4.s}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero    {za0.s, za1.s, za2.s, za3.s, za4.s}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za0.d, za1.d, za2.d, za3.d, za4.d, za5.d, za6.d, za7.d, za8.d}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero {za0.d, za1.d, za2.d, za3.d, za4.d, za5.d, za6.d, za7.d, za8.d}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za0h.b}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero    {za0h.b}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za0.s, za1h.s}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero    {za0.s, za1h.s}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:
+
+zero    {za15.q}
+// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: invalid operand for instruction
+// CHECK-NEXT: zero {za15.q}
+// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}:

diff  --git a/llvm/test/MC/AArch64/SME/zero.s b/llvm/test/MC/AArch64/SME/zero.s
new file mode 100644
index 0000000000000..c78b22352033b
--- /dev/null
+++ b/llvm/test/MC/AArch64/SME/zero.s
@@ -0,0 +1,250 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme < %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=+sme < %s \
+// RUN:        | llvm-objdump -d --mattr=+sme - | FileCheck %s --check-prefix=CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sme < %s \
+// RUN:        | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN
+// Disassemble encoding and check the re-encoding (-show-encoding) matches.
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sme < %s \
+// RUN:        | sed '/.text/d' | sed 's/.*encoding: //g' \
+// RUN:        | llvm-mc -triple=aarch64 -mattr=+sme -disassemble -show-encoding \
+// RUN:        | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+
+zero    {}
+// CHECK-INST: zero    {}
+// CHECK-ENCODING: [0x00,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 00 00 08 c0 <unknown>
+
+zero    {za0.d, za2.d, za4.d, za6.d}
+// CHECK-INST: zero {za0.h}
+// CHECK-ENCODING: [0x55,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 55 00 08 c0 <unknown>
+
+zero    {za0.d, za1.d, za2.d, za4.d, za5.d, za7.d}
+// CHECK-INST: zero    {za0.d, za1.d, za2.d, za4.d, za5.d, za7.d}
+// CHECK-ENCODING: [0xb7,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: b7 00 08 c0 <unknown>
+
+zero    {za0.d, za1.d, za2.d, za3.d, za4.d, za5.d, za6.d, za7.d}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+// --------------------------------------------------------------------------//
+// Aliases
+
+zero {za}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+zero {za0.b}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+zero {za0.h}
+// CHECK-INST: zero {za0.h}
+// CHECK-ENCODING: [0x55,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 55 00 08 c0 <unknown>
+
+zero {za1.h}
+// CHECK-INST: zero {za1.h}
+// CHECK-ENCODING: [0xaa,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: aa 00 08 c0 <unknown>
+
+zero {za0.h,za1.h}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+zero {za0.s}
+// CHECK-INST: zero {za0.s}
+// CHECK-ENCODING: [0x11,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 11 00 08 c0 <unknown>
+
+zero {za1.s}
+// CHECK-INST: zero {za1.s}
+// CHECK-ENCODING: [0x22,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 22 00 08 c0 <unknown>
+
+zero {za2.s}
+// CHECK-INST: zero {za2.s}
+// CHECK-ENCODING: [0x44,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 44 00 08 c0 <unknown>
+
+zero {za3.s}
+// CHECK-INST: zero {za3.s}
+// CHECK-ENCODING: [0x88,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 88 00 08 c0 <unknown>
+
+zero {za0.s,za1.s}
+// CHECK-INST: zero {za0.s,za1.s}
+// CHECK-ENCODING: [0x33,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 33 00 08 c0 <unknown>
+
+zero {za0.s,za2.s}
+// CHECK-INST: zero {za0.h}
+// CHECK-ENCODING: [0x55,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 55 00 08 c0 <unknown>
+
+zero {za0.s,za3.s}
+// CHECK-INST: zero {za0.s,za3.s}
+// CHECK-ENCODING: [0x99,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 99 00 08 c0 <unknown>
+
+zero {za1.s,za2.s}
+// CHECK-INST: zero {za1.s,za2.s}
+// CHECK-ENCODING: [0x66,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 66 00 08 c0 <unknown>
+
+zero {za1.s,za3.s}
+// CHECK-INST: zero {za1.h}
+// CHECK-ENCODING: [0xaa,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: aa 00 08 c0 <unknown>
+
+zero {za2.s,za3.s}
+// CHECK-INST: zero {za2.s,za3.s}
+// CHECK-ENCODING: [0xcc,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: cc 00 08 c0 <unknown>
+
+zero {za0.s,za1.s,za2.s}
+// CHECK-INST: zero {za0.s,za1.s,za2.s}
+// CHECK-ENCODING: [0x77,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 77 00 08 c0 <unknown>
+
+zero {za0.s,za1.s,za3.s}
+// CHECK-INST: zero {za0.s,za1.s,za3.s}
+// CHECK-ENCODING: [0xbb,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: bb 00 08 c0 <unknown>
+
+zero {za0.s,za2.s,za3.s}
+// CHECK-INST: zero {za0.s,za2.s,za3.s}
+// CHECK-ENCODING: [0xdd,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: dd 00 08 c0 <unknown>
+
+zero {za1.s,za2.s,za3.s}
+// CHECK-INST: zero {za1.s,za2.s,za3.s}
+// CHECK-ENCODING: [0xee,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ee 00 08 c0 <unknown>
+
+zero {za0.s,za1.s,za2.s,za3.s}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+zero {za0.d,za1.d,za2.d,za3.d,za4.d,za5.d,za6.d,za7.d}
+// CHECK-INST: zero {za}
+// CHECK-ENCODING: [0xff,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ff 00 08 c0 <unknown>
+
+zero {za0.d,za2.d,za4.d,za6.d}
+// CHECK-INST: zero {za0.h}
+// CHECK-ENCODING: [0x55,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 55 00 08 c0 <unknown>
+
+zero {za1.d,za3.d,za5.d,za7.d}
+// CHECK-INST: zero {za1.h}
+// CHECK-ENCODING: [0xaa,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: aa 00 08 c0 <unknown>
+
+zero {za0.d,za4.d}
+// CHECK-INST: zero {za0.s}
+// CHECK-ENCODING: [0x11,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 11 00 08 c0 <unknown>
+
+zero {za1.d,za5.d}
+// CHECK-INST: zero {za1.s}
+// CHECK-ENCODING: [0x22,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 22 00 08 c0 <unknown>
+
+zero {za2.d,za6.d}
+// CHECK-INST: zero {za2.s}
+// CHECK-ENCODING: [0x44,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 44 00 08 c0 <unknown>
+
+zero {za3.d,za7.d}
+// CHECK-INST: zero {za3.s}
+// CHECK-ENCODING: [0x88,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 88 00 08 c0 <unknown>
+
+zero {za0.d,za1.d,za4.d,za5.d}
+// CHECK-INST: zero {za0.s,za1.s}
+// CHECK-ENCODING: [0x33,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 33 00 08 c0 <unknown>
+
+zero {za0.d,za3.d,za4.d,za7.d}
+// CHECK-INST: zero {za0.s,za3.s}
+// CHECK-ENCODING: [0x99,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 99 00 08 c0 <unknown>
+
+zero {za1.d,za2.d,za5.d,za6.d}
+// CHECK-INST: zero {za1.s,za2.s}
+// CHECK-ENCODING: [0x66,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 66 00 08 c0 <unknown>
+
+zero {za2.d,za3.d,za6.d,za7.d}
+// CHECK-INST: zero {za2.s,za3.s}
+// CHECK-ENCODING: [0xcc,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: cc 00 08 c0 <unknown>
+
+zero {za0.d,za1.d,za2.d,za4.d,za5.d,za6.d}
+// CHECK-INST: zero {za0.s,za1.s,za2.s}
+// CHECK-ENCODING: [0x77,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: 77 00 08 c0 <unknown>
+
+zero {za0.d,za1.d,za3.d,za4.d,za5.d,za7.d}
+// CHECK-INST: zero {za0.s,za1.s,za3.s}
+// CHECK-ENCODING: [0xbb,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: bb 00 08 c0 <unknown>
+
+zero {za0.d,za2.d,za3.d,za4.d,za6.d,za7.d}
+// CHECK-INST: zero {za0.s,za2.s,za3.s}
+// CHECK-ENCODING: [0xdd,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: dd 00 08 c0 <unknown>
+
+zero {za1.d,za2.d,za3.d,za5.d,za6.d,za7.d}
+// CHECK-INST: zero {za1.s,za2.s,za3.s}
+// CHECK-ENCODING: [0xee,0x00,0x08,0xc0]
+// CHECK-ERROR: instruction requires: sme
+// CHECK-UNKNOWN: ee 00 08 c0 <unknown>


        


More information about the llvm-commits mailing list