[X86][tablgen] Add class RecognizableInstrBase to simplify X86 code, NFCI

This commit is contained in:
Shengchen Kan 2022-03-26 13:00:53 +08:00
parent 392bb8cf1f
commit bf11ed293a
5 changed files with 94 additions and 130 deletions

View File

@ -13,6 +13,7 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "X86RecognizableInstr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"
@ -109,28 +110,25 @@ public:
IsMatch(const CodeGenInstruction *EVEXInst) : EVEXInst(EVEXInst) {}
bool operator()(const CodeGenInstruction *VEXInst) {
Record *RecE = EVEXInst->TheDef;
Record *RecV = VEXInst->TheDef;
bool EVEX_W = RecE->getValueAsBit("HasVEX_W");
bool VEX_W = RecV->getValueAsBit("HasVEX_W");
bool VEX_WIG = RecV->getValueAsBit("IgnoresVEX_W");
bool EVEX_WIG = RecE->getValueAsBit("IgnoresVEX_W");
bool EVEX_W1_VEX_W0 = RecE->getValueAsBit("EVEX_W1_VEX_W0");
X86Disassembler::RecognizableInstrBase VEXRI(*VEXInst);
X86Disassembler::RecognizableInstrBase EVEXRI(*EVEXInst);
bool VEX_W = VEXRI.HasVEX_W;
bool EVEX_W = EVEXRI.HasVEX_W;
bool VEX_WIG = VEXRI.IgnoresVEX_W;
bool EVEX_WIG = EVEXRI.IgnoresVEX_W;
bool EVEX_W1_VEX_W0 = EVEXRI.Rec->getValueAsBit("EVEX_W1_VEX_W0");
if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||
RecV->getValueAsBit("isCodeGenOnly") != RecE->getValueAsBit("isCodeGenOnly") ||
if (VEXRI.IsCodeGenOnly != EVEXRI.IsCodeGenOnly ||
// VEX/EVEX fields
RecV->getValueAsDef("OpPrefix") != RecE->getValueAsDef("OpPrefix") ||
RecV->getValueAsDef("OpMap") != RecE->getValueAsDef("OpMap") ||
RecV->getValueAsBit("hasVEX_4V") != RecE->getValueAsBit("hasVEX_4V") ||
RecV->getValueAsBit("hasEVEX_L2") != RecE->getValueAsBit("hasEVEX_L2") ||
RecV->getValueAsBit("hasVEX_L") != RecE->getValueAsBit("hasVEX_L") ||
VEXRI.OpPrefix != EVEXRI.OpPrefix || VEXRI.OpMap != EVEXRI.OpMap ||
VEXRI.HasVEX_4V != EVEXRI.HasVEX_4V ||
VEXRI.HasVEX_LPrefix != EVEXRI.HasVEX_LPrefix ||
// Match is allowed if either is VEX_WIG, or they match, or EVEX
// is VEX_W1X and VEX is VEX_W0.
(!(VEX_WIG || (!EVEX_WIG && EVEX_W == VEX_W) ||
(EVEX_W1_VEX_W0 && EVEX_W && !VEX_W))) ||
// Instruction's format
RecV->getValueAsDef("Form") != RecE->getValueAsDef("Form"))
VEXRI.Form != EVEXRI.Form)
return false;
// This is needed for instructions with intrinsic version (_Int).
@ -207,23 +205,19 @@ void X86EVEX2VEXTablesEmitter::run(raw_ostream &OS) {
Target.getInstructionsByEnumValue();
for (const CodeGenInstruction *Inst : NumberedInstructions) {
X86Disassembler::RecognizableInstrBase RI(*Inst);
const Record *Def = RI.Rec;
// Filter non-X86 instructions.
if (!Inst->TheDef->isSubClassOf("X86Inst"))
if (!Def->isSubClassOf("X86Inst"))
continue;
// Add VEX encoded instructions to one of VEXInsts vectors according to
// it's opcode.
if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncVEX") {
uint64_t Opcode = getValueFromBitsInit(Inst->TheDef->
getValueAsBitsInit("Opcode"));
VEXInsts[Opcode].push_back(Inst);
}
if (RI.Encoding == X86Local::VEX)
VEXInsts[RI.Opcode].push_back(Inst);
// Add relevant EVEX encoded instructions to EVEXInsts
else if (Inst->TheDef->getValueAsDef("OpEnc")->getName() == "EncEVEX" &&
!Inst->TheDef->getValueAsBit("hasEVEX_K") &&
!Inst->TheDef->getValueAsBit("hasEVEX_B") &&
!Inst->TheDef->getValueAsBit("hasEVEX_L2") &&
!Inst->TheDef->getValueAsBit("notEVEX2VEXConvertible"))
else if (RI.Encoding == X86Local::EVEX && !RI.HasEVEX_K && !RI.HasEVEX_B &&
!RI.HasEVEX_L2Prefix && !Def->getValueAsBit("notEVEX2VEXConvertible"))
EVEXInsts.push_back(Inst);
}

