[llvm] cb7fb73 - [AArch64] Assembly Support for FEAT_GCS/FEAT_CHK

Archibald Elliott via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 15 04:04:14 PDT 2023


Author: Archibald Elliott
Date: 2023-03-15T11:03:53Z
New Revision: cb7fb737858cdfdc90406f9675c8470ea98417ed

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

LOG: [AArch64] Assembly Support for FEAT_GCS/FEAT_CHK

This implements support for two new 2022 A-profile extensions:
- FEAT_CHK - Check Feature Status Extension
- FEAT_GCS - Guarded Control Stacks

FEAT_CHK is mandatory from armv8.0-a, but is in the hint space so
there's no clang command-line flag for it, and we only print the hint as
`chkfeat x16` at v8.9a and above, to be compatible when using a
non-integrated assembler that might not yet know about the extension.

FEAT_GCS is optional from armv9.4-a onwards. It is enabled using `+gcs`
in a clang `-march=` or `-mcpu=` option string, or using a
`.arch_extension gcs` assembly directive.

This patch includes changes by Ties Stuij, Tomas Matheson, and Keith
Walker.

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

Added: 
    llvm/test/MC/AArch64/armv9.4a-chk.s
    llvm/test/MC/AArch64/armv9.4a-gcs.s
    llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt
    llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt

Modified: 
    clang/lib/Basic/Targets/AArch64.cpp
    clang/lib/Basic/Targets/AArch64.h
    llvm/include/llvm/TargetParser/AArch64TargetParser.h
    llvm/lib/Target/AArch64/AArch64.td
    llvm/lib/Target/AArch64/AArch64InstrInfo.td
    llvm/lib/Target/AArch64/AArch64SystemOperands.td
    llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
    llvm/test/MC/AArch64/directive-arch_extension-negative.s
    llvm/test/MC/AArch64/directive-arch_extension.s
    llvm/unittests/TargetParser/TargetParserTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index b274dd2672268..1711e16b46cdc 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -927,6 +927,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
       HasMOPS = true;
     if (Feature == "+d128")
       HasD128 = true;
+    if (Feature == "+gcs")
+      HasGCS = true;
   }
 
   // Check features that are manually disabled by command line options.

diff  --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h
index f6e12176a77ec..c973efc21bde2 100644
--- a/clang/lib/Basic/Targets/AArch64.h
+++ b/clang/lib/Basic/Targets/AArch64.h
@@ -81,6 +81,7 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
   bool HasNoNeon = false;
   bool HasNoSVE = false;
   bool HasFMV = true;
+  bool HasGCS = false;
 
   const llvm::AArch64::ArchInfo *ArchInfo = &llvm::AArch64::ARMV8A;
 

diff  --git a/llvm/include/llvm/TargetParser/AArch64TargetParser.h b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
index 133d10c11e57b..9cba6b4b19599 100644
--- a/llvm/include/llvm/TargetParser/AArch64TargetParser.h
+++ b/llvm/include/llvm/TargetParser/AArch64TargetParser.h
@@ -153,6 +153,7 @@ enum ArchExtKind : uint64_t {
   AEK_SPECRES2 =    1ULL << 53, // FEAT_SPECRES2
   AEK_RASv2 =       1ULL << 54, // FEAT_RASv2
   AEK_ITE =         1ULL << 55, // FEAT_ITE
+  AEK_GCS =         1ULL << 56, // FEAT_GCS
 };
 // clang-format on
 
@@ -256,6 +257,7 @@ inline constexpr ExtensionInfo Extensions[] = {
     {"the", AArch64::AEK_THE, "+the", "-the", FEAT_MAX, "", 0},
     {"tme", AArch64::AEK_TME, "+tme", "-tme", FEAT_MAX, "", 0},
     {"wfxt", AArch64::AEK_NONE, {}, {}, FEAT_WFXT, "+wfxt", 550},
+    {"gcs", AArch64::AEK_GCS, "+gcs", "-gcs", FEAT_MAX, "", 0},
     // Special cases
     {"none", AArch64::AEK_NONE, {}, {}, FEAT_MAX, "", ExtensionInfo::MaxFMVPriority},
 };

