//===- InstrDocsEmitter.cpp - Opcode Documentation Generator --------------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // 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(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) 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