Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/InstrDocsEmitter.cpp
35258 views
//===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// InstrDocsEmitter generates restructured text documentation for the opcodes9// that can be used by MachineInstr. For each opcode, the documentation lists:10// * Opcode name11// * Assembly string12// * Flags (e.g. mayLoad, isBranch, ...)13// * Operands, including type and name14// * Operand constraints15// * Implicit register uses & defs16// * Predicates17//18//===----------------------------------------------------------------------===//1920#include "Common/CodeGenDAGPatterns.h"21#include "Common/CodeGenInstruction.h"22#include "Common/CodeGenTarget.h"23#include "llvm/TableGen/Record.h"24#include "llvm/TableGen/TableGenBackend.h"25#include <string>26#include <vector>2728using namespace llvm;2930static void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {31OS << std::string(Str.size(), Kind) << "\n"32<< Str << "\n"33<< std::string(Str.size(), Kind) << "\n";34}3536static void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {37OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";38}3940static std::string escapeForRST(StringRef Str) {41std::string Result;42Result.reserve(Str.size() + 4);43for (char C : Str) {44switch (C) {45// We want special characters to be shown as their C escape codes.46case '\n':47Result += "\\n";48break;49case '\t':50Result += "\\t";51break;52// Underscore at the end of a line has a special meaning in rst.53case '_':54Result += "\\_";55break;56default:57Result += C;58}59}60return Result;61}6263static void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {64CodeGenDAGPatterns CDP(RK);65CodeGenTarget &Target = CDP.getTargetInfo();66unsigned VariantCount = Target.getAsmParserVariantCount();6768// Page title.69std::string Title = std::string(Target.getName());70Title += " Instructions";71writeTitle(Title, OS);72OS << "\n";7374for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {75Record *Inst = II->TheDef;7677// Don't print the target-independent instructions.78if (II->Namespace == "TargetOpcode")79continue;8081// Heading (instruction name).82writeHeader(escapeForRST(Inst->getName()), OS, '=');83OS << "\n";8485// Assembly string(s).86if (!II->AsmString.empty()) {87for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {88Record *AsmVariant = Target.getAsmParserVariant(VarNum);89OS << "Assembly string";90if (VariantCount != 1)91OS << " (" << AsmVariant->getValueAsString("Name") << ")";92std::string AsmString =93CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum);94// We trim spaces at each end of the asm string because rst needs the95// formatting backticks to be next to a non-whitespace character.96OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" "))97<< "``\n\n";98}99}100101// Boolean flags.102std::vector<const char *> FlagStrings;103#define xstr(s) str(s)104#define str(s) #s105#define FLAG(f) \106if (II->f) { \107FlagStrings.push_back(str(f)); \108}109FLAG(isReturn)110FLAG(isEHScopeReturn)111FLAG(isBranch)112FLAG(isIndirectBranch)113FLAG(isCompare)114FLAG(isMoveImm)115FLAG(isBitcast)116FLAG(isSelect)117FLAG(isBarrier)118FLAG(isCall)119FLAG(isAdd)120FLAG(isTrap)121FLAG(canFoldAsLoad)122FLAG(mayLoad)123// FLAG(mayLoad_Unset) // Deliberately omitted.124FLAG(mayStore)125// FLAG(mayStore_Unset) // Deliberately omitted.126FLAG(isPredicable)127FLAG(isConvertibleToThreeAddress)128FLAG(isCommutable)129FLAG(isTerminator)130FLAG(isReMaterializable)131FLAG(hasDelaySlot)132FLAG(usesCustomInserter)133FLAG(hasPostISelHook)134FLAG(hasCtrlDep)135FLAG(isNotDuplicable)136FLAG(hasSideEffects)137// FLAG(hasSideEffects_Unset) // Deliberately omitted.138FLAG(isAsCheapAsAMove)139FLAG(hasExtraSrcRegAllocReq)140FLAG(hasExtraDefRegAllocReq)141FLAG(isCodeGenOnly)142FLAG(isPseudo)143FLAG(isRegSequence)144FLAG(isExtractSubreg)145FLAG(isInsertSubreg)146FLAG(isConvergent)147FLAG(hasNoSchedulingInfo)148FLAG(variadicOpsAreDefs)149FLAG(isAuthenticated)150if (!FlagStrings.empty()) {151OS << "Flags: ";152ListSeparator LS;153for (auto FlagString : FlagStrings)154OS << LS << "``" << FlagString << "``";155OS << "\n\n";156}157158// Operands.159for (unsigned i = 0; i < II->Operands.size(); ++i) {160bool IsDef = i < II->Operands.NumDefs;161auto Op = II->Operands[i];162163if (Op.MINumOperands > 1) {164// This operand corresponds to multiple operands on the165// MachineInstruction, so print all of them, showing the types and166// names of both the compound operand and the basic operands it167// contains.168for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {169Record *SubRec =170cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();171StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx);172StringRef SubOpTypeName = SubRec->getName();173174OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()175<< "/" << SubOpTypeName << ":$" << Op.Name << ".";176// Not all sub-operands are named, make up a name for these.177if (SubOpName.empty())178OS << "anon" << SubOpIdx;179else180OS << SubOpName;181OS << "``\n\n";182}183} else {184// The operand corresponds to only one MachineInstruction operand.185OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()186<< ":$" << Op.Name << "``\n\n";187}188}189190// Constraints.191StringRef Constraints = Inst->getValueAsString("Constraints");192if (!Constraints.empty()) {193OS << "Constraints: ``" << Constraints << "``\n\n";194}195196// Implicit definitions.197if (!II->ImplicitDefs.empty()) {198OS << "Implicit defs: ";199ListSeparator LS;200for (Record *Def : II->ImplicitDefs)201OS << LS << "``" << Def->getName() << "``";202OS << "\n\n";203}204205// Implicit uses.206if (!II->ImplicitUses.empty()) {207OS << "Implicit uses: ";208ListSeparator LS;209for (Record *Use : II->ImplicitUses)210OS << LS << "``" << Use->getName() << "``";211OS << "\n\n";212}213214// Predicates.215std::vector<Record *> Predicates =216II->TheDef->getValueAsListOfDefs("Predicates");217if (!Predicates.empty()) {218OS << "Predicates: ";219ListSeparator LS;220for (Record *P : Predicates)221OS << LS << "``" << P->getName() << "``";222OS << "\n\n";223}224}225}226227static TableGen::Emitter::Opt X("gen-instr-docs", EmitInstrDocs,228"Generate instruction documentation");229230231