diff  --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td
index e113a21d74b93..67b5cf10b14dd 100644
--- a/llvm/lib/Target/AArch64/AArch64.td
+++ b/llvm/lib/Target/AArch64/AArch64.td
@@ -522,6 +522,12 @@ def FeatureNoBTIAtReturnTwice : SubtargetFeature<"no-bti-at-return-twice",
                                                  "Don't place a BTI instruction "
                                                  "after a return-twice">;
 
+def FeatureCHK : SubtargetFeature<"chk", "HasCHK",
+    "true", "Enable Armv8.0-A Check Feature Status Extension (FEAT_CHK)">;
+
+def FeatureGCS : SubtargetFeature<"gcs", "HasGCS",
+    "true", "Enable Armv9.4-A Guarded Call Stack Extension", [FeatureCHK]>;
+
 def FeatureCLRBHB : SubtargetFeature<"clrbhb", "HasCLRBHB",
     "true", "Enable Clear BHB instruction (FEAT_CLRBHB)">;
 
@@ -603,7 +609,7 @@ def HasV8_8aOps : SubtargetFeature<
 def HasV8_9aOps : SubtargetFeature<
   "v8.9a", "HasV8_9aOps", "true", "Support ARM v8.9a instructions",
   [HasV8_8aOps, FeatureCLRBHB, FeaturePRFM_SLC, FeatureSPECRES2,
-   FeatureCSSC, FeatureRASv2]>;
+   FeatureCSSC, FeatureRASv2, FeatureCHK]>;
 
 def HasV9_0aOps : SubtargetFeature<
   "v9a", "HasV9_0aOps", "true", "Support ARM v9a instructions",

diff  --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f31def209dac6..c889bb72e6cb2 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -244,6 +244,10 @@ def HasLSE128        : Predicate<"Subtarget->hasLSE128()">,
                        AssemblerPredicateWithAll<(all_of FeatureLSE128), "lse128">;
 def HasD128          : Predicate<"Subtarget->hasD128()">,
                        AssemblerPredicateWithAll<(all_of FeatureD128), "d128">;
+def HasCHK           : Predicate<"Subtarget->hasCHK()">,
+                       AssemblerPredicateWithAll<(all_of FeatureCHK), "chk">;
+def HasGCS           : Predicate<"Subtarget->hasGCS()">,
+                       AssemblerPredicateWithAll<(all_of FeatureGCS), "gcs">;
 def IsLE             : Predicate<"Subtarget->isLittleEndian()">;
 def IsBE             : Predicate<"!Subtarget->isLittleEndian()">;
 def IsWindows        : Predicate<"Subtarget->isTargetWindows()">;
