[llvm] [DecoderEmitter] Support for DecodeOrder and `resolve-conflicts-try-all` (PR #157948)

Rahul Joshi via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 11 11:31:26 PDT 2025


https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/157948

>From 7affc5b4ef78843ac8509bc8ece1ea27d762c1c1 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 10 Sep 2025 12:15:57 -0700
Subject: [PATCH 1/5] [DecoderEmitter] Add support for DecodeOrder and
 `resolve-conflicts-try-all`

---
 llvm/include/llvm/Target/Target.td            |   4 +
 .../lib/Target/AArch64/AArch64InstrFormats.td |   7 +-
 llvm/lib/Target/AArch64/AArch64InstrInfo.td   |   4 +-
 .../Disassembler/AArch64Disassembler.cpp      |  62 +++----
 .../Disassembler/AMDGPUDisassembler.cpp       |  43 +----
 .../AMDGPU/Disassembler/AMDGPUDisassembler.h  |   4 -
 llvm/lib/Target/AMDGPU/VINTERPInstructions.td |  10 +-
 llvm/lib/Target/AMDGPU/VOP1Instructions.td    |  12 +-
 llvm/lib/Target/AMDGPU/VOP2Instructions.td    |  12 +-
 llvm/lib/Target/AMDGPU/VOPCInstructions.td    |  11 +-
 llvm/lib/Target/AMDGPU/VOPInstructions.td     |  27 +--
 .../RISCV/Disassembler/RISCVDisassembler.cpp  |  22 ++-
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       |  14 ++
 llvm/lib/Target/RISCV/RISCVInstrInfoC.td      |   6 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoP.td      |  40 ++---
 llvm/lib/Target/RISCV/RISCVInstrInfoZa.td     |   2 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoZc.td     |  12 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoZclsd.td  |   5 +-
 .../lib/Target/RISCV/RISCVInstrInfoZicfiss.td |   2 +-
 llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td  |   4 +-
 llvm/utils/TableGen/DecoderEmitter.cpp        | 164 ++++++++++++++++--
 21 files changed, 304 insertions(+), 163 deletions(-)

diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 6a7ecf78b2131..c24083ec51fee 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -551,6 +551,10 @@ class InstructionEncoding {
   // where multiple ISA namespaces exist).
   string DecoderNamespace = "";
 
+  // Within a namespace, DecodeOrder is used to order instructions when we need
+  // to attempt multiple encoding.
+  int DecodeOrder = 0;
+
   // List of predicates which will be turned into isel matching code.
   list<Predicate> Predicates = [];
 
diff --git a/llvm/lib/Target/AArch64/AArch64InstrFormats.td b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
index 8958ad129269c..9d3286b7f2cd8 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrFormats.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrFormats.td
@@ -1957,7 +1957,7 @@ class MRSI : RtSystemI<1, (outs GPR64:$Rt), (ins mrs_sysreg_op:$systemreg),
                        "mrs", "\t$Rt, $systemreg"> {
   bits<16> systemreg;
   let Inst{20-5} = systemreg;
-  let DecoderNamespace = "Fallback";
+  let DecodeOrder = 1;
   // The MRS is set as a NZCV setting instruction. Not all MRS instructions
   // require doing this. The alternative was to explicitly model each one, but
   // it feels like it is unnecessary because it seems there are no negative
@@ -1972,7 +1972,7 @@ class MSRI : RtSystemI<0, (outs), (ins msr_sysreg_op:$systemreg, GPR64:$Rt),
                        "msr", "\t$systemreg, $Rt"> {
   bits<16> systemreg;
   let Inst{20-5} = systemreg;
-  let DecoderNamespace = "Fallback";
+  let DecodeOrder = 1;
 }
 
 def SystemPStateFieldWithImm0_15Operand : AsmOperandClass {
@@ -2045,7 +2045,8 @@ class MSRpstateImm0_1
   // MSRpstateI aliases with MSRI. When the MSRpstateI decoder method returns
   // Fail the decoder should attempt to decode the instruction as MSRI.
   let hasCompleteDecoder = false;
-  let DecoderNamespace = "Fallback";
+  let DecodeOrder = 1;
+
 }
 
 // SYS and SYSL generic system instructions.
diff --git a/llvm/lib/Target/AArch64/AArch64InstrInfo.td b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
index f0020a9a3c91d..fce95c28f22b6 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrInfo.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrInfo.td
@@ -10712,8 +10712,8 @@ def RPRFM:
   let hasSideEffects = 1;
   // RPRFM overlaps with PRFM (reg), when the decoder method of PRFM returns
   // Fail, the decoder should attempt to decode RPRFM. This requires setting
-  // the decoder namespace to "Fallback".
-  let DecoderNamespace = "Fallback";
+  // the decode order for RPRFM to be 1 ( > decode order for PRFM).
+  let DecodeOrder = 1;
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
index aa1c1c882e225..9f55c7a7e7bfd 100644
--- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
+++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp
@@ -1578,43 +1578,37 @@ DecodeStatus AArch64Disassembler::getInstruction(MCInst &MI, uint64_t &Size,
   uint32_t Insn =
       (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | (Bytes[0] << 0);
 
-  const uint8_t *Tables[] = {DecoderTable32, DecoderTableFallback32};
-
-  for (const auto *Table : Tables) {
-    DecodeStatus Result =
-        decodeInstruction(Table, MI, Insn, Address, this, STI);
-
-    const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
-
-    // For Scalable Matrix Extension (SME) instructions that have an implicit
-    // operand for the accumulator (ZA) or implicit immediate zero which isn't
-    // encoded, manually insert operand.
-    for (unsigned i = 0; i < Desc.getNumOperands(); i++) {
-      if (Desc.operands()[i].OperandType == MCOI::OPERAND_REGISTER) {
-        switch (Desc.operands()[i].RegClass) {
-        default:
-          break;
-        case AArch64::MPRRegClassID:
-          MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZA));
-          break;
-        case AArch64::MPR8RegClassID:
-          MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZAB0));
-          break;
-        case AArch64::ZTRRegClassID:
-          MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZT0));
-          break;
-        }
-      } else if (Desc.operands()[i].OperandType ==
-                 AArch64::OPERAND_IMPLICIT_IMM_0) {
-        MI.insert(MI.begin() + i, MCOperand::createImm(0));
+  DecodeStatus Result =
+      decodeInstruction(DecoderTable32, MI, Insn, Address, this, STI);
+  if (Result != Success)
+    return Result;
+
+  const MCInstrDesc &Desc = MCII->get(MI.getOpcode());
+
+  // For Scalable Matrix Extension (SME) instructions that have an implicit
+  // operand for the accumulator (ZA) or implicit immediate zero which isn't
+  // encoded, manually insert operand.
+  for (unsigned i = 0; i < Desc.getNumOperands(); i++) {
+    if (Desc.operands()[i].OperandType == MCOI::OPERAND_REGISTER) {
+      switch (Desc.operands()[i].RegClass) {
+      default:
+        break;
+      case AArch64::MPRRegClassID:
+        MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZA));
+        break;
+      case AArch64::MPR8RegClassID:
+        MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZAB0));
+        break;
+      case AArch64::ZTRRegClassID:
+        MI.insert(MI.begin() + i, MCOperand::createReg(AArch64::ZT0));
+        break;
       }
+    } else if (Desc.operands()[i].OperandType ==
+               AArch64::OPERAND_IMPLICIT_IMM_0) {
+      MI.insert(MI.begin() + i, MCOperand::createImm(0));
     }
-
-    if (Result != MCDisassembler::Fail)
-      return Result;
   }
-
-  return MCDisassembler::Fail;
+  return Success;
 }
 
 uint64_t AArch64Disassembler::suggestBytesToSkip(ArrayRef<uint8_t> Bytes,
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
index 6f6039bf4ec21..28467b44c711d 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.cpp
@@ -487,18 +487,6 @@ DecodeStatus AMDGPUDisassembler::tryDecodeInst(const uint8_t *Table, MCInst &MI,
   return MCDisassembler::Fail;
 }
 
-template <typename InsnType>
-DecodeStatus
-AMDGPUDisassembler::tryDecodeInst(const uint8_t *Table1, const uint8_t *Table2,
-                                  MCInst &MI, InsnType Inst, uint64_t Address,
-                                  raw_ostream &Comments) const {
-  for (const uint8_t *T : {Table1, Table2}) {
-    if (DecodeStatus Res = tryDecodeInst(T, MI, Inst, Address, Comments))
-      return Res;
-  }
-  return MCDisassembler::Fail;
-}
-
 template <typename T> static inline T eatBytes(ArrayRef<uint8_t>& Bytes) {
   assert(Bytes.size() >= sizeof(T));
   const auto Res =
@@ -617,18 +605,15 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
       std::bitset<96> DecW = eat12Bytes(Bytes);
 
       if (isGFX11() &&
-          tryDecodeInst(DecoderTableGFX1196, DecoderTableGFX11_FAKE1696, MI,
-                        DecW, Address, CS))
+          tryDecodeInst(DecoderTableGFX1196, MI, DecW, Address, CS))
         break;
 
       if (isGFX1250() &&
-          tryDecodeInst(DecoderTableGFX125096, DecoderTableGFX1250_FAKE1696, MI,
-                        DecW, Address, CS))
+          tryDecodeInst(DecoderTableGFX125096, MI, DecW, Address, CS))
         break;
 
       if (isGFX12() &&
-          tryDecodeInst(DecoderTableGFX1296, DecoderTableGFX12_FAKE1696, MI,
-                        DecW, Address, CS))
+          tryDecodeInst(DecoderTableGFX1296, MI, DecW, Address, CS))
         break;
 
       if (isGFX12() &&
@@ -698,18 +683,13 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
         break;
 
       if (isGFX1250() &&
-          tryDecodeInst(DecoderTableGFX125064, DecoderTableGFX1250_FAKE1664, MI,
-                        QW, Address, CS))
+          tryDecodeInst(DecoderTableGFX125064, MI, QW, Address, CS))
         break;
 
-      if (isGFX12() &&
-          tryDecodeInst(DecoderTableGFX1264, DecoderTableGFX12_FAKE1664, MI, QW,
-                        Address, CS))
+      if (isGFX12() && tryDecodeInst(DecoderTableGFX1264, MI, QW, Address, CS))
         break;
 
-      if (isGFX11() &&
-          tryDecodeInst(DecoderTableGFX1164, DecoderTableGFX11_FAKE1664, MI, QW,
-                        Address, CS))
+      if (isGFX11() && tryDecodeInst(DecoderTableGFX1164, MI, QW, Address, CS))
         break;
 
       if (isGFX11() &&
@@ -753,19 +733,14 @@ DecodeStatus AMDGPUDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
       if (isGFX10() && tryDecodeInst(DecoderTableGFX1032, MI, DW, Address, CS))
         break;
 
-      if (isGFX11() &&
-          tryDecodeInst(DecoderTableGFX1132, DecoderTableGFX11_FAKE1632, MI, DW,
-                        Address, CS))
+      if (isGFX11() && tryDecodeInst(DecoderTableGFX1132, MI, DW, Address, CS))
         break;
 
       if (isGFX1250() &&
-          tryDecodeInst(DecoderTableGFX125032, DecoderTableGFX1250_FAKE1632, MI,
-                        DW, Address, CS))
+          tryDecodeInst(DecoderTableGFX125032, MI, DW, Address, CS))
         break;
 
