llvm-project
1344 строки · 48.5 Кб
1//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This tablegen backend emits an assembly printer for the current target.
10// Note that this is currently fairly skeletal, but will grow over time.
11//
12//===----------------------------------------------------------------------===//
13
14#include "Basic/SequenceToOffsetTable.h"15#include "Common/AsmWriterInst.h"16#include "Common/CodeGenInstAlias.h"17#include "Common/CodeGenInstruction.h"18#include "Common/CodeGenRegisters.h"19#include "Common/CodeGenTarget.h"20#include "Common/Types.h"21#include "llvm/ADT/ArrayRef.h"22#include "llvm/ADT/DenseMap.h"23#include "llvm/ADT/STLExtras.h"24#include "llvm/ADT/SmallString.h"25#include "llvm/ADT/SmallVector.h"26#include "llvm/ADT/StringExtras.h"27#include "llvm/ADT/StringRef.h"28#include "llvm/ADT/Twine.h"29#include "llvm/Support/Casting.h"30#include "llvm/Support/Debug.h"31#include "llvm/Support/Format.h"32#include "llvm/Support/FormatVariadic.h"33#include "llvm/Support/MathExtras.h"34#include "llvm/Support/raw_ostream.h"35#include "llvm/TableGen/Error.h"36#include "llvm/TableGen/Record.h"37#include "llvm/TableGen/TableGenBackend.h"38#include <algorithm>39#include <cassert>40#include <cstddef>41#include <cstdint>42#include <deque>43#include <iterator>44#include <map>45#include <set>46#include <string>47#include <tuple>48#include <utility>49#include <vector>50
51using namespace llvm;52
53#define DEBUG_TYPE "asm-writer-emitter"54
55namespace {56
57class AsmWriterEmitter {58RecordKeeper &Records;59CodeGenTarget Target;60ArrayRef<const CodeGenInstruction *> NumberedInstructions;61std::vector<AsmWriterInst> Instructions;62
63public:64AsmWriterEmitter(RecordKeeper &R);65
66void run(raw_ostream &o);67
68private:69void EmitGetMnemonic(70raw_ostream &o,71std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,72unsigned &BitsLeft, unsigned &AsmStrBits);73void EmitPrintInstruction(74raw_ostream &o,75std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,76unsigned &BitsLeft, unsigned &AsmStrBits);77void EmitGetRegisterName(raw_ostream &o);78void EmitPrintAliasInstruction(raw_ostream &O);79
80void FindUniqueOperandCommands(std::vector<std::string> &UOC,81std::vector<std::vector<unsigned>> &InstIdxs,82std::vector<unsigned> &InstOpsUsed,83bool PassSubtarget) const;84};85
86} // end anonymous namespace87
88static void89PrintCases(std::vector<std::pair<std::string, AsmWriterOperand>> &OpsToPrint,90raw_ostream &O, bool PassSubtarget) {91O << " case " << OpsToPrint.back().first << ":";92AsmWriterOperand TheOp = OpsToPrint.back().second;93OpsToPrint.pop_back();94
95// Check to see if any other operands are identical in this list, and if so,96// emit a case label for them.97for (unsigned i = OpsToPrint.size(); i != 0; --i)98if (OpsToPrint[i - 1].second == TheOp) {99O << "\n case " << OpsToPrint[i - 1].first << ":";100OpsToPrint.erase(OpsToPrint.begin() + i - 1);101}102
103// Finally, emit the code.104O << "\n " << TheOp.getCode(PassSubtarget);105O << "\n break;\n";106}
107
108/// EmitInstructions - Emit the last instruction in the vector and any other
109/// instructions that are suitably similar to it.
110static void EmitInstructions(std::vector<AsmWriterInst> &Insts, raw_ostream &O,111bool PassSubtarget) {112AsmWriterInst FirstInst = Insts.back();113Insts.pop_back();114
115std::vector<AsmWriterInst> SimilarInsts;116unsigned DifferingOperand = ~0;117for (unsigned i = Insts.size(); i != 0; --i) {118unsigned DiffOp = Insts[i - 1].MatchesAllButOneOp(FirstInst);119if (DiffOp != ~1U) {120if (DifferingOperand == ~0U) // First match!121DifferingOperand = DiffOp;122
123// If this differs in the same operand as the rest of the instructions in124// this class, move it to the SimilarInsts list.125if (DifferingOperand == DiffOp || DiffOp == ~0U) {126SimilarInsts.push_back(Insts[i - 1]);127Insts.erase(Insts.begin() + i - 1);128}129}130}131
132O << " case " << FirstInst.CGI->Namespace133<< "::" << FirstInst.CGI->TheDef->getName() << ":\n";134for (const AsmWriterInst &AWI : SimilarInsts)135O << " case " << AWI.CGI->Namespace << "::" << AWI.CGI->TheDef->getName()136<< ":\n";137for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {138if (i != DifferingOperand) {139// If the operand is the same for all instructions, just print it.140O << " " << FirstInst.Operands[i].getCode(PassSubtarget);141} else {142// If this is the operand that varies between all of the instructions,143// emit a switch for just this operand now.144O << " switch (MI->getOpcode()) {\n";145O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";146std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint;147OpsToPrint.push_back(std::pair(FirstInst.CGI->Namespace.str() + "::" +148FirstInst.CGI->TheDef->getName().str(),149FirstInst.Operands[i]));150
151for (const AsmWriterInst &AWI : SimilarInsts) {152OpsToPrint.push_back(std::pair(153AWI.CGI->Namespace.str() + "::" + AWI.CGI->TheDef->getName().str(),154AWI.Operands[i]));155}156std::reverse(OpsToPrint.begin(), OpsToPrint.end());157while (!OpsToPrint.empty())158PrintCases(OpsToPrint, O, PassSubtarget);159O << " }";160}161O << "\n";162}163O << " break;\n";164}
165
166void AsmWriterEmitter::FindUniqueOperandCommands(167std::vector<std::string> &UniqueOperandCommands,168std::vector<std::vector<unsigned>> &InstIdxs,169std::vector<unsigned> &InstOpsUsed, bool PassSubtarget) const {170// This vector parallels UniqueOperandCommands, keeping track of which171// instructions each case are used for. It is a comma separated string of172// enums.173std::vector<std::string> InstrsForCase;174InstrsForCase.resize(UniqueOperandCommands.size());175InstOpsUsed.assign(UniqueOperandCommands.size(), 0);176
177for (size_t i = 0, e = Instructions.size(); i != e; ++i) {178const AsmWriterInst &Inst = Instructions[i];179if (Inst.Operands.empty())180continue; // Instruction already done.181
182std::string Command =183" " + Inst.Operands[0].getCode(PassSubtarget) + "\n";184
185// Check to see if we already have 'Command' in UniqueOperandCommands.186// If not, add it.187auto I = llvm::find(UniqueOperandCommands, Command);188if (I != UniqueOperandCommands.end()) {189size_t idx = I - UniqueOperandCommands.begin();190InstrsForCase[idx] += ", ";191InstrsForCase[idx] += Inst.CGI->TheDef->getName();192InstIdxs[idx].push_back(i);193} else {194UniqueOperandCommands.push_back(std::move(Command));195InstrsForCase.push_back(std::string(Inst.CGI->TheDef->getName()));196InstIdxs.emplace_back();197InstIdxs.back().push_back(i);198
199// This command matches one operand so far.200InstOpsUsed.push_back(1);201}202}203
204// For each entry of UniqueOperandCommands, there is a set of instructions205// that uses it. If the next command of all instructions in the set are206// identical, fold it into the command.207for (size_t CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e;208++CommandIdx) {209
210const auto &Idxs = InstIdxs[CommandIdx];211
212for (unsigned Op = 1;; ++Op) {213// Find the first instruction in the set.214const AsmWriterInst &FirstInst = Instructions[Idxs.front()];215// If this instruction has no more operands, we isn't anything to merge216// into this command.217if (FirstInst.Operands.size() == Op)218break;219
220// Otherwise, scan to see if all of the other instructions in this command221// set share the operand.222if (any_of(drop_begin(Idxs), [&](unsigned Idx) {223const AsmWriterInst &OtherInst = Instructions[Idx];224return OtherInst.Operands.size() == Op ||225OtherInst.Operands[Op] != FirstInst.Operands[Op];226}))227break;228
229// Okay, everything in this command set has the same next operand. Add it230// to UniqueOperandCommands and remember that it was consumed.231std::string Command =232" " + FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";233
234UniqueOperandCommands[CommandIdx] += Command;235InstOpsUsed[CommandIdx]++;236}237}238
239// Prepend some of the instructions each case is used for onto the case val.240for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {241std::string Instrs = InstrsForCase[i];242if (Instrs.size() > 70) {243Instrs.erase(Instrs.begin() + 70, Instrs.end());244Instrs += "...";245}246
247if (!Instrs.empty())248UniqueOperandCommands[i] =249" // " + Instrs + "\n" + UniqueOperandCommands[i];250}251}
252
253static void UnescapeString(std::string &Str) {254for (unsigned i = 0; i != Str.size(); ++i) {255if (Str[i] == '\\' && i != Str.size() - 1) {256switch (Str[i + 1]) {257default:258continue; // Don't execute the code after the switch.259case 'a':260Str[i] = '\a';261break;262case 'b':263Str[i] = '\b';264break;265case 'e':266Str[i] = 27;267break;268case 'f':269Str[i] = '\f';270break;271case 'n':272Str[i] = '\n';273break;274case 'r':275Str[i] = '\r';276break;277case 't':278Str[i] = '\t';279break;280case 'v':281Str[i] = '\v';282break;283case '"':284Str[i] = '\"';285break;286case '\'':287Str[i] = '\'';288break;289case '\\':290Str[i] = '\\';291break;292}293// Nuke the second character.294Str.erase(Str.begin() + i + 1);295}296}297}
298
299/// UnescapeAliasString - Supports literal braces in InstAlias asm string which
300/// are escaped with '\\' to avoid being interpreted as variants. Braces must
301/// be unescaped before c++ code is generated as (e.g.):
302///
303/// AsmString = "foo \{$\x01\}";
304///
305/// causes non-standard escape character warnings.
306static void UnescapeAliasString(std::string &Str) {307for (unsigned i = 0; i != Str.size(); ++i) {308if (Str[i] == '\\' && i != Str.size() - 1) {309switch (Str[i + 1]) {310default:311continue; // Don't execute the code after the switch.312case '{':313Str[i] = '{';314break;315case '}':316Str[i] = '}';317break;318}319// Nuke the second character.320Str.erase(Str.begin() + i + 1);321}322}323}
324
325void AsmWriterEmitter::EmitGetMnemonic(326raw_ostream &O,327std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,328unsigned &BitsLeft, unsigned &AsmStrBits) {329Record *AsmWriter = Target.getAsmWriter();330StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");331bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");332
333O << "/// getMnemonic - This method is automatically generated by "334"tablegen\n"335"/// from the instruction set description.\n"336"std::pair<const char *, uint64_t> "337<< Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n";338
339// Build an aggregate string, and build a table of offsets into it.340SequenceToOffsetTable<std::string> StringTable;341
342/// OpcodeInfo - This encodes the index of the string to use for the first343/// chunk of the output as well as indices used for operand printing.344std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size());345const unsigned OpcodeInfoBits = 64;346
347// Add all strings to the string table upfront so it can generate an optimized348// representation.349for (AsmWriterInst &AWI : Instructions) {350if (AWI.Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand &&351!AWI.Operands[0].Str.empty()) {352std::string Str = AWI.Operands[0].Str;353UnescapeString(Str);354StringTable.add(Str);355}356}357
358StringTable.layout();359
360unsigned MaxStringIdx = 0;361for (AsmWriterInst &AWI : Instructions) {362unsigned Idx;363if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand ||364AWI.Operands[0].Str.empty()) {365// Something handled by the asmwriter printer, but with no leading string.366Idx = StringTable.get("");367} else {368std::string Str = AWI.Operands[0].Str;369UnescapeString(Str);370Idx = StringTable.get(Str);371MaxStringIdx = std::max(MaxStringIdx, Idx);372
373// Nuke the string from the operand list. It is now handled!374AWI.Operands.erase(AWI.Operands.begin());375}376
377// Bias offset by one since we want 0 as a sentinel.378OpcodeInfo[AWI.CGIIndex] = Idx + 1;379}380
381// Figure out how many bits we used for the string index.382AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2);383
384// To reduce code size, we compactify common instructions into a few bits385// in the opcode-indexed table.386BitsLeft = OpcodeInfoBits - AsmStrBits;387
388while (true) {389std::vector<std::string> UniqueOperandCommands;390std::vector<std::vector<unsigned>> InstIdxs;391std::vector<unsigned> NumInstOpsHandled;392FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,393NumInstOpsHandled, PassSubtarget);394
395// If we ran out of operands to print, we're done.396if (UniqueOperandCommands.empty())397break;398
399// Compute the number of bits we need to represent these cases, this is400// ceil(log2(numentries)).401unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());402
403// If we don't have enough bits for this operand, don't include it.404if (NumBits > BitsLeft) {405LLVM_DEBUG(errs() << "Not enough bits to densely encode " << NumBits406<< " more bits\n");407break;408}409
410// Otherwise, we can include this in the initial lookup table. Add it in.411for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) {412unsigned NumOps = NumInstOpsHandled[i];413for (unsigned Idx : InstIdxs[i]) {414OpcodeInfo[Instructions[Idx].CGIIndex] |=415(uint64_t)i << (OpcodeInfoBits - BitsLeft);416// Remove the info about this operand from the instruction.417AsmWriterInst &Inst = Instructions[Idx];418if (!Inst.Operands.empty()) {419assert(NumOps <= Inst.Operands.size() &&420"Can't remove this many ops!");421Inst.Operands.erase(Inst.Operands.begin(),422Inst.Operands.begin() + NumOps);423}424}425}426BitsLeft -= NumBits;427
428// Remember the handlers for this set of operands.429TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));430}431
432// Emit the string table itself.433StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]");434
435// Emit the lookup tables in pieces to minimize wasted bytes.436unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8;437unsigned Table = 0, Shift = 0;438SmallString<128> BitsString;439raw_svector_ostream BitsOS(BitsString);440// If the total bits is more than 32-bits we need to use a 64-bit type.441BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)442<< "_t Bits = 0;\n";443while (BytesNeeded != 0) {444// Figure out how big this table section needs to be, but no bigger than 4.445unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u);446BytesNeeded -= TableSize;447TableSize *= 8; // Convert to bits;448uint64_t Mask = (1ULL << TableSize) - 1;449O << " static const uint" << TableSize << "_t OpInfo" << Table450<< "[] = {\n";451for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {452O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "453<< NumberedInstructions[i]->TheDef->getName() << "\n";454}455O << " };\n\n";456// Emit string to combine the individual table lookups.457BitsOS << " Bits |= ";458// If the total bits is more than 32-bits we need to use a 64-bit type.459if (BitsLeft < (OpcodeInfoBits - 32))460BitsOS << "(uint64_t)";461BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n";462// Prepare the shift for the next iteration and increment the table count.463Shift += TableSize;464++Table;465}466
467O << " // Emit the opcode for the instruction.\n";468O << BitsString;469
470// Make sure we don't return an invalid pointer if bits is 0471O << " if (Bits == 0)\n"472" return {nullptr, Bits};\n";473
474// Return mnemonic string and bits.475O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1476<< ")-1, Bits};\n\n";477
478O << "}\n";479}
480
481/// EmitPrintInstruction - Generate the code for the "printInstruction" method
482/// implementation. Destroys all instances of AsmWriterInst information, by
483/// clearing the Instructions vector.
484void AsmWriterEmitter::EmitPrintInstruction(485raw_ostream &O,486std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,487unsigned &BitsLeft, unsigned &AsmStrBits) {488const unsigned OpcodeInfoBits = 64;489Record *AsmWriter = Target.getAsmWriter();490StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");491bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");492
493// This function has some huge switch statements that causing excessive494// compile time in LLVM profile instrumenation build. This print function495// usually is not frequently called in compilation. Here we disable the496// profile instrumenation for this function.497O << "/// printInstruction - This method is automatically generated by "498"tablegen\n"499"/// from the instruction set description.\n"500"LLVM_NO_PROFILE_INSTRUMENT_FUNCTION\n"501"void "502<< Target.getName() << ClassName503<< "::printInstruction(const MCInst *MI, uint64_t Address, "504<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")505<< "raw_ostream &O) {\n";506
507// Emit the initial tab character.508O << " O << \"\\t\";\n\n";509
510// Emit the starting string.511O << " auto MnemonicInfo = getMnemonic(MI);\n\n";512O << " O << MnemonicInfo.first;\n\n";513
514O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)515<< "_t Bits = MnemonicInfo.second;\n"516<< " assert(Bits != 0 && \"Cannot print this instruction.\");\n";517
518// Output the table driven operand information.519BitsLeft = OpcodeInfoBits - AsmStrBits;520for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {521std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];522
523// Compute the number of bits we need to represent these cases, this is524// ceil(log2(numentries)).525unsigned NumBits = Log2_32_Ceil(Commands.size());526assert(NumBits <= BitsLeft && "consistency error");527
528// Emit code to extract this field from Bits.529O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for "530<< Commands.size() << " unique commands.\n";531
532if (Commands.size() == 2) {533// Emit two possibilitys with if/else.534O << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "535<< ((1 << NumBits) - 1) << ") {\n"536<< Commands[1] << " } else {\n"537<< Commands[0] << " }\n\n";538} else if (Commands.size() == 1) {539// Emit a single possibility.540O << Commands[0] << "\n\n";541} else {542O << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "543<< ((1 << NumBits) - 1) << ") {\n"544<< " default: llvm_unreachable(\"Invalid command number.\");\n";545
546// Print out all the cases.547for (unsigned j = 0, e = Commands.size(); j != e; ++j) {548O << " case " << j << ":\n";549O << Commands[j];550O << " break;\n";551}552O << " }\n\n";553}554BitsLeft -= NumBits;555}556
557// Okay, delete instructions with no operand info left.558llvm::erase_if(Instructions,559[](AsmWriterInst &Inst) { return Inst.Operands.empty(); });560
561// Because this is a vector, we want to emit from the end. Reverse all of the562// elements in the vector.563std::reverse(Instructions.begin(), Instructions.end());564
565// Now that we've emitted all of the operand info that fit into 64 bits, emit566// information for those instructions that are left. This is a less dense567// encoding, but we expect the main 64-bit table to handle the majority of568// instructions.569if (!Instructions.empty()) {570// Find the opcode # of inline asm.571O << " switch (MI->getOpcode()) {\n";572O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";573while (!Instructions.empty())574EmitInstructions(Instructions, O, PassSubtarget);575
576O << " }\n";577}578
579O << "}\n";580}
581
582static void583emitRegisterNameString(raw_ostream &O, StringRef AltName,584const std::deque<CodeGenRegister> &Registers) {585SequenceToOffsetTable<std::string> StringTable;586SmallVector<std::string, 4> AsmNames(Registers.size());587unsigned i = 0;588for (const auto &Reg : Registers) {589std::string &AsmName = AsmNames[i++];590
591// "NoRegAltName" is special. We don't need to do a lookup for that,592// as it's just a reference to the default register name.593if (AltName == "" || AltName == "NoRegAltName") {594AsmName = std::string(Reg.TheDef->getValueAsString("AsmName"));595if (AsmName.empty())596AsmName = std::string(Reg.getName());597} else {598// Make sure the register has an alternate name for this index.599std::vector<Record *> AltNameList =600Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");601unsigned Idx = 0, e;602for (e = AltNameList.size();603Idx < e && (AltNameList[Idx]->getName() != AltName); ++Idx)604;605// If the register has an alternate name for this index, use it.606// Otherwise, leave it empty as an error flag.607if (Idx < e) {608std::vector<StringRef> AltNames =609Reg.TheDef->getValueAsListOfStrings("AltNames");610if (AltNames.size() <= Idx)611PrintFatalError(Reg.TheDef->getLoc(),612"Register definition missing alt name for '" +613AltName + "'.");614AsmName = std::string(AltNames[Idx]);615}616}617StringTable.add(AsmName);618}619
620StringTable.layout();621StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") +622AltName + "[]");623
624O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32)625<< " RegAsmOffset" << AltName << "[] = {";626for (unsigned i = 0, e = Registers.size(); i != e; ++i) {627if ((i % 14) == 0)628O << "\n ";629O << StringTable.get(AsmNames[i]) << ", ";630}631O << "\n };\n"632<< "\n";633}
634
635void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {636Record *AsmWriter = Target.getAsmWriter();637StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");638const auto &Registers = Target.getRegBank().getRegisters();639const std::vector<Record *> &AltNameIndices = Target.getRegAltNameIndices();640bool hasAltNames = AltNameIndices.size() > 1;641StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace");642
643O << "\n\n/// getRegisterName - This method is automatically generated by "644"tblgen\n"645"/// from the register set description. This returns the assembler "646"name\n"647"/// for the specified register.\n"648"const char *"649<< Target.getName() << ClassName << "::";650if (hasAltNames)651O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n";652else653O << "getRegisterName(MCRegister Reg) {\n";654O << " unsigned RegNo = Reg.id();\n"655<< " assert(RegNo && RegNo < " << (Registers.size() + 1)656<< " && \"Invalid register number!\");\n"657<< "\n";658
659if (hasAltNames) {660for (const Record *R : AltNameIndices)661emitRegisterNameString(O, R->getName(), Registers);662} else663emitRegisterNameString(O, "", Registers);664
665if (hasAltNames) {666O << " switch(AltIdx) {\n"667<< " default: llvm_unreachable(\"Invalid register alt name index!\");\n";668for (const Record *R : AltNameIndices) {669StringRef AltName = R->getName();670O << " case ";671if (!Namespace.empty())672O << Namespace << "::";673O << AltName << ":\n";674if (R->isValueUnset("FallbackRegAltNameIndex"))675O << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName676<< "[RegNo-1]) &&\n"677<< " \"Invalid alt name index for register!\");\n";678else {679O << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName680<< "[RegNo-1]))\n"681<< " return getRegisterName(RegNo, ";682if (!Namespace.empty())683O << Namespace << "::";684O << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n";685}686O << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName687<< "[RegNo-1];\n";688}689O << " }\n";690} else {691O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"692<< " \"Invalid alt name index for register!\");\n"693<< " return AsmStrs+RegAsmOffset[RegNo-1];\n";694}695O << "}\n";696}
697
698namespace {699
700// IAPrinter - Holds information about an InstAlias. Two InstAliases match if
701// they both have the same conditionals. In which case, we cannot print out the
702// alias for that pattern.
703class IAPrinter {704std::map<StringRef, std::pair<int, int>> OpMap;705
706std::vector<std::string> Conds;707
708std::string Result;709std::string AsmString;710
711unsigned NumMIOps;712
713public:714IAPrinter(std::string R, std::string AS, unsigned NumMIOps)715: Result(std::move(R)), AsmString(std::move(AS)), NumMIOps(NumMIOps) {}716
717void addCond(std::string C) { Conds.push_back(std::move(C)); }718ArrayRef<std::string> getConds() const { return Conds; }719size_t getCondCount() const { return Conds.size(); }720
721void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {722assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");723assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF && "Idx out of range");724OpMap[Op] = std::pair(OpIdx, PrintMethodIdx);725}726
727unsigned getNumMIOps() { return NumMIOps; }728
729StringRef getResult() { return Result; }730
731bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }732int getOpIndex(StringRef Op) { return OpMap[Op].first; }733std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; }734
735std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start,736StringRef::iterator End) {737StringRef::iterator I = Start;738StringRef::iterator Next;739if (*I == '{') {740// ${some_name}741Start = ++I;742while (I != End && *I != '}')743++I;744Next = I;745// eat the final '}'746if (Next != End)747++Next;748} else {749// $name, just eat the usual suspects.750while (I != End && (isAlnum(*I) || *I == '_'))751++I;752Next = I;753}754
755return std::pair(StringRef(Start, I - Start), Next);756}757
758std::string formatAliasString(uint32_t &UnescapedSize) {759// Directly mangle mapped operands into the string. Each operand is760// identified by a '$' sign followed by a byte identifying the number of the761// operand. We add one to the index to avoid zero bytes.762StringRef ASM(AsmString);763std::string OutString;764raw_string_ostream OS(OutString);765for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) {766OS << *I;767++UnescapedSize;768if (*I == '$') {769StringRef Name;770std::tie(Name, I) = parseName(++I, E);771assert(isOpMapped(Name) && "Unmapped operand!");772
773int OpIndex, PrintIndex;774std::tie(OpIndex, PrintIndex) = getOpData(Name);775if (PrintIndex == -1) {776// Can use the default printOperand route.777OS << format("\\x%02X", (unsigned char)OpIndex + 1);778++UnescapedSize;779} else {780// 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand781// number, and which of our pre-detected Methods to call.782OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1);783UnescapedSize += 3;784}785} else {786++I;787}788}789return OutString;790}791
792bool operator==(const IAPrinter &RHS) const {793if (NumMIOps != RHS.NumMIOps)794return false;795if (Conds.size() != RHS.Conds.size())796return false;797
798unsigned Idx = 0;799for (const auto &str : Conds)800if (str != RHS.Conds[Idx++])801return false;802
803return true;804}805};806
807} // end anonymous namespace808
809static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) {810return AsmString.count(' ') + AsmString.count('\t');811}
812
813namespace {814
815struct AliasPriorityComparator {816typedef std::pair<CodeGenInstAlias, int> ValueType;817bool operator()(const ValueType &LHS, const ValueType &RHS) const {818if (LHS.second == RHS.second) {819// We don't actually care about the order, but for consistency it820// shouldn't depend on pointer comparisons.821return LessRecordByID()(LHS.first.TheDef, RHS.first.TheDef);822}823
824// Aliases with larger priorities should be considered first.825return LHS.second > RHS.second;826}827};828
829} // end anonymous namespace830
831void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {832Record *AsmWriter = Target.getAsmWriter();833
834O << "\n#ifdef PRINT_ALIAS_INSTR\n";835O << "#undef PRINT_ALIAS_INSTR\n\n";836
837//////////////////////////////838// Gather information about aliases we need to print839//////////////////////////////840
841// Emit the method that prints the alias instruction.842StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");843unsigned Variant = AsmWriter->getValueAsInt("Variant");844bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");845
846std::vector<Record *> AllInstAliases =847Records.getAllDerivedDefinitions("InstAlias");848
849// Create a map from the qualified name to a list of potential matches.850typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>851AliasWithPriority;852std::map<std::string, AliasWithPriority> AliasMap;853for (Record *R : AllInstAliases) {854int Priority = R->getValueAsInt("EmitPriority");855if (Priority < 1)856continue; // Aliases with priority 0 are never emitted.857
858const DagInit *DI = R->getValueAsDag("ResultInst");859AliasMap[getQualifiedName(DI->getOperatorAsDef(R->getLoc()))].insert(860std::pair(CodeGenInstAlias(R, Target), Priority));861}862
863// A map of which conditions need to be met for each instruction operand864// before it can be matched to the mnemonic.865std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;866
867std::vector<std::pair<std::string, bool>> PrintMethods;868
869// A list of MCOperandPredicates for all operands in use, and the reverse map870std::vector<const Record *> MCOpPredicates;871DenseMap<const Record *, unsigned> MCOpPredicateMap;872
873for (auto &Aliases : AliasMap) {874// Collection of instruction alias rules. May contain ambiguous rules.875std::vector<IAPrinter> IAPs;876
877for (auto &Alias : Aliases.second) {878const CodeGenInstAlias &CGA = Alias.first;879unsigned LastOpNo = CGA.ResultInstOperandIndex.size();880std::string FlatInstAsmString =881CodeGenInstruction::FlattenAsmStringVariants(882CGA.ResultInst->AsmString, Variant);883unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant);884
885std::string FlatAliasAsmString =886CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, Variant);887UnescapeAliasString(FlatAliasAsmString);888
889// Don't emit the alias if it has more operands than what it's aliasing.890if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant))891continue;892
893StringRef Namespace = Target.getName();894unsigned NumMIOps = 0;895for (auto &ResultInstOpnd : CGA.ResultInst->Operands)896NumMIOps += ResultInstOpnd.MINumOperands;897
898IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString, NumMIOps);899
900unsigned MIOpNum = 0;901for (unsigned i = 0, e = LastOpNo; i != e; ++i) {902// Skip over tied operands as they're not part of an alias declaration.903auto &Operands = CGA.ResultInst->Operands;904while (true) {905unsigned OpNum = Operands.getSubOperandNumber(MIOpNum).first;906if (Operands[OpNum].MINumOperands == 1 &&907Operands[OpNum].getTiedRegister() != -1) {908// Tied operands of different RegisterClass should be explicit909// within an instruction's syntax and so cannot be skipped.910int TiedOpNum = Operands[OpNum].getTiedRegister();911if (Operands[OpNum].Rec->getName() ==912Operands[TiedOpNum].Rec->getName()) {913++MIOpNum;914continue;915}916}917break;918}919
920// Ignore unchecked result operands.921while (IAP.getCondCount() < MIOpNum)922IAP.addCond("AliasPatternCond::K_Ignore, 0");923
924const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i];925
926switch (RO.Kind) {927case CodeGenInstAlias::ResultOperand::K_Record: {928const Record *Rec = RO.getRecord();929StringRef ROName = RO.getName();930int PrintMethodIdx = -1;931
932// These two may have a PrintMethod, which we want to record (if it's933// the first time we've seen it) and provide an index for the aliasing934// code to use.935if (Rec->isSubClassOf("RegisterOperand") ||936Rec->isSubClassOf("Operand")) {937StringRef PrintMethod = Rec->getValueAsString("PrintMethod");938bool IsPCRel =939Rec->getValueAsString("OperandType") == "OPERAND_PCREL";940if (PrintMethod != "" && PrintMethod != "printOperand") {941PrintMethodIdx = llvm::find_if(PrintMethods,942[&](auto &X) {943return X.first == PrintMethod;944}) -945PrintMethods.begin();946if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size())947PrintMethods.emplace_back(std::string(PrintMethod), IsPCRel);948}949}950
951if (Rec->isSubClassOf("RegisterOperand"))952Rec = Rec->getValueAsDef("RegClass");953if (Rec->isSubClassOf("RegisterClass")) {954if (!IAP.isOpMapped(ROName)) {955IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);956Record *R = CGA.ResultOperands[i].getRecord();957if (R->isSubClassOf("RegisterOperand"))958R = R->getValueAsDef("RegClass");959IAP.addCond(std::string(960formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID",961Namespace, R->getName())));962} else {963IAP.addCond(std::string(formatv(964"AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName))));965}966} else {967// Assume all printable operands are desired for now. This can be968// overridden in the InstAlias instantiation if necessary.969IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);970
971// There might be an additional predicate on the MCOperand972unsigned Entry = MCOpPredicateMap[Rec];973if (!Entry) {974if (!Rec->isValueUnset("MCOperandPredicate")) {975MCOpPredicates.push_back(Rec);976Entry = MCOpPredicates.size();977MCOpPredicateMap[Rec] = Entry;978} else979break; // No conditions on this operand at all980}981IAP.addCond(982std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry)));983}984break;985}986case CodeGenInstAlias::ResultOperand::K_Imm: {987// Just because the alias has an immediate result, doesn't mean the988// MCInst will. An MCExpr could be present, for example.989auto Imm = CGA.ResultOperands[i].getImm();990int32_t Imm32 = int32_t(Imm);991if (Imm != Imm32)992PrintFatalError("Matching an alias with an immediate out of the "993"range of int32_t is not supported");994IAP.addCond(std::string(995formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32)));996break;997}998case CodeGenInstAlias::ResultOperand::K_Reg:999if (!CGA.ResultOperands[i].getRegister()) {1000IAP.addCond(std::string(formatv(1001"AliasPatternCond::K_Reg, {0}::NoRegister", Namespace)));1002break;1003}1004
1005StringRef Reg = CGA.ResultOperands[i].getRegister()->getName();1006IAP.addCond(std::string(1007formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg)));1008break;1009}1010
1011MIOpNum += RO.getMINumOperands();1012}1013
1014std::vector<Record *> ReqFeatures;1015if (PassSubtarget) {1016// We only consider ReqFeatures predicates if PassSubtarget1017std::vector<Record *> RF =1018CGA.TheDef->getValueAsListOfDefs("Predicates");1019copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {1020return R->getValueAsBit("AssemblerMatcherPredicate");1021});1022}1023
1024for (Record *const R : ReqFeatures) {1025const DagInit *D = R->getValueAsDag("AssemblerCondDag");1026auto *Op = dyn_cast<DefInit>(D->getOperator());1027if (!Op)1028PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1029StringRef CombineType = Op->getDef()->getName();1030if (CombineType != "any_of" && CombineType != "all_of")1031PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1032if (D->getNumArgs() == 0)1033PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1034bool IsOr = CombineType == "any_of";1035// Change (any_of FeatureAll, (any_of ...)) to (any_of FeatureAll, ...).1036if (IsOr && D->getNumArgs() == 2 && isa<DagInit>(D->getArg(1))) {1037DagInit *RHS = cast<DagInit>(D->getArg(1));1038SmallVector<Init *> Args{D->getArg(0)};1039SmallVector<StringInit *> ArgNames{D->getArgName(0)};1040for (unsigned i = 0, e = RHS->getNumArgs(); i != e; ++i) {1041Args.push_back(RHS->getArg(i));1042ArgNames.push_back(RHS->getArgName(i));1043}1044D = DagInit::get(D->getOperator(), nullptr, Args, ArgNames);1045}1046
1047for (auto *Arg : D->getArgs()) {1048bool IsNeg = false;1049if (auto *NotArg = dyn_cast<DagInit>(Arg)) {1050if (NotArg->getOperator()->getAsString() != "not" ||1051NotArg->getNumArgs() != 1)1052PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1053Arg = NotArg->getArg(0);1054IsNeg = true;1055}1056if (!isa<DefInit>(Arg) ||1057!cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))1058PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1059
1060IAP.addCond(std::string(formatv(1061"AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "",1062IsNeg ? "Neg" : "", Namespace, Arg->getAsString())));1063}1064// If an AssemblerPredicate with ors is used, note end of list should1065// these be combined.1066if (IsOr)1067IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0");1068}1069
1070IAPrinterMap[Aliases.first].push_back(std::move(IAP));1071}1072}1073
1074//////////////////////////////1075// Write out the printAliasInstr function1076//////////////////////////////1077
1078std::string Header;1079raw_string_ostream HeaderO(Header);1080
1081HeaderO << "bool " << Target.getName() << ClassName1082<< "::printAliasInstr(const MCInst"1083<< " *MI, uint64_t Address, "1084<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")1085<< "raw_ostream &OS) {\n";1086
1087std::string PatternsForOpcode;1088raw_string_ostream OpcodeO(PatternsForOpcode);1089
1090unsigned PatternCount = 0;1091std::string Patterns;1092raw_string_ostream PatternO(Patterns);1093
1094unsigned CondCount = 0;1095std::string Conds;1096raw_string_ostream CondO(Conds);1097
1098// All flattened alias strings.1099std::map<std::string, uint32_t> AsmStringOffsets;1100std::vector<std::pair<uint32_t, std::string>> AsmStrings;1101size_t AsmStringsSize = 0;1102
1103// Iterate over the opcodes in enum order so they are sorted by opcode for1104// binary search.1105for (const CodeGenInstruction *Inst : NumberedInstructions) {1106auto It = IAPrinterMap.find(getQualifiedName(Inst->TheDef));1107if (It == IAPrinterMap.end())1108continue;1109std::vector<IAPrinter> &IAPs = It->second;1110std::vector<IAPrinter *> UniqueIAPs;1111
1112// Remove any ambiguous alias rules.1113for (auto &LHS : IAPs) {1114bool IsDup = false;1115for (const auto &RHS : IAPs) {1116if (&LHS != &RHS && LHS == RHS) {1117IsDup = true;1118break;1119}1120}1121
1122if (!IsDup)1123UniqueIAPs.push_back(&LHS);1124}1125
1126if (UniqueIAPs.empty())1127continue;1128
1129unsigned PatternStart = PatternCount;1130
1131// Insert the pattern start and opcode in the pattern list for debugging.1132PatternO << formatv(" // {0} - {1}\n", It->first, PatternStart);1133
1134for (IAPrinter *IAP : UniqueIAPs) {1135// Start each condition list with a comment of the resulting pattern that1136// we're trying to match.1137unsigned CondStart = CondCount;1138CondO << formatv(" // {0} - {1}\n", IAP->getResult(), CondStart);1139for (const auto &Cond : IAP->getConds())1140CondO << " {" << Cond << "},\n";1141CondCount += IAP->getCondCount();1142
1143// After operands have been examined, re-encode the alias string with1144// escapes indicating how operands should be printed.1145uint32_t UnescapedSize = 0;1146std::string EncodedAsmString = IAP->formatAliasString(UnescapedSize);1147auto Insertion =1148AsmStringOffsets.insert({EncodedAsmString, AsmStringsSize});1149if (Insertion.second) {1150// If the string is new, add it to the vector.1151AsmStrings.push_back({AsmStringsSize, EncodedAsmString});1152AsmStringsSize += UnescapedSize + 1;1153}1154unsigned AsmStrOffset = Insertion.first->second;1155
1156PatternO << formatv(" {{{0}, {1}, {2}, {3} },\n", AsmStrOffset,1157CondStart, IAP->getNumMIOps(), IAP->getCondCount());1158++PatternCount;1159}1160
1161OpcodeO << formatv(" {{{0}, {1}, {2} },\n", It->first, PatternStart,1162PatternCount - PatternStart);1163}1164
1165if (PatternsForOpcode.empty()) {1166O << Header;1167O << " return false;\n";1168O << "}\n\n";1169O << "#endif // PRINT_ALIAS_INSTR\n";1170return;1171}1172
1173// Forward declare the validation method if needed.1174if (!MCOpPredicates.empty())1175O << "static bool " << Target.getName() << ClassName1176<< "ValidateMCOperand(const MCOperand &MCOp,\n"1177<< " const MCSubtargetInfo &STI,\n"1178<< " unsigned PredicateIndex);\n";1179
1180O << Header;1181O.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n";1182O << PatternsForOpcode;1183O.indent(2) << "};\n\n";1184O.indent(2) << "static const AliasPattern Patterns[] = {\n";1185O << Patterns;1186O.indent(2) << "};\n\n";1187O.indent(2) << "static const AliasPatternCond Conds[] = {\n";1188O << Conds;1189O.indent(2) << "};\n\n";1190O.indent(2) << "static const char AsmStrings[] =\n";1191for (const auto &P : AsmStrings) {1192O.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n";1193}1194
1195O.indent(2) << ";\n\n";1196
1197// Assert that the opcode table is sorted. Use a static local constructor to1198// ensure that the check only happens once on first run.1199O << "#ifndef NDEBUG\n";1200O.indent(2) << "static struct SortCheck {\n";1201O.indent(2) << " SortCheck(ArrayRef<PatternsForOpcode> OpToPatterns) {\n";1202O.indent(2) << " assert(std::is_sorted(\n";1203O.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n";1204O.indent(2) << " [](const PatternsForOpcode &L, const "1205"PatternsForOpcode &R) {\n";1206O.indent(2) << " return L.Opcode < R.Opcode;\n";1207O.indent(2) << " }) &&\n";1208O.indent(2) << " \"tablegen failed to sort opcode patterns\");\n";1209O.indent(2) << " }\n";1210O.indent(2) << "} sortCheckVar(OpToPatterns);\n";1211O << "#endif\n\n";1212
1213O.indent(2) << "AliasMatchingData M {\n";1214O.indent(2) << " ArrayRef(OpToPatterns),\n";1215O.indent(2) << " ArrayRef(Patterns),\n";1216O.indent(2) << " ArrayRef(Conds),\n";1217O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n";1218if (MCOpPredicates.empty())1219O.indent(2) << " nullptr,\n";1220else1221O.indent(2) << " &" << Target.getName() << ClassName1222<< "ValidateMCOperand,\n";1223O.indent(2) << "};\n";1224
1225O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, "1226<< (PassSubtarget ? "&STI" : "nullptr") << ", M);\n";1227O.indent(2) << "if (!AsmString) return false;\n\n";1228
1229// Code that prints the alias, replacing the operands with the ones from the1230// MCInst.1231O << " unsigned I = 0;\n";1232O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n";1233O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n";1234O << " ++I;\n";1235O << " OS << '\\t' << StringRef(AsmString, I);\n";1236
1237O << " if (AsmString[I] != '\\0') {\n";1238O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n";1239O << " OS << '\\t';\n";1240O << " ++I;\n";1241O << " }\n";1242O << " do {\n";1243O << " if (AsmString[I] == '$') {\n";1244O << " ++I;\n";1245O << " if (AsmString[I] == (char)0xff) {\n";1246O << " ++I;\n";1247O << " int OpIdx = AsmString[I++] - 1;\n";1248O << " int PrintMethodIdx = AsmString[I++] - 1;\n";1249O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, ";1250O << (PassSubtarget ? "STI, " : "");1251O << "OS);\n";1252O << " } else\n";1253O << " printOperand(MI, unsigned(AsmString[I++]) - 1, ";1254O << (PassSubtarget ? "STI, " : "");1255O << "OS);\n";1256O << " } else {\n";1257O << " OS << AsmString[I++];\n";1258O << " }\n";1259O << " } while (AsmString[I] != '\\0');\n";1260O << " }\n\n";1261
1262O << " return true;\n";1263O << "}\n\n";1264
1265//////////////////////////////1266// Write out the printCustomAliasOperand function1267//////////////////////////////1268
1269O << "void " << Target.getName() << ClassName << "::"1270<< "printCustomAliasOperand(\n"1271<< " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n"1272<< " unsigned PrintMethodIdx,\n"1273<< (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "")1274<< " raw_ostream &OS) {\n";1275if (PrintMethods.empty())1276O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n";1277else {1278O << " switch (PrintMethodIdx) {\n"1279<< " default:\n"1280<< " llvm_unreachable(\"Unknown PrintMethod kind\");\n"1281<< " break;\n";1282
1283for (unsigned i = 0; i < PrintMethods.size(); ++i) {1284O << " case " << i << ":\n"1285<< " " << PrintMethods[i].first << "(MI, "1286<< (PrintMethods[i].second ? "Address, " : "") << "OpIdx, "1287<< (PassSubtarget ? "STI, " : "") << "OS);\n"1288<< " break;\n";1289}1290O << " }\n";1291}1292O << "}\n\n";1293
1294if (!MCOpPredicates.empty()) {1295O << "static bool " << Target.getName() << ClassName1296<< "ValidateMCOperand(const MCOperand &MCOp,\n"1297<< " const MCSubtargetInfo &STI,\n"1298<< " unsigned PredicateIndex) {\n"1299<< " switch (PredicateIndex) {\n"1300<< " default:\n"1301<< " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"1302<< " break;\n";1303
1304for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {1305StringRef MCOpPred =1306MCOpPredicates[i]->getValueAsString("MCOperandPredicate");1307O << " case " << i + 1 << ": {\n"1308<< MCOpPred.data() << "\n"1309<< " }\n";1310}1311O << " }\n"1312<< "}\n\n";1313}1314
1315O << "#endif // PRINT_ALIAS_INSTR\n";1316}
1317
1318AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {1319Record *AsmWriter = Target.getAsmWriter();1320unsigned Variant = AsmWriter->getValueAsInt("Variant");1321
1322// Get the instruction numbering.1323NumberedInstructions = Target.getInstructionsByEnumValue();1324
1325for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {1326const CodeGenInstruction *I = NumberedInstructions[i];1327if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")1328Instructions.emplace_back(*I, i, Variant);1329}1330}
1331
1332void AsmWriterEmitter::run(raw_ostream &O) {1333std::vector<std::vector<std::string>> TableDrivenOperandPrinters;1334unsigned BitsLeft = 0;1335unsigned AsmStrBits = 0;1336emitSourceFileHeader("Assembly Writer Source Fragment", O, Records);1337EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);1338EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);1339EmitGetRegisterName(O);1340EmitPrintAliasInstruction(O);1341}
1342
1343static TableGen::Emitter::OptClass<AsmWriterEmitter>1344X("gen-asm-writer", "Generate assembly writer");1345