@@ -1050,6 +1054,71 @@ def BRB_INJ:  BRBEI<0b101, "\tinj">;
 def : TokenAlias<"INJ", "inj">;
 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> {
+  let Inst{20-19} = 0b01;
+  let Inst{18-16} = op1;
+  let Inst{15-8} = 0b01110111;
+  let Inst{7-5} = op2;
+  let Predicates = [HasGCS];
+}
+
+def GCSSS1   : GCSRtIn<0b011, 0b010, "gcsss1">;
+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), 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];
+}
+
+def GCSSS2  : GCSRtOut<0b011, 0b011, "gcsss2">;
+def GCSPOPM : GCSRtOut<0b011, 0b001, "gcspopm">;
+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]>;
+
+def : TokenAlias<"DSYNC", "dsync">;
+
+let Uses = [X16], Defs = [X16], CRm = 0b0101 in {
+  def CHKFEAT   : SystemNoOperands<0b000, "hint\t#40">;
+}
+def : InstAlias<"chkfeat\tx16", (CHKFEAT), 0>;
+def : InstAlias<"chkfeat\tx16", (CHKFEAT), 1>, Requires<[HasCHK]>;
+
+class GCSSt<string mnemonic, bits<3> op>
+    : I<(outs), (ins GPR64:$Rt, GPR64sp:$Rn), mnemonic, "\t$Rt, $Rn", "", []>, Sched<[]> {
+  bits<5> Rt;
+  bits<5> Rn;
+  let Inst{31-15} = 0b11011001000111110;
+  let Inst{14-12} = op;
+  let Inst{11-10} = 0b11;
+  let Inst{9-5} = Rn;
+  let Inst{4-0} = Rt;
+  let Predicates = [HasGCS];
+}
+def GCSSTR  : GCSSt<"gcsstr",  0b000>;
+def GCSSTTR : GCSSt<"gcssttr", 0b001>;
+
+
 // ARMv8.2-A Dot Product
 let Predicates = [HasDotProd] in {
 defm SDOT : SIMDThreeSameVectorDot<0, 0, "sdot", AArch64sdot>;

diff  --git a/llvm/lib/Target/AArch64/AArch64SystemOperands.td b/llvm/lib/Target/AArch64/AArch64SystemOperands.td
index c7f404463c587..cbe02f4e15b9a 100644
--- a/llvm/lib/Target/AArch64/AArch64SystemOperands.td
+++ b/llvm/lib/Target/AArch64/AArch64SystemOperands.td
@@ -1761,6 +1761,19 @@ let Requires = [{ {AArch64::FeatureNMI} }] in {
   def : ROSysReg<"ICC_NMIAR1_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b101>; // FEAT_GICv3_NMI
 }
 
+// v9.4a Guarded Control Stack Extension (GCS)
+//                            Op0   Op1    CRn     CRm     Op2
+def : RWSysReg<"GCSCR_EL1",   0b11, 0b000, 0b0010, 0b0101, 0b000>;
+def : RWSysReg<"GCSPR_EL1",   0b11, 0b000, 0b0010, 0b0101, 0b001>;
+def : RWSysReg<"GCSCRE0_EL1", 0b11, 0b000, 0b0010, 0b0101, 0b010>;
+def : RWSysReg<"GCSPR_EL0",   0b11, 0b011, 0b0010, 0b0101, 0b001>;
+def : RWSysReg<"GCSCR_EL2",   0b11, 0b100, 0b0010, 0b0101, 0b000>;
+def : RWSysReg<"GCSPR_EL2",   0b11, 0b100, 0b0010, 0b0101, 0b001>;
+def : RWSysReg<"GCSCR_EL12",  0b11, 0b101, 0b0010, 0b0101, 0b000>;
+def : RWSysReg<"GCSPR_EL12",  0b11, 0b101, 0b0010, 0b0101, 0b001>;
+def : RWSysReg<"GCSCR_EL3",   0b11, 0b110, 0b0010, 0b0101, 0b000>;
+def : RWSysReg<"GCSPR_EL3",   0b11, 0b110, 0b0010, 0b0101, 0b001>;
+
 // v8.9a/v9.4a Memory Attribute Index Enhancement (FEAT_AIE)
 //                            Op0   Op1    CRn     CRm     Op2
 def : RWSysReg<"AMAIR2_EL1",  0b11, 0b000, 0b1010, 0b0011, 0b001>;

diff  --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
index 4f2833c1c4230..d5162d39ce43c 100644
--- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
+++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp
@@ -3677,6 +3677,7 @@ static const struct Extension {
     {"ite", {AArch64::FeatureITE}},
     {"cssc", {AArch64::FeatureCSSC}},
     {"rcpc3", {AArch64::FeatureRCPC3}},
+    {"gcs", {AArch64::FeatureGCS}},
     // FIXME: Unsupported extensions
     {"lor", {}},
     {"rdma", {}},
@@ -4841,11 +4842,6 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
     if (!parseOptionalMulOperand(Operands))
       return false;
 
-    // If this is an "smstart" or "smstop" instruction, parse its special
-    // keyword operand as an identifier.
-    if (Mnemonic == "smstart" || Mnemonic == "smstop")
-      return parseKeywordOperand(Operands);
-
     // This could be an optional "shift" or "extend" operand.
     OperandMatchResultTy GotShift = tryParseOptionalShiftExtend(Operands);
     // We can only continue if no tokens were eaten.
@@ -4854,7 +4850,8 @@ bool AArch64AsmParser::parseOperand(OperandVector &Operands, bool isCondCode,
 
     // If this is a two-word mnemonic, parse its special keyword
     // operand as an identifier.
-    if (Mnemonic == "brb")
+    if (Mnemonic == "brb" || Mnemonic == "smstart" || Mnemonic == "smstop" ||
+        Mnemonic == "gcsb")
       return parseKeywordOperand(Operands);
 
     // This was not a register so parse other operands that start with an
@@ -7621,61 +7618,21 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAArch64AsmParser() {
 unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
                                                       unsigned Kind) {
   AArch64Operand &Op = static_cast<AArch64Operand &>(AsmOp);
-  // If the kind is a token for a literal immediate, check if our asm
-  // operand matches. This is for InstAliases which have a fixed-value
-  // immediate in the syntax.
-  int64_t ExpectedVal;
+
+  auto MatchesOpImmediate = [&](int64_t ExpectedVal) -> MatchResultTy {
+    if (!Op.isImm())
+      return Match_InvalidOperand;
+    const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
+    if (!CE)
+      return Match_InvalidOperand;
+    if (CE->getValue() == ExpectedVal)
+      return Match_Success;
+    return Match_InvalidOperand;
+  };
+
   switch (Kind) {
   default:
     return Match_InvalidOperand;
-  case MCK__HASH_0:
-    ExpectedVal = 0;
-    break;
-  case MCK__HASH_1:
-    ExpectedVal = 1;
-    break;
-  case MCK__HASH_12:
-    ExpectedVal = 12;
-    break;
-  case MCK__HASH_16:
-    ExpectedVal = 16;
-    break;
-  case MCK__HASH_2:
-    ExpectedVal = 2;
-    break;
-  case MCK__HASH_24:
-    ExpectedVal = 24;
-    break;
-  case MCK__HASH_3:
-    ExpectedVal = 3;
-    break;
-  case MCK__HASH_32:
-    ExpectedVal = 32;
-    break;
-  case MCK__HASH_4:
-    ExpectedVal = 4;
-    break;
-  case MCK__HASH_48:
-    ExpectedVal = 48;
-    break;
-  case MCK__HASH_6:
-    ExpectedVal = 6;
-    break;
-  case MCK__HASH_64:
-    ExpectedVal = 64;
-    break;
-  case MCK__HASH_8:
-    ExpectedVal = 8;
-    break;
-  case MCK__HASH__MINUS_4:
-    ExpectedVal = -4;
-    break;
-  case MCK__HASH__MINUS_8:
-    ExpectedVal = -8;
-    break;
-  case MCK__HASH__MINUS_16:
-    ExpectedVal = -16;
-    break;
   case MCK_MPR:
     // If the Kind is a token for the MPR register class which has the "za"
     // register (SME accumulator array), check if the asm is a literal "za"
@@ -7684,15 +7641,36 @@ unsigned AArch64AsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
     if (Op.isTokenEqual("za"))
       return Match_Success;
     return Match_InvalidOperand;
+
+    // If the kind is a token for a literal immediate, check if our asm
+    // operand matches. This is for InstAliases which have a fixed-value
+    // immediate in the syntax.
+#define MATCH_HASH(N)                                                          \
+  case MCK__HASH_##N:                                                          \
+    return MatchesOpImmediate(N);
+    MATCH_HASH(0)
+    MATCH_HASH(1)
+    MATCH_HASH(2)
+    MATCH_HASH(3)
+    MATCH_HASH(4)
+    MATCH_HASH(6)
+    MATCH_HASH(8)
+    MATCH_HASH(12)
+    MATCH_HASH(16)
+    MATCH_HASH(24)
+    MATCH_HASH(32)
+    MATCH_HASH(40)
+    MATCH_HASH(48)
+    MATCH_HASH(64)
+#undef MATCH_HASH
+#define MATCH_HASH_MINUS(N)                                                    \
+  case MCK__HASH__MINUS_##N:                                                   \
+    return MatchesOpImmediate(-N);
+    MATCH_HASH_MINUS(4)
+    MATCH_HASH_MINUS(8)
+    MATCH_HASH_MINUS(16)
+#undef MATCH_HASH_MINUS
   }
-  if (!Op.isImm())
-    return Match_InvalidOperand;
-  const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Op.getImm());
-  if (!CE)
-    return Match_InvalidOperand;
-  if (CE->getValue() == ExpectedVal)
-    return Match_Success;
-  return Match_InvalidOperand;
 }
 
 OperandMatchResultTy

diff  --git a/llvm/test/MC/AArch64/armv9.4a-chk.s b/llvm/test/MC/AArch64/armv9.4a-chk.s
new file mode 100644
index 0000000000000..95acee370dcb1
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.4a-chk.s
@@ -0,0 +1,21 @@
+// RUN: llvm-mc -triple aarch64 -mattr=+chk -show-encoding %s | FileCheck %s
+// RUN: llvm-mc -triple aarch64 -mattr=+v8.9a -show-encoding %s | FileCheck %s
+// RUN: llvm-mc -triple aarch64 -mattr=+v9.4a -show-encoding %s | FileCheck %s
+// RUN: llvm-mc -triple aarch64 -mattr=+v8a -show-encoding %s | FileCheck %s --check-prefix=NO-CHK
+
+// FEAT_CHK is mandatory from v8.0-a, but a clang user may not be using the LLVM
+// integrated assembler, so we cannot just print `chkfeat x16` in all
+// circumstances. Thankfully, we can always print `hint #40` when we cannot
+// print `chkfeat x16`.
+//
+// So, in this case, we only print `chkfeat x16` from v8.9-a onwards, as an
+// assembler that understands v8.9-a will understand `chkfeat x16`, and those
+// that understand previous versions may not.
+
+chkfeat x16
+// CHECK: chkfeat x16                       // encoding: [0x1f,0x25,0x03,0xd5]
+// NO-CHK: hint #40                              // encoding: [0x1f,0x25,0x03,0xd5]
+
+hint #40
+// CHECK: chkfeat x16                      // encoding: [0x1f,0x25,0x03,0xd5]
+// NO-CHK: hint #40                             // encoding: [0x1f,0x25,0x03,0xd5]

diff  --git a/llvm/test/MC/AArch64/armv9.4a-gcs.s b/llvm/test/MC/AArch64/armv9.4a-gcs.s
new file mode 100644
index 0000000000000..8910229b8dace
--- /dev/null
+++ b/llvm/test/MC/AArch64/armv9.4a-gcs.s
@@ -0,0 +1,115 @@
+// RUN: llvm-mc -triple aarch64 -mattr +gcs -show-encoding %s | FileCheck %s
+// RUN: not llvm-mc -triple aarch64 -show-encoding %s 2>%t | FileCheck %s --check-prefix=NO-GCS
+// RUN: FileCheck --check-prefix=ERROR-NO-GCS %s < %t
+
+msr GCSCR_EL1, x0
+mrs x1, GCSCR_EL1
+// CHECK: msr     GCSCR_EL1, x0                   // encoding: [0x00,0x25,0x18,0xd5]
+// CHECK: mrs     x1, GCSCR_EL1                   // encoding: [0x01,0x25,0x38,0xd5]
+
+msr GCSPR_EL1, x2
+mrs x3, GCSPR_EL1
+// CHECK: msr     GCSPR_EL1, x2                   // encoding: [0x22,0x25,0x18,0xd5]
+// CHECK: mrs     x3, GCSPR_EL1                   // encoding: [0x23,0x25,0x38,0xd5]
+
+msr GCSCRE0_EL1, x4
+mrs x5, GCSCRE0_EL1
+// CHECK: msr     GCSCRE0_EL1, x4                 // encoding: [0x44,0x25,0x18,0xd5]
+// CHECK: mrs     x5, GCSCRE0_EL1                 // encoding: [0x45,0x25,0x38,0xd5]
+
+msr GCSPR_EL0, x6
+mrs x7, GCSPR_EL0
+// CHECK: msr     GCSPR_EL0, x6                   // encoding: [0x26,0x25,0x1b,0xd5]
+// CHECK: mrs     x7, GCSPR_EL0                   // encoding: [0x27,0x25,0x3b,0xd5]
+
+msr GCSCR_EL2, x10
+mrs x11, GCSCR_EL2
+// CHECK: msr     GCSCR_EL2, x10                  // encoding: [0x0a,0x25,0x1c,0xd5]
+// CHECK: mrs     x11, GCSCR_EL2                  // encoding: [0x0b,0x25,0x3c,0xd5]
+
+msr GCSPR_EL2, x12
+mrs x13, GCSPR_EL2
+// CHECK: msr     GCSPR_EL2, x12                  // encoding: [0x2c,0x25,0x1c,0xd5]
+// CHECK: mrs     x13, GCSPR_EL2                  // encoding: [0x2d,0x25,0x3c,0xd5]
+
+msr GCSCR_EL12, x14
+mrs x15, GCSCR_EL12
+// CHECK: msr     GCSCR_EL12, x14                 // encoding: [0x0e,0x25,0x1d,0xd5]
+// CHECK: mrs     x15, GCSCR_EL12                 // encoding: [0x0f,0x25,0x3d,0xd5]
+
+msr GCSPR_EL12, x16
+mrs x17, GCSPR_EL12
+// CHECK: msr     GCSPR_EL12, x16                 // encoding: [0x30,0x25,0x1d,0xd5]
+// CHECK: mrs     x17, GCSPR_EL12                 // encoding: [0x31,0x25,0x3d,0xd5]
+
+msr GCSCR_EL3, x18
+mrs x19, GCSCR_EL3
+// CHECK: msr     GCSCR_EL3, x18                  // encoding: [0x12,0x25,0x1e,0xd5]
+// CHECK: mrs     x19, GCSCR_EL3                  // encoding: [0x13,0x25,0x3e,0xd5]
+
+msr GCSPR_EL3, x20
+mrs x21, GCSPR_EL3
+// CHECK: msr     GCSPR_EL3, x20                  // encoding: [0x34,0x25,0x1e,0xd5]
+// CHECK: mrs     x21, GCSPR_EL3                  // encoding: [0x35,0x25,0x3e,0xd5]
+
+gcsss1 x21
+// CHECK: gcsss1  x21                        // encoding: [0x55,0x77,0x0b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcsss2 x22
+// CHECK: gcsss2  x22                        // encoding: [0x76,0x77,0x2b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspushm x25
+// CHECK: gcspushm x25                       // encoding: [0x19,0x77,0x0b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspopm
+// CHECK: gcspopm                             // encoding: [0x3f,0x77,0x2b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspopm xzr
+// CHECK: gcspopm                            // encoding: [0x3f,0x77,0x2b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspopm x25
+// CHECK: gcspopm  x25                        // encoding: [0x39,0x77,0x2b,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcsb dsync
+// CHECK: gcsb    dsync                           // encoding: [0x7f,0x22,0x03,0xd5]
+// ERROR-NO-GCS-NOT: [[@LINE-2]]:1: error: instruction requires: gcs
+// NO-GCS: hint #19                              // encoding: [0x7f,0x22,0x03,0xd5]
+
+hint #19
+// CHECK: gcsb    dsync                           // encoding: [0x7f,0x22,0x03,0xd5]
+// ERROR-NO-GCS-NOT: [[@LINE-2]]:1: error: instruction requires: gcs
+// NO-GCS: hint #19                              // encoding: [0x7f,0x22,0x03,0xd5]
+
+gcsstr x26, x27
+// CHECK: gcsstr x26, x27                          // encoding: [0x7a,0x0f,0x1f,0xd9]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcsstr x26, sp
+// CHECK: gcsstr x26, sp                           // encoding: [0xfa,0x0f,0x1f,0xd9]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcssttr x26, x27
+// CHECK: gcssttr x26, x27                         // encoding: [0x7a,0x1f,0x1f,0xd9]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcssttr x26, sp
+// CHECK: gcssttr x26, sp                          // encoding: [0xfa,0x1f,0x1f,0xd9]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspushx
+// CHECK: gcspushx                          // encoding: [0x9f,0x77,0x08,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspopcx
+// CHECK: gcspopcx                          // encoding: [0xbf,0x77,0x08,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs
+
+gcspopx
+// CHECK: gcspopx                           // encoding: [0xdf,0x77,0x08,0xd5]
+// ERROR-NO-GCS: [[@LINE-2]]:1: error: instruction requires: gcs

diff  --git a/llvm/test/MC/AArch64/directive-arch_extension-negative.s b/llvm/test/MC/AArch64/directive-arch_extension-negative.s
index b6686998d2ea0..1c1cfc9d33e3e 100644
--- a/llvm/test/MC/AArch64/directive-arch_extension-negative.s
+++ b/llvm/test/MC/AArch64/directive-arch_extension-negative.s
@@ -1,6 +1,6 @@
 // RUN: not llvm-mc -triple aarch64 \
 // RUN: -mattr=+crc,+sm4,+sha3,+sha2,+aes,+fp,+neon,+ras,+lse,+predres,+ccdp,+mte,+tlb-rmi,+pan-rwv,+ccpp,+rcpc,+ls64,+flagm,+hbc,+mops \
-// RUN: -mattr=+rcpc3,+lse128,+d128,+the,+rasv2,+ite,+cssc,+specres2 \
+// RUN: -mattr=+rcpc3,+lse128,+d128,+the,+rasv2,+ite,+cssc,+specres2,+gcs \
 // RUN: -filetype asm -o - %s 2>&1 | FileCheck %s
 
 .arch_extension axp64
@@ -210,3 +210,10 @@ mrs x0, ERXGSR_EL1
 mrs x0, ERXGSR_EL1
 // CHECK: [[@LINE-1]]:9: error: expected readable system register
 // CHECK-NEXT: mrs x0, ERXGSR_EL1
+
+gcspushm x0
+// CHECK-NOT: [[@LINE-1]]:1: error: instruction requires: gcs
+.arch_extension nogcs
+gcspushm x0
+// CHECK: [[@LINE-1]]:1: error: instruction requires: gcs
+// CHECK-NEXT: gcspushm x0

diff  --git a/llvm/test/MC/AArch64/directive-arch_extension.s b/llvm/test/MC/AArch64/directive-arch_extension.s
index 03ca1fe87988b..b5bbee7910561 100644
--- a/llvm/test/MC/AArch64/directive-arch_extension.s
+++ b/llvm/test/MC/AArch64/directive-arch_extension.s
@@ -128,3 +128,7 @@ trcit x0
 .arch_extension cssc
 umax x0, x1, x2
 // CHECK: umax x0, x1, x2
+
+.arch_extension gcs
+gcspushm x0
+// CHECK: gcspushm x0

diff  --git a/llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt b/llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt
new file mode 100644
index 0000000000000..730f4440402e1
--- /dev/null
+++ b/llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt
@@ -0,0 +1,8 @@
+# RUN: llvm-mc -triple=aarch64 -mattr=+v8.9a -disassemble %s 2> %t | FileCheck %s
+# RUN: llvm-mc -triple=aarch64 -mattr=+v9.4a -disassemble %s 2> %t | FileCheck %s
+# RUN: llvm-mc -triple=aarch64 -mattr=+chk   -disassemble %s 2> %t | FileCheck %s
+# RUN: llvm-mc -triple=aarch64 -mattr=+v8a   -disassemble %s 2> %t | FileCheck %s --check-prefix=NO-CHK
+
+[0x1f,0x25,0x03,0xd5]
+// CHECK: chkfeat x16
+// NO-CHK: hint #40

diff  --git a/llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt b/llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt
new file mode 100644
index 0000000000000..7e2802b263858
--- /dev/null
+++ b/llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt
@@ -0,0 +1,90 @@
+# RUN: llvm-mc -triple=aarch64 -mattr +gcs -disassemble %s 2> %t | FileCheck %s
+
+[0x00,0x25,0x18,0xd5]
+[0x01,0x25,0x38,0xd5]
+// CHECK: msr     GCSCR_EL1, x0
+// CHECK: mrs     x1, GCSCR_EL1
+
+[0x22,0x25,0x18,0xd5]
+[0x23,0x25,0x38,0xd5]
+// CHECK: msr     GCSPR_EL1, x2
+// CHECK: mrs     x3, GCSPR_EL1
+
+[0x44,0x25,0x18,0xd5]
+[0x45,0x25,0x38,0xd5]
+// CHECK: msr     GCSCRE0_EL1, x4
+// CHECK: mrs     x5, GCSCRE0_EL1
+
+[0x26,0x25,0x1b,0xd5]
+[0x27,0x25,0x3b,0xd5]
+// CHECK: msr     GCSPR_EL0, x6
+// CHECK: mrs     x7, GCSPR_EL0
+
+[0x0a,0x25,0x1c,0xd5]
+[0x0b,0x25,0x3c,0xd5]
+// CHECK: msr     GCSCR_EL2, x10
+// CHECK: mrs     x11, GCSCR_EL2
+
+[0x2c,0x25,0x1c,0xd5]
+[0x2d,0x25,0x3c,0xd5]
+// CHECK: msr     GCSPR_EL2, x12
+// CHECK: mrs     x13, GCSPR_EL2
+
+[0x0e,0x25,0x1d,0xd5]
+[0x0f,0x25,0x3d,0xd5]
+// CHECK: msr     GCSCR_EL12, x14
+// CHECK: mrs     x15, GCSCR_EL12
+
+[0x30,0x25,0x1d,0xd5]
+[0x31,0x25,0x3d,0xd5]
+// CHECK: msr     GCSPR_EL12, x16
+// CHECK: mrs     x17, GCSPR_EL12
+
+[0x12,0x25,0x1e,0xd5]
+[0x13,0x25,0x3e,0xd5]
+// CHECK: msr     GCSCR_EL3, x18
+// CHECK: mrs     x19, GCSCR_EL3
+
+[0x34,0x25,0x1e,0xd5]
+[0x35,0x25,0x3e,0xd5]
+// CHECK: msr     GCSPR_EL3, x20
+// CHECK: mrs     x21, GCSPR_EL3
+
+[0x55,0x77,0x0b,0xd5]
+// CHECK: gcsss1 x21
+
+[0x76,0x77,0x2b,0xd5]
+// CHECK: gcsss2    x22
+
+[0x19,0x77,0x0b,0xd5]
+// CHECK: gcspushm x25
+
+[0x3f,0x77,0x2b,0xd5]
+// CHECK: gcspopm
+
+[0x39,0x77,0x2b,0xd5]
+// CHECK: gcspopm    x25
+
+[0x7f,0x22,0x03,0xd5]
+// CHECK: gcsb    dsync
+
+[0x7a,0x0f,0x1f,0xd9]
+// CHECK: gcsstr   x26, x27
+
+[0xfa,0x0f,0x1f,0xd9]
+// CHECK: gcsstr   x26, sp
+
+[0x7a,0x1f,0x1f,0xd9]
+// CHECK: gcssttr  x26, x27
+
+[0xfa,0x1f,0x1f,0xd9]
+// CHECK: gcssttr  x26, sp
+
+[0x9f,0x77,0x08,0xd5]
+// CHECK: gcspushx
+
+[0xbf,0x77,0x08,0xd5]
+// CHECK: gcspopcx
+
+[0xdf,0x77,0x08,0xd5]
+// CHECK: gcspopx

diff  --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp
index ef5aa82c169a7..e83f544d0fba5 100644
--- a/llvm/unittests/TargetParser/TargetParserTest.cpp
+++ b/llvm/unittests/TargetParser/TargetParserTest.cpp
@@ -1600,7 +1600,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
       AArch64::AEK_B16B16,  AArch64::AEK_SMEF16F16, AArch64::AEK_CSSC,
       AArch64::AEK_RCPC3,   AArch64::AEK_THE,       AArch64::AEK_D128,
       AArch64::AEK_LSE128,  AArch64::AEK_SPECRES2,  AArch64::AEK_RASv2,
-      AArch64::AEK_ITE,
+      AArch64::AEK_ITE,     AArch64::AEK_GCS,
   };
 
   std::vector<StringRef> Features;
@@ -1671,6 +1671,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) {
   EXPECT_TRUE(llvm::is_contained(Features, "+lse128"));
   EXPECT_TRUE(llvm::is_contained(Features, "+specres2"));
   EXPECT_TRUE(llvm::is_contained(Features, "+ite"));
+  EXPECT_TRUE(llvm::is_contained(Features, "+gcs"));
 
   // Assuming we listed every extension above, this should produce the same
   // result. (note that AEK_NONE doesn't have a name so it won't be in the
@@ -1793,6 +1794,7 @@ TEST(TargetParserTest, AArch64ArchExtFeature) {
       {"pmuv3", "nopmuv3", "+perfmon", "-perfmon"},
       {"predres2", "nopredres2", "+specres2", "-specres2"},
       {"rasv2", "norasv2", "+rasv2", "-rasv2"},
+      {"gcs", "nogcs", "+gcs", "-gcs"},
   };
 
   for (unsigned i = 0; i < std::size(ArchExt); i++) {


        


More information about the llvm-commits mailing list