From d9e399718e9a195de10db3503805ca0a8367411e Mon Sep 17 00:00:00 2001 From: Jonathan Thackray Date: Mon, 8 Sep 2025 13:19:57 +0100 Subject: [PATCH] [AArch64][llvm] Armv9.7-A: Add support for TLBI Domains (FEAT_TLBID) Allow the following `TLBI` operation types to take an optional register operand when enabled by `FEAT_TLBID`: - ALL* - VMALL* - VMALLS12* - VMALLWS2* as documented here: * https://developer.arm.com/documentation/ddi0602/2025-09/ * https://developer.arm.com/documentation/109697/2025_09/2025-Architecture-Extensions Notes on implementation: Currently, AArch64 `SYS` alias instructions fall into two categories: * a register value must be present (indicated by any value except `XZR`) * no register value must be present (this value must be `XZR`) When +tblid is enabled, `SYS` aliases are now allowed to take an optional register, or no register as before. We need an extra tablegen flag to indicate if the register is optional or not (the existing "NeedsReg" flag is binary and not suitable; the register is either present or absent, not either for a specific TLBI operation) Don't produce an error message if the register operand is missing or unexpected, if it is specified as an optional register. --- clang/test/Driver/aarch64-v97a.c | 4 + .../print-supported-extensions-aarch64.c | 1 + llvm/lib/Target/AArch64/AArch64Features.td | 3 + llvm/lib/Target/AArch64/AArch64InstrInfo.td | 2 + .../Target/AArch64/AArch64SystemOperands.td | 72 ++++++++-------- .../AArch64/AsmParser/AArch64AsmParser.cpp | 20 +++-- .../MCTargetDesc/AArch64InstPrinter.cpp | 14 +++- .../Target/AArch64/Utils/AArch64BaseInfo.h | 24 ++++-- .../MC/AArch64/armv9.7a-tlbid-diagnostics.s | 64 ++++++++++++++ llvm/test/MC/AArch64/armv9.7a-tlbid.s | 84 +++++++++++++++++++ .../TargetParser/TargetParserTest.cpp | 4 +- 11 files changed, 239 insertions(+), 53 deletions(-) create mode 100644 llvm/test/MC/AArch64/armv9.7a-tlbid-diagnostics.s create mode 100644 llvm/test/MC/AArch64/armv9.7a-tlbid.s diff --git a/clang/test/Driver/aarch64-v97a.c b/clang/test/Driver/aarch64-v97a.c index 4a55d44466cc0..ec0e4245b81aa 100644 --- a/clang/test/Driver/aarch64-v97a.c +++ b/clang/test/Driver/aarch64-v97a.c @@ -25,3 +25,7 @@ // RUN: %clang -target aarch64 -march=armv9.7a+lscp -### -c %s 2>&1 | FileCheck -check-prefix=V97A-LSCP %s // RUN: %clang -target aarch64 -march=armv9.7-a+lscp -### -c %s 2>&1 | FileCheck -check-prefix=V97A-LSCP %s // V97A-LSCP: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.7a"{{.*}} "-target-feature" "+lscp" + +// RUN: %clang -target aarch64 -march=armv9.7a+tlbid -### -c %s 2>&1 | FileCheck -check-prefix=V97A-TLBID %s +// RUN: %clang -target aarch64 -march=armv9.7-a+tlbid -### -c %s 2>&1 | FileCheck -check-prefix=V97A-TLBID %s +// V97A-TLBID: "-cc1"{{.*}} "-triple" "aarch64{{.*}}" "-target-cpu" "generic" "-target-feature" "+v9.7a"{{.*}} "-target-feature" "+tlbid" diff --git a/clang/test/Driver/print-supported-extensions-aarch64.c b/clang/test/Driver/print-supported-extensions-aarch64.c index 9928f395866d8..3e4ceae5bd5c1 100644 --- a/clang/test/Driver/print-supported-extensions-aarch64.c +++ b/clang/test/Driver/print-supported-extensions-aarch64.c @@ -104,6 +104,7 @@ // CHECK-NEXT: sve2p1 FEAT_SVE2p1 Enable Scalable Vector Extension 2.1 instructions // CHECK-NEXT: sve2p2 FEAT_SVE2p2 Enable Armv9.6-A Scalable Vector Extension 2.2 instructions // CHECK-NEXT: the FEAT_THE Enable Armv8.9-A Translation Hardening Extension +// CHECK-NEXT: tlbid FEAT_TLBID Enable Armv9.7-A TLBI Domains extension // CHECK-NEXT: tlbiw FEAT_TLBIW Enable Armv9.5-A TLBI VMALL for Dirty State // CHECK-NEXT: tme FEAT_TME Enable Transactional Memory Extension // CHECK-NEXT: wfxt FEAT_WFxT Enable Armv8.7-A WFET and WFIT instruction diff --git a/llvm/lib/Target/AArch64/AArch64Features.td b/llvm/lib/Target/AArch64/AArch64Features.td index 7fe83537b7a36..eea06968f438a 100644 --- a/llvm/lib/Target/AArch64/AArch64Features.td +++ b/llvm/lib/Target/AArch64/AArch64Features.td @@ -595,6 +595,9 @@ def FeatureCMH : ExtensionWithMArch<"cmh", "CMH", "FEAT_CMH", def FeatureLSCP : ExtensionWithMArch<"lscp", "LSCP", "FEAT_LSCP", "Enable Armv9.7-A Load-acquire and store-release pair extension">; +def FeatureTLBID: ExtensionWithMArch<"tlbid", "TLBID", "FEAT_TLBID", + "Enable Armv9.7-A TLBI Domains extension">; + //===----------------------------------------------------------------------===// // Other Features //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td index 50646484f0cde..6918b4afd76ed 100644 --- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td @@ -400,6 +400,8 @@ def HasGCS : Predicate<"Subtarget->hasGCS()">, AssemblerPredicateWithAll<(all_of FeatureGCS), "gcs">; def HasCPA : Predicate<"Subtarget->hasCPA()">, AssemblerPredicateWithAll<(all_of FeatureCPA), "cpa">; +def HasTLBID : Predicate<"Subtarget->hasTLBID()">, + AssemblerPredicateWithAll<(all_of FeatureTLBID), "tlbid">; def IsLE : Predicate<"Subtarget->isLittleEndian()">; def IsBE : Predicate<"!Subtarget->isLittleEndian()">; def IsWindows : Predicate<"Subtarget->isTargetWindows()">; diff --git a/llvm/lib/Target/AArch64/AArch64SystemOperands.td b/llvm/lib/Target/AArch64/AArch64SystemOperands.td index a358d4b7174f3..feac7e6d14646 100644 --- a/llvm/lib/Target/AArch64/AArch64SystemOperands.td +++ b/llvm/lib/Target/AArch64/AArch64SystemOperands.td @@ -832,7 +832,7 @@ def : CMHPriorityHint<"ph", 0b1>; //===----------------------------------------------------------------------===// class TLBICommon op1, bits<4> crn, bits<4> crm, - bits<3> op2, bit needsreg> { + bits<3> op2, bit needsreg, bit optionalreg> { string Name = name; bits<14> Encoding; let Encoding{13-11} = op1; @@ -840,24 +840,25 @@ class TLBICommon op1, bits<4> crn, bits<4> crm, let Encoding{6-3} = crm; let Encoding{2-0} = op2; bit NeedsReg = needsreg; + bit OptionalReg = optionalreg; list Requires = []; list ExtraRequires = []; code RequiresStr = [{ { }] # !interleave(Requires # ExtraRequires, [{, }]) # [{ } }]; } class TLBIEntry op1, bits<4> crn, bits<4> crm, - bits<3> op2, bit needsreg> - : TLBICommon; + bits<3> op2, bit needsreg, bit optionalreg> + : TLBICommon; class TLBIPEntry op1, bits<4> crn, bits<4> crm, - bits<3> op2, bit needsreg> - : TLBICommon; + bits<3> op2, bit needsreg, bit optionalreg> + : TLBICommon; multiclass TLBITableBase { def NAME # Table : GenericTable { let FilterClass = NAME # "Entry"; let CppTypeName = NAME; - let Fields = ["Name", "Encoding", "NeedsReg", "RequiresStr"]; + let Fields = ["Name", "Encoding", "NeedsReg", "OptionalReg", "RequiresStr"]; let PrimaryKey = ["Encoding"]; let PrimaryKeyName = "lookup" # NAME # "ByEncoding"; } @@ -871,60 +872,60 @@ defm TLBI : TLBITableBase; defm TLBIP : TLBITableBase; multiclass TLBI op1, bits<4> crn, bits<4> crm, - bits<3> op2, bit needsreg = 1> { - def : TLBIEntry; - def : TLBIEntry { + bits<3> op2, bit needsreg = 1, bit optionalreg = 0> { + def : TLBIEntry; + def : TLBIEntry { let Encoding{7} = 1; let ExtraRequires = ["AArch64::FeatureXS"]; } if !eq(hasTLBIP, true) then { - def : TLBIPEntry; - def : TLBIPEntry { + def : TLBIPEntry; + def : TLBIPEntry { let Encoding{7} = 1; let ExtraRequires = ["AArch64::FeatureXS"]; } } } -// hasTLBIP op1 CRn CRm op2 needsreg +// hasTLBIP op1 CRn CRm op2 needsreg, optreg defm : TLBI<"IPAS2E1IS", 1, 0b100, 0b1000, 0b0000, 0b001>; defm : TLBI<"IPAS2LE1IS", 1, 0b100, 0b1000, 0b0000, 0b101>; -defm : TLBI<"VMALLE1IS", 0, 0b000, 0b1000, 0b0011, 0b000, 0>; -defm : TLBI<"ALLE2IS", 0, 0b100, 0b1000, 0b0011, 0b000, 0>; -defm : TLBI<"ALLE3IS", 0, 0b110, 0b1000, 0b0011, 0b000, 0>; +defm : TLBI<"VMALLE1IS", 0, 0b000, 0b1000, 0b0011, 0b000, 0, 1>; +defm : TLBI<"ALLE2IS", 0, 0b100, 0b1000, 0b0011, 0b000, 0, 1>; +defm : TLBI<"ALLE3IS", 0, 0b110, 0b1000, 0b0011, 0b000, 0, 1>; defm : TLBI<"VAE1IS", 1, 0b000, 0b1000, 0b0011, 0b001>; defm : TLBI<"VAE2IS", 1, 0b100, 0b1000, 0b0011, 0b001>; defm : TLBI<"VAE3IS", 1, 0b110, 0b1000, 0b0011, 0b001>; defm : TLBI<"ASIDE1IS", 0, 0b000, 0b1000, 0b0011, 0b010>; defm : TLBI<"VAAE1IS", 1, 0b000, 0b1000, 0b0011, 0b011>; -defm : TLBI<"ALLE1IS", 0, 0b100, 0b1000, 0b0011, 0b100, 0>; +defm : TLBI<"ALLE1IS", 0, 0b100, 0b1000, 0b0011, 0b100, 0, 1>; defm : TLBI<"VALE1IS", 1, 0b000, 0b1000, 0b0011, 0b101>; defm : TLBI<"VALE2IS", 1, 0b100, 0b1000, 0b0011, 0b101>; defm : TLBI<"VALE3IS", 1, 0b110, 0b1000, 0b0011, 0b101>; -defm : TLBI<"VMALLS12E1IS", 0, 0b100, 0b1000, 0b0011, 0b110, 0>; +defm : TLBI<"VMALLS12E1IS", 0, 0b100, 0b1000, 0b0011, 0b110, 0, 1>; defm : TLBI<"VAALE1IS", 1, 0b000, 0b1000, 0b0011, 0b111>; defm : TLBI<"IPAS2E1", 1, 0b100, 0b1000, 0b0100, 0b001>; defm : TLBI<"IPAS2LE1", 1, 0b100, 0b1000, 0b0100, 0b101>; -defm : TLBI<"VMALLE1", 0, 0b000, 0b1000, 0b0111, 0b000, 0>; -defm : TLBI<"ALLE2", 0, 0b100, 0b1000, 0b0111, 0b000, 0>; -defm : TLBI<"ALLE3", 0, 0b110, 0b1000, 0b0111, 0b000, 0>; +defm : TLBI<"VMALLE1", 0, 0b000, 0b1000, 0b0111, 0b000, 0, 0>; +defm : TLBI<"ALLE2", 0, 0b100, 0b1000, 0b0111, 0b000, 0, 0>; +defm : TLBI<"ALLE3", 0, 0b110, 0b1000, 0b0111, 0b000, 0, 0>; defm : TLBI<"VAE1", 1, 0b000, 0b1000, 0b0111, 0b001>; defm : TLBI<"VAE2", 1, 0b100, 0b1000, 0b0111, 0b001>; defm : TLBI<"VAE3", 1, 0b110, 0b1000, 0b0111, 0b001>; defm : TLBI<"ASIDE1", 0, 0b000, 0b1000, 0b0111, 0b010>; defm : TLBI<"VAAE1", 1, 0b000, 0b1000, 0b0111, 0b011>; -defm : TLBI<"ALLE1", 0, 0b100, 0b1000, 0b0111, 0b100, 0>; +defm : TLBI<"ALLE1", 0, 0b100, 0b1000, 0b0111, 0b100, 0, 0>; defm : TLBI<"VALE1", 1, 0b000, 0b1000, 0b0111, 0b101>; defm : TLBI<"VALE2", 1, 0b100, 0b1000, 0b0111, 0b101>; defm : TLBI<"VALE3", 1, 0b110, 0b1000, 0b0111, 0b101>; -defm : TLBI<"VMALLS12E1", 0, 0b100, 0b1000, 0b0111, 0b110, 0>; +defm : TLBI<"VMALLS12E1", 0, 0b100, 0b1000, 0b0111, 0b110, 0, 0>; defm : TLBI<"VAALE1", 1, 0b000, 0b1000, 0b0111, 0b111>; // Armv8.4-A Translation Lookaside Buffer Instructions (TLBI) let Requires = ["AArch64::FeatureTLB_RMI"] in { // Armv8.4-A Outer Sharable TLB Maintenance instructions: -// hasTLBIP op1 CRn CRm op2 needsreg -defm : TLBI<"VMALLE1OS", 0, 0b000, 0b1000, 0b0001, 0b000, 0>; +// hasTLBIP op1 CRn CRm op2 needsreg, optreg +defm : TLBI<"VMALLE1OS", 0, 0b000, 0b1000, 0b0001, 0b000, 0, 1>; defm : TLBI<"VAE1OS", 1, 0b000, 0b1000, 0b0001, 0b001>; defm : TLBI<"ASIDE1OS", 0, 0b000, 0b1000, 0b0001, 0b010>; defm : TLBI<"VAAE1OS", 1, 0b000, 0b1000, 0b0001, 0b011>; @@ -934,15 +935,15 @@ defm : TLBI<"IPAS2E1OS", 1, 0b100, 0b1000, 0b0100, 0b000>; defm : TLBI<"IPAS2LE1OS", 1, 0b100, 0b1000, 0b0100, 0b100>; defm : TLBI<"VAE2OS", 1, 0b100, 0b1000, 0b0001, 0b001>; defm : TLBI<"VALE2OS", 1, 0b100, 0b1000, 0b0001, 0b101>; -defm : TLBI<"VMALLS12E1OS", 0, 0b100, 0b1000, 0b0001, 0b110, 0>; +defm : TLBI<"VMALLS12E1OS", 0, 0b100, 0b1000, 0b0001, 0b110, 0, 1>; defm : TLBI<"VAE3OS", 1, 0b110, 0b1000, 0b0001, 0b001>; defm : TLBI<"VALE3OS", 1, 0b110, 0b1000, 0b0001, 0b101>; -defm : TLBI<"ALLE2OS", 0, 0b100, 0b1000, 0b0001, 0b000, 0>; -defm : TLBI<"ALLE1OS", 0, 0b100, 0b1000, 0b0001, 0b100, 0>; -defm : TLBI<"ALLE3OS", 0, 0b110, 0b1000, 0b0001, 0b000, 0>; +defm : TLBI<"ALLE2OS", 0, 0b100, 0b1000, 0b0001, 0b000, 0, 1>; +defm : TLBI<"ALLE1OS", 0, 0b100, 0b1000, 0b0001, 0b100, 0, 1>; +defm : TLBI<"ALLE3OS", 0, 0b110, 0b1000, 0b0001, 0b000, 0, 1>; // Armv8.4-A TLB Range Maintenance instructions: -// hasTLBIP op1 CRn CRm op2 needsreg +// hasTLBIP op1 CRn CRm op2 defm : TLBI<"RVAE1", 1, 0b000, 0b1000, 0b0110, 0b001>; defm : TLBI<"RVAAE1", 1, 0b000, 0b1000, 0b0110, 0b011>; defm : TLBI<"RVALE1", 1, 0b000, 0b1000, 0b0110, 0b101>; @@ -977,18 +978,19 @@ defm : TLBI<"RVALE3OS", 1, 0b110, 0b1000, 0b0101, 0b101>; // Armv9-A Realm Management Extension TLBI Instructions let Requires = ["AArch64::FeatureRME"] in { +// hasTLBIP op1 CRn CRm op2 needsreg defm : TLBI<"RPAOS", 0, 0b110, 0b1000, 0b0100, 0b011>; defm : TLBI<"RPALOS", 0, 0b110, 0b1000, 0b0100, 0b111>; -defm : TLBI<"PAALLOS", 0, 0b110, 0b1000, 0b0001, 0b100, 0>; -defm : TLBI<"PAALL", 0, 0b110, 0b1000, 0b0111, 0b100, 0>; +defm : TLBI<"PAALLOS", 0, 0b110, 0b1000, 0b0001, 0b100, 0, 0>; +defm : TLBI<"PAALL", 0, 0b110, 0b1000, 0b0111, 0b100, 0, 0>; } // Armv9.5-A TLBI VMALL for Dirty State let Requires = ["AArch64::FeatureTLBIW"] in { -// op1, CRn, CRm, op2, needsreg -defm : TLBI<"VMALLWS2E1", 0, 0b100, 0b1000, 0b0110, 0b010, 0>; -defm : TLBI<"VMALLWS2E1IS", 0, 0b100, 0b1000, 0b0010, 0b010, 0>; -defm : TLBI<"VMALLWS2E1OS", 0, 0b100, 0b1000, 0b0101, 0b010, 0>; +// hasTLBIP op1 CRn CRm op2 needsreg, optreg +defm : TLBI<"VMALLWS2E1", 0, 0b100, 0b1000, 0b0110, 0b010, 0, 0>; +defm : TLBI<"VMALLWS2E1IS", 0, 0b100, 0b1000, 0b0010, 0b010, 0, 1>; +defm : TLBI<"VMALLWS2E1OS", 0, 0b100, 0b1000, 0b0101, 0b010, 0, 1>; } //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 82de7aacfed45..08564e87ceff4 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -3885,6 +3885,7 @@ static const struct Extension { {"sme-tmop", {AArch64::FeatureSME_TMOP}}, {"cmh", {AArch64::FeatureCMH}}, {"lscp", {AArch64::FeatureLSCP}}, + {"tlbid", {AArch64::FeatureTLBID}}, }; static void setRequiredFeatureString(FeatureBitset FBS, std::string &Str) { @@ -3971,6 +3972,8 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, StringRef Op = Tok.getString(); SMLoc S = Tok.getLoc(); bool ExpectRegister = true; + bool OptionalRegister = false; + bool hasAll = getSTI().hasFeature(AArch64::FeatureAll); if (Mnemonic == "ic") { const AArch64IC::IC *IC = AArch64IC::lookupICByName(Op); @@ -4013,13 +4016,16 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, return TokError(Str); } ExpectRegister = TLBI->NeedsReg; + bool hasTLBID = getSTI().hasFeature(AArch64::FeatureTLBID); + if (hasAll || hasTLBID) { + OptionalRegister = TLBI->OptionalReg; + } createSysAlias(TLBI->Encoding, Operands, S); } else if (Mnemonic == "cfp" || Mnemonic == "dvp" || Mnemonic == "cpp" || Mnemonic == "cosp") { if (Op.lower() != "rctx") return TokError("invalid operand for prediction restriction instruction"); - bool hasAll = getSTI().hasFeature(AArch64::FeatureAll); bool hasPredres = hasAll || getSTI().hasFeature(AArch64::FeaturePredRes); bool hasSpecres2 = hasAll || getSTI().hasFeature(AArch64::FeatureSPECRES2); @@ -4052,10 +4058,12 @@ bool AArch64AsmParser::parseSysAlias(StringRef Name, SMLoc NameLoc, HasRegister = true; } - if (ExpectRegister && !HasRegister) - return TokError("specified " + Mnemonic + " op requires a register"); - else if (!ExpectRegister && HasRegister) - return TokError("specified " + Mnemonic + " op does not use a register"); + if (!OptionalRegister) { + if (ExpectRegister && !HasRegister) + return TokError("specified " + Mnemonic + " op requires a register"); + else if (!ExpectRegister && HasRegister) + return TokError("specified " + Mnemonic + " op does not use a register"); + } if (parseToken(AsmToken::EndOfStatement, "unexpected token in argument list")) return true; @@ -4088,7 +4096,7 @@ bool AArch64AsmParser::parseSyspAlias(StringRef Name, SMLoc NameLoc, return TokError("invalid operand for TLBIP instruction"); const AArch64TLBIP::TLBIP TLBIP( TLBIPorig->Name, TLBIPorig->Encoding | (HasnXSQualifier ? (1 << 7) : 0), - TLBIPorig->NeedsReg, + TLBIPorig->NeedsReg, TLBIPorig->OptionalReg, HasnXSQualifier ? TLBIPorig->FeaturesRequired | FeatureBitset({AArch64::FeatureXS}) : TLBIPorig->FeaturesRequired); diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp index 6bd53f61884c2..936c36b29c12c 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64InstPrinter.cpp @@ -909,7 +909,8 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI, Encoding |= CnVal << 7; Encoding |= Op1Val << 11; - bool NeedsReg; + bool NeedsReg = false; + bool OptionalReg = false; std::string Ins; std::string Name; @@ -1004,6 +1005,9 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI, return false; NeedsReg = TLBI->NeedsReg; + if (STI.hasFeature(AArch64::FeatureAll) || + STI.hasFeature(AArch64::FeatureTLBID)) + OptionalReg = TLBI->OptionalReg; Ins = "tlbi\t"; Name = std::string(TLBI->Name); } @@ -1013,10 +1017,10 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI, StringRef Reg = getRegisterName(MI->getOperand(4).getReg()); bool NotXZR = Reg != "xzr"; - // If a mandatory is not specified in the TableGen + // If a mandatory or optional register is not specified in the TableGen // (i.e. no register operand should be present), and the register value // is not xzr/x31, then disassemble to a SYS alias instead. - if (NotXZR && !NeedsReg) + if (NotXZR && !NeedsReg && !OptionalReg) return false; std::string Str = Ins + Name; @@ -1024,7 +1028,9 @@ bool AArch64InstPrinter::printSysAlias(const MCInst *MI, O << '\t' << Str; - if (NeedsReg) + // 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; return true; diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h index e09a0ee0518db..fb5db0dfadddf 100644 --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -409,6 +409,16 @@ struct SysAliasReg : SysAlias { : SysAlias(N, E, F), NeedsReg(R) {} }; +struct SysAliasOptionalReg : SysAlias { + bool NeedsReg; + bool OptionalReg; + constexpr SysAliasOptionalReg(const char *N, uint16_t E, bool R, bool O) + : SysAlias(N, E), NeedsReg(R), OptionalReg(O) {} + constexpr SysAliasOptionalReg(const char *N, uint16_t E, bool R, bool O, + FeatureBitset F) + : SysAlias(N, E, F), NeedsReg(R), OptionalReg(O) {} +}; + struct SysAliasImm : SysAlias { uint16_t ImmValue; constexpr SysAliasImm(const char *N, uint16_t E, uint16_t I) @@ -796,16 +806,16 @@ namespace AArch64SysReg { } namespace AArch64TLBI { - struct TLBI : SysAliasReg { - using SysAliasReg::SysAliasReg; - }; - #define GET_TLBITable_DECL - #include "AArch64GenSystemOperands.inc" +struct TLBI : SysAliasOptionalReg { + using SysAliasOptionalReg::SysAliasOptionalReg; +}; +#define GET_TLBITable_DECL +#include "AArch64GenSystemOperands.inc" } namespace AArch64TLBIP { -struct TLBIP : SysAliasReg { - using SysAliasReg::SysAliasReg; +struct TLBIP : SysAliasOptionalReg { + using SysAliasOptionalReg::SysAliasOptionalReg; }; #define GET_TLBIPTable_DECL #include "AArch64GenSystemOperands.inc" diff --git a/llvm/test/MC/AArch64/armv9.7a-tlbid-diagnostics.s b/llvm/test/MC/AArch64/armv9.7a-tlbid-diagnostics.s new file mode 100644 index 0000000000000..2440fd30fae03 --- /dev/null +++ b/llvm/test/MC/AArch64/armv9.7a-tlbid-diagnostics.s @@ -0,0 +1,64 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+tlb-rmi,+tlbiw,+rme < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+tlb-rmi,+tlbiw,+tlbid,+rme < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-NO-REGISTER + +// Test without using +tlbid - no optional register operand allowed + +tlbi vmalle1is, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmalle1is, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmalle1os, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmalls12e1os, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi alle1is, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi alle2is, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi alle3is, x5 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmallws2e1os, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmalls12e1is, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmallws2e1is, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register + +tlbi vmalle1, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi alle1, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi alle2, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi alle3, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi vmalls12e1, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi paallos, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register + +tlbi paall, x1 +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-NO-REGISTER: error: specified tlbi op does not use a register diff --git a/llvm/test/MC/AArch64/armv9.7a-tlbid.s b/llvm/test/MC/AArch64/armv9.7a-tlbid.s new file mode 100644 index 0000000000000..74a9bac4768b1 --- /dev/null +++ b/llvm/test/MC/AArch64/armv9.7a-tlbid.s @@ -0,0 +1,84 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+tlbid,+tlb-rmi,+tlbiw < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+tlb-rmi,+tlbiw < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+all < %s \ +// RUN: | llvm-objdump -d --mattr=+tlbid,+tlb-rmi,+tlbiw --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+all < %s \ +// RUN: | llvm-objdump -d --mattr=-tlbid,-tlb-rmi,-tlbiw --no-print-imm-hex - | FileCheck %s --check-prefix=CHECK-UNKNOWN +// Disassemble encoding and check the re-encoding (-show-encoding) matches. +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+tlbid,+tlb-rmi,+tlbiw < %s \ +// RUN: | sed '/.text/d' | sed 's/.*encoding: //g' \ +// RUN: | llvm-mc -triple=aarch64 -mattr=+tlbid,+tlb-rmi,+tlbiw -disassemble -show-encoding \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST + +// Armv9.7-A TLBI Domains (FEAT_TLBID) + +tlbi vmalle1is +// CHECK-INST: tlbi vmalle1is +// CHECK-ENCODING: encoding: [0x1f,0x83,0x08,0xd5] +// CHECK-UNKNOWN: d508831f tlbi vmalle1is + +tlbi vmalle1is, xzr +// CHECK-INST: tlbi vmalle1is +// CHECK-ENCODING: encoding: [0x1f,0x83,0x08,0xd5] +// CHECK-UNKNOWN: d508831f tlbi vmalle1is + +tlbi vmalle1is, x31 +// CHECK-INST: tlbi vmalle1is +// CHECK-ENCODING: encoding: [0x1f,0x83,0x08,0xd5] +// CHECK-UNKNOWN: d508831f tlbi vmalle1is + +tlbi vmalle1is, x5 +// CHECK-INST: tlbi vmalle1is, x5 +// CHECK-ENCODING: encoding: [0x05,0x83,0x08,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d5088305 sys #0, c8, c3, #0, x5 + +tlbi vmalle1os, x5 +// CHECK-INST: tlbi vmalle1os, x5 +// CHECK-ENCODING: encoding: [0x05,0x81,0x08,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d5088105 sys #0, c8, c1, #0, x5 + +tlbi alle1is, x5 +// CHECK-INST: tlbi alle1is, x5 +// CHECK-ENCODING: encoding: [0x85,0x83,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c8385 sys #4, c8, c3, #4, x5 + +tlbi alle2is, x5 +// CHECK-INST: tlbi alle2is, x5 +// CHECK-ENCODING: encoding: [0x05,0x83,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c8305 sys #4, c8, c3, #0, x5 + +tlbi alle3is, x5 +// CHECK-INST: tlbi alle3is, x5 +// CHECK-ENCODING: encoding: [0x05,0x83,0x0e,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50e8305 sys #6, c8, c3, #0, x5 + +tlbi vmalls12e1is, x1 +// CHECK-INST: tlbi vmalls12e1is, x1 +// CHECK-ENCODING: encoding: [0xc1,0x83,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c83c1 sys #4, c8, c3, #6, x1 + +tlbi vmalls12e1os, x5 +// CHECK-INST: tlbi vmalls12e1os, x5 +// CHECK-ENCODING: encoding: [0xc5,0x81,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c81c5 sys #4, c8, c1, #6, x5 + +tlbi vmallws2e1is, x1 +// CHECK-INST: tlbi vmallws2e1is, x1 +// CHECK-ENCODING: encoding: [0x41,0x82,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c8241 sys #4, c8, c2, #2, x1 + +tlbi vmallws2e1os, x1 +// CHECK-INST: tlbi vmallws2e1os, x1 +// CHECK-ENCODING: encoding: [0x41,0x85,0x0c,0xd5] +// CHECK-ERROR: error: specified tlbi op does not use a register +// CHECK-UNKNOWN: d50c8541 sys #4, c8, c5, #2, x1 diff --git a/llvm/unittests/TargetParser/TargetParserTest.cpp b/llvm/unittests/TargetParser/TargetParserTest.cpp index e9f7f2ceeb070..0801c2a6edd26 100644 --- a/llvm/unittests/TargetParser/TargetParserTest.cpp +++ b/llvm/unittests/TargetParser/TargetParserTest.cpp @@ -1444,7 +1444,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { AArch64::AEK_SME_TMOP, AArch64::AEK_SVEBITPERM, AArch64::AEK_SSVE_BITPERM, AArch64::AEK_SVESHA3, AArch64::AEK_SVESM4, AArch64::AEK_CMH, - AArch64::AEK_LSCP, + AArch64::AEK_LSCP, AArch64::AEK_TLBID, }; std::vector Features; @@ -1558,6 +1558,7 @@ TEST(TargetParserTest, AArch64ExtensionFeatures) { EXPECT_TRUE(llvm::is_contained(Features, "+sme-tmop")); EXPECT_TRUE(llvm::is_contained(Features, "+cmh")); EXPECT_TRUE(llvm::is_contained(Features, "+lscp")); + EXPECT_TRUE(llvm::is_contained(Features, "+tlbid")); // Assuming we listed every extension above, this should produce the same // result. @@ -1726,6 +1727,7 @@ TEST(TargetParserTest, AArch64ArchExtFeature) { {"sme-tmop", "nosme-tmop", "+sme-tmop", "-sme-tmop"}, {"cmh", "nocmh", "+cmh", "-cmh"}, {"lscp", "nolscp", "+lscp", "-lscp"}, + {"tlbid", "notlbid", "+tlbid", "-tlbid"}, }; for (unsigned i = 0; i < std::size(ArchExt); i++) {