Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp
35258 views
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
29
using namespace llvm;
30
31
static 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
37
static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
38
OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
39
}
40
41
static 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':
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
64
static 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(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(escapeForRST(Inst->getName()), OS, '=');
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(VarNum);
90
OS << "Assembly string";
91
if (VariantCount != 1)
92
OS << " (" << AsmVariant->getValueAsString("Name") << ")";
93
std::string AsmString =
94
CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, 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(StringRef(AsmString).trim(" "))
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>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();
172
StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(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("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("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
228
static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
229
"Generate instruction documentation");
230
231