[AArch64] Adding "armv8.8-a" memcpy/memset support.
authorSimon Tatham <simon.tatham@arm.com>
Thu, 11 Feb 2021 11:41:20 +0000 (11:41 +0000)
committerTomas Matheson <tomas.matheson@arm.com>
Wed, 5 Jan 2022 14:44:24 +0000 (14:44 +0000)
This family of instructions includes CPYF (copy forward), CPYB (copy
backward), SET (memset) and SETG (memset + initialise MTE tags), with
some sub-variants to indicate whether address translation is done in a
privileged or unprivileged way. For the copy instructions, you can
separately specify the read and write translations (so that kernels
can safely use these instructions in syscall handlers, to memcpy
between the calling process's user-space memory map and the kernel's
own privileged one).

The unusual thing about these instructions is that they write back to
multiple registers, because they perform an implementation-defined
amount of copying each time they run, and write back to _all_ the
address and size registers to indicate how much remains to be done
(and the code is expected to loop on them until the size register
becomes zero). But this is no problem in LLVM - you just define each
instruction to have multiple outputs, multiple inputs, and a set of
constraints tying their register numbers together appropriately.

This commit introduces a special subtarget feature called MOPS (after
the name the spec gives to the CPU id field), which is a dependency of
the top-level 8.8-A feature, and uses that to enable most of the new
instructions. The SETMG instructions also depend on MTE (and the test
checks that).

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

15 files changed:
llvm/lib/Target/AArch64/AArch64.td
llvm/lib/Target/AArch64/AArch64InstrFormats.td
llvm/lib/Target/AArch64/AArch64InstrInfo.td
llvm/lib/Target/AArch64/AArch64SchedA57.td
llvm/lib/Target/AArch64/AArch64SchedA64FX.td
llvm/lib/Target/AArch64/AArch64SchedExynosM3.td
llvm/lib/Target/AArch64/AArch64SchedExynosM4.td
llvm/lib/Target/AArch64/AArch64SchedExynosM5.td
llvm/lib/Target/AArch64/AArch64SchedThunderX2T99.td
llvm/lib/Target/AArch64/AArch64SchedThunderX3T110.td
llvm/lib/Target/AArch64/AArch64Subtarget.h
llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
llvm/test/MC/AArch64/armv8.8a-mops.s [new file with mode: 0644]
llvm/test/MC/Disassembler/AArch64/armv8.8a-mops.txt [new file with mode: 0644]

index 22e0c49..0a2d88c 100644 (file)
@@ -419,6 +419,9 @@ def FeatureLS64 : SubtargetFeature<"ls64", "HasLS64",
 def FeatureHBC : SubtargetFeature<"hbc", "HasHBC",
     "true", "Enable Armv8.8-A Hinted Conditional Branches Extension">;
 
+def FeatureMOPS : SubtargetFeature<"mops", "HasMOPS",
+    "true", "Enable Armv8.8-A memcpy and memset acceleration instructions">;
+
 def FeatureBRBE : SubtargetFeature<"brbe", "HasBRBE",
     "true", "Enable Branch Record Buffer Extension">;
 
@@ -502,7 +505,7 @@ def HasV8_7aOps : SubtargetFeature<
 
 def HasV8_8aOps : SubtargetFeature<
   "v8.8a", "HasV8_8aOps", "true", "Support ARM v8.8a instructions",
-  [HasV8_7aOps, FeatureHBC]>;
+  [HasV8_7aOps, FeatureHBC, FeatureMOPS]>;
 
 def HasV9_0aOps : SubtargetFeature<
   "v9a", "HasV9_0aOps", "true", "Support ARM v9a instructions",
index 7433552..fce3126 100644 (file)
@@ -11430,6 +11430,123 @@ class Store64BV<bits<3> opc, string asm_inst, list<dag> pat = []>
   let Inst{20-16} = Rs;
 }
 
+class MOPSMemoryCopyMoveBase<bit isMove, bits<2> opcode, bits<2> op1,
+                             bits<2> op2, string asm>
+  : I<(outs GPR64common:$Rd_wb, GPR64common:$Rs_wb, GPR64:$Rn_wb),
+      (ins GPR64common:$Rd, GPR64common:$Rs, GPR64:$Rn),
+      asm, "\t[$Rd]!, [$Rs]!, $Rn!",
+      "$Rd = $Rd_wb,$Rs = $Rs_wb,$Rn = $Rn_wb", []>,
+    Sched<[]> {
+  bits<5> Rd;
+  bits<5> Rs;
+  bits<5> Rn;
+  let Inst{31-27} = 0b00011;
+  let Inst{26} = isMove;
+  let Inst{25-24} = 0b01;
+  let Inst{23-22} = opcode;
+  let Inst{21} = 0b0;
+  let Inst{20-16} = Rs;
+  let Inst{15-14} = op2;
+  let Inst{13-12} = op1;
+  let Inst{11-10} = 0b01;
+  let Inst{9-5} = Rn;
+  let Inst{4-0} = Rd;
+
+  let DecoderMethod = "DecodeCPYMemOpInstruction";
+  let mayLoad = 1;
+  let mayStore = 1;
+}
+
+class MOPSMemoryCopy<bits<2> opcode, bits<2> op1, bits<2> op2, string asm>
+  : MOPSMemoryCopyMoveBase<0, opcode, op1, op2, asm>;
+
+class MOPSMemoryMove<bits<2> opcode, bits<2> op1, bits<2> op2, string asm>
+  : MOPSMemoryCopyMoveBase<1, opcode, op1, op2, asm>;
+
+class MOPSMemorySetBase<bit isTagging, bits<2> opcode, bit op1, bit op2,
+                        string asm>
+  : I<(outs GPR64common:$Rd_wb, GPR64:$Rn_wb),
+      (ins GPR64common:$Rd, GPR64:$Rn, GPR64:$Rm),
+      asm, "\t[$Rd]!, $Rn!, $Rm",
+      "$Rd = $Rd_wb,$Rn = $Rn_wb", []>,
+    Sched<[]> {
+  bits<5> Rd;
+  bits<5> Rn;
+  bits<5> Rm;
+  let Inst{31-27} = 0b00011;
+  let Inst{26} = isTagging;
+  let Inst{25-21} = 0b01110;
+  let Inst{20-16} = Rm;
+  let Inst{15-14} = opcode;
+  let Inst{13} = op2;
+  let Inst{12} = op1;
+  let Inst{11-10} = 0b01;
+  let Inst{9-5} = Rn;
+  let Inst{4-0} = Rd;
+
+  let DecoderMethod = "DecodeSETMemOpInstruction";
+  let mayLoad = 0;
+  let mayStore = 1;
+}
+
+class MOPSMemorySet<bits<2> opcode, bit op1, bit op2, string asm>
+  : MOPSMemorySetBase<0, opcode, op1, op2, asm>;
+
+class MOPSMemorySetTagging<bits<2> opcode, bit op1, bit op2, string asm>
+  : MOPSMemorySetBase<1, opcode, op1, op2, asm>;
+
+multiclass MOPSMemoryCopyInsns<bits<2> opcode, string asm> {
+  def ""   : MOPSMemoryCopy<opcode, 0b00, 0b00, asm>;
+  def WN   : MOPSMemoryCopy<opcode, 0b00, 0b01, asm # "wn">;
+  def RN   : MOPSMemoryCopy<opcode, 0b00, 0b10, asm # "rn">;
+  def N    : MOPSMemoryCopy<opcode, 0b00, 0b11, asm # "n">;
+  def WT   : MOPSMemoryCopy<opcode, 0b01, 0b00, asm # "wt">;
+  def WTWN : MOPSMemoryCopy<opcode, 0b01, 0b01, asm # "wtwn">;
+  def WTRN : MOPSMemoryCopy<opcode, 0b01, 0b10, asm # "wtrn">;
+  def WTN  : MOPSMemoryCopy<opcode, 0b01, 0b11, asm # "wtn">;
+  def RT   : MOPSMemoryCopy<opcode, 0b10, 0b00, asm # "rt">;
+  def RTWN : MOPSMemoryCopy<opcode, 0b10, 0b01, asm # "rtwn">;
+  def RTRN : MOPSMemoryCopy<opcode, 0b10, 0b10, asm # "rtrn">;
+  def RTN  : MOPSMemoryCopy<opcode, 0b10, 0b11, asm # "rtn">;
+  def T    : MOPSMemoryCopy<opcode, 0b11, 0b00, asm # "t">;
+  def TWN  : MOPSMemoryCopy<opcode, 0b11, 0b01, asm # "twn">;
+  def TRN  : MOPSMemoryCopy<opcode, 0b11, 0b10, asm # "trn">;
+  def TN   : MOPSMemoryCopy<opcode, 0b11, 0b11, asm # "tn">;
+}
+
+multiclass MOPSMemoryMoveInsns<bits<2> opcode, string asm> {
+  def ""   : MOPSMemoryMove<opcode, 0b00, 0b00, asm>;
+  def WN   : MOPSMemoryMove<opcode, 0b00, 0b01, asm # "wn">;
+  def RN   : MOPSMemoryMove<opcode, 0b00, 0b10, asm # "rn">;
+  def N    : MOPSMemoryMove<opcode, 0b00, 0b11, asm # "n">;
+  def WT   : MOPSMemoryMove<opcode, 0b01, 0b00, asm # "wt">;
+  def WTWN : MOPSMemoryMove<opcode, 0b01, 0b01, asm # "wtwn">;
+  def WTRN : MOPSMemoryMove<opcode, 0b01, 0b10, asm # "wtrn">;
+  def WTN  : MOPSMemoryMove<opcode, 0b01, 0b11, asm # "wtn">;
+  def RT   : MOPSMemoryMove<opcode, 0b10, 0b00, asm # "rt">;
+  def RTWN : MOPSMemoryMove<opcode, 0b10, 0b01, asm # "rtwn">;
+  def RTRN : MOPSMemoryMove<opcode, 0b10, 0b10, asm # "rtrn">;
+  def RTN  : MOPSMemoryMove<opcode, 0b10, 0b11, asm # "rtn">;
+  def T    : MOPSMemoryMove<opcode, 0b11, 0b00, asm # "t">;
+  def TWN  : MOPSMemoryMove<opcode, 0b11, 0b01, asm # "twn">;
+  def TRN  : MOPSMemoryMove<opcode, 0b11, 0b10, asm # "trn">;
+  def TN   : MOPSMemoryMove<opcode, 0b11, 0b11, asm # "tn">;
+}
+
+multiclass MOPSMemorySetInsns<bits<2> opcode, string asm> {
+  def "" : MOPSMemorySet<opcode, 0, 0, asm>;
+  def T  : MOPSMemorySet<opcode, 1, 0, asm # "t">;
+  def N  : MOPSMemorySet<opcode, 0, 1, asm # "n">;
+  def TN : MOPSMemorySet<opcode, 1, 1, asm # "tn">;
+}
+
+multiclass MOPSMemorySetTaggingInsns<bits<2> opcode, string asm> {
+  def "" : MOPSMemorySetTagging<opcode, 0, 0, asm>;
+  def T  : MOPSMemorySetTagging<opcode, 1, 0, asm # "t">;
+  def N  : MOPSMemorySetTagging<opcode, 0, 1, asm # "n">;
+  def TN : MOPSMemorySetTagging<opcode, 1, 1, asm # "tn">;
+}
+
 //----------------------------------------------------------------------------
 // Allow the size specifier tokens to be upper case, not just lower.
 def : TokenAlias<".4B", ".4b">;  // Add dot product
