diff --git a/llvm/lib/Target/AArch64/AArch64.td b/llvm/lib/Target/AArch64/AArch64.td --- a/llvm/lib/Target/AArch64/AArch64.td +++ b/llvm/lib/Target/AArch64/AArch64.td @@ -448,6 +448,9 @@ def FeatureMOPS : SubtargetFeature<"mops", "HasMOPS", "true", "Enable Armv8.8-A memcpy and memset acceleration instructions (FEAT_MOPS)">; +def FeatureNMI : SubtargetFeature<"nmi", "HasNMI", + "true", "Enable Armv8.8-A Non-maskable Interrupts (FEAT_NMI, FEAT_GICv3_NMI)">; + def FeatureBRBE : SubtargetFeature<"brbe", "HasBRBE", "true", "Enable Branch Record Buffer Extension (FEAT_BRBE)">; @@ -531,7 +534,7 @@ def HasV8_8aOps : SubtargetFeature< "v8.8a", "HasV8_8aOps", "true", "Support ARM v8.8a instructions", - [HasV8_7aOps, FeatureHBC, FeatureMOPS]>; + [HasV8_7aOps, FeatureHBC, FeatureMOPS, FeatureNMI]>; def HasV9_0aOps : SubtargetFeature< "v9a", "HasV9_0aOps", "true", "Support ARM v9a instructions", diff --git a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp --- a/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp @@ -3138,13 +3138,13 @@ // immediate value has been provided as an argument, we know that this is // the case as it has been ensured by semantic checking. auto PMapper = AArch64PState::lookupPStateByName(RegString->getString()); - if (PMapper) { + if (PMapper && PMapper->haveFeatures(Subtarget->getFeatureBits())) { assert (isa(N->getOperand(2)) && "Expected a constant integer expression."); unsigned Reg = PMapper->Encoding; uint64_t Immed = cast(N->getOperand(2))->getZExtValue(); unsigned State; - if (Reg == AArch64PState::PAN || Reg == AArch64PState::UAO || Reg == AArch64PState::SSBS) { + if (PMapper->hasZeroOneImm()) { assert(Immed < 2 && "Bad imm"); State = AArch64::MSRpstateImm1; } else { diff --git a/llvm/lib/Target/AArch64/AArch64SystemOperands.td b/llvm/lib/Target/AArch64/AArch64SystemOperands.td --- a/llvm/lib/Target/AArch64/AArch64SystemOperands.td +++ b/llvm/lib/Target/AArch64/AArch64SystemOperands.td @@ -338,35 +338,39 @@ // PState instruction options. //===----------------------------------------------------------------------===// -class PState encoding> : SearchableTable { +class PState op1, bits<3> op2> : SearchableTable { let SearchableFields = ["Name", "Encoding"]; let EnumValueField = "Encoding"; string Name = name; - bits<5> Encoding; - let Encoding = encoding; + bits<6> Encoding; + let Encoding{5-3} = op1; + let Encoding{2-0} = op2; code Requires = [{ {} }]; } -def : PState<"SPSel", 0b00101>; -def : PState<"DAIFSet", 0b11110>; -def : PState<"DAIFClr", 0b11111>; +def : PState<"SPSel", 0b000, 0b101>; +def : PState<"DAIFSet", 0b011, 0b110>; +def : PState<"DAIFClr", 0b011, 0b111>; // v8.1a "Privileged Access Never" extension-specific PStates let Requires = [{ {AArch64::FeaturePAN} }] in -def : PState<"PAN", 0b00100>; +def : PState<"PAN", 0b000, 0b100>; // v8.2a "User Access Override" extension-specific PStates let Requires = [{ {AArch64::FeaturePsUAO} }] in -def : PState<"UAO", 0b00011>; +def : PState<"UAO", 0b000, 0b011>; // v8.4a timing insensitivity of data processing instructions let Requires = [{ {AArch64::FeatureDIT} }] in -def : PState<"DIT", 0b11010>; +def : PState<"DIT", 0b011, 0b010>; // v8.5a Spectre Mitigation let Requires = [{ {AArch64::FeatureSSBS} }] in -def : PState<"SSBS", 0b11001>; +def : PState<"SSBS", 0b011, 0b001>; // v8.5a Memory Tagging Extension let Requires = [{ {AArch64::FeatureMTE} }] in -def : PState<"TCO", 0b11100>; +def : PState<"TCO", 0b011, 0b100>; +// v8.8a Non-Maskable Interrupts +let Requires = [{ {AArch64::FeatureNMI} }] in +def : PState<"ALLINT", 0b001, 0b000>; //===----------------------------------------------------------------------===// // SVCR instruction options. @@ -1717,3 +1721,10 @@ let Requires = [{ {AArch64::FeatureMPAM, AArch64::FeatureSME} }] in { def : RWSysReg<"MPAMSM_EL1", 0b11, 0b000, 0b1010, 0b0101, 0b011>; } // HasMPAM, HasSME + +// v8.8a Non-Maskable Interrupts +let Requires = [{ {AArch64::FeatureNMI} }] in { + // Op0 Op1 CRn CRm Op2 + def : RWSysReg<"ALLINT", 0b11, 0b000, 0b0100, 0b0011, 0b000>; + def : ROSysReg<"ICC_NMIAR1_EL1", 0b11, 0b000, 0b1100, 0b1001, 0b101>; // FEAT_GICv3_NMI +} diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -1119,15 +1119,21 @@ bool isSystemPStateFieldWithImm0_1() const { if (!isSysReg()) return false; - return (SysReg.PStateField == AArch64PState::PAN || - SysReg.PStateField == AArch64PState::DIT || - SysReg.PStateField == AArch64PState::UAO || - SysReg.PStateField == AArch64PState::SSBS); + if (SysReg.PStateField == -1U) + return false; + + auto PState = AArch64PState::lookupPStateByEncoding(SysReg.PStateField); + if (!PState) + return false; + return PState->hasZeroOneImm(); } bool isSystemPStateFieldWithImm0_15() const { - if (!isSysReg() || isSystemPStateFieldWithImm0_1()) return false; - return SysReg.PStateField != -1U; + if (!isSysReg()) + return false; + if (SysReg.PStateField == -1U) + return false; + return !isSystemPStateFieldWithImm0_1(); } bool isSVCR() const { diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp --- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1712,25 +1712,27 @@ uint64_t crm = fieldFromInstruction(insn, 8, 4); uint64_t pstate_field = (op1 << 3) | op2; - switch (pstate_field) { - case 0x01: // XAFlag - case 0x02: // AXFlag - return Fail; + if (op1 == 0) { + switch (op2) { + case 0b000: // CFINV + case 0b001: // XAFLAG + case 0b010: // AXFLAG + return Fail; + } } - if ((pstate_field == AArch64PState::PAN || - pstate_field == AArch64PState::UAO || - pstate_field == AArch64PState::SSBS) && crm > 1) + auto PState = AArch64PState::lookupPStateByEncoding(pstate_field); + if (!PState || + !PState->haveFeatures(Decoder->getSubtargetInfo().getFeatureBits())) + return Fail; + + if (PState->hasZeroOneImm() && crm > 1) return Fail; Inst.addOperand(MCOperand::createImm(pstate_field)); Inst.addOperand(MCOperand::createImm(crm)); - auto PState = AArch64PState::lookupPStateByEncoding(pstate_field); - if (PState && - PState->haveFeatures(Decoder->getSubtargetInfo().getFeatureBits())) - return Success; - return Fail; + return Success; } static DecodeStatus DecodeTestAndBranch(MCInst &Inst, uint32_t insn, diff --git a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h --- a/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h +++ b/llvm/lib/Target/AArch64/Utils/AArch64BaseInfo.h @@ -557,11 +557,15 @@ } namespace AArch64PState { - struct PState : SysAlias{ - using SysAlias::SysAlias; - }; - #define GET_PSTATE_DECL - #include "AArch64GenSystemOperands.inc" +struct PState; +#define GET_PSTATE_DECL +#include "AArch64GenSystemOperands.inc" + +struct PState : SysAlias { + using SysAlias::SysAlias; + + bool hasZeroOneImm() const { return Encoding == AArch64PState::ALLINT; } +}; } namespace AArch64PSBHint { diff --git a/llvm/test/MC/AArch64/armv8.1a-pan.s b/llvm/test/MC/AArch64/armv8.1a-pan.s --- a/llvm/test/MC/AArch64/armv8.1a-pan.s +++ b/llvm/test/MC/AArch64/armv8.1a-pan.s @@ -15,16 +15,16 @@ // CHECK: mrs x13, PAN // encoding: [0x6d,0x42,0x38,0xd5] msr pan, #-1 - msr pan, #2 + msr pan, #16 msr pan, w0 mrs w0, pan -// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. +// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. // CHECK-ERROR: msr pan, #-1 // CHECK-ERROR: ^ -// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. -// CHECK-ERROR: msr pan, #2 +// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. +// CHECK-ERROR: msr pan, #16 // CHECK-ERROR: ^ -// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. +// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. // CHECK-ERROR: msr pan, w0 // CHECK-ERROR: ^ // CHECK-ERROR: error: invalid operand for instruction diff --git a/llvm/test/MC/AArch64/armv8.2a-uao.s b/llvm/test/MC/AArch64/armv8.2a-uao.s --- a/llvm/test/MC/AArch64/armv8.2a-uao.s +++ b/llvm/test/MC/AArch64/armv8.2a-uao.s @@ -8,9 +8,9 @@ // CHECK: msr UAO, #0 // encoding: [0x7f,0x40,0x00,0xd5] // CHECK: msr UAO, #1 // encoding: [0x7f,0x41,0x00,0xd5] - msr uao, #2 -// CHECK-ERROR: error: immediate must be an integer in range [0, 1]. -// CHECK-ERROR: msr uao, #2 + msr uao, #16 +// CHECK-ERROR: error: immediate must be an integer in range [0, 15]. +// CHECK-ERROR: msr uao, #16 // CHECK-ERROR: ^ msr uao, x1 diff --git a/llvm/test/MC/AArch64/armv8.4a-dit.s b/llvm/test/MC/AArch64/armv8.4a-dit.s --- a/llvm/test/MC/AArch64/armv8.4a-dit.s +++ b/llvm/test/MC/AArch64/armv8.4a-dit.s @@ -14,13 +14,13 @@ //CHECK-NEXT: msr DIT, x0 // encoding: [0xa0,0x42,0x1b,0xd5] //CHECK-NEXT: mrs x0, DIT // encoding: [0xa0,0x42,0x3b,0xd5] -msr DIT, #2 +msr DIT, #16 msr DIT, #-1 -//CHECK-ERROR: error: immediate must be an integer in range [0, 1]. -//CHECK-ERROR-NEXT: msr DIT, #2 +//CHECK-ERROR: error: immediate must be an integer in range [0, 15]. +//CHECK-ERROR-NEXT: msr DIT, #16 //CHECK-ERROR-NEXT: ^ -//CHECK-ERROR-NEXT: error: immediate must be an integer in range [0, 1]. +//CHECK-ERROR-NEXT: error: immediate must be an integer in range [0, 15]. //CHECK-ERROR-NEXT: msr DIT, #-1 //CHECK-ERROR-NEXT: ^ @@ -34,7 +34,7 @@ //CHECK-NO-V84-NEXT: mrs x0, DIT //CHECK-NO-V84-NEXT: ^ //CHECK-NO-V84-NEXT: error: expected writable system register or pstate -//CHECK-NO-V84-NEXT: msr DIT, #2 +//CHECK-NO-V84-NEXT: msr DIT, #16 //CHECK-NO-V84-NEXT: ^ //CHECK-NO-V84-NEXT: error: expected writable system register or pstate //CHECK-NO-V84-NEXT: msr DIT, #-1 diff --git a/llvm/test/MC/AArch64/armv8.5a-ssbs-error.s b/llvm/test/MC/AArch64/armv8.5a-ssbs-error.s --- a/llvm/test/MC/AArch64/armv8.5a-ssbs-error.s +++ b/llvm/test/MC/AArch64/armv8.5a-ssbs-error.s @@ -2,9 +2,9 @@ // RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=+v8.5a < %s 2>&1 | FileCheck %s // RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=-ssbs < %s 2>&1 | FileCheck %s --check-prefix=NOSPECID -msr SSBS, #2 +msr SSBS, #16 -// CHECK: error: immediate must be an integer in range [0, 1]. -// CHECK-NEXT: msr SSBS, #2 +// CHECK: error: immediate must be an integer in range [0, 15]. +// CHECK-NEXT: msr SSBS, #16 // NOSPECID: error: expected writable system register or pstate -// NOSPECID-NEXT: msr {{ssbs|SSBS}}, #2 +// NOSPECID-NEXT: msr {{ssbs|SSBS}}, #16 diff --git a/llvm/test/MC/AArch64/armv8.8a-nmi-error.s b/llvm/test/MC/AArch64/armv8.8a-nmi-error.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AArch64/armv8.8a-nmi-error.s @@ -0,0 +1,36 @@ +// RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=+nmi < %s 2>&1 | FileCheck %s +// RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=+v8.8a < %s 2>&1 | FileCheck %s +// RUN: not llvm-mc -triple aarch64 -show-encoding < %s 2>&1 | FileCheck %s --check-prefix=NO_NMI +// RUN: not llvm-mc -triple aarch64 -show-encoding -mattr=-nmi < %s 2>&1 | FileCheck %s --check-prefix=NO_NMI + +msr ALLINT, #1 +msr ALLINT, #2 +msr ALLINT, x3 +mrs x2, ALLINT +mrs x11, icc_nmiar1_el1 +msr icc_nmiar1_el1, x12 + +// CHECK: error: immediate must be an integer in range [0, 1]. +// CHECK-NEXT: msr ALLINT, #2 +// CHECK-NEXT: ^ +// CHECK-NEXT: error: expected writable system register or pstate +// CHECK-NEXT: msr icc_nmiar1_el1, x12 +// CHECK-NEXT: ^ + +// NO_NMI: error: expected writable system register or pstate +// NO_NMI-NEXT: msr {{allint|ALLINT}}, #1 +// NO_NMI-NEXT: ^ +// NO_NMI-NEXT: error: expected writable system register or pstate +// NO_NMI-NEXT: msr {{allint|ALLINT}}, #2 +// NO_NMI-NEXT: ^ +// NO_NMI-NEXT: error: expected writable system register or pstate +// NO_NMI-NEXT: msr {{allint|ALLINT}}, x3 +// NO_NMI-NEXT: ^ +// NO_NMI-NEXT: error: expected readable system register +// NO_NMI-NEXT: mrs x2, {{allint|ALLINT}} +// NO_NMI-NEXT: ^ +// NO_NMI-NEXT: error: expected readable system register +// NO_NMI-NEXT: mrs x11, {{icc_nmiar1_el1|ICC_NMIAR1_EL1}} +// NO_NMI-NEXT: ^ +// NO_NMI-NEXT: error: expected writable system register or pstate +// NO_NMI-NEXT: msr {{icc_nmiar1_el1|ICC_NMIAR1_EL1}}, x12 diff --git a/llvm/test/MC/AArch64/armv8.8a-nmi.s b/llvm/test/MC/AArch64/armv8.8a-nmi.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/AArch64/armv8.8a-nmi.s @@ -0,0 +1,12 @@ +// RUN: llvm-mc -triple aarch64 -show-encoding -mattr=+nmi < %s | FileCheck %s +// RUN: llvm-mc -triple aarch64 -show-encoding -mattr=+v8.8a < %s | FileCheck %s + +mrs x2, ALLINT +msr ALLINT, x3 +msr ALLINT, #1 +mrs x7, ICC_NMIAR1_EL1 + +// CHECK: mrs x2, {{allint|ALLINT}} // encoding: [0x02,0x43,0x38,0xd5] +// CHECK: msr {{allint|ALLINT}}, x3 // encoding: [0x03,0x43,0x18,0xd5] +// CHECK: msr {{allint|ALLINT}}, #1 // encoding: [0x1f,0x41,0x01,0xd5] +// CHECK: mrs x7, {{icc_nmiar1_el1|ICC_NMIAR1_EL1}} // encoding: [0xa7,0xc9,0x38,0xd5] diff --git a/llvm/test/MC/Disassembler/AArch64/armv8.1a-pan.txt b/llvm/test/MC/Disassembler/AArch64/armv8.1a-pan.txt --- a/llvm/test/MC/Disassembler/AArch64/armv8.1a-pan.txt +++ b/llvm/test/MC/Disassembler/AArch64/armv8.1a-pan.txt @@ -2,11 +2,11 @@ 0x9f,0x40,0x00,0xd5 0x9f,0x41,0x00,0xd5 -0x9f,0x42,0x00,0xd5 +0x9f,0x4f,0x00,0xd5 0x65,0x42,0x18,0xd5 0x6d,0x42,0x38,0xd5 # CHECK: msr PAN, #0 # CHECK: msr PAN, #1 -# CHECK-NOT: msr PAN, #2 +# CHECK: msr PAN, #15 # CHECK: msr PAN, x5 # CHECK: mrs x13, PAN diff --git a/llvm/test/MC/Disassembler/AArch64/armv8.2a-uao.txt b/llvm/test/MC/Disassembler/AArch64/armv8.2a-uao.txt --- a/llvm/test/MC/Disassembler/AArch64/armv8.2a-uao.txt +++ b/llvm/test/MC/Disassembler/AArch64/armv8.2a-uao.txt @@ -3,13 +3,13 @@ [0x7f,0x40,0x00,0xd5] [0x7f,0x41,0x00,0xd5] -[0x7f,0x42,0x00,0xd5] +[0x7f,0x4f,0x00,0xd5] # CHECK: msr UAO, #0 # CHECK: msr UAO, #1 -# CHECK: msr S0_0_C4_C2_3, xzr +# CHECK: msr UAO, #15 # NO_V82A: msr S0_0_C4_C0_3, xzr # NO_V82A: msr S0_0_C4_C1_3, xzr -# NO_V82A: msr S0_0_C4_C2_3, xzr +# NO_V82A: msr S0_0_C4_C15_3, xzr [0x81,0x42,0x18,0xd5] [0x82,0x42,0x38,0xd5] diff --git a/llvm/test/MC/Disassembler/AArch64/armv8.8a-nmi.txt b/llvm/test/MC/Disassembler/AArch64/armv8.8a-nmi.txt new file mode 100644 --- /dev/null +++ b/llvm/test/MC/Disassembler/AArch64/armv8.8a-nmi.txt @@ -0,0 +1,30 @@ +# RUN: llvm-mc -triple=aarch64 -mattr=+nmi -disassemble %s | FileCheck %s +# RUN: llvm-mc -triple=aarch64 -mattr=+v8.8a -disassemble %s | FileCheck %s +# RUN: llvm-mc -triple=aarch64 -disassemble %s | FileCheck %s --check-prefix=NO-NMI + + +[0x03,0x43,0x38,0xd5] +# CHECK: mrs x3, ALLINT +# NO-NMI: mrs x3, S3_0_C4_C3_0 + +[0x06,0x43,0x18,0xd5] +# CHECK: msr ALLINT, x6 +# NO-NMI: msr S3_0_C4_C3_0, x6 + +[0x1f,0x40,0x01,0xd5] +# CHECK: msr ALLINT, #0 +# NO-NMI: msr S0_1_C4_C0_0, xzr + +[0x1f,0x41,0x01,0xd5] +# CHECK: msr ALLINT, #1 +# NO-NMI: msr S0_1_C4_C1_0, xzr + +# Regression test for a defect, where the bit-pattern, which should have allowed +# only ALLSTATE, allowed SPSel (and others). +[0xbf,0x51,0x00,0xd5] +# CHECK: msr S0_0_C5_C1_5, xzr +# NO-NMI: msr S0_0_C5_C1_5, xzr + +[0xa7,0xc9,0x38,0xd5] +# CHECK: mrs x7, ICC_NMIAR1_EL1 +# NO-NMI: mrs x7, S3_0_C12_C9_5