xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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