1 //==- utils/TableGen/X86CompressEVEXTablesEmitter.cpp - X86 backend-*- C++ -*-//
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
7 //===----------------------------------------------------------------------===//
9 /// This tablegen backend is responsible for emitting the X86 backend EVEX
10 /// compression tables.
12 //===----------------------------------------------------------------------===//
14 #include "CodeGenInstruction.h"
15 #include "CodeGenTarget.h"
16 #include "X86RecognizableInstr.h"
17 #include "llvm/TableGen/Error.h"
18 #include "llvm/TableGen/Record.h"
19 #include "llvm/TableGen/TableGenBackend.h"
24 using namespace X86Disassembler
;
28 const std::map
<StringRef
, StringRef
> ManualMap
= {
29 #define ENTRY(OLD, NEW) {#OLD, #NEW},
30 #include "X86ManualCompressEVEXTables.def"
32 const std::set
<StringRef
> NoCompressSet
= {
33 #define NOCOMP(INSN) #INSN,
34 #include "X86ManualCompressEVEXTables.def"
37 class X86CompressEVEXTablesEmitter
{
38 RecordKeeper
&Records
;
41 // Hold all pontentially compressible EVEX instructions
42 std::vector
<const CodeGenInstruction
*> PreCompressionInsts
;
43 // Hold all compressed instructions. Divided into groups with same opcodes
44 // to make the search more efficient
45 std::map
<uint64_t, std::vector
<const CodeGenInstruction
*>> CompressedInsts
;
47 typedef std::pair
<const CodeGenInstruction
*, const CodeGenInstruction
*>
49 typedef std::map
<const Record
*, std::vector
<const CodeGenInstruction
*>>
52 std::vector
<Entry
> Table
;
53 // Hold all compressed instructions that need to check predicate
54 PredicateInstMap PredicateInsts
;
57 X86CompressEVEXTablesEmitter(RecordKeeper
&R
) : Records(R
), Target(R
) {}
59 // run - Output X86 EVEX compression tables.
60 void run(raw_ostream
&OS
);
63 // Prints the given table as a C++ array of type X86CompressEVEXTableEntry
64 void printTable(const std::vector
<Entry
> &Table
, raw_ostream
&OS
);
65 // Prints function which checks target feature for compressed instructions.
66 void printCheckPredicate(const PredicateInstMap
&PredicateInsts
,
70 void X86CompressEVEXTablesEmitter::printTable(const std::vector
<Entry
> &Table
,
73 OS
<< "static const X86CompressEVEXTableEntry X86CompressEVEXTable[] = {\n";
75 // Print all entries added to the table
76 for (const auto &Pair
: Table
)
77 OS
<< " { X86::" << Pair
.first
->TheDef
->getName()
78 << ", X86::" << Pair
.second
->TheDef
->getName() << " },\n";
83 void X86CompressEVEXTablesEmitter::printCheckPredicate(
84 const PredicateInstMap
&PredicateInsts
, raw_ostream
&OS
) {
86 OS
<< "static bool checkPredicate(unsigned Opc, const X86Subtarget *Subtarget) {\n"
87 << " switch (Opc) {\n"
88 << " default: return true;\n";
89 for (const auto &[Key
, Val
] : PredicateInsts
) {
90 for (const auto &Inst
: Val
)
91 OS
<< " case X86::" << Inst
->TheDef
->getName() << ":\n";
92 OS
<< " return " << Key
->getValueAsString("CondString") << ";\n";
99 static uint8_t byteFromBitsInit(const BitsInit
*B
) {
100 unsigned N
= B
->getNumBits();
101 assert(N
<= 8 && "Field is too large for uint8_t!");
104 for (unsigned I
= 0; I
!= N
; ++I
) {
105 BitInit
*Bit
= cast
<BitInit
>(B
->getBit(I
));
106 Value
|= Bit
->getValue() << I
;
112 const CodeGenInstruction
*OldInst
;
115 IsMatch(const CodeGenInstruction
*OldInst
) : OldInst(OldInst
) {}
117 bool operator()(const CodeGenInstruction
*NewInst
) {
118 RecognizableInstrBase
NewRI(*NewInst
);
119 RecognizableInstrBase
OldRI(*OldInst
);
121 // Return false if any of the following fields of does not match.
122 if (std::make_tuple(OldRI
.IsCodeGenOnly
, OldRI
.OpMap
, NewRI
.OpPrefix
,
123 OldRI
.HasVEX_4V
, OldRI
.HasVEX_L
, OldRI
.HasREX_W
,
125 std::make_tuple(NewRI
.IsCodeGenOnly
, NewRI
.OpMap
, OldRI
.OpPrefix
,
126 NewRI
.HasVEX_4V
, NewRI
.HasVEX_L
, NewRI
.HasREX_W
,
130 for (unsigned I
= 0, E
= OldInst
->Operands
.size(); I
< E
; ++I
) {
131 Record
*OldOpRec
= OldInst
->Operands
[I
].Rec
;
132 Record
*NewOpRec
= NewInst
->Operands
[I
].Rec
;
134 if (OldOpRec
== NewOpRec
)
137 if (isRegisterOperand(OldOpRec
) && isRegisterOperand(NewOpRec
)) {
138 if (getRegOperandSize(OldOpRec
) != getRegOperandSize(NewOpRec
))
140 } else if (isMemoryOperand(OldOpRec
) && isMemoryOperand(NewOpRec
)) {
141 if (getMemOperandSize(OldOpRec
) != getMemOperandSize(NewOpRec
))
143 } else if (isImmediateOperand(OldOpRec
) && isImmediateOperand(NewOpRec
)) {
144 if (OldOpRec
->getValueAsDef("Type") != NewOpRec
->getValueAsDef("Type"))
153 void X86CompressEVEXTablesEmitter::run(raw_ostream
&OS
) {
154 emitSourceFileHeader("X86 EVEX compression tables", OS
);
156 ArrayRef
<const CodeGenInstruction
*> NumberedInstructions
=
157 Target
.getInstructionsByEnumValue();
159 for (const CodeGenInstruction
*Inst
: NumberedInstructions
) {
160 const Record
*Rec
= Inst
->TheDef
;
161 StringRef Name
= Rec
->getName();
162 // _REV instruction should not appear before encoding optimization
163 if (!Rec
->isSubClassOf("X86Inst") ||
164 Rec
->getValueAsBit("isAsmParserOnly") || Name
.ends_with("_REV"))
167 // Promoted legacy instruction is in EVEX space, and has REX2-encoding
168 // alternative. It's added due to HW design and never emitted by compiler.
169 if (byteFromBitsInit(Rec
->getValueAsBitsInit("OpMapBits")) ==
171 byteFromBitsInit(Rec
->getValueAsBitsInit("explicitOpPrefixBits")) ==
172 X86Local::ExplicitEVEX
)
175 if (NoCompressSet
.find(Name
) != NoCompressSet
.end())
178 RecognizableInstrBase
RI(*Inst
);
180 bool IsND
= RI
.OpMap
== X86Local::T_MAP4
&& RI
.HasEVEX_B
&& RI
.HasVEX_4V
;
181 // Add VEX encoded instructions to one of CompressedInsts vectors according
183 if (RI
.Encoding
== X86Local::VEX
)
184 CompressedInsts
[RI
.Opcode
].push_back(Inst
);
185 // Add relevant EVEX encoded instructions to PreCompressionInsts
186 else if (RI
.Encoding
== X86Local::EVEX
&& !RI
.HasEVEX_K
&& !RI
.HasEVEX_L2
&&
187 (!RI
.HasEVEX_B
|| IsND
))
188 PreCompressionInsts
.push_back(Inst
);
191 for (const CodeGenInstruction
*Inst
: PreCompressionInsts
) {
192 const Record
*Rec
= Inst
->TheDef
;
193 uint8_t Opcode
= byteFromBitsInit(Rec
->getValueAsBitsInit("Opcode"));
194 StringRef Name
= Rec
->getName();
195 const CodeGenInstruction
*NewInst
= nullptr;
196 if (ManualMap
.find(Name
) != ManualMap
.end()) {
197 Record
*NewRec
= Records
.getDef(ManualMap
.at(Rec
->getName()));
198 assert(NewRec
&& "Instruction not found!");
199 NewInst
= &Target
.getInstruction(NewRec
);
200 } else if (Name
.ends_with("_EVEX")) {
201 if (auto *NewRec
= Records
.getDef(Name
.drop_back(5)))
202 NewInst
= &Target
.getInstruction(NewRec
);
203 } else if (Name
.ends_with("_ND")) {
204 if (auto *NewRec
= Records
.getDef(Name
.drop_back(3))) {
205 auto &TempInst
= Target
.getInstruction(NewRec
);
206 if (isRegisterOperand(TempInst
.Operands
[0].Rec
))
210 // For each pre-compression instruction look for a match in the appropriate
211 // vector (instructions with the same opcode) using function object
213 auto Match
= llvm::find_if(CompressedInsts
[Opcode
], IsMatch(Inst
));
214 if (Match
!= CompressedInsts
[Opcode
].end())
221 Table
.push_back(std::make_pair(Inst
, NewInst
));
222 auto Predicates
= NewInst
->TheDef
->getValueAsListOfDefs("Predicates");
223 auto It
= llvm::find_if(Predicates
, [](const Record
*R
) {
224 StringRef Name
= R
->getName();
225 return Name
== "HasAVXNECONVERT" || Name
== "HasAVXVNNI" ||
226 Name
== "HasAVXIFMA";
228 if(It
!= Predicates
.end())
229 PredicateInsts
[*It
].push_back(NewInst
);
232 printTable(Table
, OS
);
233 printCheckPredicate(PredicateInsts
, OS
);
237 static TableGen::Emitter::OptClass
<X86CompressEVEXTablesEmitter
>
238 X("gen-x86-compress-evex-tables", "Generate X86 EVEX compression tables");