[llvm] [AArch64][llvm] Redefine some insns as an alias of `SYS` (PR #187004)

Jonathan Thackray via llvm-commits llvm-commits at lists.llvm.org
Tue Apr 14 07:05:07 PDT 2026


https://github.com/jthackray updated https://github.com/llvm/llvm-project/pull/187004

>From 66157f65a29782dba94e6e5837de8de7eed42588 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 16 Mar 2026 20:41:14 +0000
Subject: [PATCH 1/7] [AArch64][llvm] Redefine some isns as an alias of `SYS`

Some instructions are not currently defined as an alias of `SYS`
when they should be, so they don't disassemble back into the
native instruction, but instead disassemble into `SYS`.
Fix these cases and add additional testcase.

Note that I've left `GCSPUSHM` due to a `mayStore`, `GCSSS1` and
`GCSSS2` as they're used in AArch64ISelDAGToDAG.cpp, and `GCSPOPM`
has an intrinsic pattern in AArch64InstrInfo.td. They will disassemble
correctly though, as they use `InstAlias`.
---
 .../lib/Target/AArch64/AArch64InstrFormats.td |  19 ---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |  47 +++----
 .../MCTargetDesc/AArch64InstPrinter.cpp       | 116 ++++++++++++++++++
 llvm/test/MC/AArch64/armv8.9a-debug-pmu.s     |   5 +
 llvm/test/MC/AArch64/armv9.4a-gcs.s           |  40 ++++++
 llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s      |   5 +
 llvm/test/MC/AArch64/brbe.s                   |   8 +-
 7 files changed, 196 insertions(+), 44 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 406ac2fa62df2..0c2bd5313cf0e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -1843,12 +1843,6 @@ class RegInputSystemI<bits<4> CRm, bits<3> Op2, string asm,
   let Inst{7-5} = Op2;
 }
 
-class APASI : SimpleSystemI<0, (ins GPR64:$Xt), "apas", "\t$Xt">, Sched<[]> {
-  bits<5> Xt;
-  let Inst{20-5} = 0b0111001110000000;
-  let Inst{4-0} = Xt;
-}
-
 // Hint instructions that take both a CRm and a 3-bit immediate.
 // NOTE: ideally, this would have mayStore = 0, mayLoad = 0, but we cannot
 // model patterns with sufficiently fine granularity
@@ -13062,19 +13056,6 @@ class LRCPC3NEONLdStSingle<bit L, dag oops, dag iops, string asm, string cst>
   let hasSideEffects = 1;
 }
 
-//---
-// Instrumentation Extension (FEAT_ITE)
-//---
-
-let Predicates = [HasITE] in
-def TRCIT : RtSystemI<0b0, (outs), (ins GPR64:$Rt), "trcit", "\t$Rt"> {
-  let Inst{20-19} = 0b01;
-  let Inst{18-16} = 0b011;
-  let Inst{15-12} = 0b0111;
-  let Inst{11-8}  = 0b0010;
-  let Inst{7-5}   = 0b111;
-}
-
 // * RCWCAS family
 // * RCW<OP> family
 
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 129e49f645633..09a8a9a63fb7d 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -1627,16 +1627,6 @@ def WFET : RegInputSystemI<0b0000, 0b000, "wfet">;
 def WFIT : RegInputSystemI<0b0000, 0b001, "wfit">;
 }
 
-// Branch Record Buffer two-word mnemonic instructions
-class BRBEI<bits<3> op2, string keyword>
-    : SimpleSystemI<0, (ins), "brb", keyword>, Sched<[WriteSys]> {
-  let Inst{31-8} = 0b110101010000100101110010;
-  let Inst{7-5} = op2;
-  let Predicates = [HasBRBE];
-}
-def BRB_IALL: BRBEI<0b100, "\tiall">;
-def BRB_INJ:  BRBEI<0b101, "\tinj">;
-
 }
 
 // Allow uppercase and lowercase keyword arguments for BRB IALL and BRB INJ
@@ -1645,16 +1635,6 @@ def : TokenAlias<"IALL", "iall">;
 
 
 // ARMv9.4-A Guarded Control Stack
