xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision 6be3386466ab79a84b48429ae66244f21526d3df)
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 
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 
38 void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
39   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
40 }
41 
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 
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