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 21*0fca6ea1SDimitry Andric #include "Common/CodeGenDAGPatterns.h" 22*0fca6ea1SDimitry Andric #include "Common/CodeGenInstruction.h" 23*0fca6ea1SDimitry Andric #include "Common/CodeGenTarget.h" 240b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 2506c3fb27SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 260b57cec5SDimitry Andric #include <string> 270b57cec5SDimitry Andric #include <vector> 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric using namespace llvm; 300b57cec5SDimitry Andric 3106c3fb27SDimitry Andric static void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') { 3206c3fb27SDimitry Andric OS << std::string(Str.size(), Kind) << "\n" 3306c3fb27SDimitry Andric << Str << "\n" 340b57cec5SDimitry Andric << std::string(Str.size(), Kind) << "\n"; 350b57cec5SDimitry Andric } 360b57cec5SDimitry Andric 3706c3fb27SDimitry 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 4106c3fb27SDimitry 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. 47*0fca6ea1SDimitry Andric case '\n': 48*0fca6ea1SDimitry Andric Result += "\\n"; 49*0fca6ea1SDimitry Andric break; 50*0fca6ea1SDimitry Andric case '\t': 51*0fca6ea1SDimitry Andric Result += "\\t"; 52*0fca6ea1SDimitry Andric break; 530b57cec5SDimitry Andric // Underscore at the end of a line has a special meaning in rst. 54*0fca6ea1SDimitry Andric case '_': 55*0fca6ea1SDimitry Andric Result += "\\_"; 56*0fca6ea1SDimitry Andric break; 57*0fca6ea1SDimitry Andric default: 58*0fca6ea1SDimitry Andric Result += C; 590b57cec5SDimitry Andric } 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric return Result; 620b57cec5SDimitry Andric } 630b57cec5SDimitry Andric 6406c3fb27SDimitry Andric static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) { 650b57cec5SDimitry Andric CodeGenDAGPatterns CDP(RK); 660b57cec5SDimitry Andric CodeGenTarget &Target = CDP.getTargetInfo(); 670b57cec5SDimitry Andric unsigned VariantCount = Target.getAsmParserVariantCount(); 680b57cec5SDimitry Andric 690b57cec5SDimitry Andric // Page title. 705ffd83dbSDimitry Andric std::string Title = std::string(Target.getName()); 710b57cec5SDimitry Andric Title += " Instructions"; 720b57cec5SDimitry Andric writeTitle(Title, OS); 730b57cec5SDimitry Andric OS << "\n"; 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) { 760b57cec5SDimitry Andric Record *Inst = II->TheDef; 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Don't print the target-independent instructions. 790b57cec5SDimitry Andric if (II->Namespace == "TargetOpcode") 800b57cec5SDimitry Andric continue; 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric // Heading (instruction name). 830b57cec5SDimitry Andric writeHeader(escapeForRST(Inst->getName()), OS, '='); 840b57cec5SDimitry Andric OS << "\n"; 850b57cec5SDimitry Andric 860b57cec5SDimitry Andric // Assembly string(s). 870b57cec5SDimitry Andric if (!II->AsmString.empty()) { 880b57cec5SDimitry Andric for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) { 890b57cec5SDimitry Andric Record *AsmVariant = Target.getAsmParserVariant(VarNum); 900b57cec5SDimitry Andric OS << "Assembly string"; 910b57cec5SDimitry Andric if (VariantCount != 1) 920b57cec5SDimitry Andric OS << " (" << AsmVariant->getValueAsString("Name") << ")"; 930b57cec5SDimitry Andric std::string AsmString = 940b57cec5SDimitry Andric CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum); 950b57cec5SDimitry Andric // We trim spaces at each end of the asm string because rst needs the 960b57cec5SDimitry Andric // formatting backticks to be next to a non-whitespace character. 970b57cec5SDimitry Andric OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" ")) 980b57cec5SDimitry Andric << "``\n\n"; 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric } 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric // Boolean flags. 1030b57cec5SDimitry Andric std::vector<const char *> FlagStrings; 1040b57cec5SDimitry Andric #define xstr(s) str(s) 1050b57cec5SDimitry Andric #define str(s) #s 106*0fca6ea1SDimitry Andric #define FLAG(f) \ 107*0fca6ea1SDimitry Andric if (II->f) { \ 108*0fca6ea1SDimitry Andric FlagStrings.push_back(str(f)); \ 109*0fca6ea1SDimitry Andric } 1100b57cec5SDimitry Andric FLAG(isReturn) 1110b57cec5SDimitry Andric FLAG(isEHScopeReturn) 1120b57cec5SDimitry Andric FLAG(isBranch) 1130b57cec5SDimitry Andric FLAG(isIndirectBranch) 1140b57cec5SDimitry Andric FLAG(isCompare) 1150b57cec5SDimitry Andric FLAG(isMoveImm) 1160b57cec5SDimitry Andric FLAG(isBitcast) 1170b57cec5SDimitry Andric FLAG(isSelect) 1180b57cec5SDimitry Andric FLAG(isBarrier) 1190b57cec5SDimitry Andric FLAG(isCall) 1200b57cec5SDimitry Andric FLAG(isAdd) 1210b57cec5SDimitry Andric FLAG(isTrap) 1220b57cec5SDimitry Andric FLAG(canFoldAsLoad) 1230b57cec5SDimitry Andric FLAG(mayLoad) 1240b57cec5SDimitry Andric // FLAG(mayLoad_Unset) // Deliberately omitted. 1250b57cec5SDimitry Andric FLAG(mayStore) 1260b57cec5SDimitry Andric // FLAG(mayStore_Unset) // Deliberately omitted. 1270b57cec5SDimitry Andric FLAG(isPredicable) 1280b57cec5SDimitry Andric FLAG(isConvertibleToThreeAddress) 1290b57cec5SDimitry Andric FLAG(isCommutable) 1300b57cec5SDimitry Andric FLAG(isTerminator) 1310b57cec5SDimitry Andric FLAG(isReMaterializable) 1320b57cec5SDimitry Andric FLAG(hasDelaySlot) 1330b57cec5SDimitry Andric FLAG(usesCustomInserter) 1340b57cec5SDimitry Andric FLAG(hasPostISelHook) 1350b57cec5SDimitry Andric FLAG(hasCtrlDep) 1360b57cec5SDimitry Andric FLAG(isNotDuplicable) 1370b57cec5SDimitry Andric FLAG(hasSideEffects) 1380b57cec5SDimitry Andric // FLAG(hasSideEffects_Unset) // Deliberately omitted. 1390b57cec5SDimitry Andric FLAG(isAsCheapAsAMove) 1400b57cec5SDimitry Andric FLAG(hasExtraSrcRegAllocReq) 1410b57cec5SDimitry Andric FLAG(hasExtraDefRegAllocReq) 1420b57cec5SDimitry Andric FLAG(isCodeGenOnly) 1430b57cec5SDimitry Andric FLAG(isPseudo) 1440b57cec5SDimitry Andric FLAG(isRegSequence) 1450b57cec5SDimitry Andric FLAG(isExtractSubreg) 1460b57cec5SDimitry Andric FLAG(isInsertSubreg) 1470b57cec5SDimitry Andric FLAG(isConvergent) 1480b57cec5SDimitry Andric FLAG(hasNoSchedulingInfo) 1490b57cec5SDimitry Andric FLAG(variadicOpsAreDefs) 150480093f4SDimitry Andric FLAG(isAuthenticated) 1510b57cec5SDimitry Andric if (!FlagStrings.empty()) { 1520b57cec5SDimitry Andric OS << "Flags: "; 153fe6060f1SDimitry Andric ListSeparator LS; 154fe6060f1SDimitry Andric for (auto FlagString : FlagStrings) 155fe6060f1SDimitry Andric OS << LS << "``" << FlagString << "``"; 1560b57cec5SDimitry Andric OS << "\n\n"; 1570b57cec5SDimitry Andric } 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric // Operands. 1600b57cec5SDimitry Andric for (unsigned i = 0; i < II->Operands.size(); ++i) { 1610b57cec5SDimitry Andric bool IsDef = i < II->Operands.NumDefs; 1620b57cec5SDimitry Andric auto Op = II->Operands[i]; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric if (Op.MINumOperands > 1) { 1650b57cec5SDimitry Andric // This operand corresponds to multiple operands on the 1660b57cec5SDimitry Andric // MachineInstruction, so print all of them, showing the types and 1670b57cec5SDimitry Andric // names of both the compound operand and the basic operands it 1680b57cec5SDimitry Andric // contains. 1690b57cec5SDimitry Andric for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) { 1700b57cec5SDimitry Andric Record *SubRec = 1710b57cec5SDimitry Andric cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef(); 1720b57cec5SDimitry Andric StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx); 1730b57cec5SDimitry Andric StringRef SubOpTypeName = SubRec->getName(); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName() 1760b57cec5SDimitry Andric << "/" << SubOpTypeName << ":$" << Op.Name << "."; 1770b57cec5SDimitry Andric // Not all sub-operands are named, make up a name for these. 1780b57cec5SDimitry Andric if (SubOpName.empty()) 1790b57cec5SDimitry Andric OS << "anon" << SubOpIdx; 1800b57cec5SDimitry Andric else 1810b57cec5SDimitry Andric OS << SubOpName; 1820b57cec5SDimitry Andric OS << "``\n\n"; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric } else { 1850b57cec5SDimitry Andric // The operand corresponds to only one MachineInstruction operand. 1860b57cec5SDimitry Andric OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName() 1870b57cec5SDimitry Andric << ":$" << Op.Name << "``\n\n"; 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric } 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // Constraints. 1920b57cec5SDimitry Andric StringRef Constraints = Inst->getValueAsString("Constraints"); 1930b57cec5SDimitry Andric if (!Constraints.empty()) { 1940b57cec5SDimitry Andric OS << "Constraints: ``" << Constraints << "``\n\n"; 1950b57cec5SDimitry Andric } 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Implicit definitions. 1980b57cec5SDimitry Andric if (!II->ImplicitDefs.empty()) { 1990b57cec5SDimitry Andric OS << "Implicit defs: "; 200fe6060f1SDimitry Andric ListSeparator LS; 201fe6060f1SDimitry Andric for (Record *Def : II->ImplicitDefs) 202fe6060f1SDimitry Andric OS << LS << "``" << Def->getName() << "``"; 2030b57cec5SDimitry Andric OS << "\n\n"; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric 2060b57cec5SDimitry Andric // Implicit uses. 2070b57cec5SDimitry Andric if (!II->ImplicitUses.empty()) { 2080b57cec5SDimitry Andric OS << "Implicit uses: "; 209fe6060f1SDimitry Andric ListSeparator LS; 210fe6060f1SDimitry Andric for (Record *Use : II->ImplicitUses) 211fe6060f1SDimitry Andric OS << LS << "``" << Use->getName() << "``"; 2120b57cec5SDimitry Andric OS << "\n\n"; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric // Predicates. 2160b57cec5SDimitry Andric std::vector<Record *> Predicates = 2170b57cec5SDimitry Andric II->TheDef->getValueAsListOfDefs("Predicates"); 2180b57cec5SDimitry Andric if (!Predicates.empty()) { 2190b57cec5SDimitry Andric OS << "Predicates: "; 220fe6060f1SDimitry Andric ListSeparator LS; 221fe6060f1SDimitry Andric for (Record *P : Predicates) 222fe6060f1SDimitry Andric OS << LS << "``" << P->getName() << "``"; 2230b57cec5SDimitry Andric OS << "\n\n"; 2240b57cec5SDimitry Andric } 2250b57cec5SDimitry Andric } 2260b57cec5SDimitry Andric } 2270b57cec5SDimitry Andric 22806c3fb27SDimitry Andric static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs, 22906c3fb27SDimitry Andric "Generate instruction documentation"); 230