Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / llvm / utils / TableGen / InstrDocsEmitter.cpp
blob616e7b589288a2790a94e33cf88b9182821d1921
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
19 //===----------------------------------------------------------------------===//
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>
29 using namespace llvm;
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";
37 static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
38 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
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': 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;
54 return Result;
57 static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
58 CodeGenDAGPatterns CDP(RK);
59 CodeGenTarget &Target = CDP.getTargetInfo();
60 unsigned VariantCount = Target.getAsmParserVariantCount();
62 // Page title.
63 std::string Title = std::string(Target.getName());
64 Title += " Instructions";
65 writeTitle(Title, OS);
66 OS << "\n";
68 for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
69 Record *Inst = II->TheDef;
71 // Don't print the target-independent instructions.
72 if (II->Namespace == "TargetOpcode")
73 continue;
75 // Heading (instruction name).
76 writeHeader(escapeForRST(Inst->getName()), OS, '=');
77 OS << "\n";
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";
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";
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];
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();
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";
174 } else {
175 // The operand corresponds to only one MachineInstruction operand.
176 OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
177 << ":$" << Op.Name << "``\n\n";
181 // Constraints.
182 StringRef Constraints = Inst->getValueAsString("Constraints");
183 if (!Constraints.empty()) {
184 OS << "Constraints: ``" << Constraints << "``\n\n";
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";
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";
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";
218 static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
219 "Generate instruction documentation");