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