brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.2 KiB · 7ca34ad Raw
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