-class GCSNoOp<bits<3> op2, string mnemonic>
-    : SimpleSystemI<0, (ins), mnemonic, "">, Sched<[]> {
-  let Inst{20-8} = 0b0100001110111;
-  let Inst{7-5} = op2;
-  let Predicates = [HasGCS];
-}
-def GCSPUSHX : GCSNoOp<0b100, "gcspushx">;
-def GCSPOPCX : GCSNoOp<0b101, "gcspopcx">;
-def GCSPOPX  : GCSNoOp<0b110, "gcspopx">;
-
 class GCSRtIn<bits<3> op1, bits<3> op2, string mnemonic,
             list<dag> pattern = []>
     : RtSystemI<0, (outs), (ins GPR64:$Rt), mnemonic, "\t$Rt", pattern> {
@@ -2565,6 +2545,30 @@ def SYSLxt : SystemLXtI<1, "sysl">;
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
                 (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
                  sys_cr_op:$Cm, timm32_0_7:$op2, XZR)>;
+def : InstAlias<"apas $Xt",
+                (SYSxt 6, 7, 0, 0, GPR64:$Xt)>;
+def : InstAlias<"brb\tiall",
+                (SYSxt 1, 7, 2, 4, XZR)>, Requires<[HasBRBE]>;
+def : InstAlias<"brb\tinj",
+                (SYSxt 1, 7, 2, 5, XZR)>, Requires<[HasBRBE]>;
+def : InstAlias<"trcit $Rt",
+                (SYSxt 3, 7, 2, 7, GPR64:$Rt)>, Requires<[HasITE]>;
+def : InstAlias<"gcspushx",
+                (SYSxt 0, 7, 7, 4, XZR)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopcx",
+                (SYSxt 0, 7, 7, 5, XZR)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopx",
+                (SYSxt 0, 7, 7, 6, XZR)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspushm $Rt",
+                (SYSxt 3, 7, 7, 0, GPR64:$Rt)>, Requires<[HasGCS]>;
+def : InstAlias<"gcsss1 $Rt",
+                (SYSxt 3, 7, 7, 2, GPR64:$Rt)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopm",
+                (SYSLxt XZR, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopm $Rt",
+                (SYSLxt GPR64:$Rt, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+def : InstAlias<"gcsss2 $Rt",
+                (SYSLxt GPR64:$Rt, 3, 7, 7, 3)>, Requires<[HasGCS]>;
 
 
 //===----------------------------------------------------------------------===//
@@ -3094,9 +3098,6 @@ let Predicates = [HasLSUI] in {
   defm : STOPregisterLSUI<"sttset","LDTSET">; // STTSETx
 }
 
-// v9.6-a FEAT_RME_GPC3
-def APAS : APASI;
-
 // v8.1 atomic LD<OP>(register). Performs load and then ST<OP>(register)
 defm LDADD   : LDOPregister<0b000, "add", 0, 0, "">;
 defm LDADDA  : LDOPregister<0b000, "add", 1, 0, "a">;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 2f4b3fa016336..979a16baa9df8 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -925,6 +925,13 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
     default: return false;
     // MLBI aliases
     case 0: {
+      if (Op1Val == 6 && Op2Val == 0) {
+        NeedsReg = true;
+        Ins = "apas";
+        Name = "";
+        break;
+      }
+
       const AArch64MLBI::MLBI *MLBI =
           AArch64MLBI::lookupMLBIByEncoding(Encoding);
       if (!MLBI || !MLBI->haveFeatures(STI.getFeatureBits()))
@@ -941,6 +948,41 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
       case 0: goto Search_IC;
       case 3: goto Search_PRCTX;
       }
+    // BRB aliases.
+    case 2: {
+      switch (Op1Val) {
+      default:
+        return false;
+      case 1:
+        if (!(STI.hasFeature(AArch64::FeatureAll) ||
+              STI.hasFeature(AArch64::FeatureBRBE)))
+          return false;
+
+        NeedsReg = false;
+        switch (Op2Val) {
+        default:
+          return false;
+        case 4:
+          Ins = "brb\t";
+          Name = "iall";
+          break;
+        case 5:
+          Ins = "brb\t";
+          Name = "inj";
+          break;
+        }
+        break;
+      case 3:
+        if (Op2Val != 7 || !(STI.hasFeature(AArch64::FeatureAll) ||
+                             STI.hasFeature(AArch64::FeatureITE)))
+          return false;
+
+        NeedsReg = true;
+        Ins = "trcit";
+        Name = "";
+        break;
+      }
+    } break;
     // Prediction Restriction aliases
     case 3: {
       Search_PRCTX:
@@ -1014,6 +1056,47 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         return false;
       }
     } break;
+    // GCS aliases.
+    case 7: {
+      if (!(STI.hasFeature(AArch64::FeatureAll) ||
+            STI.hasFeature(AArch64::FeatureGCS)))
+        return false;
+
+      Name = "";
+      switch (Op1Val) {
+      default:
+        return false;
+      case 0:
+        NeedsReg = false;
+        switch (Op2Val) {
+        default:
+          return false;
+        case 4:
+          Ins = "gcspushx";
+          break;
+        case 5:
+          Ins = "gcspopcx";
+          break;
+        case 6:
+          Ins = "gcspopx";
+          break;
+        }
+        break;
+      case 3:
+        NeedsReg = true;
+        switch (Op2Val) {
+        default:
+          return false;
+        case 0:
+          Ins = "gcspushm";
+          break;
+        case 2:
+          Ins = "gcsss1";
+          break;
+        }
+        break;
+      }
+    } break;
     }
   } else if (CnVal == 8 || CnVal == 9) {
     // TLBI aliases
@@ -1071,6 +1154,13 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
   if (NotXZR && !NeedsReg && !OptionalReg)
     return false;
 
+  if (Name.empty()) {
+    O << '\t' << Ins;
+    if (NeedsReg || (OptionalReg && NotXZR))
+      O << '\t' << Reg;
+    return true;
+  }
+
   std::string Str = Ins + Name;
   llvm::transform(Str, Str.begin(), ::tolower);
 
@@ -1110,6 +1200,7 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
 
   std::string Ins;
   std::string Name;
+  bool OptionalReg = false;
 
   if (CnVal == 12) {
     if (CmVal == 3) {
@@ -1123,9 +1214,34 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
       Name = std::string(GICR->Name);
     } else
       return false;
+  } else if (CnVal == 7 && CmVal == 7) {
+    if (!(STI.hasFeature(AArch64::FeatureAll) ||
+          STI.hasFeature(AArch64::FeatureGCS)) ||
+        Op1Val != 3)
+      return false;
+
+    Name = "";
+    switch (Op2Val) {
+    default:
+      return false;
+    case 1:
+      Ins = "gcspopm";
+      OptionalReg = true;
+      break;
+    case 3:
+      Ins = "gcsss2";
+      break;
+    }
   } else
     return false;
 
+  if (Name.empty()) {
+    O << '\t' << Ins;
+    if (!OptionalReg || Reg != "xzr")
+      O << '\t' << Reg.str();
+    return true;
+  }
+
   llvm::transform(Name, Name.begin(), ::tolower);
 
   O << '\t' << Ins << '\t' << Reg.str() << ", " << Name;
diff --git a/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s b/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
index db5cb0701036d..ea058d484d852 100644
--- a/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
+++ b/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
@@ -1773,6 +1773,11 @@ trcit x1
 // CHECK-ERROR: error: instruction requires: ite
 // CHECK-UNKNOWN:  d50b72e1      sys #3, c7, c2, #7, x1
 
+sys #3, c7, c2, #7, x2
+// CHECK-INST: trcit x2
+// CHECK-ENCODING: encoding: [0xe2,0x72,0x0b,0xd5]
+// CHECK-UNKNOWN:  d50b72e2      sys #3, c7, c2, #7, x2
+
 // FEAT_SPE_FDS
 mrs x3, PMSDSFR_EL1
 // CHECK-INST: mrs x3, PMSDSFR_EL1
diff --git a/llvm/test/MC/AArch64/armv9.4a-gcs.s b/llvm/test/MC/AArch64/armv9.4a-gcs.s
index f702c947543ac..78b3f3639892e 100644
--- a/llvm/test/MC/AArch64/armv9.4a-gcs.s
+++ b/llvm/test/MC/AArch64/armv9.4a-gcs.s
@@ -119,24 +119,44 @@ gcsss1 x21
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50b7755 sys #3, c7, c7, #2, x21
 
+sys #3, c7, c7, #2, x20
+// CHECK-INST: gcsss1 x20
+// CHECK-ENCODING: encoding: [0x54,0x77,0x0b,0xd5]
+// CHECK-UNKNOWN:  d50b7754 sys #3, c7, c7, #2, x20
+
 gcsss2 x22
 // CHECK-INST: gcsss2 x22
 // CHECK-ENCODING: encoding: [0x76,0x77,0x2b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b7776 sysl x22, #3, c7, c7, #3
 
+sysl x23, #3, c7, c7, #3
+// CHECK-INST: gcsss2 x23
+// CHECK-ENCODING: encoding: [0x77,0x77,0x2b,0xd5]
+// CHECK-UNKNOWN:  d52b7777 sysl x23, #3, c7, c7, #3
+
 gcspushm x25
 // CHECK-INST: gcspushm x25
 // CHECK-ENCODING: encoding: [0x19,0x77,0x0b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50b7719 sys #3, c7, c7, #0, x25
 
+sys #3, c7, c7, #0, x24
+// CHECK-INST: gcspushm x24
+// CHECK-ENCODING: encoding: [0x18,0x77,0x0b,0xd5]
+// CHECK-UNKNOWN:  d50b7718 sys #3, c7, c7, #0, x24
+
 gcspopm
 // CHECK-INST: gcspopm
 // CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b773f sysl xzr, #3, c7, c7, #1
 
+sysl xzr, #3, c7, c7, #1
+// CHECK-INST: gcspopm
+// CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
+// CHECK-UNKNOWN:  d52b773f sysl xzr, #3, c7, c7, #1
+
 gcspopm xzr
 // CHECK-INST: gcspopm
 // CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
@@ -149,6 +169,11 @@ gcspopm x25
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b7739 sysl x25, #3, c7, c7, #1
 
+sysl x24, #3, c7, c7, #1
+// CHECK-INST: gcspopm x24
+// CHECK-ENCODING: encoding: [0x38,0x77,0x2b,0xd5]
+// CHECK-UNKNOWN:  d52b7738 sysl x24, #3, c7, c7, #1
+
 gcsstr x26, [x27]
 // CHECK-INST: gcsstr x26, [x27]
 // CHECK-ENCODING: encoding: [0x7a,0x0f,0x1f,0xd9]
@@ -179,18 +204,33 @@ gcspushx
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d508779f sys #0, c7, c7, #4
 
+sys #0, c7, c7, #4
+// CHECK-INST: gcspushx
+// CHECK-ENCODING: encoding: [0x9f,0x77,0x08,0xd5]
+// CHECK-UNKNOWN:  d508779f sys #0, c7, c7, #4
+
 gcspopcx
 // CHECK-INST: gcspopcx
 // CHECK-ENCODING: encoding: [0xbf,0x77,0x08,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50877bf sys #0, c7, c7, #5
 
+sys #0, c7, c7, #5
+// CHECK-INST: gcspopcx
+// CHECK-ENCODING: encoding: [0xbf,0x77,0x08,0xd5]
+// CHECK-UNKNOWN:  d50877bf sys #0, c7, c7, #5
+
 gcspopx
 // CHECK-INST: gcspopx
 // CHECK-ENCODING: encoding: [0xdf,0x77,0x08,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50877df sys #0, c7, c7, #6
 
+sys #0, c7, c7, #6
+// CHECK-INST: gcspopx
+// CHECK-ENCODING: encoding: [0xdf,0x77,0x08,0xd5]
+// CHECK-UNKNOWN:  d50877df sys #0, c7, c7, #6
+
 gcsb dsync
 // CHECK-INST: gcsb dsync
 // CHECK-ENCODING: encoding: [0x7f,0x22,0x03,0xd5]
diff --git a/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s b/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
index 2a1943ac22a27..bb431de9add13 100644
--- a/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
+++ b/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
@@ -34,6 +34,11 @@
 // CHECK-ENCODING: encoding: [0x1e,0x70,0x0e,0xd5]
 // CHECK-UNKNOWN:  d50e701e      apas x30
 
+  sys #6, c7, c0, #0, x3
+// CHECK-INST: apas x3
+// CHECK-ENCODING: encoding: [0x03,0x70,0x0e,0xd5]
+// CHECK-UNKNOWN:  d50e7003      apas x3
+
   mrs x3, GPCBW_EL3
 // CHECK-INST: mrs x3, GPCBW_EL3
 // CHECK-ENCODING: encoding: [0xa3,0x21,0x3e,0xd5]
diff --git a/llvm/test/MC/AArch64/brbe.s b/llvm/test/MC/AArch64/brbe.s
index f02017dae8e5e..8c493f08b8982 100644
--- a/llvm/test/MC/AArch64/brbe.s
+++ b/llvm/test/MC/AArch64/brbe.s
@@ -136,10 +136,14 @@ mrs x5, BRBTGT31_EL1
 
 brb iall
 brb inj
+sys #1, c7, c2, #4
+sys #1, c7, c2, #5
 // CHECK: brb iall  // encoding: [0x9f,0x72,0x09,0xd5]
 // CHECK: brb inj   // encoding: [0xbf,0x72,0x09,0xd5]
-// ERROR-NO-BRBE: [[@LINE-4]]:1: error: instruction requires: brbe
-// ERROR-NO-BRBE: [[@LINE-4]]:1: error: instruction requires: brbe
+// CHECK: brb iall  // encoding: [0x9f,0x72,0x09,0xd5]
+// CHECK: brb inj   // encoding: [0xbf,0x72,0x09,0xd5]
+// ERROR-NO-BRBE: [[@LINE-8]]:1: error: instruction requires: brbe
+// ERROR-NO-BRBE: [[@LINE-8]]:1: error: instruction requires: brbe
 
 brb IALL
 brb INJ

>From 537b32c06128149ab491cae0196a8bbc1a722f9e Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 27 Mar 2026 22:45:04 +0000
Subject: [PATCH 2/7] fixup! Move new tests into arm64-aliases.s

---
 llvm/test/MC/AArch64/arm64-aliases.s      | 32 ++++++++++++++++++
 llvm/test/MC/AArch64/armv8.9a-debug-pmu.s |  5 ---
 llvm/test/MC/AArch64/armv9.4a-gcs.s       | 40 -----------------------
 llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s  |  5 ---
 llvm/test/MC/AArch64/armv9a-sysp-pairs.s  | 25 ++++++++++++++
 llvm/test/MC/AArch64/brbe.s               |  8 ++---
 6 files changed, 59 insertions(+), 56 deletions(-)
 create mode 100644 llvm/test/MC/AArch64/armv9a-sysp-pairs.s

diff --git a/llvm/test/MC/AArch64/arm64-aliases.s b/llvm/test/MC/AArch64/arm64-aliases.s
index ae157c676c95f..f61809e559a00 100644
--- a/llvm/test/MC/AArch64/arm64-aliases.s
+++ b/llvm/test/MC/AArch64/arm64-aliases.s
@@ -1,4 +1,8 @@
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon -output-asm-variant=1 -show-encoding -print-imm-hex < %s | FileCheck %s
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+ite -filetype=obj < %s | llvm-objdump -d --mattr=+ite --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-ITE
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+gcs -filetype=obj < %s | llvm-objdump -d --mattr=+gcs --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-GCS
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+brbe -filetype=obj < %s | llvm-objdump -d --mattr=+brbe --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-BRBE
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon -filetype=obj < %s | llvm-objdump -d --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-RME
 
 foo:
 ;-----------------------------------------------------------------------------
@@ -526,6 +530,34 @@ foo:
   sys #4, c8, c7, #6, x31
 ; CHECK: tlbi vmalls12e1
 
+  sys #3, c7, c2, #7, x2
+; CHECK-ITE: trcit x2
+
+  sys #3, c7, c7, #2, x20
+; CHECK-GCS: gcsss1 x20
+  sysl x23, #3, c7, c7, #3
+; CHECK-GCS: gcsss2 x23
+  sys #3, c7, c7, #0, x24
+; CHECK-GCS: gcspushm x24
+  sysl xzr, #3, c7, c7, #1
+; CHECK-GCS: gcspopm
+  sysl x24, #3, c7, c7, #1
+; CHECK-GCS: gcspopm x24
+  sys #0, c7, c7, #4
+; CHECK-GCS: gcspushx
+  sys #0, c7, c7, #5
+; CHECK-GCS: gcspopcx
+  sys #0, c7, c7, #6
+; CHECK-GCS: gcspopx
+
+  sys #1, c7, c2, #4
+; CHECK-BRBE: brb iall
+  sys #1, c7, c2, #5
+; CHECK-BRBE: brb inj
+
+  sys #6, c7, c0, #0, x3
+; CHECK-RME: apas x3
+
   ic ialluis
 ; CHECK: ic ialluis                 ; encoding: [0x1f,0x71,0x08,0xd5]
   ic iallu
diff --git a/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s b/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
index ea058d484d852..db5cb0701036d 100644
--- a/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
+++ b/llvm/test/MC/AArch64/armv8.9a-debug-pmu.s
@@ -1773,11 +1773,6 @@ trcit x1
 // CHECK-ERROR: error: instruction requires: ite
 // CHECK-UNKNOWN:  d50b72e1      sys #3, c7, c2, #7, x1
 
-sys #3, c7, c2, #7, x2
-// CHECK-INST: trcit x2
-// CHECK-ENCODING: encoding: [0xe2,0x72,0x0b,0xd5]
-// CHECK-UNKNOWN:  d50b72e2      sys #3, c7, c2, #7, x2
-
 // FEAT_SPE_FDS
 mrs x3, PMSDSFR_EL1
 // CHECK-INST: mrs x3, PMSDSFR_EL1
diff --git a/llvm/test/MC/AArch64/armv9.4a-gcs.s b/llvm/test/MC/AArch64/armv9.4a-gcs.s
index 78b3f3639892e..f702c947543ac 100644
--- a/llvm/test/MC/AArch64/armv9.4a-gcs.s
+++ b/llvm/test/MC/AArch64/armv9.4a-gcs.s
@@ -119,44 +119,24 @@ gcsss1 x21
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50b7755 sys #3, c7, c7, #2, x21
 
-sys #3, c7, c7, #2, x20
-// CHECK-INST: gcsss1 x20
-// CHECK-ENCODING: encoding: [0x54,0x77,0x0b,0xd5]
-// CHECK-UNKNOWN:  d50b7754 sys #3, c7, c7, #2, x20
-
 gcsss2 x22
 // CHECK-INST: gcsss2 x22
 // CHECK-ENCODING: encoding: [0x76,0x77,0x2b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b7776 sysl x22, #3, c7, c7, #3
 
-sysl x23, #3, c7, c7, #3
-// CHECK-INST: gcsss2 x23
-// CHECK-ENCODING: encoding: [0x77,0x77,0x2b,0xd5]
-// CHECK-UNKNOWN:  d52b7777 sysl x23, #3, c7, c7, #3
-
 gcspushm x25
 // CHECK-INST: gcspushm x25
 // CHECK-ENCODING: encoding: [0x19,0x77,0x0b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50b7719 sys #3, c7, c7, #0, x25
 
-sys #3, c7, c7, #0, x24
-// CHECK-INST: gcspushm x24
-// CHECK-ENCODING: encoding: [0x18,0x77,0x0b,0xd5]
-// CHECK-UNKNOWN:  d50b7718 sys #3, c7, c7, #0, x24
-
 gcspopm
 // CHECK-INST: gcspopm
 // CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b773f sysl xzr, #3, c7, c7, #1
 
-sysl xzr, #3, c7, c7, #1
-// CHECK-INST: gcspopm
-// CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
-// CHECK-UNKNOWN:  d52b773f sysl xzr, #3, c7, c7, #1
-
 gcspopm xzr
 // CHECK-INST: gcspopm
 // CHECK-ENCODING: encoding: [0x3f,0x77,0x2b,0xd5]
@@ -169,11 +149,6 @@ gcspopm x25
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d52b7739 sysl x25, #3, c7, c7, #1
 
-sysl x24, #3, c7, c7, #1
-// CHECK-INST: gcspopm x24
-// CHECK-ENCODING: encoding: [0x38,0x77,0x2b,0xd5]
-// CHECK-UNKNOWN:  d52b7738 sysl x24, #3, c7, c7, #1
-
 gcsstr x26, [x27]
 // CHECK-INST: gcsstr x26, [x27]
 // CHECK-ENCODING: encoding: [0x7a,0x0f,0x1f,0xd9]
@@ -204,33 +179,18 @@ gcspushx
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d508779f sys #0, c7, c7, #4
 
-sys #0, c7, c7, #4
-// CHECK-INST: gcspushx
-// CHECK-ENCODING: encoding: [0x9f,0x77,0x08,0xd5]
-// CHECK-UNKNOWN:  d508779f sys #0, c7, c7, #4
-
 gcspopcx
 // CHECK-INST: gcspopcx
 // CHECK-ENCODING: encoding: [0xbf,0x77,0x08,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50877bf sys #0, c7, c7, #5
 
-sys #0, c7, c7, #5
-// CHECK-INST: gcspopcx
-// CHECK-ENCODING: encoding: [0xbf,0x77,0x08,0xd5]
-// CHECK-UNKNOWN:  d50877bf sys #0, c7, c7, #5
-
 gcspopx
 // CHECK-INST: gcspopx
 // CHECK-ENCODING: encoding: [0xdf,0x77,0x08,0xd5]
 // CHECK-ERROR: error: instruction requires: gcs
 // CHECK-UNKNOWN:  d50877df sys #0, c7, c7, #6
 
-sys #0, c7, c7, #6
-// CHECK-INST: gcspopx
-// CHECK-ENCODING: encoding: [0xdf,0x77,0x08,0xd5]
-// CHECK-UNKNOWN:  d50877df sys #0, c7, c7, #6
-
 gcsb dsync
 // CHECK-INST: gcsb dsync
 // CHECK-ENCODING: encoding: [0x7f,0x22,0x03,0xd5]
diff --git a/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s b/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
index bb431de9add13..2a1943ac22a27 100644
--- a/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
+++ b/llvm/test/MC/AArch64/armv9.6a-rme-gpc3.s
@@ -34,11 +34,6 @@
 // CHECK-ENCODING: encoding: [0x1e,0x70,0x0e,0xd5]
 // CHECK-UNKNOWN:  d50e701e      apas x30
 
-  sys #6, c7, c0, #0, x3
-// CHECK-INST: apas x3
-// CHECK-ENCODING: encoding: [0x03,0x70,0x0e,0xd5]
-// CHECK-UNKNOWN:  d50e7003      apas x3
-
   mrs x3, GPCBW_EL3
 // CHECK-INST: mrs x3, GPCBW_EL3
 // CHECK-ENCODING: encoding: [0xa3,0x21,0x3e,0xd5]
diff --git a/llvm/test/MC/AArch64/armv9a-sysp-pairs.s b/llvm/test/MC/AArch64/armv9a-sysp-pairs.s
new file mode 100644
index 0000000000000..87990fb122ecc
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9a-sysp-pairs.s
@@ -0,0 +1,25 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+d128,+tlb-rmi < %s \
+// RUN:   | FileCheck %s --check-prefixes=CHECK-ASM,CHECK-ENCODING
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+d128,+tlb-rmi < %s \
+// RUN:   | llvm-objdump -d --mattr=-d128,-tlb-rmi --no-print-imm-hex - \
+// RUN:   | FileCheck %s --check-prefix=CHECK-DIS
+
+sysp #0, c8, c2, #2, x8, x9
+// CHECK-ASM: sysp #0, c8, c2, #2, x8, x9
+// CHECK-ENCODING: encoding: [0x48,0x82,0x48,0xd5]
+// CHECK-DIS: sysp #0, c8, c2, #2, x8, x9
+
+sysp #0, c8, c2, #2, xzr, xzr
+// CHECK-ASM: sysp #0, c8, c2, #2
+// CHECK-ENCODING: encoding: [0x5f,0x82,0x48,0xd5]
+// CHECK-DIS: sysp #0, c8, c2, #2
+
+tlbip VAE1, x8, x9
+// CHECK-ASM: tlbip vae1, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x87,0x48,0xd5]
+// CHECK-DIS: sysp #0, c8, c7, #1, x8, x9
+
+tlbip VAE1, xzr, xzr
+// CHECK-ASM: tlbip vae1, xzr, xzr
+// CHECK-ENCODING: encoding: [0x3f,0x87,0x48,0xd5]
+// CHECK-DIS: sysp #0, c8, c7, #1
diff --git a/llvm/test/MC/AArch64/brbe.s b/llvm/test/MC/AArch64/brbe.s
index 8c493f08b8982..f02017dae8e5e 100644
--- a/llvm/test/MC/AArch64/brbe.s
+++ b/llvm/test/MC/AArch64/brbe.s
@@ -136,14 +136,10 @@ mrs x5, BRBTGT31_EL1
 
 brb iall
 brb inj
-sys #1, c7, c2, #4
-sys #1, c7, c2, #5
 // CHECK: brb iall  // encoding: [0x9f,0x72,0x09,0xd5]
 // CHECK: brb inj   // encoding: [0xbf,0x72,0x09,0xd5]
-// CHECK: brb iall  // encoding: [0x9f,0x72,0x09,0xd5]
-// CHECK: brb inj   // encoding: [0xbf,0x72,0x09,0xd5]
-// ERROR-NO-BRBE: [[@LINE-8]]:1: error: instruction requires: brbe
-// ERROR-NO-BRBE: [[@LINE-8]]:1: error: instruction requires: brbe
+// ERROR-NO-BRBE: [[@LINE-4]]:1: error: instruction requires: brbe
+// ERROR-NO-BRBE: [[@LINE-4]]:1: error: instruction requires: brbe
 
 brb IALL
 brb INJ

>From 865fa12f2e0b32eb07177bf312f939ea777dc1cd Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 27 Mar 2026 23:34:07 +0000
Subject: [PATCH 3/7] fixup! Parse instructions in AArch64AsmParser.cpp

---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 14 ---
 .../AArch64/AsmParser/AArch64AsmParser.cpp    | 92 ++++++++++++++++++-
 2 files changed, 87 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 09a8a9a63fb7d..68b2b7257616e 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2545,20 +2545,6 @@ def SYSLxt : SystemLXtI<1, "sysl">;
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
                 (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
                  sys_cr_op:$Cm, timm32_0_7:$op2, XZR)>;
-def : InstAlias<"apas $Xt",
-                (SYSxt 6, 7, 0, 0, GPR64:$Xt)>;
-def : InstAlias<"brb\tiall",
-                (SYSxt 1, 7, 2, 4, XZR)>, Requires<[HasBRBE]>;
-def : InstAlias<"brb\tinj",
-                (SYSxt 1, 7, 2, 5, XZR)>, Requires<[HasBRBE]>;
-def : InstAlias<"trcit $Rt",
-                (SYSxt 3, 7, 2, 7, GPR64:$Rt)>, Requires<[HasITE]>;
-def : InstAlias<"gcspushx",
-                (SYSxt 0, 7, 7, 4, XZR)>, Requires<[HasGCS]>;
-def : InstAlias<"gcspopcx",
-                (SYSxt 0, 7, 7, 5, XZR)>, Requires<[HasGCS]>;
-def : InstAlias<"gcspopx",
-                (SYSxt 0, 7, 7, 6, XZR)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspushm $Rt",
                 (SYSxt 3, 7, 7, 0, GPR64:$Rt)>, Requires<[HasGCS]>;
 def : InstAlias<"gcsss1 $Rt",
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 906117a066dd6..6690faae36619 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -4033,9 +4033,9 @@ void AArch64AsmParser::createSysAlias(uint16_t Encoding, OperandVector &Operands
       AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
 }
 
-/// parseSysAlias - The IC, DC, AT, TLBI, MLBI and GIC{R} and GSB instructions
-/// are simple aliases for the SYS instruction. Parse them specially so that
-/// we create a SYS MCInst.
+/// parseSysAlias - The IC, DC, AT, TLBI, MLBI, APAS, BRB, TRCIT, GCS aliases,
+/// GIC{R} and GSB instructions are simple aliases for the SYS instruction.
+/// Parse them specially so that we create a SYS MCInst.
 bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
                                    OperandVector &Operands) {
   if (Name.contains('.'))
@@ -4044,6 +4044,85 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
   Mnemonic = Name;
   Operands.push_back(AArch64Operand::CreateToken("sys", NameLoc, getContext()));
 
+  if (Mnemonic == "apas") {
+    const uint16_t Encoding = (6 << 11) | (7 << 7);
+    createSysAlias(Encoding, Operands, getLoc());
+
+    if (parseRegister(Operands))
+      return TokError("expected register operand");
+
+    if (parseToken(AsmToken::EndOfStatement,
+                   "unexpected token in argument list"))
+      return true;
+
+    return false;
+  }
+
+  if (Mnemonic == "trcit") {
+    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
+          getSTI().hasFeature(AArch64::FeatureITE)))
+      return Error(NameLoc, "instruction requires: ite");
+
+    const uint16_t Encoding = (3 << 11) | (7 << 7) | (2 << 3) | 7;
+    createSysAlias(Encoding, Operands, getLoc());
+
+    if (parseRegister(Operands))
+      return TokError("expected register operand");
+
+    if (parseToken(AsmToken::EndOfStatement,
+                   "unexpected token in argument list"))
+      return true;
+
+    return false;
+  }
+
+  if (Mnemonic == "gcspushx" || Mnemonic == "gcspopcx" || Mnemonic == "gcspopx") {
+    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
+          getSTI().hasFeature(AArch64::FeatureGCS)))
+      return Error(NameLoc, "instruction requires: gcs");
+
+    uint16_t Encoding = (7 << 7) | (7 << 3);
+    if (Mnemonic == "gcspushx")
+      Encoding |= 4;
+    else if (Mnemonic == "gcspopcx")
+      Encoding |= 5;
+    else
+      Encoding |= 6;
+    createSysAlias(Encoding, Operands, getLoc());
+
+    if (parseToken(AsmToken::EndOfStatement,
+                   "unexpected token in argument list"))
+      return true;
+
+    return false;
+  }
+
+  if (Mnemonic == "brb") {
+    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
+          getSTI().hasFeature(AArch64::FeatureBRBE)))
+      return Error(NameLoc, "instruction requires: brbe");
+
+    const AsmToken &Tok = getTok();
+    StringRef Op = Tok.getString();
+    SMLoc S = Tok.getLoc();
+    uint16_t Encoding = 0;
+    if (Op.equals_insensitive("iall"))
+      Encoding = (1 << 11) | (7 << 7) | (2 << 3) | 4;
+    else if (Op.equals_insensitive("inj"))
+      Encoding = (1 << 11) | (7 << 7) | (2 << 3) | 5;
+    else
+      return TokError("invalid operand for BRB instruction");
+
+    createSysAlias(Encoding, Operands, S);
+    Lex(); // Eat operand.
+
+    if (parseToken(AsmToken::EndOfStatement,
+                   "unexpected token in argument list"))
+      return true;
+
+    return false;
+  }
+
   const AsmToken &Tok = getTok();
   StringRef Op = Tok.getString();
   SMLoc S = Tok.getLoc();
