[clang] cb7fb73 - [AArch64] Assembly Support for FEAT_GCS/FEAT_CHK
Archibald Elliott via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 15 04:04:13 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 cfe-commits
mailing list