xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 
writeTitle(StringRef Str,raw_ostream & OS,char Kind='-')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 
writeHeader(StringRef Str,raw_ostream & OS,char Kind='-')37 static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
38   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
39 }
40 
escapeForRST(StringRef Str)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 
EmitInstrDocs(RecordKeeper & RK,raw_ostream & OS)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