1*0fca6ea1SDimitry Andric //========- utils/TableGen/X86InstrMappingEmitter.cpp - X86 backend-*- C++ -*-// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric /// 9*0fca6ea1SDimitry Andric /// This tablegen backend is responsible for emitting the X86 backend 10*0fca6ea1SDimitry Andric /// instruction mapping. 11*0fca6ea1SDimitry Andric /// 12*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 13*0fca6ea1SDimitry Andric 14*0fca6ea1SDimitry Andric #include "Common/CodeGenInstruction.h" 15*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h" 16*0fca6ea1SDimitry Andric #include "X86RecognizableInstr.h" 17*0fca6ea1SDimitry Andric #include "llvm/TableGen/Error.h" 18*0fca6ea1SDimitry Andric #include "llvm/TableGen/Record.h" 19*0fca6ea1SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 20*0fca6ea1SDimitry Andric #include <map> 21*0fca6ea1SDimitry Andric #include <set> 22*0fca6ea1SDimitry Andric 23*0fca6ea1SDimitry Andric using namespace llvm; 24*0fca6ea1SDimitry Andric using namespace X86Disassembler; 25*0fca6ea1SDimitry Andric 26*0fca6ea1SDimitry Andric namespace { 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric class X86InstrMappingEmitter { 29*0fca6ea1SDimitry Andric RecordKeeper &Records; 30*0fca6ea1SDimitry Andric CodeGenTarget Target; 31*0fca6ea1SDimitry Andric 32*0fca6ea1SDimitry Andric // Hold all pontentially compressible EVEX instructions 33*0fca6ea1SDimitry Andric std::vector<const CodeGenInstruction *> PreCompressionInsts; 34*0fca6ea1SDimitry Andric // Hold all compressed instructions. Divided into groups with same opcodes 35*0fca6ea1SDimitry Andric // to make the search more efficient 36*0fca6ea1SDimitry Andric std::map<uint64_t, std::vector<const CodeGenInstruction *>> CompressedInsts; 37*0fca6ea1SDimitry Andric 38*0fca6ea1SDimitry Andric typedef std::pair<const CodeGenInstruction *, const CodeGenInstruction *> 39*0fca6ea1SDimitry Andric Entry; 40*0fca6ea1SDimitry Andric typedef std::map<StringRef, std::vector<const CodeGenInstruction *>> 41*0fca6ea1SDimitry Andric PredicateInstMap; 42*0fca6ea1SDimitry Andric 43*0fca6ea1SDimitry Andric // Hold all compressed instructions that need to check predicate 44*0fca6ea1SDimitry Andric PredicateInstMap PredicateInsts; 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric public: 47*0fca6ea1SDimitry Andric X86InstrMappingEmitter(RecordKeeper &R) : Records(R), Target(R) {} 48*0fca6ea1SDimitry Andric 49*0fca6ea1SDimitry Andric // run - Output X86 EVEX compression tables. 50*0fca6ea1SDimitry Andric void run(raw_ostream &OS); 51*0fca6ea1SDimitry Andric 52*0fca6ea1SDimitry Andric private: 53*0fca6ea1SDimitry Andric void emitCompressEVEXTable(ArrayRef<const CodeGenInstruction *> Insts, 54*0fca6ea1SDimitry Andric raw_ostream &OS); 55*0fca6ea1SDimitry Andric void emitNFTransformTable(ArrayRef<const CodeGenInstruction *> Insts, 56*0fca6ea1SDimitry Andric raw_ostream &OS); 57*0fca6ea1SDimitry Andric void emitND2NonNDTable(ArrayRef<const CodeGenInstruction *> Insts, 58*0fca6ea1SDimitry Andric raw_ostream &OS); 59*0fca6ea1SDimitry Andric void emitSSE2AVXTable(ArrayRef<const CodeGenInstruction *> Insts, 60*0fca6ea1SDimitry Andric raw_ostream &OS); 61*0fca6ea1SDimitry Andric 62*0fca6ea1SDimitry Andric // Prints the definition of class X86TableEntry. 63*0fca6ea1SDimitry Andric void printClassDef(raw_ostream &OS); 64*0fca6ea1SDimitry Andric // Prints the given table as a C++ array of type X86TableEntry under the guard 65*0fca6ea1SDimitry Andric // \p Macro. 66*0fca6ea1SDimitry Andric void printTable(const std::vector<Entry> &Table, StringRef Name, 67*0fca6ea1SDimitry Andric StringRef Macro, raw_ostream &OS); 68*0fca6ea1SDimitry Andric }; 69*0fca6ea1SDimitry Andric 70*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::printClassDef(raw_ostream &OS) { 71*0fca6ea1SDimitry Andric OS << "struct X86TableEntry {\n" 72*0fca6ea1SDimitry Andric " uint16_t OldOpc;\n" 73*0fca6ea1SDimitry Andric " uint16_t NewOpc;\n" 74*0fca6ea1SDimitry Andric " bool operator<(const X86TableEntry &RHS) const {\n" 75*0fca6ea1SDimitry Andric " return OldOpc < RHS.OldOpc;\n" 76*0fca6ea1SDimitry Andric " }" 77*0fca6ea1SDimitry Andric " friend bool operator<(const X86TableEntry &TE, unsigned Opc) {\n" 78*0fca6ea1SDimitry Andric " return TE.OldOpc < Opc;\n" 79*0fca6ea1SDimitry Andric " }\n" 80*0fca6ea1SDimitry Andric "};"; 81*0fca6ea1SDimitry Andric 82*0fca6ea1SDimitry Andric OS << "\n\n"; 83*0fca6ea1SDimitry Andric } 84*0fca6ea1SDimitry Andric 85*0fca6ea1SDimitry Andric static void printMacroBegin(StringRef Macro, raw_ostream &OS) { 86*0fca6ea1SDimitry Andric OS << "\n#ifdef " << Macro << "\n"; 87*0fca6ea1SDimitry Andric } 88*0fca6ea1SDimitry Andric 89*0fca6ea1SDimitry Andric static void printMacroEnd(StringRef Macro, raw_ostream &OS) { 90*0fca6ea1SDimitry Andric OS << "#endif // " << Macro << "\n\n"; 91*0fca6ea1SDimitry Andric } 92*0fca6ea1SDimitry Andric 93*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::printTable(const std::vector<Entry> &Table, 94*0fca6ea1SDimitry Andric StringRef Name, StringRef Macro, 95*0fca6ea1SDimitry Andric raw_ostream &OS) { 96*0fca6ea1SDimitry Andric printMacroBegin(Macro, OS); 97*0fca6ea1SDimitry Andric 98*0fca6ea1SDimitry Andric OS << "static const X86TableEntry " << Name << "[] = {\n"; 99*0fca6ea1SDimitry Andric 100*0fca6ea1SDimitry Andric // Print all entries added to the table 101*0fca6ea1SDimitry Andric for (const auto &Pair : Table) 102*0fca6ea1SDimitry Andric OS << " { X86::" << Pair.first->TheDef->getName() 103*0fca6ea1SDimitry Andric << ", X86::" << Pair.second->TheDef->getName() << " },\n"; 104*0fca6ea1SDimitry Andric 105*0fca6ea1SDimitry Andric OS << "};\n\n"; 106*0fca6ea1SDimitry Andric 107*0fca6ea1SDimitry Andric printMacroEnd(Macro, OS); 108*0fca6ea1SDimitry Andric } 109*0fca6ea1SDimitry Andric 110*0fca6ea1SDimitry Andric static uint8_t byteFromBitsInit(const BitsInit *B) { 111*0fca6ea1SDimitry Andric unsigned N = B->getNumBits(); 112*0fca6ea1SDimitry Andric assert(N <= 8 && "Field is too large for uint8_t!"); 113*0fca6ea1SDimitry Andric 114*0fca6ea1SDimitry Andric uint8_t Value = 0; 115*0fca6ea1SDimitry Andric for (unsigned I = 0; I != N; ++I) { 116*0fca6ea1SDimitry Andric BitInit *Bit = cast<BitInit>(B->getBit(I)); 117*0fca6ea1SDimitry Andric Value |= Bit->getValue() << I; 118*0fca6ea1SDimitry Andric } 119*0fca6ea1SDimitry Andric return Value; 120*0fca6ea1SDimitry Andric } 121*0fca6ea1SDimitry Andric 122*0fca6ea1SDimitry Andric class IsMatch { 123*0fca6ea1SDimitry Andric const CodeGenInstruction *OldInst; 124*0fca6ea1SDimitry Andric 125*0fca6ea1SDimitry Andric public: 126*0fca6ea1SDimitry Andric IsMatch(const CodeGenInstruction *OldInst) : OldInst(OldInst) {} 127*0fca6ea1SDimitry Andric 128*0fca6ea1SDimitry Andric bool operator()(const CodeGenInstruction *NewInst) { 129*0fca6ea1SDimitry Andric RecognizableInstrBase NewRI(*NewInst); 130*0fca6ea1SDimitry Andric RecognizableInstrBase OldRI(*OldInst); 131*0fca6ea1SDimitry Andric 132*0fca6ea1SDimitry Andric // Return false if any of the following fields of does not match. 133*0fca6ea1SDimitry Andric if (std::tuple(OldRI.IsCodeGenOnly, OldRI.OpMap, NewRI.OpPrefix, 134*0fca6ea1SDimitry Andric OldRI.HasVEX_4V, OldRI.HasVEX_L, OldRI.HasREX_W, 135*0fca6ea1SDimitry Andric OldRI.Form) != 136*0fca6ea1SDimitry Andric std::tuple(NewRI.IsCodeGenOnly, NewRI.OpMap, OldRI.OpPrefix, 137*0fca6ea1SDimitry Andric NewRI.HasVEX_4V, NewRI.HasVEX_L, NewRI.HasREX_W, NewRI.Form)) 138*0fca6ea1SDimitry Andric return false; 139*0fca6ea1SDimitry Andric 140*0fca6ea1SDimitry Andric for (unsigned I = 0, E = OldInst->Operands.size(); I < E; ++I) { 141*0fca6ea1SDimitry Andric Record *OldOpRec = OldInst->Operands[I].Rec; 142*0fca6ea1SDimitry Andric Record *NewOpRec = NewInst->Operands[I].Rec; 143*0fca6ea1SDimitry Andric 144*0fca6ea1SDimitry Andric if (OldOpRec == NewOpRec) 145*0fca6ea1SDimitry Andric continue; 146*0fca6ea1SDimitry Andric 147*0fca6ea1SDimitry Andric if (isRegisterOperand(OldOpRec) && isRegisterOperand(NewOpRec)) { 148*0fca6ea1SDimitry Andric if (getRegOperandSize(OldOpRec) != getRegOperandSize(NewOpRec)) 149*0fca6ea1SDimitry Andric return false; 150*0fca6ea1SDimitry Andric } else if (isMemoryOperand(OldOpRec) && isMemoryOperand(NewOpRec)) { 151*0fca6ea1SDimitry Andric if (getMemOperandSize(OldOpRec) != getMemOperandSize(NewOpRec)) 152*0fca6ea1SDimitry Andric return false; 153*0fca6ea1SDimitry Andric } else if (isImmediateOperand(OldOpRec) && isImmediateOperand(NewOpRec)) { 154*0fca6ea1SDimitry Andric if (OldOpRec->getValueAsDef("Type") != NewOpRec->getValueAsDef("Type")) 155*0fca6ea1SDimitry Andric return false; 156*0fca6ea1SDimitry Andric } 157*0fca6ea1SDimitry Andric } 158*0fca6ea1SDimitry Andric 159*0fca6ea1SDimitry Andric return true; 160*0fca6ea1SDimitry Andric } 161*0fca6ea1SDimitry Andric }; 162*0fca6ea1SDimitry Andric 163*0fca6ea1SDimitry Andric static bool isInteresting(const Record *Rec) { 164*0fca6ea1SDimitry Andric // _REV instruction should not appear before encoding optimization 165*0fca6ea1SDimitry Andric return Rec->isSubClassOf("X86Inst") && 166*0fca6ea1SDimitry Andric !Rec->getValueAsBit("isAsmParserOnly") && 167*0fca6ea1SDimitry Andric !Rec->getName().ends_with("_REV"); 168*0fca6ea1SDimitry Andric } 169*0fca6ea1SDimitry Andric 170*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::emitCompressEVEXTable( 171*0fca6ea1SDimitry Andric ArrayRef<const CodeGenInstruction *> Insts, raw_ostream &OS) { 172*0fca6ea1SDimitry Andric 173*0fca6ea1SDimitry Andric const std::map<StringRef, StringRef> ManualMap = { 174*0fca6ea1SDimitry Andric #define ENTRY(OLD, NEW) {#OLD, #NEW}, 175*0fca6ea1SDimitry Andric #include "X86ManualInstrMapping.def" 176*0fca6ea1SDimitry Andric }; 177*0fca6ea1SDimitry Andric const std::set<StringRef> NoCompressSet = { 178*0fca6ea1SDimitry Andric #define NOCOMP(INSN) #INSN, 179*0fca6ea1SDimitry Andric #include "X86ManualInstrMapping.def" 180*0fca6ea1SDimitry Andric }; 181*0fca6ea1SDimitry Andric 182*0fca6ea1SDimitry Andric for (const CodeGenInstruction *Inst : Insts) { 183*0fca6ea1SDimitry Andric const Record *Rec = Inst->TheDef; 184*0fca6ea1SDimitry Andric StringRef Name = Rec->getName(); 185*0fca6ea1SDimitry Andric if (!isInteresting(Rec)) 186*0fca6ea1SDimitry Andric continue; 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric // Promoted legacy instruction is in EVEX space, and has REX2-encoding 189*0fca6ea1SDimitry Andric // alternative. It's added due to HW design and never emitted by compiler. 190*0fca6ea1SDimitry Andric if (byteFromBitsInit(Rec->getValueAsBitsInit("OpMapBits")) == 191*0fca6ea1SDimitry Andric X86Local::T_MAP4 && 192*0fca6ea1SDimitry Andric byteFromBitsInit(Rec->getValueAsBitsInit("explicitOpPrefixBits")) == 193*0fca6ea1SDimitry Andric X86Local::ExplicitEVEX) 194*0fca6ea1SDimitry Andric continue; 195*0fca6ea1SDimitry Andric 196*0fca6ea1SDimitry Andric if (NoCompressSet.find(Name) != NoCompressSet.end()) 197*0fca6ea1SDimitry Andric continue; 198*0fca6ea1SDimitry Andric 199*0fca6ea1SDimitry Andric RecognizableInstrBase RI(*Inst); 200*0fca6ea1SDimitry Andric 201*0fca6ea1SDimitry Andric bool IsND = RI.OpMap == X86Local::T_MAP4 && RI.HasEVEX_B && RI.HasVEX_4V; 202*0fca6ea1SDimitry Andric // Add VEX encoded instructions to one of CompressedInsts vectors according 203*0fca6ea1SDimitry Andric // to it's opcode. 204*0fca6ea1SDimitry Andric if (RI.Encoding == X86Local::VEX) 205*0fca6ea1SDimitry Andric CompressedInsts[RI.Opcode].push_back(Inst); 206*0fca6ea1SDimitry Andric // Add relevant EVEX encoded instructions to PreCompressionInsts 207*0fca6ea1SDimitry Andric else if (RI.Encoding == X86Local::EVEX && !RI.HasEVEX_K && !RI.HasEVEX_L2 && 208*0fca6ea1SDimitry Andric (!RI.HasEVEX_B || IsND)) 209*0fca6ea1SDimitry Andric PreCompressionInsts.push_back(Inst); 210*0fca6ea1SDimitry Andric } 211*0fca6ea1SDimitry Andric 212*0fca6ea1SDimitry Andric std::vector<Entry> Table; 213*0fca6ea1SDimitry Andric for (const CodeGenInstruction *Inst : PreCompressionInsts) { 214*0fca6ea1SDimitry Andric const Record *Rec = Inst->TheDef; 215*0fca6ea1SDimitry Andric uint8_t Opcode = byteFromBitsInit(Rec->getValueAsBitsInit("Opcode")); 216*0fca6ea1SDimitry Andric StringRef Name = Rec->getName(); 217*0fca6ea1SDimitry Andric const CodeGenInstruction *NewInst = nullptr; 218*0fca6ea1SDimitry Andric if (ManualMap.find(Name) != ManualMap.end()) { 219*0fca6ea1SDimitry Andric Record *NewRec = Records.getDef(ManualMap.at(Rec->getName())); 220*0fca6ea1SDimitry Andric assert(NewRec && "Instruction not found!"); 221*0fca6ea1SDimitry Andric NewInst = &Target.getInstruction(NewRec); 222*0fca6ea1SDimitry Andric } else if (Name.ends_with("_EVEX")) { 223*0fca6ea1SDimitry Andric if (auto *NewRec = Records.getDef(Name.drop_back(5))) 224*0fca6ea1SDimitry Andric NewInst = &Target.getInstruction(NewRec); 225*0fca6ea1SDimitry Andric } else if (Name.ends_with("_ND")) 226*0fca6ea1SDimitry Andric // Leave it to ND2NONND table. 227*0fca6ea1SDimitry Andric continue; 228*0fca6ea1SDimitry Andric else { 229*0fca6ea1SDimitry Andric // For each pre-compression instruction look for a match in the 230*0fca6ea1SDimitry Andric // appropriate vector (instructions with the same opcode) using function 231*0fca6ea1SDimitry Andric // object IsMatch. 232*0fca6ea1SDimitry Andric auto Match = llvm::find_if(CompressedInsts[Opcode], IsMatch(Inst)); 233*0fca6ea1SDimitry Andric if (Match != CompressedInsts[Opcode].end()) 234*0fca6ea1SDimitry Andric NewInst = *Match; 235*0fca6ea1SDimitry Andric } 236*0fca6ea1SDimitry Andric 237*0fca6ea1SDimitry Andric if (!NewInst) 238*0fca6ea1SDimitry Andric continue; 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric Table.push_back(std::pair(Inst, NewInst)); 241*0fca6ea1SDimitry Andric auto Predicates = NewInst->TheDef->getValueAsListOfDefs("Predicates"); 242*0fca6ea1SDimitry Andric auto It = llvm::find_if(Predicates, [](const Record *R) { 243*0fca6ea1SDimitry Andric StringRef Name = R->getName(); 244*0fca6ea1SDimitry Andric return Name == "HasAVXNECONVERT" || Name == "HasAVXVNNI" || 245*0fca6ea1SDimitry Andric Name == "HasAVXIFMA"; 246*0fca6ea1SDimitry Andric }); 247*0fca6ea1SDimitry Andric if (It != Predicates.end()) 248*0fca6ea1SDimitry Andric PredicateInsts[(*It)->getValueAsString("CondString")].push_back(NewInst); 249*0fca6ea1SDimitry Andric } 250*0fca6ea1SDimitry Andric 251*0fca6ea1SDimitry Andric StringRef Macro = "GET_X86_COMPRESS_EVEX_TABLE"; 252*0fca6ea1SDimitry Andric printTable(Table, "X86CompressEVEXTable", Macro, OS); 253*0fca6ea1SDimitry Andric 254*0fca6ea1SDimitry Andric // Prints function which checks target feature for compressed instructions. 255*0fca6ea1SDimitry Andric printMacroBegin(Macro, OS); 256*0fca6ea1SDimitry Andric OS << "static bool checkPredicate(unsigned Opc, const X86Subtarget " 257*0fca6ea1SDimitry Andric "*Subtarget) {\n" 258*0fca6ea1SDimitry Andric << " switch (Opc) {\n" 259*0fca6ea1SDimitry Andric << " default: return true;\n"; 260*0fca6ea1SDimitry Andric for (const auto &[Key, Val] : PredicateInsts) { 261*0fca6ea1SDimitry Andric for (const auto &Inst : Val) 262*0fca6ea1SDimitry Andric OS << " case X86::" << Inst->TheDef->getName() << ":\n"; 263*0fca6ea1SDimitry Andric OS << " return " << Key << ";\n"; 264*0fca6ea1SDimitry Andric } 265*0fca6ea1SDimitry Andric OS << " }\n"; 266*0fca6ea1SDimitry Andric OS << "}\n\n"; 267*0fca6ea1SDimitry Andric printMacroEnd(Macro, OS); 268*0fca6ea1SDimitry Andric } 269*0fca6ea1SDimitry Andric 270*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::emitNFTransformTable( 271*0fca6ea1SDimitry Andric ArrayRef<const CodeGenInstruction *> Insts, raw_ostream &OS) { 272*0fca6ea1SDimitry Andric std::vector<Entry> Table; 273*0fca6ea1SDimitry Andric for (const CodeGenInstruction *Inst : Insts) { 274*0fca6ea1SDimitry Andric const Record *Rec = Inst->TheDef; 275*0fca6ea1SDimitry Andric if (!isInteresting(Rec)) 276*0fca6ea1SDimitry Andric continue; 277*0fca6ea1SDimitry Andric std::string Name = Rec->getName().str(); 278*0fca6ea1SDimitry Andric auto Pos = Name.find("_NF"); 279*0fca6ea1SDimitry Andric if (Pos == std::string::npos) 280*0fca6ea1SDimitry Andric continue; 281*0fca6ea1SDimitry Andric 282*0fca6ea1SDimitry Andric if (auto *NewRec = Records.getDef(Name.erase(Pos, 3))) { 283*0fca6ea1SDimitry Andric #ifndef NDEBUG 284*0fca6ea1SDimitry Andric auto ClobberEFLAGS = [](const Record *R) { 285*0fca6ea1SDimitry Andric return llvm::any_of( 286*0fca6ea1SDimitry Andric R->getValueAsListOfDefs("Defs"), 287*0fca6ea1SDimitry Andric [](const Record *Def) { return Def->getName() == "EFLAGS"; }); 288*0fca6ea1SDimitry Andric }; 289*0fca6ea1SDimitry Andric if (ClobberEFLAGS(Rec)) 290*0fca6ea1SDimitry Andric report_fatal_error("EFLAGS should not be clobbered by " + 291*0fca6ea1SDimitry Andric Rec->getName()); 292*0fca6ea1SDimitry Andric if (!ClobberEFLAGS(NewRec)) 293*0fca6ea1SDimitry Andric report_fatal_error("EFLAGS should be clobbered by " + 294*0fca6ea1SDimitry Andric NewRec->getName()); 295*0fca6ea1SDimitry Andric #endif 296*0fca6ea1SDimitry Andric Table.push_back(std::pair(&Target.getInstruction(NewRec), Inst)); 297*0fca6ea1SDimitry Andric } 298*0fca6ea1SDimitry Andric } 299*0fca6ea1SDimitry Andric printTable(Table, "X86NFTransformTable", "GET_X86_NF_TRANSFORM_TABLE", OS); 300*0fca6ea1SDimitry Andric } 301*0fca6ea1SDimitry Andric 302*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::emitND2NonNDTable( 303*0fca6ea1SDimitry Andric ArrayRef<const CodeGenInstruction *> Insts, raw_ostream &OS) { 304*0fca6ea1SDimitry Andric 305*0fca6ea1SDimitry Andric const std::map<StringRef, StringRef> ManualMap = { 306*0fca6ea1SDimitry Andric #define ENTRY_ND(OLD, NEW) {#OLD, #NEW}, 307*0fca6ea1SDimitry Andric #include "X86ManualInstrMapping.def" 308*0fca6ea1SDimitry Andric }; 309*0fca6ea1SDimitry Andric const std::set<StringRef> NoCompressSet = { 310*0fca6ea1SDimitry Andric #define NOCOMP_ND(INSN) #INSN, 311*0fca6ea1SDimitry Andric #include "X86ManualInstrMapping.def" 312*0fca6ea1SDimitry Andric }; 313*0fca6ea1SDimitry Andric 314*0fca6ea1SDimitry Andric std::vector<Entry> Table; 315*0fca6ea1SDimitry Andric for (const CodeGenInstruction *Inst : Insts) { 316*0fca6ea1SDimitry Andric const Record *Rec = Inst->TheDef; 317*0fca6ea1SDimitry Andric StringRef Name = Rec->getName(); 318*0fca6ea1SDimitry Andric if (!isInteresting(Rec) || NoCompressSet.find(Name) != NoCompressSet.end()) 319*0fca6ea1SDimitry Andric continue; 320*0fca6ea1SDimitry Andric if (ManualMap.find(Name) != ManualMap.end()) { 321*0fca6ea1SDimitry Andric auto *NewRec = Records.getDef(ManualMap.at(Rec->getName())); 322*0fca6ea1SDimitry Andric assert(NewRec && "Instruction not found!"); 323*0fca6ea1SDimitry Andric auto &NewInst = Target.getInstruction(NewRec); 324*0fca6ea1SDimitry Andric Table.push_back(std::pair(Inst, &NewInst)); 325*0fca6ea1SDimitry Andric continue; 326*0fca6ea1SDimitry Andric } 327*0fca6ea1SDimitry Andric 328*0fca6ea1SDimitry Andric if (!Name.ends_with("_ND")) 329*0fca6ea1SDimitry Andric continue; 330*0fca6ea1SDimitry Andric auto *NewRec = Records.getDef(Name.drop_back(3)); 331*0fca6ea1SDimitry Andric if (!NewRec) 332*0fca6ea1SDimitry Andric continue; 333*0fca6ea1SDimitry Andric auto &NewInst = Target.getInstruction(NewRec); 334*0fca6ea1SDimitry Andric if (isRegisterOperand(NewInst.Operands[0].Rec)) 335*0fca6ea1SDimitry Andric Table.push_back(std::pair(Inst, &NewInst)); 336*0fca6ea1SDimitry Andric } 337*0fca6ea1SDimitry Andric printTable(Table, "X86ND2NonNDTable", "GET_X86_ND2NONND_TABLE", OS); 338*0fca6ea1SDimitry Andric } 339*0fca6ea1SDimitry Andric 340*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::emitSSE2AVXTable( 341*0fca6ea1SDimitry Andric ArrayRef<const CodeGenInstruction *> Insts, raw_ostream &OS) { 342*0fca6ea1SDimitry Andric 343*0fca6ea1SDimitry Andric const std::map<StringRef, StringRef> ManualMap = { 344*0fca6ea1SDimitry Andric #define ENTRY_SSE2AVX(OLD, NEW) {#OLD, #NEW}, 345*0fca6ea1SDimitry Andric #include "X86ManualInstrMapping.def" 346*0fca6ea1SDimitry Andric }; 347*0fca6ea1SDimitry Andric 348*0fca6ea1SDimitry Andric std::vector<Entry> Table; 349*0fca6ea1SDimitry Andric for (const CodeGenInstruction *Inst : Insts) { 350*0fca6ea1SDimitry Andric const Record *Rec = Inst->TheDef; 351*0fca6ea1SDimitry Andric StringRef Name = Rec->getName(); 352*0fca6ea1SDimitry Andric if (!isInteresting(Rec)) 353*0fca6ea1SDimitry Andric continue; 354*0fca6ea1SDimitry Andric if (ManualMap.find(Name) != ManualMap.end()) { 355*0fca6ea1SDimitry Andric auto *NewRec = Records.getDef(ManualMap.at(Rec->getName())); 356*0fca6ea1SDimitry Andric assert(NewRec && "Instruction not found!"); 357*0fca6ea1SDimitry Andric auto &NewInst = Target.getInstruction(NewRec); 358*0fca6ea1SDimitry Andric Table.push_back(std::pair(Inst, &NewInst)); 359*0fca6ea1SDimitry Andric continue; 360*0fca6ea1SDimitry Andric } 361*0fca6ea1SDimitry Andric 362*0fca6ea1SDimitry Andric std::string NewName = ("V" + Name).str(); 363*0fca6ea1SDimitry Andric auto *AVXRec = Records.getDef(NewName); 364*0fca6ea1SDimitry Andric if (!AVXRec) 365*0fca6ea1SDimitry Andric continue; 366*0fca6ea1SDimitry Andric auto &AVXInst = Target.getInstruction(AVXRec); 367*0fca6ea1SDimitry Andric Table.push_back(std::pair(Inst, &AVXInst)); 368*0fca6ea1SDimitry Andric } 369*0fca6ea1SDimitry Andric printTable(Table, "X86SSE2AVXTable", "GET_X86_SSE2AVX_TABLE", OS); 370*0fca6ea1SDimitry Andric } 371*0fca6ea1SDimitry Andric 372*0fca6ea1SDimitry Andric void X86InstrMappingEmitter::run(raw_ostream &OS) { 373*0fca6ea1SDimitry Andric emitSourceFileHeader("X86 instruction mapping", OS); 374*0fca6ea1SDimitry Andric 375*0fca6ea1SDimitry Andric ArrayRef<const CodeGenInstruction *> Insts = 376*0fca6ea1SDimitry Andric Target.getInstructionsByEnumValue(); 377*0fca6ea1SDimitry Andric printClassDef(OS); 378*0fca6ea1SDimitry Andric emitCompressEVEXTable(Insts, OS); 379*0fca6ea1SDimitry Andric emitNFTransformTable(Insts, OS); 380*0fca6ea1SDimitry Andric emitND2NonNDTable(Insts, OS); 381*0fca6ea1SDimitry Andric emitSSE2AVXTable(Insts, OS); 382*0fca6ea1SDimitry Andric } 383*0fca6ea1SDimitry Andric } // namespace 384*0fca6ea1SDimitry Andric 385*0fca6ea1SDimitry Andric static TableGen::Emitter::OptClass<X86InstrMappingEmitter> 386*0fca6ea1SDimitry Andric X("gen-x86-instr-mapping", "Generate X86 instruction mapping"); 387