View File

@ -212,20 +212,6 @@ static inline uint64_t getValueFromBitsInit(const BitsInit *B) {
return Value;
}
// Returns true if the two given BitsInits represent the same integer value
static inline bool equalBitsInits(const BitsInit *B1, const BitsInit *B2) {
if (B1->getNumBits() != B2->getNumBits())
PrintFatalError("Comparing two BitsInits with different sizes!");
for (unsigned i = 0, e = B1->getNumBits(); i != e; ++i) {
BitInit *Bit1 = cast<BitInit>(B1->getBit(i));
BitInit *Bit2 = cast<BitInit>(B2->getBit(i));
if (Bit1->getValue() != Bit2->getValue())
return false;
}
return true;
}
// Return the size of the register operand
static inline unsigned int getRegOperandSize(const Record *RegRec) {
if (RegRec->isSubClassOf("RegisterOperand"))
@ -323,53 +309,42 @@ public:
: MemInst(Inst) {}
bool operator()(const CodeGenInstruction *RegInst) {
Record *MemRec = MemInst->TheDef;
Record *RegRec = RegInst->TheDef;
X86Disassembler::RecognizableInstrBase RegRI(*RegInst);
X86Disassembler::RecognizableInstrBase MemRI(*MemInst);
const Record *RegRec = RegRI.Rec;
const Record *MemRec = MemRI.Rec;
// EVEX_B means different things for memory and register forms.
if (RegRI.HasEVEX_B != 0 || MemRI.HasEVEX_B != 0)
return false;
// Instruction's format - The register form's "Form" field should be
// the opposite of the memory form's "Form" field.
if (!areOppositeForms(RegRI.Form, MemRI.Form))
return false;
// Return false if one (at least) of the encoding fields of both
// instructions do not match.
if (RegRec->getValueAsDef("OpEnc") != MemRec->getValueAsDef("OpEnc") ||
!equalBitsInits(RegRec->getValueAsBitsInit("Opcode"),
MemRec->getValueAsBitsInit("Opcode")) ||
// VEX/EVEX fields
RegRec->getValueAsDef("OpPrefix") !=
MemRec->getValueAsDef("OpPrefix") ||
RegRec->getValueAsDef("OpMap") != MemRec->getValueAsDef("OpMap") ||
RegRec->getValueAsDef("OpSize") != MemRec->getValueAsDef("OpSize") ||
RegRec->getValueAsDef("AdSize") != MemRec->getValueAsDef("AdSize") ||
RegRec->getValueAsBit("hasVEX_4V") !=
MemRec->getValueAsBit("hasVEX_4V") ||
RegRec->getValueAsBit("hasEVEX_K") !=
MemRec->getValueAsBit("hasEVEX_K") ||
RegRec->getValueAsBit("hasEVEX_Z") !=
MemRec->getValueAsBit("hasEVEX_Z") ||
// EVEX_B means different things for memory and register forms.
RegRec->getValueAsBit("hasEVEX_B") != 0 ||
MemRec->getValueAsBit("hasEVEX_B") != 0 ||
if (RegRI.Encoding != MemRI.Encoding || RegRI.Opcode != MemRI.Opcode ||
RegRI.OpPrefix != MemRI.OpPrefix || RegRI.OpMap != MemRI.OpMap ||
RegRI.OpSize != MemRI.OpSize || RegRI.AdSize != MemRI.AdSize ||
RegRI.HasREX_WPrefix != MemRI.HasREX_WPrefix ||
RegRI.HasVEX_4V != MemRI.HasVEX_4V ||
RegRI.HasVEX_LPrefix != MemRI.HasVEX_LPrefix ||
RegRI.HasVEX_W != MemRI.HasVEX_W ||
RegRI.IgnoresVEX_L != MemRI.IgnoresVEX_L ||
RegRI.IgnoresVEX_W != MemRI.IgnoresVEX_W ||
RegRI.HasEVEX_K != MemRI.HasEVEX_K ||
RegRI.HasEVEX_KZ != MemRI.HasEVEX_KZ ||
RegRI.HasEVEX_L2Prefix != MemRI.HasEVEX_L2Prefix ||
RegRec->getValueAsBit("hasEVEX_RC") !=
MemRec->getValueAsBit("hasEVEX_RC") ||
RegRec->getValueAsBit("hasREX_WPrefix") !=
MemRec->getValueAsBit("hasREX_WPrefix") ||
RegRec->getValueAsBit("hasLockPrefix") !=
MemRec->getValueAsBit("hasLockPrefix") ||
RegRec->getValueAsBit("hasNoTrackPrefix") !=
MemRec->getValueAsBit("hasNoTrackPrefix") ||
RegRec->getValueAsBit("hasVEX_L") !=
MemRec->getValueAsBit("hasVEX_L") ||
RegRec->getValueAsBit("hasEVEX_L2") !=
MemRec->getValueAsBit("hasEVEX_L2") ||
RegRec->getValueAsBit("ignoresVEX_L") !=
MemRec->getValueAsBit("ignoresVEX_L") ||
RegRec->getValueAsBit("HasVEX_W") !=
MemRec->getValueAsBit("HasVEX_W") ||
RegRec->getValueAsBit("IgnoresVEX_W") !=
MemRec->getValueAsBit("IgnoresVEX_W") ||
RegRec->getValueAsBit("EVEX_W1_VEX_W0") !=
MemRec->getValueAsBit("EVEX_W1_VEX_W0") ||
// Instruction's format - The register form's "Form" field should be
// the opposite of the memory form's "Form" field.
!areOppositeForms(RegRec->getValueAsBitsInit("FormBits"),
MemRec->getValueAsBitsInit("FormBits")) ||
RegRec->getValueAsBit("isAsmParserOnly") !=
MemRec->getValueAsBit("isAsmParserOnly"))
return false;
@ -424,31 +399,24 @@ public:
private:
// Return true of the 2 given forms are the opposite of each other.
bool areOppositeForms(const BitsInit *RegFormBits,
const BitsInit *MemFormBits) {
uint64_t MemFormNum = getValueFromBitsInit(MemFormBits);
uint64_t RegFormNum = getValueFromBitsInit(RegFormBits);
if ((MemFormNum == X86Local::MRM0m && RegFormNum == X86Local::MRM0r) ||
(MemFormNum == X86Local::MRM1m && RegFormNum == X86Local::MRM1r) ||
(MemFormNum == X86Local::MRM2m && RegFormNum == X86Local::MRM2r) ||
(MemFormNum == X86Local::MRM3m && RegFormNum == X86Local::MRM3r) ||
(MemFormNum == X86Local::MRM4m && RegFormNum == X86Local::MRM4r) ||
(MemFormNum == X86Local::MRM5m && RegFormNum == X86Local::MRM5r) ||
(MemFormNum == X86Local::MRM6m && RegFormNum == X86Local::MRM6r) ||
(MemFormNum == X86Local::MRM7m && RegFormNum == X86Local::MRM7r) ||
(MemFormNum == X86Local::MRMXm && RegFormNum == X86Local::MRMXr) ||
(MemFormNum == X86Local::MRMXmCC && RegFormNum == X86Local::MRMXrCC) ||
(MemFormNum == X86Local::MRMDestMem &&
RegFormNum == X86Local::MRMDestReg) ||
(MemFormNum == X86Local::MRMSrcMem &&
RegFormNum == X86Local::MRMSrcReg) ||
(MemFormNum == X86Local::MRMSrcMem4VOp3 &&
RegFormNum == X86Local::MRMSrcReg4VOp3) ||
(MemFormNum == X86Local::MRMSrcMemOp4 &&
RegFormNum == X86Local::MRMSrcRegOp4) ||
(MemFormNum == X86Local::MRMSrcMemCC &&
RegFormNum == X86Local::MRMSrcRegCC))
bool areOppositeForms(unsigned RegForm, unsigned MemForm) {
if ((MemForm == X86Local::MRM0m && RegForm == X86Local::MRM0r) ||
(MemForm == X86Local::MRM1m && RegForm == X86Local::MRM1r) ||
(MemForm == X86Local::MRM2m && RegForm == X86Local::MRM2r) ||
(MemForm == X86Local::MRM3m && RegForm == X86Local::MRM3r) ||
(MemForm == X86Local::MRM4m && RegForm == X86Local::MRM4r) ||
(MemForm == X86Local::MRM5m && RegForm == X86Local::MRM5r) ||
(MemForm == X86Local::MRM6m && RegForm == X86Local::MRM6r) ||
(MemForm == X86Local::MRM7m && RegForm == X86Local::MRM7r) ||
(MemForm == X86Local::MRMXm && RegForm == X86Local::MRMXr) ||
(MemForm == X86Local::MRMXmCC && RegForm == X86Local::MRMXrCC) ||
(MemForm == X86Local::MRMDestMem && RegForm == X86Local::MRMDestReg) ||
(MemForm == X86Local::MRMSrcMem && RegForm == X86Local::MRMSrcReg) ||
(MemForm == X86Local::MRMSrcMem4VOp3 &&
RegForm == X86Local::MRMSrcReg4VOp3) ||
(MemForm == X86Local::MRMSrcMemOp4 &&
RegForm == X86Local::MRMSrcRegOp4) ||
(MemForm == X86Local::MRMSrcMemCC && RegForm == X86Local::MRMSrcRegCC))
return true;
return false;

View File

@ -13,7 +13,6 @@
#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "X86DisassemblerTables.h"
#include "X86RecognizableInstr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"
@ -41,23 +40,17 @@ void X86MnemonicTablesEmitter::run(raw_ostream &OS) {
// Hold all instructions grouped by mnemonic
StringMap<SmallVector<const CodeGenInstruction *, 0>> MnemonicToCGInstrMap;
// Unused
X86Disassembler::DisassemblerTables Tables;
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
Target.getInstructionsByEnumValue();
for (unsigned II = 0, IE = NumberedInstructions.size(); II != IE; ++II) {
const CodeGenInstruction *I = NumberedInstructions[II];
X86Disassembler::RecognizableInstr RI(Tables, *I, II);
Record *Def = I->TheDef;
if ( // Filter non-X86 instructions
!Def->isSubClassOf("X86Inst") ||
// Skip pseudo instructions as they may contain non-alnum characters in
// mnemonic
(RI.IsCodeGenOnly && !RI.ForceDisassemble) ||
// Non-parsable instruction defs contain prefix as part of AsmString
for (const CodeGenInstruction *I : NumberedInstructions) {
X86Disassembler::RecognizableInstrBase RI(*I);
const Record *Def = RI.Rec;
if (!RI.ShouldBeEmitted)
continue;
if ( // Non-parsable instruction defs contain prefix as part of AsmString
Def->getValueAsString("AsmVariantName") == "NonParsable" ||
// Skip CodeGenInstructions that are not real standalone instructions
RI.Form == X86Local::PrefixByte || RI.Form == X86Local::Pseudo)
// Skip prefix byte
RI.Form == X86Local::PrefixByte)
continue;
std::string Mnemonic = X86Disassembler::getMnemonic(I, Variant);
MnemonicToCGInstrMap[Mnemonic].push_back(I);

View File

@ -75,14 +75,9 @@ static uint8_t byteFromRec(const Record* rec, StringRef name) {
return byteFromBitsInit(*bits);
}
RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
const CodeGenInstruction &insn,
InstrUID uid) {
UID = uid;
RecognizableInstrBase::RecognizableInstrBase(const CodeGenInstruction &insn) {
Rec = insn.TheDef;
Name = std::string(Rec->getName());
Spec = &tables.specForUID(UID);
if (!Rec->isSubClassOf("X86Inst")) {
ShouldBeEmitted = false;
@ -144,6 +139,14 @@ RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
ShouldBeEmitted = true;
}
RecognizableInstr::RecognizableInstr(DisassemblerTables &tables,
const CodeGenInstruction &insn,
InstrUID uid)
: RecognizableInstrBase(insn) {
UID = uid;
Spec = &tables.specForUID(UID);
}
void RecognizableInstr::processInstr(DisassemblerTables &tables,
const CodeGenInstruction &insn,
InstrUID uid)

View File

@ -158,14 +158,8 @@ namespace X86Disassembler {
class DisassemblerTables;
/// RecognizableInstr - Encapsulates all information required to decode a single
/// instruction, as extracted from the LLVM instruction tables. Has methods
/// to interpret the information available in the LLVM tables, and to emit the
/// instruction into DisassemblerTables.
class RecognizableInstr {
public:
/// The opcode of the instruction, as used in an MCInst
InstrUID UID;
/// Extract common fields of a single X86 instruction from a CodeGenInstruction
struct RecognizableInstrBase {
/// The record from the .td files corresponding to this instruction
const Record* Rec;
/// The OpPrefix field from the record
@ -228,6 +222,18 @@ public:
/// memory operands expand to 5 operands in the MCInst
const std::vector<CGIOperandList::OperandInfo>* Operands;
/// \param insn The CodeGenInstruction to extract information from.
RecognizableInstrBase(const CodeGenInstruction &insn);
};
/// RecognizableInstr - Encapsulates all information required to decode a single
/// instruction, as extracted from the LLVM instruction tables. Has methods
/// to interpret the information available in the LLVM tables, and to emit the
/// instruction into DisassemblerTables.
class RecognizableInstr : public RecognizableInstrBase {
public:
/// The opcode of the instruction, as used in an MCInst
InstrUID UID;
/// The description of the instruction that is emitted into the instruction
/// info table
InstructionSpecifier* Spec;