xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
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 "TableGenBackends.h"
250b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
260b57cec5SDimitry Andric #include <string>
270b57cec5SDimitry Andric #include <vector>
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric namespace llvm {
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
340b57cec5SDimitry Andric   OS << std::string(Str.size(), Kind) << "\n" << Str << "\n"
350b57cec5SDimitry Andric      << std::string(Str.size(), Kind) << "\n";
360b57cec5SDimitry Andric }
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
390b57cec5SDimitry Andric   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric std::string escapeForRST(StringRef Str) {
430b57cec5SDimitry Andric   std::string Result;
440b57cec5SDimitry Andric   Result.reserve(Str.size() + 4);
450b57cec5SDimitry Andric   for (char C : Str) {
460b57cec5SDimitry Andric     switch (C) {
470b57cec5SDimitry Andric     // We want special characters to be shown as their C escape codes.
480b57cec5SDimitry Andric     case '\n': Result += "\\n"; break;
490b57cec5SDimitry Andric     case '\t': Result += "\\t"; break;
500b57cec5SDimitry Andric     // Underscore at the end of a line has a special meaning in rst.
510b57cec5SDimitry Andric     case '_': Result += "\\_"; break;
520b57cec5SDimitry Andric     default: Result += C;
530b57cec5SDimitry Andric     }
540b57cec5SDimitry Andric   }
550b57cec5SDimitry Andric   return Result;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
590b57cec5SDimitry Andric   CodeGenDAGPatterns CDP(RK);
600b57cec5SDimitry Andric   CodeGenTarget &Target = CDP.getTargetInfo();
610b57cec5SDimitry Andric   unsigned VariantCount = Target.getAsmParserVariantCount();
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   // Page title.
640b57cec5SDimitry Andric   std::string Title = Target.getName();
650b57cec5SDimitry Andric   Title += " Instructions";
660b57cec5SDimitry Andric   writeTitle(Title, OS);
670b57cec5SDimitry Andric   OS << "\n";
680b57cec5SDimitry Andric 
690b57cec5SDimitry Andric   for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
700b57cec5SDimitry Andric     Record *Inst = II->TheDef;
710b57cec5SDimitry Andric 
720b57cec5SDimitry Andric     // Don't print the target-independent instructions.
730b57cec5SDimitry Andric     if (II->Namespace == "TargetOpcode")
740b57cec5SDimitry Andric       continue;
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric     // Heading (instruction name).
770b57cec5SDimitry Andric     writeHeader(escapeForRST(Inst->getName()), OS, '=');
780b57cec5SDimitry Andric     OS << "\n";
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric     // Assembly string(s).
810b57cec5SDimitry Andric     if (!II->AsmString.empty()) {
820b57cec5SDimitry Andric       for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {
830b57cec5SDimitry Andric         Record *AsmVariant = Target.getAsmParserVariant(VarNum);
840b57cec5SDimitry Andric         OS << "Assembly string";
850b57cec5SDimitry Andric         if (VariantCount != 1)
860b57cec5SDimitry Andric           OS << " (" << AsmVariant->getValueAsString("Name") << ")";
870b57cec5SDimitry Andric         std::string AsmString =
880b57cec5SDimitry Andric             CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum);
890b57cec5SDimitry Andric         // We trim spaces at each end of the asm string because rst needs the
900b57cec5SDimitry Andric         // formatting backticks to be next to a non-whitespace character.
910b57cec5SDimitry Andric         OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" "))
920b57cec5SDimitry Andric            << "``\n\n";
930b57cec5SDimitry Andric       }
940b57cec5SDimitry Andric     }
950b57cec5SDimitry Andric 
960b57cec5SDimitry Andric     // Boolean flags.
970b57cec5SDimitry Andric     std::vector<const char *> FlagStrings;
980b57cec5SDimitry Andric #define xstr(s) str(s)
990b57cec5SDimitry Andric #define str(s) #s
1000b57cec5SDimitry Andric #define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); }
1010b57cec5SDimitry Andric     FLAG(isReturn)
1020b57cec5SDimitry Andric     FLAG(isEHScopeReturn)
1030b57cec5SDimitry Andric     FLAG(isBranch)
1040b57cec5SDimitry Andric     FLAG(isIndirectBranch)
1050b57cec5SDimitry Andric     FLAG(isCompare)
1060b57cec5SDimitry Andric     FLAG(isMoveImm)
1070b57cec5SDimitry Andric     FLAG(isBitcast)
1080b57cec5SDimitry Andric     FLAG(isSelect)
1090b57cec5SDimitry Andric     FLAG(isBarrier)
1100b57cec5SDimitry Andric     FLAG(isCall)
1110b57cec5SDimitry Andric     FLAG(isAdd)
1120b57cec5SDimitry Andric     FLAG(isTrap)
1130b57cec5SDimitry Andric     FLAG(canFoldAsLoad)
1140b57cec5SDimitry Andric     FLAG(mayLoad)
1150b57cec5SDimitry Andric     //FLAG(mayLoad_Unset) // Deliberately omitted.
1160b57cec5SDimitry Andric     FLAG(mayStore)
1170b57cec5SDimitry Andric     //FLAG(mayStore_Unset) // Deliberately omitted.
1180b57cec5SDimitry Andric     FLAG(isPredicable)
1190b57cec5SDimitry Andric     FLAG(isConvertibleToThreeAddress)
1200b57cec5SDimitry Andric     FLAG(isCommutable)
1210b57cec5SDimitry Andric     FLAG(isTerminator)
1220b57cec5SDimitry Andric     FLAG(isReMaterializable)
1230b57cec5SDimitry Andric     FLAG(hasDelaySlot)
1240b57cec5SDimitry Andric     FLAG(usesCustomInserter)
1250b57cec5SDimitry Andric     FLAG(hasPostISelHook)
1260b57cec5SDimitry Andric     FLAG(hasCtrlDep)
1270b57cec5SDimitry Andric     FLAG(isNotDuplicable)
1280b57cec5SDimitry Andric     FLAG(hasSideEffects)
1290b57cec5SDimitry Andric     //FLAG(hasSideEffects_Unset) // Deliberately omitted.
1300b57cec5SDimitry Andric     FLAG(isAsCheapAsAMove)
1310b57cec5SDimitry Andric     FLAG(hasExtraSrcRegAllocReq)
1320b57cec5SDimitry Andric     FLAG(hasExtraDefRegAllocReq)
1330b57cec5SDimitry Andric     FLAG(isCodeGenOnly)
1340b57cec5SDimitry Andric     FLAG(isPseudo)
1350b57cec5SDimitry Andric     FLAG(isRegSequence)
1360b57cec5SDimitry Andric     FLAG(isExtractSubreg)
1370b57cec5SDimitry Andric     FLAG(isInsertSubreg)
1380b57cec5SDimitry Andric     FLAG(isConvergent)
1390b57cec5SDimitry Andric     FLAG(hasNoSchedulingInfo)
1400b57cec5SDimitry Andric     FLAG(variadicOpsAreDefs)
141*480093f4SDimitry Andric     FLAG(isAuthenticated)
1420b57cec5SDimitry Andric     if (!FlagStrings.empty()) {
1430b57cec5SDimitry Andric       OS << "Flags: ";
1440b57cec5SDimitry Andric       bool IsFirst = true;
1450b57cec5SDimitry Andric       for (auto FlagString : FlagStrings) {
1460b57cec5SDimitry Andric         if (!IsFirst)
1470b57cec5SDimitry Andric           OS << ", ";
1480b57cec5SDimitry Andric         OS << "``" << FlagString << "``";
1490b57cec5SDimitry Andric         IsFirst = false;
1500b57cec5SDimitry Andric       }
1510b57cec5SDimitry Andric       OS << "\n\n";
1520b57cec5SDimitry Andric     }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric     // Operands.
1550b57cec5SDimitry Andric     for (unsigned i = 0; i < II->Operands.size(); ++i) {
1560b57cec5SDimitry Andric       bool IsDef = i < II->Operands.NumDefs;
1570b57cec5SDimitry Andric       auto Op = II->Operands[i];
1580b57cec5SDimitry Andric 
1590b57cec5SDimitry Andric       if (Op.MINumOperands > 1) {
1600b57cec5SDimitry Andric         // This operand corresponds to multiple operands on the
1610b57cec5SDimitry Andric         // MachineInstruction, so print all of them, showing the types and
1620b57cec5SDimitry Andric         // names of both the compound operand and the basic operands it
1630b57cec5SDimitry Andric         // contains.
1640b57cec5SDimitry Andric         for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {
1650b57cec5SDimitry Andric           Record *SubRec =
1660b57cec5SDimitry Andric               cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();
1670b57cec5SDimitry Andric           StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx);
1680b57cec5SDimitry Andric           StringRef SubOpTypeName = SubRec->getName();
1690b57cec5SDimitry Andric 
1700b57cec5SDimitry Andric           OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
1710b57cec5SDimitry Andric              << "/" << SubOpTypeName << ":$" << Op.Name << ".";
1720b57cec5SDimitry Andric           // Not all sub-operands are named, make up a name for these.
1730b57cec5SDimitry Andric           if (SubOpName.empty())
1740b57cec5SDimitry Andric             OS << "anon" << SubOpIdx;
1750b57cec5SDimitry Andric           else
1760b57cec5SDimitry Andric             OS << SubOpName;
1770b57cec5SDimitry Andric           OS << "``\n\n";
1780b57cec5SDimitry Andric         }
1790b57cec5SDimitry Andric       } else {
1800b57cec5SDimitry Andric         // The operand corresponds to only one MachineInstruction operand.
1810b57cec5SDimitry Andric         OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
1820b57cec5SDimitry Andric            << ":$" << Op.Name << "``\n\n";
1830b57cec5SDimitry Andric       }
1840b57cec5SDimitry Andric     }
1850b57cec5SDimitry Andric 
1860b57cec5SDimitry Andric     // Constraints.
1870b57cec5SDimitry Andric     StringRef Constraints = Inst->getValueAsString("Constraints");
1880b57cec5SDimitry Andric     if (!Constraints.empty()) {
1890b57cec5SDimitry Andric       OS << "Constraints: ``" << Constraints << "``\n\n";
1900b57cec5SDimitry Andric     }
1910b57cec5SDimitry Andric 
1920b57cec5SDimitry Andric     // Implicit definitions.
1930b57cec5SDimitry Andric     if (!II->ImplicitDefs.empty()) {
1940b57cec5SDimitry Andric       OS << "Implicit defs: ";
1950b57cec5SDimitry Andric       bool IsFirst = true;
1960b57cec5SDimitry Andric       for (Record *Def : II->ImplicitDefs) {
1970b57cec5SDimitry Andric         if (!IsFirst)
1980b57cec5SDimitry Andric           OS << ", ";
1990b57cec5SDimitry Andric         OS << "``" << Def->getName() << "``";
2000b57cec5SDimitry Andric         IsFirst = false;
2010b57cec5SDimitry Andric       }
2020b57cec5SDimitry Andric       OS << "\n\n";
2030b57cec5SDimitry Andric     }
2040b57cec5SDimitry Andric 
2050b57cec5SDimitry Andric     // Implicit uses.
2060b57cec5SDimitry Andric     if (!II->ImplicitUses.empty()) {
2070b57cec5SDimitry Andric       OS << "Implicit uses: ";
2080b57cec5SDimitry Andric       bool IsFirst = true;
2090b57cec5SDimitry Andric       for (Record *Use : II->ImplicitUses) {
2100b57cec5SDimitry Andric         if (!IsFirst)
2110b57cec5SDimitry Andric           OS << ", ";
2120b57cec5SDimitry Andric         OS << "``" << Use->getName() << "``";
2130b57cec5SDimitry Andric         IsFirst = false;
2140b57cec5SDimitry Andric       }
2150b57cec5SDimitry Andric       OS << "\n\n";
2160b57cec5SDimitry Andric     }
2170b57cec5SDimitry Andric 
2180b57cec5SDimitry Andric     // Predicates.
2190b57cec5SDimitry Andric     std::vector<Record *> Predicates =
2200b57cec5SDimitry Andric         II->TheDef->getValueAsListOfDefs("Predicates");
2210b57cec5SDimitry Andric     if (!Predicates.empty()) {
2220b57cec5SDimitry Andric       OS << "Predicates: ";
2230b57cec5SDimitry Andric       bool IsFirst = true;
2240b57cec5SDimitry Andric       for (Record *P : Predicates) {
2250b57cec5SDimitry Andric         if (!IsFirst)
2260b57cec5SDimitry Andric           OS << ", ";
2270b57cec5SDimitry Andric         OS << "``" << P->getName() << "``";
2280b57cec5SDimitry Andric         IsFirst = false;
2290b57cec5SDimitry Andric       }
2300b57cec5SDimitry Andric       OS << "\n\n";
2310b57cec5SDimitry Andric     }
2320b57cec5SDimitry Andric   }
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric 
2358bcb0991SDimitry Andric } // end namespace llvm
236