xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision a90b9d0159070121c221b966469c3e36d912bf82)
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 "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': 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;
52     }
53   }
54   return Result;
55 }
56 
57 static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
58   CodeGenDAGPatterns CDP(RK);
59   CodeGenTarget &Target = CDP.getTargetInfo();
60   unsigned VariantCount = Target.getAsmParserVariantCount();
61 
62   // Page title.
63   std::string Title = std::string(Target.getName());
64   Title += " Instructions";
65   writeTitle(Title, OS);
66   OS << "\n";
67 
68   for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
69     Record *Inst = II->TheDef;
70 
71     // Don't print the target-independent instructions.
72     if (II->Namespace == "TargetOpcode")
73       continue;
74 
75     // Heading (instruction name).
76     writeHeader(escapeForRST(Inst->getName()), OS, '=');
77     OS << "\n";
78 
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";
92       }
93     }
94 
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";
147     }
148 
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];
153 
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();
164 
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";
173         }
174       } else {
175         // The operand corresponds to only one MachineInstruction operand.
176         OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
177            << ":$" << Op.Name << "``\n\n";
178       }
179     }
180 
181     // Constraints.
182     StringRef Constraints = Inst->getValueAsString("Constraints");
183     if (!Constraints.empty()) {
184       OS << "Constraints: ``" << Constraints << "``\n\n";
185     }
186 
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";
194     }
195 
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";
203     }
204 
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";
214     }
215   }
216 }
217 
218 static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,
219                                 "Generate instruction documentation");
220