From a280e3997e5627ca5d07a12966299d4d9dd42066 Mon Sep 17 00:00:00 2001 From: Jacques Pienaar Date: Tue, 22 Jan 2019 09:31:04 -0800 Subject: [PATCH] Start doc generation pass. Start doc generation pass that generates simple markdown output. The output is formatted simply[1] in markdown, but this allows seeing what info we have, where we can refine the op description (e.g., the inputs is probably redundant), what info is missing (e.g., the attributes could probably have a description). The formatting of the description is still left up to whatever was in the op definition (which luckily, due to the uniformity in the .td file, turned out well but relying on the indentation there is fragile). The mechanism to autogenerate these post changes has not been added yet either. The output file could be run through a markdown formatter too to remove extra spaces. [1]. This is not proposal for final style :) There could also be a discussion around single doc vs multiple (per dialect, per op), whether we want a TOC, whether operands/attributes should be headings or just formatted differently ... PiperOrigin-RevId: 230354538 --- mlir/include/mlir/TableGen/Operator.h | 6 ++ mlir/lib/TableGen/Operator.cpp | 16 ++++ mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp | 2 +- mlir/tools/mlir-tblgen/OpDocGen.cpp | 92 +++++++++++++++++++++ mlir/tools/mlir-tblgen/ReferenceImplGen.cpp | 14 ++-- mlir/tools/mlir-tblgen/RewriterGen.cpp | 2 +- 6 files changed, 123 insertions(+), 9 deletions(-) create mode 100644 mlir/tools/mlir-tblgen/OpDocGen.cpp diff --git a/mlir/include/mlir/TableGen/Operator.h b/mlir/include/mlir/TableGen/Operator.h index 6ee799d7158f..55b1e47e06ee 100644 --- a/mlir/include/mlir/TableGen/Operator.h +++ b/mlir/include/mlir/TableGen/Operator.h @@ -105,6 +105,12 @@ public: StringRef getArgName(int index) const; int getNumArgs() const { return operands.size() + attributes.size(); } + // Query functions for the documentation of the operator. + bool hasDescription() const; + StringRef getDescription() const; + bool hasSummary() const; + StringRef getSummary() const; + private: // Populates the operands and attributes. void populateOperandsAndAttributes(); diff --git a/mlir/lib/TableGen/Operator.cpp b/mlir/lib/TableGen/Operator.cpp index cec048f6c77d..5b1d2c423dc3 100644 --- a/mlir/lib/TableGen/Operator.cpp +++ b/mlir/lib/TableGen/Operator.cpp @@ -165,3 +165,19 @@ bool tblgen::Operator::Operand::hasMatcher() const { tblgen::TypeConstraint tblgen::Operator::Operand::getTypeConstraint() const { return tblgen::TypeConstraint(*defInit); } + +bool tblgen::Operator::hasDescription() const { + return def.getValue("description") != nullptr; +} + +StringRef tblgen::Operator::getDescription() const { + return def.getValueAsString("description"); +} + +bool tblgen::Operator::hasSummary() const { + return def.getValue("summary") != nullptr; +} + +StringRef tblgen::Operator::getSummary() const { + return def.getValueAsString("summary"); +} diff --git a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp index f361ff31109d..ead70a35deef 100644 --- a/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp +++ b/mlir/tools/mlir-tblgen/OpDefinitionsGen.cpp @@ -514,7 +514,7 @@ static void emitOpDefFile(const RecordKeeper &recordKeeper, raw_ostream &os) { os << "#undef ALL_OPS"; } -mlir::GenRegistration +static mlir::GenRegistration genOpDefinitions("gen-op-definitions", "Generate op definitions", [](const RecordKeeper &records, raw_ostream &os) { emitOpDefinitions(records, os); diff --git a/mlir/tools/mlir-tblgen/OpDocGen.cpp b/mlir/tools/mlir-tblgen/OpDocGen.cpp new file mode 100644 index 000000000000..870e31ec40b6 --- /dev/null +++ b/mlir/tools/mlir-tblgen/OpDocGen.cpp @@ -0,0 +1,92 @@ +//===- OpDocGen.cpp - MLIR operation documentation generator --------------===// +// +// Copyright 2019 The MLIR Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ============================================================================= +// +// OpDocGen uses the description of operations to generate documentation for the +// operations. +// +//===----------------------------------------------------------------------===// + +#include "mlir/TableGen/GenInfo.h" +#include "mlir/TableGen/Operator.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/FormatVariadic.h" +#include "llvm/Support/Signals.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; +using namespace mlir; + +using mlir::tblgen::Operator; + +static void emitOpDoc(const RecordKeeper &recordKeeper, raw_ostream &os) { + const auto &defs = recordKeeper.getAllDerivedDefinitions("Op"); + os << "\n"; + + // TODO: Group by dialect. + // TODO: Add docs for types used (maybe dialect specific ones?) and link + // between use and def. + os << "# Operation definition\n"; + for (auto *def : defs) { + Operator op(def); + os << "## " << op.getOperationName() << " (" << op.qualifiedCppClassName() + << ")"; + + // Emit summary & description of operator. + if (op.hasSummary()) + os << "\n" << op.getSummary(); + os << "\n"; + // TODO: Add line level reformatting to ensure spacing is as desired. + if (op.hasDescription()) + os << op.getDescription() << "\n"; + + // Emit operands & type of operand. All operands are numbered, some may be + // named too. + os << "\n### Operands:\n"; + for (auto operand : op.getOperands()) { + os << "1. "; + if (operand.name && !operand.name->getValue().empty()) + os << operand.name->getAsUnquotedString() << ": "; + else + os << "«unnamed»: "; + os << operand.defInit->getAsUnquotedString(); + os << "\n"; + } + + // Emit attributes. + // TODO: Attributes are only documented by TableGen name, with no further + // info. This should be improved. + os << "\n### Attributes:\n"; + for (auto namedAttr : op.getAttributes()) { + os << "- " << namedAttr.getName() << ": "; + if (namedAttr.attr.isDerivedAttr()) + os << "derived"; + else + os << namedAttr.attr.getTableGenDefName(); + os << "\n"; + } + os << "\n"; + } +} + +static mlir::GenRegistration + genRegister("gen-op-doc", "Generate operation documentation", + [](const RecordKeeper &records, raw_ostream &os) { + emitOpDoc(records, os); + return false; + }); diff --git a/mlir/tools/mlir-tblgen/ReferenceImplGen.cpp b/mlir/tools/mlir-tblgen/ReferenceImplGen.cpp index 244f23708eda..bd10594f6f37 100644 --- a/mlir/tools/mlir-tblgen/ReferenceImplGen.cpp +++ b/mlir/tools/mlir-tblgen/ReferenceImplGen.cpp @@ -91,10 +91,10 @@ static void emitReferenceImplementations(const RecordKeeper &recordKeeper, << "}\n"; } -mlir::GenRegistration genRegister("gen-reference-implementations", - "Generate reference implemenations", - [](const RecordKeeper &records, - raw_ostream &os) { - emitReferenceImplementations(records, os); - return false; - }); +static mlir::GenRegistration + genRegister("gen-reference-implementations", + "Generate reference implemenations", + [](const RecordKeeper &records, raw_ostream &os) { + emitReferenceImplementations(records, os); + return false; + }); diff --git a/mlir/tools/mlir-tblgen/RewriterGen.cpp b/mlir/tools/mlir-tblgen/RewriterGen.cpp index 4ffe5db1bd08..0dd6b13620d2 100644 --- a/mlir/tools/mlir-tblgen/RewriterGen.cpp +++ b/mlir/tools/mlir-tblgen/RewriterGen.cpp @@ -376,7 +376,7 @@ static void emitRewriters(const RecordKeeper &recordKeeper, raw_ostream &os) { os << "}\n"; } -mlir::GenRegistration +static mlir::GenRegistration genRewriters("gen-rewriters", "Generate pattern rewriters", [](const RecordKeeper &records, raw_ostream &os) { emitRewriters(records, os);