xref: /src/contrib/llvm-project/llvm/utils/TableGen/CodeEmitterGen.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1009b1c42SEd Schouten //===- CodeEmitterGen.cpp - Code Emitter Generator ------------------------===//
2009b1c42SEd Schouten //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6009b1c42SEd Schouten //
7009b1c42SEd Schouten //===----------------------------------------------------------------------===//
8009b1c42SEd Schouten //
9009b1c42SEd Schouten // CodeEmitterGen uses the descriptions of instructions and their fields to
107fa27ce4SDimitry Andric // construct an automated code emitter: a function called
117fa27ce4SDimitry Andric // getBinaryCodeForInstr() that, given a MCInst, returns the value of the
127fa27ce4SDimitry Andric // instruction - either as an uint64_t or as an APInt, depending on the
137fa27ce4SDimitry Andric // maximum bit width of all Inst definitions.
147fa27ce4SDimitry Andric //
157fa27ce4SDimitry Andric // In addition, it generates another function called getOperandBitOffset()
167fa27ce4SDimitry Andric // that, given a MCInst and an operand index, returns the minimum of indices of
177fa27ce4SDimitry Andric // all bits that carry some portion of the respective operand. When the target's
187fa27ce4SDimitry Andric // encodeInstruction() stores the instruction in a little-endian byte order, the
197fa27ce4SDimitry Andric // returned value is the offset of the start of the operand in the encoded
207fa27ce4SDimitry Andric // instruction. Other targets might need to adjust the returned value according
217fa27ce4SDimitry Andric // to their encodeInstruction() implementation.
22009b1c42SEd Schouten //
23009b1c42SEd Schouten //===----------------------------------------------------------------------===//
24009b1c42SEd Schouten 
25ac9a064cSDimitry Andric #include "Common/CodeGenHwModes.h"
26ac9a064cSDimitry Andric #include "Common/CodeGenInstruction.h"
27ac9a064cSDimitry Andric #include "Common/CodeGenTarget.h"
28ac9a064cSDimitry Andric #include "Common/InfoByHwMode.h"
29ac9a064cSDimitry Andric #include "Common/VarLenCodeEmitterGen.h"
301d5ae102SDimitry Andric #include "llvm/ADT/APInt.h"
31b915e9e0SDimitry Andric #include "llvm/ADT/ArrayRef.h"
32009b1c42SEd Schouten #include "llvm/ADT/StringExtras.h"
33b915e9e0SDimitry Andric #include "llvm/Support/Casting.h"
34b915e9e0SDimitry Andric #include "llvm/Support/raw_ostream.h"
35145449b1SDimitry Andric #include "llvm/TableGen/Error.h"
364a16efa3SDimitry Andric #include "llvm/TableGen/Record.h"
3758b69754SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
38b915e9e0SDimitry Andric #include <cstdint>
39cf099d11SDimitry Andric #include <map>
40b915e9e0SDimitry Andric #include <set>
4158b69754SDimitry Andric #include <string>
42b915e9e0SDimitry Andric #include <utility>
4358b69754SDimitry Andric #include <vector>
44b915e9e0SDimitry Andric 
45009b1c42SEd Schouten using namespace llvm;
46009b1c42SEd Schouten 
4758b69754SDimitry Andric namespace {
4858b69754SDimitry Andric 
4958b69754SDimitry Andric class CodeEmitterGen {
5058b69754SDimitry Andric   RecordKeeper &Records;
51b915e9e0SDimitry Andric 
5258b69754SDimitry Andric public:
CodeEmitterGen(RecordKeeper & R)5358b69754SDimitry Andric   CodeEmitterGen(RecordKeeper &R) : Records(R) {}
5458b69754SDimitry Andric 
5558b69754SDimitry Andric   void run(raw_ostream &o);
56b915e9e0SDimitry Andric 
5758b69754SDimitry Andric private:
5858b69754SDimitry Andric   int getVariableBit(const std::string &VarName, BitsInit *BI, int bit);
597fa27ce4SDimitry Andric   std::pair<std::string, std::string>
607fa27ce4SDimitry Andric   getInstructionCases(Record *R, CodeGenTarget &Target);
617fa27ce4SDimitry Andric   void addInstructionCasesForEncoding(Record *R, Record *EncodingDef,
627fa27ce4SDimitry Andric                                       CodeGenTarget &Target, std::string &Case,
637fa27ce4SDimitry Andric                                       std::string &BitOffsetCase);
64e3b55780SDimitry Andric   bool addCodeToMergeInOperand(Record *R, BitsInit *BI,
657fa27ce4SDimitry Andric                                const std::string &VarName, std::string &Case,
667fa27ce4SDimitry Andric                                std::string &BitOffsetCase,
677fa27ce4SDimitry Andric                                CodeGenTarget &Target);
6858b69754SDimitry Andric 
691d5ae102SDimitry Andric   void emitInstructionBaseValues(
701d5ae102SDimitry Andric       raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
71ac9a064cSDimitry Andric       CodeGenTarget &Target, unsigned HwMode = DefaultMode);
727fa27ce4SDimitry Andric   void
737fa27ce4SDimitry Andric   emitCaseMap(raw_ostream &o,
747fa27ce4SDimitry Andric               const std::map<std::string, std::vector<std::string>> &CaseMap);
757fa27ce4SDimitry Andric   unsigned BitWidth = 0u;
767fa27ce4SDimitry Andric   bool UseAPInt = false;
7758b69754SDimitry Andric };
7858b69754SDimitry Andric 
79009b1c42SEd Schouten // If the VarBitInit at position 'bit' matches the specified variable then
80009b1c42SEd Schouten // return the variable bit position.  Otherwise return -1.
getVariableBit(const std::string & VarName,BitsInit * BI,int bit)81ac9a064cSDimitry Andric int CodeEmitterGen::getVariableBit(const std::string &VarName, BitsInit *BI,
82ac9a064cSDimitry Andric                                    int bit) {
83522600a2SDimitry Andric   if (VarBitInit *VBI = dyn_cast<VarBitInit>(BI->getBit(bit))) {
84522600a2SDimitry Andric     if (VarInit *VI = dyn_cast<VarInit>(VBI->getBitVar()))
85cf099d11SDimitry Andric       if (VI->getName() == VarName)
86cf099d11SDimitry Andric         return VBI->getBitNum();
87522600a2SDimitry Andric   } else if (VarInit *VI = dyn_cast<VarInit>(BI->getBit(bit))) {
886b943ff3SDimitry Andric     if (VI->getName() == VarName)
896b943ff3SDimitry Andric       return 0;
906b943ff3SDimitry Andric   }
91009b1c42SEd Schouten 
92009b1c42SEd Schouten   return -1;
93009b1c42SEd Schouten }
94009b1c42SEd Schouten 
95e3b55780SDimitry Andric // Returns true if it succeeds, false if an error.
addCodeToMergeInOperand(Record * R,BitsInit * BI,const std::string & VarName,std::string & Case,std::string & BitOffsetCase,CodeGenTarget & Target)96e3b55780SDimitry Andric bool CodeEmitterGen::addCodeToMergeInOperand(Record *R, BitsInit *BI,
97e3b55780SDimitry Andric                                              const std::string &VarName,
98e3b55780SDimitry Andric                                              std::string &Case,
997fa27ce4SDimitry Andric                                              std::string &BitOffsetCase,
100e3b55780SDimitry Andric                                              CodeGenTarget &Target) {
101cf099d11SDimitry Andric   CodeGenInstruction &CGI = Target.getInstruction(R);
102cf099d11SDimitry Andric 
103cf099d11SDimitry Andric   // Determine if VarName actually contributes to the Inst encoding.
104cf099d11SDimitry Andric   int bit = BI->getNumBits() - 1;
105cf099d11SDimitry Andric 
106cf099d11SDimitry Andric   // Scan for a bit that this contributed to.
107cf099d11SDimitry Andric   for (; bit >= 0;) {
108cf099d11SDimitry Andric     if (getVariableBit(VarName, BI, bit) != -1)
109cf099d11SDimitry Andric       break;
110cf099d11SDimitry Andric 
111cf099d11SDimitry Andric     --bit;
112cf099d11SDimitry Andric   }
113cf099d11SDimitry Andric 
114cf099d11SDimitry Andric   // If we found no bits, ignore this value, otherwise emit the call to get the
115cf099d11SDimitry Andric   // operand encoding.
116e3b55780SDimitry Andric   if (bit < 0)
117e3b55780SDimitry Andric     return true;
118cf099d11SDimitry Andric 
119cf099d11SDimitry Andric   // If the operand matches by name, reference according to that
120cf099d11SDimitry Andric   // operand number. Non-matching operands are assumed to be in
121cf099d11SDimitry Andric   // order.
122cf099d11SDimitry Andric   unsigned OpIdx;
123e3b55780SDimitry Andric   std::pair<unsigned, unsigned> SubOp;
124e3b55780SDimitry Andric   if (CGI.Operands.hasSubOperandAlias(VarName, SubOp)) {
125e3b55780SDimitry Andric     OpIdx = CGI.Operands[SubOp.first].MIOperandNo + SubOp.second;
126e3b55780SDimitry Andric   } else if (CGI.Operands.hasOperandNamed(VarName, OpIdx)) {
127cf099d11SDimitry Andric     // Get the machine operand number for the indicated operand.
128cf099d11SDimitry Andric     OpIdx = CGI.Operands[OpIdx].MIOperandNo;
129cf099d11SDimitry Andric   } else {
130ac9a064cSDimitry Andric     PrintError(R, Twine("No operand named ") + VarName + " in record " +
131ac9a064cSDimitry Andric                       R->getName());
132e3b55780SDimitry Andric     return false;
1335ca98fd9SDimitry Andric   }
1345ca98fd9SDimitry Andric 
135e3b55780SDimitry Andric   if (CGI.Operands.isFlatOperandNotEmitted(OpIdx)) {
136ac9a064cSDimitry Andric     PrintError(R,
137ac9a064cSDimitry Andric                "Operand " + VarName + " used but also marked as not emitted!");
138e3b55780SDimitry Andric     return false;
139cf099d11SDimitry Andric   }
140cf099d11SDimitry Andric 
141cf099d11SDimitry Andric   std::pair<unsigned, unsigned> SO = CGI.Operands.getSubOperandNumber(OpIdx);
142e3b55780SDimitry Andric   std::string &EncoderMethodName =
143e3b55780SDimitry Andric       CGI.Operands[SO.first].EncoderMethodNames[SO.second];
144cf099d11SDimitry Andric 
1451d5ae102SDimitry Andric   if (UseAPInt)
1461d5ae102SDimitry Andric     Case += "      op.clearAllBits();\n";
1471d5ae102SDimitry Andric 
1481d5ae102SDimitry Andric   Case += "      // op: " + VarName + "\n";
149e3b55780SDimitry Andric 
150e3b55780SDimitry Andric   // If the source operand has a custom encoder, use it.
151e3b55780SDimitry Andric   if (!EncoderMethodName.empty()) {
1521d5ae102SDimitry Andric     if (UseAPInt) {
1531d5ae102SDimitry Andric       Case += "      " + EncoderMethodName + "(MI, " + utostr(OpIdx);
1541d5ae102SDimitry Andric       Case += ", op";
1551d5ae102SDimitry Andric     } else {
1561d5ae102SDimitry Andric       Case += "      op = " + EncoderMethodName + "(MI, " + utostr(OpIdx);
1571d5ae102SDimitry Andric     }
1581d5ae102SDimitry Andric     Case += ", Fixups, STI);\n";
159cf099d11SDimitry Andric   } else {
1601d5ae102SDimitry Andric     if (UseAPInt) {
161ac9a064cSDimitry Andric       Case +=
162ac9a064cSDimitry Andric           "      getMachineOpValue(MI, MI.getOperand(" + utostr(OpIdx) + ")";
1631d5ae102SDimitry Andric       Case += ", op, Fixups, STI";
1641d5ae102SDimitry Andric     } else {
165ac9a064cSDimitry Andric       Case += "      op = getMachineOpValue(MI, MI.getOperand(" +
166ac9a064cSDimitry Andric               utostr(OpIdx) + ")";
1675ca98fd9SDimitry Andric       Case += ", Fixups, STI";
1681d5ae102SDimitry Andric     }
169cf099d11SDimitry Andric     Case += ");\n";
170cf099d11SDimitry Andric   }
171cf099d11SDimitry Andric 
1721d5ae102SDimitry Andric   // Precalculate the number of lits this variable contributes to in the
1731d5ae102SDimitry Andric   // operand. If there is a single lit (consecutive range of bits) we can use a
1741d5ae102SDimitry Andric   // destructive sequence on APInt that reduces memory allocations.
1751d5ae102SDimitry Andric   int numOperandLits = 0;
1761d5ae102SDimitry Andric   for (int tmpBit = bit; tmpBit >= 0;) {
1771d5ae102SDimitry Andric     int varBit = getVariableBit(VarName, BI, tmpBit);
1781d5ae102SDimitry Andric 
1791d5ae102SDimitry Andric     // If this bit isn't from a variable, skip it.
1801d5ae102SDimitry Andric     if (varBit == -1) {
1811d5ae102SDimitry Andric       --tmpBit;
1821d5ae102SDimitry Andric       continue;
1831d5ae102SDimitry Andric     }
1841d5ae102SDimitry Andric 
1851d5ae102SDimitry Andric     // Figure out the consecutive range of bits covered by this operand, in
1861d5ae102SDimitry Andric     // order to generate better encoding code.
1871d5ae102SDimitry Andric     int beginVarBit = varBit;
1881d5ae102SDimitry Andric     int N = 1;
1891d5ae102SDimitry Andric     for (--tmpBit; tmpBit >= 0;) {
1901d5ae102SDimitry Andric       varBit = getVariableBit(VarName, BI, tmpBit);
1911d5ae102SDimitry Andric       if (varBit == -1 || varBit != (beginVarBit - N))
1921d5ae102SDimitry Andric         break;
1931d5ae102SDimitry Andric       ++N;
1941d5ae102SDimitry Andric       --tmpBit;
1951d5ae102SDimitry Andric     }
1961d5ae102SDimitry Andric     ++numOperandLits;
1971d5ae102SDimitry Andric   }
1981d5ae102SDimitry Andric 
1997fa27ce4SDimitry Andric   unsigned BitOffset = -1;
200cf099d11SDimitry Andric   for (; bit >= 0;) {
201cf099d11SDimitry Andric     int varBit = getVariableBit(VarName, BI, bit);
202cf099d11SDimitry Andric 
203cf099d11SDimitry Andric     // If this bit isn't from a variable, skip it.
204cf099d11SDimitry Andric     if (varBit == -1) {
205cf099d11SDimitry Andric       --bit;
206cf099d11SDimitry Andric       continue;
207cf099d11SDimitry Andric     }
208cf099d11SDimitry Andric 
209cf099d11SDimitry Andric     // Figure out the consecutive range of bits covered by this operand, in
210cf099d11SDimitry Andric     // order to generate better encoding code.
211cf099d11SDimitry Andric     int beginInstBit = bit;
212cf099d11SDimitry Andric     int beginVarBit = varBit;
213cf099d11SDimitry Andric     int N = 1;
214cf099d11SDimitry Andric     for (--bit; bit >= 0;) {
215cf099d11SDimitry Andric       varBit = getVariableBit(VarName, BI, bit);
216ac9a064cSDimitry Andric       if (varBit == -1 || varBit != (beginVarBit - N))
217ac9a064cSDimitry Andric         break;
218cf099d11SDimitry Andric       ++N;
219cf099d11SDimitry Andric       --bit;
220cf099d11SDimitry Andric     }
221cf099d11SDimitry Andric 
2221d5ae102SDimitry Andric     std::string maskStr;
2231d5ae102SDimitry Andric     int opShift;
2241d5ae102SDimitry Andric 
2251d5ae102SDimitry Andric     unsigned loBit = beginVarBit - N + 1;
2261d5ae102SDimitry Andric     unsigned hiBit = loBit + N;
2271d5ae102SDimitry Andric     unsigned loInstBit = beginInstBit - N + 1;
2287fa27ce4SDimitry Andric     BitOffset = loInstBit;
2291d5ae102SDimitry Andric     if (UseAPInt) {
2301d5ae102SDimitry Andric       std::string extractStr;
2311d5ae102SDimitry Andric       if (N >= 64) {
2321d5ae102SDimitry Andric         extractStr = "op.extractBits(" + itostr(hiBit - loBit) + ", " +
2331d5ae102SDimitry Andric                      itostr(loBit) + ")";
2341d5ae102SDimitry Andric         Case += "      Value.insertBits(" + extractStr + ", " +
2351d5ae102SDimitry Andric                 itostr(loInstBit) + ");\n";
2361d5ae102SDimitry Andric       } else {
2371d5ae102SDimitry Andric         extractStr = "op.extractBitsAsZExtValue(" + itostr(hiBit - loBit) +
2381d5ae102SDimitry Andric                      ", " + itostr(loBit) + ")";
2391d5ae102SDimitry Andric         Case += "      Value.insertBits(" + extractStr + ", " +
2401d5ae102SDimitry Andric                 itostr(loInstBit) + ", " + itostr(hiBit - loBit) + ");\n";
2411d5ae102SDimitry Andric       }
2421d5ae102SDimitry Andric     } else {
24363faed5bSDimitry Andric       uint64_t opMask = ~(uint64_t)0 >> (64 - N);
2441d5ae102SDimitry Andric       opShift = beginVarBit - N + 1;
245cf099d11SDimitry Andric       opMask <<= opShift;
2461d5ae102SDimitry Andric       maskStr = "UINT64_C(" + utostr(opMask) + ")";
247cf099d11SDimitry Andric       opShift = beginInstBit - beginVarBit;
248cf099d11SDimitry Andric 
2491d5ae102SDimitry Andric       if (numOperandLits == 1) {
2501d5ae102SDimitry Andric         Case += "      op &= " + maskStr + ";\n";
251cf099d11SDimitry Andric         if (opShift > 0) {
2521d5ae102SDimitry Andric           Case += "      op <<= " + itostr(opShift) + ";\n";
2531d5ae102SDimitry Andric         } else if (opShift < 0) {
2541d5ae102SDimitry Andric           Case += "      op >>= " + itostr(-opShift) + ";\n";
2551d5ae102SDimitry Andric         }
2561d5ae102SDimitry Andric         Case += "      Value |= op;\n";
2571d5ae102SDimitry Andric       } else {
2581d5ae102SDimitry Andric         if (opShift > 0) {
2591d5ae102SDimitry Andric           Case += "      Value |= (op & " + maskStr + ") << " +
260cf099d11SDimitry Andric                   itostr(opShift) + ";\n";
261cf099d11SDimitry Andric         } else if (opShift < 0) {
2621d5ae102SDimitry Andric           Case += "      Value |= (op & " + maskStr + ") >> " +
263cf099d11SDimitry Andric                   itostr(-opShift) + ";\n";
264cf099d11SDimitry Andric         } else {
2651d5ae102SDimitry Andric           Case += "      Value |= (op & " + maskStr + ");\n";
2661d5ae102SDimitry Andric         }
2671d5ae102SDimitry Andric       }
268cf099d11SDimitry Andric     }
269cf099d11SDimitry Andric   }
2707fa27ce4SDimitry Andric 
2717fa27ce4SDimitry Andric   if (BitOffset != (unsigned)-1) {
2727fa27ce4SDimitry Andric     BitOffsetCase += "      case " + utostr(OpIdx) + ":\n";
2737fa27ce4SDimitry Andric     BitOffsetCase += "        // op: " + VarName + "\n";
2747fa27ce4SDimitry Andric     BitOffsetCase += "        return " + utostr(BitOffset) + ";\n";
2757fa27ce4SDimitry Andric   }
2767fa27ce4SDimitry Andric 
277e3b55780SDimitry Andric   return true;
278cf099d11SDimitry Andric }
279cf099d11SDimitry Andric 
2807fa27ce4SDimitry Andric std::pair<std::string, std::string>
getInstructionCases(Record * R,CodeGenTarget & Target)2817fa27ce4SDimitry Andric CodeEmitterGen::getInstructionCases(Record *R, CodeGenTarget &Target) {
2827fa27ce4SDimitry Andric   std::string Case, BitOffsetCase;
2837fa27ce4SDimitry Andric 
284ac9a064cSDimitry Andric   auto append = [&](const std::string &S) {
2857fa27ce4SDimitry Andric     Case += S;
2867fa27ce4SDimitry Andric     BitOffsetCase += S;
2877fa27ce4SDimitry Andric   };
2887fa27ce4SDimitry Andric 
2891d5ae102SDimitry Andric   if (const RecordVal *RV = R->getValue("EncodingInfos")) {
2901d5ae102SDimitry Andric     if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
2911d5ae102SDimitry Andric       const CodeGenHwModes &HWM = Target.getHwModes();
2921d5ae102SDimitry Andric       EncodingInfoByHwMode EBM(DI->getDef(), HWM);
293ac9a064cSDimitry Andric 
294ac9a064cSDimitry Andric       // Invoke the interface to obtain the HwMode ID controlling the
295ac9a064cSDimitry Andric       // EncodingInfo for the current subtarget. This interface will
296ac9a064cSDimitry Andric       // mask off irrelevant HwMode IDs.
297ac9a064cSDimitry Andric       append("      unsigned HwMode = "
298ac9a064cSDimitry Andric              "STI.getHwMode(MCSubtargetInfo::HwMode_EncodingInfo);\n");
299ac9a064cSDimitry Andric       Case += "      switch (HwMode) {\n";
300ac9a064cSDimitry Andric       Case += "      default: llvm_unreachable(\"Unknown hardware mode!\"); "
301ac9a064cSDimitry Andric               "break;\n";
302ac9a064cSDimitry Andric       for (auto &[ModeId, Encoding] : EBM) {
303ac9a064cSDimitry Andric         if (ModeId == DefaultMode) {
304ac9a064cSDimitry Andric           Case +=
305ac9a064cSDimitry Andric               "      case " + itostr(DefaultMode) + ": InstBitsByHw = InstBits";
306ac9a064cSDimitry Andric         } else {
307ac9a064cSDimitry Andric           Case += "      case " + itostr(ModeId) +
308ac9a064cSDimitry Andric                   ": InstBitsByHw = InstBits_" +
309ac9a064cSDimitry Andric                   std::string(HWM.getMode(ModeId).Name);
310ac9a064cSDimitry Andric         }
311ac9a064cSDimitry Andric         Case += "; break;\n";
312ac9a064cSDimitry Andric       }
313ac9a064cSDimitry Andric       Case += "      };\n";
314ac9a064cSDimitry Andric 
315ac9a064cSDimitry Andric       // We need to remodify the 'Inst' value from the table we found above.
316ac9a064cSDimitry Andric       if (UseAPInt) {
317ac9a064cSDimitry Andric         int NumWords = APInt::getNumWords(BitWidth);
318ac9a064cSDimitry Andric         Case += "      Inst = APInt(" + itostr(BitWidth);
319ac9a064cSDimitry Andric         Case += ", ArrayRef(InstBitsByHw + opcode * " + itostr(NumWords) +
320ac9a064cSDimitry Andric                 ", " + itostr(NumWords);
321ac9a064cSDimitry Andric         Case += "));\n";
322ac9a064cSDimitry Andric         Case += "      Value = Inst;\n";
323ac9a064cSDimitry Andric       } else {
324ac9a064cSDimitry Andric         Case += "      Value = InstBitsByHw[opcode];\n";
325ac9a064cSDimitry Andric       }
326ac9a064cSDimitry Andric 
3277fa27ce4SDimitry Andric       append("      switch (HwMode) {\n");
3287fa27ce4SDimitry Andric       append("      default: llvm_unreachable(\"Unhandled HwMode\");\n");
329ac9a064cSDimitry Andric       for (auto &[ModeId, Encoding] : EBM) {
330ac9a064cSDimitry Andric         append("      case " + itostr(ModeId) + ": {\n");
331ac9a064cSDimitry Andric         addInstructionCasesForEncoding(R, Encoding, Target, Case,
3327fa27ce4SDimitry Andric                                        BitOffsetCase);
3337fa27ce4SDimitry Andric         append("      break;\n");
3347fa27ce4SDimitry Andric         append("      }\n");
3351d5ae102SDimitry Andric       }
3367fa27ce4SDimitry Andric       append("      }\n");
337ac9a064cSDimitry Andric       return std::pair(std::move(Case), std::move(BitOffsetCase));
3381d5ae102SDimitry Andric     }
3391d5ae102SDimitry Andric   }
3407fa27ce4SDimitry Andric   addInstructionCasesForEncoding(R, R, Target, Case, BitOffsetCase);
341ac9a064cSDimitry Andric   return std::pair(std::move(Case), std::move(BitOffsetCase));
3421d5ae102SDimitry Andric }
3431d5ae102SDimitry Andric 
addInstructionCasesForEncoding(Record * R,Record * EncodingDef,CodeGenTarget & Target,std::string & Case,std::string & BitOffsetCase)3447fa27ce4SDimitry Andric void CodeEmitterGen::addInstructionCasesForEncoding(
3457fa27ce4SDimitry Andric     Record *R, Record *EncodingDef, CodeGenTarget &Target, std::string &Case,
3467fa27ce4SDimitry Andric     std::string &BitOffsetCase) {
3471d5ae102SDimitry Andric   BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
3485ca98fd9SDimitry Andric 
349cf099d11SDimitry Andric   // Loop over all of the fields in the instruction, determining which are the
350cf099d11SDimitry Andric   // operands to the instruction.
351e3b55780SDimitry Andric   bool Success = true;
3527fa27ce4SDimitry Andric   size_t OrigBitOffsetCaseSize = BitOffsetCase.size();
3537fa27ce4SDimitry Andric   BitOffsetCase += "      switch (OpNum) {\n";
3547fa27ce4SDimitry Andric   size_t BitOffsetCaseSizeBeforeLoop = BitOffsetCase.size();
3551d5ae102SDimitry Andric   for (const RecordVal &RV : EncodingDef->getValues()) {
356cf099d11SDimitry Andric     // Ignore fixed fields in the record, we're looking for values like:
357cf099d11SDimitry Andric     //    bits<5> RST = { ?, ?, ?, ?, ? };
358b60736ecSDimitry Andric     if (RV.isNonconcreteOK() || RV.getValue()->isComplete())
359cf099d11SDimitry Andric       continue;
360cf099d11SDimitry Andric 
3617fa27ce4SDimitry Andric     Success &= addCodeToMergeInOperand(R, BI, std::string(RV.getName()), Case,
3627fa27ce4SDimitry Andric                                        BitOffsetCase, Target);
363cf099d11SDimitry Andric   }
3647fa27ce4SDimitry Andric   // Avoid empty switches.
3657fa27ce4SDimitry Andric   if (BitOffsetCase.size() == BitOffsetCaseSizeBeforeLoop)
3667fa27ce4SDimitry Andric     BitOffsetCase.resize(OrigBitOffsetCaseSize);
3677fa27ce4SDimitry Andric   else
3687fa27ce4SDimitry Andric     BitOffsetCase += "      }\n";
369cf099d11SDimitry Andric 
370e3b55780SDimitry Andric   if (!Success) {
371e3b55780SDimitry Andric     // Dump the record, so we can see what's going on...
372e3b55780SDimitry Andric     std::string E;
373e3b55780SDimitry Andric     raw_string_ostream S(E);
374e3b55780SDimitry Andric     S << "Dumping record for previous error:\n";
375e3b55780SDimitry Andric     S << *R;
376e3b55780SDimitry Andric     PrintNote(E);
377e3b55780SDimitry Andric   }
378e3b55780SDimitry Andric 
379f382538dSDimitry Andric   StringRef PostEmitter = R->getValueAsString("PostEncoderMethod");
3805ca98fd9SDimitry Andric   if (!PostEmitter.empty()) {
381f382538dSDimitry Andric     Case += "      Value = ";
382f382538dSDimitry Andric     Case += PostEmitter;
383f382538dSDimitry Andric     Case += "(MI, Value";
3845ca98fd9SDimitry Andric     Case += ", STI";
3855ca98fd9SDimitry Andric     Case += ");\n";
3865ca98fd9SDimitry Andric   }
387cf099d11SDimitry Andric }
388009b1c42SEd Schouten 
emitInstBits(raw_ostream & OS,const APInt & Bits)3891d5ae102SDimitry Andric static void emitInstBits(raw_ostream &OS, const APInt &Bits) {
3901d5ae102SDimitry Andric   for (unsigned I = 0; I < Bits.getNumWords(); ++I)
3911d5ae102SDimitry Andric     OS << ((I > 0) ? ", " : "") << "UINT64_C(" << utostr(Bits.getRawData()[I])
3921d5ae102SDimitry Andric        << ")";
3931d5ae102SDimitry Andric }
3941d5ae102SDimitry Andric 
emitInstructionBaseValues(raw_ostream & o,ArrayRef<const CodeGenInstruction * > NumberedInstructions,CodeGenTarget & Target,unsigned HwMode)3951d5ae102SDimitry Andric void CodeEmitterGen::emitInstructionBaseValues(
3961d5ae102SDimitry Andric     raw_ostream &o, ArrayRef<const CodeGenInstruction *> NumberedInstructions,
397ac9a064cSDimitry Andric     CodeGenTarget &Target, unsigned HwMode) {
3981d5ae102SDimitry Andric   const CodeGenHwModes &HWM = Target.getHwModes();
399ac9a064cSDimitry Andric   if (HwMode == DefaultMode)
4001d5ae102SDimitry Andric     o << "  static const uint64_t InstBits[] = {\n";
4011d5ae102SDimitry Andric   else
402ac9a064cSDimitry Andric     o << "  static const uint64_t InstBits_"
403ac9a064cSDimitry Andric       << HWM.getModeName(HwMode, /*IncludeDefault=*/true) << "[] = {\n";
4041d5ae102SDimitry Andric 
4051d5ae102SDimitry Andric   for (const CodeGenInstruction *CGI : NumberedInstructions) {
4061d5ae102SDimitry Andric     Record *R = CGI->TheDef;
4071d5ae102SDimitry Andric 
4081d5ae102SDimitry Andric     if (R->getValueAsString("Namespace") == "TargetOpcode" ||
4091d5ae102SDimitry Andric         R->getValueAsBit("isPseudo")) {
410ac9a064cSDimitry Andric       o << "    ";
411ac9a064cSDimitry Andric       emitInstBits(o, APInt(BitWidth, 0));
412ac9a064cSDimitry Andric       o << ",\n";
4131d5ae102SDimitry Andric       continue;
4141d5ae102SDimitry Andric     }
4151d5ae102SDimitry Andric 
4161d5ae102SDimitry Andric     Record *EncodingDef = R;
4171d5ae102SDimitry Andric     if (const RecordVal *RV = R->getValue("EncodingInfos")) {
4181d5ae102SDimitry Andric       if (auto *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
4191d5ae102SDimitry Andric         EncodingInfoByHwMode EBM(DI->getDef(), HWM);
420ac9a064cSDimitry Andric         if (EBM.hasMode(HwMode)) {
4211d5ae102SDimitry Andric           EncodingDef = EBM.get(HwMode);
422ac9a064cSDimitry Andric         } else {
423ac9a064cSDimitry Andric           // If the HwMode does not match, then Encoding '0'
424ac9a064cSDimitry Andric           // should be generated.
425ac9a064cSDimitry Andric           APInt Value(BitWidth, 0);
426ac9a064cSDimitry Andric           o << "    ";
427ac9a064cSDimitry Andric           emitInstBits(o, Value);
428ac9a064cSDimitry Andric           o << "," << '\t' << "// " << R->getName() << "\n";
429ac9a064cSDimitry Andric           continue;
430ac9a064cSDimitry Andric         }
4311d5ae102SDimitry Andric       }
4321d5ae102SDimitry Andric     }
4331d5ae102SDimitry Andric     BitsInit *BI = EncodingDef->getValueAsBitsInit("Inst");
4341d5ae102SDimitry Andric 
4351d5ae102SDimitry Andric     // Start by filling in fixed values.
4361d5ae102SDimitry Andric     APInt Value(BitWidth, 0);
4371d5ae102SDimitry Andric     for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i) {
438e3b55780SDimitry Andric       if (auto *B = dyn_cast<BitInit>(BI->getBit(i)); B && B->getValue())
439e3b55780SDimitry Andric         Value.setBit(i);
4401d5ae102SDimitry Andric     }
4411d5ae102SDimitry Andric     o << "    ";
4421d5ae102SDimitry Andric     emitInstBits(o, Value);
4431d5ae102SDimitry Andric     o << "," << '\t' << "// " << R->getName() << "\n";
4441d5ae102SDimitry Andric   }
4451d5ae102SDimitry Andric   o << "    UINT64_C(0)\n  };\n";
4461d5ae102SDimitry Andric }
4471d5ae102SDimitry Andric 
emitCaseMap(raw_ostream & o,const std::map<std::string,std::vector<std::string>> & CaseMap)4487fa27ce4SDimitry Andric void CodeEmitterGen::emitCaseMap(
4497fa27ce4SDimitry Andric     raw_ostream &o,
4507fa27ce4SDimitry Andric     const std::map<std::string, std::vector<std::string>> &CaseMap) {
4517fa27ce4SDimitry Andric   std::map<std::string, std::vector<std::string>>::const_iterator IE, EE;
4527fa27ce4SDimitry Andric   for (IE = CaseMap.begin(), EE = CaseMap.end(); IE != EE; ++IE) {
4537fa27ce4SDimitry Andric     const std::string &Case = IE->first;
4547fa27ce4SDimitry Andric     const std::vector<std::string> &InstList = IE->second;
4557fa27ce4SDimitry Andric 
4567fa27ce4SDimitry Andric     for (int i = 0, N = InstList.size(); i < N; i++) {
4577fa27ce4SDimitry Andric       if (i)
4587fa27ce4SDimitry Andric         o << "\n";
4597fa27ce4SDimitry Andric       o << "    case " << InstList[i] << ":";
4607fa27ce4SDimitry Andric     }
4617fa27ce4SDimitry Andric     o << " {\n";
4627fa27ce4SDimitry Andric     o << Case;
4637fa27ce4SDimitry Andric     o << "      break;\n"
4647fa27ce4SDimitry Andric       << "    }\n";
4657fa27ce4SDimitry Andric   }
4667fa27ce4SDimitry Andric }
4677fa27ce4SDimitry Andric 
run(raw_ostream & o)46818f153bdSEd Schouten void CodeEmitterGen::run(raw_ostream &o) {
4697fa27ce4SDimitry Andric   emitSourceFileHeader("Machine Code Emitter", o);
4707fa27ce4SDimitry Andric 
471cf099d11SDimitry Andric   CodeGenTarget Target(Records);
472009b1c42SEd Schouten   std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction");
473009b1c42SEd Schouten 
474009b1c42SEd Schouten   // For little-endian instruction bit encodings, reverse the bit order
4755ca98fd9SDimitry Andric   Target.reverseBitsForLittleEndianEncoding();
476009b1c42SEd Schouten 
47701095a5dSDimitry Andric   ArrayRef<const CodeGenInstruction *> NumberedInstructions =
4782f12f10aSRoman Divacky       Target.getInstructionsByEnumValue();
479009b1c42SEd Schouten 
480ac9a064cSDimitry Andric   if (Target.hasVariableLengthEncodings()) {
481145449b1SDimitry Andric     emitVarLenCodeEmitter(Records, o);
482145449b1SDimitry Andric   } else {
4831d5ae102SDimitry Andric     const CodeGenHwModes &HWM = Target.getHwModes();
4841d5ae102SDimitry Andric     // The set of HwModes used by instruction encodings.
4851d5ae102SDimitry Andric     std::set<unsigned> HwModes;
4861d5ae102SDimitry Andric     BitWidth = 0;
4871d5ae102SDimitry Andric     for (const CodeGenInstruction *CGI : NumberedInstructions) {
4881d5ae102SDimitry Andric       Record *R = CGI->TheDef;
4891d5ae102SDimitry Andric       if (R->getValueAsString("Namespace") == "TargetOpcode" ||
4901d5ae102SDimitry Andric           R->getValueAsBit("isPseudo"))
4911d5ae102SDimitry Andric         continue;
4921d5ae102SDimitry Andric 
4931d5ae102SDimitry Andric       if (const RecordVal *RV = R->getValue("EncodingInfos")) {
4941d5ae102SDimitry Andric         if (DefInit *DI = dyn_cast_or_null<DefInit>(RV->getValue())) {
4951d5ae102SDimitry Andric           EncodingInfoByHwMode EBM(DI->getDef(), HWM);
496344a3780SDimitry Andric           for (auto &KV : EBM) {
4971d5ae102SDimitry Andric             BitsInit *BI = KV.second->getValueAsBitsInit("Inst");
4981d5ae102SDimitry Andric             BitWidth = std::max(BitWidth, BI->getNumBits());
4991d5ae102SDimitry Andric             HwModes.insert(KV.first);
5001d5ae102SDimitry Andric           }
5011d5ae102SDimitry Andric           continue;
5021d5ae102SDimitry Andric         }
5031d5ae102SDimitry Andric       }
5041d5ae102SDimitry Andric       BitsInit *BI = R->getValueAsBitsInit("Inst");
5051d5ae102SDimitry Andric       BitWidth = std::max(BitWidth, BI->getNumBits());
5061d5ae102SDimitry Andric     }
5071d5ae102SDimitry Andric     UseAPInt = BitWidth > 64;
5081d5ae102SDimitry Andric 
509009b1c42SEd Schouten     // Emit function declaration
5101d5ae102SDimitry Andric     if (UseAPInt) {
5111d5ae102SDimitry Andric       o << "void " << Target.getName()
5121d5ae102SDimitry Andric         << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
5131d5ae102SDimitry Andric         << "    SmallVectorImpl<MCFixup> &Fixups,\n"
5141d5ae102SDimitry Andric         << "    APInt &Inst,\n"
5151d5ae102SDimitry Andric         << "    APInt &Scratch,\n"
5161d5ae102SDimitry Andric         << "    const MCSubtargetInfo &STI) const {\n";
5171d5ae102SDimitry Andric     } else {
51863faed5bSDimitry Andric       o << "uint64_t " << Target.getName();
519cf099d11SDimitry Andric       o << "MCCodeEmitter::getBinaryCodeForInstr(const MCInst &MI,\n"
5205ca98fd9SDimitry Andric         << "    SmallVectorImpl<MCFixup> &Fixups,\n"
5215ca98fd9SDimitry Andric         << "    const MCSubtargetInfo &STI) const {\n";
5221d5ae102SDimitry Andric     }
523009b1c42SEd Schouten 
524009b1c42SEd Schouten     // Emit instruction base values
525ac9a064cSDimitry Andric     emitInstructionBaseValues(o, NumberedInstructions, Target, DefaultMode);
526ac9a064cSDimitry Andric     if (!HwModes.empty()) {
527ac9a064cSDimitry Andric       // Emit table for instrs whose encodings are controlled by HwModes.
528ac9a064cSDimitry Andric       for (unsigned HwMode : HwModes) {
529ac9a064cSDimitry Andric         if (HwMode == DefaultMode)
530ac9a064cSDimitry Andric           continue;
531ac9a064cSDimitry Andric         emitInstructionBaseValues(o, NumberedInstructions, Target, HwMode);
532009b1c42SEd Schouten       }
533009b1c42SEd Schouten 
534ac9a064cSDimitry Andric       // This pointer will be assigned to the HwMode table later.
535ac9a064cSDimitry Andric       o << "  const uint64_t *InstBitsByHw;\n";
536009b1c42SEd Schouten     }
537009b1c42SEd Schouten 
538009b1c42SEd Schouten     // Map to accumulate all the cases.
539009b1c42SEd Schouten     std::map<std::string, std::vector<std::string>> CaseMap;
5407fa27ce4SDimitry Andric     std::map<std::string, std::vector<std::string>> BitOffsetCaseMap;
541009b1c42SEd Schouten 
542009b1c42SEd Schouten     // Construct all cases statement for each opcode
543344a3780SDimitry Andric     for (Record *R : Insts) {
544411bd29eSDimitry Andric       if (R->getValueAsString("Namespace") == "TargetOpcode" ||
545411bd29eSDimitry Andric           R->getValueAsBit("isPseudo"))
54666e41e3cSRoman Divacky         continue;
547f382538dSDimitry Andric       std::string InstName =
548f382538dSDimitry Andric           (R->getValueAsString("Namespace") + "::" + R->getName()).str();
5497fa27ce4SDimitry Andric       std::string Case, BitOffsetCase;
5507fa27ce4SDimitry Andric       std::tie(Case, BitOffsetCase) = getInstructionCases(R, Target);
551009b1c42SEd Schouten 
5527fa27ce4SDimitry Andric       CaseMap[Case].push_back(InstName);
5537fa27ce4SDimitry Andric       BitOffsetCaseMap[BitOffsetCase].push_back(std::move(InstName));
554009b1c42SEd Schouten     }
555009b1c42SEd Schouten 
556009b1c42SEd Schouten     // Emit initial function code
5571d5ae102SDimitry Andric     if (UseAPInt) {
5581d5ae102SDimitry Andric       int NumWords = APInt::getNumWords(BitWidth);
5591d5ae102SDimitry Andric       o << "  const unsigned opcode = MI.getOpcode();\n"
5601d5ae102SDimitry Andric         << "  if (Scratch.getBitWidth() != " << BitWidth << ")\n"
5611d5ae102SDimitry Andric         << "    Scratch = Scratch.zext(" << BitWidth << ");\n"
562e3b55780SDimitry Andric         << "  Inst = APInt(" << BitWidth << ", ArrayRef(InstBits + opcode * "
563e3b55780SDimitry Andric         << NumWords << ", " << NumWords << "));\n"
5641d5ae102SDimitry Andric         << "  APInt &Value = Inst;\n"
5651d5ae102SDimitry Andric         << "  APInt &op = Scratch;\n"
5661d5ae102SDimitry Andric         << "  switch (opcode) {\n";
5671d5ae102SDimitry Andric     } else {
568009b1c42SEd Schouten       o << "  const unsigned opcode = MI.getOpcode();\n"
56963faed5bSDimitry Andric         << "  uint64_t Value = InstBits[opcode];\n"
57063faed5bSDimitry Andric         << "  uint64_t op = 0;\n"
571cf099d11SDimitry Andric         << "  (void)op;  // suppress warning\n"
572009b1c42SEd Schouten         << "  switch (opcode) {\n";
5731d5ae102SDimitry Andric     }
574009b1c42SEd Schouten 
575009b1c42SEd Schouten     // Emit each case statement
5767fa27ce4SDimitry Andric     emitCaseMap(o, CaseMap);
577009b1c42SEd Schouten 
578009b1c42SEd Schouten     // Default case: unhandled opcode
579009b1c42SEd Schouten     o << "  default:\n"
58059850d08SRoman Divacky       << "    std::string msg;\n"
58159850d08SRoman Divacky       << "    raw_string_ostream Msg(msg);\n"
58259850d08SRoman Divacky       << "    Msg << \"Not supported instr: \" << MI;\n"
583145449b1SDimitry Andric       << "    report_fatal_error(Msg.str().c_str());\n"
5841d5ae102SDimitry Andric       << "  }\n";
5851d5ae102SDimitry Andric     if (UseAPInt)
5861d5ae102SDimitry Andric       o << "  Inst = Value;\n";
5871d5ae102SDimitry Andric     else
5881d5ae102SDimitry Andric       o << "  return Value;\n";
5891d5ae102SDimitry Andric     o << "}\n\n";
5907fa27ce4SDimitry Andric 
5917fa27ce4SDimitry Andric     o << "#ifdef GET_OPERAND_BIT_OFFSET\n"
5927fa27ce4SDimitry Andric       << "#undef GET_OPERAND_BIT_OFFSET\n\n"
5937fa27ce4SDimitry Andric       << "uint32_t " << Target.getName()
5947fa27ce4SDimitry Andric       << "MCCodeEmitter::getOperandBitOffset(const MCInst &MI,\n"
5957fa27ce4SDimitry Andric       << "    unsigned OpNum,\n"
5967fa27ce4SDimitry Andric       << "    const MCSubtargetInfo &STI) const {\n"
5977fa27ce4SDimitry Andric       << "  switch (MI.getOpcode()) {\n";
5987fa27ce4SDimitry Andric     emitCaseMap(o, BitOffsetCaseMap);
5997fa27ce4SDimitry Andric     o << "  }\n"
6007fa27ce4SDimitry Andric       << "  std::string msg;\n"
6017fa27ce4SDimitry Andric       << "  raw_string_ostream Msg(msg);\n"
6027fa27ce4SDimitry Andric       << "  Msg << \"Not supported instr[opcode]: \" << MI << \"[\" << OpNum "
6037fa27ce4SDimitry Andric          "<< \"]\";\n"
6047fa27ce4SDimitry Andric       << "  report_fatal_error(Msg.str().c_str());\n"
6057fa27ce4SDimitry Andric       << "}\n\n"
6067fa27ce4SDimitry Andric       << "#endif // GET_OPERAND_BIT_OFFSET\n\n";
607145449b1SDimitry Andric   }
608009b1c42SEd Schouten }
60958b69754SDimitry Andric 
610b915e9e0SDimitry Andric } // end anonymous namespace
61158b69754SDimitry Andric 
6127fa27ce4SDimitry Andric static TableGen::Emitter::OptClass<CodeEmitterGen>
6137fa27ce4SDimitry Andric     X("gen-emitter", "Generate machine code emitter");
614