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<ConstantSDNode>(N->getOperand(2))
               && "Expected a constant integer expression.");
     unsigned Reg = PMapper->Encoding;
     uint64_t Immed = cast<ConstantSDNode>(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<string name, bits<5> encoding> : SearchableTable {
+class PState<string name, bits<3> 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