index 7ee2a74..af944ce 100644 (file)
@@ -200,8 +200,10 @@ def HasBRBE          : Predicate<"Subtarget->hasBRBE()">,
                        AssemblerPredicate<(all_of FeatureBRBE), "brbe">;
 def HasSPE_EEF       : Predicate<"Subtarget->hasSPE_EEF()">,
                        AssemblerPredicate<(all_of FeatureSPE_EEF), "spe-eef">;
-def HasHBC            : Predicate<"Subtarget->hasHBC()">,
+def HasHBC           : Predicate<"Subtarget->hasHBC()">,
                        AssemblerPredicate<(all_of FeatureHBC), "hbc">;
+def HasMOPS          : Predicate<"Subtarget->hasMOPS()">,
+                       AssemblerPredicate<(all_of FeatureMOPS), "mops">;
 def IsLE             : Predicate<"Subtarget->isLittleEndian()">;
 def IsBE             : Predicate<"!Subtarget->isLittleEndian()">;
 def IsWindows        : Predicate<"Subtarget->isTargetWindows()">;
@@ -8315,6 +8317,26 @@ let Predicates = [HasLS64] in {
   def : ST64BPattern<int_aarch64_st64bv0, ST64BV0>;
 }
 
+let Predicates = [HasMOPS] in {
+  defm CPYFP : MOPSMemoryCopyInsns<0b00, "cpyfp">;
+  defm CPYFM : MOPSMemoryCopyInsns<0b01, "cpyfm">;
+  defm CPYFE : MOPSMemoryCopyInsns<0b10, "cpyfe">;
+
+  defm CPYP : MOPSMemoryMoveInsns<0b00, "cpyp">;
+  defm CPYM : MOPSMemoryMoveInsns<0b01, "cpym">;
+  defm CPYE : MOPSMemoryMoveInsns<0b10, "cpye">;
+
+  defm SETP : MOPSMemorySetInsns<0b00, "setp">;
+  defm SETM : MOPSMemorySetInsns<0b01, "setm">;
+  defm SETE : MOPSMemorySetInsns<0b10, "sete">;
+}
+let Predicates = [HasMOPS, HasMTE] in {
+  defm SETGP     : MOPSMemorySetTaggingInsns<0b00, "setgp">;
+  defm SETGM     : MOPSMemorySetTaggingInsns<0b01, "setgm">;
+  // Can't use SETGE because it's a reserved name in TargetSelectionDAG.td
+  defm MOPSSETGE : MOPSMemorySetTaggingInsns<0b10, "setge">;
+}
+
 let Defs = [X16, X17], mayStore = 1, isCodeGenOnly = 1 in
 def StoreSwiftAsyncContext
       : Pseudo<(outs), (ins GPR64:$ctx, GPR64sp:$base, simm9:$offset),
index 168a762..61538cb 100644 (file)
@@ -526,7 +526,7 @@ def : InstRW<[A57Write_5cyc_2V], (instregex "^FRINT[AIMNPXZ](v4f32|v2f64)")>;
 def : InstRW<[A57Write_3cyc_2V], (instregex "^(BIF|BIT|BSL|BSP)v16i8")>;
 
 // ASIMD duplicate, gen reg, D-form and Q-form
-def : InstRW<[A57Write_8cyc_1L_1V], (instregex "^CPY")>;
+def : InstRW<[A57Write_8cyc_1L_1V], (instregex "^CPY[^PMEF]")>;
 def : InstRW<[A57Write_8cyc_1L_1V], (instregex "^DUPv.+gpr")>;
 
 // ASIMD move, saturating
index 1d25a6c..6d1ef66 100644 (file)
@@ -1891,7 +1891,7 @@ def : InstRW<[A64FXWrite_4Cyc_GI0],
 // ASIMD duplicate, gen reg
 // ASIMD duplicate, element
 def : InstRW<[A64FXWrite_DUPGENERAL], (instregex "^DUPv")>;
-def : InstRW<[A64FXWrite_6Cyc_GI0], (instregex "^CPY")>;
+def : InstRW<[A64FXWrite_6Cyc_GI0], (instregex "^CPY[^PMEF]")>;
 def : InstRW<[A64FXWrite_6Cyc_GI0], (instregex "^DUPv.+gpr")>;
 
 // ASIMD extract