@@ -5506,11 +5585,14 @@ bool AArch64AsmParser::parseInstruction(ParseInstructionInfo &Info,
   size_t Start = 0, Next = Name.find('.');
   StringRef Head = Name.slice(Start, Next);
 
-  // IC, DC, AT, TLBI, MLBI, PLBI, GIC{R}, GSB and Prediction invalidation
+  // IC, DC, AT, TLBI, MLBI, PLBI, APAS, BRB, TRCIT, GCS aliases, GIC{R},
+  // GSB and Prediction invalidation
   // instructions are aliases for the SYS instruction.
   if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi" ||
       Head == "cfp" || Head == "dvp" || Head == "cpp" || Head == "cosp" ||
-      Head == "mlbi" || Head == "plbi" || Head == "gic" || Head == "gsb")
+      Head == "mlbi" || Head == "plbi" || Head == "gic" || Head == "gsb" ||
+      Head == "apas" || Head == "brb" || Head == "trcit" ||
+      Head == "gcspushx" || Head == "gcspopcx" || Head == "gcspopx")
     return parseSysAlias(Head, NameLoc, Operands);
 
   // GICR instructions are aliases for the SYSL instruction.

>From b4582a214515b5f367c2251fb685ef4e927ae8f2 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 30 Mar 2026 11:23:29 +0100
Subject: [PATCH 4/7] fixup! Improve printing code for tabs and commas

