From cb7fb737858cdfdc90406f9675c8470ea98417ed Mon Sep 17 00:00:00 2001 From: Archibald Elliott Date: Wed, 15 Mar 2023 10:38:11 +0000 Subject: [PATCH] [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 --- clang/lib/Basic/Targets/AArch64.cpp | 2 + clang/lib/Basic/Targets/AArch64.h | 1 + .../llvm/TargetParser/AArch64TargetParser.h | 2 + llvm/lib/Target/AArch64/AArch64.td | 8 +- llvm/lib/Target/AArch64/AArch64InstrInfo.td | 69 +++++++++++++ llvm/lib/Target/AArch64/AArch64SystemOperands.td | 13 +++ .../Target/AArch64/AsmParser/AArch64AsmParser.cpp | 110 ++++++++------------ llvm/test/MC/AArch64/armv9.4a-chk.s | 21 ++++ llvm/test/MC/AArch64/armv9.4a-gcs.s | 115 +++++++++++++++++++++ .../MC/AArch64/directive-arch_extension-negative.s | 9 +- llvm/test/MC/AArch64/directive-arch_extension.s | 4 + llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt | 8 ++ llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt | 90 ++++++++++++++++ llvm/unittests/TargetParser/TargetParserTest.cpp | 4 +- 14 files changed, 387 insertions(+), 69 deletions(-) create mode 100644 llvm/test/MC/AArch64/armv9.4a-chk.s create mode 100644 llvm/test/MC/AArch64/armv9.4a-gcs.s create mode 100644 llvm/test/MC/Disassembler/AArch64/armv9.4a-chk.txt create mode 100644 llvm/test/MC/Disassembler/AArch64/armv9.4a-gcs.txt diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index b274dd2..1711e16 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -927,6 +927,8 @@ bool AArch64TargetInfo::handleTargetFeatures(std::vector &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 f6e1217..c973efc 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 133d10c..9cba6b4 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 e113a21..67b5cf10 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 f31def2..c889bb7 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 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 op1, bits<3> op2, string mnemonic, + list 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 op1, bits<3> op2, string mnemonic, + list 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 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 c7f4044..cbe02f4 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 4f2833c..d5162d3 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(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(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(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 0000000..95acee3 --- /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 0000000..8910229 --- /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 b668699..1c1cfc9 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 03ca1fe..b5bbee7 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 0000000..730f444 --- /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 0000000..7e2802b --- /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 ef5aa82..e83f544 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 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++) { -- 2.7.4