xref: /llvm-project/llvm/utils/TableGen/Common/VarLenCodeEmitterGen.cpp (revision 62e2c7fb2d18b43149a07526f6a3c0563d50e2fa)
1fa3d789dSPierre van Houtryve //===- VarLenCodeEmitterGen.cpp - CEG for variable-length insts -----------===//
2fa3d789dSPierre van Houtryve //
3fa3d789dSPierre van Houtryve // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fa3d789dSPierre van Houtryve // See https://llvm.org/LICENSE.txt for license information.
5fa3d789dSPierre van Houtryve // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fa3d789dSPierre van Houtryve //
7fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
8fa3d789dSPierre van Houtryve //
9fa3d789dSPierre van Houtryve // The CodeEmitterGen component for variable-length instructions.
10fa3d789dSPierre van Houtryve //
11fa3d789dSPierre van Houtryve // The basic CodeEmitterGen is almost exclusively designed for fixed-
12fa3d789dSPierre van Houtryve // length instructions. A good analogy for its encoding scheme is how printf
13fa3d789dSPierre van Houtryve // works: The (immutable) formatting string represent the fixed values in the
14fa3d789dSPierre van Houtryve // encoded instruction. Placeholders (i.e. %something), on the other hand,
15fa3d789dSPierre van Houtryve // represent encoding for instruction operands.
16fa3d789dSPierre van Houtryve // ```
17fa3d789dSPierre van Houtryve // printf("1101 %src 1001 %dst", <encoded value for operand `src`>,
18fa3d789dSPierre van Houtryve //                               <encoded value for operand `dst`>);
19fa3d789dSPierre van Houtryve // ```
20fa3d789dSPierre van Houtryve // VarLenCodeEmitterGen in this file provides an alternative encoding scheme
21fa3d789dSPierre van Houtryve // that works more like a C++ stream operator:
22fa3d789dSPierre van Houtryve // ```
23fa3d789dSPierre van Houtryve // OS << 0b1101;
24fa3d789dSPierre van Houtryve // if (Cond)
25fa3d789dSPierre van Houtryve //   OS << OperandEncoding0;
26fa3d789dSPierre van Houtryve // OS << 0b1001 << OperandEncoding1;
27fa3d789dSPierre van Houtryve // ```
28fa3d789dSPierre van Houtryve // You are free to concatenate arbitrary types (and sizes) of encoding
29fa3d789dSPierre van Houtryve // fragments on any bit position, bringing more flexibilities on defining
30fa3d789dSPierre van Houtryve // encoding for variable-length instructions.
31fa3d789dSPierre van Houtryve //
32fa3d789dSPierre van Houtryve // In a more specific way, instruction encoding is represented by a DAG type
33fa3d789dSPierre van Houtryve // `Inst` field. Here is an example:
34fa3d789dSPierre van Houtryve // ```
35fa3d789dSPierre van Houtryve // dag Inst = (descend 0b1101, (operand "$src", 4), 0b1001,
36fa3d789dSPierre van Houtryve //                     (operand "$dst", 4));
37fa3d789dSPierre van Houtryve // ```
38fa3d789dSPierre van Houtryve // It represents the following instruction encoding:
39fa3d789dSPierre van Houtryve // ```
40fa3d789dSPierre van Houtryve // MSB                                                     LSB
41fa3d789dSPierre van Houtryve // 1101<encoding for operand src>1001<encoding for operand dst>
42fa3d789dSPierre van Houtryve // ```
43fa3d789dSPierre van Houtryve // For more details about DAG operators in the above snippet, please
44fa3d789dSPierre van Houtryve // refer to \file include/llvm/Target/Target.td.
45fa3d789dSPierre van Houtryve //
46fa3d789dSPierre van Houtryve // VarLenCodeEmitter will convert the above DAG into the same helper function
47fa3d789dSPierre van Houtryve // generated by CodeEmitter, `MCCodeEmitter::getBinaryCodeForInstr` (except
48fa3d789dSPierre van Houtryve // for few details).
49fa3d789dSPierre van Houtryve //
50fa3d789dSPierre van Houtryve //===----------------------------------------------------------------------===//
51fa3d789dSPierre van Houtryve 
52fa3d789dSPierre van Houtryve #include "VarLenCodeEmitterGen.h"
53fa3d789dSPierre van Houtryve #include "CodeGenHwModes.h"
54fa3d789dSPierre van Houtryve #include "CodeGenInstruction.h"
55fa3d789dSPierre van Houtryve #include "CodeGenTarget.h"
56fa3d789dSPierre van Houtryve #include "InfoByHwMode.h"
57fa3d789dSPierre van Houtryve #include "llvm/ADT/ArrayRef.h"
58fa3d789dSPierre van Houtryve #include "llvm/ADT/DenseMap.h"
59fa3d789dSPierre van Houtryve #include "llvm/Support/raw_ostream.h"
60fa3d789dSPierre van Houtryve #include "llvm/TableGen/Error.h"
61fa3d789dSPierre van Houtryve #include "llvm/TableGen/Record.h"
62fa3d789dSPierre van Houtryve 
63fa3d789dSPierre van Houtryve #include <algorithm>
64fa3d789dSPierre van Houtryve 
65fa3d789dSPierre van Houtryve using namespace llvm;
66fa3d789dSPierre van Houtryve 
67fa3d789dSPierre van Houtryve namespace {
68fa3d789dSPierre van Houtryve 
69fa3d789dSPierre van Houtryve class VarLenCodeEmitterGen {
70100b34bbSRahul Joshi   const RecordKeeper &Records;
71fa3d789dSPierre van Houtryve 
72fa3d789dSPierre van Houtryve   // Representaton of alternative encodings used for HwModes.
73fa3d789dSPierre van Houtryve   using AltEncodingTy = int;
74fa3d789dSPierre van Houtryve   // Mode identifier when only one encoding is defined.
75fa3d789dSPierre van Houtryve   const AltEncodingTy Universal = -1;
76fa3d789dSPierre van Houtryve   // The set of alternative instruction encodings with a descriptive
77fa3d789dSPierre van Houtryve   // name suffix to improve readability of the generated code.
78fa3d789dSPierre van Houtryve   std::map<AltEncodingTy, std::string> Modes;
79fa3d789dSPierre van Houtryve 
8037865681SRahul Joshi   DenseMap<const Record *, DenseMap<AltEncodingTy, VarLenInst>> VarLenInsts;
81fa3d789dSPierre van Houtryve 
82fa3d789dSPierre van Houtryve   // Emit based values (i.e. fixed bits in the encoded instructions)
83fa3d789dSPierre van Houtryve   void emitInstructionBaseValues(
84fa3d789dSPierre van Houtryve       raw_ostream &OS,
85fa3d789dSPierre van Houtryve       ArrayRef<const CodeGenInstruction *> NumberedInstructions,
86100b34bbSRahul Joshi       const CodeGenTarget &Target, AltEncodingTy Mode);
87fa3d789dSPierre van Houtryve 
88100b34bbSRahul Joshi   std::string getInstructionCases(const Record *R, const CodeGenTarget &Target);
89100b34bbSRahul Joshi   std::string getInstructionCaseForEncoding(const Record *R, AltEncodingTy Mode,
90fa3d789dSPierre van Houtryve                                             const VarLenInst &VLI,
91100b34bbSRahul Joshi                                             const CodeGenTarget &Target,
92100b34bbSRahul Joshi                                             int Indent);
93fa3d789dSPierre van Houtryve 
94fa3d789dSPierre van Houtryve public:
95100b34bbSRahul Joshi   explicit VarLenCodeEmitterGen(const RecordKeeper &R) : Records(R) {}
96fa3d789dSPierre van Houtryve 
97fa3d789dSPierre van Houtryve   void run(raw_ostream &OS);
98fa3d789dSPierre van Houtryve };
99fa3d789dSPierre van Houtryve } // end anonymous namespace
100fa3d789dSPierre van Houtryve 
101fa3d789dSPierre van Houtryve // Get the name of custom encoder or decoder, if there is any.
102fa3d789dSPierre van Houtryve // Returns `{encoder name, decoder name}`.
103*62e2c7fbSRahul Joshi static std::pair<StringRef, StringRef>
104*62e2c7fbSRahul Joshi getCustomCoders(ArrayRef<const Init *> Args) {
105fa3d789dSPierre van Houtryve   std::pair<StringRef, StringRef> Result;
106fa3d789dSPierre van Houtryve   for (const auto *Arg : Args) {
107fa3d789dSPierre van Houtryve     const auto *DI = dyn_cast<DagInit>(Arg);
108fa3d789dSPierre van Houtryve     if (!DI)
109fa3d789dSPierre van Houtryve       continue;
110fa3d789dSPierre van Houtryve     const Init *Op = DI->getOperator();
111fa3d789dSPierre van Houtryve     if (!isa<DefInit>(Op))
112fa3d789dSPierre van Houtryve       continue;
113fa3d789dSPierre van Houtryve     // syntax: `(<encoder | decoder> "function name")`
114fa3d789dSPierre van Houtryve     StringRef OpName = cast<DefInit>(Op)->getDef()->getName();
115fa3d789dSPierre van Houtryve     if (OpName != "encoder" && OpName != "decoder")
116fa3d789dSPierre van Houtryve       continue;
117fa3d789dSPierre van Houtryve     if (!DI->getNumArgs() || !isa<StringInit>(DI->getArg(0)))
118fa3d789dSPierre van Houtryve       PrintFatalError("expected '" + OpName +
119fa3d789dSPierre van Houtryve                       "' directive to be followed by a custom function name.");
120fa3d789dSPierre van Houtryve     StringRef FuncName = cast<StringInit>(DI->getArg(0))->getValue();
121fa3d789dSPierre van Houtryve     if (OpName == "encoder")
122fa3d789dSPierre van Houtryve       Result.first = FuncName;
123fa3d789dSPierre van Houtryve     else
124fa3d789dSPierre van Houtryve       Result.second = FuncName;
125fa3d789dSPierre van Houtryve   }
126fa3d789dSPierre van Houtryve   return Result;
127fa3d789dSPierre van Houtryve }
128fa3d789dSPierre van Houtryve 
129fa3d789dSPierre van Houtryve VarLenInst::VarLenInst(const DagInit *DI, const RecordVal *TheDef)
130fa3d789dSPierre van Houtryve     : TheDef(TheDef), NumBits(0U), HasDynamicSegment(false) {
131fa3d789dSPierre van Houtryve   buildRec(DI);
132fa3d789dSPierre van Houtryve   for (const auto &S : Segments)
133fa3d789dSPierre van Houtryve     NumBits += S.BitWidth;
134fa3d789dSPierre van Houtryve }
135fa3d789dSPierre van Houtryve 
136fa3d789dSPierre van Houtryve void VarLenInst::buildRec(const DagInit *DI) {
137fa3d789dSPierre van Houtryve   assert(TheDef && "The def record is nullptr ?");
138fa3d789dSPierre van Houtryve 
139fa3d789dSPierre van Houtryve   std::string Op = DI->getOperator()->getAsString();
140fa3d789dSPierre van Houtryve 
141fa3d789dSPierre van Houtryve   if (Op == "ascend" || Op == "descend") {
142fa3d789dSPierre van Houtryve     bool Reverse = Op == "descend";
143fa3d789dSPierre van Houtryve     int i = Reverse ? DI->getNumArgs() - 1 : 0;
144fa3d789dSPierre van Houtryve     int e = Reverse ? -1 : DI->getNumArgs();
145fa3d789dSPierre van Houtryve     int s = Reverse ? -1 : 1;
146fa3d789dSPierre van Houtryve     for (; i != e; i += s) {
147fa3d789dSPierre van Houtryve       const Init *Arg = DI->getArg(i);
148fa3d789dSPierre van Houtryve       if (const auto *BI = dyn_cast<BitsInit>(Arg)) {
149fa3d789dSPierre van Houtryve         if (!BI->isComplete())
150fa3d789dSPierre van Houtryve           PrintFatalError(TheDef->getLoc(),
151fa3d789dSPierre van Houtryve                           "Expecting complete bits init in `" + Op + "`");
152fa3d789dSPierre van Houtryve         Segments.push_back({BI->getNumBits(), BI});
153fa3d789dSPierre van Houtryve       } else if (const auto *BI = dyn_cast<BitInit>(Arg)) {
154fa3d789dSPierre van Houtryve         if (!BI->isConcrete())
155fa3d789dSPierre van Houtryve           PrintFatalError(TheDef->getLoc(),
156fa3d789dSPierre van Houtryve                           "Expecting concrete bit init in `" + Op + "`");
157fa3d789dSPierre van Houtryve         Segments.push_back({1, BI});
158fa3d789dSPierre van Houtryve       } else if (const auto *SubDI = dyn_cast<DagInit>(Arg)) {
159fa3d789dSPierre van Houtryve         buildRec(SubDI);
160fa3d789dSPierre van Houtryve       } else {
161fa3d789dSPierre van Houtryve         PrintFatalError(TheDef->getLoc(), "Unrecognized type of argument in `" +
162fa3d789dSPierre van Houtryve                                               Op + "`: " + Arg->getAsString());
163fa3d789dSPierre van Houtryve       }
164fa3d789dSPierre van Houtryve     }
165fa3d789dSPierre van Houtryve   } else if (Op == "operand") {
166fa3d789dSPierre van Houtryve     // (operand <operand name>, <# of bits>,
167fa3d789dSPierre van Houtryve     //          [(encoder <custom encoder>)][, (decoder <custom decoder>)])
168fa3d789dSPierre van Houtryve     if (DI->getNumArgs() < 2)
169fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(),
170fa3d789dSPierre van Houtryve                       "Expecting at least 2 arguments for `operand`");
171fa3d789dSPierre van Houtryve     HasDynamicSegment = true;
172fa3d789dSPierre van Houtryve     const Init *OperandName = DI->getArg(0), *NumBits = DI->getArg(1);
173fa3d789dSPierre van Houtryve     if (!isa<StringInit>(OperandName) || !isa<IntInit>(NumBits))
174fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(), "Invalid argument types for `operand`");
175fa3d789dSPierre van Houtryve 
176fa3d789dSPierre van Houtryve     auto NumBitsVal = cast<IntInit>(NumBits)->getValue();
177fa3d789dSPierre van Houtryve     if (NumBitsVal <= 0)
178fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(), "Invalid number of bits for `operand`");
179fa3d789dSPierre van Houtryve 
180fa3d789dSPierre van Houtryve     auto [CustomEncoder, CustomDecoder] =
181fa3d789dSPierre van Houtryve         getCustomCoders(DI->getArgs().slice(2));
182fa3d789dSPierre van Houtryve     Segments.push_back({static_cast<unsigned>(NumBitsVal), OperandName,
183fa3d789dSPierre van Houtryve                         CustomEncoder, CustomDecoder});
184fa3d789dSPierre van Houtryve   } else if (Op == "slice") {
185fa3d789dSPierre van Houtryve     // (slice <operand name>, <high / low bit>, <low / high bit>,
186fa3d789dSPierre van Houtryve     //        [(encoder <custom encoder>)][, (decoder <custom decoder>)])
187fa3d789dSPierre van Houtryve     if (DI->getNumArgs() < 3)
188fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(),
189fa3d789dSPierre van Houtryve                       "Expecting at least 3 arguments for `slice`");
190fa3d789dSPierre van Houtryve     HasDynamicSegment = true;
191*62e2c7fbSRahul Joshi     const Init *OperandName = DI->getArg(0), *HiBit = DI->getArg(1),
192fa3d789dSPierre van Houtryve                *LoBit = DI->getArg(2);
193fa3d789dSPierre van Houtryve     if (!isa<StringInit>(OperandName) || !isa<IntInit>(HiBit) ||
194fa3d789dSPierre van Houtryve         !isa<IntInit>(LoBit))
195fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(), "Invalid argument types for `slice`");
196fa3d789dSPierre van Houtryve 
197fa3d789dSPierre van Houtryve     auto HiBitVal = cast<IntInit>(HiBit)->getValue(),
198fa3d789dSPierre van Houtryve          LoBitVal = cast<IntInit>(LoBit)->getValue();
199fa3d789dSPierre van Houtryve     if (HiBitVal < 0 || LoBitVal < 0)
200fa3d789dSPierre van Houtryve       PrintFatalError(TheDef->getLoc(), "Invalid bit range for `slice`");
201fa3d789dSPierre van Houtryve     bool NeedSwap = false;
202fa3d789dSPierre van Houtryve     unsigned NumBits = 0U;
203fa3d789dSPierre van Houtryve     if (HiBitVal < LoBitVal) {
204fa3d789dSPierre van Houtryve       NeedSwap = true;
205fa3d789dSPierre van Houtryve       NumBits = static_cast<unsigned>(LoBitVal - HiBitVal + 1);
206fa3d789dSPierre van Houtryve     } else {
207fa3d789dSPierre van Houtryve       NumBits = static_cast<unsigned>(HiBitVal - LoBitVal + 1);
208fa3d789dSPierre van Houtryve     }
209fa3d789dSPierre van Houtryve 
210fa3d789dSPierre van Houtryve     auto [CustomEncoder, CustomDecoder] =
211fa3d789dSPierre van Houtryve         getCustomCoders(DI->getArgs().slice(3));
212fa3d789dSPierre van Houtryve 
213fa3d789dSPierre van Houtryve     if (NeedSwap) {
214fa3d789dSPierre van Houtryve       // Normalization: Hi bit should always be the second argument.
215*62e2c7fbSRahul Joshi       const Init *const NewArgs[] = {OperandName, LoBit, HiBit};
216fa3d789dSPierre van Houtryve       Segments.push_back({NumBits,
217fa3d789dSPierre van Houtryve                           DagInit::get(DI->getOperator(), nullptr, NewArgs, {}),
218fa3d789dSPierre van Houtryve                           CustomEncoder, CustomDecoder});
219fa3d789dSPierre van Houtryve     } else {
220fa3d789dSPierre van Houtryve       Segments.push_back({NumBits, DI, CustomEncoder, CustomDecoder});
221fa3d789dSPierre van Houtryve     }
222fa3d789dSPierre van Houtryve   }
223fa3d789dSPierre van Houtryve }
224fa3d789dSPierre van Houtryve 
225fa3d789dSPierre van Houtryve void VarLenCodeEmitterGen::run(raw_ostream &OS) {
226fa3d789dSPierre van Houtryve   CodeGenTarget Target(Records);
227fa3d789dSPierre van Houtryve 
228fa3d789dSPierre van Houtryve   auto NumberedInstructions = Target.getInstructionsByEnumValue();
229fa3d789dSPierre van Houtryve 
230fa3d789dSPierre van Houtryve   for (const CodeGenInstruction *CGI : NumberedInstructions) {
23137865681SRahul Joshi     const Record *R = CGI->TheDef;
232fa3d789dSPierre van Houtryve     // Create the corresponding VarLenInst instance.
233fa3d789dSPierre van Houtryve     if (R->getValueAsString("Namespace") == "TargetOpcode" ||
234fa3d789dSPierre van Houtryve         R->getValueAsBit("isPseudo"))
235fa3d789dSPierre van Houtryve       continue;
236fa3d789dSPierre van Houtryve 
237fa3d789dSPierre van Houtryve     // Setup alternative encodings according to HwModes
238fa3d789dSPierre van Houtryve     if (const RecordVal *RV = R->getValue("EncodingInfos")) {
239fa3d789dSPierre van Houtryve       if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
240fa3d789dSPierre van Houtryve         const CodeGenHwModes &HWM = Target.getHwModes();
241fa3d789dSPierre van Houtryve         EncodingInfoByHwMode EBM(DI->getDef(), HWM);
242100b34bbSRahul Joshi         for (const auto [Mode, EncodingDef] : EBM) {
243fa3d789dSPierre van Houtryve           Modes.insert({Mode, "_" + HWM.getMode(Mode).Name.str()});
244985600dcSRahul Joshi           const RecordVal *RV = EncodingDef->getValue("Inst");
245*62e2c7fbSRahul Joshi           const DagInit *DI = cast<DagInit>(RV->getValue());
246fa3d789dSPierre van Houtryve           VarLenInsts[R].insert({Mode, VarLenInst(DI, RV)});
247fa3d789dSPierre van Houtryve         }
248fa3d789dSPierre van Houtryve         continue;
249fa3d789dSPierre van Houtryve       }
250fa3d789dSPierre van Houtryve     }
25137865681SRahul Joshi     const RecordVal *RV = R->getValue("Inst");
252100b34bbSRahul Joshi     const DagInit *DI = cast<DagInit>(RV->getValue());
253fa3d789dSPierre van Houtryve     VarLenInsts[R].insert({Universal, VarLenInst(DI, RV)});
254fa3d789dSPierre van Houtryve   }
255fa3d789dSPierre van Houtryve 
256fa3d789dSPierre van Houtryve   if (Modes.empty())
257fa3d789dSPierre van Houtryve     Modes.insert({Universal, ""}); // Base case, skip suffix.
258fa3d789dSPierre van Houtryve 
259fa3d789dSPierre van Houtryve   // Emit function declaration
260fa3d789dSPierre van Houtryve   OS << "void " << Target.getName()
261fa3d789dSPierre van Houtryve      << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
262fa3d789dSPierre van Houtryve      << "    SmallVectorImpl<MCFixup> &Fixups,\n"
263fa3d789dSPierre van Houtryve      << "    APInt &Inst,\n"
264fa3d789dSPierre van Houtryve      << "    APInt &Scratch,\n"
265fa3d789dSPierre van Houtryve      << "    const MCSubtargetInfo &STI) const {\n";
266fa3d789dSPierre van Houtryve 
267fa3d789dSPierre van Houtryve   // Emit instruction base values
268fa3d789dSPierre van Houtryve   for (const auto &Mode : Modes)
269fa3d789dSPierre van Houtryve     emitInstructionBaseValues(OS, NumberedInstructions, Target, Mode.first);
270fa3d789dSPierre van Houtryve 
271fa3d789dSPierre van Houtryve   if (Modes.size() > 1) {
272fa3d789dSPierre van Houtryve     OS << "  unsigned Mode = STI.getHwMode();\n";
273fa3d789dSPierre van Houtryve   }
274fa3d789dSPierre van Houtryve 
275fa3d789dSPierre van Houtryve   for (const auto &Mode : Modes) {
276fa3d789dSPierre van Houtryve     // Emit helper function to retrieve base values.
277fa3d789dSPierre van Houtryve     OS << "  auto getInstBits" << Mode.second
278fa3d789dSPierre van Houtryve        << " = [&](unsigned Opcode) -> APInt {\n"
279fa3d789dSPierre van Houtryve        << "    unsigned NumBits = Index" << Mode.second << "[Opcode][0];\n"
280fa3d789dSPierre van Houtryve        << "    if (!NumBits)\n"
281fa3d789dSPierre van Houtryve        << "      return APInt::getZeroWidth();\n"
282fa3d789dSPierre van Houtryve        << "    unsigned Idx = Index" << Mode.second << "[Opcode][1];\n"
283fa3d789dSPierre van Houtryve        << "    ArrayRef<uint64_t> Data(&InstBits" << Mode.second << "[Idx], "
284fa3d789dSPierre van Houtryve        << "APInt::getNumWords(NumBits));\n"
285fa3d789dSPierre van Houtryve        << "    return APInt(NumBits, Data);\n"
286fa3d789dSPierre van Houtryve        << "  };\n";
287fa3d789dSPierre van Houtryve   }
288fa3d789dSPierre van Houtryve 
289fa3d789dSPierre van Houtryve   // Map to accumulate all the cases.
290fa3d789dSPierre van Houtryve   std::map<std::string, std::vector<std::string>> CaseMap;
291fa3d789dSPierre van Houtryve 
292fa3d789dSPierre van Houtryve   // Construct all cases statement for each opcode
293100b34bbSRahul Joshi   for (const Record *R : Records.getAllDerivedDefinitions("Instruction")) {
294fa3d789dSPierre van Houtryve     if (R->getValueAsString("Namespace") == "TargetOpcode" ||
295fa3d789dSPierre van Houtryve         R->getValueAsBit("isPseudo"))
296fa3d789dSPierre van Houtryve       continue;
297fa3d789dSPierre van Houtryve     std::string InstName =
298fa3d789dSPierre van Houtryve         (R->getValueAsString("Namespace") + "::" + R->getName()).str();
299fa3d789dSPierre van Houtryve     std::string Case = getInstructionCases(R, Target);
300fa3d789dSPierre van Houtryve 
301fa3d789dSPierre van Houtryve     CaseMap[Case].push_back(std::move(InstName));
302fa3d789dSPierre van Houtryve   }
303fa3d789dSPierre van Houtryve 
304fa3d789dSPierre van Houtryve   // Emit initial function code
305fa3d789dSPierre van Houtryve   OS << "  const unsigned opcode = MI.getOpcode();\n"
306fa3d789dSPierre van Houtryve      << "  switch (opcode) {\n";
307fa3d789dSPierre van Houtryve 
308fa3d789dSPierre van Houtryve   // Emit each case statement
309fa3d789dSPierre van Houtryve   for (const auto &C : CaseMap) {
310fa3d789dSPierre van Houtryve     const std::string &Case = C.first;
311fa3d789dSPierre van Houtryve     const auto &InstList = C.second;
312fa3d789dSPierre van Houtryve 
313fa3d789dSPierre van Houtryve     ListSeparator LS("\n");
314fa3d789dSPierre van Houtryve     for (const auto &InstName : InstList)
315fa3d789dSPierre van Houtryve       OS << LS << "    case " << InstName << ":";
316fa3d789dSPierre van Houtryve 
317fa3d789dSPierre van Houtryve     OS << " {\n";
318fa3d789dSPierre van Houtryve     OS << Case;
319fa3d789dSPierre van Houtryve     OS << "      break;\n"
320fa3d789dSPierre van Houtryve        << "    }\n";
321fa3d789dSPierre van Houtryve   }
322fa3d789dSPierre van Houtryve   // Default case: unhandled opcode
323fa3d789dSPierre van Houtryve   OS << "  default:\n"
324fa3d789dSPierre van Houtryve      << "    std::string msg;\n"
325fa3d789dSPierre van Houtryve      << "    raw_string_ostream Msg(msg);\n"
326fa3d789dSPierre van Houtryve      << "    Msg << \"Not supported instr: \" << MI;\n"
327fa3d789dSPierre van Houtryve      << "    report_fatal_error(Msg.str().c_str());\n"
328fa3d789dSPierre van Houtryve      << "  }\n";
329fa3d789dSPierre van Houtryve   OS << "}\n\n";
330fa3d789dSPierre van Houtryve }
331fa3d789dSPierre van Houtryve 
332fa3d789dSPierre van Houtryve static void emitInstBits(raw_ostream &IS, raw_ostream &SS, const APInt &Bits,
333fa3d789dSPierre van Houtryve                          unsigned &Index) {
334fa3d789dSPierre van Houtryve   if (!Bits.getNumWords()) {
335fa3d789dSPierre van Houtryve     IS.indent(4) << "{/*NumBits*/0, /*Index*/0},";
336fa3d789dSPierre van Houtryve     return;
337fa3d789dSPierre van Houtryve   }
338fa3d789dSPierre van Houtryve 
339fa3d789dSPierre van Houtryve   IS.indent(4) << "{/*NumBits*/" << Bits.getBitWidth() << ", " << "/*Index*/"
340fa3d789dSPierre van Houtryve                << Index << "},";
341fa3d789dSPierre van Houtryve 
342fa3d789dSPierre van Houtryve   SS.indent(4);
343fa3d789dSPierre van Houtryve   for (unsigned I = 0; I < Bits.getNumWords(); ++I, ++Index)
344fa3d789dSPierre van Houtryve     SS << "UINT64_C(" << utostr(Bits.getRawData()[I]) << "),";
345fa3d789dSPierre van Houtryve }
346fa3d789dSPierre van Houtryve 
347fa3d789dSPierre van Houtryve void VarLenCodeEmitterGen::emitInstructionBaseValues(
348fa3d789dSPierre van Houtryve     raw_ostream &OS, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
349100b34bbSRahul Joshi     const CodeGenTarget &Target, AltEncodingTy Mode) {
350fa3d789dSPierre van Houtryve   std::string IndexArray, StorageArray;
351fa3d789dSPierre van Houtryve   raw_string_ostream IS(IndexArray), SS(StorageArray);
352fa3d789dSPierre van Houtryve 
353fa3d789dSPierre van Houtryve   IS << "  static const unsigned Index" << Modes[Mode] << "[][2] = {\n";
354fa3d789dSPierre van Houtryve   SS << "  static const uint64_t InstBits" << Modes[Mode] << "[] = {\n";
355fa3d789dSPierre van Houtryve 
356fa3d789dSPierre van Houtryve   unsigned NumFixedValueWords = 0U;
357fa3d789dSPierre van Houtryve   for (const CodeGenInstruction *CGI : NumberedInstructions) {
35837865681SRahul Joshi     const Record *R = CGI->TheDef;
359fa3d789dSPierre van Houtryve 
360fa3d789dSPierre van Houtryve     if (R->getValueAsString("Namespace") == "TargetOpcode" ||
361fa3d789dSPierre van Houtryve         R->getValueAsBit("isPseudo")) {
362fa3d789dSPierre van Houtryve       IS.indent(4) << "{/*NumBits*/0, /*Index*/0},\n";
363fa3d789dSPierre van Houtryve       continue;
364fa3d789dSPierre van Houtryve     }
365fa3d789dSPierre van Houtryve 
366fa3d789dSPierre van Houtryve     const auto InstIt = VarLenInsts.find(R);
367fa3d789dSPierre van Houtryve     if (InstIt == VarLenInsts.end())
368fa3d789dSPierre van Houtryve       PrintFatalError(R, "VarLenInst not found for this record");
369fa3d789dSPierre van Houtryve     auto ModeIt = InstIt->second.find(Mode);
370fa3d789dSPierre van Houtryve     if (ModeIt == InstIt->second.end())
371fa3d789dSPierre van Houtryve       ModeIt = InstIt->second.find(Universal);
372fa3d789dSPierre van Houtryve     if (ModeIt == InstIt->second.end()) {
373fa3d789dSPierre van Houtryve       IS.indent(4) << "{/*NumBits*/0, /*Index*/0},\t" << "// " << R->getName()
374fa3d789dSPierre van Houtryve                    << " no encoding\n";
375fa3d789dSPierre van Houtryve       continue;
376fa3d789dSPierre van Houtryve     }
377fa3d789dSPierre van Houtryve     const VarLenInst &VLI = ModeIt->second;
378fa3d789dSPierre van Houtryve     unsigned i = 0U, BitWidth = VLI.size();
379fa3d789dSPierre van Houtryve 
380fa3d789dSPierre van Houtryve     // Start by filling in fixed values.
381fa3d789dSPierre van Houtryve     APInt Value(BitWidth, 0);
382fa3d789dSPierre van Houtryve     auto SI = VLI.begin(), SE = VLI.end();
383fa3d789dSPierre van Houtryve     // Scan through all the segments that have fixed-bits values.
384fa3d789dSPierre van Houtryve     while (i < BitWidth && SI != SE) {
385fa3d789dSPierre van Houtryve       unsigned SegmentNumBits = SI->BitWidth;
386fa3d789dSPierre van Houtryve       if (const auto *BI = dyn_cast<BitsInit>(SI->Value)) {
387fa3d789dSPierre van Houtryve         for (unsigned Idx = 0U; Idx != SegmentNumBits; ++Idx) {
388fa3d789dSPierre van Houtryve           auto *B = cast<BitInit>(BI->getBit(Idx));
389fa3d789dSPierre van Houtryve           Value.setBitVal(i + Idx, B->getValue());
390fa3d789dSPierre van Houtryve         }
391fa3d789dSPierre van Houtryve       }
392fa3d789dSPierre van Houtryve       if (const auto *BI = dyn_cast<BitInit>(SI->Value))
393fa3d789dSPierre van Houtryve         Value.setBitVal(i, BI->getValue());
394fa3d789dSPierre van Houtryve 
395fa3d789dSPierre van Houtryve       i += SegmentNumBits;
396fa3d789dSPierre van Houtryve       ++SI;
397fa3d789dSPierre van Houtryve     }
398fa3d789dSPierre van Houtryve 
399fa3d789dSPierre van Houtryve     emitInstBits(IS, SS, Value, NumFixedValueWords);
400fa3d789dSPierre van Houtryve     IS << '\t' << "// " << R->getName() << "\n";
401fa3d789dSPierre van Houtryve     if (Value.getNumWords())
402fa3d789dSPierre van Houtryve       SS << '\t' << "// " << R->getName() << "\n";
403fa3d789dSPierre van Houtryve   }
404fa3d789dSPierre van Houtryve   IS.indent(4) << "{/*NumBits*/0, /*Index*/0}\n  };\n";
405fa3d789dSPierre van Houtryve   SS.indent(4) << "UINT64_C(0)\n  };\n";
406fa3d789dSPierre van Houtryve 
407caf26b94SYoungsuk Kim   OS << IndexArray << StorageArray;
408fa3d789dSPierre van Houtryve }
409fa3d789dSPierre van Houtryve 
410100b34bbSRahul Joshi std::string
411100b34bbSRahul Joshi VarLenCodeEmitterGen::getInstructionCases(const Record *R,
412100b34bbSRahul Joshi                                           const CodeGenTarget &Target) {
413fa3d789dSPierre van Houtryve   auto It = VarLenInsts.find(R);
414fa3d789dSPierre van Houtryve   if (It == VarLenInsts.end())
415fa3d789dSPierre van Houtryve     PrintFatalError(R, "Parsed encoding record not found");
416fa3d789dSPierre van Houtryve   const auto &Map = It->second;
417fa3d789dSPierre van Houtryve 
418fa3d789dSPierre van Houtryve   // Is this instructions encoding universal (same for all modes)?
419fa3d789dSPierre van Houtryve   // Allways true if there is only one mode.
420fa3d789dSPierre van Houtryve   if (Map.size() == 1 && Map.begin()->first == Universal) {
421fa3d789dSPierre van Houtryve     // Universal, just pick the first mode.
422fa3d789dSPierre van Houtryve     AltEncodingTy Mode = Modes.begin()->first;
423fa3d789dSPierre van Houtryve     const auto &Encoding = Map.begin()->second;
424100b34bbSRahul Joshi     return getInstructionCaseForEncoding(R, Mode, Encoding, Target,
425100b34bbSRahul Joshi                                          /*Indent=*/6);
426fa3d789dSPierre van Houtryve   }
427fa3d789dSPierre van Houtryve 
428fa3d789dSPierre van Houtryve   std::string Case;
429fa3d789dSPierre van Houtryve   Case += "      switch (Mode) {\n";
430fa3d789dSPierre van Houtryve   Case += "      default: llvm_unreachable(\"Unhandled Mode\");\n";
431fa3d789dSPierre van Houtryve   for (const auto &Mode : Modes) {
432fa3d789dSPierre van Houtryve     Case += "      case " + itostr(Mode.first) + ": {\n";
433fa3d789dSPierre van Houtryve     const auto &It = Map.find(Mode.first);
434fa3d789dSPierre van Houtryve     if (It == Map.end()) {
435fa3d789dSPierre van Houtryve       Case +=
436fa3d789dSPierre van Houtryve           "        llvm_unreachable(\"Undefined encoding in this mode\");\n";
437fa3d789dSPierre van Houtryve     } else {
438100b34bbSRahul Joshi       Case += getInstructionCaseForEncoding(R, It->first, It->second, Target,
439100b34bbSRahul Joshi                                             /*Indent=*/8);
440fa3d789dSPierre van Houtryve     }
441fa3d789dSPierre van Houtryve     Case += "        break;\n";
442fa3d789dSPierre van Houtryve     Case += "      }\n";
443fa3d789dSPierre van Houtryve   }
444fa3d789dSPierre van Houtryve   Case += "      }\n";
445fa3d789dSPierre van Houtryve   return Case;
446fa3d789dSPierre van Houtryve }
447fa3d789dSPierre van Houtryve 
448fa3d789dSPierre van Houtryve std::string VarLenCodeEmitterGen::getInstructionCaseForEncoding(
449100b34bbSRahul Joshi     const Record *R, AltEncodingTy Mode, const VarLenInst &VLI,
450100b34bbSRahul Joshi     const CodeGenTarget &Target, int Indent) {
451fa3d789dSPierre van Houtryve   CodeGenInstruction &CGI = Target.getInstruction(R);
452fa3d789dSPierre van Houtryve 
453fa3d789dSPierre van Houtryve   std::string Case;
454fa3d789dSPierre van Houtryve   raw_string_ostream SS(Case);
455fa3d789dSPierre van Houtryve   // Populate based value.
456100b34bbSRahul Joshi   SS.indent(Indent) << "Inst = getInstBits" << Modes[Mode] << "(opcode);\n";
457fa3d789dSPierre van Houtryve 
458fa3d789dSPierre van Houtryve   // Process each segment in VLI.
459fa3d789dSPierre van Houtryve   size_t Offset = 0U;
460fa3d789dSPierre van Houtryve   unsigned HighScratchAccess = 0U;
461fa3d789dSPierre van Houtryve   for (const auto &ES : VLI) {
462fa3d789dSPierre van Houtryve     unsigned NumBits = ES.BitWidth;
463fa3d789dSPierre van Houtryve     const Init *Val = ES.Value;
464fa3d789dSPierre van Houtryve     // If it's a StringInit or DagInit, it's a reference to an operand
465fa3d789dSPierre van Houtryve     // or part of an operand.
466fa3d789dSPierre van Houtryve     if (isa<StringInit>(Val) || isa<DagInit>(Val)) {
467fa3d789dSPierre van Houtryve       StringRef OperandName;
468fa3d789dSPierre van Houtryve       unsigned LoBit = 0U;
469fa3d789dSPierre van Houtryve       if (const auto *SV = dyn_cast<StringInit>(Val)) {
470fa3d789dSPierre van Houtryve         OperandName = SV->getValue();
471fa3d789dSPierre van Houtryve       } else {
472fa3d789dSPierre van Houtryve         // Normalized: (slice <operand name>, <high bit>, <low bit>)
473fa3d789dSPierre van Houtryve         const auto *DV = cast<DagInit>(Val);
474fa3d789dSPierre van Houtryve         OperandName = cast<StringInit>(DV->getArg(0))->getValue();
475fa3d789dSPierre van Houtryve         LoBit = static_cast<unsigned>(cast<IntInit>(DV->getArg(2))->getValue());
476fa3d789dSPierre van Houtryve       }
477fa3d789dSPierre van Houtryve 
478fa3d789dSPierre van Houtryve       auto OpIdx = CGI.Operands.ParseOperandName(OperandName);
479fa3d789dSPierre van Houtryve       unsigned FlatOpIdx = CGI.Operands.getFlattenedOperandNumber(OpIdx);
480fa3d789dSPierre van Houtryve       StringRef CustomEncoder =
481fa3d789dSPierre van Houtryve           CGI.Operands[OpIdx.first].EncoderMethodNames[OpIdx.second];
482fa3d789dSPierre van Houtryve       if (ES.CustomEncoder.size())
483fa3d789dSPierre van Houtryve         CustomEncoder = ES.CustomEncoder;
484fa3d789dSPierre van Houtryve 
485100b34bbSRahul Joshi       SS.indent(Indent) << "Scratch.clearAllBits();\n";
486100b34bbSRahul Joshi       SS.indent(Indent) << "// op: " << OperandName.drop_front(1) << "\n";
487fa3d789dSPierre van Houtryve       if (CustomEncoder.empty())
488100b34bbSRahul Joshi         SS.indent(Indent) << "getMachineOpValue(MI, MI.getOperand("
489fa3d789dSPierre van Houtryve                           << utostr(FlatOpIdx) << ")";
490fa3d789dSPierre van Houtryve       else
491100b34bbSRahul Joshi         SS.indent(Indent) << CustomEncoder << "(MI, /*OpIdx=*/"
492100b34bbSRahul Joshi                           << utostr(FlatOpIdx);
493fa3d789dSPierre van Houtryve 
494fa3d789dSPierre van Houtryve       SS << ", /*Pos=*/" << utostr(Offset) << ", Scratch, Fixups, STI);\n";
495fa3d789dSPierre van Houtryve 
496100b34bbSRahul Joshi       SS.indent(Indent) << "Inst.insertBits("
497100b34bbSRahul Joshi                         << "Scratch.extractBits(" << utostr(NumBits) << ", "
498100b34bbSRahul Joshi                         << utostr(LoBit) << ")"
499100b34bbSRahul Joshi                         << ", " << Offset << ");\n";
500fa3d789dSPierre van Houtryve 
501fa3d789dSPierre van Houtryve       HighScratchAccess = std::max(HighScratchAccess, NumBits + LoBit);
502fa3d789dSPierre van Houtryve     }
503fa3d789dSPierre van Houtryve     Offset += NumBits;
504fa3d789dSPierre van Houtryve   }
505fa3d789dSPierre van Houtryve 
506fa3d789dSPierre van Houtryve   StringRef PostEmitter = R->getValueAsString("PostEncoderMethod");
507fa3d789dSPierre van Houtryve   if (!PostEmitter.empty())
508100b34bbSRahul Joshi     SS.indent(Indent) << "Inst = " << PostEmitter << "(MI, Inst, STI);\n";
509fa3d789dSPierre van Houtryve 
510fa3d789dSPierre van Houtryve   // Resize the scratch buffer if it's to small.
511fa3d789dSPierre van Houtryve   std::string ScratchResizeStr;
512fa3d789dSPierre van Houtryve   if (VLI.size() && !VLI.isFixedValueOnly()) {
513fa3d789dSPierre van Houtryve     raw_string_ostream RS(ScratchResizeStr);
514100b34bbSRahul Joshi     RS.indent(Indent) << "if (Scratch.getBitWidth() < " << HighScratchAccess
515fa3d789dSPierre van Houtryve                       << ") { Scratch = Scratch.zext(" << HighScratchAccess
516fa3d789dSPierre van Houtryve                       << "); }\n";
517fa3d789dSPierre van Houtryve   }
518fa3d789dSPierre van Houtryve 
519fa3d789dSPierre van Houtryve   return ScratchResizeStr + Case;
520fa3d789dSPierre van Houtryve }
521fa3d789dSPierre van Houtryve 
522100b34bbSRahul Joshi void llvm::emitVarLenCodeEmitter(const RecordKeeper &R, raw_ostream &OS) {
523fa3d789dSPierre van Houtryve   VarLenCodeEmitterGen(R).run(OS);
524fa3d789dSPierre van Houtryve }
525