---
 .../AArch64/MCTargetDesc/AArch64InstPrinter.cpp     | 13 +++++--------
 1 file changed, 5 insertions(+), 8 deletions(-)

diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 979a16baa9df8..e5a80900df25e 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -919,6 +919,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
   bool OptionalReg = false;
   std::string Ins;
   std::string Name;
+  StringRef RegSep = ", ";
 
   if (CnVal == 7) {
     switch (CmVal) {
@@ -929,6 +930,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         NeedsReg = true;
         Ins = "apas";
         Name = "";
+        RegSep = "\t";
         break;
       }
 
@@ -980,6 +982,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         NeedsReg = true;
         Ins = "trcit";
         Name = "";
+        RegSep = "\t";
         break;
       }
     } break;
@@ -1063,6 +1066,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
         return false;
 
       Name = "";
+      RegSep = "\t";
       switch (Op1Val) {
       default:
         return false;
@@ -1154,13 +1158,6 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
   if (NotXZR && !NeedsReg && !OptionalReg)
     return false;
 
-  if (Name.empty()) {
-    O << '\t' << Ins;
-    if (NeedsReg || (OptionalReg && NotXZR))
-      O << '\t' << Reg;
-    return true;
-  }
-
   std::string Str = Ins + Name;
   llvm::transform(Str, Str.begin(), ::tolower);
 
@@ -1169,7 +1166,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
   // For optional registers, don't print the value if it's xzr/x31
   // since this defaults to xzr/x31 if register is not specified.
   if (NeedsReg || (OptionalReg && NotXZR))
-    O << ", " << Reg;
+    O << RegSep << Reg;
 
   return true;
 }

