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