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
2019-01-23 01:31:04 +08:00
|
|
|
//===- 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;
|
|
|
|
|
2019-01-23 07:46:14 +08:00
|
|
|
// Emit the description by first aligning the text to the left per line (e.g.,
|
|
|
|
// removing the minimum indentation across the block) and then indenting by 4.
|
|
|
|
// This follows from the expectation that the description in the tablegen file
|
|
|
|
// is already formatted in a way the user wanted but has some additional
|
|
|
|
// indenting due to being nested in the op definition.
|
|
|
|
static void emitDescription(StringRef description, raw_ostream &os) {
|
|
|
|
// Determine the minimum number of spaces in a line.
|
|
|
|
size_t min_indent = -1;
|
|
|
|
StringRef remaining = description;
|
|
|
|
while (!remaining.empty()) {
|
|
|
|
auto split = remaining.split('\n');
|
|
|
|
size_t indent = split.first.find_first_not_of(" \t");
|
|
|
|
if (indent != StringRef::npos)
|
|
|
|
min_indent = std::min(indent, min_indent);
|
|
|
|
remaining = split.second;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Print out the description indented.
|
|
|
|
os << "\n";
|
|
|
|
remaining = description;
|
|
|
|
bool printed = false;
|
|
|
|
while (!remaining.empty()) {
|
|
|
|
auto split = remaining.split('\n');
|
|
|
|
if (split.second.empty()) {
|
|
|
|
// Skip last line with just spaces.
|
|
|
|
if (split.first.ltrim().empty())
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// Print empty new line without spaces if line only has spaces, unless no
|
|
|
|
// text has been emitted before.
|
|
|
|
if (split.first.ltrim().empty()) {
|
|
|
|
if (printed)
|
|
|
|
os << "\n";
|
|
|
|
} else {
|
|
|
|
os.indent(4) << split.first.substr(min_indent) << "\n";
|
|
|
|
printed = true;
|
|
|
|
}
|
|
|
|
remaining = split.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
2019-01-23 01:31:04 +08:00
|
|
|
static void emitOpDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
|
|
|
|
const auto &defs = recordKeeper.getAllDerivedDefinitions("Op");
|
|
|
|
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\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);
|
2019-01-30 01:27:04 +08:00
|
|
|
os << "## " << op.getOperationName() << " (" << op.getQualCppClassName()
|
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
2019-01-23 01:31:04 +08:00
|
|
|
<< ")";
|
|
|
|
|
|
|
|
// Emit summary & description of operator.
|
|
|
|
if (op.hasSummary())
|
|
|
|
os << "\n" << op.getSummary();
|
|
|
|
os << "\n";
|
|
|
|
if (op.hasDescription())
|
2019-01-23 07:46:14 +08:00
|
|
|
emitDescription(op.getDescription(), os);
|
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
2019-01-23 01:31:04 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
});
|