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/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 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 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 -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 static inline T eatBytes(ArrayRef& 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 DecodeStatus tryDecodeInst(const uint8_t *Table, MCInst &MI, InsnType Inst, uint64_t Address, raw_ostream &Comments) const; - template - DecodeStatus tryDecodeInst(const uint8_t *Table1, const uint8_t *Table2, - MCInst &MI, InsnType Inst, uint64_t Address, - raw_ostream &Comments) const; Expected onSymbolStart(SymbolInfoTy &Symbol, uint64_t &Size, ArrayRef 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 op, string asmName> { defvar ps = !cast(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, VINTERPe_gfx11; @@ -249,8 +250,9 @@ multiclass VINTERP_Real_gfx11 op, string asmName> { multiclass VINTERP_Real_gfx12 op, string asmName> { defvar ps = !cast(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, VINTERPe_gfx12; 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 op, string opName, string asmName> { defvar ps = !cast(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; } } @@ -961,8 +961,8 @@ multiclass VOP1_Real_dpp_with_name op, string opName, string asmName> { defvar ps = !cast(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; } } @@ -977,8 +977,8 @@ multiclass VOP1_Real_dpp8_with_name op, string opName, string asmName> { defvar ps = !cast(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; } 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_Real { 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 pattern=[]> : @@ -1517,8 +1517,8 @@ class VOP2_DPP16_Gen op, VOP2_DPP_Pseudo ps, GFXGen Gen, VOP2_DPP16 { 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 op, VOP2_Pseudo ps, @@ -1547,8 +1547,8 @@ class VOP2_DPP8_Gen op, VOP2_Pseudo ps, GFXGen Gen, VOP2_DPP8 { 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 { @@ -1677,7 +1678,8 @@ multiclass VOPC_Real_with_name 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 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 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, VOPCe { @@ -1880,7 +1883,7 @@ multiclass VOPCX_Real_with_name 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 : VOP3_Real { 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 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 op, VOP_Pseudo ps, string opName = ps.OpName> @@ -1816,7 +1816,8 @@ multiclass VOP3Dot_Real_Base op, string asmName, string opN bit isSingle = 0> { defvar ps = !cast(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, @@ -1886,8 +1887,8 @@ multiclass VOP3Dot_Real_dpp_Base op, string asmName, string def _e64_dpp#Gen.Suffix : VOP3_DPP16_Gen_t16 { 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 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 op, string opName, string asmName> { defvar ps = !cast(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; @@ -2006,8 +2007,8 @@ multiclass VOP3_BITOP3_Real_dpp_Base op, string asmName> { multiclass VOP3_BITOP3_Real_dpp8_Base op, string asmName> { defvar ps = !cast(NAME#"_e64"); def _e64_dpp8#Gen.Suffix : VOP3_BITOP3_DPP8 { - 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/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/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..e48d2ebddc249 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 = 0;//1; +defvar DecodeOrderZcOverlap = 0;//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 { // 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..7ba75afd9f3ea 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -116,6 +116,11 @@ static cl::opt IgnoreFullyDefinedOperands( "Do not automatically decode operands with no '?' in their encoding."), cl::init(false), cl::cat(DisassemblerEmitterCat)); +static cl::opt 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 decode 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 decode 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 Encodings; public: - explicit LessEncodingIDByWidth(ArrayRef Encodings) + explicit LessEncodingID(ArrayRef 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> FilterChooserMap; + /// Per decode order filter choosers. Applicable when the set of candidates + /// have more than 1 decode orders. + SmallVector> 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 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,18 @@ class FilterChooser { // decoded bits in order to verify that the instruction matches the Opcode. std::vector getIslands(const KnownBits &EncodingBits) const; + // Returns the decode order for the given encoding ID. + 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 findBestFilter(ArrayRef BitAttrs, @@ -685,6 +719,51 @@ 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 targets. To control this, they can use the + // DecodeOrder. If we have multiple decode orders, the filter chooser will + // 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) { + return getDecodeOrder(A) < getDecodeOrder(B); + }; + + int64_t MaxFixedOrder = std::numeric_limits::min(); + for (ArrayRef 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. @@ -722,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, @@ -801,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); @@ -829,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); @@ -838,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. @@ -857,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; @@ -870,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. @@ -891,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); @@ -1580,6 +1672,42 @@ std::unique_ptr FilterChooser::findBestFilter() const { return nullptr; } +bool FilterChooser::hasMultipleDecodeOrders() const { + if (EncodingIDs.size() <= 1) + return false; + // 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()); +} + +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 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 (as opposed to using Idx + 1). + for (const auto &[Idx, ID] : enumerate(IDs)) { + int64_t CurrentOrder = getDecodeOrder(ID); + if (CurrentOrder != LastOrder) { + ArrayRef SubIDs = IDs.slice(LastIndex, Idx - LastIndex); + PerDecodeOrderChoosers.push_back(std::make_unique( + Encodings, SubIDs, FilterBits, *this)); + LastOrder = CurrentOrder; + LastIndex = Idx; + } + } + + // Finish the last span. + ArrayRef SubIDs = IDs.slice(LastIndex, IDs.size() - LastIndex); + PerDecodeOrderChoosers.push_back( + std::make_unique(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 +1726,19 @@ void FilterChooser::doFilter() { return; } + // 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; + } + + if (ResolveConflictsTryAll) { + AttemptAll = true; + return; + } + // Print out useful conflict information for postmortem analysis. errs() << "Decoding Conflict:\n"; dump(); @@ -1612,12 +1753,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'; } } @@ -1626,10 +1772,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 +1795,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 +1822,37 @@ 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. 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_ScopeNoFail); + 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. + // 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_ScopeNoFail); + 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 +2243,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"); @@ -2143,10 +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"( - SmallVector ScopeStack; + SmallVector ScopeStack; + SmallVector NoFailScopeStack; + uint64_t CurFieldValue = 0; DecodeStatus S = MCDisassembler::Success; + + // 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 { + 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}; + }; + while (true) { ptrdiff_t Loc = Ptr - DecodeTable; const uint8_t DecoderOp = *Ptr++; @@ -2155,12 +2360,16 @@ 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"); + SmallVector &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 << ")\n"; + }); break; } case MCD::OPC_ExtractField: { @@ -2201,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(); + Ptr = Ret.second; LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n'); } break; @@ -2229,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(); + Ptr = Ret.second; LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n'); } break; @@ -2250,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(); + Ptr = Ret.second; LLVM_DEBUG(dbgs() << "continuing at " << Ptr - DecodeTable << '\n'); } break; @@ -2279,8 +2491,23 @@ 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::Fail) { + LLVM_DEBUG(dbgs() << ", Returning\n"); + return S; + } + // 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) { OS << R"( @@ -2299,20 +2526,26 @@ 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::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(); - 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; })"; }