10b57cec5SDimitry Andric //===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This tablegen backend emits an assembly printer for the current target.
100b57cec5SDimitry Andric // Note that this is currently fairly skeletal, but will grow over time.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric
14*0fca6ea1SDimitry Andric #include "Basic/SequenceToOffsetTable.h"
15*0fca6ea1SDimitry Andric #include "Common/AsmWriterInst.h"
16*0fca6ea1SDimitry Andric #include "Common/CodeGenInstAlias.h"
17*0fca6ea1SDimitry Andric #include "Common/CodeGenInstruction.h"
18*0fca6ea1SDimitry Andric #include "Common/CodeGenRegisters.h"
19*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h"
20*0fca6ea1SDimitry Andric #include "Common/Types.h"
210b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
220b57cec5SDimitry Andric #include "llvm/ADT/DenseMap.h"
2381ad6265SDimitry Andric #include "llvm/ADT/STLExtras.h"
240b57cec5SDimitry Andric #include "llvm/ADT/SmallString.h"
250b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
260b57cec5SDimitry Andric #include "llvm/ADT/StringExtras.h"
270b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
280b57cec5SDimitry Andric #include "llvm/ADT/Twine.h"
290b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
300b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
310b57cec5SDimitry Andric #include "llvm/Support/Format.h"
32480093f4SDimitry Andric #include "llvm/Support/FormatVariadic.h"
330b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
340b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
350b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
360b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
370b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
380b57cec5SDimitry Andric #include <algorithm>
390b57cec5SDimitry Andric #include <cassert>
400b57cec5SDimitry Andric #include <cstddef>
410b57cec5SDimitry Andric #include <cstdint>
420b57cec5SDimitry Andric #include <deque>
430b57cec5SDimitry Andric #include <iterator>
440b57cec5SDimitry Andric #include <map>
450b57cec5SDimitry Andric #include <set>
460b57cec5SDimitry Andric #include <string>
470b57cec5SDimitry Andric #include <tuple>
480b57cec5SDimitry Andric #include <utility>
490b57cec5SDimitry Andric #include <vector>
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric using namespace llvm;
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric #define DEBUG_TYPE "asm-writer-emitter"
540b57cec5SDimitry Andric
550b57cec5SDimitry Andric namespace {
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric class AsmWriterEmitter {
580b57cec5SDimitry Andric RecordKeeper &Records;
590b57cec5SDimitry Andric CodeGenTarget Target;
600b57cec5SDimitry Andric ArrayRef<const CodeGenInstruction *> NumberedInstructions;
610b57cec5SDimitry Andric std::vector<AsmWriterInst> Instructions;
620b57cec5SDimitry Andric
630b57cec5SDimitry Andric public:
640b57cec5SDimitry Andric AsmWriterEmitter(RecordKeeper &R);
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric void run(raw_ostream &o);
67*0fca6ea1SDimitry Andric
680b57cec5SDimitry Andric private:
69e8d8bef9SDimitry Andric void EmitGetMnemonic(
70e8d8bef9SDimitry Andric raw_ostream &o,
71e8d8bef9SDimitry Andric std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
72e8d8bef9SDimitry Andric unsigned &BitsLeft, unsigned &AsmStrBits);
73e8d8bef9SDimitry Andric void EmitPrintInstruction(
74e8d8bef9SDimitry Andric raw_ostream &o,
75e8d8bef9SDimitry Andric std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
76e8d8bef9SDimitry Andric unsigned &BitsLeft, unsigned &AsmStrBits);
770b57cec5SDimitry Andric void EmitGetRegisterName(raw_ostream &o);
780b57cec5SDimitry Andric void EmitPrintAliasInstruction(raw_ostream &O);
790b57cec5SDimitry Andric
800b57cec5SDimitry Andric void FindUniqueOperandCommands(std::vector<std::string> &UOC,
810b57cec5SDimitry Andric std::vector<std::vector<unsigned>> &InstIdxs,
820b57cec5SDimitry Andric std::vector<unsigned> &InstOpsUsed,
830b57cec5SDimitry Andric bool PassSubtarget) const;
840b57cec5SDimitry Andric };
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric } // end anonymous namespace
870b57cec5SDimitry Andric
88*0fca6ea1SDimitry Andric static void
PrintCases(std::vector<std::pair<std::string,AsmWriterOperand>> & OpsToPrint,raw_ostream & O,bool PassSubtarget)89*0fca6ea1SDimitry Andric PrintCases(std::vector<std::pair<std::string, AsmWriterOperand>> &OpsToPrint,
90*0fca6ea1SDimitry Andric raw_ostream &O, bool PassSubtarget) {
910b57cec5SDimitry Andric O << " case " << OpsToPrint.back().first << ":";
920b57cec5SDimitry Andric AsmWriterOperand TheOp = OpsToPrint.back().second;
930b57cec5SDimitry Andric OpsToPrint.pop_back();
940b57cec5SDimitry Andric
950b57cec5SDimitry Andric // Check to see if any other operands are identical in this list, and if so,
960b57cec5SDimitry Andric // emit a case label for them.
970b57cec5SDimitry Andric for (unsigned i = OpsToPrint.size(); i != 0; --i)
980b57cec5SDimitry Andric if (OpsToPrint[i - 1].second == TheOp) {
990b57cec5SDimitry Andric O << "\n case " << OpsToPrint[i - 1].first << ":";
1000b57cec5SDimitry Andric OpsToPrint.erase(OpsToPrint.begin() + i - 1);
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric // Finally, emit the code.
1040b57cec5SDimitry Andric O << "\n " << TheOp.getCode(PassSubtarget);
1050b57cec5SDimitry Andric O << "\n break;\n";
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric /// EmitInstructions - Emit the last instruction in the vector and any other
1090b57cec5SDimitry Andric /// instructions that are suitably similar to it.
EmitInstructions(std::vector<AsmWriterInst> & Insts,raw_ostream & O,bool PassSubtarget)110*0fca6ea1SDimitry Andric static void EmitInstructions(std::vector<AsmWriterInst> &Insts, raw_ostream &O,
111*0fca6ea1SDimitry Andric bool PassSubtarget) {
1120b57cec5SDimitry Andric AsmWriterInst FirstInst = Insts.back();
1130b57cec5SDimitry Andric Insts.pop_back();
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric std::vector<AsmWriterInst> SimilarInsts;
1160b57cec5SDimitry Andric unsigned DifferingOperand = ~0;
1170b57cec5SDimitry Andric for (unsigned i = Insts.size(); i != 0; --i) {
1180b57cec5SDimitry Andric unsigned DiffOp = Insts[i - 1].MatchesAllButOneOp(FirstInst);
1190b57cec5SDimitry Andric if (DiffOp != ~1U) {
1200b57cec5SDimitry Andric if (DifferingOperand == ~0U) // First match!
1210b57cec5SDimitry Andric DifferingOperand = DiffOp;
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric // If this differs in the same operand as the rest of the instructions in
1240b57cec5SDimitry Andric // this class, move it to the SimilarInsts list.
1250b57cec5SDimitry Andric if (DifferingOperand == DiffOp || DiffOp == ~0U) {
1260b57cec5SDimitry Andric SimilarInsts.push_back(Insts[i - 1]);
1270b57cec5SDimitry Andric Insts.erase(Insts.begin() + i - 1);
1280b57cec5SDimitry Andric }
1290b57cec5SDimitry Andric }
1300b57cec5SDimitry Andric }
1310b57cec5SDimitry Andric
132*0fca6ea1SDimitry Andric O << " case " << FirstInst.CGI->Namespace
133*0fca6ea1SDimitry Andric << "::" << FirstInst.CGI->TheDef->getName() << ":\n";
1340b57cec5SDimitry Andric for (const AsmWriterInst &AWI : SimilarInsts)
135*0fca6ea1SDimitry Andric O << " case " << AWI.CGI->Namespace << "::" << AWI.CGI->TheDef->getName()
136*0fca6ea1SDimitry Andric << ":\n";
1370b57cec5SDimitry Andric for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {
1380b57cec5SDimitry Andric if (i != DifferingOperand) {
1390b57cec5SDimitry Andric // If the operand is the same for all instructions, just print it.
1400b57cec5SDimitry Andric O << " " << FirstInst.Operands[i].getCode(PassSubtarget);
1410b57cec5SDimitry Andric } else {
1420b57cec5SDimitry Andric // If this is the operand that varies between all of the instructions,
1430b57cec5SDimitry Andric // emit a switch for just this operand now.
1440b57cec5SDimitry Andric O << " switch (MI->getOpcode()) {\n";
1450b57cec5SDimitry Andric O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
1460b57cec5SDimitry Andric std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint;
147*0fca6ea1SDimitry Andric OpsToPrint.push_back(std::pair(FirstInst.CGI->Namespace.str() + "::" +
1480b57cec5SDimitry Andric FirstInst.CGI->TheDef->getName().str(),
1490b57cec5SDimitry Andric FirstInst.Operands[i]));
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric for (const AsmWriterInst &AWI : SimilarInsts) {
152*0fca6ea1SDimitry Andric OpsToPrint.push_back(std::pair(
153*0fca6ea1SDimitry Andric AWI.CGI->Namespace.str() + "::" + AWI.CGI->TheDef->getName().str(),
1540b57cec5SDimitry Andric AWI.Operands[i]));
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric std::reverse(OpsToPrint.begin(), OpsToPrint.end());
1570b57cec5SDimitry Andric while (!OpsToPrint.empty())
1580b57cec5SDimitry Andric PrintCases(OpsToPrint, O, PassSubtarget);
1590b57cec5SDimitry Andric O << " }";
1600b57cec5SDimitry Andric }
1610b57cec5SDimitry Andric O << "\n";
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric O << " break;\n";
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric
FindUniqueOperandCommands(std::vector<std::string> & UniqueOperandCommands,std::vector<std::vector<unsigned>> & InstIdxs,std::vector<unsigned> & InstOpsUsed,bool PassSubtarget) const166*0fca6ea1SDimitry Andric void AsmWriterEmitter::FindUniqueOperandCommands(
167*0fca6ea1SDimitry Andric std::vector<std::string> &UniqueOperandCommands,
1680b57cec5SDimitry Andric std::vector<std::vector<unsigned>> &InstIdxs,
169*0fca6ea1SDimitry Andric std::vector<unsigned> &InstOpsUsed, bool PassSubtarget) const {
1700b57cec5SDimitry Andric // This vector parallels UniqueOperandCommands, keeping track of which
1710b57cec5SDimitry Andric // instructions each case are used for. It is a comma separated string of
1720b57cec5SDimitry Andric // enums.
1730b57cec5SDimitry Andric std::vector<std::string> InstrsForCase;
1740b57cec5SDimitry Andric InstrsForCase.resize(UniqueOperandCommands.size());
1750b57cec5SDimitry Andric InstOpsUsed.assign(UniqueOperandCommands.size(), 0);
1760b57cec5SDimitry Andric
1770b57cec5SDimitry Andric for (size_t i = 0, e = Instructions.size(); i != e; ++i) {
1780b57cec5SDimitry Andric const AsmWriterInst &Inst = Instructions[i];
1790b57cec5SDimitry Andric if (Inst.Operands.empty())
1800b57cec5SDimitry Andric continue; // Instruction already done.
1810b57cec5SDimitry Andric
182*0fca6ea1SDimitry Andric std::string Command =
183*0fca6ea1SDimitry Andric " " + Inst.Operands[0].getCode(PassSubtarget) + "\n";
1840b57cec5SDimitry Andric
1850b57cec5SDimitry Andric // Check to see if we already have 'Command' in UniqueOperandCommands.
1860b57cec5SDimitry Andric // If not, add it.
1870b57cec5SDimitry Andric auto I = llvm::find(UniqueOperandCommands, Command);
1880b57cec5SDimitry Andric if (I != UniqueOperandCommands.end()) {
1890b57cec5SDimitry Andric size_t idx = I - UniqueOperandCommands.begin();
1900b57cec5SDimitry Andric InstrsForCase[idx] += ", ";
1910b57cec5SDimitry Andric InstrsForCase[idx] += Inst.CGI->TheDef->getName();
1920b57cec5SDimitry Andric InstIdxs[idx].push_back(i);
1930b57cec5SDimitry Andric } else {
1940b57cec5SDimitry Andric UniqueOperandCommands.push_back(std::move(Command));
1955ffd83dbSDimitry Andric InstrsForCase.push_back(std::string(Inst.CGI->TheDef->getName()));
1960b57cec5SDimitry Andric InstIdxs.emplace_back();
1970b57cec5SDimitry Andric InstIdxs.back().push_back(i);
1980b57cec5SDimitry Andric
1990b57cec5SDimitry Andric // This command matches one operand so far.
2000b57cec5SDimitry Andric InstOpsUsed.push_back(1);
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric }
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric // For each entry of UniqueOperandCommands, there is a set of instructions
2050b57cec5SDimitry Andric // that uses it. If the next command of all instructions in the set are
2060b57cec5SDimitry Andric // identical, fold it into the command.
207*0fca6ea1SDimitry Andric for (size_t CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e;
208*0fca6ea1SDimitry Andric ++CommandIdx) {
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric const auto &Idxs = InstIdxs[CommandIdx];
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric for (unsigned Op = 1;; ++Op) {
2130b57cec5SDimitry Andric // Find the first instruction in the set.
2140b57cec5SDimitry Andric const AsmWriterInst &FirstInst = Instructions[Idxs.front()];
2150b57cec5SDimitry Andric // If this instruction has no more operands, we isn't anything to merge
2160b57cec5SDimitry Andric // into this command.
2170b57cec5SDimitry Andric if (FirstInst.Operands.size() == Op)
2180b57cec5SDimitry Andric break;
2190b57cec5SDimitry Andric
2200b57cec5SDimitry Andric // Otherwise, scan to see if all of the other instructions in this command
2210b57cec5SDimitry Andric // set share the operand.
222e8d8bef9SDimitry Andric if (any_of(drop_begin(Idxs), [&](unsigned Idx) {
2230b57cec5SDimitry Andric const AsmWriterInst &OtherInst = Instructions[Idx];
2240b57cec5SDimitry Andric return OtherInst.Operands.size() == Op ||
2250b57cec5SDimitry Andric OtherInst.Operands[Op] != FirstInst.Operands[Op];
2260b57cec5SDimitry Andric }))
2270b57cec5SDimitry Andric break;
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric // Okay, everything in this command set has the same next operand. Add it
2300b57cec5SDimitry Andric // to UniqueOperandCommands and remember that it was consumed.
231*0fca6ea1SDimitry Andric std::string Command =
232*0fca6ea1SDimitry Andric " " + FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric UniqueOperandCommands[CommandIdx] += Command;
2350b57cec5SDimitry Andric InstOpsUsed[CommandIdx]++;
2360b57cec5SDimitry Andric }
2370b57cec5SDimitry Andric }
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric // Prepend some of the instructions each case is used for onto the case val.
2400b57cec5SDimitry Andric for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {
2410b57cec5SDimitry Andric std::string Instrs = InstrsForCase[i];
2420b57cec5SDimitry Andric if (Instrs.size() > 70) {
2430b57cec5SDimitry Andric Instrs.erase(Instrs.begin() + 70, Instrs.end());
2440b57cec5SDimitry Andric Instrs += "...";
2450b57cec5SDimitry Andric }
2460b57cec5SDimitry Andric
2470b57cec5SDimitry Andric if (!Instrs.empty())
248*0fca6ea1SDimitry Andric UniqueOperandCommands[i] =
249*0fca6ea1SDimitry Andric " // " + Instrs + "\n" + UniqueOperandCommands[i];
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
UnescapeString(std::string & Str)2530b57cec5SDimitry Andric static void UnescapeString(std::string &Str) {
2540b57cec5SDimitry Andric for (unsigned i = 0; i != Str.size(); ++i) {
2550b57cec5SDimitry Andric if (Str[i] == '\\' && i != Str.size() - 1) {
2560b57cec5SDimitry Andric switch (Str[i + 1]) {
257*0fca6ea1SDimitry Andric default:
258*0fca6ea1SDimitry Andric continue; // Don't execute the code after the switch.
259*0fca6ea1SDimitry Andric case 'a':
260*0fca6ea1SDimitry Andric Str[i] = '\a';
261*0fca6ea1SDimitry Andric break;
262*0fca6ea1SDimitry Andric case 'b':
263*0fca6ea1SDimitry Andric Str[i] = '\b';
264*0fca6ea1SDimitry Andric break;
265*0fca6ea1SDimitry Andric case 'e':
266*0fca6ea1SDimitry Andric Str[i] = 27;
267*0fca6ea1SDimitry Andric break;
268*0fca6ea1SDimitry Andric case 'f':
269*0fca6ea1SDimitry Andric Str[i] = '\f';
270*0fca6ea1SDimitry Andric break;
271*0fca6ea1SDimitry Andric case 'n':
272*0fca6ea1SDimitry Andric Str[i] = '\n';
273*0fca6ea1SDimitry Andric break;
274*0fca6ea1SDimitry Andric case 'r':
275*0fca6ea1SDimitry Andric Str[i] = '\r';
276*0fca6ea1SDimitry Andric break;
277*0fca6ea1SDimitry Andric case 't':
278*0fca6ea1SDimitry Andric Str[i] = '\t';
279*0fca6ea1SDimitry Andric break;
280*0fca6ea1SDimitry Andric case 'v':
281*0fca6ea1SDimitry Andric Str[i] = '\v';
282*0fca6ea1SDimitry Andric break;
283*0fca6ea1SDimitry Andric case '"':
284*0fca6ea1SDimitry Andric Str[i] = '\"';
285*0fca6ea1SDimitry Andric break;
286*0fca6ea1SDimitry Andric case '\'':
287*0fca6ea1SDimitry Andric Str[i] = '\'';
288*0fca6ea1SDimitry Andric break;
289*0fca6ea1SDimitry Andric case '\\':
290*0fca6ea1SDimitry Andric Str[i] = '\\';
291*0fca6ea1SDimitry Andric break;
2920b57cec5SDimitry Andric }
2930b57cec5SDimitry Andric // Nuke the second character.
2940b57cec5SDimitry Andric Str.erase(Str.begin() + i + 1);
2950b57cec5SDimitry Andric }
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric }
2980b57cec5SDimitry Andric
2995ffd83dbSDimitry Andric /// UnescapeAliasString - Supports literal braces in InstAlias asm string which
3005ffd83dbSDimitry Andric /// are escaped with '\\' to avoid being interpreted as variants. Braces must
3015ffd83dbSDimitry Andric /// be unescaped before c++ code is generated as (e.g.):
3025ffd83dbSDimitry Andric ///
3035ffd83dbSDimitry Andric /// AsmString = "foo \{$\x01\}";
3045ffd83dbSDimitry Andric ///
3055ffd83dbSDimitry Andric /// causes non-standard escape character warnings.
UnescapeAliasString(std::string & Str)3065ffd83dbSDimitry Andric static void UnescapeAliasString(std::string &Str) {
3075ffd83dbSDimitry Andric for (unsigned i = 0; i != Str.size(); ++i) {
3085ffd83dbSDimitry Andric if (Str[i] == '\\' && i != Str.size() - 1) {
3095ffd83dbSDimitry Andric switch (Str[i + 1]) {
310*0fca6ea1SDimitry Andric default:
311*0fca6ea1SDimitry Andric continue; // Don't execute the code after the switch.
312*0fca6ea1SDimitry Andric case '{':
313*0fca6ea1SDimitry Andric Str[i] = '{';
314*0fca6ea1SDimitry Andric break;
315*0fca6ea1SDimitry Andric case '}':
316*0fca6ea1SDimitry Andric Str[i] = '}';
317*0fca6ea1SDimitry Andric break;
3185ffd83dbSDimitry Andric }
3195ffd83dbSDimitry Andric // Nuke the second character.
3205ffd83dbSDimitry Andric Str.erase(Str.begin() + i + 1);
3215ffd83dbSDimitry Andric }
3225ffd83dbSDimitry Andric }
3235ffd83dbSDimitry Andric }
3245ffd83dbSDimitry Andric
EmitGetMnemonic(raw_ostream & O,std::vector<std::vector<std::string>> & TableDrivenOperandPrinters,unsigned & BitsLeft,unsigned & AsmStrBits)325e8d8bef9SDimitry Andric void AsmWriterEmitter::EmitGetMnemonic(
326e8d8bef9SDimitry Andric raw_ostream &O,
327e8d8bef9SDimitry Andric std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
328e8d8bef9SDimitry Andric unsigned &BitsLeft, unsigned &AsmStrBits) {
3290b57cec5SDimitry Andric Record *AsmWriter = Target.getAsmWriter();
3300b57cec5SDimitry Andric StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
3310b57cec5SDimitry Andric bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
3320b57cec5SDimitry Andric
333e8d8bef9SDimitry Andric O << "/// getMnemonic - This method is automatically generated by "
334480093f4SDimitry Andric "tablegen\n"
3350b57cec5SDimitry Andric "/// from the instruction set description.\n"
336e8d8bef9SDimitry Andric "std::pair<const char *, uint64_t> "
337e8d8bef9SDimitry Andric << Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n";
3380b57cec5SDimitry Andric
3390b57cec5SDimitry Andric // Build an aggregate string, and build a table of offsets into it.
3400b57cec5SDimitry Andric SequenceToOffsetTable<std::string> StringTable;
3410b57cec5SDimitry Andric
3420b57cec5SDimitry Andric /// OpcodeInfo - This encodes the index of the string to use for the first
3430b57cec5SDimitry Andric /// chunk of the output as well as indices used for operand printing.
3440b57cec5SDimitry Andric std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size());
3450b57cec5SDimitry Andric const unsigned OpcodeInfoBits = 64;
3460b57cec5SDimitry Andric
3470b57cec5SDimitry Andric // Add all strings to the string table upfront so it can generate an optimized
3480b57cec5SDimitry Andric // representation.
3490b57cec5SDimitry Andric for (AsmWriterInst &AWI : Instructions) {
350*0fca6ea1SDimitry Andric if (AWI.Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand &&
3510b57cec5SDimitry Andric !AWI.Operands[0].Str.empty()) {
3520b57cec5SDimitry Andric std::string Str = AWI.Operands[0].Str;
3530b57cec5SDimitry Andric UnescapeString(Str);
3540b57cec5SDimitry Andric StringTable.add(Str);
3550b57cec5SDimitry Andric }
3560b57cec5SDimitry Andric }
3570b57cec5SDimitry Andric
3580b57cec5SDimitry Andric StringTable.layout();
3590b57cec5SDimitry Andric
3600b57cec5SDimitry Andric unsigned MaxStringIdx = 0;
3610b57cec5SDimitry Andric for (AsmWriterInst &AWI : Instructions) {
3620b57cec5SDimitry Andric unsigned Idx;
3630b57cec5SDimitry Andric if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand ||
3640b57cec5SDimitry Andric AWI.Operands[0].Str.empty()) {
3650b57cec5SDimitry Andric // Something handled by the asmwriter printer, but with no leading string.
3660b57cec5SDimitry Andric Idx = StringTable.get("");
3670b57cec5SDimitry Andric } else {
3680b57cec5SDimitry Andric std::string Str = AWI.Operands[0].Str;
3690b57cec5SDimitry Andric UnescapeString(Str);
3700b57cec5SDimitry Andric Idx = StringTable.get(Str);
3710b57cec5SDimitry Andric MaxStringIdx = std::max(MaxStringIdx, Idx);
3720b57cec5SDimitry Andric
3730b57cec5SDimitry Andric // Nuke the string from the operand list. It is now handled!
3740b57cec5SDimitry Andric AWI.Operands.erase(AWI.Operands.begin());
3750b57cec5SDimitry Andric }
3760b57cec5SDimitry Andric
3770b57cec5SDimitry Andric // Bias offset by one since we want 0 as a sentinel.
3780b57cec5SDimitry Andric OpcodeInfo[AWI.CGIIndex] = Idx + 1;
3790b57cec5SDimitry Andric }
3800b57cec5SDimitry Andric
3810b57cec5SDimitry Andric // Figure out how many bits we used for the string index.
382e8d8bef9SDimitry Andric AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2);
3830b57cec5SDimitry Andric
3840b57cec5SDimitry Andric // To reduce code size, we compactify common instructions into a few bits
3850b57cec5SDimitry Andric // in the opcode-indexed table.
386e8d8bef9SDimitry Andric BitsLeft = OpcodeInfoBits - AsmStrBits;
3870b57cec5SDimitry Andric
3880b57cec5SDimitry Andric while (true) {
3890b57cec5SDimitry Andric std::vector<std::string> UniqueOperandCommands;
3900b57cec5SDimitry Andric std::vector<std::vector<unsigned>> InstIdxs;
3910b57cec5SDimitry Andric std::vector<unsigned> NumInstOpsHandled;
3920b57cec5SDimitry Andric FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,
3930b57cec5SDimitry Andric NumInstOpsHandled, PassSubtarget);
3940b57cec5SDimitry Andric
3950b57cec5SDimitry Andric // If we ran out of operands to print, we're done.
396*0fca6ea1SDimitry Andric if (UniqueOperandCommands.empty())
397*0fca6ea1SDimitry Andric break;
3980b57cec5SDimitry Andric
3990b57cec5SDimitry Andric // Compute the number of bits we need to represent these cases, this is
4000b57cec5SDimitry Andric // ceil(log2(numentries)).
4010b57cec5SDimitry Andric unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());
4020b57cec5SDimitry Andric
4030b57cec5SDimitry Andric // If we don't have enough bits for this operand, don't include it.
4040b57cec5SDimitry Andric if (NumBits > BitsLeft) {
4050b57cec5SDimitry Andric LLVM_DEBUG(errs() << "Not enough bits to densely encode " << NumBits
4060b57cec5SDimitry Andric << " more bits\n");
4070b57cec5SDimitry Andric break;
4080b57cec5SDimitry Andric }
4090b57cec5SDimitry Andric
4100b57cec5SDimitry Andric // Otherwise, we can include this in the initial lookup table. Add it in.
4110b57cec5SDimitry Andric for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) {
4120b57cec5SDimitry Andric unsigned NumOps = NumInstOpsHandled[i];
4130b57cec5SDimitry Andric for (unsigned Idx : InstIdxs[i]) {
4140b57cec5SDimitry Andric OpcodeInfo[Instructions[Idx].CGIIndex] |=
4150b57cec5SDimitry Andric (uint64_t)i << (OpcodeInfoBits - BitsLeft);
4160b57cec5SDimitry Andric // Remove the info about this operand from the instruction.
4170b57cec5SDimitry Andric AsmWriterInst &Inst = Instructions[Idx];
4180b57cec5SDimitry Andric if (!Inst.Operands.empty()) {
4190b57cec5SDimitry Andric assert(NumOps <= Inst.Operands.size() &&
4200b57cec5SDimitry Andric "Can't remove this many ops!");
4210b57cec5SDimitry Andric Inst.Operands.erase(Inst.Operands.begin(),
4220b57cec5SDimitry Andric Inst.Operands.begin() + NumOps);
4230b57cec5SDimitry Andric }
4240b57cec5SDimitry Andric }
4250b57cec5SDimitry Andric }
4260b57cec5SDimitry Andric BitsLeft -= NumBits;
4270b57cec5SDimitry Andric
4280b57cec5SDimitry Andric // Remember the handlers for this set of operands.
4290b57cec5SDimitry Andric TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));
4300b57cec5SDimitry Andric }
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andric // Emit the string table itself.
4335ffd83dbSDimitry Andric StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]");
4340b57cec5SDimitry Andric
4350b57cec5SDimitry Andric // Emit the lookup tables in pieces to minimize wasted bytes.
4360b57cec5SDimitry Andric unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8;
4370b57cec5SDimitry Andric unsigned Table = 0, Shift = 0;
4380b57cec5SDimitry Andric SmallString<128> BitsString;
4390b57cec5SDimitry Andric raw_svector_ostream BitsOS(BitsString);
4400b57cec5SDimitry Andric // If the total bits is more than 32-bits we need to use a 64-bit type.
4410b57cec5SDimitry Andric BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)
4420b57cec5SDimitry Andric << "_t Bits = 0;\n";
4430b57cec5SDimitry Andric while (BytesNeeded != 0) {
4440b57cec5SDimitry Andric // Figure out how big this table section needs to be, but no bigger than 4.
445bdd1243dSDimitry Andric unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u);
4460b57cec5SDimitry Andric BytesNeeded -= TableSize;
4470b57cec5SDimitry Andric TableSize *= 8; // Convert to bits;
4480b57cec5SDimitry Andric uint64_t Mask = (1ULL << TableSize) - 1;
4490b57cec5SDimitry Andric O << " static const uint" << TableSize << "_t OpInfo" << Table
4500b57cec5SDimitry Andric << "[] = {\n";
4510b57cec5SDimitry Andric for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
4520b57cec5SDimitry Andric O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "
4530b57cec5SDimitry Andric << NumberedInstructions[i]->TheDef->getName() << "\n";
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric O << " };\n\n";
4560b57cec5SDimitry Andric // Emit string to combine the individual table lookups.
4570b57cec5SDimitry Andric BitsOS << " Bits |= ";
4580b57cec5SDimitry Andric // If the total bits is more than 32-bits we need to use a 64-bit type.
4590b57cec5SDimitry Andric if (BitsLeft < (OpcodeInfoBits - 32))
4600b57cec5SDimitry Andric BitsOS << "(uint64_t)";
4610b57cec5SDimitry Andric BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n";
4620b57cec5SDimitry Andric // Prepare the shift for the next iteration and increment the table count.
4630b57cec5SDimitry Andric Shift += TableSize;
4640b57cec5SDimitry Andric ++Table;
4650b57cec5SDimitry Andric }
4660b57cec5SDimitry Andric
4670b57cec5SDimitry Andric O << " // Emit the opcode for the instruction.\n";
4680b57cec5SDimitry Andric O << BitsString;
4690b57cec5SDimitry Andric
470cb14a3feSDimitry Andric // Make sure we don't return an invalid pointer if bits is 0
471cb14a3feSDimitry Andric O << " if (Bits == 0)\n"
472cb14a3feSDimitry Andric " return {nullptr, Bits};\n";
473cb14a3feSDimitry Andric
474e8d8bef9SDimitry Andric // Return mnemonic string and bits.
475e8d8bef9SDimitry Andric O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1
476e8d8bef9SDimitry Andric << ")-1, Bits};\n\n";
477e8d8bef9SDimitry Andric
478e8d8bef9SDimitry Andric O << "}\n";
479e8d8bef9SDimitry Andric }
480e8d8bef9SDimitry Andric
481e8d8bef9SDimitry Andric /// EmitPrintInstruction - Generate the code for the "printInstruction" method
482e8d8bef9SDimitry Andric /// implementation. Destroys all instances of AsmWriterInst information, by
483e8d8bef9SDimitry Andric /// clearing the Instructions vector.
EmitPrintInstruction(raw_ostream & O,std::vector<std::vector<std::string>> & TableDrivenOperandPrinters,unsigned & BitsLeft,unsigned & AsmStrBits)484e8d8bef9SDimitry Andric void AsmWriterEmitter::EmitPrintInstruction(
485e8d8bef9SDimitry Andric raw_ostream &O,
486e8d8bef9SDimitry Andric std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,
487e8d8bef9SDimitry Andric unsigned &BitsLeft, unsigned &AsmStrBits) {
488e8d8bef9SDimitry Andric const unsigned OpcodeInfoBits = 64;
489e8d8bef9SDimitry Andric Record *AsmWriter = Target.getAsmWriter();
490e8d8bef9SDimitry Andric StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
491e8d8bef9SDimitry Andric bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
492e8d8bef9SDimitry Andric
493349cc55cSDimitry Andric // This function has some huge switch statements that causing excessive
494349cc55cSDimitry Andric // compile time in LLVM profile instrumenation build. This print function
495349cc55cSDimitry Andric // usually is not frequently called in compilation. Here we disable the
496349cc55cSDimitry Andric // profile instrumenation for this function.
497e8d8bef9SDimitry Andric O << "/// printInstruction - This method is automatically generated by "
498e8d8bef9SDimitry Andric "tablegen\n"
499e8d8bef9SDimitry Andric "/// from the instruction set description.\n"
500349cc55cSDimitry Andric "LLVM_NO_PROFILE_INSTRUMENT_FUNCTION\n"
501e8d8bef9SDimitry Andric "void "
502e8d8bef9SDimitry Andric << Target.getName() << ClassName
503e8d8bef9SDimitry Andric << "::printInstruction(const MCInst *MI, uint64_t Address, "
504e8d8bef9SDimitry Andric << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
505e8d8bef9SDimitry Andric << "raw_ostream &O) {\n";
506e8d8bef9SDimitry Andric
507e8d8bef9SDimitry Andric // Emit the initial tab character.
508e8d8bef9SDimitry Andric O << " O << \"\\t\";\n\n";
509e8d8bef9SDimitry Andric
5100b57cec5SDimitry Andric // Emit the starting string.
511e8d8bef9SDimitry Andric O << " auto MnemonicInfo = getMnemonic(MI);\n\n";
512e8d8bef9SDimitry Andric O << " O << MnemonicInfo.first;\n\n";
513e8d8bef9SDimitry Andric
514e8d8bef9SDimitry Andric O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)
515e8d8bef9SDimitry Andric << "_t Bits = MnemonicInfo.second;\n"
516e8d8bef9SDimitry Andric << " assert(Bits != 0 && \"Cannot print this instruction.\");\n";
5170b57cec5SDimitry Andric
5180b57cec5SDimitry Andric // Output the table driven operand information.
5190b57cec5SDimitry Andric BitsLeft = OpcodeInfoBits - AsmStrBits;
5200b57cec5SDimitry Andric for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {
5210b57cec5SDimitry Andric std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];
5220b57cec5SDimitry Andric
5230b57cec5SDimitry Andric // Compute the number of bits we need to represent these cases, this is
5240b57cec5SDimitry Andric // ceil(log2(numentries)).
5250b57cec5SDimitry Andric unsigned NumBits = Log2_32_Ceil(Commands.size());
5260b57cec5SDimitry Andric assert(NumBits <= BitsLeft && "consistency error");
5270b57cec5SDimitry Andric
5280b57cec5SDimitry Andric // Emit code to extract this field from Bits.
529*0fca6ea1SDimitry Andric O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for "
530*0fca6ea1SDimitry Andric << Commands.size() << " unique commands.\n";
5310b57cec5SDimitry Andric
5320b57cec5SDimitry Andric if (Commands.size() == 2) {
5330b57cec5SDimitry Andric // Emit two possibilitys with if/else.
534*0fca6ea1SDimitry Andric O << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "
5350b57cec5SDimitry Andric << ((1 << NumBits) - 1) << ") {\n"
536*0fca6ea1SDimitry Andric << Commands[1] << " } else {\n"
537*0fca6ea1SDimitry Andric << Commands[0] << " }\n\n";
5380b57cec5SDimitry Andric } else if (Commands.size() == 1) {
5390b57cec5SDimitry Andric // Emit a single possibility.
5400b57cec5SDimitry Andric O << Commands[0] << "\n\n";
5410b57cec5SDimitry Andric } else {
542*0fca6ea1SDimitry Andric O << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "
5430b57cec5SDimitry Andric << ((1 << NumBits) - 1) << ") {\n"
5440b57cec5SDimitry Andric << " default: llvm_unreachable(\"Invalid command number.\");\n";
5450b57cec5SDimitry Andric
5460b57cec5SDimitry Andric // Print out all the cases.
5470b57cec5SDimitry Andric for (unsigned j = 0, e = Commands.size(); j != e; ++j) {
5480b57cec5SDimitry Andric O << " case " << j << ":\n";
5490b57cec5SDimitry Andric O << Commands[j];
5500b57cec5SDimitry Andric O << " break;\n";
5510b57cec5SDimitry Andric }
5520b57cec5SDimitry Andric O << " }\n\n";
5530b57cec5SDimitry Andric }
5540b57cec5SDimitry Andric BitsLeft -= NumBits;
5550b57cec5SDimitry Andric }
5560b57cec5SDimitry Andric
5570b57cec5SDimitry Andric // Okay, delete instructions with no operand info left.
558e8d8bef9SDimitry Andric llvm::erase_if(Instructions,
5590b57cec5SDimitry Andric [](AsmWriterInst &Inst) { return Inst.Operands.empty(); });
5600b57cec5SDimitry Andric
5610b57cec5SDimitry Andric // Because this is a vector, we want to emit from the end. Reverse all of the
5620b57cec5SDimitry Andric // elements in the vector.
5630b57cec5SDimitry Andric std::reverse(Instructions.begin(), Instructions.end());
5640b57cec5SDimitry Andric
5650b57cec5SDimitry Andric // Now that we've emitted all of the operand info that fit into 64 bits, emit
5660b57cec5SDimitry Andric // information for those instructions that are left. This is a less dense
5670b57cec5SDimitry Andric // encoding, but we expect the main 64-bit table to handle the majority of
5680b57cec5SDimitry Andric // instructions.
5690b57cec5SDimitry Andric if (!Instructions.empty()) {
5700b57cec5SDimitry Andric // Find the opcode # of inline asm.
5710b57cec5SDimitry Andric O << " switch (MI->getOpcode()) {\n";
5720b57cec5SDimitry Andric O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";
5730b57cec5SDimitry Andric while (!Instructions.empty())
5740b57cec5SDimitry Andric EmitInstructions(Instructions, O, PassSubtarget);
5750b57cec5SDimitry Andric
5760b57cec5SDimitry Andric O << " }\n";
5770b57cec5SDimitry Andric }
5780b57cec5SDimitry Andric
5790b57cec5SDimitry Andric O << "}\n";
5800b57cec5SDimitry Andric }
5810b57cec5SDimitry Andric
5820b57cec5SDimitry Andric static void
emitRegisterNameString(raw_ostream & O,StringRef AltName,const std::deque<CodeGenRegister> & Registers)5830b57cec5SDimitry Andric emitRegisterNameString(raw_ostream &O, StringRef AltName,
5840b57cec5SDimitry Andric const std::deque<CodeGenRegister> &Registers) {
5850b57cec5SDimitry Andric SequenceToOffsetTable<std::string> StringTable;
5860b57cec5SDimitry Andric SmallVector<std::string, 4> AsmNames(Registers.size());
5870b57cec5SDimitry Andric unsigned i = 0;
5880b57cec5SDimitry Andric for (const auto &Reg : Registers) {
5890b57cec5SDimitry Andric std::string &AsmName = AsmNames[i++];
5900b57cec5SDimitry Andric
5910b57cec5SDimitry Andric // "NoRegAltName" is special. We don't need to do a lookup for that,
5920b57cec5SDimitry Andric // as it's just a reference to the default register name.
5930b57cec5SDimitry Andric if (AltName == "" || AltName == "NoRegAltName") {
5945ffd83dbSDimitry Andric AsmName = std::string(Reg.TheDef->getValueAsString("AsmName"));
5950b57cec5SDimitry Andric if (AsmName.empty())
5965ffd83dbSDimitry Andric AsmName = std::string(Reg.getName());
5970b57cec5SDimitry Andric } else {
5980b57cec5SDimitry Andric // Make sure the register has an alternate name for this index.
5990b57cec5SDimitry Andric std::vector<Record *> AltNameList =
6000b57cec5SDimitry Andric Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");
6010b57cec5SDimitry Andric unsigned Idx = 0, e;
6020b57cec5SDimitry Andric for (e = AltNameList.size();
603*0fca6ea1SDimitry Andric Idx < e && (AltNameList[Idx]->getName() != AltName); ++Idx)
6040b57cec5SDimitry Andric ;
6050b57cec5SDimitry Andric // If the register has an alternate name for this index, use it.
6060b57cec5SDimitry Andric // Otherwise, leave it empty as an error flag.
6070b57cec5SDimitry Andric if (Idx < e) {
6080b57cec5SDimitry Andric std::vector<StringRef> AltNames =
6090b57cec5SDimitry Andric Reg.TheDef->getValueAsListOfStrings("AltNames");
6100b57cec5SDimitry Andric if (AltNames.size() <= Idx)
6110b57cec5SDimitry Andric PrintFatalError(Reg.TheDef->getLoc(),
6120b57cec5SDimitry Andric "Register definition missing alt name for '" +
6130b57cec5SDimitry Andric AltName + "'.");
6145ffd83dbSDimitry Andric AsmName = std::string(AltNames[Idx]);
6150b57cec5SDimitry Andric }
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric StringTable.add(AsmName);
6180b57cec5SDimitry Andric }
6190b57cec5SDimitry Andric
6200b57cec5SDimitry Andric StringTable.layout();
6215ffd83dbSDimitry Andric StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") +
6225ffd83dbSDimitry Andric AltName + "[]");
6230b57cec5SDimitry Andric
6240b57cec5SDimitry Andric O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32)
6250b57cec5SDimitry Andric << " RegAsmOffset" << AltName << "[] = {";
6260b57cec5SDimitry Andric for (unsigned i = 0, e = Registers.size(); i != e; ++i) {
6270b57cec5SDimitry Andric if ((i % 14) == 0)
6280b57cec5SDimitry Andric O << "\n ";
6290b57cec5SDimitry Andric O << StringTable.get(AsmNames[i]) << ", ";
6300b57cec5SDimitry Andric }
6310b57cec5SDimitry Andric O << "\n };\n"
6320b57cec5SDimitry Andric << "\n";
6330b57cec5SDimitry Andric }
6340b57cec5SDimitry Andric
EmitGetRegisterName(raw_ostream & O)6350b57cec5SDimitry Andric void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {
6360b57cec5SDimitry Andric Record *AsmWriter = Target.getAsmWriter();
6370b57cec5SDimitry Andric StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
6380b57cec5SDimitry Andric const auto &Registers = Target.getRegBank().getRegisters();
6390b57cec5SDimitry Andric const std::vector<Record *> &AltNameIndices = Target.getRegAltNameIndices();
6400b57cec5SDimitry Andric bool hasAltNames = AltNameIndices.size() > 1;
6410b57cec5SDimitry Andric StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace");
6420b57cec5SDimitry Andric
643*0fca6ea1SDimitry Andric O << "\n\n/// getRegisterName - This method is automatically generated by "
644*0fca6ea1SDimitry Andric "tblgen\n"
645*0fca6ea1SDimitry Andric "/// from the register set description. This returns the assembler "
646*0fca6ea1SDimitry Andric "name\n"
6470b57cec5SDimitry Andric "/// for the specified register.\n"
648*0fca6ea1SDimitry Andric "const char *"
649*0fca6ea1SDimitry Andric << Target.getName() << ClassName << "::";
6500b57cec5SDimitry Andric if (hasAltNames)
651bdd1243dSDimitry Andric O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n";
6520b57cec5SDimitry Andric else
653bdd1243dSDimitry Andric O << "getRegisterName(MCRegister Reg) {\n";
654bdd1243dSDimitry Andric O << " unsigned RegNo = Reg.id();\n"
655bdd1243dSDimitry Andric << " assert(RegNo && RegNo < " << (Registers.size() + 1)
6560b57cec5SDimitry Andric << " && \"Invalid register number!\");\n"
6570b57cec5SDimitry Andric << "\n";
6580b57cec5SDimitry Andric
6590b57cec5SDimitry Andric if (hasAltNames) {
6600b57cec5SDimitry Andric for (const Record *R : AltNameIndices)
6610b57cec5SDimitry Andric emitRegisterNameString(O, R->getName(), Registers);
6620b57cec5SDimitry Andric } else
6630b57cec5SDimitry Andric emitRegisterNameString(O, "", Registers);
6640b57cec5SDimitry Andric
6650b57cec5SDimitry Andric if (hasAltNames) {
6660b57cec5SDimitry Andric O << " switch(AltIdx) {\n"
6670b57cec5SDimitry Andric << " default: llvm_unreachable(\"Invalid register alt name index!\");\n";
6680b57cec5SDimitry Andric for (const Record *R : AltNameIndices) {
6690b57cec5SDimitry Andric StringRef AltName = R->getName();
6700b57cec5SDimitry Andric O << " case ";
6710b57cec5SDimitry Andric if (!Namespace.empty())
6720b57cec5SDimitry Andric O << Namespace << "::";
6730b57cec5SDimitry Andric O << AltName << ":\n";
6740b57cec5SDimitry Andric if (R->isValueUnset("FallbackRegAltNameIndex"))
6750b57cec5SDimitry Andric O << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName
6760b57cec5SDimitry Andric << "[RegNo-1]) &&\n"
6770b57cec5SDimitry Andric << " \"Invalid alt name index for register!\");\n";
6780b57cec5SDimitry Andric else {
6790b57cec5SDimitry Andric O << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName
6800b57cec5SDimitry Andric << "[RegNo-1]))\n"
6810b57cec5SDimitry Andric << " return getRegisterName(RegNo, ";
6820b57cec5SDimitry Andric if (!Namespace.empty())
6830b57cec5SDimitry Andric O << Namespace << "::";
6840b57cec5SDimitry Andric O << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n";
6850b57cec5SDimitry Andric }
6860b57cec5SDimitry Andric O << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName
6870b57cec5SDimitry Andric << "[RegNo-1];\n";
6880b57cec5SDimitry Andric }
6890b57cec5SDimitry Andric O << " }\n";
6900b57cec5SDimitry Andric } else {
6910b57cec5SDimitry Andric O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"
6920b57cec5SDimitry Andric << " \"Invalid alt name index for register!\");\n"
6930b57cec5SDimitry Andric << " return AsmStrs+RegAsmOffset[RegNo-1];\n";
6940b57cec5SDimitry Andric }
6950b57cec5SDimitry Andric O << "}\n";
6960b57cec5SDimitry Andric }
6970b57cec5SDimitry Andric
6980b57cec5SDimitry Andric namespace {
6990b57cec5SDimitry Andric
7000b57cec5SDimitry Andric // IAPrinter - Holds information about an InstAlias. Two InstAliases match if
7010b57cec5SDimitry Andric // they both have the same conditionals. In which case, we cannot print out the
7020b57cec5SDimitry Andric // alias for that pattern.
7030b57cec5SDimitry Andric class IAPrinter {
7040b57cec5SDimitry Andric std::map<StringRef, std::pair<int, int>> OpMap;
7050b57cec5SDimitry Andric
706480093f4SDimitry Andric std::vector<std::string> Conds;
707480093f4SDimitry Andric
7080b57cec5SDimitry Andric std::string Result;
7090b57cec5SDimitry Andric std::string AsmString;
7100b57cec5SDimitry Andric
711480093f4SDimitry Andric unsigned NumMIOps;
7120b57cec5SDimitry Andric
713480093f4SDimitry Andric public:
IAPrinter(std::string R,std::string AS,unsigned NumMIOps)714480093f4SDimitry Andric IAPrinter(std::string R, std::string AS, unsigned NumMIOps)
715480093f4SDimitry Andric : Result(std::move(R)), AsmString(std::move(AS)), NumMIOps(NumMIOps) {}
716480093f4SDimitry Andric
addCond(std::string C)717480093f4SDimitry Andric void addCond(std::string C) { Conds.push_back(std::move(C)); }
getConds() const718480093f4SDimitry Andric ArrayRef<std::string> getConds() const { return Conds; }
getCondCount() const719480093f4SDimitry Andric size_t getCondCount() const { return Conds.size(); }
7200b57cec5SDimitry Andric
addOperand(StringRef Op,int OpIdx,int PrintMethodIdx=-1)7210b57cec5SDimitry Andric void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {
7220b57cec5SDimitry Andric assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");
723*0fca6ea1SDimitry Andric assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF && "Idx out of range");
724*0fca6ea1SDimitry Andric OpMap[Op] = std::pair(OpIdx, PrintMethodIdx);
7250b57cec5SDimitry Andric }
7260b57cec5SDimitry Andric
getNumMIOps()727480093f4SDimitry Andric unsigned getNumMIOps() { return NumMIOps; }
728480093f4SDimitry Andric
getResult()729480093f4SDimitry Andric StringRef getResult() { return Result; }
730480093f4SDimitry Andric
isOpMapped(StringRef Op)7310b57cec5SDimitry Andric bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }
getOpIndex(StringRef Op)7320b57cec5SDimitry Andric int getOpIndex(StringRef Op) { return OpMap[Op].first; }
getOpData(StringRef Op)7330b57cec5SDimitry Andric std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; }
7340b57cec5SDimitry Andric
parseName(StringRef::iterator Start,StringRef::iterator End)7350b57cec5SDimitry Andric std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start,
7360b57cec5SDimitry Andric StringRef::iterator End) {
7370b57cec5SDimitry Andric StringRef::iterator I = Start;
7380b57cec5SDimitry Andric StringRef::iterator Next;
7390b57cec5SDimitry Andric if (*I == '{') {
7400b57cec5SDimitry Andric // ${some_name}
7410b57cec5SDimitry Andric Start = ++I;
7420b57cec5SDimitry Andric while (I != End && *I != '}')
7430b57cec5SDimitry Andric ++I;
7440b57cec5SDimitry Andric Next = I;
7450b57cec5SDimitry Andric // eat the final '}'
7460b57cec5SDimitry Andric if (Next != End)
7470b57cec5SDimitry Andric ++Next;
7480b57cec5SDimitry Andric } else {
7490b57cec5SDimitry Andric // $name, just eat the usual suspects.
750e8d8bef9SDimitry Andric while (I != End && (isAlnum(*I) || *I == '_'))
7510b57cec5SDimitry Andric ++I;
7520b57cec5SDimitry Andric Next = I;
7530b57cec5SDimitry Andric }
7540b57cec5SDimitry Andric
755*0fca6ea1SDimitry Andric return std::pair(StringRef(Start, I - Start), Next);
7560b57cec5SDimitry Andric }
7570b57cec5SDimitry Andric
formatAliasString(uint32_t & UnescapedSize)758480093f4SDimitry Andric std::string formatAliasString(uint32_t &UnescapedSize) {
7590b57cec5SDimitry Andric // Directly mangle mapped operands into the string. Each operand is
7600b57cec5SDimitry Andric // identified by a '$' sign followed by a byte identifying the number of the
7610b57cec5SDimitry Andric // operand. We add one to the index to avoid zero bytes.
7620b57cec5SDimitry Andric StringRef ASM(AsmString);
763480093f4SDimitry Andric std::string OutString;
764480093f4SDimitry Andric raw_string_ostream OS(OutString);
7650b57cec5SDimitry Andric for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) {
7660b57cec5SDimitry Andric OS << *I;
767480093f4SDimitry Andric ++UnescapedSize;
7680b57cec5SDimitry Andric if (*I == '$') {
7690b57cec5SDimitry Andric StringRef Name;
7700b57cec5SDimitry Andric std::tie(Name, I) = parseName(++I, E);
7710b57cec5SDimitry Andric assert(isOpMapped(Name) && "Unmapped operand!");
7720b57cec5SDimitry Andric
7730b57cec5SDimitry Andric int OpIndex, PrintIndex;
7740b57cec5SDimitry Andric std::tie(OpIndex, PrintIndex) = getOpData(Name);
7750b57cec5SDimitry Andric if (PrintIndex == -1) {
7760b57cec5SDimitry Andric // Can use the default printOperand route.
7770b57cec5SDimitry Andric OS << format("\\x%02X", (unsigned char)OpIndex + 1);
778480093f4SDimitry Andric ++UnescapedSize;
779480093f4SDimitry Andric } else {
7800b57cec5SDimitry Andric // 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand
7810b57cec5SDimitry Andric // number, and which of our pre-detected Methods to call.
7820b57cec5SDimitry Andric OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1);
783480093f4SDimitry Andric UnescapedSize += 3;
784480093f4SDimitry Andric }
7850b57cec5SDimitry Andric } else {
7860b57cec5SDimitry Andric ++I;
7870b57cec5SDimitry Andric }
7880b57cec5SDimitry Andric }
789480093f4SDimitry Andric return OutString;
7900b57cec5SDimitry Andric }
7910b57cec5SDimitry Andric
operator ==(const IAPrinter & RHS) const7920b57cec5SDimitry Andric bool operator==(const IAPrinter &RHS) const {
793480093f4SDimitry Andric if (NumMIOps != RHS.NumMIOps)
794480093f4SDimitry Andric return false;
7950b57cec5SDimitry Andric if (Conds.size() != RHS.Conds.size())
7960b57cec5SDimitry Andric return false;
7970b57cec5SDimitry Andric
7980b57cec5SDimitry Andric unsigned Idx = 0;
7990b57cec5SDimitry Andric for (const auto &str : Conds)
8000b57cec5SDimitry Andric if (str != RHS.Conds[Idx++])
8010b57cec5SDimitry Andric return false;
8020b57cec5SDimitry Andric
8030b57cec5SDimitry Andric return true;
8040b57cec5SDimitry Andric }
8050b57cec5SDimitry Andric };
8060b57cec5SDimitry Andric
8070b57cec5SDimitry Andric } // end anonymous namespace
8080b57cec5SDimitry Andric
CountNumOperands(StringRef AsmString,unsigned Variant)8090b57cec5SDimitry Andric static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) {
8100b57cec5SDimitry Andric return AsmString.count(' ') + AsmString.count('\t');
8110b57cec5SDimitry Andric }
8120b57cec5SDimitry Andric
8130b57cec5SDimitry Andric namespace {
8140b57cec5SDimitry Andric
8150b57cec5SDimitry Andric struct AliasPriorityComparator {
8160b57cec5SDimitry Andric typedef std::pair<CodeGenInstAlias, int> ValueType;
operator ()__anon992240d30511::AliasPriorityComparator8170b57cec5SDimitry Andric bool operator()(const ValueType &LHS, const ValueType &RHS) const {
8180b57cec5SDimitry Andric if (LHS.second == RHS.second) {
8190b57cec5SDimitry Andric // We don't actually care about the order, but for consistency it
8200b57cec5SDimitry Andric // shouldn't depend on pointer comparisons.
8210b57cec5SDimitry Andric return LessRecordByID()(LHS.first.TheDef, RHS.first.TheDef);
8220b57cec5SDimitry Andric }
8230b57cec5SDimitry Andric
8240b57cec5SDimitry Andric // Aliases with larger priorities should be considered first.
8250b57cec5SDimitry Andric return LHS.second > RHS.second;
8260b57cec5SDimitry Andric }
8270b57cec5SDimitry Andric };
8280b57cec5SDimitry Andric
8290b57cec5SDimitry Andric } // end anonymous namespace
8300b57cec5SDimitry Andric
EmitPrintAliasInstruction(raw_ostream & O)8310b57cec5SDimitry Andric void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {
8320b57cec5SDimitry Andric Record *AsmWriter = Target.getAsmWriter();
8330b57cec5SDimitry Andric
8340b57cec5SDimitry Andric O << "\n#ifdef PRINT_ALIAS_INSTR\n";
8350b57cec5SDimitry Andric O << "#undef PRINT_ALIAS_INSTR\n\n";
8360b57cec5SDimitry Andric
8370b57cec5SDimitry Andric //////////////////////////////
8380b57cec5SDimitry Andric // Gather information about aliases we need to print
8390b57cec5SDimitry Andric //////////////////////////////
8400b57cec5SDimitry Andric
8410b57cec5SDimitry Andric // Emit the method that prints the alias instruction.
8420b57cec5SDimitry Andric StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");
8430b57cec5SDimitry Andric unsigned Variant = AsmWriter->getValueAsInt("Variant");
8440b57cec5SDimitry Andric bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");
8450b57cec5SDimitry Andric
8460b57cec5SDimitry Andric std::vector<Record *> AllInstAliases =
8470b57cec5SDimitry Andric Records.getAllDerivedDefinitions("InstAlias");
8480b57cec5SDimitry Andric
8490b57cec5SDimitry Andric // Create a map from the qualified name to a list of potential matches.
8500b57cec5SDimitry Andric typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>
8510b57cec5SDimitry Andric AliasWithPriority;
8520b57cec5SDimitry Andric std::map<std::string, AliasWithPriority> AliasMap;
8530b57cec5SDimitry Andric for (Record *R : AllInstAliases) {
8540b57cec5SDimitry Andric int Priority = R->getValueAsInt("EmitPriority");
8550b57cec5SDimitry Andric if (Priority < 1)
8560b57cec5SDimitry Andric continue; // Aliases with priority 0 are never emitted.
8570b57cec5SDimitry Andric
8580b57cec5SDimitry Andric const DagInit *DI = R->getValueAsDag("ResultInst");
8598bcb0991SDimitry Andric AliasMap[getQualifiedName(DI->getOperatorAsDef(R->getLoc()))].insert(
860*0fca6ea1SDimitry Andric std::pair(CodeGenInstAlias(R, Target), Priority));
8610b57cec5SDimitry Andric }
8620b57cec5SDimitry Andric
8630b57cec5SDimitry Andric // A map of which conditions need to be met for each instruction operand
8640b57cec5SDimitry Andric // before it can be matched to the mnemonic.
8650b57cec5SDimitry Andric std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;
8660b57cec5SDimitry Andric
8675ffd83dbSDimitry Andric std::vector<std::pair<std::string, bool>> PrintMethods;
8680b57cec5SDimitry Andric
8690b57cec5SDimitry Andric // A list of MCOperandPredicates for all operands in use, and the reverse map
8700b57cec5SDimitry Andric std::vector<const Record *> MCOpPredicates;
8710b57cec5SDimitry Andric DenseMap<const Record *, unsigned> MCOpPredicateMap;
8720b57cec5SDimitry Andric
8730b57cec5SDimitry Andric for (auto &Aliases : AliasMap) {
874480093f4SDimitry Andric // Collection of instruction alias rules. May contain ambiguous rules.
875480093f4SDimitry Andric std::vector<IAPrinter> IAPs;
876480093f4SDimitry Andric
8770b57cec5SDimitry Andric for (auto &Alias : Aliases.second) {
8780b57cec5SDimitry Andric const CodeGenInstAlias &CGA = Alias.first;
8790b57cec5SDimitry Andric unsigned LastOpNo = CGA.ResultInstOperandIndex.size();
8800b57cec5SDimitry Andric std::string FlatInstAsmString =
881*0fca6ea1SDimitry Andric CodeGenInstruction::FlattenAsmStringVariants(
882*0fca6ea1SDimitry Andric CGA.ResultInst->AsmString, Variant);
8830b57cec5SDimitry Andric unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant);
8840b57cec5SDimitry Andric
8850b57cec5SDimitry Andric std::string FlatAliasAsmString =
886480093f4SDimitry Andric CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, Variant);
8875ffd83dbSDimitry Andric UnescapeAliasString(FlatAliasAsmString);
8880b57cec5SDimitry Andric
8890b57cec5SDimitry Andric // Don't emit the alias if it has more operands than what it's aliasing.
8900b57cec5SDimitry Andric if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant))
8910b57cec5SDimitry Andric continue;
8920b57cec5SDimitry Andric
8930b57cec5SDimitry Andric StringRef Namespace = Target.getName();
8940b57cec5SDimitry Andric unsigned NumMIOps = 0;
8950b57cec5SDimitry Andric for (auto &ResultInstOpnd : CGA.ResultInst->Operands)
8960b57cec5SDimitry Andric NumMIOps += ResultInstOpnd.MINumOperands;
8970b57cec5SDimitry Andric
898480093f4SDimitry Andric IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString, NumMIOps);
8990b57cec5SDimitry Andric
9000b57cec5SDimitry Andric unsigned MIOpNum = 0;
9010b57cec5SDimitry Andric for (unsigned i = 0, e = LastOpNo; i != e; ++i) {
9020b57cec5SDimitry Andric // Skip over tied operands as they're not part of an alias declaration.
9030b57cec5SDimitry Andric auto &Operands = CGA.ResultInst->Operands;
9040b57cec5SDimitry Andric while (true) {
9050b57cec5SDimitry Andric unsigned OpNum = Operands.getSubOperandNumber(MIOpNum).first;
9060b57cec5SDimitry Andric if (Operands[OpNum].MINumOperands == 1 &&
9070b57cec5SDimitry Andric Operands[OpNum].getTiedRegister() != -1) {
908*0fca6ea1SDimitry Andric // Tied operands of different RegisterClass should be explicit
909*0fca6ea1SDimitry Andric // within an instruction's syntax and so cannot be skipped.
9100b57cec5SDimitry Andric int TiedOpNum = Operands[OpNum].getTiedRegister();
9110b57cec5SDimitry Andric if (Operands[OpNum].Rec->getName() ==
9120b57cec5SDimitry Andric Operands[TiedOpNum].Rec->getName()) {
9130b57cec5SDimitry Andric ++MIOpNum;
9140b57cec5SDimitry Andric continue;
9150b57cec5SDimitry Andric }
9160b57cec5SDimitry Andric }
9170b57cec5SDimitry Andric break;
9180b57cec5SDimitry Andric }
9190b57cec5SDimitry Andric
920480093f4SDimitry Andric // Ignore unchecked result operands.
921480093f4SDimitry Andric while (IAP.getCondCount() < MIOpNum)
922480093f4SDimitry Andric IAP.addCond("AliasPatternCond::K_Ignore, 0");
9230b57cec5SDimitry Andric
9240b57cec5SDimitry Andric const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i];
9250b57cec5SDimitry Andric
9260b57cec5SDimitry Andric switch (RO.Kind) {
9270b57cec5SDimitry Andric case CodeGenInstAlias::ResultOperand::K_Record: {
9280b57cec5SDimitry Andric const Record *Rec = RO.getRecord();
9290b57cec5SDimitry Andric StringRef ROName = RO.getName();
9300b57cec5SDimitry Andric int PrintMethodIdx = -1;
9310b57cec5SDimitry Andric
9320b57cec5SDimitry Andric // These two may have a PrintMethod, which we want to record (if it's
9330b57cec5SDimitry Andric // the first time we've seen it) and provide an index for the aliasing
9340b57cec5SDimitry Andric // code to use.
9350b57cec5SDimitry Andric if (Rec->isSubClassOf("RegisterOperand") ||
9360b57cec5SDimitry Andric Rec->isSubClassOf("Operand")) {
9370b57cec5SDimitry Andric StringRef PrintMethod = Rec->getValueAsString("PrintMethod");
9385ffd83dbSDimitry Andric bool IsPCRel =
9395ffd83dbSDimitry Andric Rec->getValueAsString("OperandType") == "OPERAND_PCREL";
9400b57cec5SDimitry Andric if (PrintMethod != "" && PrintMethod != "printOperand") {
9415ffd83dbSDimitry Andric PrintMethodIdx = llvm::find_if(PrintMethods,
9425ffd83dbSDimitry Andric [&](auto &X) {
9435ffd83dbSDimitry Andric return X.first == PrintMethod;
9445ffd83dbSDimitry Andric }) -
9455ffd83dbSDimitry Andric PrintMethods.begin();
9460b57cec5SDimitry Andric if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size())
9475ffd83dbSDimitry Andric PrintMethods.emplace_back(std::string(PrintMethod), IsPCRel);
9480b57cec5SDimitry Andric }
9490b57cec5SDimitry Andric }
9500b57cec5SDimitry Andric
9510b57cec5SDimitry Andric if (Rec->isSubClassOf("RegisterOperand"))
9520b57cec5SDimitry Andric Rec = Rec->getValueAsDef("RegClass");
9530b57cec5SDimitry Andric if (Rec->isSubClassOf("RegisterClass")) {
9540b57cec5SDimitry Andric if (!IAP.isOpMapped(ROName)) {
9550b57cec5SDimitry Andric IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
9560b57cec5SDimitry Andric Record *R = CGA.ResultOperands[i].getRecord();
9570b57cec5SDimitry Andric if (R->isSubClassOf("RegisterOperand"))
9580b57cec5SDimitry Andric R = R->getValueAsDef("RegClass");
9595ffd83dbSDimitry Andric IAP.addCond(std::string(
9605ffd83dbSDimitry Andric formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID",
9615ffd83dbSDimitry Andric Namespace, R->getName())));
9620b57cec5SDimitry Andric } else {
9635ffd83dbSDimitry Andric IAP.addCond(std::string(formatv(
9645ffd83dbSDimitry Andric "AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName))));
9650b57cec5SDimitry Andric }
9660b57cec5SDimitry Andric } else {
9670b57cec5SDimitry Andric // Assume all printable operands are desired for now. This can be
9680b57cec5SDimitry Andric // overridden in the InstAlias instantiation if necessary.
9690b57cec5SDimitry Andric IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);
9700b57cec5SDimitry Andric
9710b57cec5SDimitry Andric // There might be an additional predicate on the MCOperand
9720b57cec5SDimitry Andric unsigned Entry = MCOpPredicateMap[Rec];
9730b57cec5SDimitry Andric if (!Entry) {
9740b57cec5SDimitry Andric if (!Rec->isValueUnset("MCOperandPredicate")) {
9750b57cec5SDimitry Andric MCOpPredicates.push_back(Rec);
9760b57cec5SDimitry Andric Entry = MCOpPredicates.size();
9770b57cec5SDimitry Andric MCOpPredicateMap[Rec] = Entry;
9780b57cec5SDimitry Andric } else
9790b57cec5SDimitry Andric break; // No conditions on this operand at all
9800b57cec5SDimitry Andric }
9815ffd83dbSDimitry Andric IAP.addCond(
9825ffd83dbSDimitry Andric std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry)));
9830b57cec5SDimitry Andric }
9840b57cec5SDimitry Andric break;
9850b57cec5SDimitry Andric }
9860b57cec5SDimitry Andric case CodeGenInstAlias::ResultOperand::K_Imm: {
9870b57cec5SDimitry Andric // Just because the alias has an immediate result, doesn't mean the
9880b57cec5SDimitry Andric // MCInst will. An MCExpr could be present, for example.
989480093f4SDimitry Andric auto Imm = CGA.ResultOperands[i].getImm();
990480093f4SDimitry Andric int32_t Imm32 = int32_t(Imm);
991480093f4SDimitry Andric if (Imm != Imm32)
992480093f4SDimitry Andric PrintFatalError("Matching an alias with an immediate out of the "
993480093f4SDimitry Andric "range of int32_t is not supported");
9945ffd83dbSDimitry Andric IAP.addCond(std::string(
9955ffd83dbSDimitry Andric formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32)));
9960b57cec5SDimitry Andric break;
9970b57cec5SDimitry Andric }
9980b57cec5SDimitry Andric case CodeGenInstAlias::ResultOperand::K_Reg:
9990b57cec5SDimitry Andric if (!CGA.ResultOperands[i].getRegister()) {
100081ad6265SDimitry Andric IAP.addCond(std::string(formatv(
100181ad6265SDimitry Andric "AliasPatternCond::K_Reg, {0}::NoRegister", Namespace)));
10020b57cec5SDimitry Andric break;
10030b57cec5SDimitry Andric }
10040b57cec5SDimitry Andric
1005480093f4SDimitry Andric StringRef Reg = CGA.ResultOperands[i].getRegister()->getName();
10065ffd83dbSDimitry Andric IAP.addCond(std::string(
10075ffd83dbSDimitry Andric formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg)));
10080b57cec5SDimitry Andric break;
10090b57cec5SDimitry Andric }
10100b57cec5SDimitry Andric
10110b57cec5SDimitry Andric MIOpNum += RO.getMINumOperands();
10120b57cec5SDimitry Andric }
10130b57cec5SDimitry Andric
1014480093f4SDimitry Andric std::vector<Record *> ReqFeatures;
1015480093f4SDimitry Andric if (PassSubtarget) {
1016480093f4SDimitry Andric // We only consider ReqFeatures predicates if PassSubtarget
1017480093f4SDimitry Andric std::vector<Record *> RF =
1018480093f4SDimitry Andric CGA.TheDef->getValueAsListOfDefs("Predicates");
1019480093f4SDimitry Andric copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {
1020480093f4SDimitry Andric return R->getValueAsBit("AssemblerMatcherPredicate");
1021480093f4SDimitry Andric });
1022480093f4SDimitry Andric }
1023480093f4SDimitry Andric
1024fe6060f1SDimitry Andric for (Record *const R : ReqFeatures) {
10255ffd83dbSDimitry Andric const DagInit *D = R->getValueAsDag("AssemblerCondDag");
102606c3fb27SDimitry Andric auto *Op = dyn_cast<DefInit>(D->getOperator());
102706c3fb27SDimitry Andric if (!Op)
102806c3fb27SDimitry Andric PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
102906c3fb27SDimitry Andric StringRef CombineType = Op->getDef()->getName();
10305ffd83dbSDimitry Andric if (CombineType != "any_of" && CombineType != "all_of")
10315ffd83dbSDimitry Andric PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
10325ffd83dbSDimitry Andric if (D->getNumArgs() == 0)
10335ffd83dbSDimitry Andric PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
10345ffd83dbSDimitry Andric bool IsOr = CombineType == "any_of";
103581ad6265SDimitry Andric // Change (any_of FeatureAll, (any_of ...)) to (any_of FeatureAll, ...).
103681ad6265SDimitry Andric if (IsOr && D->getNumArgs() == 2 && isa<DagInit>(D->getArg(1))) {
103706c3fb27SDimitry Andric DagInit *RHS = cast<DagInit>(D->getArg(1));
103881ad6265SDimitry Andric SmallVector<Init *> Args{D->getArg(0)};
103981ad6265SDimitry Andric SmallVector<StringInit *> ArgNames{D->getArgName(0)};
104081ad6265SDimitry Andric for (unsigned i = 0, e = RHS->getNumArgs(); i != e; ++i) {
104181ad6265SDimitry Andric Args.push_back(RHS->getArg(i));
104281ad6265SDimitry Andric ArgNames.push_back(RHS->getArgName(i));
104381ad6265SDimitry Andric }
104481ad6265SDimitry Andric D = DagInit::get(D->getOperator(), nullptr, Args, ArgNames);
104581ad6265SDimitry Andric }
10460b57cec5SDimitry Andric
10475ffd83dbSDimitry Andric for (auto *Arg : D->getArgs()) {
10485ffd83dbSDimitry Andric bool IsNeg = false;
10495ffd83dbSDimitry Andric if (auto *NotArg = dyn_cast<DagInit>(Arg)) {
10505ffd83dbSDimitry Andric if (NotArg->getOperator()->getAsString() != "not" ||
10515ffd83dbSDimitry Andric NotArg->getNumArgs() != 1)
10525ffd83dbSDimitry Andric PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
10535ffd83dbSDimitry Andric Arg = NotArg->getArg(0);
10545ffd83dbSDimitry Andric IsNeg = true;
10550b57cec5SDimitry Andric }
10565ffd83dbSDimitry Andric if (!isa<DefInit>(Arg) ||
10575ffd83dbSDimitry Andric !cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))
10585ffd83dbSDimitry Andric PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");
10595ffd83dbSDimitry Andric
10605ffd83dbSDimitry Andric IAP.addCond(std::string(formatv(
10615ffd83dbSDimitry Andric "AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "",
10625ffd83dbSDimitry Andric IsNeg ? "Neg" : "", Namespace, Arg->getAsString())));
10635ffd83dbSDimitry Andric }
10645ffd83dbSDimitry Andric // If an AssemblerPredicate with ors is used, note end of list should
10655ffd83dbSDimitry Andric // these be combined.
10665ffd83dbSDimitry Andric if (IsOr)
10675ffd83dbSDimitry Andric IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0");
10680b57cec5SDimitry Andric }
10690b57cec5SDimitry Andric
10700b57cec5SDimitry Andric IAPrinterMap[Aliases.first].push_back(std::move(IAP));
10710b57cec5SDimitry Andric }
10720b57cec5SDimitry Andric }
10730b57cec5SDimitry Andric
10740b57cec5SDimitry Andric //////////////////////////////
10750b57cec5SDimitry Andric // Write out the printAliasInstr function
10760b57cec5SDimitry Andric //////////////////////////////
10770b57cec5SDimitry Andric
10780b57cec5SDimitry Andric std::string Header;
10790b57cec5SDimitry Andric raw_string_ostream HeaderO(Header);
10800b57cec5SDimitry Andric
10810b57cec5SDimitry Andric HeaderO << "bool " << Target.getName() << ClassName
10820b57cec5SDimitry Andric << "::printAliasInstr(const MCInst"
10835ffd83dbSDimitry Andric << " *MI, uint64_t Address, "
10845ffd83dbSDimitry Andric << (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")
10850b57cec5SDimitry Andric << "raw_ostream &OS) {\n";
10860b57cec5SDimitry Andric
1087480093f4SDimitry Andric std::string PatternsForOpcode;
1088480093f4SDimitry Andric raw_string_ostream OpcodeO(PatternsForOpcode);
10890b57cec5SDimitry Andric
1090480093f4SDimitry Andric unsigned PatternCount = 0;
1091480093f4SDimitry Andric std::string Patterns;
1092480093f4SDimitry Andric raw_string_ostream PatternO(Patterns);
1093480093f4SDimitry Andric
1094480093f4SDimitry Andric unsigned CondCount = 0;
1095480093f4SDimitry Andric std::string Conds;
1096480093f4SDimitry Andric raw_string_ostream CondO(Conds);
1097480093f4SDimitry Andric
1098480093f4SDimitry Andric // All flattened alias strings.
1099480093f4SDimitry Andric std::map<std::string, uint32_t> AsmStringOffsets;
1100480093f4SDimitry Andric std::vector<std::pair<uint32_t, std::string>> AsmStrings;
1101480093f4SDimitry Andric size_t AsmStringsSize = 0;
1102480093f4SDimitry Andric
1103480093f4SDimitry Andric // Iterate over the opcodes in enum order so they are sorted by opcode for
1104480093f4SDimitry Andric // binary search.
1105480093f4SDimitry Andric for (const CodeGenInstruction *Inst : NumberedInstructions) {
1106480093f4SDimitry Andric auto It = IAPrinterMap.find(getQualifiedName(Inst->TheDef));
1107480093f4SDimitry Andric if (It == IAPrinterMap.end())
1108480093f4SDimitry Andric continue;
1109480093f4SDimitry Andric std::vector<IAPrinter> &IAPs = It->second;
11100b57cec5SDimitry Andric std::vector<IAPrinter *> UniqueIAPs;
11110b57cec5SDimitry Andric
1112480093f4SDimitry Andric // Remove any ambiguous alias rules.
11130b57cec5SDimitry Andric for (auto &LHS : IAPs) {
11140b57cec5SDimitry Andric bool IsDup = false;
11150b57cec5SDimitry Andric for (const auto &RHS : IAPs) {
11160b57cec5SDimitry Andric if (&LHS != &RHS && LHS == RHS) {
11170b57cec5SDimitry Andric IsDup = true;
11180b57cec5SDimitry Andric break;
11190b57cec5SDimitry Andric }
11200b57cec5SDimitry Andric }
11210b57cec5SDimitry Andric
11220b57cec5SDimitry Andric if (!IsDup)
11230b57cec5SDimitry Andric UniqueIAPs.push_back(&LHS);
11240b57cec5SDimitry Andric }
11250b57cec5SDimitry Andric
1126*0fca6ea1SDimitry Andric if (UniqueIAPs.empty())
1127*0fca6ea1SDimitry Andric continue;
11280b57cec5SDimitry Andric
1129480093f4SDimitry Andric unsigned PatternStart = PatternCount;
1130480093f4SDimitry Andric
1131480093f4SDimitry Andric // Insert the pattern start and opcode in the pattern list for debugging.
1132480093f4SDimitry Andric PatternO << formatv(" // {0} - {1}\n", It->first, PatternStart);
11330b57cec5SDimitry Andric
11340b57cec5SDimitry Andric for (IAPrinter *IAP : UniqueIAPs) {
1135480093f4SDimitry Andric // Start each condition list with a comment of the resulting pattern that
1136480093f4SDimitry Andric // we're trying to match.
1137480093f4SDimitry Andric unsigned CondStart = CondCount;
1138480093f4SDimitry Andric CondO << formatv(" // {0} - {1}\n", IAP->getResult(), CondStart);
1139480093f4SDimitry Andric for (const auto &Cond : IAP->getConds())
1140480093f4SDimitry Andric CondO << " {" << Cond << "},\n";
1141480093f4SDimitry Andric CondCount += IAP->getCondCount();
1142480093f4SDimitry Andric
1143480093f4SDimitry Andric // After operands have been examined, re-encode the alias string with
1144480093f4SDimitry Andric // escapes indicating how operands should be printed.
1145480093f4SDimitry Andric uint32_t UnescapedSize = 0;
1146480093f4SDimitry Andric std::string EncodedAsmString = IAP->formatAliasString(UnescapedSize);
1147480093f4SDimitry Andric auto Insertion =
1148480093f4SDimitry Andric AsmStringOffsets.insert({EncodedAsmString, AsmStringsSize});
1149480093f4SDimitry Andric if (Insertion.second) {
1150480093f4SDimitry Andric // If the string is new, add it to the vector.
1151480093f4SDimitry Andric AsmStrings.push_back({AsmStringsSize, EncodedAsmString});
1152480093f4SDimitry Andric AsmStringsSize += UnescapedSize + 1;
1153480093f4SDimitry Andric }
1154480093f4SDimitry Andric unsigned AsmStrOffset = Insertion.first->second;
1155480093f4SDimitry Andric
1156480093f4SDimitry Andric PatternO << formatv(" {{{0}, {1}, {2}, {3} },\n", AsmStrOffset,
1157480093f4SDimitry Andric CondStart, IAP->getNumMIOps(), IAP->getCondCount());
1158480093f4SDimitry Andric ++PatternCount;
11590b57cec5SDimitry Andric }
11600b57cec5SDimitry Andric
1161480093f4SDimitry Andric OpcodeO << formatv(" {{{0}, {1}, {2} },\n", It->first, PatternStart,
1162480093f4SDimitry Andric PatternCount - PatternStart);
11630b57cec5SDimitry Andric }
11640b57cec5SDimitry Andric
1165*0fca6ea1SDimitry Andric if (PatternsForOpcode.empty()) {
1166*0fca6ea1SDimitry Andric O << Header;
11670b57cec5SDimitry Andric O << " return false;\n";
11680b57cec5SDimitry Andric O << "}\n\n";
11690b57cec5SDimitry Andric O << "#endif // PRINT_ALIAS_INSTR\n";
11700b57cec5SDimitry Andric return;
11710b57cec5SDimitry Andric }
11720b57cec5SDimitry Andric
1173480093f4SDimitry Andric // Forward declare the validation method if needed.
11740b57cec5SDimitry Andric if (!MCOpPredicates.empty())
11750b57cec5SDimitry Andric O << "static bool " << Target.getName() << ClassName
11760b57cec5SDimitry Andric << "ValidateMCOperand(const MCOperand &MCOp,\n"
11770b57cec5SDimitry Andric << " const MCSubtargetInfo &STI,\n"
11780b57cec5SDimitry Andric << " unsigned PredicateIndex);\n";
11790b57cec5SDimitry Andric
1180*0fca6ea1SDimitry Andric O << Header;
1181480093f4SDimitry Andric O.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n";
1182*0fca6ea1SDimitry Andric O << PatternsForOpcode;
1183480093f4SDimitry Andric O.indent(2) << "};\n\n";
1184480093f4SDimitry Andric O.indent(2) << "static const AliasPattern Patterns[] = {\n";
1185*0fca6ea1SDimitry Andric O << Patterns;
1186480093f4SDimitry Andric O.indent(2) << "};\n\n";
1187480093f4SDimitry Andric O.indent(2) << "static const AliasPatternCond Conds[] = {\n";
1188*0fca6ea1SDimitry Andric O << Conds;
1189480093f4SDimitry Andric O.indent(2) << "};\n\n";
1190480093f4SDimitry Andric O.indent(2) << "static const char AsmStrings[] =\n";
1191480093f4SDimitry Andric for (const auto &P : AsmStrings) {
1192480093f4SDimitry Andric O.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n";
1193480093f4SDimitry Andric }
1194480093f4SDimitry Andric
1195480093f4SDimitry Andric O.indent(2) << ";\n\n";
1196480093f4SDimitry Andric
1197480093f4SDimitry Andric // Assert that the opcode table is sorted. Use a static local constructor to
1198480093f4SDimitry Andric // ensure that the check only happens once on first run.
1199480093f4SDimitry Andric O << "#ifndef NDEBUG\n";
1200480093f4SDimitry Andric O.indent(2) << "static struct SortCheck {\n";
1201480093f4SDimitry Andric O.indent(2) << " SortCheck(ArrayRef<PatternsForOpcode> OpToPatterns) {\n";
1202480093f4SDimitry Andric O.indent(2) << " assert(std::is_sorted(\n";
1203480093f4SDimitry Andric O.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n";
1204480093f4SDimitry Andric O.indent(2) << " [](const PatternsForOpcode &L, const "
1205480093f4SDimitry Andric "PatternsForOpcode &R) {\n";
1206480093f4SDimitry Andric O.indent(2) << " return L.Opcode < R.Opcode;\n";
1207480093f4SDimitry Andric O.indent(2) << " }) &&\n";
1208480093f4SDimitry Andric O.indent(2) << " \"tablegen failed to sort opcode patterns\");\n";
1209480093f4SDimitry Andric O.indent(2) << " }\n";
1210480093f4SDimitry Andric O.indent(2) << "} sortCheckVar(OpToPatterns);\n";
1211480093f4SDimitry Andric O << "#endif\n\n";
1212480093f4SDimitry Andric
1213480093f4SDimitry Andric O.indent(2) << "AliasMatchingData M {\n";
1214bdd1243dSDimitry Andric O.indent(2) << " ArrayRef(OpToPatterns),\n";
1215bdd1243dSDimitry Andric O.indent(2) << " ArrayRef(Patterns),\n";
1216bdd1243dSDimitry Andric O.indent(2) << " ArrayRef(Conds),\n";
1217bdd1243dSDimitry Andric O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n";
1218480093f4SDimitry Andric if (MCOpPredicates.empty())
1219480093f4SDimitry Andric O.indent(2) << " nullptr,\n";
1220480093f4SDimitry Andric else
1221*0fca6ea1SDimitry Andric O.indent(2) << " &" << Target.getName() << ClassName
1222*0fca6ea1SDimitry Andric << "ValidateMCOperand,\n";
1223480093f4SDimitry Andric O.indent(2) << "};\n";
1224480093f4SDimitry Andric
1225480093f4SDimitry Andric O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, "
1226480093f4SDimitry Andric << (PassSubtarget ? "&STI" : "nullptr") << ", M);\n";
1227480093f4SDimitry Andric O.indent(2) << "if (!AsmString) return false;\n\n";
12280b57cec5SDimitry Andric
12290b57cec5SDimitry Andric // Code that prints the alias, replacing the operands with the ones from the
12300b57cec5SDimitry Andric // MCInst.
12310b57cec5SDimitry Andric O << " unsigned I = 0;\n";
12320b57cec5SDimitry Andric O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n";
12330b57cec5SDimitry Andric O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n";
12340b57cec5SDimitry Andric O << " ++I;\n";
12350b57cec5SDimitry Andric O << " OS << '\\t' << StringRef(AsmString, I);\n";
12360b57cec5SDimitry Andric
12370b57cec5SDimitry Andric O << " if (AsmString[I] != '\\0') {\n";
12380b57cec5SDimitry Andric O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n";
12390b57cec5SDimitry Andric O << " OS << '\\t';\n";
12400b57cec5SDimitry Andric O << " ++I;\n";
12410b57cec5SDimitry Andric O << " }\n";
12420b57cec5SDimitry Andric O << " do {\n";
12430b57cec5SDimitry Andric O << " if (AsmString[I] == '$') {\n";
12440b57cec5SDimitry Andric O << " ++I;\n";
12450b57cec5SDimitry Andric O << " if (AsmString[I] == (char)0xff) {\n";
12460b57cec5SDimitry Andric O << " ++I;\n";
12470b57cec5SDimitry Andric O << " int OpIdx = AsmString[I++] - 1;\n";
12480b57cec5SDimitry Andric O << " int PrintMethodIdx = AsmString[I++] - 1;\n";
12495ffd83dbSDimitry Andric O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, ";
12500b57cec5SDimitry Andric O << (PassSubtarget ? "STI, " : "");
12510b57cec5SDimitry Andric O << "OS);\n";
12520b57cec5SDimitry Andric O << " } else\n";
12530b57cec5SDimitry Andric O << " printOperand(MI, unsigned(AsmString[I++]) - 1, ";
12540b57cec5SDimitry Andric O << (PassSubtarget ? "STI, " : "");
12550b57cec5SDimitry Andric O << "OS);\n";
12560b57cec5SDimitry Andric O << " } else {\n";
12570b57cec5SDimitry Andric O << " OS << AsmString[I++];\n";
12580b57cec5SDimitry Andric O << " }\n";
12590b57cec5SDimitry Andric O << " } while (AsmString[I] != '\\0');\n";
12600b57cec5SDimitry Andric O << " }\n\n";
12610b57cec5SDimitry Andric
12620b57cec5SDimitry Andric O << " return true;\n";
12630b57cec5SDimitry Andric O << "}\n\n";
12640b57cec5SDimitry Andric
12650b57cec5SDimitry Andric //////////////////////////////
12660b57cec5SDimitry Andric // Write out the printCustomAliasOperand function
12670b57cec5SDimitry Andric //////////////////////////////
12680b57cec5SDimitry Andric
12690b57cec5SDimitry Andric O << "void " << Target.getName() << ClassName << "::"
12700b57cec5SDimitry Andric << "printCustomAliasOperand(\n"
12715ffd83dbSDimitry Andric << " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n"
12720b57cec5SDimitry Andric << " unsigned PrintMethodIdx,\n"
12730b57cec5SDimitry Andric << (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "")
12740b57cec5SDimitry Andric << " raw_ostream &OS) {\n";
12750b57cec5SDimitry Andric if (PrintMethods.empty())
12760b57cec5SDimitry Andric O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n";
12770b57cec5SDimitry Andric else {
12780b57cec5SDimitry Andric O << " switch (PrintMethodIdx) {\n"
12790b57cec5SDimitry Andric << " default:\n"
12800b57cec5SDimitry Andric << " llvm_unreachable(\"Unknown PrintMethod kind\");\n"
12810b57cec5SDimitry Andric << " break;\n";
12820b57cec5SDimitry Andric
12830b57cec5SDimitry Andric for (unsigned i = 0; i < PrintMethods.size(); ++i) {
12840b57cec5SDimitry Andric O << " case " << i << ":\n"
12855ffd83dbSDimitry Andric << " " << PrintMethods[i].first << "(MI, "
12865ffd83dbSDimitry Andric << (PrintMethods[i].second ? "Address, " : "") << "OpIdx, "
12870b57cec5SDimitry Andric << (PassSubtarget ? "STI, " : "") << "OS);\n"
12880b57cec5SDimitry Andric << " break;\n";
12890b57cec5SDimitry Andric }
12900b57cec5SDimitry Andric O << " }\n";
12910b57cec5SDimitry Andric }
12920b57cec5SDimitry Andric O << "}\n\n";
12930b57cec5SDimitry Andric
12940b57cec5SDimitry Andric if (!MCOpPredicates.empty()) {
12950b57cec5SDimitry Andric O << "static bool " << Target.getName() << ClassName
12960b57cec5SDimitry Andric << "ValidateMCOperand(const MCOperand &MCOp,\n"
12970b57cec5SDimitry Andric << " const MCSubtargetInfo &STI,\n"
12980b57cec5SDimitry Andric << " unsigned PredicateIndex) {\n"
12990b57cec5SDimitry Andric << " switch (PredicateIndex) {\n"
13000b57cec5SDimitry Andric << " default:\n"
13010b57cec5SDimitry Andric << " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"
13020b57cec5SDimitry Andric << " break;\n";
13030b57cec5SDimitry Andric
13040b57cec5SDimitry Andric for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {
1305*0fca6ea1SDimitry Andric StringRef MCOpPred =
1306*0fca6ea1SDimitry Andric MCOpPredicates[i]->getValueAsString("MCOperandPredicate");
13070b57cec5SDimitry Andric O << " case " << i + 1 << ": {\n"
1308e8d8bef9SDimitry Andric << MCOpPred.data() << "\n"
13090b57cec5SDimitry Andric << " }\n";
13100b57cec5SDimitry Andric }
13110b57cec5SDimitry Andric O << " }\n"
13120b57cec5SDimitry Andric << "}\n\n";
13130b57cec5SDimitry Andric }
13140b57cec5SDimitry Andric
13150b57cec5SDimitry Andric O << "#endif // PRINT_ALIAS_INSTR\n";
13160b57cec5SDimitry Andric }
13170b57cec5SDimitry Andric
AsmWriterEmitter(RecordKeeper & R)13180b57cec5SDimitry Andric AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {
13190b57cec5SDimitry Andric Record *AsmWriter = Target.getAsmWriter();
13200b57cec5SDimitry Andric unsigned Variant = AsmWriter->getValueAsInt("Variant");
13210b57cec5SDimitry Andric
13220b57cec5SDimitry Andric // Get the instruction numbering.
13230b57cec5SDimitry Andric NumberedInstructions = Target.getInstructionsByEnumValue();
13240b57cec5SDimitry Andric
13250b57cec5SDimitry Andric for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {
13260b57cec5SDimitry Andric const CodeGenInstruction *I = NumberedInstructions[i];
13270b57cec5SDimitry Andric if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")
13280b57cec5SDimitry Andric Instructions.emplace_back(*I, i, Variant);
13290b57cec5SDimitry Andric }
13300b57cec5SDimitry Andric }
13310b57cec5SDimitry Andric
run(raw_ostream & O)13320b57cec5SDimitry Andric void AsmWriterEmitter::run(raw_ostream &O) {
1333e8d8bef9SDimitry Andric std::vector<std::vector<std::string>> TableDrivenOperandPrinters;
1334e8d8bef9SDimitry Andric unsigned BitsLeft = 0;
1335e8d8bef9SDimitry Andric unsigned AsmStrBits = 0;
13365f757f3fSDimitry Andric emitSourceFileHeader("Assembly Writer Source Fragment", O, Records);
1337e8d8bef9SDimitry Andric EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
1338e8d8bef9SDimitry Andric EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);
13390b57cec5SDimitry Andric EmitGetRegisterName(O);
13400b57cec5SDimitry Andric EmitPrintAliasInstruction(O);
13410b57cec5SDimitry Andric }
13420b57cec5SDimitry Andric
134306c3fb27SDimitry Andric static TableGen::Emitter::OptClass<AsmWriterEmitter>
134406c3fb27SDimitry Andric X("gen-asm-writer", "Generate assembly writer");
1345