>From c4a194fc2e813f579bf0f2f70fa2fdcf1cb1b684 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Thu, 2 Apr 2026 19:16:39 +0100
Subject: [PATCH 5/7] fixup! Ensure GCSPUSHM, GCSSS1, GCSPOPM and GCSSS2 are
 all converted

---
 .../Target/AArch64/AArch64ISelDAGToDAG.cpp    | 14 ++++--
 .../lib/Target/AArch64/AArch64InstrFormats.td | 23 +++++++--
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 50 ++++---------------
 .../AArch64/AArch64SchedFalkorDetails.td      |  2 +-
 .../AArch64/AsmParser/AArch64AsmParser.cpp    |  3 +-
 .../MCTargetDesc/AArch64InstPrinter.cpp       | 15 +++---
 6 files changed, 51 insertions(+), 56 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
index 09ff2209a67eb..93e0aedcb0304 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp
@@ -5077,10 +5077,18 @@ void AArch64DAGToDAGISel::Select(SDNode *Node) {
       SDValue Chain = Node->getOperand(0);
       SDValue Val = Node->getOperand(2);
       SDValue Zero = CurDAG->getCopyFromReg(Chain, DL, AArch64::XZR, MVT::i64);
+      SDValue Op1 = CurDAG->getTargetConstant(3, DL, MVT::i32);
+      SDValue Cn = CurDAG->getTargetConstant(7, DL, MVT::i32);
+      SDValue Cm = CurDAG->getTargetConstant(7, DL, MVT::i32);
+      SDValue SS1Op2 = CurDAG->getTargetConstant(2, DL, MVT::i32);
+      SDValue SS2Op2 = CurDAG->getTargetConstant(3, DL, MVT::i32);
+      SDValue SS1Ops[] = {Op1, Cn, Cm, SS1Op2, Val, Chain};
       SDNode *SS1 =
-          CurDAG->getMachineNode(AArch64::GCSSS1, DL, MVT::Other, Val, Chain);
-      SDNode *SS2 = CurDAG->getMachineNode(AArch64::GCSSS2, DL, MVT::i64,
-                                           MVT::Other, Zero, SDValue(SS1, 0));
+          CurDAG->getMachineNode(AArch64::SYSxt, DL, MVT::Other, SS1Ops);
+      SDValue SS2Ops[] = {Zero, Op1, Cn, Cm, SS2Op2, SDValue(SS1, 0)};
+      SDNode *SS2 = CurDAG->getMachineNode(
+          AArch64::SYSLxt_GCS, DL, CurDAG->getVTList(MVT::i64, MVT::Other),
+          SS2Ops);
       ReplaceNode(Node, SS2);
       return;
     }
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 0c2bd5313cf0e..4d62ce5e6d822 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2143,10 +2143,8 @@ class SystemXtI<string asm>
   let hasSideEffects = 1;
 }
 
