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