230 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// InstrDocsEmitter generates restructured text documentation for the opcodes10// that can be used by MachineInstr. For each opcode, the documentation lists:11// * Opcode name12// * Assembly string13// * Flags (e.g. mayLoad, isBranch, ...)14// * Operands, including type and name15// * Operand constraints16// * Implicit register uses & defs17// * Predicates18//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 29using namespace llvm;30 31static 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 37static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {38 OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";39}40 41static 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 64static void EmitInstrDocs(const RecordKeeper &RK, raw_ostream &OS) {65 const CodeGenDAGPatterns CDP(RK);66 const CodeGenTarget &Target = CDP.getTargetInfo();67 unsigned VariantCount = Target.getAsmParserVariantCount();68 69 // Page title.70 std::string Title = Target.getName().str();71 Title += " Instructions";72 writeTitle(Title, OS);73 OS << "\n";74 75 for (const CodeGenInstruction *II : Target.getInstructions()) {76 const 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 const 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 the96 // 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) #s106#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 const auto &Op = II->Operands[i];163 164 if (Op.MINumOperands > 1) {165 // This operand corresponds to multiple operands on the166 // MachineInstruction, so print all of them, showing the types and167 // names of both the compound operand and the basic operands it168 // contains.169 for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {170 const 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 else181 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 (const 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 (const Record *Use : II->ImplicitUses)211 OS << LS << "``" << Use->getName() << "``";212 OS << "\n\n";213 }214 215 // Predicates.216 std::vector<const Record *> Predicates =217 II->TheDef->getValueAsListOfDefs("Predicates");218 if (!Predicates.empty()) {219 OS << "Predicates: ";220 ListSeparator LS;221 for (const Record *P : Predicates)222 OS << LS << "``" << P->getName() << "``";223 OS << "\n\n";224 }225 }226}227 228static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,229 "Generate instruction documentation");230