index 14df823..c834ed9 100644 (file)
@@ -669,7 +669,7 @@ def : InstRW<[M3WriteNEONB], (instregex "^DUPv.+gpr")>;
 def : InstRW<[M3WriteNSHF1], (instregex "^DUPv.+lane")>;
 def : InstRW<[M3WriteNSHF1], (instregex "^EXTv")>;
 def : InstRW<[M3WriteNSHF1], (instregex "^[SU]?Q?XTU?Nv")>;
-def : InstRW<[M3WriteNSHF1], (instregex "^CPY")>;
+def : InstRW<[M3WriteNSHF1], (instregex "^CPY[^PMEF]")>;
 def : InstRW<[M3WriteNSHF1], (instregex "^INSv.+lane")>;
 def : InstRW<[M3WriteMOVI],  (instregex "^MOVI")>;
 def : InstRW<[M3WriteNALU1], (instregex "^FMOVv")>;
index 8f740a9..65439dc 100644 (file)
@@ -810,7 +810,7 @@ def : InstRW<[M4WriteNALU1],  (instregex "^RBITv")>;
 def : InstRW<[M4WriteNALU1],  (instregex "^(BIF|BIT|BSL|BSP)v")>;
 def : InstRW<[M4WriteNALU1],  (instregex "^CL[STZ]v")>;
 def : InstRW<[M4WriteNEONB],  (instregex "^DUPv.+gpr")>;
-def : InstRW<[M4WriteNSHF1],  (instregex "^CPY")>;
+def : InstRW<[M4WriteNSHF1],  (instregex "^CPY[^PMEF]")>;
 def : InstRW<[M4WriteNSHF1],  (instregex "^DUPv.+lane")>;
 def : InstRW<[M4WriteNSHF1],  (instregex "^EXTv")>;
 def : InstRW<[M4WriteNSHT4A], (instregex "^XTNv")>;
index 93e1b66..6e14dbe 100644 (file)
@@ -848,7 +848,7 @@ def : InstRW<[M5WriteNALU2],  (instregex "^RBITv")>;
 def : InstRW<[M5WriteNALU2],  (instregex "^(BIF|BIT|BSL|BSP)v")>;
 def : InstRW<[M5WriteNALU2],  (instregex "^CL[STZ]v")>;
 def : InstRW<[M5WriteNEONB],  (instregex "^DUPv.+gpr")>;
-def : InstRW<[M5WriteNSHF2],  (instregex "^CPY")>;
+def : InstRW<[M5WriteNSHF2],  (instregex "^CPY[^PMEF]")>;
 def : InstRW<[M5WriteNSHF2],  (instregex "^DUPv.+lane")>;
 def : InstRW<[M5WriteNSHF2],  (instregex "^EXTv")>;
 def : InstRW<[M5WriteNSHT4A], (instregex "^XTNv")>;
index e4cae97..41dd1ca 100644 (file)
@@ -1499,7 +1499,7 @@ def : InstRW<[THX2T99Write_5Cyc_F01],
 // ASIMD duplicate, gen reg
 // ASIMD duplicate, element
 def : InstRW<[THX2T99Write_5Cyc_F01], (instregex "^DUPv")>;
-def : InstRW<[THX2T99Write_5Cyc_F01], (instregex "^CPY")>;
+def : InstRW<[THX2T99Write_5Cyc_F01], (instregex "^CPY[^PMEF]")>;
 def : InstRW<[THX2T99Write_5Cyc_F01], (instregex "^DUPv.+gpr")>;
 
 // ASIMD extract
index 08be2b3..f27a431 100644 (file)
@@ -1608,7 +1608,7 @@ def : InstRW<[THX3T110Write_3_4Cyc_F23_F0123],
 // ASIMD duplicate, gen reg
 // ASIMD duplicate, element
 def : InstRW<[THX3T110Write_5Cyc_F0123], (instregex "^DUPv")>;
-def : InstRW<[THX3T110Write_5Cyc_F0123], (instregex "^CPY")>;
+def : InstRW<[THX3T110Write_5Cyc_F0123], (instregex "^CPY[^PMEF]")>;
 def : InstRW<[THX3T110Write_5Cyc_F0123], (instregex "^DUPv.+gpr")>;
 
 // ASIMD extract
index adb10a4..5057dbe 100644 (file)
@@ -192,6 +192,7 @@ protected:
 
   // Armv8.8-A Extensions
   bool HasHBC = false;
+  bool HasMOPS = false;
 
   // Arm SVE2 extensions
   bool HasSVE2 = false;
@@ -584,6 +585,7 @@ public:
   bool hasEL2VMSA() const { return HasEL2VMSA; }
   bool hasEL3() const { return HasEL3; }
   bool hasHBC() const { return HasHBC; }
+  bool hasMOPS() const { return HasMOPS; }
 
   bool fixCortexA53_835769() const { return FixCortexA53_835769; }
 
index fb709b9..888d73b 100644 (file)
@@ -4866,6 +4866,177 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
   }
   }
 
