1 //==- X86MnemonicTables.cpp - Generate mnemonic extraction tables. -*- C++ -*-//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend is responsible for emitting tables that group
10 // instructions by their mnemonic name wrt AsmWriter Variant (e.g. isADD, etc).
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "CodeGenInstruction.h"
15 #include "CodeGenTarget.h"
16 #include "X86DisassemblerTables.h"
17 #include "X86RecognizableInstr.h"
18 #include "llvm/TableGen/Error.h"
19 #include "llvm/TableGen/TableGenBackend.h"
20 
21 using namespace llvm;
22 
23 namespace {
24 
25 class X86MnemonicTablesEmitter {
26   CodeGenTarget Target;
27 
28 public:
29   X86MnemonicTablesEmitter(RecordKeeper &R) : Target(R) {}
30 
31   // Output X86 mnemonic tables.
32   void run(raw_ostream &OS);
33 };
34 
35 void X86MnemonicTablesEmitter::run(raw_ostream &OS) {
36   emitSourceFileHeader("X86 Mnemonic tables", OS);
37   OS << "namespace llvm {\nnamespace X86 {\n\n";
38   Record *AsmWriter = Target.getAsmWriter();
39   unsigned Variant = AsmWriter->getValueAsInt("Variant");
40 
41   // Hold all instructions grouped by mnemonic
42   StringMap<SmallVector<const CodeGenInstruction *, 0>> MnemonicToCGInstrMap;
43 
44   // Unused
45   X86Disassembler::DisassemblerTables Tables;
46   ArrayRef<const CodeGenInstruction *> NumberedInstructions =
47       Target.getInstructionsByEnumValue();
48   for (unsigned II = 0, IE = NumberedInstructions.size(); II != IE; ++II) {
49     const CodeGenInstruction *I = NumberedInstructions[II];
50     X86Disassembler::RecognizableInstr RI(Tables, *I, II);
51     Record *Def = I->TheDef;
52     if ( // Filter non-X86 instructions
53         !Def->isSubClassOf("X86Inst") ||
54         // Skip pseudo instructions as they may contain non-alnum characters in
55         // mnemonic
56         (RI.IsCodeGenOnly && !RI.ForceDisassemble) ||
57         // Non-parsable instruction defs contain prefix as part of AsmString
58         Def->getValueAsString("AsmVariantName") == "NonParsable" ||
59         // Skip CodeGenInstructions that are not real standalone instructions
60         RI.Form == X86Local::PrefixByte || RI.Form == X86Local::Pseudo)
61       continue;
62     // Flatten an instruction assembly string.
63     std::string AsmString = I->FlattenAsmStringVariants(I->AsmString, Variant);
64     StringRef Mnemonic(AsmString);
65     // Extract a mnemonic assuming it's separated by \t
66     Mnemonic = Mnemonic.take_until([](char C) { return C == '\t'; });
67 
68     // Special case: CMOVCC, JCC, SETCC have "${cond}" in mnemonic.
69     // Replace it with "CC" in-place.
70     size_t CondPos = Mnemonic.find("${cond}");
71     if (CondPos != StringRef::npos)
72       Mnemonic = AsmString.replace(CondPos, StringRef::npos, "CC");
73 
74     // It's intentional that we put a std::string to the map (StringRef::upper
75     // returns a string) as AsmString is deallocated at the end of the iteration
76     MnemonicToCGInstrMap[Mnemonic.upper()].push_back(I);
77   }
78 
79   OS << "#ifdef GET_X86_MNEMONIC_TABLES_H\n";
80   OS << "#undef GET_X86_MNEMONIC_TABLES_H\n\n";
81   for (StringRef Mnemonic : MnemonicToCGInstrMap.keys())
82     OS << "bool is" << Mnemonic << "(unsigned Opcode);\n";
83   OS << "#endif // GET_X86_MNEMONIC_TABLES_H\n\n";
84 
85   OS << "#ifdef GET_X86_MNEMONIC_TABLES_CPP\n";
86   OS << "#undef GET_X86_MNEMONIC_TABLES_CPP\n\n";
87   for (StringRef Mnemonic : MnemonicToCGInstrMap.keys()) {
88     OS << "bool is" << Mnemonic << "(unsigned Opcode) {\n";
89     auto Mnemonics = MnemonicToCGInstrMap[Mnemonic];
90     if (Mnemonics.size() == 1) {
91       const CodeGenInstruction *CGI = *Mnemonics.begin();
92       OS << "\treturn Opcode == " << CGI->TheDef->getName() << ";\n}\n\n";
93     } else {
94       OS << "\tswitch (Opcode) {\n";
95       for (const CodeGenInstruction *CGI : Mnemonics) {
96         OS << "\tcase " << CGI->TheDef->getName() << ":\n";
97       }
98       OS << "\t\treturn true;\n\t}\n\treturn false;\n}\n\n";
99     }
100   }
101   OS << "#endif // GET_X86_MNEMONIC_TABLES_CPP\n\n";
102   OS << "} // end namespace X86\n} // end namespace llvm";
103 }
104 
105 } // namespace
106 
107 namespace llvm {
108 void EmitX86MnemonicTables(RecordKeeper &RK, raw_ostream &OS) {
109   X86MnemonicTablesEmitter(RK).run(OS);
110 }
111 } // namespace llvm
112