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 --------------===//
|
|
|
|
//
|
2020-01-26 11:58:30 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
2019-12-24 01:35:36 +08:00
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
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
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
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 uses the description of operations to generate documentation for the
|
|
|
|
// operations.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-25 03:45:11 +08:00
|
|
|
#include "DocGenUtilities.h"
|
2021-04-07 03:53:27 +08:00
|
|
|
#include "OpGenHelpers.h"
|
2020-10-04 06:17:38 +08:00
|
|
|
#include "mlir/Support/IndentedOstream.h"
|
2021-03-04 08:37:32 +08:00
|
|
|
#include "mlir/TableGen/AttrOrTypeDef.h"
|
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
|
|
|
#include "mlir/TableGen/GenInfo.h"
|
|
|
|
#include "mlir/TableGen/Operator.h"
|
2019-10-06 03:21:07 +08:00
|
|
|
#include "llvm/ADT/DenseMap.h"
|
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
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2021-04-15 09:04:59 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
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
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
2021-08-20 22:01:54 +08:00
|
|
|
#include "llvm/Support/Regex.h"
|
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
|
|
|
#include "llvm/Support/Signals.h"
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
|
|
|
2020-10-14 06:07:27 +08:00
|
|
|
#include <set>
|
|
|
|
|
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
|
|
|
using namespace llvm;
|
|
|
|
using namespace mlir;
|
2019-10-06 03:21:07 +08:00
|
|
|
using namespace mlir::tblgen;
|
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
|
|
|
|
|
|
|
using mlir::tblgen::Operator;
|
|
|
|
|
2021-04-15 09:04:59 +08:00
|
|
|
extern llvm::cl::opt<std::string> selectedDialect;
|
|
|
|
|
2019-01-30 02:28:56 +08:00
|
|
|
// Emit the description by aligning the text to the left per line (e.g.,
|
|
|
|
// removing the minimum indentation across the block).
|
|
|
|
//
|
|
|
|
// This expects 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.
|
2019-09-25 03:45:11 +08:00
|
|
|
void mlir::tblgen::emitDescription(StringRef description, raw_ostream &os) {
|
2020-10-04 06:17:38 +08:00
|
|
|
raw_indented_ostream ros(os);
|
2021-11-30 22:09:00 +08:00
|
|
|
ros.printReindented(description.rtrim(" \t"));
|
2019-01-23 07:46:14 +08:00
|
|
|
}
|
|
|
|
|
2019-10-06 03:21:07 +08:00
|
|
|
// Emits `str` with trailing newline if not empty.
|
|
|
|
static void emitIfNotEmpty(StringRef str, raw_ostream &os) {
|
|
|
|
if (!str.empty()) {
|
|
|
|
emitDescription(str, os);
|
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
}
|
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
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
/// Emit the given named constraint.
|
|
|
|
template <typename T>
|
|
|
|
static void emitNamedConstraint(const T &it, raw_ostream &os) {
|
|
|
|
if (!it.name.empty())
|
2021-11-11 08:09:43 +08:00
|
|
|
os << "| `" << it.name << "`";
|
2020-03-25 02:57:13 +08:00
|
|
|
else
|
|
|
|
os << "«unnamed»";
|
2021-01-07 06:08:03 +08:00
|
|
|
os << " | " << it.constraint.getSummary() << "\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
}
|
2019-10-30 04:38:32 +08:00
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Operation Documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
2019-10-06 03:21:07 +08:00
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
/// Emit the assembly format of an operation.
|
|
|
|
static void emitAssemblyFormat(StringRef opName, StringRef format,
|
|
|
|
raw_ostream &os) {
|
|
|
|
os << "\nSyntax:\n\n```\noperation ::= `" << opName << "` ";
|
|
|
|
|
|
|
|
// Print the assembly format aligned.
|
|
|
|
unsigned indent = strlen("operation ::= ");
|
|
|
|
std::pair<StringRef, StringRef> split = format.split('\n');
|
|
|
|
os << split.first.trim() << "\n";
|
|
|
|
do {
|
|
|
|
split = split.second.split('\n');
|
|
|
|
StringRef formatChunk = split.first.trim();
|
|
|
|
if (!formatChunk.empty())
|
|
|
|
os.indent(indent) << formatChunk << "\n";
|
|
|
|
} while (!split.second.empty());
|
|
|
|
os << "```\n\n";
|
|
|
|
}
|
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
|
|
|
|
2022-01-02 09:26:44 +08:00
|
|
|
static void emitOpTraitsDoc(const Operator &op, raw_ostream &os) {
|
2021-11-11 08:09:43 +08:00
|
|
|
// TODO: We should link to the trait/documentation of it. That also means we
|
|
|
|
// should add descriptions to traits that can be queried.
|
|
|
|
// Collect using set to sort effects, interfaces & traits.
|
|
|
|
std::set<std::string> effects, interfaces, traits;
|
|
|
|
for (auto &trait : op.getTraits()) {
|
2021-11-11 10:18:36 +08:00
|
|
|
if (isa<PredTrait>(&trait))
|
2021-11-11 08:09:43 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
std::string name = trait.getDef().getName().str();
|
|
|
|
StringRef ref = name;
|
|
|
|
StringRef traitName = trait.getDef().getValueAsString("trait");
|
|
|
|
traitName.consume_back("::Trait");
|
|
|
|
traitName.consume_back("::Impl");
|
|
|
|
if (ref.startswith("anonymous_"))
|
|
|
|
name = traitName.str();
|
2021-11-11 10:18:36 +08:00
|
|
|
if (isa<InterfaceTrait>(&trait)) {
|
2021-11-11 08:09:43 +08:00
|
|
|
if (trait.getDef().isSubClassOf("SideEffectsTraitBase")) {
|
|
|
|
auto effectName = trait.getDef().getValueAsString("baseEffectName");
|
|
|
|
effectName.consume_front("::");
|
|
|
|
effectName.consume_front("mlir::");
|
|
|
|
std::string effectStr;
|
|
|
|
llvm::raw_string_ostream os(effectStr);
|
|
|
|
os << effectName << "{";
|
|
|
|
auto list = trait.getDef().getValueAsListOfDefs("effects");
|
|
|
|
llvm::interleaveComma(list, os, [&](Record *rec) {
|
|
|
|
StringRef effect = rec->getValueAsString("effect");
|
|
|
|
effect.consume_front("::");
|
|
|
|
effect.consume_front("mlir::");
|
|
|
|
os << effect << " on " << rec->getValueAsString("resource");
|
|
|
|
});
|
|
|
|
os << "}";
|
|
|
|
effects.insert(os.str());
|
|
|
|
name.append(llvm::formatv(" ({0})", traitName).str());
|
|
|
|
}
|
|
|
|
interfaces.insert(name);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
traits.insert(name);
|
|
|
|
}
|
|
|
|
if (!traits.empty()) {
|
|
|
|
llvm::interleaveComma(traits, os << "\nTraits: ");
|
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
if (!interfaces.empty()) {
|
|
|
|
llvm::interleaveComma(interfaces, os << "\nInterfaces: ");
|
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
if (!effects.empty()) {
|
|
|
|
llvm::interleaveComma(effects, os << "\nEffects: ");
|
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
static void emitOpDoc(const Operator &op, raw_ostream &os) {
|
2020-03-25 02:57:13 +08:00
|
|
|
os << llvm::formatv("### `{0}` ({1})\n", op.getOperationName(),
|
|
|
|
op.getQualCppClassName());
|
|
|
|
|
|
|
|
// Emit the summary, syntax, and description if present.
|
|
|
|
if (op.hasSummary())
|
2020-10-04 06:17:38 +08:00
|
|
|
os << "\n" << op.getSummary() << "\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
if (op.hasAssemblyFormat())
|
|
|
|
emitAssemblyFormat(op.getOperationName(), op.getAssemblyFormat().trim(),
|
|
|
|
os);
|
|
|
|
if (op.hasDescription())
|
|
|
|
mlir::tblgen::emitDescription(op.getDescription(), os);
|
|
|
|
|
2021-11-11 08:09:43 +08:00
|
|
|
emitOpTraitsDoc(op, os);
|
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
// Emit attributes.
|
|
|
|
if (op.getNumAttributes() != 0) {
|
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
|
|
|
// TODO: Attributes are only documented by TableGen name, with no further
|
|
|
|
// info. This should be improved.
|
2019-11-06 01:31:35 +08:00
|
|
|
os << "\n#### Attributes:\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
os << "| Attribute | MLIR Type | Description |\n"
|
|
|
|
<< "| :-------: | :-------: | ----------- |\n";
|
|
|
|
for (const auto &it : op.getAttributes()) {
|
|
|
|
StringRef storageType = it.attr.getStorageType();
|
2021-11-11 08:09:43 +08:00
|
|
|
os << "| `" << it.name << "` | " << storageType << " | "
|
2021-01-07 06:08:03 +08:00
|
|
|
<< it.attr.getSummary() << "\n";
|
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
|
|
|
}
|
2020-03-25 02:57:13 +08:00
|
|
|
}
|
2019-01-30 02:28:56 +08:00
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
// Emit each of the operands.
|
|
|
|
if (op.getNumOperands() != 0) {
|
|
|
|
os << "\n#### Operands:\n\n";
|
|
|
|
os << "| Operand | Description |\n"
|
|
|
|
<< "| :-----: | ----------- |\n";
|
|
|
|
for (const auto &it : op.getOperands())
|
|
|
|
emitNamedConstraint(it, os);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Emit results.
|
|
|
|
if (op.getNumResults() != 0) {
|
2019-11-06 01:31:35 +08:00
|
|
|
os << "\n#### Results:\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
os << "| Result | Description |\n"
|
|
|
|
<< "| :----: | ----------- |\n";
|
|
|
|
for (const auto &it : op.getResults())
|
|
|
|
emitNamedConstraint(it, os);
|
|
|
|
}
|
2019-01-30 02:28:56 +08:00
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
// Emit successors.
|
|
|
|
if (op.getNumSuccessors() != 0) {
|
|
|
|
os << "\n#### Successors:\n\n";
|
|
|
|
os << "| Successor | Description |\n"
|
|
|
|
<< "| :-------: | ----------- |\n";
|
|
|
|
for (const auto &it : op.getSuccessors())
|
|
|
|
emitNamedConstraint(it, 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
|
|
|
}
|
2020-03-25 02:57:13 +08:00
|
|
|
|
|
|
|
os << "\n";
|
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
|
|
|
}
|
|
|
|
|
2019-10-06 03:21:07 +08:00
|
|
|
static void emitOpDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
|
2021-04-07 03:53:27 +08:00
|
|
|
auto opDefs = getRequestedOpDefinitions(recordKeeper);
|
2020-03-25 02:57:13 +08:00
|
|
|
|
|
|
|
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
|
|
|
|
for (const llvm::Record *opDef : opDefs)
|
|
|
|
emitOpDoc(Operator(opDef), os);
|
|
|
|
}
|
|
|
|
|
2022-04-04 20:24:54 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Attribute Documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static void emitAttrDoc(const Attribute &attr, raw_ostream &os) {
|
|
|
|
os << "### " << attr.getSummary() << "\n\n";
|
|
|
|
emitDescription(attr.getDescription(), os);
|
|
|
|
os << "\n\n";
|
|
|
|
}
|
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Type Documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
static void emitTypeDoc(const Type &type, raw_ostream &os) {
|
2022-04-04 20:24:54 +08:00
|
|
|
os << "### " << type.getSummary() << "\n\n";
|
2021-01-07 06:08:03 +08:00
|
|
|
emitDescription(type.getDescription(), os);
|
2022-04-04 20:24:54 +08:00
|
|
|
os << "\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
}
|
|
|
|
|
2020-10-14 06:07:27 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TypeDef Documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
static void emitAttrOrTypeDefAssemblyFormat(const AttrOrTypeDef &def,
|
|
|
|
raw_ostream &os) {
|
2021-11-30 22:09:00 +08:00
|
|
|
ArrayRef<AttrOrTypeParameter> parameters = def.getParameters();
|
2021-03-20 09:19:16 +08:00
|
|
|
if (parameters.empty()) {
|
|
|
|
os << "\nSyntax: `!" << def.getDialect().getName() << "."
|
|
|
|
<< def.getMnemonic() << "`\n";
|
2020-10-14 06:07:27 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
os << "\nSyntax:\n\n```\n!" << def.getDialect().getName() << "."
|
|
|
|
<< def.getMnemonic() << "<\n";
|
2021-12-24 06:13:06 +08:00
|
|
|
for (const auto &it : llvm::enumerate(parameters)) {
|
2021-03-20 09:19:16 +08:00
|
|
|
const AttrOrTypeParameter ¶m = it.value();
|
|
|
|
os << " " << param.getSyntax();
|
|
|
|
if (it.index() < (parameters.size() - 1))
|
2020-10-14 06:07:27 +08:00
|
|
|
os << ",";
|
2021-03-20 09:19:16 +08:00
|
|
|
os << " # " << param.getName() << "\n";
|
2020-10-14 06:07:27 +08:00
|
|
|
}
|
|
|
|
os << ">\n```\n";
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
static void emitAttrOrTypeDefDoc(const AttrOrTypeDef &def, raw_ostream &os) {
|
|
|
|
os << llvm::formatv("### {0}\n", def.getCppClassName());
|
2020-10-14 06:07:27 +08:00
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
// Emit the summary if present.
|
|
|
|
if (def.hasSummary())
|
|
|
|
os << "\n" << def.getSummary() << "\n";
|
|
|
|
|
|
|
|
// Emit the syntax if present.
|
2022-03-12 11:02:53 +08:00
|
|
|
if (def.getMnemonic() && !def.hasCustomAssemblyFormat())
|
2021-03-20 09:19:16 +08:00
|
|
|
emitAttrOrTypeDefAssemblyFormat(def, os);
|
|
|
|
|
|
|
|
// Emit the description if present.
|
|
|
|
if (def.hasDescription()) {
|
2021-02-23 18:30:25 +08:00
|
|
|
os << "\n";
|
2021-03-20 09:19:16 +08:00
|
|
|
mlir::tblgen::emitDescription(def.getDescription(), os);
|
2021-02-23 18:30:25 +08:00
|
|
|
}
|
2020-10-14 06:07:27 +08:00
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
// Emit parameter documentation.
|
2021-11-30 22:09:00 +08:00
|
|
|
ArrayRef<AttrOrTypeParameter> parameters = def.getParameters();
|
2021-01-07 06:08:03 +08:00
|
|
|
if (!parameters.empty()) {
|
2021-03-20 09:19:16 +08:00
|
|
|
os << "\n#### Parameters:\n\n";
|
2020-10-14 06:07:27 +08:00
|
|
|
os << "| Parameter | C++ type | Description |\n"
|
|
|
|
<< "| :-------: | :-------: | ----------- |\n";
|
|
|
|
for (const auto &it : parameters) {
|
2021-01-07 06:08:03 +08:00
|
|
|
auto desc = it.getSummary();
|
2021-02-23 18:30:25 +08:00
|
|
|
os << "| " << it.getName() << " | `" << it.getCppType() << "` | "
|
2020-10-14 06:07:27 +08:00
|
|
|
<< (desc ? *desc : "") << " |\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
os << "\n";
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
static void emitAttrOrTypeDefDoc(const RecordKeeper &recordKeeper,
|
|
|
|
raw_ostream &os, StringRef recordTypeName) {
|
|
|
|
std::vector<llvm::Record *> defs =
|
|
|
|
recordKeeper.getAllDerivedDefinitions(recordTypeName);
|
|
|
|
|
|
|
|
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
|
|
|
|
for (const llvm::Record *def : defs)
|
|
|
|
emitAttrOrTypeDefDoc(AttrOrTypeDef(def), os);
|
|
|
|
}
|
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Dialect Documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-04-04 20:24:54 +08:00
|
|
|
static void emitDialectDoc(const Dialect &dialect,
|
|
|
|
ArrayRef<Attribute> attributes,
|
|
|
|
ArrayRef<AttrDef> attrDefs, ArrayRef<Operator> ops,
|
|
|
|
ArrayRef<Type> types, ArrayRef<TypeDef> typeDefs,
|
|
|
|
raw_ostream &os) {
|
2021-04-15 09:04:59 +08:00
|
|
|
if (selectedDialect.getNumOccurrences() &&
|
|
|
|
dialect.getName() != selectedDialect)
|
|
|
|
return;
|
2021-03-20 09:19:16 +08:00
|
|
|
os << "# '" << dialect.getName() << "' Dialect\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
emitIfNotEmpty(dialect.getSummary(), os);
|
|
|
|
emitIfNotEmpty(dialect.getDescription(), os);
|
|
|
|
|
2021-08-20 22:01:54 +08:00
|
|
|
// Generate a TOC marker except if description already contains one.
|
|
|
|
llvm::Regex r("^[[:space:]]*\\[TOC\\]$", llvm::Regex::RegexFlags::Newline);
|
|
|
|
if (!r.match(dialect.getDescription()))
|
|
|
|
os << "[TOC]\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
|
2022-04-04 20:24:54 +08:00
|
|
|
if (!attributes.empty()) {
|
|
|
|
os << "## Attribute constraint definition\n\n";
|
|
|
|
for (const Attribute &attr : attributes)
|
|
|
|
emitAttrDoc(attr, os);
|
|
|
|
}
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
if (!attrDefs.empty()) {
|
|
|
|
os << "## Attribute definition\n\n";
|
|
|
|
for (const AttrDef &def : attrDefs)
|
|
|
|
emitAttrOrTypeDefDoc(def, os);
|
|
|
|
}
|
|
|
|
|
2020-07-07 16:35:23 +08:00
|
|
|
// TODO: Add link between use and def for types
|
2020-03-25 02:57:13 +08:00
|
|
|
if (!types.empty()) {
|
2020-10-14 06:07:27 +08:00
|
|
|
os << "## Type constraint definition\n\n";
|
2020-03-25 02:57:13 +08:00
|
|
|
for (const Type &type : types)
|
|
|
|
emitTypeDoc(type, os);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ops.empty()) {
|
|
|
|
os << "## Operation definition\n\n";
|
|
|
|
for (const Operator &op : ops)
|
|
|
|
emitOpDoc(op, os);
|
|
|
|
}
|
2020-10-14 06:07:27 +08:00
|
|
|
|
|
|
|
if (!typeDefs.empty()) {
|
|
|
|
os << "## Type definition\n\n";
|
2021-03-20 09:19:16 +08:00
|
|
|
for (const TypeDef &def : typeDefs)
|
|
|
|
emitAttrOrTypeDefDoc(def, os);
|
2020-10-14 06:07:27 +08:00
|
|
|
}
|
2020-03-25 02:57:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void emitDialectDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
|
2021-04-07 03:53:27 +08:00
|
|
|
std::vector<Record *> opDefs = getRequestedOpDefinitions(recordKeeper);
|
2022-04-04 20:24:54 +08:00
|
|
|
std::vector<Record *> attrDefs =
|
|
|
|
recordKeeper.getAllDerivedDefinitionsIfDefined("DialectAttr");
|
2021-03-20 09:19:16 +08:00
|
|
|
std::vector<Record *> typeDefs =
|
2022-01-28 13:58:31 +08:00
|
|
|
recordKeeper.getAllDerivedDefinitionsIfDefined("DialectType");
|
2021-03-20 09:19:16 +08:00
|
|
|
std::vector<Record *> typeDefDefs =
|
2022-01-28 13:58:31 +08:00
|
|
|
recordKeeper.getAllDerivedDefinitionsIfDefined("TypeDef");
|
2021-03-20 09:19:16 +08:00
|
|
|
std::vector<Record *> attrDefDefs =
|
2022-01-28 13:58:31 +08:00
|
|
|
recordKeeper.getAllDerivedDefinitionsIfDefined("AttrDef");
|
2019-10-06 03:21:07 +08:00
|
|
|
|
2020-10-14 06:07:27 +08:00
|
|
|
std::set<Dialect> dialectsWithDocs;
|
2021-03-20 09:19:16 +08:00
|
|
|
|
2022-04-04 20:24:54 +08:00
|
|
|
llvm::StringMap<std::vector<Attribute>> dialectAttrs;
|
2021-03-20 09:19:16 +08:00
|
|
|
llvm::StringMap<std::vector<AttrDef>> dialectAttrDefs;
|
|
|
|
llvm::StringMap<std::vector<Operator>> dialectOps;
|
|
|
|
llvm::StringMap<std::vector<Type>> dialectTypes;
|
|
|
|
llvm::StringMap<std::vector<TypeDef>> dialectTypeDefs;
|
2022-04-04 20:24:54 +08:00
|
|
|
for (Record *attrDef : attrDefs) {
|
|
|
|
Attribute attr(attrDef);
|
|
|
|
if (const Dialect &dialect = attr.getDialect()) {
|
|
|
|
dialectAttrs[dialect.getName()].push_back(attr);
|
|
|
|
dialectsWithDocs.insert(dialect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (Record *attrDef : attrDefDefs) {
|
2021-03-20 09:19:16 +08:00
|
|
|
AttrDef attr(attrDef);
|
|
|
|
dialectAttrDefs[attr.getDialect().getName()].push_back(attr);
|
|
|
|
dialectsWithDocs.insert(attr.getDialect());
|
|
|
|
}
|
2022-04-04 20:24:54 +08:00
|
|
|
for (Record *opDef : opDefs) {
|
2019-10-07 23:40:29 +08:00
|
|
|
Operator op(opDef);
|
2021-03-20 09:19:16 +08:00
|
|
|
dialectOps[op.getDialect().getName()].push_back(op);
|
2020-10-14 06:07:27 +08:00
|
|
|
dialectsWithDocs.insert(op.getDialect());
|
2019-10-06 03:21:07 +08:00
|
|
|
}
|
2022-04-04 20:24:54 +08:00
|
|
|
for (Record *typeDef : typeDefs) {
|
2019-10-07 23:40:29 +08:00
|
|
|
Type type(typeDef);
|
2022-04-04 20:24:54 +08:00
|
|
|
if (const Dialect &dialect = type.getDialect()) {
|
2021-03-20 09:19:16 +08:00
|
|
|
dialectTypes[dialect.getName()].push_back(type);
|
2022-04-04 20:24:54 +08:00
|
|
|
dialectsWithDocs.insert(dialect);
|
|
|
|
}
|
2019-10-07 23:40:29 +08:00
|
|
|
}
|
2022-04-04 20:24:54 +08:00
|
|
|
for (Record *typeDef : typeDefDefs) {
|
2020-10-14 06:07:27 +08:00
|
|
|
TypeDef type(typeDef);
|
2021-03-20 09:19:16 +08:00
|
|
|
dialectTypeDefs[type.getDialect().getName()].push_back(type);
|
2020-10-14 06:07:27 +08:00
|
|
|
dialectsWithDocs.insert(type.getDialect());
|
|
|
|
}
|
2019-10-07 23:40:29 +08:00
|
|
|
|
|
|
|
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
|
2021-03-20 09:19:16 +08:00
|
|
|
for (const Dialect &dialect : dialectsWithDocs) {
|
|
|
|
StringRef dialectName = dialect.getName();
|
2022-04-04 20:24:54 +08:00
|
|
|
emitDialectDoc(dialect, dialectAttrs[dialectName],
|
|
|
|
dialectAttrDefs[dialectName], dialectOps[dialectName],
|
|
|
|
dialectTypes[dialectName], dialectTypeDefs[dialectName], os);
|
2021-03-20 09:19:16 +08:00
|
|
|
}
|
2019-10-06 03:21:07 +08:00
|
|
|
}
|
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Gen Registration
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
static mlir::GenRegistration
|
|
|
|
genAttrRegister("gen-attrdef-doc",
|
|
|
|
"Generate dialect attribute documentation",
|
|
|
|
[](const RecordKeeper &records, raw_ostream &os) {
|
|
|
|
emitAttrOrTypeDefDoc(records, os, "AttrDef");
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2020-03-25 02:57:13 +08:00
|
|
|
static mlir::GenRegistration
|
|
|
|
genOpRegister("gen-op-doc", "Generate dialect documentation",
|
|
|
|
[](const RecordKeeper &records, raw_ostream &os) {
|
|
|
|
emitOpDoc(records, os);
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
2021-03-20 09:19:16 +08:00
|
|
|
static mlir::GenRegistration
|
|
|
|
genTypeRegister("gen-typedef-doc", "Generate dialect type documentation",
|
|
|
|
[](const RecordKeeper &records, raw_ostream &os) {
|
|
|
|
emitAttrOrTypeDefDoc(records, os, "TypeDef");
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
|
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 mlir::GenRegistration
|
2020-03-25 02:57:13 +08:00
|
|
|
genRegister("gen-dialect-doc", "Generate dialect documentation",
|
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
|
|
|
[](const RecordKeeper &records, raw_ostream &os) {
|
2020-03-25 02:57:13 +08:00
|
|
|
emitDialectDoc(records, 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
|
|
|
return false;
|
|
|
|
});
|