#include "CodeGenTarget.h"
#include "TableGenBackends.h"
#include "X86RecognizableInstr.h"
-#include "llvm/ADT/DenseMap.h"
#include "llvm/Support/FormattedStream.h"
-#include "llvm/Support/X86FoldTablesUtils.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
using namespace X86Disassembler;
namespace {
+
+// 3 possible strategies for the unfolding flag (TB_NO_REVERSE) of the
+// manual added entries.
+enum UnfoldStrategy {
+ UNFOLD, // Allow unfolding
+ NO_UNFOLD, // Prevent unfolding
+ NO_STRATEGY // Make decision according to operands' sizes
+};
+
// Represents an entry in the manual mapped instructions set.
struct ManualMapEntry {
const char *RegInstStr;
const char *MemInstStr;
- uint16_t Strategy;
+ UnfoldStrategy Strategy;
ManualMapEntry(const char *RegInstStr, const char *MemInstStr,
- uint16_t Strategy = 0)
+ UnfoldStrategy Strategy = NO_STRATEGY)
: RegInstStr(RegInstStr), MemInstStr(MemInstStr), Strategy(Strategy) {}
};
"PCMPESTRM", "PCMPESTRI",
"PCMPISTRM", "PCMPISTRI" };
-#include "X86FoldTablesEmitterManualMapSet.inc"
+// For manually mapping instructions that do not match by their encoding.
+const ManualMapEntry ManualMapSet[] = {
+ { "ADD16ri_DB", "ADD16mi", NO_UNFOLD },
+ { "ADD16ri8_DB", "ADD16mi8", NO_UNFOLD },
+ { "ADD16rr_DB", "ADD16mr", NO_UNFOLD },
+ { "ADD32ri_DB", "ADD32mi", NO_UNFOLD },
+ { "ADD32ri8_DB", "ADD32mi8", NO_UNFOLD },
+ { "ADD32rr_DB", "ADD32mr", NO_UNFOLD },
+ { "ADD64ri32_DB", "ADD64mi32", NO_UNFOLD },
+ { "ADD64ri8_DB", "ADD64mi8", NO_UNFOLD },
+ { "ADD64rr_DB", "ADD64mr", NO_UNFOLD },
+ { "ADD8ri_DB", "ADD8mi", NO_UNFOLD },
+ { "ADD8rr_DB", "ADD8mr", NO_UNFOLD },
+ { "ADD16rr_DB", "ADD16rm", NO_UNFOLD },
+ { "ADD32rr_DB", "ADD32rm", NO_UNFOLD },
+ { "ADD64rr_DB", "ADD64rm", NO_UNFOLD },
+ { "ADD8rr_DB", "ADD8rm", NO_UNFOLD },
+ { "MMX_MOVD64from64rr", "MMX_MOVQ64mr", UNFOLD },
+ { "MMX_MOVD64grr", "MMX_MOVD64mr", UNFOLD },
+ { "MOVLHPSrr", "MOVHPSrm", NO_UNFOLD },
+ { "PUSH16r", "PUSH16rmm", UNFOLD },
+ { "PUSH32r", "PUSH32rmm", UNFOLD },
+ { "PUSH64r", "PUSH64rmm", UNFOLD },
+ { "TAILJMPr", "TAILJMPm", UNFOLD },
+ { "TAILJMPr64", "TAILJMPm64", UNFOLD },
+ { "TAILJMPr64_REX", "TAILJMPm64_REX", UNFOLD },
+ { "VMOVLHPSZrr", "VMOVHPSZ128rm", NO_UNFOLD },
+ { "VMOVLHPSrr", "VMOVHPSrm", NO_UNFOLD },
+};
+
+
static bool isExplicitAlign(const CodeGenInstruction *Inst) {
return any_of(ExplicitAlign, [Inst](const char *InstStr) {
return Inst->TheDef->getName().contains(InstStr);
public:
bool CannotUnfold = false;
- bool CannotFold = false;
bool IsLoad = false;
bool IsStore = false;
bool IsAligned = false;
unsigned int Alignment = 0;
- X86FoldTableEntry() = default;
X86FoldTableEntry(const CodeGenInstruction *RegInst,
const CodeGenInstruction *MemInst)
: RegInst(RegInst), MemInst(MemInst) {}
void print(formatted_raw_ostream &OS) const {
- // Stop printing record if it can't fold and unfold.
- if(CannotUnfold && CannotFold)
- return;
OS.indent(2);
- OS << "{X86::" << RegInst->TheDef->getName() << ", ";
- OS << "X86::" << MemInst->TheDef->getName() << ", ";
+ OS << "{ X86::" << RegInst->TheDef->getName() << ",";
+ OS.PadToColumn(40);
+ OS << "X86::" << MemInst->TheDef->getName() << ",";
+ OS.PadToColumn(75);
std::string Attrs;
if (IsLoad)
- Attrs += "TB_FOLDED_LOAD|";
+ Attrs += "TB_FOLDED_LOAD | ";
if (IsStore)
- Attrs += "TB_FOLDED_STORE|";
+ Attrs += "TB_FOLDED_STORE | ";
if (CannotUnfold)
- Attrs += "TB_NO_REVERSE|";
- if (CannotFold)
- Attrs += "TB_NO_FORWARD|";
+ Attrs += "TB_NO_REVERSE | ";
if (IsAligned)
- Attrs += "TB_ALIGN_" + std::to_string(Alignment) + "|";
+ Attrs += "TB_ALIGN_" + std::to_string(Alignment) + " | ";
- StringRef SimplifiedAttrs = StringRef(Attrs).rtrim("|");
+ StringRef SimplifiedAttrs = StringRef(Attrs).rtrim("| ");
if (SimplifiedAttrs.empty())
SimplifiedAttrs = "0";
- OS << SimplifiedAttrs << "},\n";
+ OS << SimplifiedAttrs << " },\n";
}
- };
-
- struct CodeGenInstructionComparator {
- // Comparator function
- bool operator()(const CodeGenInstruction *LHS,
- const CodeGenInstruction *RHS) const {
- assert(LHS && RHS && "LHS and RHS shouldn't be nullptr");
- bool LHSpseudo = LHS->TheDef->getValueAsBit("isPseudo");
- bool RHSpseudo = RHS->TheDef->getValueAsBit("isPseudo");
+ bool operator<(const X86FoldTableEntry &RHS) const {
+ bool LHSpseudo = RegInst->TheDef->getValueAsBit("isPseudo");
+ bool RHSpseudo = RHS.RegInst->TheDef->getValueAsBit("isPseudo");
if (LHSpseudo != RHSpseudo)
return LHSpseudo;
- return LHS->TheDef->getName() < RHS->TheDef->getName();
+ return RegInst->TheDef->getName() < RHS.RegInst->TheDef->getName();
}
};
- typedef std::map<const CodeGenInstruction *, X86FoldTableEntry,
- CodeGenInstructionComparator>
- FoldTable;
+ typedef std::vector<X86FoldTableEntry> FoldTable;
// std::vector for each folding table.
// Table2Addr - Holds instructions which their memory form performs load+store
// Table#i - Holds instructions which the their memory form perform a load OR
// Decides to which table to add the entry with the given instructions.
// S sets the strategy of adding the TB_NO_REVERSE flag.
void updateTables(const CodeGenInstruction *RegInstr,
- const CodeGenInstruction *MemInstr, const uint16_t S = 0,
- bool IsManual = false);
+ const CodeGenInstruction *MemInstr,
+ const UnfoldStrategy S = NO_STRATEGY);
// Generates X86FoldTableEntry with the given instructions and fill it with
// the appropriate flags - then adds it to Table.
void addEntryWithFlags(FoldTable &Table, const CodeGenInstruction *RegInstr,
- const CodeGenInstruction *MemInstr, const uint16_t S,
- const unsigned int FoldedInd, bool isManual);
+ const CodeGenInstruction *MemInstr,
+ const UnfoldStrategy S, const unsigned int FoldedInd);
// Print the given table as a static const C++ array of type
// X86MemoryFoldTableEntry.
OS << "static const X86MemoryFoldTableEntry MemoryFold" << TableName
<< "[] = {\n";
- for (auto &E : Table)
- E.second.print(OS);
+ for (const X86FoldTableEntry &E : Table)
+ E.print(OS);
OS << "};\n\n";
}
void X86FoldTablesEmitter::addEntryWithFlags(FoldTable &Table,
const CodeGenInstruction *RegInstr,
const CodeGenInstruction *MemInstr,
- const uint16_t S,
- const unsigned int FoldedInd,
- bool isManual) {
+ const UnfoldStrategy S,
+ const unsigned int FoldedInd) {
X86FoldTableEntry Result = X86FoldTableEntry(RegInstr, MemInstr);
Record *RegRec = RegInstr->TheDef;
Record *MemRec = MemInstr->TheDef;
- if (isManual) {
- Result.CannotUnfold = (S & TB_NO_REVERSE) != 0;
- Result.CannotFold = (S & TB_NO_FORWARD) != 0;
- Result.IsLoad = (S & TB_FOLDED_LOAD) != 0;
- Result.IsStore = (S & TB_FOLDED_STORE) != 0;
- Result.IsAligned = (S & TB_ALIGN_MASK) != 0;
- Result.Alignment = 1 << (((S & TB_ALIGN_MASK) >> TB_ALIGN_SHIFT) - 1);
- Table[RegInstr] = Result;
- return;
- }
-
// Only table0 entries should explicitly specify a load or store flag.
if (&Table == &Table0) {
unsigned MemInOpsNum = MemRec->getValueAsDag("InOperandList")->getNumArgs();
// the register in the register form instruction.
// If the register's size is greater than the memory's operand size, do not
// allow unfolding.
-
- // the unfolded load size will be based on the register size. If that’s bigger
- // than the memory operand size, the unfolded load will load more memory and
- // potentially cause a memory fault.
- if (getRegOperandSize(RegOpRec) > getMemOperandSize(MemOpRec))
- Result.CannotUnfold = true;
-
- // Check no-kz version's isMoveReg
- Record *BaseDef = nullptr;
- if (RegRec->getName().ends_with("rkz") &&
- (BaseDef = Records.getDef(
- RegRec->getName().substr(0, RegRec->getName().size() - 2)))) {
- Result.CannotUnfold =
- Target.getInstruction(BaseDef).isMoveReg ? true : Result.CannotUnfold;
- } else if (RegRec->getName().ends_with("rk") &&
- (BaseDef = Records.getDef(
- RegRec->getName().substr(0, RegRec->getName().size() - 1)))) {
- Result.CannotUnfold =
- Target.getInstruction(BaseDef).isMoveReg ? true : Result.CannotUnfold;
- } else if (RegInstr->isMoveReg && Result.IsStore)
+ if (S == UNFOLD)
+ Result.CannotUnfold = false;
+ else if (S == NO_UNFOLD)
Result.CannotUnfold = true;
+ else if (getRegOperandSize(RegOpRec) > getMemOperandSize(MemOpRec))
+ Result.CannotUnfold = true; // S == NO_STRATEGY
uint64_t Enc = getValueFromBitsInit(RegRec->getValueAsBitsInit("OpEncBits"));
if (isExplicitAlign(RegInstr)) {
Result.Alignment = 16;
}
}
- // Expand is only ever created as a masked instruction. It is not safe to
- // unfold a masked expand because we don't know if it came from an expand load
- // intrinsic or folding a plain load. If it is from a expand load intrinsic,
- // Unfolding to plain load would read more elements and could trigger a fault.
- if (RegRec->getName().contains("EXPAND"))
- Result.CannotUnfold = true;
- Table[RegInstr] = Result;
+ Table.push_back(Result);
}
void X86FoldTablesEmitter::updateTables(const CodeGenInstruction *RegInstr,
const CodeGenInstruction *MemInstr,
- const uint16_t S, bool IsManual) {
+ const UnfoldStrategy S) {
Record *RegRec = RegInstr->TheDef;
Record *MemRec = MemInstr->TheDef;
// Instructions which Read-Modify-Write should be added to Table2Addr.
if (MemOutSize != RegOutSize && MemInSize == RegInSize) {
- addEntryWithFlags(Table2Addr, RegInstr, MemInstr, S, 0, IsManual);
+ addEntryWithFlags(Table2Addr, RegInstr, MemInstr, S, 0);
return;
}
isMemoryOperand(MemOpRec)) {
switch (i) {
case 0:
- addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0, IsManual);
+ addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0);
return;
case 1:
- addEntryWithFlags(Table1, RegInstr, MemInstr, S, 1, IsManual);
+ addEntryWithFlags(Table1, RegInstr, MemInstr, S, 1);
return;
case 2:
- addEntryWithFlags(Table2, RegInstr, MemInstr, S, 2, IsManual);
+ addEntryWithFlags(Table2, RegInstr, MemInstr, S, 2);
return;
case 3:
- addEntryWithFlags(Table3, RegInstr, MemInstr, S, 3, IsManual);
+ addEntryWithFlags(Table3, RegInstr, MemInstr, S, 3);
return;
case 4:
- addEntryWithFlags(Table4, RegInstr, MemInstr, S, 4, IsManual);
+ addEntryWithFlags(Table4, RegInstr, MemInstr, S, 4);
return;
}
}
Record *MemOpRec = MemInstr->Operands[RegOutSize - 1].Rec;
if (isRegisterOperand(RegOpRec) && isMemoryOperand(MemOpRec) &&
getRegOperandSize(RegOpRec) == getMemOperandSize(MemOpRec))
- addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0, IsManual);
+ addEntryWithFlags(Table0, RegInstr, MemInstr, S, 0);
}
}
Record *MemInstIter = Records.getDef(Entry.MemInstStr);
updateTables(&(Target.getInstruction(RegInstIter)),
- &(Target.getInstruction(MemInstIter)), Entry.Strategy, true);
+ &(Target.getInstruction(MemInstIter)), Entry.Strategy);
}
+ // Sort the tables before printing.
+ llvm::sort(Table2Addr);
+ llvm::sort(Table0);
+ llvm::sort(Table1);
+ llvm::sort(Table2);
+ llvm::sort(Table3);
+ llvm::sort(Table4);
+
// Print all tables.
printTable(Table2Addr, "Table2Addr", OS);
printTable(Table0, "Table0", OS);
+++ /dev/null
-const ManualMapEntry ManualMapSet[] = {
- // Part1: These following records are for manually mapping instructions that
- // do not match by their encoding.
- { "ADD16ri_DB", "ADD16mi", TB_NO_REVERSE },
- { "ADD16ri8_DB", "ADD16mi8", TB_NO_REVERSE },
- { "ADD16rr_DB", "ADD16mr", TB_NO_REVERSE },
- { "ADD32ri_DB", "ADD32mi", TB_NO_REVERSE },
- { "ADD32ri8_DB", "ADD32mi8", TB_NO_REVERSE },
- { "ADD32rr_DB", "ADD32mr", TB_NO_REVERSE },
- { "ADD64ri32_DB", "ADD64mi32", TB_NO_REVERSE },
- { "ADD64ri8_DB", "ADD64mi8", TB_NO_REVERSE },
- { "ADD64rr_DB", "ADD64mr", TB_NO_REVERSE },
- { "ADD8ri_DB", "ADD8mi", TB_NO_REVERSE },
- { "ADD8rr_DB", "ADD8mr", TB_NO_REVERSE },
- { "ADD16rr_DB", "ADD16rm", TB_NO_REVERSE },
- { "ADD32rr_DB", "ADD32rm", TB_NO_REVERSE },
- { "ADD64rr_DB", "ADD64rm", TB_NO_REVERSE },
- { "ADD8rr_DB", "ADD8rm", TB_NO_REVERSE },
- { "MMX_MOVD64from64rr", "MMX_MOVQ64mr", TB_FOLDED_STORE },
- { "MMX_MOVD64grr", "MMX_MOVD64mr", TB_FOLDED_STORE },
- { "MOV64toSDrr", "MOV64mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "MOVDI2SSrr", "MOV32mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "MOVPQIto64rr", "MOVPQI2QImr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "MOVSDto64rr", "MOVSDmr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "MOVSS2DIrr", "MOVSSmr", TB_FOLDED_STORE },
- { "MOVLHPSrr", "MOVHPSrm", TB_NO_REVERSE },
- { "PUSH16r", "PUSH16rmm", TB_FOLDED_LOAD },
- { "PUSH32r", "PUSH32rmm", TB_FOLDED_LOAD },
- { "PUSH64r", "PUSH64rmm", TB_FOLDED_LOAD },
- { "TAILJMPr", "TAILJMPm", TB_FOLDED_LOAD },
- { "TAILJMPr64", "TAILJMPm64", TB_FOLDED_LOAD },
- { "TAILJMPr64_REX", "TAILJMPm64_REX", TB_FOLDED_LOAD },
- { "TCRETURNri", "TCRETURNmi", TB_FOLDED_LOAD | TB_NO_FORWARD },
- { "TCRETURNri64", "TCRETURNmi64", TB_FOLDED_LOAD | TB_NO_FORWARD },
- { "VMOVLHPSZrr", "VMOVHPSZ128rm", TB_NO_REVERSE },
- { "VMOVLHPSrr", "VMOVHPSrm", TB_NO_REVERSE },
- { "VMOV64toSDZrr", "MOV64mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOV64toSDrr", "MOV64mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVDI2SSZrr", "MOV32mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVDI2SSrr", "MOV32mr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVPQIto64Zrr", "VMOVPQI2QIZmr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVPQIto64rr", "VMOVPQI2QImr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVSDto64Zrr", "VMOVSDZmr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVSDto64rr", "VMOVSDmr", TB_FOLDED_STORE | TB_NO_REVERSE },
- { "VMOVSS2DIZrr", "VMOVSSZmr", TB_FOLDED_STORE },
- { "VMOVSS2DIrr", "VMOVSSmr", TB_FOLDED_STORE },
- { "MMX_MOVD64to64rr", "MMX_MOVQ64rm", 0 },
- { "MOV64toPQIrr", "MOVQI2PQIrm", TB_NO_REVERSE },
- { "MOV64toSDrr", "MOVSDrm_alt", TB_NO_REVERSE },
- { "MOVDI2SSrr", "MOVSSrm_alt", 0 },
- { "VMOV64toPQIZrr", "VMOVQI2PQIZrm", TB_NO_REVERSE },
- { "VMOV64toPQIrr", "VMOVQI2PQIrm", TB_NO_REVERSE },
- { "VMOV64toSDZrr", "VMOVSDZrm_alt", TB_NO_REVERSE },
- { "VMOV64toSDrr", "VMOVSDrm_alt", TB_NO_REVERSE },
- { "VMOVDI2SSZrr", "VMOVSSZrm_alt", 0 },
- { "VMOVDI2SSrr", "VMOVSSrm_alt", 0 },
- { "MOVSDrr", "MOVLPDrm", TB_NO_REVERSE },
- { "VMOVSDZrr", "VMOVLPDZ128rm", TB_NO_REVERSE },
- { "VMOVSDrr", "VMOVLPDrm", TB_NO_REVERSE },
-
- // Part2: These following records are for manually mapping instructions that
- // have same opcode.
- // INSERTPSrm has no count_s while INSERTPSrr has count_s.
- // count_s is to indicate which element in dst vector is inserted.
- // if count_s!=0, we can't fold INSERTPSrr into INSERTPSrm
- //
- // the following folding can happen when count_s==0
- // load xmm0, m32
- // insertpsrr xmm1, xmm0, imm
- // =>
- // insertpsrm xmm1, m32, imm
- { "INSERTPSrr", "INSERTPSrm", TB_NO_REVERSE | TB_NO_FORWARD },
- { "UD1Lr", "UD1Lm", TB_NO_REVERSE | TB_NO_FORWARD },
- { "UD1Qr", "UD1Qm", TB_NO_REVERSE | TB_NO_FORWARD },
- { "UD1Wr", "UD1Wm", TB_NO_REVERSE | TB_NO_FORWARD },
- // Remove {"MMX_MOVQ64rr", "MMX_MOVQ64mr"} since it will create duplicate in
- // unfolding table due to the {"MMX_MOVD64from64rr", "MMX_MOVQ64mr"}
- { "MMX_MOVQ64rr", "MMX_MOVQ64mr", TB_NO_FORWARD | TB_NO_REVERSE },
- // Remove {"MMX_MOVQ64rr", "MMX_MOVQ64rm"} since it will create duplicate in
- // unfolding table due to the {"MMX_MOVD64from64rr", "MMX_MOVQ64rm"}
- { "MMX_MOVQ64rr", "MMX_MOVQ64rm", TB_NO_FORWARD | TB_NO_REVERSE },
-};
-