10b57cec5SDimitry Andric //===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // InstrDocsEmitter generates restructured text documentation for the opcodes 100b57cec5SDimitry Andric // that can be used by MachineInstr. For each opcode, the documentation lists: 110b57cec5SDimitry Andric // * Opcode name 120b57cec5SDimitry Andric // * Assembly string 130b57cec5SDimitry Andric // * Flags (e.g. mayLoad, isBranch, ...) 140b57cec5SDimitry Andric // * Operands, including type and name 150b57cec5SDimitry Andric // * Operand constraints 160b57cec5SDimitry Andric // * Implicit register uses & defs 170b57cec5SDimitry Andric // * Predicates 180b57cec5SDimitry Andric // 190b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric #include "CodeGenDAGPatterns.h" 220b57cec5SDimitry Andric #include "CodeGenInstruction.h" 230b57cec5SDimitry Andric #include "CodeGenTarget.h" 240b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 25*06c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 260b57cec5SDimitry Andric #include <string> 270b57cec5SDimitry Andric #include <vector> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 31*06c3fb27SDimitry Andric static void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') { 32*06c3fb27SDimitry Andric OS << std::string(Str.size(), Kind) << "\n" 33*06c3fb27SDimitry Andric << Str << "\n" 340b57cec5SDimitry Andric << std::string(Str.size(), Kind) << "\n"; 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 37*06c3fb27SDimitry Andric static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') { 380b57cec5SDimitry Andric OS << Str << "\n" << std::string(Str.size(), Kind) << "\n"; 390b57cec5SDimitry Andric } 400b57cec5SDimitry Andric 41*06c3fb27SDimitry Andric static std::string escapeForRST(StringRef Str) { 420b57cec5SDimitry Andric std::string Result; 430b57cec5SDimitry Andric Result.reserve(Str.size() + 4); 440b57cec5SDimitry Andric for (char C : Str) { 450b57cec5SDimitry Andric switch (C) { 460b57cec5SDimitry Andric // We want special characters to be shown as their C escape codes. 470b57cec5SDimitry Andric case '\n': Result += "\\n"; break; 480b57cec5SDimitry Andric case '\t': Result += "\\t"; break; 490b57cec5SDimitry Andric // Underscore at the end of a line has a special meaning in rst. 500b57cec5SDimitry Andric case '_': Result += "\\_"; break; 510b57cec5SDimitry Andric default: Result += C; 520b57cec5SDimitry Andric } 530b57cec5SDimitry Andric } 540b57cec5SDimitry Andric return Result; 550b57cec5SDimitry Andric } 560b57cec5SDimitry Andric 57*06c3fb27SDimitry Andric static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) { 580b57cec5SDimitry Andric CodeGenDAGPatterns CDP(RK); 590b57cec5SDimitry Andric CodeGenTarget &Target = CDP.getTargetInfo(); 600b57cec5SDimitry Andric unsigned VariantCount = Target.getAsmParserVariantCount(); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Page title. 635ffd83dbSDimitry Andric std::string Title = std::string(Target.getName()); 640b57cec5SDimitry Andric Title += " Instructions"; 650b57cec5SDimitry Andric writeTitle(Title, OS); 660b57cec5SDimitry Andric OS << "\n"; 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { 690b57cec5SDimitry Andric Record *Inst = II->TheDef; 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Don't print the target-independent instructions. 720b57cec5SDimitry Andric if (II->Namespace == "TargetOpcode") 730b57cec5SDimitry Andric continue; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric // Heading (instruction name). 760b57cec5SDimitry Andric writeHeader(escapeForRST(Inst->getName()), OS, '='); 770b57cec5SDimitry Andric OS << "\n"; 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric // Assembly string(s). 800b57cec5SDimitry Andric if (!II->AsmString.empty()) { 810b57cec5SDimitry Andric for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) { 820b57cec5SDimitry Andric Record *AsmVariant = Target.getAsmParserVariant(VarNum); 830b57cec5SDimitry Andric OS << "Assembly string"; 840b57cec5SDimitry Andric if (VariantCount != 1) 850b57cec5SDimitry Andric OS << " (" << AsmVariant->getValueAsString("Name") << ")"; 860b57cec5SDimitry Andric std::string AsmString = 870b57cec5SDimitry Andric CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum); 880b57cec5SDimitry Andric // We trim spaces at each end of the asm string because rst needs the 890b57cec5SDimitry Andric // formatting backticks to be next to a non-whitespace character. 900b57cec5SDimitry Andric OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" ")) 910b57cec5SDimitry Andric << "``\n\n"; 920b57cec5SDimitry Andric } 930b57cec5SDimitry Andric } 940b57cec5SDimitry Andric 950b57cec5SDimitry Andric // Boolean flags. 960b57cec5SDimitry Andric std::vector<const char *> FlagStrings; 970b57cec5SDimitry Andric #define xstr(s) str(s) 980b57cec5SDimitry Andric #define str(s) #s 990b57cec5SDimitry Andric #define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); } 1000b57cec5SDimitry Andric FLAG(isReturn) 1010b57cec5SDimitry Andric FLAG(isEHScopeReturn) 1020b57cec5SDimitry Andric FLAG(isBranch) 1030b57cec5SDimitry Andric FLAG(isIndirectBranch) 1040b57cec5SDimitry Andric FLAG(isCompare) 1050b57cec5SDimitry Andric FLAG(isMoveImm) 1060b57cec5SDimitry Andric FLAG(isBitcast) 1070b57cec5SDimitry Andric FLAG(isSelect) 1080b57cec5SDimitry Andric FLAG(isBarrier) 1090b57cec5SDimitry Andric FLAG(isCall) 1100b57cec5SDimitry Andric FLAG(isAdd) 1110b57cec5SDimitry Andric FLAG(isTrap) 1120b57cec5SDimitry Andric FLAG(canFoldAsLoad) 1130b57cec5SDimitry Andric FLAG(mayLoad) 1140b57cec5SDimitry Andric //FLAG(mayLoad_Unset) // Deliberately omitted. 1150b57cec5SDimitry Andric FLAG(mayStore) 1160b57cec5SDimitry Andric //FLAG(mayStore_Unset) // Deliberately omitted. 1170b57cec5SDimitry Andric FLAG(isPredicable) 1180b57cec5SDimitry Andric FLAG(isConvertibleToThreeAddress) 1190b57cec5SDimitry Andric FLAG(isCommutable) 1200b57cec5SDimitry Andric FLAG(isTerminator) 1210b57cec5SDimitry Andric FLAG(isReMaterializable) 1220b57cec5SDimitry Andric FLAG(hasDelaySlot) 1230b57cec5SDimitry Andric FLAG(usesCustomInserter) 1240b57cec5SDimitry Andric FLAG(hasPostISelHook) 1250b57cec5SDimitry Andric FLAG(hasCtrlDep) 1260b57cec5SDimitry Andric FLAG(isNotDuplicable) 1270b57cec5SDimitry Andric FLAG(hasSideEffects) 1280b57cec5SDimitry Andric //FLAG(hasSideEffects_Unset) // Deliberately omitted. 1290b57cec5SDimitry Andric FLAG(isAsCheapAsAMove) 1300b57cec5SDimitry Andric FLAG(hasExtraSrcRegAllocReq) 1310b57cec5SDimitry Andric FLAG(hasExtraDefRegAllocReq) 1320b57cec5SDimitry Andric FLAG(isCodeGenOnly) 1330b57cec5SDimitry Andric FLAG(isPseudo) 1340b57cec5SDimitry Andric FLAG(isRegSequence) 1350b57cec5SDimitry Andric FLAG(isExtractSubreg) 1360b57cec5SDimitry Andric FLAG(isInsertSubreg) 1370b57cec5SDimitry Andric FLAG(isConvergent) 1380b57cec5SDimitry Andric FLAG(hasNoSchedulingInfo) 1390b57cec5SDimitry Andric FLAG(variadicOpsAreDefs) 140480093f4SDimitry Andric FLAG(isAuthenticated) 1410b57cec5SDimitry Andric if (!FlagStrings.empty()) { 1420b57cec5SDimitry Andric OS << "Flags: "; 143fe6060f1SDimitry Andric ListSeparator LS; 144fe6060f1SDimitry Andric for (auto FlagString : FlagStrings) 145fe6060f1SDimitry Andric OS << LS << "``" << FlagString << "``"; 1460b57cec5SDimitry Andric OS << "\n\n"; 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric 1490b57cec5SDimitry Andric // Operands. 1500b57cec5SDimitry Andric for (unsigned i = 0; i < II->Operands.size(); ++i) { 1510b57cec5SDimitry Andric bool IsDef = i < II->Operands.NumDefs; 1520b57cec5SDimitry Andric auto Op = II->Operands[i]; 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric if (Op.MINumOperands > 1) { 1550b57cec5SDimitry Andric // This operand corresponds to multiple operands on the 1560b57cec5SDimitry Andric // MachineInstruction, so print all of them, showing the types and 1570b57cec5SDimitry Andric // names of both the compound operand and the basic operands it 1580b57cec5SDimitry Andric // contains. 1590b57cec5SDimitry Andric for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) { 1600b57cec5SDimitry Andric Record *SubRec = 1610b57cec5SDimitry Andric cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef(); 1620b57cec5SDimitry Andric StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx); 1630b57cec5SDimitry Andric StringRef SubOpTypeName = SubRec->getName(); 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName() 1660b57cec5SDimitry Andric << "/" << SubOpTypeName << ":$" << Op.Name << "."; 1670b57cec5SDimitry Andric // Not all sub-operands are named, make up a name for these. 1680b57cec5SDimitry Andric if (SubOpName.empty()) 1690b57cec5SDimitry Andric OS << "anon" << SubOpIdx; 1700b57cec5SDimitry Andric else 1710b57cec5SDimitry Andric OS << SubOpName; 1720b57cec5SDimitry Andric OS << "``\n\n"; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } else { 1750b57cec5SDimitry Andric // The operand corresponds to only one MachineInstruction operand. 1760b57cec5SDimitry Andric OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName() 1770b57cec5SDimitry Andric << ":$" << Op.Name << "``\n\n"; 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric } 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric // Constraints. 1820b57cec5SDimitry Andric StringRef Constraints = Inst->getValueAsString("Constraints"); 1830b57cec5SDimitry Andric if (!Constraints.empty()) { 1840b57cec5SDimitry Andric OS << "Constraints: ``" << Constraints << "``\n\n"; 1850b57cec5SDimitry Andric } 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // Implicit definitions. 1880b57cec5SDimitry Andric if (!II->ImplicitDefs.empty()) { 1890b57cec5SDimitry Andric OS << "Implicit defs: "; 190fe6060f1SDimitry Andric ListSeparator LS; 191fe6060f1SDimitry Andric for (Record *Def : II->ImplicitDefs) 192fe6060f1SDimitry Andric OS << LS << "``" << Def->getName() << "``"; 1930b57cec5SDimitry Andric OS << "\n\n"; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric // Implicit uses. 1970b57cec5SDimitry Andric if (!II->ImplicitUses.empty()) { 1980b57cec5SDimitry Andric OS << "Implicit uses: "; 199fe6060f1SDimitry Andric ListSeparator LS; 200fe6060f1SDimitry Andric for (Record *Use : II->ImplicitUses) 201fe6060f1SDimitry Andric OS << LS << "``" << Use->getName() << "``"; 2020b57cec5SDimitry Andric OS << "\n\n"; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 2050b57cec5SDimitry Andric // Predicates. 2060b57cec5SDimitry Andric std::vector<Record *> Predicates = 2070b57cec5SDimitry Andric II->TheDef->getValueAsListOfDefs("Predicates"); 2080b57cec5SDimitry Andric if (!Predicates.empty()) { 2090b57cec5SDimitry Andric OS << "Predicates: "; 210fe6060f1SDimitry Andric ListSeparator LS; 211fe6060f1SDimitry Andric for (Record *P : Predicates) 212fe6060f1SDimitry Andric OS << LS << "``" << P->getName() << "``"; 2130b57cec5SDimitry Andric OS << "\n\n"; 2140b57cec5SDimitry Andric } 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric } 2170b57cec5SDimitry Andric 218*06c3fb27SDimitry Andric static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs, 219*06c3fb27SDimitry Andric "Generate instruction documentation"); 220