xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // InstrDocsEmitter generates restructured text documentation for the opcodes
10*0b57cec5SDimitry Andric // that can be used by MachineInstr. For each opcode, the documentation lists:
11*0b57cec5SDimitry Andric // * Opcode name
12*0b57cec5SDimitry Andric // * Assembly string
13*0b57cec5SDimitry Andric // * Flags (e.g. mayLoad, isBranch, ...)
14*0b57cec5SDimitry Andric // * Operands, including type and name
15*0b57cec5SDimitry Andric // * Operand constraints
16*0b57cec5SDimitry Andric // * Implicit register uses & defs
17*0b57cec5SDimitry Andric // * Predicates
18*0b57cec5SDimitry Andric //
19*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
20*0b57cec5SDimitry Andric 
21*0b57cec5SDimitry Andric #include "CodeGenDAGPatterns.h"
22*0b57cec5SDimitry Andric #include "CodeGenInstruction.h"
23*0b57cec5SDimitry Andric #include "CodeGenTarget.h"
24*0b57cec5SDimitry Andric #include "TableGenBackends.h"
25*0b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
26*0b57cec5SDimitry Andric #include <string>
27*0b57cec5SDimitry Andric #include <vector>
28*0b57cec5SDimitry Andric 
29*0b57cec5SDimitry Andric using namespace llvm;
30*0b57cec5SDimitry Andric 
31*0b57cec5SDimitry Andric namespace llvm {
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
34*0b57cec5SDimitry Andric   OS << std::string(Str.size(), Kind) << "\n" << Str << "\n"
35*0b57cec5SDimitry Andric      << std::string(Str.size(), Kind) << "\n";
36*0b57cec5SDimitry Andric }
37*0b57cec5SDimitry Andric 
38*0b57cec5SDimitry Andric void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
39*0b57cec5SDimitry Andric   OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
40*0b57cec5SDimitry Andric }
41*0b57cec5SDimitry Andric 
42*0b57cec5SDimitry Andric std::string escapeForRST(StringRef Str) {
43*0b57cec5SDimitry Andric   std::string Result;
44*0b57cec5SDimitry Andric   Result.reserve(Str.size() + 4);
45*0b57cec5SDimitry Andric   for (char C : Str) {
46*0b57cec5SDimitry Andric     switch (C) {
47*0b57cec5SDimitry Andric     // We want special characters to be shown as their C escape codes.
48*0b57cec5SDimitry Andric     case '\n': Result += "\\n"; break;
49*0b57cec5SDimitry Andric     case '\t': Result += "\\t"; break;
50*0b57cec5SDimitry Andric     // Underscore at the end of a line has a special meaning in rst.
51*0b57cec5SDimitry Andric     case '_': Result += "\\_"; break;
52*0b57cec5SDimitry Andric     default: Result += C;
53*0b57cec5SDimitry Andric     }
54*0b57cec5SDimitry Andric   }
55*0b57cec5SDimitry Andric   return Result;
56*0b57cec5SDimitry Andric }
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
59*0b57cec5SDimitry Andric   CodeGenDAGPatterns CDP(RK);
60*0b57cec5SDimitry Andric   CodeGenTarget &Target = CDP.getTargetInfo();
61*0b57cec5SDimitry Andric   unsigned VariantCount = Target.getAsmParserVariantCount();
62*0b57cec5SDimitry Andric 
63*0b57cec5SDimitry Andric   // Page title.
64*0b57cec5SDimitry Andric   std::string Title = Target.getName();
65*0b57cec5SDimitry Andric   Title += " Instructions";
66*0b57cec5SDimitry Andric   writeTitle(Title, OS);
67*0b57cec5SDimitry Andric   OS << "\n";
68*0b57cec5SDimitry Andric 
69*0b57cec5SDimitry Andric   for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
70*0b57cec5SDimitry Andric     Record *Inst = II->TheDef;
71*0b57cec5SDimitry Andric 
72*0b57cec5SDimitry Andric     // Don't print the target-independent instructions.
73*0b57cec5SDimitry Andric     if (II->Namespace == "TargetOpcode")
74*0b57cec5SDimitry Andric       continue;
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric     // Heading (instruction name).
77*0b57cec5SDimitry Andric     writeHeader(escapeForRST(Inst->getName()), OS, '=');
78*0b57cec5SDimitry Andric     OS << "\n";
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric     // Assembly string(s).
81*0b57cec5SDimitry Andric     if (!II->AsmString.empty()) {
82*0b57cec5SDimitry Andric       for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {
83*0b57cec5SDimitry Andric         Record *AsmVariant = Target.getAsmParserVariant(VarNum);
84*0b57cec5SDimitry Andric         OS << "Assembly string";
85*0b57cec5SDimitry Andric         if (VariantCount != 1)
86*0b57cec5SDimitry Andric           OS << " (" << AsmVariant->getValueAsString("Name") << ")";
87*0b57cec5SDimitry Andric         std::string AsmString =
88*0b57cec5SDimitry Andric             CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum);
89*0b57cec5SDimitry Andric         // We trim spaces at each end of the asm string because rst needs the
90*0b57cec5SDimitry Andric         // formatting backticks to be next to a non-whitespace character.
91*0b57cec5SDimitry Andric         OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" "))
92*0b57cec5SDimitry Andric            << "``\n\n";
93*0b57cec5SDimitry Andric       }
94*0b57cec5SDimitry Andric     }
95*0b57cec5SDimitry Andric 
96*0b57cec5SDimitry Andric     // Boolean flags.
97*0b57cec5SDimitry Andric     std::vector<const char *> FlagStrings;
98*0b57cec5SDimitry Andric #define xstr(s) str(s)
99*0b57cec5SDimitry Andric #define str(s) #s
100*0b57cec5SDimitry Andric #define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); }
101*0b57cec5SDimitry Andric     FLAG(isReturn)
102*0b57cec5SDimitry Andric     FLAG(isEHScopeReturn)
103*0b57cec5SDimitry Andric     FLAG(isBranch)
104*0b57cec5SDimitry Andric     FLAG(isIndirectBranch)
105*0b57cec5SDimitry Andric     FLAG(isCompare)
106*0b57cec5SDimitry Andric     FLAG(isMoveImm)
107*0b57cec5SDimitry Andric     FLAG(isBitcast)
108*0b57cec5SDimitry Andric     FLAG(isSelect)
109*0b57cec5SDimitry Andric     FLAG(isBarrier)
110*0b57cec5SDimitry Andric     FLAG(isCall)
111*0b57cec5SDimitry Andric     FLAG(isAdd)
112*0b57cec5SDimitry Andric     FLAG(isTrap)
113*0b57cec5SDimitry Andric     FLAG(canFoldAsLoad)
114*0b57cec5SDimitry Andric     FLAG(mayLoad)
115*0b57cec5SDimitry Andric     //FLAG(mayLoad_Unset) // Deliberately omitted.
116*0b57cec5SDimitry Andric     FLAG(mayStore)
117*0b57cec5SDimitry Andric     //FLAG(mayStore_Unset) // Deliberately omitted.
118*0b57cec5SDimitry Andric     FLAG(isPredicable)
119*0b57cec5SDimitry Andric     FLAG(isConvertibleToThreeAddress)
120*0b57cec5SDimitry Andric     FLAG(isCommutable)
121*0b57cec5SDimitry Andric     FLAG(isTerminator)
122*0b57cec5SDimitry Andric     FLAG(isReMaterializable)
123*0b57cec5SDimitry Andric     FLAG(hasDelaySlot)
124*0b57cec5SDimitry Andric     FLAG(usesCustomInserter)
125*0b57cec5SDimitry Andric     FLAG(hasPostISelHook)
126*0b57cec5SDimitry Andric     FLAG(hasCtrlDep)
127*0b57cec5SDimitry Andric     FLAG(isNotDuplicable)
128*0b57cec5SDimitry Andric     FLAG(hasSideEffects)
129*0b57cec5SDimitry Andric     //FLAG(hasSideEffects_Unset) // Deliberately omitted.
130*0b57cec5SDimitry Andric     FLAG(isAsCheapAsAMove)
131*0b57cec5SDimitry Andric     FLAG(hasExtraSrcRegAllocReq)
132*0b57cec5SDimitry Andric     FLAG(hasExtraDefRegAllocReq)
133*0b57cec5SDimitry Andric     FLAG(isCodeGenOnly)
134*0b57cec5SDimitry Andric     FLAG(isPseudo)
135*0b57cec5SDimitry Andric     FLAG(isRegSequence)
136*0b57cec5SDimitry Andric     FLAG(isExtractSubreg)
137*0b57cec5SDimitry Andric     FLAG(isInsertSubreg)
138*0b57cec5SDimitry Andric     FLAG(isConvergent)
139*0b57cec5SDimitry Andric     FLAG(hasNoSchedulingInfo)
140*0b57cec5SDimitry Andric     FLAG(variadicOpsAreDefs)
141*0b57cec5SDimitry Andric     if (!FlagStrings.empty()) {
142*0b57cec5SDimitry Andric       OS << "Flags: ";
143*0b57cec5SDimitry Andric       bool IsFirst = true;
144*0b57cec5SDimitry Andric       for (auto FlagString : FlagStrings) {
145*0b57cec5SDimitry Andric         if (!IsFirst)
146*0b57cec5SDimitry Andric           OS << ", ";
147*0b57cec5SDimitry Andric         OS << "``" << FlagString << "``";
148*0b57cec5SDimitry Andric         IsFirst = false;
149*0b57cec5SDimitry Andric       }
150*0b57cec5SDimitry Andric       OS << "\n\n";
151*0b57cec5SDimitry Andric     }
152*0b57cec5SDimitry Andric 
153*0b57cec5SDimitry Andric     // Operands.
154*0b57cec5SDimitry Andric     for (unsigned i = 0; i < II->Operands.size(); ++i) {
155*0b57cec5SDimitry Andric       bool IsDef = i < II->Operands.NumDefs;
156*0b57cec5SDimitry Andric       auto Op = II->Operands[i];
157*0b57cec5SDimitry Andric 
158*0b57cec5SDimitry Andric       if (Op.MINumOperands > 1) {
159*0b57cec5SDimitry Andric         // This operand corresponds to multiple operands on the
160*0b57cec5SDimitry Andric         // MachineInstruction, so print all of them, showing the types and
161*0b57cec5SDimitry Andric         // names of both the compound operand and the basic operands it
162*0b57cec5SDimitry Andric         // contains.
163*0b57cec5SDimitry Andric         for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {
164*0b57cec5SDimitry Andric           Record *SubRec =
165*0b57cec5SDimitry Andric               cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();
166*0b57cec5SDimitry Andric           StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx);
167*0b57cec5SDimitry Andric           StringRef SubOpTypeName = SubRec->getName();
168*0b57cec5SDimitry Andric 
169*0b57cec5SDimitry Andric           OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
170*0b57cec5SDimitry Andric              << "/" << SubOpTypeName << ":$" << Op.Name << ".";
171*0b57cec5SDimitry Andric           // Not all sub-operands are named, make up a name for these.
172*0b57cec5SDimitry Andric           if (SubOpName.empty())
173*0b57cec5SDimitry Andric             OS << "anon" << SubOpIdx;
174*0b57cec5SDimitry Andric           else
175*0b57cec5SDimitry Andric             OS << SubOpName;
176*0b57cec5SDimitry Andric           OS << "``\n\n";
177*0b57cec5SDimitry Andric         }
178*0b57cec5SDimitry Andric       } else {
179*0b57cec5SDimitry Andric         // The operand corresponds to only one MachineInstruction operand.
180*0b57cec5SDimitry Andric         OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
181*0b57cec5SDimitry Andric            << ":$" << Op.Name << "``\n\n";
182*0b57cec5SDimitry Andric       }
183*0b57cec5SDimitry Andric     }
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric     // Constraints.
186*0b57cec5SDimitry Andric     StringRef Constraints = Inst->getValueAsString("Constraints");
187*0b57cec5SDimitry Andric     if (!Constraints.empty()) {
188*0b57cec5SDimitry Andric       OS << "Constraints: ``" << Constraints << "``\n\n";
189*0b57cec5SDimitry Andric     }
190*0b57cec5SDimitry Andric 
191*0b57cec5SDimitry Andric     // Implicit definitions.
192*0b57cec5SDimitry Andric     if (!II->ImplicitDefs.empty()) {
193*0b57cec5SDimitry Andric       OS << "Implicit defs: ";
194*0b57cec5SDimitry Andric       bool IsFirst = true;
195*0b57cec5SDimitry Andric       for (Record *Def : II->ImplicitDefs) {
196*0b57cec5SDimitry Andric         if (!IsFirst)
197*0b57cec5SDimitry Andric           OS << ", ";
198*0b57cec5SDimitry Andric         OS << "``" << Def->getName() << "``";
199*0b57cec5SDimitry Andric         IsFirst = false;
200*0b57cec5SDimitry Andric       }
201*0b57cec5SDimitry Andric       OS << "\n\n";
202*0b57cec5SDimitry Andric     }
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric     // Implicit uses.
205*0b57cec5SDimitry Andric     if (!II->ImplicitUses.empty()) {
206*0b57cec5SDimitry Andric       OS << "Implicit uses: ";
207*0b57cec5SDimitry Andric       bool IsFirst = true;
208*0b57cec5SDimitry Andric       for (Record *Use : II->ImplicitUses) {
209*0b57cec5SDimitry Andric         if (!IsFirst)
210*0b57cec5SDimitry Andric           OS << ", ";
211*0b57cec5SDimitry Andric         OS << "``" << Use->getName() << "``";
212*0b57cec5SDimitry Andric         IsFirst = false;
213*0b57cec5SDimitry Andric       }
214*0b57cec5SDimitry Andric       OS << "\n\n";
215*0b57cec5SDimitry Andric     }
216*0b57cec5SDimitry Andric 
217*0b57cec5SDimitry Andric     // Predicates.
218*0b57cec5SDimitry Andric     std::vector<Record *> Predicates =
219*0b57cec5SDimitry Andric         II->TheDef->getValueAsListOfDefs("Predicates");
220*0b57cec5SDimitry Andric     if (!Predicates.empty()) {
221*0b57cec5SDimitry Andric       OS << "Predicates: ";
222*0b57cec5SDimitry Andric       bool IsFirst = true;
223*0b57cec5SDimitry Andric       for (Record *P : Predicates) {
224*0b57cec5SDimitry Andric         if (!IsFirst)
225*0b57cec5SDimitry Andric           OS << ", ";
226*0b57cec5SDimitry Andric         OS << "``" << P->getName() << "``";
227*0b57cec5SDimitry Andric         IsFirst = false;
228*0b57cec5SDimitry Andric       }
229*0b57cec5SDimitry Andric       OS << "\n\n";
230*0b57cec5SDimitry Andric     }
231*0b57cec5SDimitry Andric   }
232*0b57cec5SDimitry Andric }
233*0b57cec5SDimitry Andric 
234*0b57cec5SDimitry Andric } // end llvm namespace
235