brintos

brintos / llvm-project-archived public Read only

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