-class SystemLXtI<bit L, string asm>
-  : RtSystemI<L, (outs),
-       (ins GPR64:$Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2),
-       asm, "\t$Rt, $op1, $Cn, $Cm, $op2"> {
+class BaseSystemLXtI<bit L, dag oops, dag iops, string asm>
+  : RtSystemI<L, oops, iops, asm, "\t$Rt, $op1, $Cn, $Cm, $op2"> {
   bits<3> op1;
   bits<4> Cn;
   bits<4> Cm;
@@ -2158,6 +2156,23 @@ class SystemLXtI<bit L, string asm>
   let Inst{7-5}   = op2;
 }
 
+class SystemLXtI<bit L, string asm>
+  : BaseSystemLXtI<L, (outs),
+       (ins GPR64:$Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
+            imm0_7:$op2), asm>;
+
+// GCS SYSL operations preserve the old destination value when GCS is disabled
+// at runtime, so codegen needs a tied def/use form for those cases only.
+class GCSTiedSystemLXtI<bit L, string asm>
+  : BaseSystemLXtI<L, (outs GPR64:$Rt),
+       (ins GPR64:$src, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
+            imm0_7:$op2), asm> {
+  let mayLoad = 1;
+  let mayStore = 1;
+  let hasSideEffects = 1;
+  let Constraints = "$src = $Rt";
+}
+
 def RangePrefetchOperand : AsmOperandClass {
   let Name = "RangePrefetch";
   let ParserMethod = "tryParseRPRFMOperand";
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 68b2b7257616e..079c12e722350 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -1635,44 +1635,6 @@ def : TokenAlias<"IALL", "iall">;
 
 
 // ARMv9.4-A Guarded Control Stack
-class GCSRtIn<bits<3> op1, bits<3> op2, string mnemonic,
-            list<dag> pattern = []>
-    : RtSystemI<0, (outs), (ins GPR64:$Rt), mnemonic, "\t$Rt", pattern> {
-  let Inst{20-19} = 0b01;
-  let Inst{18-16} = op1;
-  let Inst{15-8} = 0b01110111;
-  let Inst{7-5} = op2;
-  let Predicates = [HasGCS];
-  let hasSideEffects = 1;
-}
-
-let mayStore = 1, mayLoad = 1 in
-def GCSSS1   : GCSRtIn<0b011, 0b010, "gcsss1">;
-let mayStore = 1 in
-def GCSPUSHM : GCSRtIn<0b011, 0b000, "gcspushm">;
-
-class GCSRtOut<bits<3> op1, bits<3> op2, string mnemonic,
-            list<dag> pattern = []>
-    : RtSystemI<1, (outs GPR64:$Rt), (ins GPR64:$src), mnemonic, "\t$Rt", pattern> {
-  let Inst{20-19} = 0b01;
-  let Inst{18-16} = op1;
-  let Inst{15-8} = 0b01110111;
-  let Inst{7-5} = op2;
-  let Predicates = [HasGCS];
-  let hasSideEffects = 1;
-  // The input register is unchanged when GCS is disabled, so we need it as
-  // both an input and output operand.
-  let Constraints = "$src = $Rt";
-}
-
-let mayStore = 1, mayLoad = 1 in
-def GCSSS2  : GCSRtOut<0b011, 0b011, "gcsss2">;
-// FIXME: mayStore = 1 only needed to match the intrinsic definition
-let mayStore = 1, mayLoad = 1 in
-def GCSPOPM : GCSRtOut<0b011, 0b001, "gcspopm",
-                       [(set GPR64:$Rt, (int_aarch64_gcspopm GPR64:$src))]>;
-def GCSPOPM_NoOp : InstAlias<"gcspopm", (GCSPOPM XZR)>, Requires<[HasGCS]>; // Rt defaults to XZR if absent
-
 def GCSB_DSYNC_disable : InstAlias<"gcsb\tdsync", (HINT 19), 0>;
 def GCSB_DSYNC         : InstAlias<"gcsb\tdsync", (HINT 19), 1>, Requires<[HasGCS]>;
 
@@ -2541,6 +2503,9 @@ def MSR_FPMR : Pseudo<(outs), (ins GPR64:$val),
 // Generic system instructions
 def SYSxt  : SystemXtI<"sys">;
 def SYSLxt : SystemLXtI<1, "sysl">;
+def SYSLxt_GCS : GCSTiedSystemLXtI<1, "sysl"> {
+  let isCodeGenOnly = 1;
+}
 
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
                 (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
@@ -2550,11 +2515,14 @@ def : InstAlias<"gcspushm $Rt",
 def : InstAlias<"gcsss1 $Rt",
                 (SYSxt 3, 7, 7, 2, GPR64:$Rt)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspopm",
-                (SYSLxt XZR, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+                (SYSLxt_GCS XZR, 3, 7, 7, 1)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspopm $Rt",
-                (SYSLxt GPR64:$Rt, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+                (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 1)>, Requires<[HasGCS]>;
 def : InstAlias<"gcsss2 $Rt",
-                (SYSLxt GPR64:$Rt, 3, 7, 7, 3)>, Requires<[HasGCS]>;
+                (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 3)>, Requires<[HasGCS]>;
+let Predicates = [HasGCS] in
+def : Pat<(int_aarch64_gcspopm GPR64:$Rt),
+          (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 1)>;
 
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td b/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td
index 375e3652c9e87..cc864cb2bf5ec 100644
--- a/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td
+++ b/llvm/lib/Target/AArch64/AArch64SchedFalkorDetails.td
@@ -1243,7 +1243,7 @@ def : InstRW<[WriteSequence<[FalkorWr_1LD_3cyc, FalkorWr_1XYZ_1cyc]>],
 // -----------------------------------------------------------------------------
 def : InstRW<[FalkorWr_1LD_0cyc],     (instrs CLREX, DMB, DSB)>;
 def : InstRW<[FalkorWr_1none_0cyc],   (instrs BRK, DCPS1, DCPS2, DCPS3, HINT, HLT, HVC, ISB, SMC, SVC)>;
-def : InstRW<[FalkorWr_1ST_0cyc],     (instrs SYSxt, SYSLxt)>;
+def : InstRW<[FalkorWr_1ST_0cyc],     (instrs SYSxt, SYSLxt, SYSLxt_GCS)>;
 def : InstRW<[FalkorWr_1Z_0cyc],      (instrs MSRpstateImm1, MSRpstateImm4)>;
 
 def : InstRW<[FalkorWr_1LD_3cyc, FalkorReadIncLd],
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 6690faae36619..de10cf0557d69 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -4076,7 +4076,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
     return false;
   }
 
-  if (Mnemonic == "gcspushx" || Mnemonic == "gcspopcx" || Mnemonic == "gcspopx") {
+  if (Mnemonic == "gcspushx" || Mnemonic == "gcspopcx" ||
+      Mnemonic == "gcspopx") {
     if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
           getSTI().hasFeature(AArch64::FeatureGCS)))
       return Error(NameLoc, "instruction requires: gcs");
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index e5a80900df25e..8306e49207700 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -84,7 +84,7 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
       return;
     }
 
-  if (Opcode == AArch64::SYSLxt)
+  if (Opcode == AArch64::SYSLxt || Opcode == AArch64::SYSLxt_GCS)
     if (printSyslAlias(MI, STI, O)) {
       printAnnotation(O, Annot);
       return;
@@ -1176,14 +1176,17 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
                                         raw_ostream &O) {
 #ifndef NDEBUG
   unsigned Opcode = MI->getOpcode();
-  assert(Opcode == AArch64::SYSLxt && "Invalid opcode for SYSL alias!");
+  assert((Opcode == AArch64::SYSLxt || Opcode == AArch64::SYSLxt_GCS) &&
+         "Invalid opcode for SYSL alias!");
 #endif
 
+  unsigned OpOffset = Opcode == AArch64::SYSLxt_GCS ? 1 : 0;
+
   StringRef Reg = getRegisterName(MI->getOperand(0).getReg());
-  const MCOperand &Op1 = MI->getOperand(1);
-  const MCOperand &Cn = MI->getOperand(2);
-  const MCOperand &Cm = MI->getOperand(3);
-  const MCOperand &Op2 = MI->getOperand(4);
+  const MCOperand &Op1 = MI->getOperand(OpOffset + 1);
+  const MCOperand &Cn = MI->getOperand(OpOffset + 2);
+  const MCOperand &Cm = MI->getOperand(OpOffset + 3);
+  const MCOperand &Op2 = MI->getOperand(OpOffset + 4);
 
   unsigned Op1Val = Op1.getImm();
   unsigned CnVal = Cn.getImm();

>From 4bc3ec9a05a47f2ddfc2a92dfa56e223e35ca1ce Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Mon, 13 Apr 2026 15:27:20 +0100
Subject: [PATCH 6/7] fixup! Add negative tests, and revert 391c34289 (move to
 aliases in Tablegen)

---
 .../lib/Target/AArch64/AArch64InstrFormats.td |  8 +-
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 14 +++
 .../AArch64/AsmParser/AArch64AsmParser.cpp    | 93 +------------------
 .../MCTargetDesc/AArch64InstPrinter.cpp       |  4 +-
 llvm/test/MC/AArch64/arm64-aliases.s          | 14 +++
 llvm/test/MC/AArch64/armv9a-sysp-pairs.s      | 25 -----
 llvm/test/MC/AArch64/armv9a-sysp.s            |  8 ++
 llvm/test/MC/AArch64/armv9a-tlbip.s           |  7 ++
 8 files changed, 54 insertions(+), 119 deletions(-)
 delete mode 100644 llvm/test/MC/AArch64/armv9a-sysp-pairs.s

diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 4d62ce5e6d822..f1c9300024373 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2161,16 +2161,16 @@ class SystemLXtI<bit L, string asm>
        (ins GPR64:$Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
             imm0_7:$op2), asm>;
 
-// GCS SYSL operations preserve the old destination value when GCS is disabled
-// at runtime, so codegen needs a tied def/use form for those cases only.
+// Codegen-only GCS SYSL operations need a tied def/use on Rt because they
+// preserve the old destination value when GCS is disabled at runtime.
 class GCSTiedSystemLXtI<bit L, string asm>
   : BaseSystemLXtI<L, (outs GPR64:$Rt),
-       (ins GPR64:$src, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
+       (ins GPR64:$_Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
             imm0_7:$op2), asm> {
   let mayLoad = 1;
   let mayStore = 1;
   let hasSideEffects = 1;
-  let Constraints = "$src = $Rt";
+  let Constraints = "$Rt = $_Rt";
 }
 
 def RangePrefetchOperand : AsmOperandClass {
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 079c12e722350..2f1562afa9b41 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2510,6 +2510,20 @@ def SYSLxt_GCS : GCSTiedSystemLXtI<1, "sysl"> {
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
                 (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
                  sys_cr_op:$Cm, timm32_0_7:$op2, XZR)>;
+def : InstAlias<"apas $Xt",
+                (SYSxt 6, 7, 0, 0, GPR64:$Xt)>;
+def : InstAlias<"brb\tiall",
+                (SYSxt 1, 7, 2, 4, XZR)>, Requires<[HasBRBE]>;
+def : InstAlias<"brb\tinj",
+                (SYSxt 1, 7, 2, 5, XZR)>, Requires<[HasBRBE]>;
+def : InstAlias<"trcit $Rt",
+                (SYSxt 3, 7, 2, 7, GPR64:$Rt)>, Requires<[HasITE]>;
+def : InstAlias<"gcspushx",
+                (SYSxt 0, 7, 7, 4, XZR)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopcx",
+                (SYSxt 0, 7, 7, 5, XZR)>, Requires<[HasGCS]>;
+def : InstAlias<"gcspopx",
+                (SYSxt 0, 7, 7, 6, XZR)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspushm $Rt",
                 (SYSxt 3, 7, 7, 0, GPR64:$Rt)>, Requires<[HasGCS]>;
 def : InstAlias<"gcsss1 $Rt",
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index de10cf0557d69..906117a066dd6 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -4033,9 +4033,9 @@ void AArch64AsmParser::createSysAlias(uint16_t Encoding, OperandVector &Operands
       AArch64Operand::CreateImm(Expr, S, getLoc(), getContext()));
 }
 
-/// parseSysAlias - The IC, DC, AT, TLBI, MLBI, APAS, BRB, TRCIT, GCS aliases,
-/// GIC{R} and GSB instructions are simple aliases for the SYS instruction.
-/// Parse them specially so that we create a SYS MCInst.
+/// parseSysAlias - The IC, DC, AT, TLBI, MLBI and GIC{R} and GSB instructions
+/// are simple aliases for the SYS instruction. Parse them specially so that
+/// we create a SYS MCInst.
 bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
                                    OperandVector &Operands) {
   if (Name.contains('.'))
@@ -4044,86 +4044,6 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc,
   Mnemonic = Name;
   Operands.push_back(AArch64Operand::CreateToken("sys", NameLoc, getContext()));
 
-  if (Mnemonic == "apas") {
-    const uint16_t Encoding = (6 << 11) | (7 << 7);
-    createSysAlias(Encoding, Operands, getLoc());
-
-    if (parseRegister(Operands))
-      return TokError("expected register operand");
-
-    if (parseToken(AsmToken::EndOfStatement,
-                   "unexpected token in argument list"))
-      return true;
-
-    return false;
-  }
-
-  if (Mnemonic == "trcit") {
-    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
-          getSTI().hasFeature(AArch64::FeatureITE)))
-      return Error(NameLoc, "instruction requires: ite");
-
-    const uint16_t Encoding = (3 << 11) | (7 << 7) | (2 << 3) | 7;
-    createSysAlias(Encoding, Operands, getLoc());
-
-    if (parseRegister(Operands))
-      return TokError("expected register operand");
-
-    if (parseToken(AsmToken::EndOfStatement,
-                   "unexpected token in argument list"))
-      return true;
-
-    return false;
-  }
-
-  if (Mnemonic == "gcspushx" || Mnemonic == "gcspopcx" ||
-      Mnemonic == "gcspopx") {
-    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
-          getSTI().hasFeature(AArch64::FeatureGCS)))
-      return Error(NameLoc, "instruction requires: gcs");
-
-    uint16_t Encoding = (7 << 7) | (7 << 3);
-    if (Mnemonic == "gcspushx")
-      Encoding |= 4;
-    else if (Mnemonic == "gcspopcx")
-      Encoding |= 5;
-    else
-      Encoding |= 6;
-    createSysAlias(Encoding, Operands, getLoc());
-
-    if (parseToken(AsmToken::EndOfStatement,
-                   "unexpected token in argument list"))
-      return true;
-
-    return false;
-  }
-
-  if (Mnemonic == "brb") {
-    if (!(getSTI().hasFeature(AArch64::FeatureAll) ||
-          getSTI().hasFeature(AArch64::FeatureBRBE)))
-      return Error(NameLoc, "instruction requires: brbe");
-
-    const AsmToken &Tok = getTok();
-    StringRef Op = Tok.getString();
-    SMLoc S = Tok.getLoc();
-    uint16_t Encoding = 0;
-    if (Op.equals_insensitive("iall"))
-      Encoding = (1 << 11) | (7 << 7) | (2 << 3) | 4;
-    else if (Op.equals_insensitive("inj"))
-      Encoding = (1 << 11) | (7 << 7) | (2 << 3) | 5;
-    else
-      return TokError("invalid operand for BRB instruction");
-
-    createSysAlias(Encoding, Operands, S);
-    Lex(); // Eat operand.
-
-    if (parseToken(AsmToken::EndOfStatement,
-                   "unexpected token in argument list"))
-      return true;
-
-    return false;
-  }
-
   const AsmToken &Tok = getTok();
   StringRef Op = Tok.getString();
   SMLoc S = Tok.getLoc();
@@ -5586,14 +5506,11 @@ bool AArch64AsmParser::parseInstruction(ParseInstructionInfo &Info,
   size_t Start = 0, Next = Name.find('.');
   StringRef Head = Name.slice(Start, Next);
 
-  // IC, DC, AT, TLBI, MLBI, PLBI, APAS, BRB, TRCIT, GCS aliases, GIC{R},
-  // GSB and Prediction invalidation
+  // IC, DC, AT, TLBI, MLBI, PLBI, GIC{R}, GSB and Prediction invalidation
   // instructions are aliases for the SYS instruction.
   if (Head == "ic" || Head == "dc" || Head == "at" || Head == "tlbi" ||
       Head == "cfp" || Head == "dvp" || Head == "cpp" || Head == "cosp" ||
-      Head == "mlbi" || Head == "plbi" || Head == "gic" || Head == "gsb" ||
-      Head == "apas" || Head == "brb" || Head == "trcit" ||
-      Head == "gcspushx" || Head == "gcspopcx" || Head == "gcspopx")
+      Head == "mlbi" || Head == "plbi" || Head == "gic" || Head == "gsb")
     return parseSysAlias(Head, NameLoc, Operands);
 
   // GICR instructions are aliases for the SYSL instruction.
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 8306e49207700..d513d47ebd52f 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1065,8 +1065,8 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
             STI.hasFeature(AArch64::FeatureGCS)))
         return false;
 
