1//===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// InstrDocsEmitter generates restructured text documentation for the opcodes
10// that can be used by MachineInstr. For each opcode, the documentation lists:
11// * Opcode name
12// * Assembly string
13// * Flags (e.g. mayLoad, isBranch, ...)
14// * Operands, including type and name
15// * Operand constraints
16// * Implicit register uses & defs
17// * Predicates
18//
19//===----------------------------------------------------------------------===//
20
21#include "CodeGenDAGPatterns.h"
22#include "CodeGenInstruction.h"
23#include "CodeGenTarget.h"
24#include "llvm/TableGen/Record.h"
25#include "llvm/TableGen/TableGenBackend.h"
26#include <string>
27#include <vector>
28
29using namespace llvm;
30
31static void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
32  OS << std::string(Str.size(), Kind) << "\n"
33     << Str << "\n"
34     << std::string(Str.size(), Kind) << "\n";
35}
36
37static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
38  OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
39}
40
41static std::string escapeForRST(StringRef Str) {
42  std::string Result;
43  Result.reserve(Str.size() + 4);
44  for (char C : Str) {
45    switch (C) {
46    // We want special characters to be shown as their C escape codes.
47    case '\n': Result += "\\n"; break;
48    case '\t': Result += "\\t"; break;
49    // Underscore at the end of a line has a special meaning in rst.
50    case '_': Result += "\\_"; break;
51    default: Result += C;
52    }
53  }
54  return Result;
55}
56
57static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
58  CodeGenDAGPatterns CDP(RK);
59  CodeGenTarget &Target = CDP.getTargetInfo();
60  unsigned VariantCount = Target.getAsmParserVariantCount();
61
62  // Page title.
63  std::string Title = std::string(Target.getName());
64  Title += " Instructions";
65  writeTitle(Title, OS);
66  OS << "\n";
67
68  for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
69    Record *Inst = II->TheDef;
70
71    // Don't print the target-independent instructions.
72    if (II->Namespace == "TargetOpcode")
73      continue;
74
75    // Heading (instruction name).
76    writeHeader(escapeForRST(Inst->getName()), OS, '=');
77    OS << "\n";
78
79    // Assembly string(s).
80    if (!II->AsmString.empty()) {
81      for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {
82        Record *AsmVariant = Target.getAsmParserVariant(VarNum);
83        OS << "Assembly string";
84        if (VariantCount != 1)
85          OS << " (" << AsmVariant->getValueAsString("Name") << ")";
86        std::string AsmString =
87            CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum);
88        // We trim spaces at each end of the asm string because rst needs the
89        // formatting backticks to be next to a non-whitespace character.
90        OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" "))
91           << "``\n\n";
92      }
93    }
94
95    // Boolean flags.
96    std::vector<const char *> FlagStrings;
97#define xstr(s) str(s)
98#define str(s) #s
99#define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); }
100    FLAG(isReturn)
101    FLAG(isEHScopeReturn)
102    FLAG(isBranch)
103    FLAG(isIndirectBranch)
104    FLAG(isCompare)
105    FLAG(isMoveImm)
106    FLAG(isBitcast)
107    FLAG(isSelect)
108    FLAG(isBarrier)
109    FLAG(isCall)
110    FLAG(isAdd)
111    FLAG(isTrap)
112    FLAG(canFoldAsLoad)
113    FLAG(mayLoad)
114    //FLAG(mayLoad_Unset) // Deliberately omitted.
115    FLAG(mayStore)
116    //FLAG(mayStore_Unset) // Deliberately omitted.
117    FLAG(isPredicable)
118    FLAG(isConvertibleToThreeAddress)
119    FLAG(isCommutable)
120    FLAG(isTerminator)
121    FLAG(isReMaterializable)
122    FLAG(hasDelaySlot)
123    FLAG(usesCustomInserter)
124    FLAG(hasPostISelHook)
125    FLAG(hasCtrlDep)
126    FLAG(isNotDuplicable)
127    FLAG(hasSideEffects)
128    //FLAG(hasSideEffects_Unset) // Deliberately omitted.
129    FLAG(isAsCheapAsAMove)
130    FLAG(hasExtraSrcRegAllocReq)
131    FLAG(hasExtraDefRegAllocReq)
132    FLAG(isCodeGenOnly)
133    FLAG(isPseudo)
134    FLAG(isRegSequence)
135    FLAG(isExtractSubreg)
136    FLAG(isInsertSubreg)
137    FLAG(isConvergent)
138    FLAG(hasNoSchedulingInfo)
139    FLAG(variadicOpsAreDefs)
140    FLAG(isAuthenticated)
141    if (!FlagStrings.empty()) {
142      OS << "Flags: ";
143      ListSeparator LS;
144      for (auto FlagString : FlagStrings)
145        OS << LS << "``" << FlagString << "``";
146      OS << "\n\n";
147    }
148
149    // Operands.
150    for (unsigned i = 0; i < II->Operands.size(); ++i) {
151      bool IsDef = i < II->Operands.NumDefs;
152      auto Op = II->Operands[i];
153
154      if (Op.MINumOperands > 1) {
155        // This operand corresponds to multiple operands on the
156        // MachineInstruction, so print all of them, showing the types and
157        // names of both the compound operand and the basic operands it
158        // contains.
159        for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {
160          Record *SubRec =
161              cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();
162          StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx);
163          StringRef SubOpTypeName = SubRec->getName();
164
165          OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
166             << "/" << SubOpTypeName << ":$" << Op.Name << ".";
167          // Not all sub-operands are named, make up a name for these.
168          if (SubOpName.empty())
169            OS << "anon" << SubOpIdx;
170          else
171            OS << SubOpName;
172          OS << "``\n\n";
173        }
174      } else {
175        // The operand corresponds to only one MachineInstruction operand.
176        OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
177           << ":$" << Op.Name << "``\n\n";
178      }
179    }
180
181    // Constraints.
182    StringRef Constraints = Inst->getValueAsString("Constraints");
183    if (!Constraints.empty()) {
184      OS << "Constraints: ``" << Constraints << "``\n\n";
185    }
186
187    // Implicit definitions.
188    if (!II->ImplicitDefs.empty()) {
189      OS << "Implicit defs: ";
190      ListSeparator LS;
191      for (Record *Def : II->ImplicitDefs)
192        OS << LS << "``" << Def->getName() << "``";
193      OS << "\n\n";
194    }
195
196    // Implicit uses.
197    if (!II->ImplicitUses.empty()) {
198      OS << "Implicit uses: ";
199      ListSeparator LS;
200      for (Record *Use : II->ImplicitUses)
201        OS << LS << "``" << Use->getName() << "``";
202      OS << "\n\n";
203    }
204
205    // Predicates.
206    std::vector<Record *> Predicates =
207        II->TheDef->getValueAsListOfDefs("Predicates");
208    if (!Predicates.empty()) {
209      OS << "Predicates: ";
210      ListSeparator LS;
211      for (Record *P : Predicates)
212        OS << LS << "``" << P->getName() << "``";
213      OS << "\n\n";
214    }
215  }
216}
217
218static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
219                                "Generate instruction documentation");
220