-      if (isGFX12() &&
-          tryDecodeInst(DecoderTableGFX1232, DecoderTableGFX12_FAKE1632, MI, DW,
-                        Address, CS))
+      if (isGFX12() && tryDecodeInst(DecoderTableGFX1232, MI, DW, Address, CS))
         break;
     }
 
diff --git a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
index c1131c2936fc7..b33a8bfa7db6d 100644
--- a/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
+++ b/llvm/lib/Target/AMDGPU/Disassembler/AMDGPUDisassembler.h
@@ -79,10 +79,6 @@ class AMDGPUDisassembler : public MCDisassembler {
   template <typename InsnType>
   DecodeStatus tryDecodeInst(const uint8_t *Table, MCInst &MI, InsnType Inst,
                              uint64_t Address, raw_ostream &Comments) const;
-  template <typename InsnType>
-  DecodeStatus tryDecodeInst(const uint8_t *Table1, const uint8_t *Table2,
-                             MCInst &MI, InsnType Inst, uint64_t Address,
-                             raw_ostream &Comments) const;
 
   Expected<bool> onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size,
                                ArrayRef<uint8_t> Bytes,
diff --git a/llvm/lib/Target/AMDGPU/VINTERPInstructions.td b/llvm/lib/Target/AMDGPU/VINTERPInstructions.td
index 5e89e34ca56e9..e7cc1b9b255ac 100644
--- a/llvm/lib/Target/AMDGPU/VINTERPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VINTERPInstructions.td
@@ -239,8 +239,9 @@ defm : VInterpF16Pat<int_amdgcn_interp_p2_rtz_f16,
 
 multiclass VINTERP_Real_gfx11 <bits<7> op, string asmName> {
   defvar ps = !cast<VOP3_Pseudo>(NAME);
-  let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11" #
-                           !if(ps.Pfl.IsRealTrue16, "", "_FAKE16") in {
+  let AssemblerPredicate = isGFX11Only, DecoderNamespace = "GFX11",
+      // When decoding, attempt decoding IsRealTrue16 first, then the fake one.
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1) in {
     def _gfx11 :
       VINTERP_Real<ps, SIEncodingFamily.GFX11, asmName>,
       VINTERPe_gfx11<op, ps.Pfl>;
@@ -249,8 +250,9 @@ multiclass VINTERP_Real_gfx11 <bits<7> op, string asmName> {
 
 multiclass VINTERP_Real_gfx12 <bits<7> op, string asmName> {
   defvar ps = !cast<VOP3_Pseudo>(NAME);
-  let AssemblerPredicate = isGFX12Only, DecoderNamespace = "GFX12" #
-                           !if(ps.Pfl.IsRealTrue16, "", "_FAKE16") in {
+  let AssemblerPredicate = isGFX12Only, DecoderNamespace = "GFX12",
+      // When decoding, attempt decoding IsRealTrue16 first, then the fake one.
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1) in {
     def _gfx12 :
       VINTERP_Real<ps, SIEncodingFamily.GFX12, asmName>,
       VINTERPe_gfx12<op, ps.Pfl>;
diff --git a/llvm/lib/Target/AMDGPU/VOP1Instructions.td b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
index f816d7de27ee4..0ce794a7c6c76 100644
--- a/llvm/lib/Target/AMDGPU/VOP1Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP1Instructions.td
@@ -940,8 +940,8 @@ multiclass VOP1_Real_e32_with_name<GFXGen Gen, bits<9> op, string opName,
                                    string asmName> {
   defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
   let AsmString = asmName # ps.AsmOperands,
-      DecoderNamespace = Gen.DecoderNamespace #
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16") in {
+      DecoderNamespace = Gen.DecoderNamespace,
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1) in {
     defm NAME : VOP1_Real_e32<Gen, op, opName>;
   }
 }
@@ -961,8 +961,8 @@ multiclass VOP1_Real_dpp_with_name<GFXGen Gen, bits<9> op, string opName,
                                    string asmName> {
   defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
   let AsmString = asmName # ps.Pfl.AsmDPP16,
-      DecoderNamespace = Gen.DecoderNamespace #
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16") in {
+      DecoderNamespace = Gen.DecoderNamespace,
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1) in {
     defm NAME : VOP1_Real_dpp<Gen, op, opName>;
   }
 }
@@ -977,8 +977,8 @@ multiclass VOP1_Real_dpp8_with_name<GFXGen Gen, bits<9> op, string opName,
                                     string asmName> {
   defvar ps = !cast<VOP1_Pseudo>(opName#"_e32");
   let AsmString = asmName # ps.Pfl.AsmDPP8,
-      DecoderNamespace = Gen.DecoderNamespace #
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16") in {
+      DecoderNamespace = Gen.DecoderNamespace,
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1) in {
     if !not(ps.Pfl.HasExt64BitDPP) then
       defm NAME : VOP1_Real_dpp8<Gen, op, opName>;
   }
diff --git a/llvm/lib/Target/AMDGPU/VOP2Instructions.td b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
index cff66aaedb11e..b698b2f24e2f2 100644
--- a/llvm/lib/Target/AMDGPU/VOP2Instructions.td
+++ b/llvm/lib/Target/AMDGPU/VOP2Instructions.td
@@ -127,8 +127,8 @@ class VOP2_Real_Gen <VOP2_Pseudo ps, GFXGen Gen, string real_name = ps.Mnemonic>
   VOP2_Real <ps, Gen.Subtarget, real_name> {
   let AssemblerPredicate = Gen.AssemblerPredicate;
   let True16Predicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, NoTrue16Predicate);
-  let DecoderNamespace = Gen.DecoderNamespace#
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+  let DecoderNamespace = Gen.DecoderNamespace;
+  let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
 }
 
 class VOP2_SDWA_Pseudo <string OpName, VOPProfile P, list<dag> pattern=[]> :
@@ -1517,8 +1517,8 @@ class VOP2_DPP16_Gen<bits<6> op, VOP2_DPP_Pseudo ps, GFXGen Gen,
     VOP2_DPP16<op, ps, Gen.Subtarget, opName, p> {
   let AssemblerPredicate = Gen.AssemblerPredicate;
   let True16Predicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, NoTrue16Predicate);
-  let DecoderNamespace = Gen.DecoderNamespace#
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+  let DecoderNamespace = Gen.DecoderNamespace;
+  let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
 }
 
 class VOP2_DPP8<bits<6> op, VOP2_Pseudo ps,
@@ -1547,8 +1547,8 @@ class VOP2_DPP8_Gen<bits<6> op, VOP2_Pseudo ps, GFXGen Gen,
     VOP2_DPP8<op, ps, p> {
   let AssemblerPredicate = Gen.AssemblerPredicate;
   let True16Predicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, NoTrue16Predicate);
-  let DecoderNamespace = Gen.DecoderNamespace#
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+  let DecoderNamespace = Gen.DecoderNamespace;
+  let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/AMDGPU/VOPCInstructions.td b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
index 2730ec52294e9..82f2fc7df3006 100644
--- a/llvm/lib/Target/AMDGPU/VOPCInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPCInstructions.td
@@ -310,6 +310,7 @@ class VOPCInstAlias <VOP3_Pseudo ps, Instruction inst,
   let SubtargetPredicate = AssemblerPredicate;
 
   string DecoderNamespace; // dummy
+  int DecodeOrder; // dummy
 }
 
 multiclass VOPCInstAliases <string old_name, string Arch, string real_name = old_name, string mnemonic_from = real_name> {
@@ -1677,7 +1678,8 @@ multiclass VOPC_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
                                                      pseudo_mnemonic),
                               asm_name, ps64.AsmVariantName>;
 
-    let DecoderNamespace = Gen.DecoderNamespace # !if(ps32.Pfl.IsRealTrue16, "", "_FAKE16") in {
+    let DecoderNamespace = Gen.DecoderNamespace,
+        DecodeOrder = !if(ps32.Pfl.IsRealTrue16, 0, 1) in {
       def _e32#Gen.Suffix :
         // 32 and 64 bit forms of the instruction have _e32 and _e64
         // respectively appended to their assembly mnemonic.
@@ -1753,7 +1755,7 @@ multiclass VOPC_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
           def _e64_dpp8#Gen.Suffix : VOPC64_DPP8_Dst<{0, op}, ps64, asm_name>;
         }
       } // end if ps64.Pfl.HasExtVOP3DPP
-    } // End DecoderNamespace
+    } // End DecoderOrder
   } // End AssemblerPredicate
 }
 
@@ -1824,7 +1826,8 @@ multiclass VOPCX_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
                                                      pseudo_mnemonic),
                               asm_name, ps64.AsmVariantName>;
 
-    let DecoderNamespace = Gen.DecoderNamespace # !if(ps32.Pfl.IsRealTrue16, "", "_FAKE16") in {
+    let DecoderNamespace = Gen.DecoderNamespace,
+        DecodeOrder = !if(ps32.Pfl.IsRealTrue16, 0, 1) in {
       def _e32#Gen.Suffix
           : VOPC_Real<ps32, Gen.Subtarget, asm_name>,
             VOPCe<op{7-0}> {
@@ -1880,7 +1883,7 @@ multiclass VOPCX_Real_with_name<GFXGen Gen, bits<9> op, string OpName,
           }
         }
       } // End if ps64.Pfl.HasExtVOP3DPP
-    } // End DecoderNamespace
+    } // End DecodeOrder
   } // End AssemblerPredicate
 }
 
diff --git a/llvm/lib/Target/AMDGPU/VOPInstructions.td b/llvm/lib/Target/AMDGPU/VOPInstructions.td
index 5550a0c08b918..edc03358c0652 100644
--- a/llvm/lib/Target/AMDGPU/VOPInstructions.td
+++ b/llvm/lib/Target/AMDGPU/VOPInstructions.td
@@ -204,8 +204,8 @@ class VOP3_Real_Gen <VOP_Pseudo ps, GFXGen Gen, string asm_name = ps.Mnemonic> :
   VOP3_Real <ps, Gen.Subtarget, asm_name> {
   let AssemblerPredicate = Gen.AssemblerPredicate;
   let True16Predicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts, NoTrue16Predicate);
-  let DecoderNamespace = Gen.DecoderNamespace#
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+  let DecoderNamespace = Gen.DecoderNamespace;
+  let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
 }
 
 // XXX - Is there any reason to distinguish this from regular VOP3
@@ -1705,8 +1705,8 @@ class VOP3_DPP16_Gen_t16<bits<10> op, VOP_DPP_Pseudo ps, GFXGen Gen,
   let True16Predicate =
       !if (ps.Pfl.IsRealTrue16, UseRealTrue16Insts, NoTrue16Predicate);
   let AssemblerPredicate = Gen.AssemblerPredicate;