-      Name = "";
       RegSep = "\t";
+      Name = "";
       switch (Op1Val) {
       default:
         return false;
@@ -1174,8 +1174,8 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
 bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
                                         const MCSubtargetInfo &STI,
                                         raw_ostream &O) {
-#ifndef NDEBUG
   unsigned Opcode = MI->getOpcode();
+#ifndef NDEBUG
   assert((Opcode == AArch64::SYSLxt || Opcode == AArch64::SYSLxt_GCS) &&
          "Invalid opcode for SYSL alias!");
 #endif
diff --git a/llvm/test/MC/AArch64/arm64-aliases.s b/llvm/test/MC/AArch64/arm64-aliases.s
index f61809e559a00..4d7444fb67afe 100644
--- a/llvm/test/MC/AArch64/arm64-aliases.s
+++ b/llvm/test/MC/AArch64/arm64-aliases.s
@@ -1,7 +1,10 @@
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon -output-asm-variant=1 -show-encoding -print-imm-hex < %s | FileCheck %s
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+ite -filetype=obj < %s | llvm-objdump -d --mattr=+ite --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-ITE
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+ite -filetype=obj < %s | llvm-objdump -d --mattr=-ite --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-NO-ITE
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+gcs -filetype=obj < %s | llvm-objdump -d --mattr=+gcs --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-GCS
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+gcs -filetype=obj < %s | llvm-objdump -d --mattr=-gcs --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-NO-GCS
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+brbe -filetype=obj < %s | llvm-objdump -d --mattr=+brbe --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-BRBE
+; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon,+brbe -filetype=obj < %s | llvm-objdump -d --mattr=-brbe --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-NO-BRBE
 ; RUN: llvm-mc -triple arm64-apple-darwin -mattr=neon -filetype=obj < %s | llvm-objdump -d --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-RME
 
 foo:
@@ -532,28 +535,39 @@ foo:
 
   sys #3, c7, c2, #7, x2
 ; CHECK-ITE: trcit x2
+; CHECK-NO-ITE: sys #3, c7, c2, #7, x2
 
   sys #3, c7, c7, #2, x20
 ; CHECK-GCS: gcsss1 x20
+; CHECK-NO-GCS: sys #3, c7, c7, #2, x20
   sysl x23, #3, c7, c7, #3
 ; CHECK-GCS: gcsss2 x23
+; CHECK-NO-GCS: sysl x23, #3, c7, c7, #3
   sys #3, c7, c7, #0, x24
 ; CHECK-GCS: gcspushm x24
+; CHECK-NO-GCS: sys #3, c7, c7, #0, x24
   sysl xzr, #3, c7, c7, #1
 ; CHECK-GCS: gcspopm
+; CHECK-NO-GCS: sysl xzr, #3, c7, c7, #1
   sysl x24, #3, c7, c7, #1
 ; CHECK-GCS: gcspopm x24
+; CHECK-NO-GCS: sysl x24, #3, c7, c7, #1
   sys #0, c7, c7, #4
 ; CHECK-GCS: gcspushx
+; CHECK-NO-GCS: sys #0, c7, c7, #4
   sys #0, c7, c7, #5
 ; CHECK-GCS: gcspopcx
+; CHECK-NO-GCS: sys #0, c7, c7, #5
   sys #0, c7, c7, #6
 ; CHECK-GCS: gcspopx
+; CHECK-NO-GCS: sys #0, c7, c7, #6
 
   sys #1, c7, c2, #4
 ; CHECK-BRBE: brb iall
+; CHECK-NO-BRBE: sys #1, c7, c2, #4
   sys #1, c7, c2, #5
 ; CHECK-BRBE: brb inj
+; CHECK-NO-BRBE: sys #1, c7, c2, #5
 
   sys #6, c7, c0, #0, x3
 ; CHECK-RME: apas x3
diff --git a/llvm/test/MC/AArch64/armv9a-sysp-pairs.s b/llvm/test/MC/AArch64/armv9a-sysp-pairs.s
deleted file mode 100644
index 87990fb122ecc..0000000000000
--- a/llvm/test/MC/AArch64/armv9a-sysp-pairs.s
+++ /dev/null
@@ -1,25 +0,0 @@
-// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+d128,+tlb-rmi < %s \
-// RUN:   | FileCheck %s --check-prefixes=CHECK-ASM,CHECK-ENCODING
-// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+d128,+tlb-rmi < %s \
-// RUN:   | llvm-objdump -d --mattr=-d128,-tlb-rmi --no-print-imm-hex - \
-// RUN:   | FileCheck %s --check-prefix=CHECK-DIS
-
-sysp #0, c8, c2, #2, x8, x9
-// CHECK-ASM: sysp #0, c8, c2, #2, x8, x9
-// CHECK-ENCODING: encoding: [0x48,0x82,0x48,0xd5]
-// CHECK-DIS: sysp #0, c8, c2, #2, x8, x9
-
-sysp #0, c8, c2, #2, xzr, xzr
-// CHECK-ASM: sysp #0, c8, c2, #2
-// CHECK-ENCODING: encoding: [0x5f,0x82,0x48,0xd5]
-// CHECK-DIS: sysp #0, c8, c2, #2
-
-tlbip VAE1, x8, x9
-// CHECK-ASM: tlbip vae1, x8, x9
-// CHECK-ENCODING: encoding: [0x28,0x87,0x48,0xd5]
-// CHECK-DIS: sysp #0, c8, c7, #1, x8, x9
-
-tlbip VAE1, xzr, xzr
-// CHECK-ASM: tlbip vae1, xzr, xzr
-// CHECK-ENCODING: encoding: [0x3f,0x87,0x48,0xd5]
-// CHECK-DIS: sysp #0, c8, c7, #1
diff --git a/llvm/test/MC/AArch64/armv9a-sysp.s b/llvm/test/MC/AArch64/armv9a-sysp.s
index f1e039f3e8770..9ed1027ad88c1 100644
--- a/llvm/test/MC/AArch64/armv9a-sysp.s
+++ b/llvm/test/MC/AArch64/armv9a-sysp.s
@@ -45,6 +45,14 @@ sysp #4, c2, c1, #0, x0, x1// VTTBR_EL2     3  4  2  1  0
 // CHECK-INST: sysp #4, c2, c1, #0, x0, x1
 // CHECK-ENCODING: encoding: [0x00,0x21,0x4c,0xd5]
 
+sysp #0, c8, c2, #2, x8, x9
+// CHECK-INST: sysp #0, c8, c2, #2, x8, x9
+// CHECK-ENCODING: encoding: [0x48,0x82,0x48,0xd5]
+
+sysp #0, c8, c2, #2, xzr, xzr
+// CHECK-INST: sysp #0, c8, c2, #2
+// CHECK-ENCODING: encoding: [0x5f,0x82,0x48,0xd5]
+
 sysp #0, c2, c0, #0, x0, x1
 // CHECK-INST: sysp #0, c2, c0, #0, x0, x1
 // CHECK-ENCODING: encoding: [0x00,0x20,0x48,0xd5]
diff --git a/llvm/test/MC/AArch64/armv9a-tlbip.s b/llvm/test/MC/AArch64/armv9a-tlbip.s
index 8764a83809472..9e3937726989a 100644
--- a/llvm/test/MC/AArch64/armv9a-tlbip.s
+++ b/llvm/test/MC/AArch64/armv9a-tlbip.s
@@ -55,6 +55,13 @@ tlbip VAE1, x8, x9
 // CHECK-TLBID: error: instruction requires: d128
 // CHECK-UNKNOWN: d5488728 sysp #0, c8, c7, #1, x8, x9
 
+tlbip VAE1, xzr, xzr
+// CHECK-INST: tlbip vae1, xzr, xzr
+// CHECK-ENCODING: encoding: [0x3f,0x87,0x48,0xd5]
+// CHECK-ERROR: error: instruction requires: d128
+// CHECK-TLBID: error: instruction requires: d128
+// CHECK-UNKNOWN: d548873f sysp #0, c8, c7, #1
+
 tlbip VAE1NXS, x8, x9
 // CHECK-INST: tlbip vae1nxs, x8, x9
 // CHECK-ENCODING: encoding: [0x28,0x97,0x48,0xd5]

>From ab3cc369e4129565a0a3a410b51c0c3a2b389a30 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Tue, 14 Apr 2026 14:08:16 +0100
Subject: [PATCH 7/7] fixup! SYSL only has dest register

---
 .../lib/Target/AArch64/AArch64InstrFormats.td | 18 ++++++------
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   | 13 +++++----
 .../MCTargetDesc/AArch64InstPrinter.cpp       | 29 +++++--------------
 3 files changed, 23 insertions(+), 37 deletions(-)

diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index f1c9300024373..fb483f88931aa 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -2157,20 +2157,20 @@ class BaseSystemLXtI<bit L, dag oops, dag iops, string asm>
 }
 
 class SystemLXtI<bit L, string asm>
