Skip to content

Commit

Permalink
[X86][tablgen] Add class RecognizableInstrBase to simplify X86 code, …
Browse files Browse the repository at this point in the history
…NFCI
  • Loading branch information
KanRobert committed Mar 26, 2022
1 parent 392bb8c commit bf11ed2
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 131 deletions.
48 changes: 21 additions & 27 deletions llvm/utils/TableGen/X86EVEX2VEXTablesEmitter.cpp
Expand Up @@ -13,6 +13,7 @@

#include "CodeGenInstruction.h"
#include "CodeGenTarget.h"
#include "X86RecognizableInstr.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/TableGenBackend.h"

Expand Down Expand Up @@ -109,28 +110,25 @@ class IsMatch {
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");

if (RecV->getValueAsDef("OpEnc")->getName().str() != "EncVEX" ||
RecV->getValueAsBit("isCodeGenOnly") != RecE->getValueAsBit("isCodeGenOnly") ||
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 (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).
Expand Down Expand Up @@ -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);
}

Expand Down
118 changes: 43 additions & 75 deletions llvm/utils/TableGen/X86FoldTablesEmitter.cpp
Expand Up @@ -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"))
Expand Down Expand Up @@ -323,53 +309,42 @@ class IsMatch {
: 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;
Expand Down Expand Up @@ -424,31 +399,24 @@ class IsMatch {

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;
Expand Down
23 changes: 8 additions & 15 deletions llvm/utils/TableGen/X86MnemonicTables.cpp
Expand Up @@ -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"
Expand Down Expand Up @@ -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);
Expand Down
15 changes: 9 additions & 6 deletions llvm/utils/TableGen/X86RecognizableInstr.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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)
Expand Down
22 changes: 14 additions & 8 deletions llvm/utils/TableGen/X86RecognizableInstr.h
Expand Up @@ -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
Expand Down Expand Up @@ -228,6 +222,18 @@ class RecognizableInstr {
/// 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;
Expand Down

0 comments on commit bf11ed2

Please sign in to comment.