-  let DecoderNamespace =
-      Gen.DecoderNamespace #!if (ps.Pfl.IsRealTrue16, "", "_FAKE16");
+  let DecoderNamespace = Gen.DecoderNamespace;
+  let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
 }
 
 class Base_VOP3_DPP8<bits<10> op, VOP_Pseudo ps, string opName = ps.OpName>
@@ -1816,7 +1816,8 @@ multiclass VOP3Dot_Real_Base<GFXGen Gen, bits<10> op, string asmName, string opN
                              bit isSingle = 0> {
   defvar ps = !cast<VOP_Pseudo>(opName#"_e64");
   let AsmString = asmName # ps.AsmOperands,
-      DecoderNamespace = Gen.DecoderNamespace # !if(ps.Pfl.IsRealTrue16, "", "_FAKE16"),
+      DecoderNamespace = Gen.DecoderNamespace,
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1),
       IsSingle = !or(isSingle, ps.Pfl.IsSingle) in {
     def _e64#Gen.Suffix :
       VOP3_Real_Gen<ps, Gen>,
@@ -1886,8 +1887,8 @@ multiclass VOP3Dot_Real_dpp_Base<GFXGen Gen, bits<10> op, string asmName, string
   def _e64_dpp#Gen.Suffix :
     VOP3_DPP16_Gen_t16<op, ps, Gen> {
       let AsmString = asmName # ps.Pfl.AsmVOP3DPP16;
-      let DecoderNamespace = Gen.DecoderNamespace
-                             # !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+      let DecoderNamespace = Gen.DecoderNamespace;
+      let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
       let Inst{11} = ?;
       let Inst{12} = ?;
     }
@@ -1915,8 +1916,8 @@ multiclass VOP3Dot_Real_dpp8_Base<GFXGen Gen, bits<10> op, string asmName, strin
     let Inst{11} = ?;
     let Inst{12} = ?;
     let AsmString = asmName # ps.Pfl.AsmVOP3DPP8;
-    let DecoderNamespace = Gen.DecoderNamespace
-                           # !if(ps.Pfl.IsRealTrue16, "", "_FAKE16");
+    let DecoderNamespace = Gen.DecoderNamespace;
+    let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
     let AssemblerPredicate = Gen.AssemblerPredicate;
   }
 }