-  : BaseSystemLXtI<L, (outs),
-       (ins GPR64:$Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
-            imm0_7:$op2), asm>;
-
-// Codegen-only GCS SYSL operations need a tied def/use on Rt because they
-// preserve the old destination value when GCS is disabled at runtime.
-class GCSTiedSystemLXtI<bit L, string asm>
   : BaseSystemLXtI<L, (outs GPR64:$Rt),
+       (ins imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm, imm0_7:$op2), asm>;
+
+// Codegen-only GCS SYSL operations preserve the incoming Rt value when GCS is
+// disabled at runtime, so keep a tied def/use pseudo until asm emission.
+class GCSTiedSystemLXtPseudo
+  : Pseudo<(outs GPR64:$Rt),
        (ins GPR64:$_Rt, imm0_7:$op1, sys_cr_op:$Cn, sys_cr_op:$Cm,
-            imm0_7:$op2), asm> {
+            imm0_7:$op2), [], "$Rt = $_Rt">,
+    Sched<[WriteSys]> {
   let mayLoad = 1;
   let mayStore = 1;
   let hasSideEffects = 1;
-  let Constraints = "$Rt = $_Rt";
+  let Size = 4;
 }
 
 def RangePrefetchOperand : AsmOperandClass {
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 2f1562afa9b41..826ac70f47375 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -2503,9 +2503,10 @@ def MSR_FPMR : Pseudo<(outs), (ins GPR64:$val),
 // Generic system instructions
 def SYSxt  : SystemXtI<"sys">;
 def SYSLxt : SystemLXtI<1, "sysl">;
-def SYSLxt_GCS : GCSTiedSystemLXtI<1, "sysl"> {
-  let isCodeGenOnly = 1;
-}
+def SYSLxt_GCS : GCSTiedSystemLXtPseudo,
+                 PseudoInstExpansion<(SYSLxt GPR64:$Rt, imm0_7:$op1,
+                                            sys_cr_op:$Cn, sys_cr_op:$Cm,
+                                            imm0_7:$op2)>;
 
 def : InstAlias<"sys $op1, $Cn, $Cm, $op2",
                 (SYSxt timm32_0_7:$op1, sys_cr_op:$Cn,
@@ -2529,11 +2530,11 @@ def : InstAlias<"gcspushm $Rt",
 def : InstAlias<"gcsss1 $Rt",
                 (SYSxt 3, 7, 7, 2, GPR64:$Rt)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspopm",
-                (SYSLxt_GCS XZR, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+                (SYSLxt XZR, 3, 7, 7, 1)>, Requires<[HasGCS]>;
 def : InstAlias<"gcspopm $Rt",
-                (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 1)>, Requires<[HasGCS]>;
+                (SYSLxt GPR64:$Rt, 3, 7, 7, 1)>, Requires<[HasGCS]>;
 def : InstAlias<"gcsss2 $Rt",
-                (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 3)>, Requires<[HasGCS]>;
+                (SYSLxt GPR64:$Rt, 3, 7, 7, 3)>, Requires<[HasGCS]>;
 let Predicates = [HasGCS] in
 def : Pat<(int_aarch64_gcspopm GPR64:$Rt),
           (SYSLxt_GCS GPR64:$Rt, 3, 7, 7, 1)>;
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index d513d47ebd52f..3006c757901a7 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -84,7 +84,7 @@ void AArch64InstPrinter::printInst(const MCInst *MI, uint64_t Address,
       return;
     }
 
-  if (Opcode == AArch64::SYSLxt || Opcode == AArch64::SYSLxt_GCS)
+  if (Opcode == AArch64::SYSLxt)
     if (printSyslAlias(MI, STI, O)) {
       printAnnotation(O, Annot);
       return;
@@ -926,14 +926,6 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
     default: return false;
     // MLBI aliases
     case 0: {
-      if (Op1Val == 6 && Op2Val == 0) {
-        NeedsReg = true;
-        Ins = "apas";
-        Name = "";
-        RegSep = "\t";
-        break;
-      }
-
       const AArch64MLBI::MLBI *MLBI =
           AArch64MLBI::lookupMLBIByEncoding(Encoding);
       if (!MLBI || !MLBI->haveFeatures(STI.getFeatureBits()))
@@ -979,11 +971,7 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI,
                              STI.hasFeature(AArch64::FeatureITE)))
           return false;
 
-        NeedsReg = true;
-        Ins = "trcit";
-        Name = "";
-        RegSep = "\t";
-        break;
+        return false;
       }
     } break;
     // Prediction Restriction aliases
@@ -1176,17 +1164,14 @@ bool AArch64InstPrinter::printSyslAlias(const MCInst *MI,
                                         raw_ostream &O) {
   unsigned Opcode = MI->getOpcode();
 #ifndef NDEBUG
-  assert((Opcode == AArch64::SYSLxt || Opcode == AArch64::SYSLxt_GCS) &&
-         "Invalid opcode for SYSL alias!");
+  assert(Opcode == AArch64::SYSLxt && "Invalid opcode for SYSL alias!");
 #endif
 
-  unsigned OpOffset = Opcode == AArch64::SYSLxt_GCS ? 1 : 0;
-
   StringRef Reg = getRegisterName(MI->getOperand(0).getReg());
-  const MCOperand &Op1 = MI->getOperand(OpOffset + 1);
-  const MCOperand &Cn = MI->getOperand(OpOffset + 2);
-  const MCOperand &Cm = MI->getOperand(OpOffset + 3);
-  const MCOperand &Op2 = MI->getOperand(OpOffset + 4);
+  const MCOperand &Op1 = MI->getOperand(1);
+  const MCOperand &Cn = MI->getOperand(2);
+  const MCOperand &Cm = MI->getOperand(3);
+  const MCOperand &Op2 = MI->getOperand(4);
 
   unsigned Op1Val = Op1.getImm();
   unsigned CnVal = Cn.getImm();



More information about the llvm-commits mailing list