+  // Check v8.8-A memops instructions.
+  switch (Inst.getOpcode()) {
+  case AArch64::CPYFP:
+  case AArch64::CPYFPWN:
+  case AArch64::CPYFPRN:
+  case AArch64::CPYFPN:
+  case AArch64::CPYFPWT:
+  case AArch64::CPYFPWTWN:
+  case AArch64::CPYFPWTRN:
+  case AArch64::CPYFPWTN:
+  case AArch64::CPYFPRT:
+  case AArch64::CPYFPRTWN:
+  case AArch64::CPYFPRTRN:
+  case AArch64::CPYFPRTN:
+  case AArch64::CPYFPT:
+  case AArch64::CPYFPTWN:
+  case AArch64::CPYFPTRN:
+  case AArch64::CPYFPTN:
+  case AArch64::CPYFM:
+  case AArch64::CPYFMWN:
+  case AArch64::CPYFMRN:
+  case AArch64::CPYFMN:
+  case AArch64::CPYFMWT:
+  case AArch64::CPYFMWTWN:
+  case AArch64::CPYFMWTRN:
+  case AArch64::CPYFMWTN:
+  case AArch64::CPYFMRT:
+  case AArch64::CPYFMRTWN:
+  case AArch64::CPYFMRTRN:
+  case AArch64::CPYFMRTN:
+  case AArch64::CPYFMT:
+  case AArch64::CPYFMTWN:
+  case AArch64::CPYFMTRN:
+  case AArch64::CPYFMTN:
+  case AArch64::CPYFE:
+  case AArch64::CPYFEWN:
+  case AArch64::CPYFERN:
+  case AArch64::CPYFEN:
+  case AArch64::CPYFEWT:
+  case AArch64::CPYFEWTWN:
+  case AArch64::CPYFEWTRN:
+  case AArch64::CPYFEWTN:
+  case AArch64::CPYFERT:
+  case AArch64::CPYFERTWN:
+  case AArch64::CPYFERTRN:
+  case AArch64::CPYFERTN:
+  case AArch64::CPYFET:
+  case AArch64::CPYFETWN:
+  case AArch64::CPYFETRN:
+  case AArch64::CPYFETN:
+  case AArch64::CPYP:
+  case AArch64::CPYPWN:
+  case AArch64::CPYPRN:
+  case AArch64::CPYPN:
+  case AArch64::CPYPWT:
+  case AArch64::CPYPWTWN:
+  case AArch64::CPYPWTRN:
+  case AArch64::CPYPWTN:
+  case AArch64::CPYPRT:
+  case AArch64::CPYPRTWN:
+  case AArch64::CPYPRTRN:
+  case AArch64::CPYPRTN:
+  case AArch64::CPYPT:
+  case AArch64::CPYPTWN:
+  case AArch64::CPYPTRN:
+  case AArch64::CPYPTN:
+  case AArch64::CPYM:
+  case AArch64::CPYMWN:
+  case AArch64::CPYMRN:
+  case AArch64::CPYMN:
+  case AArch64::CPYMWT:
+  case AArch64::CPYMWTWN:
+  case AArch64::CPYMWTRN:
+  case AArch64::CPYMWTN:
+  case AArch64::CPYMRT:
+  case AArch64::CPYMRTWN:
+  case AArch64::CPYMRTRN:
+  case AArch64::CPYMRTN:
+  case AArch64::CPYMT:
+  case AArch64::CPYMTWN:
+  case AArch64::CPYMTRN:
+  case AArch64::CPYMTN:
+  case AArch64::CPYE:
+  case AArch64::CPYEWN:
+  case AArch64::CPYERN:
+  case AArch64::CPYEN:
+  case AArch64::CPYEWT:
+  case AArch64::CPYEWTWN:
+  case AArch64::CPYEWTRN:
+  case AArch64::CPYEWTN:
+  case AArch64::CPYERT:
+  case AArch64::CPYERTWN:
+  case AArch64::CPYERTRN:
+  case AArch64::CPYERTN:
+  case AArch64::CPYET:
+  case AArch64::CPYETWN:
+  case AArch64::CPYETRN:
+  case AArch64::CPYETN: {
+    unsigned Xd_wb = Inst.getOperand(0).getReg();
+    unsigned Xs_wb = Inst.getOperand(1).getReg();
+    unsigned Xn_wb = Inst.getOperand(2).getReg();
+    unsigned Xd = Inst.getOperand(3).getReg();
+    unsigned Xs = Inst.getOperand(4).getReg();
+    unsigned Xn = Inst.getOperand(5).getReg();
+    if (Xd_wb != Xd)
+      return Error(Loc[0],
+                   "invalid CPY instruction, Xd_wb and Xd do not match");
+    if (Xs_wb != Xs)
+      return Error(Loc[0],
+                   "invalid CPY instruction, Xs_wb and Xs do not match");
+    if (Xn_wb != Xn)
+      return Error(Loc[0],
+                   "invalid CPY instruction, Xn_wb and Xn do not match");
+    if (Xd == Xs)
+      return Error(Loc[0], "invalid CPY instruction, destination and source"
+                           " registers are the same");
+    if (Xd == Xn)
+      return Error(Loc[0], "invalid CPY instruction, destination and size"
+                           " registers are the same");
+    if (Xs == Xn)
+      return Error(Loc[0], "invalid CPY instruction, source and size"
+                           " registers are the same");
+    break;
+  }
+  case AArch64::SETP:
+  case AArch64::SETPT:
+  case AArch64::SETPN:
+  case AArch64::SETPTN:
+  case AArch64::SETM:
+  case AArch64::SETMT:
+  case AArch64::SETMN:
+  case AArch64::SETMTN:
+  case AArch64::SETE:
+  case AArch64::SETET:
+  case AArch64::SETEN:
+  case AArch64::SETETN:
+  case AArch64::SETGP:
+  case AArch64::SETGPT:
+  case AArch64::SETGPN:
+  case AArch64::SETGPTN:
+  case AArch64::SETGM:
+  case AArch64::SETGMT:
+  case AArch64::SETGMN:
+  case AArch64::SETGMTN:
+  case AArch64::MOPSSETGE:
+  case AArch64::MOPSSETGET:
+  case AArch64::MOPSSETGEN:
+  case AArch64::MOPSSETGETN: {
+    unsigned Xd_wb = Inst.getOperand(0).getReg();
+    unsigned Xn_wb = Inst.getOperand(1).getReg();
+    unsigned Xd = Inst.getOperand(2).getReg();
+    unsigned Xn = Inst.getOperand(3).getReg();
+    unsigned Xm = Inst.getOperand(4).getReg();
+    if (Xd_wb != Xd)
+      return Error(Loc[0],
+                   "invalid SET instruction, Xd_wb and Xd do not match");
+    if (Xn_wb != Xn)
+      return Error(Loc[0],
+                   "invalid SET instruction, Xn_wb and Xn do not match");
+    if (Xd == Xn)
+      return Error(Loc[0], "invalid SET instruction, destination and size"
+                           " registers are the same");
+    if (Xd == Xm)
+      return Error(Loc[0], "invalid SET instruction, destination and source"
+                           " registers are the same");
+    if (Xn == Xm)
+      return Error(Loc[0], "invalid SET instruction, source and size"
+                           " registers are the same");
+    break;
+  }
+  }
 
   // Now check immediate ranges. Separate from the above as there is overlap
   // in the instructions being checked and this keeps the nested conditionals
index 96d410e..2c38172 100644 (file)
@@ -238,6 +238,12 @@ static DecodeStatus DecodeSVEIncDecImm(MCInst &Inst, unsigned Imm,
                                        uint64_t Addr, const void *Decoder);
 static DecodeStatus DecodeSVCROp(MCInst &Inst, unsigned Imm, uint64_t Address,
                                  const void *Decoder);
