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 "Common/CodeGenDAGPatterns.h"
22#include "Common/CodeGenInstruction.h"
23#include "Common/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(res_arg: 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':
48 Result += "\\n";
49 break;
50 case '\t':
51 Result += "\\t";
52 break;
53 // Underscore at the end of a line has a special meaning in rst.
54 case '_':
55 Result += "\\_";
56 break;
57 default:
58 Result += C;
59 }
60 }
61 return Result;
62}
63
64static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
65 CodeGenDAGPatterns CDP(RK);
66 CodeGenTarget &Target = CDP.getTargetInfo();
67 unsigned VariantCount = Target.getAsmParserVariantCount();
68
69 // Page title.
70 std::string Title = std::string(Target.getName());
71 Title += " Instructions";
72 writeTitle(Str: Title, OS);
73 OS << "\n";
74
75 for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
76 Record *Inst = II->TheDef;
77
78 // Don't print the target-independent instructions.
79 if (II->Namespace == "TargetOpcode")
80 continue;
81
82 // Heading (instruction name).
83 writeHeader(Str: escapeForRST(Str: Inst->getName()), OS, Kind: '=');
84 OS << "\n";
85
86 // Assembly string(s).
87 if (!II->AsmString.empty()) {
88 for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {
89 Record *AsmVariant = Target.getAsmParserVariant(i: VarNum);
90 OS << "Assembly string";
91 if (VariantCount != 1)
92 OS << " (" << AsmVariant->getValueAsString(FieldName: "Name") << ")";
93 std::string AsmString =
94 CodeGenInstruction::FlattenAsmStringVariants(AsmString: II->AsmString, Variant: VarNum);
95 // We trim spaces at each end of the asm string because rst needs the
96 // formatting backticks to be next to a non-whitespace character.
97 OS << ": ``" << escapeForRST(Str: StringRef(AsmString).trim(Chars: " "))
98 << "``\n\n";
99 }
100 }
101
102 // Boolean flags.
103 std::vector<const char *> FlagStrings;
104#define xstr(s) str(s)
105#define str(s) #s
106#define FLAG(f) \
107 if (II->f) { \
108 FlagStrings.push_back(str(f)); \
109 }
110 FLAG(isReturn)
111 FLAG(isEHScopeReturn)
112 FLAG(isBranch)
113 FLAG(isIndirectBranch)
114 FLAG(isCompare)
115 FLAG(isMoveImm)
116 FLAG(isBitcast)
117 FLAG(isSelect)
118 FLAG(isBarrier)
119 FLAG(isCall)
120 FLAG(isAdd)
121 FLAG(isTrap)
122 FLAG(canFoldAsLoad)
123 FLAG(mayLoad)
124 // FLAG(mayLoad_Unset) // Deliberately omitted.
125 FLAG(mayStore)
126 // FLAG(mayStore_Unset) // Deliberately omitted.
127 FLAG(isPredicable)
128 FLAG(isConvertibleToThreeAddress)
129 FLAG(isCommutable)
130 FLAG(isTerminator)
131 FLAG(isReMaterializable)
132 FLAG(hasDelaySlot)
133 FLAG(usesCustomInserter)
134 FLAG(hasPostISelHook)
135 FLAG(hasCtrlDep)
136 FLAG(isNotDuplicable)
137 FLAG(hasSideEffects)
138 // FLAG(hasSideEffects_Unset) // Deliberately omitted.
139 FLAG(isAsCheapAsAMove)
140 FLAG(hasExtraSrcRegAllocReq)
141 FLAG(hasExtraDefRegAllocReq)
142 FLAG(isCodeGenOnly)
143 FLAG(isPseudo)
144 FLAG(isRegSequence)
145 FLAG(isExtractSubreg)
146 FLAG(isInsertSubreg)
147 FLAG(isConvergent)
148 FLAG(hasNoSchedulingInfo)
149 FLAG(variadicOpsAreDefs)
150 FLAG(isAuthenticated)
151 if (!FlagStrings.empty()) {
152 OS << "Flags: ";
153 ListSeparator LS;
154 for (auto FlagString : FlagStrings)
155 OS << LS << "``" << FlagString << "``";
156 OS << "\n\n";
157 }
158
159 // Operands.
160 for (unsigned i = 0; i < II->Operands.size(); ++i) {
161 bool IsDef = i < II->Operands.NumDefs;
162 auto Op = II->Operands[i];
163
164 if (Op.MINumOperands > 1) {
165 // This operand corresponds to multiple operands on the
166 // MachineInstruction, so print all of them, showing the types and
167 // names of both the compound operand and the basic operands it
168 // contains.
169 for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {
170 Record *SubRec =
171 cast<DefInit>(Val: Op.MIOperandInfo->getArg(Num: SubOpIdx))->getDef();
172 StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(Num: SubOpIdx);
173 StringRef SubOpTypeName = SubRec->getName();
174
175 OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
176 << "/" << SubOpTypeName << ":$" << Op.Name << ".";
177 // Not all sub-operands are named, make up a name for these.
178 if (SubOpName.empty())
179 OS << "anon" << SubOpIdx;
180 else
181 OS << SubOpName;
182 OS << "``\n\n";
183 }
184 } else {
185 // The operand corresponds to only one MachineInstruction operand.
186 OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
187 << ":$" << Op.Name << "``\n\n";
188 }
189 }
190
191 // Constraints.
192 StringRef Constraints = Inst->getValueAsString(FieldName: "Constraints");
193 if (!Constraints.empty()) {
194 OS << "Constraints: ``" << Constraints << "``\n\n";
195 }
196
197 // Implicit definitions.
198 if (!II->ImplicitDefs.empty()) {
199 OS << "Implicit defs: ";
200 ListSeparator LS;
201 for (Record *Def : II->ImplicitDefs)
202 OS << LS << "``" << Def->getName() << "``";
203 OS << "\n\n";
204 }
205
206 // Implicit uses.
207 if (!II->ImplicitUses.empty()) {
208 OS << "Implicit uses: ";
209 ListSeparator LS;
210 for (Record *Use : II->ImplicitUses)
211 OS << LS << "``" << Use->getName() << "``";
212 OS << "\n\n";
213 }
214
215 // Predicates.
216 std::vector<Record *> Predicates =
217 II->TheDef->getValueAsListOfDefs(FieldName: "Predicates");
218 if (!Predicates.empty()) {
219 OS << "Predicates: ";
220 ListSeparator LS;
221 for (Record *P : Predicates)
222 OS << LS << "``" << P->getName() << "``";
223 OS << "\n\n";
224 }
225 }
226}
227
228static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
229 "Generate instruction documentation");
230