[llvm] [AArch64][llvm] Allow some `tlbip` insns to be used with only +tlbid (PR #177995)

Jonathan Thackray via llvm-commits llvm-commits at lists.llvm.org
Mon Jan 26 09:00:37 PST 2026


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

>From 190c45ed153f5a1a351d7c5abaa41a6481301838 Mon Sep 17 00:00:00 2001
From: Jonathan Thackray <jonathan.thackray at arm.com>
Date: Fri, 23 Jan 2026 17:23:39 +0000
Subject: [PATCH] [AArch64][llvm] Allow some `tlbip` insns to be used with only
 +tlbid

Allow `tlbip` instructions containing *E1IS*, *E1OS*, *E2IS* or *E2OS*
to be used with `+tlbid` or `+d128`. This is because the 2025 Armv9.7-A
MemSys specification says:

```
All TLBIP *E1IS*, TLBIP*E1OS*, TLBIP*E2IS* and TLBIP*E2OS* instructions
that are currently dependent on FEAT_D128 are updated to be dependent
on FEAT_D128 or FEAT_TLBID
```
---
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |  5 +-
 .../AArch64/AsmParser/AArch64AsmParser.cpp    | 57 ++++++++++++++++++-
 .../MCTargetDesc/AArch64InstPrinter.cpp       |  2 +-
 .../Target/AArch64/Utils/AArch64BaseInfo.h    | 26 +++++++++
 llvm/test/MC/AArch64/armv9.7a-tlbip-tlbid.s   | 39 +++++++++++++
 .../AArch64/armv9a-tlbip-d128-diagnostics.s   |  5 ++
 6 files changed, 130 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/MC/AArch64/armv9.7a-tlbip-tlbid.s
 create mode 100644 llvm/test/MC/AArch64/armv9a-tlbip-d128-diagnostics.s

diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index 7f43a38f337d0..023961e6c7bcb 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -391,6 +391,9 @@ def HasLSE128        : Predicate<"Subtarget->hasLSE128()">,
                                  AssemblerPredicateWithAll<(all_of FeatureLSE128), "lse128">;
 def HasD128          : Predicate<"Subtarget->hasD128()">,
                                  AssemblerPredicateWithAll<(all_of FeatureD128), "d128">;
+def HasD128OrTLBID   : Predicate<"Subtarget->hasD128() || Subtarget->hasTLBID()">,
+                                 AssemblerPredicateWithAll<(any_of FeatureD128, FeatureTLBID),
+                                                           "d128 or tlbid">;
 def HasCHK           : Predicate<"Subtarget->hasCHK()">,
                                  AssemblerPredicateWithAll<(all_of FeatureCHK), "chk">;
 def HasGCS           : Predicate<"Subtarget->hasGCS()">,
@@ -11184,7 +11187,7 @@ let Predicates = [HasRCPC3, HasNEON] in {
 //===----------------------------------------------------------------------===//
 // 128-bit System Instructions (FEAT_SYSINSTR128)
 //===----------------------------------------------------------------------===//
-let Predicates = [HasD128] in {
+let Predicates = [HasD128OrTLBID] in {
   def SYSPxt  : SystemPXtI<0, "sysp">;
 
   def SYSPxt_XZR
diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 5ef3e2e50ec86..0fce51e7814cb 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -4275,13 +4275,38 @@ bool AArch64AsmParser::parseSyspAlias(StringRef Name, SMLoc NameLoc,
         HasnXSQualifier
             ? TLBIPorig->FeaturesRequired | FeatureBitset({AArch64::FeatureXS})
             : TLBIPorig->FeaturesRequired);
-    if (!TLBIP.haveFeatures(getSTI().getFeatureBits())) {
+
+    if (!haveTLBIPFeatures(TLBIP, getSTI().getFeatureBits())) {
       std::string Name =
           std::string(TLBIP.Name) + (HasnXSQualifier ? "nXS" : "");
       std::string Str("TLBIP " + Name + " requires: ");
-      setRequiredFeatureString(TLBIP.getRequiredFeatures(), Str);
+      FeatureBitset Required = TLBIP.getRequiredFeatures();
+
+      // With FEAT_TLBID, the spec was updated to say:
+      //   "All TLBIP *E1IS*, *E1OS*, *E2IS* and *E2OS* instructions that
+      //    are currently dependent on FEAT_D128 are updated to be dependent
+      //    on FEAT_D128 or FEAT_TLBID."
+      // Hence this logic here to allow either.
+      if (isTLBIP_D128OrTLBID(TLBIP.Name) && Required[AArch64::FeatureD128]) {
+        FeatureBitset RequiredWithoutD128 = Required;
+        RequiredWithoutD128.reset(AArch64::FeatureD128);
+
+        if (RequiredWithoutD128.any()) {
+          setRequiredFeatureString(RequiredWithoutD128, Str);
+          Str += ", ";
+        }
+        Str += "d128 or tlbid";
+      } else {
+        setRequiredFeatureString(Required, Str);
+      }
       return TokError(Str);
     }
+    if (!getSTI().hasFeature(AArch64::FeatureD128) &&
+        !getSTI().hasFeature(AArch64::FeatureTLBID)) {
+      if (isTLBIP_D128OrTLBID(TLBIP.Name))
+        return TokError("instruction requires: d128 or tlbid");
+      return TokError("instruction requires: d128");
+    }
     createSysAlias(TLBIP.Encoding, Operands, S);
   }
 
@@ -5718,6 +5743,34 @@ bool AArch64AsmParser::validateInstruction(MCInst &Inst, SMLoc &IDLoc,
     }
   }
 
+  // Allow +tlbid or +d128 for specific `TLBIP` instructions
+  if ((Inst.getOpcode() == AArch64::SYSPxt ||
+       Inst.getOpcode() == AArch64::SYSPxt_XZR) &&
+      !getSTI().hasFeature(AArch64::FeatureD128)) {
+    if (!getSTI().hasFeature(AArch64::FeatureTLBID))
+      return Error(IDLoc, "instruction requires: d128");
+
+    if (Inst.getNumOperands() < 5 || !Inst.getOperand(0).isImm() ||
+        !Inst.getOperand(1).isImm() || !Inst.getOperand(2).isImm() ||
+        !Inst.getOperand(3).isImm())
+      return Error(IDLoc, "instruction requires: d128");
+
+    // If +tlbid, check first four operands are immediates, build the
+    // system opcode encoding, and look it up in the TLBIP table
+    unsigned Op1Val = Inst.getOperand(0).getImm();
+    unsigned CnVal = Inst.getOperand(1).getImm();
+    unsigned CmVal = Inst.getOperand(2).getImm();
+    unsigned Op2Val = Inst.getOperand(3).getImm();
+    uint16_t Encoding = Op2Val | (CmVal << 3) | (CnVal << 7) | (Op1Val << 11);
+
+    const AArch64TLBIP::TLBIP *TLBIP =
+        AArch64TLBIP::lookupTLBIPByEncoding(Encoding);
+
+    if (!TLBIP || !isTLBIP_D128OrTLBID(TLBIP->Name) ||
+        !haveTLBIPFeatures(*TLBIP, getSTI().getFeatureBits()))
+      return Error(IDLoc, "instruction requires: d128");
+  }
+
   // On ARM64EC, only valid registers may be used. Warn against using
   // explicitly disallowed registers.
   if (IsWindowsArm64EC) {
diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
index 3e4c1101fb8e1..d9c0e93e2e966 100644
--- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
+++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp
@@ -1171,7 +1171,7 @@ bool AArch64InstPrinter::printSyspAlias(const MCInst *MI,
 
     const AArch64TLBIP::TLBIP *TLBIP =
         AArch64TLBIP::lookupTLBIPByEncoding(Encoding);
-    if (!TLBIP || !TLBIP->haveFeatures(STI.getFeatureBits()))
+    if (!TLBIP || !haveTLBIPFeatures(*TLBIP, STI.getFeatureBits()))
       return false;
 
     Ins = "tlbip\t";
diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
index 0c98fdc75cacd..0272038a35909 100644
--- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
+++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h
@@ -829,6 +829,32 @@ struct TLBIP : SysAliasOptionalReg {
 #include "AArch64GenSystemOperands.inc"
 } // namespace AArch64TLBIP
 
+inline bool isTLBIP_D128OrTLBID(StringRef Name) {
+  if (Name.ends_with_insensitive("nxs"))
+    Name = Name.drop_back(3);
+
+  return Name.ends_with("e1is") || Name.ends_with("e1os") ||
+         Name.ends_with("e2is") || Name.ends_with("e2os");
+}
+
+inline bool haveTLBIPFeatures(const AArch64TLBIP::TLBIP &TLBIP,
+                              FeatureBitset ActiveFeatures) {
+  if (ActiveFeatures[AArch64::FeatureAll])
+    return true;
+
+  FeatureBitset Required = TLBIP.FeaturesRequired;
+  if (isTLBIP_D128OrTLBID(TLBIP.Name) && Required[AArch64::FeatureD128]) {
+    Required.reset(AArch64::FeatureD128);
+    if ((Required & ActiveFeatures) != Required)
+      return false;
+
+    return ActiveFeatures[AArch64::FeatureD128] ||
+           ActiveFeatures[AArch64::FeatureTLBID];
+  }
+
+  return (Required & ActiveFeatures) == Required;
+}
+
 namespace AArch64MLBI {
 struct MLBI : SysAliasReg {
   using SysAliasReg::SysAliasReg;
diff --git a/llvm/test/MC/AArch64/armv9.7a-tlbip-tlbid.s b/llvm/test/MC/AArch64/armv9.7a-tlbip-tlbid.s
new file mode 100644
index 0000000000000..c971c26b11ac2
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.7a-tlbip-tlbid.s
@@ -0,0 +1,39 @@
+// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+tlbid,+tlb-rmi,+xs < %s \
+// RUN:        | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST
+// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+tlbid,+tlb-rmi,+xs < %s \
+// RUN:        | llvm-objdump -d --mattr=+tlbid,+tlb-rmi,+xs --no-print-imm-hex - \
+// RUN:        | FileCheck %s --check-prefix=CHECK-INST
+
+// FEAT_TLBID allows TLBIP E1/E2 IS/OS instructions without FEAT_D128.
+
+tlbip VAE1IS, x8, x9
+// CHECK-INST: tlbip vae1is, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x83,0x48,0xd5]
+
+tlbip VAE1ISNXS, x8, x9
+// CHECK-INST: tlbip vae1isnxs, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x93,0x48,0xd5]
+
+tlbip VAE1OS, x8, x9
+// CHECK-INST: tlbip vae1os, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x81,0x48,0xd5]
+
+tlbip VAE1OSNXS, x8, x9
+// CHECK-INST: tlbip vae1osnxs, x8, x9
+// CHECK-ENCODING: encoding: [0x28,0x91,0x48,0xd5]
+
+tlbip VAE2IS, x14, x15
+// CHECK-INST: tlbip vae2is, x14, x15
+// CHECK-ENCODING: encoding: [0x2e,0x83,0x4c,0xd5]
+
+tlbip VAE2ISNXS, x14, x15
+// CHECK-INST: tlbip vae2isnxs, x14, x15
+// CHECK-ENCODING: encoding: [0x2e,0x93,0x4c,0xd5]
+
+tlbip VAE2OS, x14, x15
+// CHECK-INST: tlbip vae2os, x14, x15
+// CHECK-ENCODING: encoding: [0x2e,0x81,0x4c,0xd5]
+
+tlbip VAE2OSNXS, x14, x15
+// CHECK-INST: tlbip vae2osnxs, x14, x15
+// CHECK-ENCODING: encoding: [0x2e,0x91,0x4c,0xd5]
diff --git a/llvm/test/MC/AArch64/armv9a-tlbip-d128-diagnostics.s b/llvm/test/MC/AArch64/armv9a-tlbip-d128-diagnostics.s
new file mode 100644
index 0000000000000..020b33b5d03e4
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9a-tlbip-d128-diagnostics.s
@@ -0,0 +1,5 @@
+// RUN: not llvm-mc -triple=aarch64 -mattr=+tlb-rmi,+tlbid -show-encoding %s -o - 2>&1 \
+// RUN:        | FileCheck %s --check-prefix=ERRORS
+
+tlbip rvale1, x0, x1
+// ERRORS: error: instruction requires: d128



More information about the llvm-commits mailing list