235 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			7.0 KiB
		
	
	
	
		
			C++
		
	
	
	
//===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
//
 | 
						|
// InstrDocsEmitter generates restructured text documentation for the opcodes
 | 
						|
// that can be used by MachineInstr. For each opcode, the documentation lists:
 | 
						|
// * Opcode name
 | 
						|
// * Assembly string
 | 
						|
// * Flags (e.g. mayLoad, isBranch, ...)
 | 
						|
// * Operands, including type and name
 | 
						|
// * Operand constraints
 | 
						|
// * Implicit register uses & defs
 | 
						|
// * Predicates
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "CodeGenDAGPatterns.h"
 | 
						|
#include "CodeGenInstruction.h"
 | 
						|
#include "CodeGenTarget.h"
 | 
						|
#include "TableGenBackends.h"
 | 
						|
#include "llvm/TableGen/Record.h"
 | 
						|
#include <string>
 | 
						|
#include <vector>
 | 
						|
 | 
						|
using namespace llvm;
 | 
						|
 | 
						|
namespace llvm {
 | 
						|
 | 
						|
void writeTitle(StringRef Str, raw_ostream &OS, char Kind = '-') {
 | 
						|
  OS << std::string(Str.size(), Kind) << "\n" << Str << "\n"
 | 
						|
     << std::string(Str.size(), Kind) << "\n";
 | 
						|
}
 | 
						|
 | 
						|
void writeHeader(StringRef Str, raw_ostream &OS, char Kind = '-') {
 | 
						|
  OS << Str << "\n" << std::string(Str.size(), Kind) << "\n";
 | 
						|
}
 | 
						|
 | 
						|
std::string escapeForRST(StringRef Str) {
 | 
						|
  std::string Result;
 | 
						|
  Result.reserve(Str.size() + 4);
 | 
						|
  for (char C : Str) {
 | 
						|
    switch (C) {
 | 
						|
    // We want special characters to be shown as their C escape codes.
 | 
						|
    case '\n': Result += "\\n"; break;
 | 
						|
    case '\t': Result += "\\t"; break;
 | 
						|
    // Underscore at the end of a line has a special meaning in rst.
 | 
						|
    case '_': Result += "\\_"; break;
 | 
						|
    default: Result += C;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return Result;
 | 
						|
}
 | 
						|
 | 
						|
void EmitInstrDocs(RecordKeeper &RK, raw_ostream &OS) {
 | 
						|
  CodeGenDAGPatterns CDP(RK);
 | 
						|
  CodeGenTarget &Target = CDP.getTargetInfo();
 | 
						|
  unsigned VariantCount = Target.getAsmParserVariantCount();
 | 
						|
 | 
						|
  // Page title.
 | 
						|
  std::string Title = Target.getName();
 | 
						|
  Title += " Instructions";
 | 
						|
  writeTitle(Title, OS);
 | 
						|
  OS << "\n";
 | 
						|
 | 
						|
  for (const CodeGenInstruction *II : Target.getInstructionsByEnumValue()) {
 | 
						|
    Record *Inst = II->TheDef;
 | 
						|
 | 
						|
    // Don't print the target-independent instructions.
 | 
						|
    if (II->Namespace == "TargetOpcode")
 | 
						|
      continue;
 | 
						|
 | 
						|
    // Heading (instruction name).
 | 
						|
    writeHeader(escapeForRST(Inst->getName()), OS, '=');
 | 
						|
    OS << "\n";
 | 
						|
 | 
						|
    // Assembly string(s).
 | 
						|
    if (!II->AsmString.empty()) {
 | 
						|
      for (unsigned VarNum = 0; VarNum < VariantCount; ++VarNum) {
 | 
						|
        Record *AsmVariant = Target.getAsmParserVariant(VarNum);
 | 
						|
        OS << "Assembly string";
 | 
						|
        if (VariantCount != 1)
 | 
						|
          OS << " (" << AsmVariant->getValueAsString("Name") << ")";
 | 
						|
        std::string AsmString =
 | 
						|
            CodeGenInstruction::FlattenAsmStringVariants(II->AsmString, VarNum);
 | 
						|
        // We trim spaces at each end of the asm string because rst needs the
 | 
						|
        // formatting backticks to be next to a non-whitespace character.
 | 
						|
        OS << ": ``" << escapeForRST(StringRef(AsmString).trim(" "))
 | 
						|
           << "``\n\n";
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Boolean flags.
 | 
						|
    std::vector<const char *> FlagStrings;
 | 
						|
#define xstr(s) str(s)
 | 
						|
#define str(s) #s
 | 
						|
#define FLAG(f) if (II->f) { FlagStrings.push_back(str(f)); }
 | 
						|
    FLAG(isReturn)
 | 
						|
    FLAG(isEHScopeReturn)
 | 
						|
    FLAG(isBranch)
 | 
						|
    FLAG(isIndirectBranch)
 | 
						|
    FLAG(isCompare)
 | 
						|
    FLAG(isMoveImm)
 | 
						|
    FLAG(isBitcast)
 | 
						|
    FLAG(isSelect)
 | 
						|
    FLAG(isBarrier)
 | 
						|
    FLAG(isCall)
 | 
						|
    FLAG(isAdd)
 | 
						|
    FLAG(isTrap)
 | 
						|
    FLAG(canFoldAsLoad)
 | 
						|
    FLAG(mayLoad)
 | 
						|
    //FLAG(mayLoad_Unset) // Deliberately omitted.
 | 
						|
    FLAG(mayStore)
 | 
						|
    //FLAG(mayStore_Unset) // Deliberately omitted.
 | 
						|
    FLAG(isPredicable)
 | 
						|
    FLAG(isConvertibleToThreeAddress)
 | 
						|
    FLAG(isCommutable)
 | 
						|
    FLAG(isTerminator)
 | 
						|
    FLAG(isReMaterializable)
 | 
						|
    FLAG(hasDelaySlot)
 | 
						|
    FLAG(usesCustomInserter)
 | 
						|
    FLAG(hasPostISelHook)
 | 
						|
    FLAG(hasCtrlDep)
 | 
						|
    FLAG(isNotDuplicable)
 | 
						|
    FLAG(hasSideEffects)
 | 
						|
    //FLAG(hasSideEffects_Unset) // Deliberately omitted.
 | 
						|
    FLAG(isAsCheapAsAMove)
 | 
						|
    FLAG(hasExtraSrcRegAllocReq)
 | 
						|
    FLAG(hasExtraDefRegAllocReq)
 | 
						|
    FLAG(isCodeGenOnly)
 | 
						|
    FLAG(isPseudo)
 | 
						|
    FLAG(isRegSequence)
 | 
						|
    FLAG(isExtractSubreg)
 | 
						|
    FLAG(isInsertSubreg)
 | 
						|
    FLAG(isConvergent)
 | 
						|
    FLAG(hasNoSchedulingInfo)
 | 
						|
    FLAG(variadicOpsAreDefs)
 | 
						|
    if (!FlagStrings.empty()) {
 | 
						|
      OS << "Flags: ";
 | 
						|
      bool IsFirst = true;
 | 
						|
      for (auto FlagString : FlagStrings) {
 | 
						|
        if (!IsFirst)
 | 
						|
          OS << ", ";
 | 
						|
        OS << "``" << FlagString << "``";
 | 
						|
        IsFirst = false;
 | 
						|
      }
 | 
						|
      OS << "\n\n";
 | 
						|
    }
 | 
						|
 | 
						|
    // Operands.
 | 
						|
    for (unsigned i = 0; i < II->Operands.size(); ++i) {
 | 
						|
      bool IsDef = i < II->Operands.NumDefs;
 | 
						|
      auto Op = II->Operands[i];
 | 
						|
 | 
						|
      if (Op.MINumOperands > 1) {
 | 
						|
        // This operand corresponds to multiple operands on the
 | 
						|
        // MachineInstruction, so print all of them, showing the types and
 | 
						|
        // names of both the compound operand and the basic operands it
 | 
						|
        // contains.
 | 
						|
        for (unsigned SubOpIdx = 0; SubOpIdx < Op.MINumOperands; ++SubOpIdx) {
 | 
						|
          Record *SubRec =
 | 
						|
              cast<DefInit>(Op.MIOperandInfo->getArg(SubOpIdx))->getDef();
 | 
						|
          StringRef SubOpName = Op.MIOperandInfo->getArgNameStr(SubOpIdx);
 | 
						|
          StringRef SubOpTypeName = SubRec->getName();
 | 
						|
 | 
						|
          OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
 | 
						|
             << "/" << SubOpTypeName << ":$" << Op.Name << ".";
 | 
						|
          // Not all sub-operands are named, make up a name for these.
 | 
						|
          if (SubOpName.empty())
 | 
						|
            OS << "anon" << SubOpIdx;
 | 
						|
          else
 | 
						|
            OS << SubOpName;
 | 
						|
          OS << "``\n\n";
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        // The operand corresponds to only one MachineInstruction operand.
 | 
						|
        OS << "* " << (IsDef ? "DEF" : "USE") << " ``" << Op.Rec->getName()
 | 
						|
           << ":$" << Op.Name << "``\n\n";
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    // Constraints.
 | 
						|
    StringRef Constraints = Inst->getValueAsString("Constraints");
 | 
						|
    if (!Constraints.empty()) {
 | 
						|
      OS << "Constraints: ``" << Constraints << "``\n\n";
 | 
						|
    }
 | 
						|
 | 
						|
    // Implicit definitions.
 | 
						|
    if (!II->ImplicitDefs.empty()) {
 | 
						|
      OS << "Implicit defs: ";
 | 
						|
      bool IsFirst = true;
 | 
						|
      for (Record *Def : II->ImplicitDefs) {
 | 
						|
        if (!IsFirst)
 | 
						|
          OS << ", ";
 | 
						|
        OS << "``" << Def->getName() << "``";
 | 
						|
        IsFirst = false;
 | 
						|
      }
 | 
						|
      OS << "\n\n";
 | 
						|
    }
 | 
						|
 | 
						|
    // Implicit uses.
 | 
						|
    if (!II->ImplicitUses.empty()) {
 | 
						|
      OS << "Implicit uses: ";
 | 
						|
      bool IsFirst = true;
 | 
						|
      for (Record *Use : II->ImplicitUses) {
 | 
						|
        if (!IsFirst)
 | 
						|
          OS << ", ";
 | 
						|
        OS << "``" << Use->getName() << "``";
 | 
						|
        IsFirst = false;
 | 
						|
      }
 | 
						|
      OS << "\n\n";
 | 
						|
    }
 | 
						|
 | 
						|
    // Predicates.
 | 
						|
    std::vector<Record *> Predicates =
 | 
						|
        II->TheDef->getValueAsListOfDefs("Predicates");
 | 
						|
    if (!Predicates.empty()) {
 | 
						|
      OS << "Predicates: ";
 | 
						|
      bool IsFirst = true;
 | 
						|
      for (Record *P : Predicates) {
 | 
						|
        if (!IsFirst)
 | 
						|
          OS << ", ";
 | 
						|
        OS << "``" << P->getName() << "``";
 | 
						|
        IsFirst = false;
 | 
						|
      }
 | 
						|
      OS << "\n\n";
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
} // end llvm namespace
 |