Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/AsmWriterEmitter.cpp
35258 views
//===- AsmWriterEmitter.cpp - Generate an assembly writer -----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits an assembly printer for the current target.9// Note that this is currently fairly skeletal, but will grow over time.10//11//===----------------------------------------------------------------------===//1213#include "Basic/SequenceToOffsetTable.h"14#include "Common/AsmWriterInst.h"15#include "Common/CodeGenInstAlias.h"16#include "Common/CodeGenInstruction.h"17#include "Common/CodeGenRegisters.h"18#include "Common/CodeGenTarget.h"19#include "Common/Types.h"20#include "llvm/ADT/ArrayRef.h"21#include "llvm/ADT/DenseMap.h"22#include "llvm/ADT/STLExtras.h"23#include "llvm/ADT/SmallString.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/StringExtras.h"26#include "llvm/ADT/StringRef.h"27#include "llvm/ADT/Twine.h"28#include "llvm/Support/Casting.h"29#include "llvm/Support/Debug.h"30#include "llvm/Support/Format.h"31#include "llvm/Support/FormatVariadic.h"32#include "llvm/Support/MathExtras.h"33#include "llvm/Support/raw_ostream.h"34#include "llvm/TableGen/Error.h"35#include "llvm/TableGen/Record.h"36#include "llvm/TableGen/TableGenBackend.h"37#include <algorithm>38#include <cassert>39#include <cstddef>40#include <cstdint>41#include <deque>42#include <iterator>43#include <map>44#include <set>45#include <string>46#include <tuple>47#include <utility>48#include <vector>4950using namespace llvm;5152#define DEBUG_TYPE "asm-writer-emitter"5354namespace {5556class AsmWriterEmitter {57RecordKeeper &Records;58CodeGenTarget Target;59ArrayRef<const CodeGenInstruction *> NumberedInstructions;60std::vector<AsmWriterInst> Instructions;6162public:63AsmWriterEmitter(RecordKeeper &R);6465void run(raw_ostream &o);6667private:68void EmitGetMnemonic(69raw_ostream &o,70std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,71unsigned &BitsLeft, unsigned &AsmStrBits);72void EmitPrintInstruction(73raw_ostream &o,74std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,75unsigned &BitsLeft, unsigned &AsmStrBits);76void EmitGetRegisterName(raw_ostream &o);77void EmitPrintAliasInstruction(raw_ostream &O);7879void FindUniqueOperandCommands(std::vector<std::string> &UOC,80std::vector<std::vector<unsigned>> &InstIdxs,81std::vector<unsigned> &InstOpsUsed,82bool PassSubtarget) const;83};8485} // end anonymous namespace8687static void88PrintCases(std::vector<std::pair<std::string, AsmWriterOperand>> &OpsToPrint,89raw_ostream &O, bool PassSubtarget) {90O << " case " << OpsToPrint.back().first << ":";91AsmWriterOperand TheOp = OpsToPrint.back().second;92OpsToPrint.pop_back();9394// Check to see if any other operands are identical in this list, and if so,95// emit a case label for them.96for (unsigned i = OpsToPrint.size(); i != 0; --i)97if (OpsToPrint[i - 1].second == TheOp) {98O << "\n case " << OpsToPrint[i - 1].first << ":";99OpsToPrint.erase(OpsToPrint.begin() + i - 1);100}101102// Finally, emit the code.103O << "\n " << TheOp.getCode(PassSubtarget);104O << "\n break;\n";105}106107/// EmitInstructions - Emit the last instruction in the vector and any other108/// instructions that are suitably similar to it.109static void EmitInstructions(std::vector<AsmWriterInst> &Insts, raw_ostream &O,110bool PassSubtarget) {111AsmWriterInst FirstInst = Insts.back();112Insts.pop_back();113114std::vector<AsmWriterInst> SimilarInsts;115unsigned DifferingOperand = ~0;116for (unsigned i = Insts.size(); i != 0; --i) {117unsigned DiffOp = Insts[i - 1].MatchesAllButOneOp(FirstInst);118if (DiffOp != ~1U) {119if (DifferingOperand == ~0U) // First match!120DifferingOperand = DiffOp;121122// If this differs in the same operand as the rest of the instructions in123// this class, move it to the SimilarInsts list.124if (DifferingOperand == DiffOp || DiffOp == ~0U) {125SimilarInsts.push_back(Insts[i - 1]);126Insts.erase(Insts.begin() + i - 1);127}128}129}130131O << " case " << FirstInst.CGI->Namespace132<< "::" << FirstInst.CGI->TheDef->getName() << ":\n";133for (const AsmWriterInst &AWI : SimilarInsts)134O << " case " << AWI.CGI->Namespace << "::" << AWI.CGI->TheDef->getName()135<< ":\n";136for (unsigned i = 0, e = FirstInst.Operands.size(); i != e; ++i) {137if (i != DifferingOperand) {138// If the operand is the same for all instructions, just print it.139O << " " << FirstInst.Operands[i].getCode(PassSubtarget);140} else {141// If this is the operand that varies between all of the instructions,142// emit a switch for just this operand now.143O << " switch (MI->getOpcode()) {\n";144O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";145std::vector<std::pair<std::string, AsmWriterOperand>> OpsToPrint;146OpsToPrint.push_back(std::pair(FirstInst.CGI->Namespace.str() + "::" +147FirstInst.CGI->TheDef->getName().str(),148FirstInst.Operands[i]));149150for (const AsmWriterInst &AWI : SimilarInsts) {151OpsToPrint.push_back(std::pair(152AWI.CGI->Namespace.str() + "::" + AWI.CGI->TheDef->getName().str(),153AWI.Operands[i]));154}155std::reverse(OpsToPrint.begin(), OpsToPrint.end());156while (!OpsToPrint.empty())157PrintCases(OpsToPrint, O, PassSubtarget);158O << " }";159}160O << "\n";161}162O << " break;\n";163}164165void AsmWriterEmitter::FindUniqueOperandCommands(166std::vector<std::string> &UniqueOperandCommands,167std::vector<std::vector<unsigned>> &InstIdxs,168std::vector<unsigned> &InstOpsUsed, bool PassSubtarget) const {169// This vector parallels UniqueOperandCommands, keeping track of which170// instructions each case are used for. It is a comma separated string of171// enums.172std::vector<std::string> InstrsForCase;173InstrsForCase.resize(UniqueOperandCommands.size());174InstOpsUsed.assign(UniqueOperandCommands.size(), 0);175176for (size_t i = 0, e = Instructions.size(); i != e; ++i) {177const AsmWriterInst &Inst = Instructions[i];178if (Inst.Operands.empty())179continue; // Instruction already done.180181std::string Command =182" " + Inst.Operands[0].getCode(PassSubtarget) + "\n";183184// Check to see if we already have 'Command' in UniqueOperandCommands.185// If not, add it.186auto I = llvm::find(UniqueOperandCommands, Command);187if (I != UniqueOperandCommands.end()) {188size_t idx = I - UniqueOperandCommands.begin();189InstrsForCase[idx] += ", ";190InstrsForCase[idx] += Inst.CGI->TheDef->getName();191InstIdxs[idx].push_back(i);192} else {193UniqueOperandCommands.push_back(std::move(Command));194InstrsForCase.push_back(std::string(Inst.CGI->TheDef->getName()));195InstIdxs.emplace_back();196InstIdxs.back().push_back(i);197198// This command matches one operand so far.199InstOpsUsed.push_back(1);200}201}202203// For each entry of UniqueOperandCommands, there is a set of instructions204// that uses it. If the next command of all instructions in the set are205// identical, fold it into the command.206for (size_t CommandIdx = 0, e = UniqueOperandCommands.size(); CommandIdx != e;207++CommandIdx) {208209const auto &Idxs = InstIdxs[CommandIdx];210211for (unsigned Op = 1;; ++Op) {212// Find the first instruction in the set.213const AsmWriterInst &FirstInst = Instructions[Idxs.front()];214// If this instruction has no more operands, we isn't anything to merge215// into this command.216if (FirstInst.Operands.size() == Op)217break;218219// Otherwise, scan to see if all of the other instructions in this command220// set share the operand.221if (any_of(drop_begin(Idxs), [&](unsigned Idx) {222const AsmWriterInst &OtherInst = Instructions[Idx];223return OtherInst.Operands.size() == Op ||224OtherInst.Operands[Op] != FirstInst.Operands[Op];225}))226break;227228// Okay, everything in this command set has the same next operand. Add it229// to UniqueOperandCommands and remember that it was consumed.230std::string Command =231" " + FirstInst.Operands[Op].getCode(PassSubtarget) + "\n";232233UniqueOperandCommands[CommandIdx] += Command;234InstOpsUsed[CommandIdx]++;235}236}237238// Prepend some of the instructions each case is used for onto the case val.239for (unsigned i = 0, e = InstrsForCase.size(); i != e; ++i) {240std::string Instrs = InstrsForCase[i];241if (Instrs.size() > 70) {242Instrs.erase(Instrs.begin() + 70, Instrs.end());243Instrs += "...";244}245246if (!Instrs.empty())247UniqueOperandCommands[i] =248" // " + Instrs + "\n" + UniqueOperandCommands[i];249}250}251252static void UnescapeString(std::string &Str) {253for (unsigned i = 0; i != Str.size(); ++i) {254if (Str[i] == '\\' && i != Str.size() - 1) {255switch (Str[i + 1]) {256default:257continue; // Don't execute the code after the switch.258case 'a':259Str[i] = '\a';260break;261case 'b':262Str[i] = '\b';263break;264case 'e':265Str[i] = 27;266break;267case 'f':268Str[i] = '\f';269break;270case 'n':271Str[i] = '\n';272break;273case 'r':274Str[i] = '\r';275break;276case 't':277Str[i] = '\t';278break;279case 'v':280Str[i] = '\v';281break;282case '"':283Str[i] = '\"';284break;285case '\'':286Str[i] = '\'';287break;288case '\\':289Str[i] = '\\';290break;291}292// Nuke the second character.293Str.erase(Str.begin() + i + 1);294}295}296}297298/// UnescapeAliasString - Supports literal braces in InstAlias asm string which299/// are escaped with '\\' to avoid being interpreted as variants. Braces must300/// be unescaped before c++ code is generated as (e.g.):301///302/// AsmString = "foo \{$\x01\}";303///304/// causes non-standard escape character warnings.305static void UnescapeAliasString(std::string &Str) {306for (unsigned i = 0; i != Str.size(); ++i) {307if (Str[i] == '\\' && i != Str.size() - 1) {308switch (Str[i + 1]) {309default:310continue; // Don't execute the code after the switch.311case '{':312Str[i] = '{';313break;314case '}':315Str[i] = '}';316break;317}318// Nuke the second character.319Str.erase(Str.begin() + i + 1);320}321}322}323324void AsmWriterEmitter::EmitGetMnemonic(325raw_ostream &O,326std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,327unsigned &BitsLeft, unsigned &AsmStrBits) {328Record *AsmWriter = Target.getAsmWriter();329StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");330bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");331332O << "/// getMnemonic - This method is automatically generated by "333"tablegen\n"334"/// from the instruction set description.\n"335"std::pair<const char *, uint64_t> "336<< Target.getName() << ClassName << "::getMnemonic(const MCInst *MI) {\n";337338// Build an aggregate string, and build a table of offsets into it.339SequenceToOffsetTable<std::string> StringTable;340341/// OpcodeInfo - This encodes the index of the string to use for the first342/// chunk of the output as well as indices used for operand printing.343std::vector<uint64_t> OpcodeInfo(NumberedInstructions.size());344const unsigned OpcodeInfoBits = 64;345346// Add all strings to the string table upfront so it can generate an optimized347// representation.348for (AsmWriterInst &AWI : Instructions) {349if (AWI.Operands[0].OperandType == AsmWriterOperand::isLiteralTextOperand &&350!AWI.Operands[0].Str.empty()) {351std::string Str = AWI.Operands[0].Str;352UnescapeString(Str);353StringTable.add(Str);354}355}356357StringTable.layout();358359unsigned MaxStringIdx = 0;360for (AsmWriterInst &AWI : Instructions) {361unsigned Idx;362if (AWI.Operands[0].OperandType != AsmWriterOperand::isLiteralTextOperand ||363AWI.Operands[0].Str.empty()) {364// Something handled by the asmwriter printer, but with no leading string.365Idx = StringTable.get("");366} else {367std::string Str = AWI.Operands[0].Str;368UnescapeString(Str);369Idx = StringTable.get(Str);370MaxStringIdx = std::max(MaxStringIdx, Idx);371372// Nuke the string from the operand list. It is now handled!373AWI.Operands.erase(AWI.Operands.begin());374}375376// Bias offset by one since we want 0 as a sentinel.377OpcodeInfo[AWI.CGIIndex] = Idx + 1;378}379380// Figure out how many bits we used for the string index.381AsmStrBits = Log2_32_Ceil(MaxStringIdx + 2);382383// To reduce code size, we compactify common instructions into a few bits384// in the opcode-indexed table.385BitsLeft = OpcodeInfoBits - AsmStrBits;386387while (true) {388std::vector<std::string> UniqueOperandCommands;389std::vector<std::vector<unsigned>> InstIdxs;390std::vector<unsigned> NumInstOpsHandled;391FindUniqueOperandCommands(UniqueOperandCommands, InstIdxs,392NumInstOpsHandled, PassSubtarget);393394// If we ran out of operands to print, we're done.395if (UniqueOperandCommands.empty())396break;397398// Compute the number of bits we need to represent these cases, this is399// ceil(log2(numentries)).400unsigned NumBits = Log2_32_Ceil(UniqueOperandCommands.size());401402// If we don't have enough bits for this operand, don't include it.403if (NumBits > BitsLeft) {404LLVM_DEBUG(errs() << "Not enough bits to densely encode " << NumBits405<< " more bits\n");406break;407}408409// Otherwise, we can include this in the initial lookup table. Add it in.410for (size_t i = 0, e = InstIdxs.size(); i != e; ++i) {411unsigned NumOps = NumInstOpsHandled[i];412for (unsigned Idx : InstIdxs[i]) {413OpcodeInfo[Instructions[Idx].CGIIndex] |=414(uint64_t)i << (OpcodeInfoBits - BitsLeft);415// Remove the info about this operand from the instruction.416AsmWriterInst &Inst = Instructions[Idx];417if (!Inst.Operands.empty()) {418assert(NumOps <= Inst.Operands.size() &&419"Can't remove this many ops!");420Inst.Operands.erase(Inst.Operands.begin(),421Inst.Operands.begin() + NumOps);422}423}424}425BitsLeft -= NumBits;426427// Remember the handlers for this set of operands.428TableDrivenOperandPrinters.push_back(std::move(UniqueOperandCommands));429}430431// Emit the string table itself.432StringTable.emitStringLiteralDef(O, " static const char AsmStrs[]");433434// Emit the lookup tables in pieces to minimize wasted bytes.435unsigned BytesNeeded = ((OpcodeInfoBits - BitsLeft) + 7) / 8;436unsigned Table = 0, Shift = 0;437SmallString<128> BitsString;438raw_svector_ostream BitsOS(BitsString);439// If the total bits is more than 32-bits we need to use a 64-bit type.440BitsOS << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)441<< "_t Bits = 0;\n";442while (BytesNeeded != 0) {443// Figure out how big this table section needs to be, but no bigger than 4.444unsigned TableSize = std::min(llvm::bit_floor(BytesNeeded), 4u);445BytesNeeded -= TableSize;446TableSize *= 8; // Convert to bits;447uint64_t Mask = (1ULL << TableSize) - 1;448O << " static const uint" << TableSize << "_t OpInfo" << Table449<< "[] = {\n";450for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {451O << " " << ((OpcodeInfo[i] >> Shift) & Mask) << "U,\t// "452<< NumberedInstructions[i]->TheDef->getName() << "\n";453}454O << " };\n\n";455// Emit string to combine the individual table lookups.456BitsOS << " Bits |= ";457// If the total bits is more than 32-bits we need to use a 64-bit type.458if (BitsLeft < (OpcodeInfoBits - 32))459BitsOS << "(uint64_t)";460BitsOS << "OpInfo" << Table << "[MI->getOpcode()] << " << Shift << ";\n";461// Prepare the shift for the next iteration and increment the table count.462Shift += TableSize;463++Table;464}465466O << " // Emit the opcode for the instruction.\n";467O << BitsString;468469// Make sure we don't return an invalid pointer if bits is 0470O << " if (Bits == 0)\n"471" return {nullptr, Bits};\n";472473// Return mnemonic string and bits.474O << " return {AsmStrs+(Bits & " << (1 << AsmStrBits) - 1475<< ")-1, Bits};\n\n";476477O << "}\n";478}479480/// EmitPrintInstruction - Generate the code for the "printInstruction" method481/// implementation. Destroys all instances of AsmWriterInst information, by482/// clearing the Instructions vector.483void AsmWriterEmitter::EmitPrintInstruction(484raw_ostream &O,485std::vector<std::vector<std::string>> &TableDrivenOperandPrinters,486unsigned &BitsLeft, unsigned &AsmStrBits) {487const unsigned OpcodeInfoBits = 64;488Record *AsmWriter = Target.getAsmWriter();489StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");490bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");491492// This function has some huge switch statements that causing excessive493// compile time in LLVM profile instrumenation build. This print function494// usually is not frequently called in compilation. Here we disable the495// profile instrumenation for this function.496O << "/// printInstruction - This method is automatically generated by "497"tablegen\n"498"/// from the instruction set description.\n"499"LLVM_NO_PROFILE_INSTRUMENT_FUNCTION\n"500"void "501<< Target.getName() << ClassName502<< "::printInstruction(const MCInst *MI, uint64_t Address, "503<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")504<< "raw_ostream &O) {\n";505506// Emit the initial tab character.507O << " O << \"\\t\";\n\n";508509// Emit the starting string.510O << " auto MnemonicInfo = getMnemonic(MI);\n\n";511O << " O << MnemonicInfo.first;\n\n";512513O << " uint" << ((BitsLeft < (OpcodeInfoBits - 32)) ? 64 : 32)514<< "_t Bits = MnemonicInfo.second;\n"515<< " assert(Bits != 0 && \"Cannot print this instruction.\");\n";516517// Output the table driven operand information.518BitsLeft = OpcodeInfoBits - AsmStrBits;519for (unsigned i = 0, e = TableDrivenOperandPrinters.size(); i != e; ++i) {520std::vector<std::string> &Commands = TableDrivenOperandPrinters[i];521522// Compute the number of bits we need to represent these cases, this is523// ceil(log2(numentries)).524unsigned NumBits = Log2_32_Ceil(Commands.size());525assert(NumBits <= BitsLeft && "consistency error");526527// Emit code to extract this field from Bits.528O << "\n // Fragment " << i << " encoded into " << NumBits << " bits for "529<< Commands.size() << " unique commands.\n";530531if (Commands.size() == 2) {532// Emit two possibilitys with if/else.533O << " if ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "534<< ((1 << NumBits) - 1) << ") {\n"535<< Commands[1] << " } else {\n"536<< Commands[0] << " }\n\n";537} else if (Commands.size() == 1) {538// Emit a single possibility.539O << Commands[0] << "\n\n";540} else {541O << " switch ((Bits >> " << (OpcodeInfoBits - BitsLeft) << ") & "542<< ((1 << NumBits) - 1) << ") {\n"543<< " default: llvm_unreachable(\"Invalid command number.\");\n";544545// Print out all the cases.546for (unsigned j = 0, e = Commands.size(); j != e; ++j) {547O << " case " << j << ":\n";548O << Commands[j];549O << " break;\n";550}551O << " }\n\n";552}553BitsLeft -= NumBits;554}555556// Okay, delete instructions with no operand info left.557llvm::erase_if(Instructions,558[](AsmWriterInst &Inst) { return Inst.Operands.empty(); });559560// Because this is a vector, we want to emit from the end. Reverse all of the561// elements in the vector.562std::reverse(Instructions.begin(), Instructions.end());563564// Now that we've emitted all of the operand info that fit into 64 bits, emit565// information for those instructions that are left. This is a less dense566// encoding, but we expect the main 64-bit table to handle the majority of567// instructions.568if (!Instructions.empty()) {569// Find the opcode # of inline asm.570O << " switch (MI->getOpcode()) {\n";571O << " default: llvm_unreachable(\"Unexpected opcode.\");\n";572while (!Instructions.empty())573EmitInstructions(Instructions, O, PassSubtarget);574575O << " }\n";576}577578O << "}\n";579}580581static void582emitRegisterNameString(raw_ostream &O, StringRef AltName,583const std::deque<CodeGenRegister> &Registers) {584SequenceToOffsetTable<std::string> StringTable;585SmallVector<std::string, 4> AsmNames(Registers.size());586unsigned i = 0;587for (const auto &Reg : Registers) {588std::string &AsmName = AsmNames[i++];589590// "NoRegAltName" is special. We don't need to do a lookup for that,591// as it's just a reference to the default register name.592if (AltName == "" || AltName == "NoRegAltName") {593AsmName = std::string(Reg.TheDef->getValueAsString("AsmName"));594if (AsmName.empty())595AsmName = std::string(Reg.getName());596} else {597// Make sure the register has an alternate name for this index.598std::vector<Record *> AltNameList =599Reg.TheDef->getValueAsListOfDefs("RegAltNameIndices");600unsigned Idx = 0, e;601for (e = AltNameList.size();602Idx < e && (AltNameList[Idx]->getName() != AltName); ++Idx)603;604// If the register has an alternate name for this index, use it.605// Otherwise, leave it empty as an error flag.606if (Idx < e) {607std::vector<StringRef> AltNames =608Reg.TheDef->getValueAsListOfStrings("AltNames");609if (AltNames.size() <= Idx)610PrintFatalError(Reg.TheDef->getLoc(),611"Register definition missing alt name for '" +612AltName + "'.");613AsmName = std::string(AltNames[Idx]);614}615}616StringTable.add(AsmName);617}618619StringTable.layout();620StringTable.emitStringLiteralDef(O, Twine(" static const char AsmStrs") +621AltName + "[]");622623O << " static const " << getMinimalTypeForRange(StringTable.size() - 1, 32)624<< " RegAsmOffset" << AltName << "[] = {";625for (unsigned i = 0, e = Registers.size(); i != e; ++i) {626if ((i % 14) == 0)627O << "\n ";628O << StringTable.get(AsmNames[i]) << ", ";629}630O << "\n };\n"631<< "\n";632}633634void AsmWriterEmitter::EmitGetRegisterName(raw_ostream &O) {635Record *AsmWriter = Target.getAsmWriter();636StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");637const auto &Registers = Target.getRegBank().getRegisters();638const std::vector<Record *> &AltNameIndices = Target.getRegAltNameIndices();639bool hasAltNames = AltNameIndices.size() > 1;640StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace");641642O << "\n\n/// getRegisterName - This method is automatically generated by "643"tblgen\n"644"/// from the register set description. This returns the assembler "645"name\n"646"/// for the specified register.\n"647"const char *"648<< Target.getName() << ClassName << "::";649if (hasAltNames)650O << "\ngetRegisterName(MCRegister Reg, unsigned AltIdx) {\n";651else652O << "getRegisterName(MCRegister Reg) {\n";653O << " unsigned RegNo = Reg.id();\n"654<< " assert(RegNo && RegNo < " << (Registers.size() + 1)655<< " && \"Invalid register number!\");\n"656<< "\n";657658if (hasAltNames) {659for (const Record *R : AltNameIndices)660emitRegisterNameString(O, R->getName(), Registers);661} else662emitRegisterNameString(O, "", Registers);663664if (hasAltNames) {665O << " switch(AltIdx) {\n"666<< " default: llvm_unreachable(\"Invalid register alt name index!\");\n";667for (const Record *R : AltNameIndices) {668StringRef AltName = R->getName();669O << " case ";670if (!Namespace.empty())671O << Namespace << "::";672O << AltName << ":\n";673if (R->isValueUnset("FallbackRegAltNameIndex"))674O << " assert(*(AsmStrs" << AltName << "+RegAsmOffset" << AltName675<< "[RegNo-1]) &&\n"676<< " \"Invalid alt name index for register!\");\n";677else {678O << " if (!*(AsmStrs" << AltName << "+RegAsmOffset" << AltName679<< "[RegNo-1]))\n"680<< " return getRegisterName(RegNo, ";681if (!Namespace.empty())682O << Namespace << "::";683O << R->getValueAsDef("FallbackRegAltNameIndex")->getName() << ");\n";684}685O << " return AsmStrs" << AltName << "+RegAsmOffset" << AltName686<< "[RegNo-1];\n";687}688O << " }\n";689} else {690O << " assert (*(AsmStrs+RegAsmOffset[RegNo-1]) &&\n"691<< " \"Invalid alt name index for register!\");\n"692<< " return AsmStrs+RegAsmOffset[RegNo-1];\n";693}694O << "}\n";695}696697namespace {698699// IAPrinter - Holds information about an InstAlias. Two InstAliases match if700// they both have the same conditionals. In which case, we cannot print out the701// alias for that pattern.702class IAPrinter {703std::map<StringRef, std::pair<int, int>> OpMap;704705std::vector<std::string> Conds;706707std::string Result;708std::string AsmString;709710unsigned NumMIOps;711712public:713IAPrinter(std::string R, std::string AS, unsigned NumMIOps)714: Result(std::move(R)), AsmString(std::move(AS)), NumMIOps(NumMIOps) {}715716void addCond(std::string C) { Conds.push_back(std::move(C)); }717ArrayRef<std::string> getConds() const { return Conds; }718size_t getCondCount() const { return Conds.size(); }719720void addOperand(StringRef Op, int OpIdx, int PrintMethodIdx = -1) {721assert(OpIdx >= 0 && OpIdx < 0xFE && "Idx out of range");722assert(PrintMethodIdx >= -1 && PrintMethodIdx < 0xFF && "Idx out of range");723OpMap[Op] = std::pair(OpIdx, PrintMethodIdx);724}725726unsigned getNumMIOps() { return NumMIOps; }727728StringRef getResult() { return Result; }729730bool isOpMapped(StringRef Op) { return OpMap.find(Op) != OpMap.end(); }731int getOpIndex(StringRef Op) { return OpMap[Op].first; }732std::pair<int, int> &getOpData(StringRef Op) { return OpMap[Op]; }733734std::pair<StringRef, StringRef::iterator> parseName(StringRef::iterator Start,735StringRef::iterator End) {736StringRef::iterator I = Start;737StringRef::iterator Next;738if (*I == '{') {739// ${some_name}740Start = ++I;741while (I != End && *I != '}')742++I;743Next = I;744// eat the final '}'745if (Next != End)746++Next;747} else {748// $name, just eat the usual suspects.749while (I != End && (isAlnum(*I) || *I == '_'))750++I;751Next = I;752}753754return std::pair(StringRef(Start, I - Start), Next);755}756757std::string formatAliasString(uint32_t &UnescapedSize) {758// Directly mangle mapped operands into the string. Each operand is759// identified by a '$' sign followed by a byte identifying the number of the760// operand. We add one to the index to avoid zero bytes.761StringRef ASM(AsmString);762std::string OutString;763raw_string_ostream OS(OutString);764for (StringRef::iterator I = ASM.begin(), E = ASM.end(); I != E;) {765OS << *I;766++UnescapedSize;767if (*I == '$') {768StringRef Name;769std::tie(Name, I) = parseName(++I, E);770assert(isOpMapped(Name) && "Unmapped operand!");771772int OpIndex, PrintIndex;773std::tie(OpIndex, PrintIndex) = getOpData(Name);774if (PrintIndex == -1) {775// Can use the default printOperand route.776OS << format("\\x%02X", (unsigned char)OpIndex + 1);777++UnescapedSize;778} else {779// 3 bytes if a PrintMethod is needed: 0xFF, the MCInst operand780// number, and which of our pre-detected Methods to call.781OS << format("\\xFF\\x%02X\\x%02X", OpIndex + 1, PrintIndex + 1);782UnescapedSize += 3;783}784} else {785++I;786}787}788return OutString;789}790791bool operator==(const IAPrinter &RHS) const {792if (NumMIOps != RHS.NumMIOps)793return false;794if (Conds.size() != RHS.Conds.size())795return false;796797unsigned Idx = 0;798for (const auto &str : Conds)799if (str != RHS.Conds[Idx++])800return false;801802return true;803}804};805806} // end anonymous namespace807808static unsigned CountNumOperands(StringRef AsmString, unsigned Variant) {809return AsmString.count(' ') + AsmString.count('\t');810}811812namespace {813814struct AliasPriorityComparator {815typedef std::pair<CodeGenInstAlias, int> ValueType;816bool operator()(const ValueType &LHS, const ValueType &RHS) const {817if (LHS.second == RHS.second) {818// We don't actually care about the order, but for consistency it819// shouldn't depend on pointer comparisons.820return LessRecordByID()(LHS.first.TheDef, RHS.first.TheDef);821}822823// Aliases with larger priorities should be considered first.824return LHS.second > RHS.second;825}826};827828} // end anonymous namespace829830void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) {831Record *AsmWriter = Target.getAsmWriter();832833O << "\n#ifdef PRINT_ALIAS_INSTR\n";834O << "#undef PRINT_ALIAS_INSTR\n\n";835836//////////////////////////////837// Gather information about aliases we need to print838//////////////////////////////839840// Emit the method that prints the alias instruction.841StringRef ClassName = AsmWriter->getValueAsString("AsmWriterClassName");842unsigned Variant = AsmWriter->getValueAsInt("Variant");843bool PassSubtarget = AsmWriter->getValueAsInt("PassSubtarget");844845std::vector<Record *> AllInstAliases =846Records.getAllDerivedDefinitions("InstAlias");847848// Create a map from the qualified name to a list of potential matches.849typedef std::set<std::pair<CodeGenInstAlias, int>, AliasPriorityComparator>850AliasWithPriority;851std::map<std::string, AliasWithPriority> AliasMap;852for (Record *R : AllInstAliases) {853int Priority = R->getValueAsInt("EmitPriority");854if (Priority < 1)855continue; // Aliases with priority 0 are never emitted.856857const DagInit *DI = R->getValueAsDag("ResultInst");858AliasMap[getQualifiedName(DI->getOperatorAsDef(R->getLoc()))].insert(859std::pair(CodeGenInstAlias(R, Target), Priority));860}861862// A map of which conditions need to be met for each instruction operand863// before it can be matched to the mnemonic.864std::map<std::string, std::vector<IAPrinter>> IAPrinterMap;865866std::vector<std::pair<std::string, bool>> PrintMethods;867868// A list of MCOperandPredicates for all operands in use, and the reverse map869std::vector<const Record *> MCOpPredicates;870DenseMap<const Record *, unsigned> MCOpPredicateMap;871872for (auto &Aliases : AliasMap) {873// Collection of instruction alias rules. May contain ambiguous rules.874std::vector<IAPrinter> IAPs;875876for (auto &Alias : Aliases.second) {877const CodeGenInstAlias &CGA = Alias.first;878unsigned LastOpNo = CGA.ResultInstOperandIndex.size();879std::string FlatInstAsmString =880CodeGenInstruction::FlattenAsmStringVariants(881CGA.ResultInst->AsmString, Variant);882unsigned NumResultOps = CountNumOperands(FlatInstAsmString, Variant);883884std::string FlatAliasAsmString =885CodeGenInstruction::FlattenAsmStringVariants(CGA.AsmString, Variant);886UnescapeAliasString(FlatAliasAsmString);887888// Don't emit the alias if it has more operands than what it's aliasing.889if (NumResultOps < CountNumOperands(FlatAliasAsmString, Variant))890continue;891892StringRef Namespace = Target.getName();893unsigned NumMIOps = 0;894for (auto &ResultInstOpnd : CGA.ResultInst->Operands)895NumMIOps += ResultInstOpnd.MINumOperands;896897IAPrinter IAP(CGA.Result->getAsString(), FlatAliasAsmString, NumMIOps);898899unsigned MIOpNum = 0;900for (unsigned i = 0, e = LastOpNo; i != e; ++i) {901// Skip over tied operands as they're not part of an alias declaration.902auto &Operands = CGA.ResultInst->Operands;903while (true) {904unsigned OpNum = Operands.getSubOperandNumber(MIOpNum).first;905if (Operands[OpNum].MINumOperands == 1 &&906Operands[OpNum].getTiedRegister() != -1) {907// Tied operands of different RegisterClass should be explicit908// within an instruction's syntax and so cannot be skipped.909int TiedOpNum = Operands[OpNum].getTiedRegister();910if (Operands[OpNum].Rec->getName() ==911Operands[TiedOpNum].Rec->getName()) {912++MIOpNum;913continue;914}915}916break;917}918919// Ignore unchecked result operands.920while (IAP.getCondCount() < MIOpNum)921IAP.addCond("AliasPatternCond::K_Ignore, 0");922923const CodeGenInstAlias::ResultOperand &RO = CGA.ResultOperands[i];924925switch (RO.Kind) {926case CodeGenInstAlias::ResultOperand::K_Record: {927const Record *Rec = RO.getRecord();928StringRef ROName = RO.getName();929int PrintMethodIdx = -1;930931// These two may have a PrintMethod, which we want to record (if it's932// the first time we've seen it) and provide an index for the aliasing933// code to use.934if (Rec->isSubClassOf("RegisterOperand") ||935Rec->isSubClassOf("Operand")) {936StringRef PrintMethod = Rec->getValueAsString("PrintMethod");937bool IsPCRel =938Rec->getValueAsString("OperandType") == "OPERAND_PCREL";939if (PrintMethod != "" && PrintMethod != "printOperand") {940PrintMethodIdx = llvm::find_if(PrintMethods,941[&](auto &X) {942return X.first == PrintMethod;943}) -944PrintMethods.begin();945if (static_cast<unsigned>(PrintMethodIdx) == PrintMethods.size())946PrintMethods.emplace_back(std::string(PrintMethod), IsPCRel);947}948}949950if (Rec->isSubClassOf("RegisterOperand"))951Rec = Rec->getValueAsDef("RegClass");952if (Rec->isSubClassOf("RegisterClass")) {953if (!IAP.isOpMapped(ROName)) {954IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);955Record *R = CGA.ResultOperands[i].getRecord();956if (R->isSubClassOf("RegisterOperand"))957R = R->getValueAsDef("RegClass");958IAP.addCond(std::string(959formatv("AliasPatternCond::K_RegClass, {0}::{1}RegClassID",960Namespace, R->getName())));961} else {962IAP.addCond(std::string(formatv(963"AliasPatternCond::K_TiedReg, {0}", IAP.getOpIndex(ROName))));964}965} else {966// Assume all printable operands are desired for now. This can be967// overridden in the InstAlias instantiation if necessary.968IAP.addOperand(ROName, MIOpNum, PrintMethodIdx);969970// There might be an additional predicate on the MCOperand971unsigned Entry = MCOpPredicateMap[Rec];972if (!Entry) {973if (!Rec->isValueUnset("MCOperandPredicate")) {974MCOpPredicates.push_back(Rec);975Entry = MCOpPredicates.size();976MCOpPredicateMap[Rec] = Entry;977} else978break; // No conditions on this operand at all979}980IAP.addCond(981std::string(formatv("AliasPatternCond::K_Custom, {0}", Entry)));982}983break;984}985case CodeGenInstAlias::ResultOperand::K_Imm: {986// Just because the alias has an immediate result, doesn't mean the987// MCInst will. An MCExpr could be present, for example.988auto Imm = CGA.ResultOperands[i].getImm();989int32_t Imm32 = int32_t(Imm);990if (Imm != Imm32)991PrintFatalError("Matching an alias with an immediate out of the "992"range of int32_t is not supported");993IAP.addCond(std::string(994formatv("AliasPatternCond::K_Imm, uint32_t({0})", Imm32)));995break;996}997case CodeGenInstAlias::ResultOperand::K_Reg:998if (!CGA.ResultOperands[i].getRegister()) {999IAP.addCond(std::string(formatv(1000"AliasPatternCond::K_Reg, {0}::NoRegister", Namespace)));1001break;1002}10031004StringRef Reg = CGA.ResultOperands[i].getRegister()->getName();1005IAP.addCond(std::string(1006formatv("AliasPatternCond::K_Reg, {0}::{1}", Namespace, Reg)));1007break;1008}10091010MIOpNum += RO.getMINumOperands();1011}10121013std::vector<Record *> ReqFeatures;1014if (PassSubtarget) {1015// We only consider ReqFeatures predicates if PassSubtarget1016std::vector<Record *> RF =1017CGA.TheDef->getValueAsListOfDefs("Predicates");1018copy_if(RF, std::back_inserter(ReqFeatures), [](Record *R) {1019return R->getValueAsBit("AssemblerMatcherPredicate");1020});1021}10221023for (Record *const R : ReqFeatures) {1024const DagInit *D = R->getValueAsDag("AssemblerCondDag");1025auto *Op = dyn_cast<DefInit>(D->getOperator());1026if (!Op)1027PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1028StringRef CombineType = Op->getDef()->getName();1029if (CombineType != "any_of" && CombineType != "all_of")1030PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1031if (D->getNumArgs() == 0)1032PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1033bool IsOr = CombineType == "any_of";1034// Change (any_of FeatureAll, (any_of ...)) to (any_of FeatureAll, ...).1035if (IsOr && D->getNumArgs() == 2 && isa<DagInit>(D->getArg(1))) {1036DagInit *RHS = cast<DagInit>(D->getArg(1));1037SmallVector<Init *> Args{D->getArg(0)};1038SmallVector<StringInit *> ArgNames{D->getArgName(0)};1039for (unsigned i = 0, e = RHS->getNumArgs(); i != e; ++i) {1040Args.push_back(RHS->getArg(i));1041ArgNames.push_back(RHS->getArgName(i));1042}1043D = DagInit::get(D->getOperator(), nullptr, Args, ArgNames);1044}10451046for (auto *Arg : D->getArgs()) {1047bool IsNeg = false;1048if (auto *NotArg = dyn_cast<DagInit>(Arg)) {1049if (NotArg->getOperator()->getAsString() != "not" ||1050NotArg->getNumArgs() != 1)1051PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");1052Arg = NotArg->getArg(0);1053IsNeg = true;1054}1055if (!isa<DefInit>(Arg) ||1056!cast<DefInit>(Arg)->getDef()->isSubClassOf("SubtargetFeature"))1057PrintFatalError(R->getLoc(), "Invalid AssemblerCondDag!");10581059IAP.addCond(std::string(formatv(1060"AliasPatternCond::K_{0}{1}Feature, {2}::{3}", IsOr ? "Or" : "",1061IsNeg ? "Neg" : "", Namespace, Arg->getAsString())));1062}1063// If an AssemblerPredicate with ors is used, note end of list should1064// these be combined.1065if (IsOr)1066IAP.addCond("AliasPatternCond::K_EndOrFeatures, 0");1067}10681069IAPrinterMap[Aliases.first].push_back(std::move(IAP));1070}1071}10721073//////////////////////////////1074// Write out the printAliasInstr function1075//////////////////////////////10761077std::string Header;1078raw_string_ostream HeaderO(Header);10791080HeaderO << "bool " << Target.getName() << ClassName1081<< "::printAliasInstr(const MCInst"1082<< " *MI, uint64_t Address, "1083<< (PassSubtarget ? "const MCSubtargetInfo &STI, " : "")1084<< "raw_ostream &OS) {\n";10851086std::string PatternsForOpcode;1087raw_string_ostream OpcodeO(PatternsForOpcode);10881089unsigned PatternCount = 0;1090std::string Patterns;1091raw_string_ostream PatternO(Patterns);10921093unsigned CondCount = 0;1094std::string Conds;1095raw_string_ostream CondO(Conds);10961097// All flattened alias strings.1098std::map<std::string, uint32_t> AsmStringOffsets;1099std::vector<std::pair<uint32_t, std::string>> AsmStrings;1100size_t AsmStringsSize = 0;11011102// Iterate over the opcodes in enum order so they are sorted by opcode for1103// binary search.1104for (const CodeGenInstruction *Inst : NumberedInstructions) {1105auto It = IAPrinterMap.find(getQualifiedName(Inst->TheDef));1106if (It == IAPrinterMap.end())1107continue;1108std::vector<IAPrinter> &IAPs = It->second;1109std::vector<IAPrinter *> UniqueIAPs;11101111// Remove any ambiguous alias rules.1112for (auto &LHS : IAPs) {1113bool IsDup = false;1114for (const auto &RHS : IAPs) {1115if (&LHS != &RHS && LHS == RHS) {1116IsDup = true;1117break;1118}1119}11201121if (!IsDup)1122UniqueIAPs.push_back(&LHS);1123}11241125if (UniqueIAPs.empty())1126continue;11271128unsigned PatternStart = PatternCount;11291130// Insert the pattern start and opcode in the pattern list for debugging.1131PatternO << formatv(" // {0} - {1}\n", It->first, PatternStart);11321133for (IAPrinter *IAP : UniqueIAPs) {1134// Start each condition list with a comment of the resulting pattern that1135// we're trying to match.1136unsigned CondStart = CondCount;1137CondO << formatv(" // {0} - {1}\n", IAP->getResult(), CondStart);1138for (const auto &Cond : IAP->getConds())1139CondO << " {" << Cond << "},\n";1140CondCount += IAP->getCondCount();11411142// After operands have been examined, re-encode the alias string with1143// escapes indicating how operands should be printed.1144uint32_t UnescapedSize = 0;1145std::string EncodedAsmString = IAP->formatAliasString(UnescapedSize);1146auto Insertion =1147AsmStringOffsets.insert({EncodedAsmString, AsmStringsSize});1148if (Insertion.second) {1149// If the string is new, add it to the vector.1150AsmStrings.push_back({AsmStringsSize, EncodedAsmString});1151AsmStringsSize += UnescapedSize + 1;1152}1153unsigned AsmStrOffset = Insertion.first->second;11541155PatternO << formatv(" {{{0}, {1}, {2}, {3} },\n", AsmStrOffset,1156CondStart, IAP->getNumMIOps(), IAP->getCondCount());1157++PatternCount;1158}11591160OpcodeO << formatv(" {{{0}, {1}, {2} },\n", It->first, PatternStart,1161PatternCount - PatternStart);1162}11631164if (PatternsForOpcode.empty()) {1165O << Header;1166O << " return false;\n";1167O << "}\n\n";1168O << "#endif // PRINT_ALIAS_INSTR\n";1169return;1170}11711172// Forward declare the validation method if needed.1173if (!MCOpPredicates.empty())1174O << "static bool " << Target.getName() << ClassName1175<< "ValidateMCOperand(const MCOperand &MCOp,\n"1176<< " const MCSubtargetInfo &STI,\n"1177<< " unsigned PredicateIndex);\n";11781179O << Header;1180O.indent(2) << "static const PatternsForOpcode OpToPatterns[] = {\n";1181O << PatternsForOpcode;1182O.indent(2) << "};\n\n";1183O.indent(2) << "static const AliasPattern Patterns[] = {\n";1184O << Patterns;1185O.indent(2) << "};\n\n";1186O.indent(2) << "static const AliasPatternCond Conds[] = {\n";1187O << Conds;1188O.indent(2) << "};\n\n";1189O.indent(2) << "static const char AsmStrings[] =\n";1190for (const auto &P : AsmStrings) {1191O.indent(4) << "/* " << P.first << " */ \"" << P.second << "\\0\"\n";1192}11931194O.indent(2) << ";\n\n";11951196// Assert that the opcode table is sorted. Use a static local constructor to1197// ensure that the check only happens once on first run.1198O << "#ifndef NDEBUG\n";1199O.indent(2) << "static struct SortCheck {\n";1200O.indent(2) << " SortCheck(ArrayRef<PatternsForOpcode> OpToPatterns) {\n";1201O.indent(2) << " assert(std::is_sorted(\n";1202O.indent(2) << " OpToPatterns.begin(), OpToPatterns.end(),\n";1203O.indent(2) << " [](const PatternsForOpcode &L, const "1204"PatternsForOpcode &R) {\n";1205O.indent(2) << " return L.Opcode < R.Opcode;\n";1206O.indent(2) << " }) &&\n";1207O.indent(2) << " \"tablegen failed to sort opcode patterns\");\n";1208O.indent(2) << " }\n";1209O.indent(2) << "} sortCheckVar(OpToPatterns);\n";1210O << "#endif\n\n";12111212O.indent(2) << "AliasMatchingData M {\n";1213O.indent(2) << " ArrayRef(OpToPatterns),\n";1214O.indent(2) << " ArrayRef(Patterns),\n";1215O.indent(2) << " ArrayRef(Conds),\n";1216O.indent(2) << " StringRef(AsmStrings, std::size(AsmStrings)),\n";1217if (MCOpPredicates.empty())1218O.indent(2) << " nullptr,\n";1219else1220O.indent(2) << " &" << Target.getName() << ClassName1221<< "ValidateMCOperand,\n";1222O.indent(2) << "};\n";12231224O.indent(2) << "const char *AsmString = matchAliasPatterns(MI, "1225<< (PassSubtarget ? "&STI" : "nullptr") << ", M);\n";1226O.indent(2) << "if (!AsmString) return false;\n\n";12271228// Code that prints the alias, replacing the operands with the ones from the1229// MCInst.1230O << " unsigned I = 0;\n";1231O << " while (AsmString[I] != ' ' && AsmString[I] != '\\t' &&\n";1232O << " AsmString[I] != '$' && AsmString[I] != '\\0')\n";1233O << " ++I;\n";1234O << " OS << '\\t' << StringRef(AsmString, I);\n";12351236O << " if (AsmString[I] != '\\0') {\n";1237O << " if (AsmString[I] == ' ' || AsmString[I] == '\\t') {\n";1238O << " OS << '\\t';\n";1239O << " ++I;\n";1240O << " }\n";1241O << " do {\n";1242O << " if (AsmString[I] == '$') {\n";1243O << " ++I;\n";1244O << " if (AsmString[I] == (char)0xff) {\n";1245O << " ++I;\n";1246O << " int OpIdx = AsmString[I++] - 1;\n";1247O << " int PrintMethodIdx = AsmString[I++] - 1;\n";1248O << " printCustomAliasOperand(MI, Address, OpIdx, PrintMethodIdx, ";1249O << (PassSubtarget ? "STI, " : "");1250O << "OS);\n";1251O << " } else\n";1252O << " printOperand(MI, unsigned(AsmString[I++]) - 1, ";1253O << (PassSubtarget ? "STI, " : "");1254O << "OS);\n";1255O << " } else {\n";1256O << " OS << AsmString[I++];\n";1257O << " }\n";1258O << " } while (AsmString[I] != '\\0');\n";1259O << " }\n\n";12601261O << " return true;\n";1262O << "}\n\n";12631264//////////////////////////////1265// Write out the printCustomAliasOperand function1266//////////////////////////////12671268O << "void " << Target.getName() << ClassName << "::"1269<< "printCustomAliasOperand(\n"1270<< " const MCInst *MI, uint64_t Address, unsigned OpIdx,\n"1271<< " unsigned PrintMethodIdx,\n"1272<< (PassSubtarget ? " const MCSubtargetInfo &STI,\n" : "")1273<< " raw_ostream &OS) {\n";1274if (PrintMethods.empty())1275O << " llvm_unreachable(\"Unknown PrintMethod kind\");\n";1276else {1277O << " switch (PrintMethodIdx) {\n"1278<< " default:\n"1279<< " llvm_unreachable(\"Unknown PrintMethod kind\");\n"1280<< " break;\n";12811282for (unsigned i = 0; i < PrintMethods.size(); ++i) {1283O << " case " << i << ":\n"1284<< " " << PrintMethods[i].first << "(MI, "1285<< (PrintMethods[i].second ? "Address, " : "") << "OpIdx, "1286<< (PassSubtarget ? "STI, " : "") << "OS);\n"1287<< " break;\n";1288}1289O << " }\n";1290}1291O << "}\n\n";12921293if (!MCOpPredicates.empty()) {1294O << "static bool " << Target.getName() << ClassName1295<< "ValidateMCOperand(const MCOperand &MCOp,\n"1296<< " const MCSubtargetInfo &STI,\n"1297<< " unsigned PredicateIndex) {\n"1298<< " switch (PredicateIndex) {\n"1299<< " default:\n"1300<< " llvm_unreachable(\"Unknown MCOperandPredicate kind\");\n"1301<< " break;\n";13021303for (unsigned i = 0; i < MCOpPredicates.size(); ++i) {1304StringRef MCOpPred =1305MCOpPredicates[i]->getValueAsString("MCOperandPredicate");1306O << " case " << i + 1 << ": {\n"1307<< MCOpPred.data() << "\n"1308<< " }\n";1309}1310O << " }\n"1311<< "}\n\n";1312}13131314O << "#endif // PRINT_ALIAS_INSTR\n";1315}13161317AsmWriterEmitter::AsmWriterEmitter(RecordKeeper &R) : Records(R), Target(R) {1318Record *AsmWriter = Target.getAsmWriter();1319unsigned Variant = AsmWriter->getValueAsInt("Variant");13201321// Get the instruction numbering.1322NumberedInstructions = Target.getInstructionsByEnumValue();13231324for (unsigned i = 0, e = NumberedInstructions.size(); i != e; ++i) {1325const CodeGenInstruction *I = NumberedInstructions[i];1326if (!I->AsmString.empty() && I->TheDef->getName() != "PHI")1327Instructions.emplace_back(*I, i, Variant);1328}1329}13301331void AsmWriterEmitter::run(raw_ostream &O) {1332std::vector<std::vector<std::string>> TableDrivenOperandPrinters;1333unsigned BitsLeft = 0;1334unsigned AsmStrBits = 0;1335emitSourceFileHeader("Assembly Writer Source Fragment", O, Records);1336EmitGetMnemonic(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);1337EmitPrintInstruction(O, TableDrivenOperandPrinters, BitsLeft, AsmStrBits);1338EmitGetRegisterName(O);1339EmitPrintAliasInstruction(O);1340}13411342static TableGen::Emitter::OptClass<AsmWriterEmitter>1343X("gen-asm-writer", "Generate assembly writer");134413451346