+static DecodeStatus DecodeCPYMemOpInstruction(MCInst &Inst, uint32_t insn,
+                                              uint64_t Addr,
+                                              const void *Decoder);
+static DecodeStatus DecodeSETMemOpInstruction(MCInst &Inst, uint32_t insn,
+                                              uint64_t Addr,
+                                              const void *Decoder);
 
 static bool Check(DecodeStatus &Out, DecodeStatus In) {
   switch (In) {
@@ -1842,3 +1848,52 @@ static DecodeStatus DecodeSVCROp(MCInst &Inst, unsigned Imm, uint64_t Address,
   }
   return Fail;
 }
+
+static DecodeStatus DecodeCPYMemOpInstruction(MCInst &Inst, uint32_t insn,
+                                              uint64_t Addr,
+                                              const void *Decoder) {
+  unsigned Rd = fieldFromInstruction(insn, 0, 5);
+  unsigned Rs = fieldFromInstruction(insn, 16, 5);
+  unsigned Rn = fieldFromInstruction(insn, 5, 5);
+
+  // None of the registers may alias: if they do, then the instruction is not
+  // merely unpredictable but actually entirely unallocated.
+  if (Rd == Rs || Rs == Rn || Rd == Rn)
+    return MCDisassembler::Fail;
+
+  // All three register operands are written back, so they all appear
+  // twice in the operand list, once as outputs and once as inputs.
+  if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+      !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) ||
+      !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+      !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+      !DecodeGPR64commonRegisterClass(Inst, Rs, Addr, Decoder) ||
+      !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder))
+    return MCDisassembler::Fail;
+
+  return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeSETMemOpInstruction(MCInst &Inst, uint32_t insn,
+                                              uint64_t Addr,
+                                              const void *Decoder) {
+  unsigned Rd = fieldFromInstruction(insn, 0, 5);
+  unsigned Rm = fieldFromInstruction(insn, 16, 5);
+  unsigned Rn = fieldFromInstruction(insn, 5, 5);
+
+  // None of the registers may alias: if they do, then the instruction is not
+  // merely unpredictable but actually entirely unallocated.
+  if (Rd == Rm || Rm == Rn || Rd == Rn)
+    return MCDisassembler::Fail;
+
+  // Rd and Rn (not Rm) register operands are written back, so they appear
+  // twice in the operand list, once as outputs and once as inputs.
+  if (!DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+      !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+      !DecodeGPR64commonRegisterClass(Inst, Rd, Addr, Decoder) ||
+      !DecodeGPR64RegisterClass(Inst, Rn, Addr, Decoder) ||
+      !DecodeGPR64RegisterClass(Inst, Rm, Addr, Decoder))
+    return MCDisassembler::Fail;
+
+  return MCDisassembler::Success;
+}
\ No newline at end of file
diff --git a/llvm/test/MC/AArch64/armv8.8a-mops.s b/llvm/test/MC/AArch64/armv8.8a-mops.s
new file mode 100644 (file)
index 0000000..f8d75e7
--- /dev/null
@@ -0,0 +1,654 @@
+// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+mops,+mte < %s 2> %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MTE
+// RUN: FileCheck --check-prefix=CHECK-ERROR %s < %t
+// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+v8.8a,+mte < %s 2> %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-MTE
+// RUN: FileCheck --check-prefix=CHECK-ERROR %s < %t
+// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+mops < %s 2> %t | FileCheck %s --check-prefix=CHECK
+// RUN: FileCheck --check-prefix=CHECK-NO-MTE-ERR %s < %t
+// RUN: not llvm-mc -triple aarch64-none-linux-gnu -show-encoding -mattr=+v8.8a < %s 2> %t | FileCheck %s --check-prefix=CHECK
+// RUN: FileCheck --check-prefix=CHECK-NO-MTE-ERR %s < %t
+// RUN: not llvm-mc -triple aarch64-none-linux-gnu < %s 2> %t
+// RUN: FileCheck --check-prefix=CHECK-NO-MOPS-ERR --check-prefix=CHECK-NO-MOPSMTE-ERR %s < %t
+
+// CHECK:      [0x40,0x04,0x01,0x19]
+// CHECK-NEXT: [0x40,0x44,0x01,0x19]
+// CHECK-NEXT: [0x40,0x84,0x01,0x19]
+// CHECK-NEXT: [0x40,0xc4,0x01,0x19]
+// CHECK-NEXT: [0x40,0x14,0x01,0x19]
+// CHECK-NEXT: [0x40,0x54,0x01,0x19]
+// CHECK-NEXT: [0x40,0x94,0x01,0x19]
+// CHECK-NEXT: [0x40,0xd4,0x01,0x19]
+// CHECK-NEXT: [0x40,0x24,0x01,0x19]
+// CHECK-NEXT: [0x40,0x64,0x01,0x19]
+// CHECK-NEXT: [0x40,0xa4,0x01,0x19]
+// CHECK-NEXT: [0x40,0xe4,0x01,0x19]
+// CHECK-NEXT: [0x40,0x34,0x01,0x19]
+// CHECK-NEXT: [0x40,0x74,0x01,0x19]
+// CHECK-NEXT: [0x40,0xb4,0x01,0x19]
+// CHECK-NEXT: [0x40,0xf4,0x01,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpyfp [x0]!, [x1]!, x2!
+cpyfpwn [x0]!, [x1]!, x2!
+cpyfprn [x0]!, [x1]!, x2!
+cpyfpn [x0]!, [x1]!, x2!
+cpyfpwt [x0]!, [x1]!, x2!
+cpyfpwtwn [x0]!, [x1]!, x2!
+cpyfpwtrn [x0]!, [x1]!, x2!
+cpyfpwtn [x0]!, [x1]!, x2!
+cpyfprt [x0]!, [x1]!, x2!
+cpyfprtwn [x0]!, [x1]!, x2!
+cpyfprtrn [x0]!, [x1]!, x2!
+cpyfprtn [x0]!, [x1]!, x2!
+cpyfpt [x0]!, [x1]!, x2!
+cpyfptwn [x0]!, [x1]!, x2!
+cpyfptrn [x0]!, [x1]!, x2!
+cpyfptn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x40,0x04,0x41,0x19]
+// CHECK-NEXT: [0x40,0x44,0x41,0x19]
+// CHECK-NEXT: [0x40,0x84,0x41,0x19]
+// CHECK-NEXT: [0x40,0xc4,0x41,0x19]
+// CHECK-NEXT: [0x40,0x14,0x41,0x19]
+// CHECK-NEXT: [0x40,0x54,0x41,0x19]
+// CHECK-NEXT: [0x40,0x94,0x41,0x19]
+// CHECK-NEXT: [0x40,0xd4,0x41,0x19]
+// CHECK-NEXT: [0x40,0x24,0x41,0x19]
+// CHECK-NEXT: [0x40,0x64,0x41,0x19]
+// CHECK-NEXT: [0x40,0xa4,0x41,0x19]
+// CHECK-NEXT: [0x40,0xe4,0x41,0x19]
+// CHECK-NEXT: [0x40,0x34,0x41,0x19]
+// CHECK-NEXT: [0x40,0x74,0x41,0x19]
+// CHECK-NEXT: [0x40,0xb4,0x41,0x19]
+// CHECK-NEXT: [0x40,0xf4,0x41,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpyfm [x0]!, [x1]!, x2!
+cpyfmwn [x0]!, [x1]!, x2!
+cpyfmrn [x0]!, [x1]!, x2!
+cpyfmn [x0]!, [x1]!, x2!
+cpyfmwt [x0]!, [x1]!, x2!
+cpyfmwtwn [x0]!, [x1]!, x2!
+cpyfmwtrn [x0]!, [x1]!, x2!
+cpyfmwtn [x0]!, [x1]!, x2!
+cpyfmrt [x0]!, [x1]!, x2!
+cpyfmrtwn [x0]!, [x1]!, x2!
+cpyfmrtrn [x0]!, [x1]!, x2!
+cpyfmrtn [x0]!, [x1]!, x2!
+cpyfmt [x0]!, [x1]!, x2!
+cpyfmtwn [x0]!, [x1]!, x2!
+cpyfmtrn [x0]!, [x1]!, x2!
+cpyfmtn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x40,0x04,0x81,0x19]
+// CHECK-NEXT: [0x40,0x44,0x81,0x19]
+// CHECK-NEXT: [0x40,0x84,0x81,0x19]
+// CHECK-NEXT: [0x40,0xc4,0x81,0x19]
+// CHECK-NEXT: [0x40,0x14,0x81,0x19]
+// CHECK-NEXT: [0x40,0x54,0x81,0x19]
+// CHECK-NEXT: [0x40,0x94,0x81,0x19]
+// CHECK-NEXT: [0x40,0xd4,0x81,0x19]
+// CHECK-NEXT: [0x40,0x24,0x81,0x19]
+// CHECK-NEXT: [0x40,0x64,0x81,0x19]
+// CHECK-NEXT: [0x40,0xa4,0x81,0x19]
+// CHECK-NEXT: [0x40,0xe4,0x81,0x19]
+// CHECK-NEXT: [0x40,0x34,0x81,0x19]
+// CHECK-NEXT: [0x40,0x74,0x81,0x19]
+// CHECK-NEXT: [0x40,0xb4,0x81,0x19]
+// CHECK-NEXT: [0x40,0xf4,0x81,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpyfe [x0]!, [x1]!, x2!
+cpyfewn [x0]!, [x1]!, x2!
+cpyfern [x0]!, [x1]!, x2!
+cpyfen [x0]!, [x1]!, x2!
+cpyfewt [x0]!, [x1]!, x2!
+cpyfewtwn [x0]!, [x1]!, x2!
+cpyfewtrn [x0]!, [x1]!, x2!
+cpyfewtn [x0]!, [x1]!, x2!
+cpyfert [x0]!, [x1]!, x2!
+cpyfertwn [x0]!, [x1]!, x2!
+cpyfertrn [x0]!, [x1]!, x2!
+cpyfertn [x0]!, [x1]!, x2!
+cpyfet [x0]!, [x1]!, x2!
+cpyfetwn [x0]!, [x1]!, x2!
+cpyfetrn [x0]!, [x1]!, x2!
+cpyfetn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x40,0x04,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x44,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x84,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xc4,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x14,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x54,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x94,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xd4,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x24,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x64,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xa4,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xe4,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x34,0x01,0x1d]
+// CHECK-NEXT: [0x40,0x74,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xb4,0x01,0x1d]
+// CHECK-NEXT: [0x40,0xf4,0x01,0x1d]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpyp [x0]!, [x1]!, x2!
+cpypwn [x0]!, [x1]!, x2!
+cpyprn [x0]!, [x1]!, x2!
+cpypn [x0]!, [x1]!, x2!
+cpypwt [x0]!, [x1]!, x2!
+cpypwtwn [x0]!, [x1]!, x2!
+cpypwtrn [x0]!, [x1]!, x2!
+cpypwtn [x0]!, [x1]!, x2!
+cpyprt [x0]!, [x1]!, x2!
+cpyprtwn [x0]!, [x1]!, x2!
+cpyprtrn [x0]!, [x1]!, x2!
+cpyprtn [x0]!, [x1]!, x2!
+cpypt [x0]!, [x1]!, x2!
+cpyptwn [x0]!, [x1]!, x2!
+cpyptrn [x0]!, [x1]!, x2!
+cpyptn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x40,0x04,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x44,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x84,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xc4,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x14,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x54,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x94,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xd4,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x24,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x64,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xa4,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xe4,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x34,0x41,0x1d]
+// CHECK-NEXT: [0x40,0x74,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xb4,0x41,0x1d]
+// CHECK-NEXT: [0x40,0xf4,0x41,0x1d]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpym [x0]!, [x1]!, x2!
+cpymwn [x0]!, [x1]!, x2!
+cpymrn [x0]!, [x1]!, x2!
+cpymn [x0]!, [x1]!, x2!
+cpymwt [x0]!, [x1]!, x2!
+cpymwtwn [x0]!, [x1]!, x2!
+cpymwtrn [x0]!, [x1]!, x2!
+cpymwtn [x0]!, [x1]!, x2!
+cpymrt [x0]!, [x1]!, x2!
+cpymrtwn [x0]!, [x1]!, x2!
+cpymrtrn [x0]!, [x1]!, x2!
+cpymrtn [x0]!, [x1]!, x2!
+cpymt [x0]!, [x1]!, x2!
+cpymtwn [x0]!, [x1]!, x2!
+cpymtrn [x0]!, [x1]!, x2!
+cpymtn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x40,0x04,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x44,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x84,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xc4,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x14,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x54,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x94,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xd4,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x24,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x64,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xa4,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xe4,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x34,0x81,0x1d]
+// CHECK-NEXT: [0x40,0x74,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xb4,0x81,0x1d]
+// CHECK-NEXT: [0x40,0xf4,0x81,0x1d]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+cpye [x0]!, [x1]!, x2!
+cpyewn [x0]!, [x1]!, x2!
+cpyern [x0]!, [x1]!, x2!
+cpyen [x0]!, [x1]!, x2!
+cpyewt [x0]!, [x1]!, x2!
+cpyewtwn [x0]!, [x1]!, x2!
+cpyewtrn [x0]!, [x1]!, x2!
+cpyewtn [x0]!, [x1]!, x2!
+cpyert [x0]!, [x1]!, x2!
+cpyertwn [x0]!, [x1]!, x2!
+cpyertrn [x0]!, [x1]!, x2!
+cpyertn [x0]!, [x1]!, x2!
+cpyet [x0]!, [x1]!, x2!
+cpyetwn [x0]!, [x1]!, x2!
+cpyetrn [x0]!, [x1]!, x2!
+cpyetn [x0]!, [x1]!, x2!
+
+// CHECK:      [0x20,0x04,0xc2,0x19]
+// CHECK-NEXT: [0x20,0x14,0xc2,0x19]
+// CHECK-NEXT: [0x20,0x24,0xc2,0x19]
+// CHECK-NEXT: [0x20,0x34,0xc2,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+setp [x0]!, x1!, x2
+setpt [x0]!, x1!, x2
+setpn [x0]!, x1!, x2
+setptn [x0]!, x1!, x2
+
+// CHECK: [0x20,0x44,0xc2,0x19]
+// CHECK: [0x20,0x54,0xc2,0x19]
+// CHECK: [0x20,0x64,0xc2,0x19]
+// CHECK: [0x20,0x74,0xc2,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+setm [x0]!, x1!, x2
+setmt [x0]!, x1!, x2
+setmn [x0]!, x1!, x2
+setmtn [x0]!, x1!, x2
+
+// CHECK: [0x20,0x84,0xc2,0x19]
+// CHECK: [0x20,0x94,0xc2,0x19]
+// CHECK: [0x20,0xa4,0xc2,0x19]
+// CHECK: [0x20,0xb4,0xc2,0x19]
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+// CHECK-NO-MOPS-ERR: error: instruction requires: mops
+sete [x0]!, x1!, x2
+setet [x0]!, x1!, x2
+seten [x0]!, x1!, x2
+setetn [x0]!, x1!, x2
+
+// CHECK-MTE: [0x20,0x04,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x14,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x24,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x34,0xc2,0x1d]
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+setgp [x0]!, x1!, x2
+setgpt [x0]!, x1!, x2
+setgpn [x0]!, x1!, x2
+setgptn [x0]!, x1!, x2
+
+// CHECK-MTE: [0x20,0x44,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x54,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x64,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x74,0xc2,0x1d]
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+setgm [x0]!, x1!, x2
+setgmt [x0]!, x1!, x2
+setgmn [x0]!, x1!, x2
+setgmtn [x0]!, x1!, x2
+
+// CHECK-MTE: [0x20,0x84,0xc2,0x1d]
+// CHECK-MTE: [0x20,0x94,0xc2,0x1d]
+// CHECK-MTE: [0x20,0xa4,0xc2,0x1d]
+// CHECK-MTE: [0x20,0xb4,0xc2,0x1d]
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MTE-ERR: error: instruction requires: mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+// CHECK-NO-MOPSMTE-ERR: error: instruction requires: mops mte
+setge [x0]!, x1!, x2
+setget [x0]!, x1!, x2
+setgen [x0]!, x1!, x2
+setgetn [x0]!, x1!, x2
+
+// All operand must be different from each other
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpyfp [x0]!, [x0]!, x1!
+cpyfp [x0]!, [x1]!, x0!
+cpyfp [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpyfm [x0]!, [x0]!, x1!
+cpyfm [x0]!, [x1]!, x0!
+cpyfm [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpyfe [x0]!, [x0]!, x1!
+cpyfe [x0]!, [x1]!, x0!
+cpyfe [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpyp [x0]!, [x0]!, x1!
+cpyp [x0]!, [x1]!, x0!
+cpyp [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpym [x0]!, [x0]!, x1!
+cpym [x0]!, [x1]!, x0!
+cpym [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid CPY instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid CPY instruction, source and size registers are the same
+cpye [x0]!, [x0]!, x1!
+cpye [x0]!, [x1]!, x0!
+cpye [x1]!, [x0]!, x0!
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+setp [x0]!, x0!, x1
+setp [x0]!, x1!, x0
+setp [x1]!, x0!, x0
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+setm [x0]!, x0!, x1
+setm [x0]!, x1!, x0
+setm [x1]!, x0!, x0
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+sete [x0]!, x0!, x1
+sete [x0]!, x1!, x0
+sete [x1]!, x0!, x0
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+setgp [x0]!, x0!, x1
+setgp [x0]!, x1!, x0
+setgp [x1]!, x0!, x0
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+setgm [x0]!, x0!, x1
+setgm [x0]!, x1!, x0
+setgm [x1]!, x0!, x0
+
+// CHECK-ERROR: error: invalid SET instruction, destination and size registers are the same
+// CHECK-ERROR: error: invalid SET instruction, destination and source registers are the same
+// CHECK-ERROR: error: invalid SET instruction, source and size registers are the same
+setge [x0]!, x0!, x1
+setge [x0]!, x1!, x0
+setge [x1]!, x0!, x0
+
+// SP cannot be used as argument at any position
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpyfp [sp]!, [x1]!, x2!
+cpyfp [x0]!, [sp]!, x2!
+cpyfp [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpyfm [sp]!, [x1]!, x2!
+cpyfm [x0]!, [sp]!, x2!
+cpyfm [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpyfe [sp]!, [x1]!, x2!
+cpyfe [x0]!, [sp]!, x2!
+cpyfe [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpyp [sp]!, [x2]!, x2!
+cpyp [x0]!, [sp]!, x2!
+cpyp [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpym [sp]!, [x2]!, x2!
+cpym [x0]!, [sp]!, x2!
+cpym [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+cpye [sp]!, [x2]!, x2!
+cpye [x0]!, [sp]!, x2!
+cpye [x0]!, [x1]!, sp!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+setp [sp]!, x1!, x2
+setp [x0]!, sp!, x2
+setp [x0]!, x1!, sp
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+setm [sp]!, x1!, x2
+setm [x0]!, sp!, x2
+setm [x0]!, x1!, sp
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+sete [sp]!, x1!, x2
+sete [x0]!, sp!, x2
+sete [x0]!, x1!, sp
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+setgp [sp]!, x1!, x2
+setgp [x0]!, sp!, x2
+setgp [x0]!, x1!, sp
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+setgm [sp]!, x1!, x2
+setgm [x0]!, sp!, x2
+setgm [x0]!, x1!, sp
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+setge [sp]!, x1!, x2
+setge [x0]!, sp!, x2
+setge [x0]!, x1!, sp
+
+// XZR can only be used at:
+//  - the size operand in CPY.
+//  - the size or source operands in SET.
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpyfp [x0]!, [x1]!, xzr!
+cpyfp [xzr]!, [x1]!, x2!
+cpyfp [x0]!, [xzr]!, x2!
+cpyfp [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpyfm [x0]!, [x1]!, xzr!
+cpyfm [xzr]!, [x1]!, x2!
+cpyfm [x0]!, [xzr]!, x2!
+cpyfm [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpyfe [x0]!, [x1]!, xzr!
+cpyfe [xzr]!, [x1]!, x2!
+cpyfe [x0]!, [xzr]!, x2!
+cpyfe [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpyp [x0]!, [x1]!, xzr!
+cpyp [xzr]!, [x2]!, x2!
+cpyp [x0]!, [xzr]!, x2!
+cpyp [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpym [x0]!, [x1]!, xzr!
+cpym [xzr]!, [x2]!, x2!
+cpym [x0]!, [xzr]!, x2!
+cpym [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       cpye [x0]!, [x1]!, xzr!
+cpye [xzr]!, [x2]!, x2!
+cpye [x0]!, [xzr]!, x2!
+cpye [x0]!, [x1]!, xzr!
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       setp [x0]!, xzr!, x2
+// CHECK:       setp [x0]!, x1!, xzr
+setp [xzr]!, x1!, x2
+setp [x0]!, xzr!, x2
+setp [x0]!, x1!, xzr
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       setm [x0]!, xzr!, x2
+// CHECK:       setm [x0]!, x1!, xzr
+setm [xzr]!, x1!, x2
+setm [x0]!, xzr!, x2
+setm [x0]!, x1!, xzr
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK:       sete [x0]!, xzr!, x2
+// CHECK:       sete [x0]!, x1!, xzr
+sete [xzr]!, x1!, x2
+sete [x0]!, xzr!, x2
+sete [x0]!, x1!, xzr
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-MTE:   setgp [x0]!, xzr!, x2
+// CHECK-MTE:   setgp [x0]!, x1!, xzr
+setgp [xzr]!, x1!, x2
+setgp [x0]!, xzr!, x2
+setgp [x0]!, x1!, xzr
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-MTE:   setgm [x0]!, xzr!, x2
+// CHECK-MTE:   setgm [x0]!, x1!, xzr
+setgm [xzr]!, x1!, x2
+setgm [x0]!, xzr!, x2
+setgm [x0]!, x1!, xzr
+
+// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-MTE:   setge [x0]!, xzr!, x2
+// CHECK-MTE:   setge [x0]!, x1!, xzr
+setge [xzr]!, x1!, x2
+setge [x0]!, xzr!, x2
+setge [x0]!, x1!, xzr
diff --git a/llvm/test/MC/Disassembler/AArch64/armv8.8a-mops.txt b/llvm/test/MC/Disassembler/AArch64/armv8.8a-mops.txt
new file mode 100644 (file)
index 0000000..eedac19
--- /dev/null
@@ -0,0 +1,434 @@
+# RUN: not llvm-mc -triple aarch64-arm-none-eabi -mattr=+mops,+mte -disassemble < %s 2> %t | FileCheck %s --check-prefixes=CHECK-MOPS,CHECK-MTE
+# RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t
+# RUN: not llvm-mc -triple aarch64-arm-none-eabi -mattr=+v8.8a,+mte -disassemble < %s 2> %t | FileCheck %s --check-prefixes=CHECK-MOPS,CHECK-MTE
+# RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t
+# RUN: not llvm-mc -triple aarch64-arm-none-eabi -mattr=+mops -disassemble < %s 2> %t | FileCheck %s --check-prefix=CHECK-MOPS
+# RUN: FileCheck %s --check-prefixes=CHECK-INVALID,CHECK-NO-MTE < %t
+# RUN: not llvm-mc -triple aarch64-arm-none-eabi -mattr=+v8.8a -disassemble < %s 2> %t | FileCheck %s --check-prefix=CHECK-MOPS
+# RUN: FileCheck %s --check-prefixes=CHECK-INVALID,CHECK-NO-MTE < %t
+# RUN: not llvm-mc -triple aarch64-arm-none-eabi -disassemble < %s 2> %t
+# RUN: FileCheck %s --check-prefixes=CHECK-INVALID,CHECK-NO-MOPS,CHECK-NO-MTE < %t
+
+
+[0x40,0x04,0x01,0x19]
+[0x40,0x44,0x01,0x19]
+[0x40,0x84,0x01,0x19]
+[0x40,0xc4,0x01,0x19]
+[0x40,0x14,0x01,0x19]
+[0x40,0x54,0x01,0x19]
+[0x40,0x94,0x01,0x19]
+[0x40,0xd4,0x01,0x19]
+[0x40,0x24,0x01,0x19]
+[0x40,0x64,0x01,0x19]
+[0x40,0xa4,0x01,0x19]
+[0x40,0xe4,0x01,0x19]
+[0x40,0x34,0x01,0x19]
+[0x40,0x74,0x01,0x19]
+[0x40,0xb4,0x01,0x19]
+[0x40,0xf4,0x01,0x19]
+# CHECK-MOPS: cpyfp    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpwn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfprn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpwt  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpwtwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpwtrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpwtn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfprt  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfprtwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfprtrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfprtn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfpt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfptwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfptrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfptn  [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x40,0x04,0x41,0x19]
+[0x40,0x44,0x41,0x19]
+[0x40,0x84,0x41,0x19]
+[0x40,0xc4,0x41,0x19]
+[0x40,0x14,0x41,0x19]
+[0x40,0x54,0x41,0x19]
+[0x40,0x94,0x41,0x19]
+[0x40,0xd4,0x41,0x19]
+[0x40,0x24,0x41,0x19]
+[0x40,0x64,0x41,0x19]
+[0x40,0xa4,0x41,0x19]
+[0x40,0xe4,0x41,0x19]
+[0x40,0x34,0x41,0x19]
+[0x40,0x74,0x41,0x19]
+[0x40,0xb4,0x41,0x19]
+[0x40,0xf4,0x41,0x19]
+# CHECK-MOPS: cpyfm    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmwn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmrn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmwt  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmwtwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmwtrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmwtn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmrt  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmrtwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmrtrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmrtn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfmtn  [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x40,0x04,0x81,0x19]
+[0x40,0x44,0x81,0x19]
+[0x40,0x84,0x81,0x19]
+[0x40,0xc4,0x81,0x19]
+[0x40,0x14,0x81,0x19]
+[0x40,0x54,0x81,0x19]
+[0x40,0x94,0x81,0x19]
+[0x40,0xd4,0x81,0x19]
+[0x40,0x24,0x81,0x19]
+[0x40,0x64,0x81,0x19]
+[0x40,0xa4,0x81,0x19]
+[0x40,0xe4,0x81,0x19]
+[0x40,0x34,0x81,0x19]
+[0x40,0x74,0x81,0x19]
+[0x40,0xb4,0x81,0x19]
+[0x40,0xf4,0x81,0x19]
+# CHECK-MOPS: cpyfe    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfewn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfern  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfen   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfewt  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfewtwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfewtrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfewtn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfert  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfertwn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfertrn        [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfertn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfet   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfetwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfetrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyfetn  [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x40,0x04,0x01,0x1d]
+[0x40,0x44,0x01,0x1d]
+[0x40,0x84,0x01,0x1d]
+[0x40,0xc4,0x01,0x1d]
+[0x40,0x14,0x01,0x1d]
+[0x40,0x54,0x01,0x1d]
+[0x40,0x94,0x01,0x1d]
+[0x40,0xd4,0x01,0x1d]
+[0x40,0x24,0x01,0x1d]
+[0x40,0x64,0x01,0x1d]
+[0x40,0xa4,0x01,0x1d]
+[0x40,0xe4,0x01,0x1d]
+[0x40,0x34,0x01,0x1d]
+[0x40,0x74,0x01,0x1d]
+[0x40,0xb4,0x01,0x1d]
+[0x40,0xf4,0x01,0x1d]
+# CHECK-MOPS: cpyp     [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypwn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyprn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypn    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypwt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypwtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypwtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypwtn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyprt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyprtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyprtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyprtn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpypt    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyptwn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyptrn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyptn   [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x40,0x04,0x41,0x1d]
+[0x40,0x44,0x41,0x1d]
+[0x40,0x84,0x41,0x1d]
+[0x40,0xc4,0x41,0x1d]
+[0x40,0x14,0x41,0x1d]
+[0x40,0x54,0x41,0x1d]
+[0x40,0x94,0x41,0x1d]
+[0x40,0xd4,0x41,0x1d]
+[0x40,0x24,0x41,0x1d]
+[0x40,0x64,0x41,0x1d]
+[0x40,0xa4,0x41,0x1d]
+[0x40,0xe4,0x41,0x1d]
+[0x40,0x34,0x41,0x1d]
+[0x40,0x74,0x41,0x1d]
+[0x40,0xb4,0x41,0x1d]
+[0x40,0xf4,0x41,0x1d]
+# CHECK-MOPS: cpym     [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymwn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymrn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymn    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymwt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymwtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymwtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymwtn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymrt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymrtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymrtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymrtn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymt    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymtwn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymtrn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpymtn   [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x40,0x04,0x81,0x1d]
+[0x40,0x44,0x81,0x1d]
+[0x40,0x84,0x81,0x1d]
+[0x40,0xc4,0x81,0x1d]
+[0x40,0x14,0x81,0x1d]
+[0x40,0x54,0x81,0x1d]
+[0x40,0x94,0x81,0x1d]
+[0x40,0xd4,0x81,0x1d]
+[0x40,0x24,0x81,0x1d]
+[0x40,0x64,0x81,0x1d]
+[0x40,0xa4,0x81,0x1d]
+[0x40,0xe4,0x81,0x1d]
+[0x40,0x34,0x81,0x1d]
+[0x40,0x74,0x81,0x1d]
+[0x40,0xb4,0x81,0x1d]
+[0x40,0xf4,0x81,0x1d]
+# CHECK-MOPS: cpye     [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyewn   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyern   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyen    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyewt   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyewtwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyewtrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyewtn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyert   [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyertwn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyertrn [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyertn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyet    [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyetwn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyetrn  [x0]!, [x1]!, x2!
+# CHECK-MOPS: cpyetn   [x0]!, [x1]!, x2!
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x20,0x04,0xc2,0x19]
+[0x20,0x14,0xc2,0x19]
+[0x20,0x24,0xc2,0x19]
+[0x20,0x34,0xc2,0x19]
+# CHECK-MOPS: setp     [x0]!, x1!, x2
+# CHECK-MOPS: setpt    [x0]!, x1!, x2
+# CHECK-MOPS: setpn    [x0]!, x1!, x2
+# CHECK-MOPS: setptn   [x0]!, x1!, x2
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x20,0x44,0xc2,0x19]
+[0x20,0x54,0xc2,0x19]
+[0x20,0x64,0xc2,0x19]
+[0x20,0x74,0xc2,0x19]
+# CHECK-MOPS: setm     [x0]!, x1!, x2
+# CHECK-MOPS: setmt    [x0]!, x1!, x2
+# CHECK-MOPS: setmn    [x0]!, x1!, x2
+# CHECK-MOPS: setmtn   [x0]!, x1!, x2
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x20,0x84,0xc2,0x19]
+[0x20,0x94,0xc2,0x19]
+[0x20,0xa4,0xc2,0x19]
+[0x20,0xb4,0xc2,0x19]
+# CHECK-MOPS: sete     [x0]!, x1!, x2
+# CHECK-MOPS: setet    [x0]!, x1!, x2
+# CHECK-MOPS: seten    [x0]!, x1!, x2
+# CHECK-MOPS: setetn   [x0]!, x1!, x2
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+# CHECK-NO-MOPS: warning: invalid instruction encoding
+
+[0x20,0x04,0xc2,0x1d]
+[0x20,0x14,0xc2,0x1d]
+[0x20,0x24,0xc2,0x1d]
+[0x20,0x34,0xc2,0x1d]
+# CHECK-MTE: setgp     [x0]!, x1!, x2
+# CHECK-MTE: setgpt [x0]!, x1!, x2
+# CHECK-MTE: setgpn    [x0]!, x1!, x2
+# CHECK-MTE: setgptn   [x0]!, x1!, x2
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+
+[0x20,0x44,0xc2,0x1d]
+[0x20,0x54,0xc2,0x1d]
+[0x20,0x64,0xc2,0x1d]
+[0x20,0x74,0xc2,0x1d]
+# CHECK-MTE: setgm     [x0]!, x1!, x2
+# CHECK-MTE: setgmt    [x0]!, x1!, x2
+# CHECK-MTE: setgmn    [x0]!, x1!, x2
+# CHECK-MTE: setgmtn   [x0]!, x1!, x2
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+
+[0x20,0x84,0xc2,0x1d]
+[0x20,0x94,0xc2,0x1d]
+[0x20,0xa4,0xc2,0x1d]
+[0x20,0xb4,0xc2,0x1d]
+# CHECK-MTE: setge     [x0]!, x1!, x2
+# CHECK-MTE: setget    [x0]!, x1!, x2
+# CHECK-MTE: setgen    [x0]!, x1!, x2
+# CHECK-MTE: setgetn   [x0]!, x1!, x2
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+# CHECK-NO-MTE: warning: invalid instruction encoding
+
+
+# Register number 31 (SP or XZR) is not allowed in address positions.
+# cpyfp
+[0x5f,0x04,0x01,0x19]
+[0x40,0x04,0x1f,0x19]
+# cpyfm
+[0x5f,0x04,0x41,0x19]
+[0x40,0x04,0x5f,0x19]
+# cpyfe
+[0x5f,0x04,0x81,0x19]
+[0x40,0x04,0x9f,0x19]
+# cpyp
+[0x5f,0x04,0x01,0x1d]
+[0x40,0x04,0x1f,0x1d]
+# cpym
+[0x5f,0x04,0x41,0x1d]
+[0x40,0x04,0x5f,0x1d]
+# cpye
+[0x5f,0x04,0x81,0x1d]
+[0x40,0x04,0x9f,0x1d]
+# setp
+[0x5f,0x04,0xc2,0x19]
+# setm
+[0x5f,0x44,0xc2,0x19]
+# sete
+[0x5f,0x84,0xc2,0x19]
+# setgp
+[0x5f,0x04,0xc2,0x1d]
+# setgm
+[0x5f,0x44,0xc2,0x1d]
+# setge
+[0x5f,0x84,0xc2,0x1d]
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding
+# CHECK-INVALID: warning: invalid instruction encoding