@@ -1925,8 +1926,8 @@ multiclass VOP3_Real_dpp8_with_name<GFXGen Gen, bits<10> op, string opName,
                                     string asmName> {
   defvar ps = !cast<VOP3_Pseudo>(opName#"_e64");
   let AsmString = asmName # ps.Pfl.AsmVOP3DPP8,
-      DecoderNamespace = Gen.DecoderNamespace#
-                         !if(ps.Pfl.IsRealTrue16, "", "_FAKE16"),
+      DecoderNamespace = Gen.DecoderNamespace,
+      DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1),
       True16Predicate = !if(ps.Pfl.IsRealTrue16, UseRealTrue16Insts,
                             NoTrue16Predicate) in {
     defm NAME : VOP3_Real_dpp8_Base<Gen, op, opName>;
@@ -2006,8 +2007,8 @@ multiclass VOP3_BITOP3_Real_dpp_Base<GFXGen Gen, bits<10> op, string asmName> {
 multiclass VOP3_BITOP3_Real_dpp8_Base<GFXGen Gen, bits<10> op, string asmName> {
   defvar ps = !cast<VOP3_Pseudo>(NAME#"_e64");
   def _e64_dpp8#Gen.Suffix : VOP3_BITOP3_DPP8<op, ps, asmName> {
-    let DecoderNamespace =
-      Gen.DecoderNamespace #!if (ps.Pfl.IsRealTrue16, "", "_FAKE16");
+    let DecoderNamespace = Gen.DecoderNamespace;
+    let DecodeOrder = !if(ps.Pfl.IsRealTrue16, 0, 1);
     let AssemblerPredicate = Gen.AssemblerPredicate;
   }
 }
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index 89df9d82f8780..6bfa941c2d13e 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -689,9 +689,14 @@ static constexpr DecoderListEntry DecoderList32[]{
     {DecoderTableXMIPS32, XMIPSGroup, "Mips extensions"},
     {DecoderTableXAndes32, XAndesGroup, "Andes extensions"},
     {DecoderTableXSMT32, XSMTGroup, "SpacemiT extensions"},
-    // Standard Extensions
+
+    // Standard Extensions.
+    // The decoder order within this table is as follows:
+    // standard 32-bit instructions : 0
+    // RV32-only standard 32-bit instructions : 1
+    // Zfinx (Float in Integer) : 2 (TBD)
+    // RV32-only Zdinx (Double in Integer) : 3 (TBD)
     {DecoderTable32, {}, "standard 32-bit instructions"},
-    {DecoderTableRV32Only32, {}, "RV32-only standard 32-bit instructions"},
     {DecoderTableZfinx32, {}, "Zfinx (Float in Integer)"},
     {DecoderTableZdinxRV32Only32, {}, "RV32-only Zdinx (Double in Integer)"},
 };
@@ -739,15 +744,16 @@ static constexpr DecoderListEntry DecoderList16[]{
      {RISCV::FeatureVendorXqccmp},
      "Xqccmp (Qualcomm 16-bit Push/Pop & Double Move Instructions)"},
     {DecoderTableXwchc16, {RISCV::FeatureVendorXwchc}, "WCH QingKe XW"},
+
     // Standard Extensions
+    // Instructions in this table have the following decoding order:
+    // Zicfiss (Shadow Stack 16-bit) : -1
+    // standard 16-bit instructions : 0
+    // RV32-only 16-bit instructions : 1
+    // ZcOverlap (16-bit Instructions overlapping with Zcf/Zcd): 2
+
     // DecoderTableZicfiss16 must be checked before DecoderTable16.
-    {DecoderTableZicfiss16, {}, "Zicfiss (Shadow Stack 16-bit)"},
     {DecoderTable16, {}, "standard 16-bit instructions"},
-    {DecoderTableRV32Only16, {}, "RV32-only 16-bit instructions"},
-    // Zc* instructions incompatible with Zcf or Zcd
-    {DecoderTableZcOverlap16,
-     {},
-     "ZcOverlap (16-bit Instructions overlapping with Zcf/Zcd)"},
 };
 
 DecodeStatus RISCVDisassembler::getInstruction16(MCInst &MI, uint64_t &Size,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 92552b36aa0b9..5c68e37eb552c 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2312,6 +2312,20 @@ def : Pat<(i64 (add GPR:$rs1, negImm:$rs2)), (SUB GPR:$rs1, negImm:$rs2)>;
 let Predicates = [HasStdExtZihintpause] in
 def : Pat<(int_riscv_pause), (FENCE 0x1, 0x0)>;
 
+//===----------------------------------------------------------------------===//
+// Decoder orders for various instruction classes.
+//===----------------------------------------------------------------------===//
+
+// For 16 bit instructions.
+defvar DecodeOrderZicfiss16 = -1;
+defvar DecodeOrderRV32Only16 = 1;
+defvar DecodeOrderZcOverlap = 2;
+
+// For 32-bit instructions.
+defvar DecodeOrderRV32Only32 = 1;
+defvar DecodeOrderZfinx32 = 2;
+defvar DecodeOrderZdinxRV32Only32 = 2;
+
 //===----------------------------------------------------------------------===//
 // Standard extensions
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
index 9fc73662d9704..738accb00fb99 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoC.td
@@ -379,7 +379,7 @@ def PseudoC_ADDI_NOP : Pseudo<(outs GPRX0:$rd), (ins GPRX0:$rs1, simm6:$imm),
 }
 
 let hasSideEffects = 0, mayLoad = 0, mayStore = 0, isCall = 1,
-    DecoderNamespace = "RV32Only", Defs = [X1],
+    DecodeOrder = DecodeOrderRV32Only16, Defs = [X1],
     Predicates = [HasStdExtZca, IsRV32]  in
 def C_JAL : RVInst16CJ<0b001, 0b01, (outs), (ins bare_simm12_lsb0:$offset),
                        "c.jal", "$offset">, Sched<[WriteJal]>;
@@ -542,7 +542,7 @@ def C_UNIMP : RVInst16<(outs), (ins), "c.unimp", "", [], InstFormatOther>,
 
 } // Predicates = [HasStdExtZca]
 
-let DecoderNamespace = "RV32Only",
+let DecodeOrder = DecodeOrderRV32Only16,
     Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32] in {
   def C_FLW  : CLoad_ri<0b011, "c.flw", FPR32C, uimm7_lsb00>,
                Sched<[WriteFLD32, ReadFMemBase]> {
@@ -569,7 +569,7 @@ let DecoderNamespace = "RV32Only",
                  Sched<[WriteFST32, ReadFStoreData, ReadFMemBase]> {
     let Inst{8-7}  = imm{7-6};
   }
-} // DecoderNamespace = "RV32Only", Predicates = [HasStdExtCOrZcfOrZce, HasStdExtF, IsRV32]
+} // DecodeOrder = DecodeOrderRV32Only16
 
 let Predicates = [HasStdExtCOrZcd, HasStdExtD] in {
   def C_FLD  : CLoad_ri<0b001, "c.fld", FPR64C, uimm8_lsb000>,
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
index cfa20cb016918..e4a14a0d71458 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoP.td
@@ -382,9 +382,9 @@ let Predicates = [HasStdExtP] in {
   def PSLLI_H  : RVPShiftH_ri<0b000, 0b010, "pslli.h">;
   def PSSLAI_H : RVPShiftH_ri<0b101, 0b010, "psslai.h">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def SSLAI    : RVPShiftW_ri<0b101, 0b010, "sslai">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PSLLI_W  : RVPShiftW_ri<0b000, 0b010, "pslli.w">;
   def PSSLAI_W : RVPShiftW_ri<0b101, 0b010, "psslai.w">;
@@ -431,7 +431,7 @@ let Predicates = [HasStdExtP] in {
 
   def PSSHAR_HS : RVPBinaryScalar_rr<0b111, 0b00, 0b010, "psshar.hs">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def SSHA      : RVPBinaryScalar_rr<0b110, 0b01, 0b010, "ssha">;
 
   def SSHAR     : RVPBinaryScalar_rr<0b111, 0b01, 0b010, "sshar">;
@@ -461,7 +461,7 @@ let Predicates = [HasStdExtP] in {
 
   def PSATI_H    : RVPShiftH_ri<0b110, 0b100, "psati.h">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def USATI_RV32 : RVPShiftW_ri<0b010, 0b100, "usati">;
 
   def SRARI_RV32 : RVPShiftW_ri<0b101, 0b100, "srari">;
@@ -542,7 +542,7 @@ let Predicates = [HasStdExtP] in {
   def PASUBU_H : RVPBinary_rr<0b1111, 0b00, 0b000, "pasubu.h">;
   def PASUBU_B : RVPBinary_rr<0b1111, 0b10, 0b000, "pasubu.b">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def SADD     : RVPBinary_rr<0b0010, 0b01, 0b000, "sadd">;
 
   def AADD     : RVPBinary_rr<0b0011, 0b01, 0b000, "aadd">;
@@ -558,7 +558,7 @@ let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
   def SSUBU    : RVPBinary_rr<0b1110, 0b01, 0b000, "ssubu">;
 
   def ASUBU    : RVPBinary_rr<0b1111, 0b01, 0b000, "asubu">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PADD_W   : RVPBinary_rr<0b0000, 0b01, 0b000, "padd.w">;
 
@@ -596,7 +596,7 @@ let Predicates = [HasStdExtP] in {
 
   def PDIFSUMAU_B  : RVPTernary_rrr<0b0111, 0b10, 0b001, "pdifsumau.b">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def MUL_H01      : RVPBinary_rr<0b0010, 0b01, 0b001, "mul.h01">;
 
   def MACC_H01     : RVPTernary_rrr<0b0011, 0b01, 0b001, "macc.h01">;
@@ -604,7 +604,7 @@ let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
   def MULU_H01     : RVPBinary_rr<0b0110, 0b01, 0b001, "mulu.h01">;
 
   def MACCU_H01    : RVPTernary_rrr<0b0111, 0b01, 0b001, "maccu.h01">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PMUL_W_H01   : RVPBinary_rr<0b0010, 0b01, 0b001, "pmul.w.h01">;
   def MUL_W01      : RVPBinary_rr<0b0010, 0b11, 0b001, "mul.w01">;
@@ -626,9 +626,9 @@ let Predicates = [HasStdExtP] in {
 
   def PSSH1SADD_H : RVPBinary_rr<0b0110, 0b00, 0b010, "pssh1sadd.h">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def SSH1SADD    : RVPBinary_rr<0b0110, 0b01, 0b010, "ssh1sadd">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PSH1ADD_W   : RVPBinary_rr<0b0100, 0b01, 0b010, "psh1add.w">;
 
@@ -658,7 +658,7 @@ let Predicates = [HasStdExtP] in {
 
   def PMULSU_H_B11  : RVPBinary_rr<0b1110, 0b00, 0b011, "pmulsu.h.b11">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def MUL_H00       : RVPBinary_rr<0b0000, 0b01, 0b011, "mul.h00">;
 
   def MACC_H00      : RVPTernary_rrr<0b0001, 0b01, 0b011, "macc.h00">;
@@ -682,7 +682,7 @@ let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
   def MULSU_H11     : RVPBinary_rr<0b1110, 0b01, 0b011, "mulsu.h11">;
 
   def MACCSU_H11    : RVPTernary_rrr<0b1111, 0b01, 0b011, "maccsu.h11">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PMUL_W_H00    : RVPBinary_rr<0b0000, 0b01, 0b011, "pmul.w.h00">;
   def MUL_W00       : RVPBinary_rr<0b0000, 0b11, 0b011, "mul.w00">;
@@ -732,13 +732,13 @@ let Predicates = [HasStdExtP] in {
 
   def PPACKT_H    : RVPBinary_rr<0b0110, 0b00, 0b100, "ppackt.h">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def PACKBT_RV32 : RVPBinary_rr<0b0010, 0b01, 0b100, "packbt">;
 
   def PACKTB_RV32 : RVPBinary_rr<0b0100, 0b01, 0b100, "packtb">;
 
   def PACKT_RV32  : RVPBinary_rr<0b0110, 0b01, 0b100, "packt">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PPACK_W     : RVPBinary_rr<0b0000, 0b01, 0b100, "ppack.w">;
 
@@ -791,10 +791,10 @@ let Predicates = [HasStdExtP] in {
   def PM2ADDASU_H : RVPBinary_rr<0b1101, 0b00, 0b101, "pm2addasu.h">;
   def PM4ADDASU_B : RVPBinary_rr<0b1101, 0b10, 0b101, "pm4addasu.b">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def MQACC_H01  : RVPTernary_rrr<0b1111, 0b00, 0b101, "mqacc.h01">;
   def MQRACC_H01 : RVPTernary_rrr<0b1111, 0b10, 0b101, "mqracc.h01">;
-} // // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PM2ADD_W      : RVPBinary_rr<0b0000, 0b01, 0b101, "pm2add.w">;
   def PM4ADD_H      : RVPBinary_rr<0b0000, 0b11, 0b101, "pm4add.h">;
@@ -870,13 +870,13 @@ let Predicates = [HasStdExtP] in {
   def PMAXU_H  : RVPBinary_rr<0b1111, 0b00, 0b110, "pmaxu.h">;
   def PMAXU_B  : RVPBinary_rr<0b1111, 0b10, 0b110, "pmaxu.b">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def MSEQ  : RVPBinary_rr<0b1000, 0b01, 0b110, "mseq">;
 
   def MSLT  : RVPBinary_rr<0b1010, 0b01, 0b110, "mslt">;
 
   def MSLTU : RVPBinary_rr<0b1011, 0b01, 0b110, "msltu">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 let Predicates = [HasStdExtP, IsRV64] in {
   def PAS_WX   : RVPBinary_rr<0b0000, 0b01, 0b110, "pas.wx">;
   def PSA_WX   : RVPBinary_rr<0b0000, 0b11, 0b110, "psa.wx">;
@@ -936,7 +936,7 @@ let Predicates = [HasStdExtP] in {
   def PMULQ_H       : RVPBinary_rr<0b1010, 0b00, 0b111, "pmulq.h">;
   def PMULQR_H      : RVPBinary_rr<0b1010, 0b10, 0b111, "pmulqr.h">;
 } // Predicates = [HasStdExtP]
-let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
   def MULHR      : RVPBinary_rr<0b0000, 0b11, 0b111, "mulhr">;
 
   def MHACC      : RVPTernary_rrr<0b0001, 0b01, 0b111, "mhacc">;
@@ -972,7 +972,7 @@ let Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in {
 
   def MQACC_H11  : RVPTernary_rrr<0b1111, 0b00, 0b111, "mqacc.h11">;
   def MQRACC_H11 : RVPTernary_rrr<0b1111, 0b10, 0b111, "mqracc.h11">;
-} // Predicates = [HasStdExtP, IsRV32], DecoderNamespace = "RV32Only" in
+} // Predicates = [HasStdExtP, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in
 let Predicates = [HasStdExtP, IsRV64] in {
   def PMULH_W       : RVPBinary_rr<0b0000, 0b01, 0b111, "pmulh.w">;
   def PMULHR_W      : RVPBinary_rr<0b0000, 0b11, 0b111, "pmulhr.w">;
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td
index 7cf6d5ff762ff..5affd1aa47d4a 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZa.td
@@ -59,7 +59,7 @@ let Predicates = [HasStdExtZacas], IsSignExtendingOpW = 1 in {
 defm AMOCAS_W : AMO_cas_aq_rl<0b00101, 0b010, "amocas.w", GPR>;
 } // Predicates = [HasStdExtZacas]
 
-let Predicates = [HasStdExtZacas, IsRV32], DecoderNamespace = "RV32Only"  in {
+let Predicates = [HasStdExtZacas, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
 defm AMOCAS_D_RV32 : AMO_cas_aq_rl<0b00101, 0b011, "amocas.d", GPRPairRV32>;
 } // Predicates = [HasStdExtZacas, IsRV32]
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
index ed1a60aa49cab..6b80b552b6e53 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZc.td
@@ -216,7 +216,7 @@ def C_SH_INX : CStoreH_rri<0b100011, 0b0, "c.sh", GPRF16C>,
 } // Predicates = [HasStdExtZcb]
 
 // Zcmp
-let DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmp],
+let DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmp],
     hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
 let Defs = [X10, X11] in
 def CM_MVA01S : RVInst16CA<0b101011, 0b11, 0b10, (outs),
@@ -227,9 +227,9 @@ let Uses = [X10, X11] in
 def CM_MVSA01 : RVInst16CA<0b101011, 0b01, 0b10, (outs SR07:$rs1, SR07:$rs2),
                             (ins), "cm.mvsa01", "$rs1, $rs2">,
                 Sched<[WriteIALU, WriteIALU, ReadIALU, ReadIALU]>;
-} // DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmp]...
+} // DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmp]...
 
-let DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmp] in {
+let DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmp] in {
 let hasSideEffects = 0, mayLoad = 0, mayStore = 1, Uses = [X2], Defs = [X2] in
 def CM_PUSH : RVInstZcCPPP<0b11000, "cm.push", negstackadj>,
               Sched<[WriteIALU, ReadIALU, ReadStoreData, ReadStoreData,
@@ -258,9 +258,9 @@ def CM_POP : RVInstZcCPPP<0b11010, "cm.pop">,
              Sched<[WriteIALU, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                     WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW, WriteLDW,
                     WriteLDW, WriteLDW, WriteLDW, ReadIALU]>;
-} // DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmp]...
+} // DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmp]...
 
-let DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmt],
+let DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmt],
     hasSideEffects = 0, mayLoad = 0, mayStore = 0 in {
 def CM_JT : RVInst16CJ<0b101, 0b10, (outs), (ins uimm5:$index),
                        "cm.jt", "$index">{
@@ -278,7 +278,7 @@ def CM_JALT : RVInst16CJ<0b101, 0b10, (outs), (ins uimm8ge32:$index),
   let Inst{12-10} = 0b000;
   let Inst{9-2} = index;
 }
-} // DecoderNamespace = "ZcOverlap", Predicates = [HasStdExtZcmt]...
+} // DecodeOrder = DecodeOrderZcOverlap, Predicates = [HasStdExtZcmt]...
 
 
 let Predicates = [HasStdExtZcb, HasStdExtZmmul] in{
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZclsd.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZclsd.td
index 962ad3c5a3151..1e6ffc8fe0488 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZclsd.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZclsd.td
@@ -41,7 +41,8 @@ def GPRPairCRV32 : RegisterOperand<GPRPairC> {
 // Instructions
 //===----------------------------------------------------------------------===//
 
-let Predicates = [HasStdExtZclsd, IsRV32], DecoderNamespace = "ZcOverlap" in {
+let Predicates = [HasStdExtZclsd, IsRV32],
+    DecodeOrder = DecodeOrderZcOverlap in {
 def C_LDSP_RV32 : CStackLoad<0b011, "c.ldsp", GPRPairNoX0RV32, uimm9_lsb000>,
                   Sched<[WriteLDD, ReadMemBase]> {
   let Inst{4-2} = imm{8-6};
@@ -65,7 +66,7 @@ def C_SD_RV32 : CStore_rri<0b111, "c.sd", GPRPairCRV32, uimm8_lsb000>,
   let Inst{12-10} = imm{5-3};
   let Inst{6-5} = imm{7-6};
 }
-}// Predicates = [HasStdExtZclsd, IsRV32], DecoderNamespace = "ZcOverlap"
+}// Predicates = [HasStdExtZclsd, IsRV32], DecodeOrder = DecodeOrderZcOverlap
 
 //===----------------------------------------------------------------------===//
 // Assembler Pseudo Instructions
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
index 50ebaa9951979..286e2bf722531 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZicfiss.td
@@ -48,7 +48,7 @@ def SSPUSH : RVInstR<0b1100111, 0b100, OPC_SYSTEM, (outs), (ins GPRX1X5:$rs2),
 } // Predicates = [HasStdExtZicfiss]
 
 let Predicates = [HasStdExtZicfiss, HasStdExtZcmop],
-    DecoderNamespace = "Zicfiss" in {
+    DecodeOrder = DecodeOrderZicfiss16 in {
 let Uses = [SSP], Defs = [SSP], hasSideEffects = 0, mayLoad = 0, mayStore = 1 in
 def C_SSPUSH : RVC_SSInst<0b00001, GPRX1, "c.sspush">;
 
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
index a3203f288b545..a6f58e06b7362 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZilsd.td
@@ -33,11 +33,11 @@ def riscv_st_rv32 : RVSDNode<"SD_RV32", SDT_RISCV_SD_RV32,
 // Instructions
 //===----------------------------------------------------------------------===//
 
-let Predicates = [HasStdExtZilsd, IsRV32], DecoderNamespace = "RV32Only" in {
+let Predicates = [HasStdExtZilsd, IsRV32], DecodeOrder = DecodeOrderRV32Only32 in {
 def LD_RV32 : Load_ri<0b011, "ld", GPRPairRV32>, Sched<[WriteLDD, ReadMemBase]>;
 def SD_RV32 : Store_rri<0b011, "sd", GPRPairRV32>,
               Sched<[WriteSTD, ReadStoreData, ReadMemBase]>;
-} // Predicates = [HasStdExtZilsd, IsRV32], DecoderNamespace = "RV32Only"
+} // Predicates = [HasStdExtZilsd, IsRV32], DecodeOrder = DecodeOrderRV32Only32
 
 //===----------------------------------------------------------------------===//
 // Assembler Pseudo Instructions
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 8747d02ac892b..5cf5dd93fbed5 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -116,6 +116,11 @@ static cl::opt<bool> IgnoreFullyDefinedOperands(
         "Do not automatically decode operands with no '?' in their encoding."),
     cl::init(false), cl::cat(DisassemblerEmitterCat));
 
+static cl::opt<bool> ResolveConflictsTryAll(
+    "resolve-conflicts-try-all",
+    cl::desc("Resolve conflicts by attempting to decode all candidates."),
+    cl::init(false), cl::cat(DisassemblerEmitterCat));
+
 STATISTIC(NumEncodings, "Number of encodings considered");
 STATISTIC(NumEncodingsLackingDisasm,
           "Number of encodings without disassembler info");
@@ -188,6 +193,9 @@ class InstructionEncoding {
   /// The namespace in which this encoding exists.
   StringRef DecoderNamespace;
 
+  /// The decoder order.
+  int64_t DecodeOrder;
+
   /// Known bits of this encoding. This is the value of the `Inst` field
   /// with any variable references replaced with '?'.
   KnownBits InstBits;
@@ -224,6 +232,9 @@ class InstructionEncoding {
   /// Returns the namespace in which this encoding exists.
   StringRef getDecoderNamespace() const { return DecoderNamespace; }
 
+  /// Returns the decoder order for this encoding.
+  int64_t getDecodeOrder() const { return DecodeOrder; }
+
   /// Returns the size of this encoding, in bits.
   unsigned getBitWidth() const { return InstBits.getBitWidth(); }
 
@@ -263,16 +274,20 @@ class InstructionEncoding {
   void parseFixedLenOperands(const BitsInit &Bits);
 };
 
-/// Sorting predicate to sort encoding IDs by encoding width.
-class LessEncodingIDByWidth {
+/// Sorting predicate to sort encoding IDs by encoding width. Within the same
+/// width, sort them by their decode order.
+class LessEncodingID {
   ArrayRef<InstructionEncoding> Encodings;
 
 public:
-  explicit LessEncodingIDByWidth(ArrayRef<InstructionEncoding> Encodings)
+  explicit LessEncodingID(ArrayRef<InstructionEncoding> Encodings)
       : Encodings(Encodings) {}
 
   bool operator()(unsigned ID1, unsigned ID2) const {
-    return Encodings[ID1].getBitWidth() < Encodings[ID2].getBitWidth();
+    const InstructionEncoding &E1 = Encodings[ID1];
+    const InstructionEncoding &E2 = Encodings[ID2];
+    return std::tuple(E1.getBitWidth(), E1.getDecodeOrder()) <
+           std::tuple(E2.getBitWidth(), E2.getDecodeOrder());
   }
 };
 
@@ -517,6 +532,13 @@ class FilterChooser {
   /// The "field value" here refers to the encoding bits in the filtered range.
   std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
 
+  /// Per decode order filter choosers. Applicable when the set of candidates
+  /// have more than 1 decode order.
+  SmallVector<std::unique_ptr<const FilterChooser>> PerDecodeOrderChoosers;
+
+  /// Handle this chooser by attempting to decode all endodings.
+  bool AttemptAll = false;
+
   /// Set to true if decoding conflict was encountered.
   bool HasConflict = false;
 
@@ -532,7 +554,7 @@ class FilterChooser {
                 ArrayRef<unsigned> EncodingIDs)
       : Encodings(Encodings), EncodingIDs(EncodingIDs), Parent(nullptr) {
     // Sort encoding IDs once.
-    stable_sort(this->EncodingIDs, LessEncodingIDByWidth(Encodings));
+    stable_sort(this->EncodingIDs, LessEncodingID(Encodings));
     // Filter width is the width of the smallest encoding.
     unsigned FilterWidth = Encodings[this->EncodingIDs.front()].getBitWidth();
     FilterBits = KnownBits(FilterWidth);
@@ -545,7 +567,7 @@ class FilterChooser {
                 const FilterChooser &Parent)
       : Encodings(Encodings), EncodingIDs(EncodingIDs), Parent(&Parent) {
     // Inferior filter choosers are created from sorted array of encoding IDs.
-    assert(is_sorted(EncodingIDs, LessEncodingIDByWidth(Encodings)));
+    assert(is_sorted(EncodingIDs, LessEncodingID(Encodings)));
     assert(!FilterBits.hasConflict() && "Broken filter");
     // Filter width is the width of the smallest encoding.
     unsigned FilterWidth = Encodings[EncodingIDs.front()].getBitWidth();
@@ -584,6 +606,17 @@ class FilterChooser {
   // decoded bits in order to verify that the instruction matches the Opcode.
   std::vector<Island> getIslands(const KnownBits &EncodingBits) const;
 
+  int64_t getDecodeOrder(unsigned ID) const {
+    return Encodings[ID].getDecodeOrder();
+  }
+
+  /// Returns true if the set of encoding IDs have more than one decode order.
+  bool hasMultipleDecodeOrders() const;
+
+  // Split the set of candidate encodings into one bucket per decode order and
+  // create inferior FilterChoosers per bucket.
+  void splitByDecodeOrder();
+
   /// Scans the well-known encoding bits of the encodings and, builds up a list
   /// of candidate filters, and then returns the best one, if any.
   std::unique_ptr<Filter> findBestFilter(ArrayRef<bitAttr_t> BitAttrs,
@@ -685,6 +718,44 @@ void FilterChooser::applyFilter(const Filter &F) {
   NumBits = F.NumBits;
   assert(FilterBits.extractBits(NumBits, StartBit).isUnknown());
 
+  // When a filter has both fixed and variable encodings, we give priority to
+  // the fixed encoding (FilteredIDs) and if that fails, we attempt the variable
+  // encodings. See DecoderTableBuilder::emitTableEntries. This order may not be
+  // the right order for certain backends. To control this, they can use the
+  // DecodeOrder. If we have multiple decode orders, the filter chooser will
+  // attempt the fixed-then-variable encoding per decode order, so if we want
+  // certain variable encoding to be prioritized over fixed ones, the fixed ones
+  // can get a larger decode order.
+
+  // If we have multiple decode order, we want to attempt decoding in the
+  // following order: fixed0, variable0, fixed1, variable1 etc.
+  // If we do not split, we will attempt to decode as: fixed, variable.
+  // That may be ok if all fixed IDs have decode order <= all variable IDs, that
+  // is max(fixed decode order) <= min(variable decode order). Otherwise we
+  // split per decode order.
+  if (hasMultipleDecodeOrders() && !F.VariableIDs.empty() &&
+      !F.FilteredIDs.empty()) {
+    auto LessDecodeOrder = [&](unsigned A, unsigned B) {
+      return getDecodeOrder(A) < getDecodeOrder(B);
+    };
+
+    int64_t MaxFixedOrder = std::numeric_limits<int64_t>::min();
+    for (ArrayRef<unsigned> InferiorEncodingIDs :
+         make_second_range(F.FilteredIDs)) {
+      auto MaxIt = llvm::max_element(InferiorEncodingIDs, LessDecodeOrder);
+      int64_t CurrentMax = getDecodeOrder(*MaxIt);
+      MaxFixedOrder = std::max(MaxFixedOrder, CurrentMax);
+    }
+
+    auto MinIt = llvm::min_element(F.VariableIDs, LessDecodeOrder);
+    int64_t MinVariableOrder = getDecodeOrder(*MinIt);
+
+    if (MaxFixedOrder > MinVariableOrder) {
+      splitByDecodeOrder();
+      return;
+    }
+  }
+
   if (!F.VariableIDs.empty()) {
     // Delegates to an inferior filter chooser for further processing on this
     // group of instructions whose segment values are variable.
@@ -1580,6 +1651,42 @@ std::unique_ptr<Filter> FilterChooser::findBestFilter() const {
   return nullptr;
 }
 
+bool FilterChooser::hasMultipleDecodeOrders() const {
+  if (EncodingIDs.size() <= 1)
+    return false;
+  // Encodings are sorted by decoder order, so there are multiple decode orders
+  // if the first and last decode order do not match.
+  return getDecodeOrder(EncodingIDs.front()) !=
+         getDecodeOrder(EncodingIDs.back());
+}
+
+void FilterChooser::splitByDecodeOrder() {
+  if (!hasMultipleDecodeOrders())
+    PrintFatalError("Cannot split by decode orders for a single decode order");
+
+  // Create one inferior FilterChooser per decode order span.
+  ArrayRef<unsigned> IDs = ArrayRef(EncodingIDs);
+  int64_t LastOrder = getDecodeOrder(IDs.front());
+  size_t LastIndex = 0;
+  // Note: first iteration here is redundant, but this allows us to keep Idx
+  // value correct.
+  for (const auto &[Idx, ID] : enumerate(IDs)) {
+    int64_t CurrentOrder = getDecodeOrder(ID);
+    if (CurrentOrder != LastOrder) {
+      ArrayRef<unsigned> SubIDs = IDs.slice(LastIndex, Idx - LastIndex);
+      PerDecodeOrderChoosers.push_back(std::make_unique<FilterChooser>(
+          Encodings, SubIDs, FilterBits, *this));
+      LastOrder = CurrentOrder;
+      LastIndex = Idx;
+    }
+  }
+
+  // Finish the last span.
+  ArrayRef<unsigned> SubIDs = IDs.slice(LastIndex, IDs.size() - LastIndex);
+  PerDecodeOrderChoosers.push_back(
+      std::make_unique<FilterChooser>(Encodings, SubIDs, FilterBits, *this));
+}
+
 // Decides on the best configuration of filter(s) to use in order to decode
 // the instructions.  A conflict of instructions may occur, in which case we
 // dump the conflict set to the standard error.
@@ -1598,6 +1705,18 @@ void FilterChooser::doFilter() {
     return;
   }
 
+  // If there are multiple decode orders, then splin the candidates by decode
+  // order if we are unable to find a filter.
+  if (hasMultipleDecodeOrders()) {
+    splitByDecodeOrder();
+    return;
+  }
+
+  if (ResolveConflictsTryAll) {
+    AttemptAll = true;
+    return;
+  }
+
   // Print out useful conflict information for postmortem analysis.
   errs() << "Decoding Conflict:\n";
   dump();
@@ -1626,10 +1745,10 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
 
   // If there are other encodings that could match if those with all bits
   // known don't, enter a scope so that they have a chance.
-  size_t FixupLoc = 0;
+  size_t VarScopeFixupLoc = 0;
   if (FC.VariableFC) {
     Table.insertOpcode(MCD::OPC_Scope);
-    FixupLoc = Table.insertNumToSkip();
+    VarScopeFixupLoc = Table.insertNumToSkip();
   }
 
   if (FC.SingletonEncodingID) {
@@ -1649,7 +1768,7 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
 
     // Emit table entries for the only case.
     emitTableEntries(*Delegate);
-  } else {
+  } else if (FC.FilterChooserMap.size() > 1) {
     // The general case: emit a switch over the field value.
     Table.insertOpcode(MCD::OPC_ExtractField);
     Table.insertULEB128(FC.StartBit);
@@ -1676,10 +1795,34 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
 
     // Emit table entries for the last case.
     emitTableEntries(*Delegate);
+  } else if (FC.PerDecodeOrderChoosers.size() > 1) {
+    // Attempt to decode all inferior choosers and allow them to fail, except
+    // the last one.
+    for (const auto &Delegate : drop_end(FC.PerDecodeOrderChoosers)) {
+      Table.insertOpcode(MCD::OPC_Scope);
+      unsigned FixupLoc = Table.insertNumToSkip();
+      emitTableEntries(*Delegate);
+      Table.patchNumToSkip(FixupLoc, Table.size());
+    }
+    emitTableEntries(*FC.PerDecodeOrderChoosers.back());
+  } else if (FC.AttemptAll) {
+    // Attempt all encoding and allow them to fail, except the last one.
+    for (const auto ID : drop_end(FC.EncodingIDs)) {
+      Table.insertOpcode(MCD::OPC_Scope);
+      unsigned FixupLoc = Table.insertNumToSkip();
+      FilterChooser SingletonFC(FC.Encodings, ID, FC.FilterBits, *FC.Parent);
+      emitSingletonTableEntry(SingletonFC);
+      Table.patchNumToSkip(FixupLoc, Table.size());
+    }
+    FilterChooser LastSingletonFC(FC.Encodings, FC.EncodingIDs.back(),
+                                  FC.FilterBits, *FC.Parent);
+    emitSingletonTableEntry(LastSingletonFC);
+  } else {
+    llvm_unreachable("FilterChooser not setup to do any filtering");
   }
 
   if (FC.VariableFC) {
-    Table.patchNumToSkip(FixupLoc, Table.size());
+    Table.patchNumToSkip(VarScopeFixupLoc, Table.size());
     emitTableEntries(*FC.VariableFC);
   }
 }
@@ -2070,6 +2213,7 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef,
   Name.append(InstDef->getName());
 
   DecoderNamespace = EncodingDef->getValueAsString("DecoderNamespace");
+  DecodeOrder = EncodingDef->getValueAsInt("DecodeOrder");
   DecoderMethod = EncodingDef->getValueAsString("DecoderMethod");
   if (!DecoderMethod.empty())
     HasCompleteDecoder = EncodingDef->getValueAsBit("hasCompleteDecoder");

>From ee404cb3d6e2bc4f902e7828b7e9d643342a8d64 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 10 Sep 2025 15:39:03 -0700
Subject: [PATCH 2/5] Rework some comments

---
 llvm/utils/TableGen/DecoderEmitter.cpp | 50 ++++++++++++++++----------
 1 file changed, 31 insertions(+), 19 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 5cf5dd93fbed5..1265850910cfe 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -193,7 +193,7 @@ class InstructionEncoding {
   /// The namespace in which this encoding exists.
   StringRef DecoderNamespace;
 
-  /// The decoder order.
+  /// The decode order.
   int64_t DecodeOrder;
 
   /// Known bits of this encoding. This is the value of the `Inst` field
@@ -232,7 +232,7 @@ class InstructionEncoding {
   /// Returns the namespace in which this encoding exists.
   StringRef getDecoderNamespace() const { return DecoderNamespace; }
 
-  /// Returns the decoder order for this encoding.
+  /// Returns the decode order for this encoding.
   int64_t getDecodeOrder() const { return DecodeOrder; }
 
   /// Returns the size of this encoding, in bits.
@@ -533,7 +533,7 @@ class FilterChooser {
   std::map<uint64_t, std::unique_ptr<const FilterChooser>> FilterChooserMap;
 
   /// Per decode order filter choosers. Applicable when the set of candidates
-  /// have more than 1 decode order.
+  /// have more than 1 decode orders.
   SmallVector<std::unique_ptr<const FilterChooser>> PerDecodeOrderChoosers;
 
   /// Handle this chooser by attempting to decode all endodings.
@@ -606,6 +606,7 @@ class FilterChooser {
   // decoded bits in order to verify that the instruction matches the Opcode.
   std::vector<Island> getIslands(const KnownBits &EncodingBits) const;
 
+  // Returns the decode order for the given encoding ID.
   int64_t getDecodeOrder(unsigned ID) const {
     return Encodings[ID].getDecodeOrder();
   }
@@ -721,18 +722,25 @@ void FilterChooser::applyFilter(const Filter &F) {
   // When a filter has both fixed and variable encodings, we give priority to
   // the fixed encoding (FilteredIDs) and if that fails, we attempt the variable
   // encodings. See DecoderTableBuilder::emitTableEntries. This order may not be
-  // the right order for certain backends. To control this, they can use the
+  // the right order for certain targets. To control this, they can use the
   // DecodeOrder. If we have multiple decode orders, the filter chooser will
-  // attempt the fixed-then-variable encoding per decode order, so if we want
-  // certain variable encoding to be prioritized over fixed ones, the fixed ones
-  // can get a larger decode order.
-
-  // If we have multiple decode order, we want to attempt decoding in the
-  // following order: fixed0, variable0, fixed1, variable1 etc.
-  // If we do not split, we will attempt to decode as: fixed, variable.
-  // That may be ok if all fixed IDs have decode order <= all variable IDs, that
-  // is max(fixed decode order) <= min(variable decode order). Otherwise we
-  // split per decode order.
+  // effectively attempt the fixed-then-variable encoding per decode order. This
+  // allows targets to prioritize certain variable encoding over fixed ones by
+  // assigning the fixed ones a larger decode order.
+
+  // If we always split per decode order, we get the following attempt order
+  //   f[0] -> v[0] -> f[1] -> v[1]
+  //
+  // However, instead of always splitting a chooser with multiple decode orders
+  // we can split only when necessary and only the smallest number of splits
+  // as long as we effectively get the same attempt order as above. As an
+  // example, if the max decode order among the fixed encoding is <= min
+  // decode order among varying encoding, then even if we do not split, we get
+  // the same effective attempt order. This simple criteria is implemented
+  // below (i.e, we fully split when this criteria is not met). There may be
+  // more refined ways to do the decode order splitting. For example, not
+  // splitting all the decode orders fully put doing partial splits. This can
+  // be implemented in future as an optimization if desired.
   if (hasMultipleDecodeOrders() && !F.VariableIDs.empty() &&
       !F.FilteredIDs.empty()) {
     auto LessDecodeOrder = [&](unsigned A, unsigned B) {
@@ -1654,7 +1662,7 @@ std::unique_ptr<Filter> FilterChooser::findBestFilter() const {
 bool FilterChooser::hasMultipleDecodeOrders() const {
   if (EncodingIDs.size() <= 1)
     return false;
-  // Encodings are sorted by decoder order, so there are multiple decode orders
+  // Encodings are sorted by decode order, so there are multiple decode orders
   // if the first and last decode order do not match.
   return getDecodeOrder(EncodingIDs.front()) !=
          getDecodeOrder(EncodingIDs.back());
@@ -1669,7 +1677,7 @@ void FilterChooser::splitByDecodeOrder() {
   int64_t LastOrder = getDecodeOrder(IDs.front());
   size_t LastIndex = 0;
   // Note: first iteration here is redundant, but this allows us to keep Idx
-  // value correct.
+  // value correct (as opposed to using Idx + 1).
   for (const auto &[Idx, ID] : enumerate(IDs)) {
     int64_t CurrentOrder = getDecodeOrder(ID);
     if (CurrentOrder != LastOrder) {
@@ -1705,8 +1713,9 @@ void FilterChooser::doFilter() {
     return;
   }
 
-  // If there are multiple decode orders, then splin the candidates by decode
-  // order if we are unable to find a filter.
+  // If we were unable to find a useful filter and there are multiple decode
+  // orders involved, split the candidates by decode order and create per decode
+  // order choosers.
   if (hasMultipleDecodeOrders()) {
     splitByDecodeOrder();
     return;
@@ -1797,7 +1806,8 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
     emitTableEntries(*Delegate);
   } else if (FC.PerDecodeOrderChoosers.size() > 1) {
     // Attempt to decode all inferior choosers and allow them to fail, except
-    // the last one.
+    // the last one. Note that `PerDecodeOrderChoosers` when preset is expected
+    // to have atleast 2 entries, hence the size() > 1 check above.
     for (const auto &Delegate : drop_end(FC.PerDecodeOrderChoosers)) {
       Table.insertOpcode(MCD::OPC_Scope);
       unsigned FixupLoc = Table.insertNumToSkip();
@@ -1807,6 +1817,8 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
     emitTableEntries(*FC.PerDecodeOrderChoosers.back());
   } else if (FC.AttemptAll) {
     // Attempt all encoding and allow them to fail, except the last one.
+    // We expect here to have > 1 EncodingIDs, else we could have created a
+    // singleton chooser.
     for (const auto ID : drop_end(FC.EncodingIDs)) {
       Table.insertOpcode(MCD::OPC_Scope);
       unsigned FixupLoc = Table.insertNumToSkip();

>From bc83e8193fc1ef5f21a70806e6a9f9a345d49a0d Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Wed, 10 Sep 2025 17:58:34 -0700
Subject: [PATCH 3/5] Print decode order when dumping

---
 llvm/utils/TableGen/DecoderEmitter.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index 1265850910cfe..b4305cf6cd66f 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -1740,12 +1740,17 @@ void FilterChooser::dump() const {
   // Dump filter stack.
   dumpStack(errs(), Indent, PadToWidth);
 
+  bool PrintDecoderOrder = hasMultipleDecodeOrders();
+
   // Dump encodings.
   for (unsigned EncodingID : EncodingIDs) {
     const InstructionEncoding &Encoding = Encodings[EncodingID];
     errs() << Indent << indent(PadToWidth - Encoding.getBitWidth());
     printKnownBits(errs(), Encoding.getMandatoryBits(), '_');
-    errs() << "  " << Encoding.getName() << '\n';
+    errs() << "  " << Encoding.getName();
+    if (PrintDecoderOrder)
+      errs() << " (" << Encoding.getDecodeOrder() << ")";
+    errs() << '\n';
   }
 }
 

>From b6ea8cec04601c4007e48f3c5f719bdaffde8d8c Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 11 Sep 2025 00:24:36 -0700
Subject: [PATCH 4/5] Fix resolve-conflicts-try-all using a non-failing scope,
 adopt it for RISCV 16 bit insts

---
 llvm/include/llvm/MC/MCDecoderOps.h     |   1 +
 llvm/lib/Target/RISCV/CMakeLists.txt    |   2 +-
 llvm/lib/Target/RISCV/RISCVInstrInfo.td |   4 +-
 llvm/utils/TableGen/DecoderEmitter.cpp  | 102 ++++++++++++++++++------
 4 files changed, 80 insertions(+), 29 deletions(-)

diff --git a/llvm/include/llvm/MC/MCDecoderOps.h b/llvm/include/llvm/MC/MCDecoderOps.h
index 790ff3eb4f333..3636748f5924b 100644
--- a/llvm/include/llvm/MC/MCDecoderOps.h
+++ b/llvm/include/llvm/MC/MCDecoderOps.h
@@ -17,6 +17,7 @@ namespace llvm::MCD {
 // enabled.
 enum DecoderOps {
   OPC_Scope = 1,         // OPC_Scope(nts_t NumToSkip)
+  OPC_ScopeNoFail,       // OPC_ScopeNoFail(nts_t NumToSkip)
   OPC_ExtractField,      // OPC_ExtractField(uleb128 Start, uint8_t Len)
   OPC_FilterValueOrSkip, // OPC_FilterValueOrSkip(uleb128 Val, nts_t NumToSkip)
   OPC_FilterValue,       // OPC_FilterValue(uleb128 Val)
diff --git a/llvm/lib/Target/RISCV/CMakeLists.txt b/llvm/lib/Target/RISCV/CMakeLists.txt
index 0ff178e1f1959..7957176c3b6e7 100644
--- a/llvm/lib/Target/RISCV/CMakeLists.txt
+++ b/llvm/lib/Target/RISCV/CMakeLists.txt
@@ -8,7 +8,7 @@ tablegen(LLVM RISCVGenCompressInstEmitter.inc -gen-compress-inst-emitter)
 tablegen(LLVM RISCVGenMacroFusion.inc -gen-macro-fusion-pred)
 tablegen(LLVM RISCVGenDAGISel.inc -gen-dag-isel)
 tablegen(LLVM RISCVGenDisassemblerTables.inc -gen-disassembler
-              --specialize-decoders-per-bitwidth)
+              --specialize-decoders-per-bitwidth --resolve-conflicts-try-all)
 tablegen(LLVM RISCVGenInstrInfo.inc -gen-instr-info)
 tablegen(LLVM RISCVGenMCCodeEmitter.inc -gen-emitter)
 tablegen(LLVM RISCVGenMCPseudoLowering.inc -gen-pseudo-lowering)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 5c68e37eb552c..e48d2ebddc249 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -2318,8 +2318,8 @@ def : Pat<(int_riscv_pause), (FENCE 0x1, 0x0)>;
 
 // For 16 bit instructions.
 defvar DecodeOrderZicfiss16 = -1;
-defvar DecodeOrderRV32Only16 = 1;
-defvar DecodeOrderZcOverlap = 2;
+defvar DecodeOrderRV32Only16 = 0;//1;
+defvar DecodeOrderZcOverlap = 0;//2;
 
 // For 32-bit instructions.
 defvar DecodeOrderRV32Only32 = 1;
diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index b4305cf6cd66f..cb0f930170fd2 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -801,6 +801,26 @@ unsigned Filter::usefulness() const {
 //                              //
 //////////////////////////////////
 
+static StringRef getDecoderOpName(uint8_t Op) {
+  // clang-format off
+  static constexpr StringLiteral Names[] = {
+    "OPC_Scope",
+    "OPC_ScopeNoFail",
+    "OPC_ExtractField",
+    "OPC_FilterValueOrSkip",
+    "OPC_FilterValue",
+    "OPC_CheckField",
+    "OPC_CheckPredicate",
+    "OPC_Decode",
+    "OPC_TryDecode",
+    "OPC_SoftFail",
+  };
+  // clang-format on
+  if (Op >= MCD::OPC_Scope && Op <= MCD::OPC_SoftFail)
+    return Names[Op - MCD::OPC_Scope];
+  llvm_unreachable("Unknown decoder op");
+}
+
 // Emit the decoder state machine table. Returns a mask of MCD decoder ops
 // that were emitted.
 unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
@@ -880,20 +900,19 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
 
     const uint8_t DecoderOp = *I++;
     OpcodeMask |= (1 << DecoderOp);
+    OS << "  MCD::" << getDecoderOpName(DecoderOp) << ", ";
     switch (DecoderOp) {
     default:
       PrintFatalError("Invalid decode table opcode: " + Twine((int)DecoderOp) +
                       " at index " + Twine(Pos));
-    case MCD::OPC_Scope: {
-      OS << "  MCD::OPC_Scope, ";
+    case MCD::OPC_Scope:
+    case MCD::OPC_ScopeNoFail: {
       uint32_t NumToSkip = emitNumToSkip(I, OS);
       emitNumToSkipComment(NumToSkip);
       OS << '\n';
       break;
     }
     case MCD::OPC_ExtractField: {
-      OS << "  MCD::OPC_ExtractField, ";
-
       // ULEB128 encoded start value.
       const char *ErrMsg = nullptr;
       unsigned Start = decodeULEB128(&*I, nullptr, EndPtr, &ErrMsg);
@@ -908,7 +927,6 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
       break;
     }
     case MCD::OPC_FilterValueOrSkip: {
-      OS << "  MCD::OPC_FilterValueOrSkip, ";
       // The filter value is ULEB128 encoded.
       emitULEB128(I, OS);
       uint32_t NumToSkip = emitNumToSkip(I, OS);
@@ -917,14 +935,12 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
       break;
     }
     case MCD::OPC_FilterValue: {
-      OS << "  MCD::OPC_FilterValue, ";
       // The filter value is ULEB128 encoded.
       emitULEB128(I, OS);
       OS << '\n';
       break;
     }
     case MCD::OPC_CheckField: {
-      OS << "  MCD::OPC_CheckField, ";
       // ULEB128 encoded start value.
       emitULEB128(I, OS);
       // 8-bit length.
@@ -936,7 +952,6 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
       break;
     }
     case MCD::OPC_CheckPredicate: {
-      OS << "  MCD::OPC_CheckPredicate, ";
       emitULEB128(I, OS);
       OS << '\n';
       break;
@@ -949,7 +964,6 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
       unsigned Opc = decodeULEB128(&*I, nullptr, EndPtr, &ErrMsg);
       assert(ErrMsg == nullptr && "ULEB128 value too large!");
 
-      OS << "  MCD::OPC_" << (IsTry ? "Try" : "") << "Decode, ";
       emitULEB128(I, OS);
 
       // Decoder index.
@@ -970,7 +984,6 @@ unsigned DecoderEmitter::emitTable(formatted_raw_ostream &OS,
       break;
     }
     case MCD::OPC_SoftFail: {
-      OS << "  MCD::OPC_SoftFail, ";
       // Decode the positive mask.
       const char *ErrMsg = nullptr;
       uint64_t PositiveMask = decodeULEB128(&*I, nullptr, EndPtr, &ErrMsg);
@@ -1814,7 +1827,7 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
     // the last one. Note that `PerDecodeOrderChoosers` when preset is expected
     // to have atleast 2 entries, hence the size() > 1 check above.
     for (const auto &Delegate : drop_end(FC.PerDecodeOrderChoosers)) {
-      Table.insertOpcode(MCD::OPC_Scope);
+      Table.insertOpcode(MCD::OPC_ScopeNoFail);
       unsigned FixupLoc = Table.insertNumToSkip();
       emitTableEntries(*Delegate);
       Table.patchNumToSkip(FixupLoc, Table.size());
@@ -1825,7 +1838,7 @@ void DecoderTableBuilder::emitTableEntries(const FilterChooser &FC) const {
     // We expect here to have > 1 EncodingIDs, else we could have created a
     // singleton chooser.
     for (const auto ID : drop_end(FC.EncodingIDs)) {
-      Table.insertOpcode(MCD::OPC_Scope);
+      Table.insertOpcode(MCD::OPC_ScopeNoFail);
       unsigned FixupLoc = Table.insertNumToSkip();
       FilterChooser SingletonFC(FC.Encodings, ID, FC.FilterBits, *FC.Parent);
       emitSingletonTableEntry(SingletonFC);
@@ -2305,7 +2318,26 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
   }
 
   OS << R"(
-  SmallVector<const uint8_t *, 8> ScopeStack;
+  struct Scope {
+    const uint8_t *SkipTo;
+    // Indicates a non failing scope, which means we will never return with
+    // failure from the decode function when in this scope. It also implies that
+    // any nested scopes within it will be forced to be non-failing as well.
+    bool NoFail;
+    Scope(const uint8_t *SkipTo, bool NoFail)
+      : SkipTo(SkipTo), NoFail(NoFail) {}
+  };
+
+  SmallVector<Scope, 8> ScopeStack;
+
+  // Returns if we are allowed to fail and return from the function in the
+  // current scope.
+  auto CanReturnOnFailure = [&ScopeStack]() -> bool {
+    if (ScopeStack.empty())
+      return true;
+    return !ScopeStack.back().NoFail;
+  };
+
   uint64_t CurFieldValue = 0;
   DecodeStatus S = MCDisassembler::Success;
   while (true) {
@@ -2316,12 +2348,18 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
       errs() << Loc << ": Unexpected decode table opcode: "
              << (int)DecoderOp << '\n';
       return MCDisassembler::Fail;
-    case MCD::OPC_Scope: {
+    case MCD::OPC_Scope:
+    case MCD::OPC_ScopeNoFail: {
       unsigned NumToSkip = decodeNumToSkip(Ptr);
       const uint8_t *SkipTo = Ptr + NumToSkip;
-      ScopeStack.push_back(SkipTo);
-      LLVM_DEBUG(dbgs() << Loc << ": OPC_Scope(" << SkipTo - DecodeTable
-                        << ")\n");
+      bool NoFail = DecoderOp == MCD::OPC_ScopeNoFail;
+      NoFail |= !CanReturnOnFailure();
+      ScopeStack.emplace_back(SkipTo, NoFail);
+      LLVM_DEBUG({
+        const char *OpName = DecoderOp == MCD::OPC_Scope ? "OPC_Scope" : "OPC_ScopeNoFail";
+        dbgs() << Loc << ": " << OpName << "(" << SkipTo - DecodeTable
+               << "NoFail = " << NoFail << ")\n";
+      });
       break;
     }
     case MCD::OPC_ExtractField: {
@@ -2366,7 +2404,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val();
+        Ptr = ScopeStack.pop_back_val().SkipTo;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2394,7 +2432,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val();
+        Ptr = ScopeStack.pop_back_val().SkipTo;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2415,7 +2453,7 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val();
+        Ptr = ScopeStack.pop_back_val().SkipTo;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2440,8 +2478,17 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
 
       LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc
                    << ", using decoder " << DecodeIdx << ": "
-                   << (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
-      return S;
+                   << (S != MCDisassembler::Fail ? "PASS" : "FAIL"));
+      if (S == MCDisassembler::Success || CanReturnOnFailure()) {
+        LLVM_DEBUG(dbgs() << ", Returning\n");
+        return S;
+      }
+      MI.clear();
+      Ptr = ScopeStack.pop_back_val().SkipTo;
+      LLVM_DEBUG(dbgs() << ", continuing at " << Ptr - DecodeTable << '\n');
+      // Reset the decode status.
+      S = MCDisassembler::Success;
+      break;
     })";
   if (HasTryDecode) {
     OS << R"(
@@ -2460,16 +2507,19 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
 
       if (DecodeComplete) {
         // Decoding complete.
-        LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS\n" : "FAIL\n"));
-        MI = TmpMI;
-        return S;
+        LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS" : "FAIL"));
+        if (S == MCDisassembler::Success || CanReturnOnFailure()) {
+          MI = TmpMI;
+          LLVM_DEBUG(dbgs() << ", Returning\n");
+          return S;
+        }
       }
       assert(S == MCDisassembler::Fail);
       if (ScopeStack.empty()) {
         LLVM_DEBUG(dbgs() << "FAIL, returning FAIL\n");
         return MCDisassembler::Fail;
       }
-      Ptr = ScopeStack.pop_back_val();
+      Ptr = ScopeStack.pop_back_val().SkipTo;
       LLVM_DEBUG(dbgs() << "FAIL, continuing at " << Ptr - DecodeTable << '\n');
       // Reset decode status. This also drops a SoftFail status that could be
       // set before the decode attempt.

>From e94d5b2ab95a98afc71abd22b84af5b898f2b534 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 11 Sep 2025 11:30:39 -0700
Subject: [PATCH 5/5] Split scope stack into 2

---
 llvm/utils/TableGen/DecoderEmitter.cpp | 98 ++++++++++++++++----------
 1 file changed, 60 insertions(+), 38 deletions(-)

diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp
index cb0f930170fd2..7ba75afd9f3ea 100644
--- a/llvm/utils/TableGen/DecoderEmitter.cpp
+++ b/llvm/utils/TableGen/DecoderEmitter.cpp
@@ -2317,29 +2317,41 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
 )";
   }
 
+  // We maintain 2 scope stacks. One is ScopeStack which is used in conjunction
+  // with OPC_Scope and it encodes the "regular" forward traversal through the
+  // decoder table in response to Field or Predicate check failures.
+  //
+  // Other is NoFailScopeStack and is used in conjunction with OPC_ScopeNoFail
+  // and it essentially encodes nested checks that in any failure mode continue
+  // further checks and never return from the decode function with a failure.
+  // This is used when we need to attempt multiple decoding possibilities and
+  // a failure anywhere is not a signal to return from the decode function but
+  // to reset some state and continue.
+  //
+  // ScopeStack can be thought of as nested within the NoFailScopeStack. A
+  // "failure" will result in clearing the ScopeStack and continuing execution
+  // at the top of the NoFailScopeStack, if its not empty, else returning from
+  // the decode function with a failure.
+
   OS << R"(
-  struct Scope {
-    const uint8_t *SkipTo;
-    // Indicates a non failing scope, which means we will never return with
-    // failure from the decode function when in this scope. It also implies that
-    // any nested scopes within it will be forced to be non-failing as well.
-    bool NoFail;
-    Scope(const uint8_t *SkipTo, bool NoFail)
-      : SkipTo(SkipTo), NoFail(NoFail) {}
-  };
+  SmallVector<const uint8_t *> ScopeStack;
+  SmallVector<const uint8_t *> NoFailScopeStack;
 
-  SmallVector<Scope, 8> ScopeStack;
+  uint64_t CurFieldValue = 0;
+  DecodeStatus S = MCDisassembler::Success;
 
-  // Returns if we are allowed to fail and return from the function in the
-  // current scope.
-  auto CanReturnOnFailure = [&ScopeStack]() -> bool {
-    if (ScopeStack.empty())
-      return true;
-    return !ScopeStack.back().NoFail;
+  // Handle a return with failure. Returns true if we can actually return from
+  // the decode function, else adjust the state and return the continuation
+  // point.
+  auto PopScope = [&](bool CheckScopeStack) -> std::pair<bool, const uint8_t*> {
+    if (CheckScopeStack && !ScopeStack.empty())
+      return {false, ScopeStack.pop_back_val()};
+    ScopeStack.resize(0);
+    if (!NoFailScopeStack.empty())
+      return {false, NoFailScopeStack.pop_back_val()};
+    return {true, nullptr};
   };
 
-  uint64_t CurFieldValue = 0;
-  DecodeStatus S = MCDisassembler::Success;
   while (true) {
     ptrdiff_t Loc = Ptr - DecodeTable;
     const uint8_t DecoderOp = *Ptr++;
@@ -2352,13 +2364,11 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
     case MCD::OPC_ScopeNoFail: {
       unsigned NumToSkip = decodeNumToSkip(Ptr);
       const uint8_t *SkipTo = Ptr + NumToSkip;
-      bool NoFail = DecoderOp == MCD::OPC_ScopeNoFail;
-      NoFail |= !CanReturnOnFailure();
-      ScopeStack.emplace_back(SkipTo, NoFail);
+      SmallVector<const uint8_t *> &Stack = DecoderOp == MCD::OPC_ScopeNoFail ? NoFailScopeStack : ScopeStack;
+      Stack.push_back(SkipTo);
       LLVM_DEBUG({
         const char *OpName = DecoderOp == MCD::OPC_Scope ? "OPC_Scope" : "OPC_ScopeNoFail";
-        dbgs() << Loc << ": " << OpName << "(" << SkipTo - DecodeTable
-               << "NoFail = " << NoFail << ")\n";
+        dbgs() << Loc << ": " << OpName << "(" << SkipTo - DecodeTable << ")\n";
       });
       break;
     }
@@ -2400,11 +2410,12 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
                         << (Failed ? "FAIL, " : "PASS\n"));
 
       if (Failed) {
-        if (ScopeStack.empty()) {
+        auto Ret = PopScope(/*CheckScopeStack=*/true);
+        if (Ret.first) {
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val().SkipTo;
+        Ptr = Ret.second;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2428,11 +2439,12 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
                         << FieldValue << ", ExpectedValue = " << ExpectedValue
                         << ": " << (Failed ? "FAIL, " : "PASS\n"););
       if (Failed) {
-        if (ScopeStack.empty()) {
+        auto Ret = PopScope(/*CheckScopeStack=*/true);
+        if (Ret.first) {
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val().SkipTo;
+        Ptr = Ret.second;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2449,11 +2461,12 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
                         << (Failed ? "FAIL, " : "PASS\n"););
 
       if (Failed) {
-        if (ScopeStack.empty()) {
+        auto Ret = PopScope(/*CheckScopeStack=*/true);
+        if (Ret.first) {
           LLVM_DEBUG(dbgs() << "returning Fail\n");
           return MCDisassembler::Fail;
         }
-        Ptr = ScopeStack.pop_back_val().SkipTo;
+        Ptr = Ret.second;
         LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       }
       break;
@@ -2479,15 +2492,21 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
       LLVM_DEBUG(dbgs() << Loc << ": OPC_Decode: opcode " << Opc
                    << ", using decoder " << DecodeIdx << ": "
                    << (S != MCDisassembler::Fail ? "PASS" : "FAIL"));
-      if (S == MCDisassembler::Success || CanReturnOnFailure()) {
+      if (S != MCDisassembler::Fail) {
         LLVM_DEBUG(dbgs() << ", Returning\n");
         return S;
       }
-      MI.clear();
-      Ptr = ScopeStack.pop_back_val().SkipTo;
-      LLVM_DEBUG(dbgs() << ", continuing at " << Ptr - DecodeTable << '\n');
+      // We ignore the scope stack and just check NoFail stack here.
+      auto Ret = PopScope(/*CheckScopeStack=*/false);
+      if (Ret.first) {
+        LLVM_DEBUG(dbgs() << "returning Fail\n");
+        return MCDisassembler::Fail;
+      }
       // Reset the decode status.
+      MI.clear();
       S = MCDisassembler::Success;
+      Ptr = Ret.second;
+      LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n');
       break;
     })";
   if (HasTryDecode) {
@@ -2508,22 +2527,25 @@ static DecodeStatus decodeInstruction(const uint8_t DecodeTable[], MCInst &MI,
       if (DecodeComplete) {
         // Decoding complete.
         LLVM_DEBUG(dbgs() << (S != MCDisassembler::Fail ? "PASS" : "FAIL"));
-        if (S == MCDisassembler::Success || CanReturnOnFailure()) {
+        if (S != MCDisassembler::Fail) {
           MI = TmpMI;
           LLVM_DEBUG(dbgs() << ", Returning\n");
           return S;
         }
       }
-      assert(S == MCDisassembler::Fail);
-      if (ScopeStack.empty()) {
+      // If decoding was complete, we only check the NoFail stack, else we
+      // check both stacks when popping the scope.
+      auto Ret = PopScope(/*CheckScopeStack=*/!DecodeComplete);
+
+      if (Ret.first) {
         LLVM_DEBUG(dbgs() << "FAIL, returning FAIL\n");
         return MCDisassembler::Fail;
       }
-      Ptr = ScopeStack.pop_back_val().SkipTo;
-      LLVM_DEBUG(dbgs() << "FAIL, continuing at " << Ptr - DecodeTable << '\n');
       // Reset decode status. This also drops a SoftFail status that could be
       // set before the decode attempt.
       S = MCDisassembler::Success;
+      Ptr = Ret.second;
+      LLVM_DEBUG(dbgs() << "FAIL, continuing at " << Ptr - DecodeTable << '\n');
       break;
     })";
   }



More information about the llvm-commits mailing list