forked from OSchip/llvm-project
Allow attaching descriptions to OpInterfaces and InterfaceMethods.
This change adds support for documenting interfaces and their methods. A tablegen generator for the interface documentation is also added(gen-op-interface-doc). Documentation is added to an OpInterface via the `description` field: def MyOpInterface : OpInterface<"MyOpInterface"> { let description = [{ My interface is very interesting. }]; } Documentation is added to an InterfaceMethod via a new `description` field that comes right before the optional body: InterfaceMethod<"void", "foo", (ins), [{ This is the foo method. }]>, PiperOrigin-RevId: 270965485
This commit is contained in:
parent
458ede8775
commit
635544fc12
|
@ -298,10 +298,11 @@ of the boilerplate necessary.
|
|||
|
||||
Providing a definition of the `OpInterface` class will auto-generate the C++
|
||||
classes for the interface. An `OpInterface` includes a name, for the C++ class,
|
||||
along with a list of interface methods.
|
||||
a description, and a list of interface methods.
|
||||
|
||||
```tablegen
|
||||
def MyInterface : OpInterface<"MyInterface"> {
|
||||
let description = ...;
|
||||
let methods = [...];
|
||||
}
|
||||
```
|
||||
|
@ -313,6 +314,8 @@ static method on the derived operation.
|
|||
|
||||
An `InterfaceMethod` is comprised of the following components:
|
||||
|
||||
* Description
|
||||
- A string description of what this method does and its invariants.
|
||||
* ReturnType
|
||||
- A string corresponding to the C++ return type of the method.
|
||||
* MethodName
|
||||
|
@ -331,27 +334,38 @@ Examples:
|
|||
|
||||
```tablegen
|
||||
def MyInterface : OpInterface<"MyInterface"> {
|
||||
let description = [{
|
||||
My interface is very interesting. ...
|
||||
}];
|
||||
|
||||
let methods = [
|
||||
// A simple non-static method with no inputs.
|
||||
InterfaceMethod<"unsigned", "foo">,
|
||||
InterfaceMethod<"'foo' is a non-static method with no inputs.",
|
||||
"unsigned", "foo"
|
||||
>,
|
||||
|
||||
// A new non-static method accepting an input argument.
|
||||
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
|
||||
InterfaceMethod<"/*insert doc here*/",
|
||||
"Value *", "bar", (ins "unsigned":$i)
|
||||
>,
|
||||
|
||||
// Query a static property of the derived operation.
|
||||
StaticInterfaceMethod<"unsigned", "fooStatic">,
|
||||
StaticInterfaceMethod<"'fooStatic' is a static method with no inputs.",
|
||||
"unsigned", "fooStatic"
|
||||
>,
|
||||
|
||||
// Provide the definition of a static interface method.
|
||||
// Note: `ConcreteOp` corresponds to the derived operation typename.
|
||||
StaticInterfaceMethod<"Operation *", "create",
|
||||
(ins "OpBuilder &":$builder, "Location":$loc), [{
|
||||
StaticInterfaceMethod<"/*insert doc here*/",
|
||||
"Operation *", "create", (ins "OpBuilder &":$builder, "Location":$loc), [{
|
||||
return builder.create<ConcreteOp>(loc);
|
||||
}]>,
|
||||
|
||||
// Provide a definition of the non-static method.
|
||||
// Note: `op` corresponds to the derived operation variable.
|
||||
InterfaceMethod<"unsigned", "getNumInputsAndOutputs", (ins), [{
|
||||
return op.getNumInputs() + op.getNumOutputs();
|
||||
InterfaceMethod<"/*insert doc here*/",
|
||||
"unsigned", "getNumInputsAndOutputs", (ins), [{
|
||||
return op.getNumInputs() + op.getNumOutputs();
|
||||
}]>,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -34,35 +34,50 @@ include "mlir/IR/OpBase.td"
|
|||
// region. A callable is either a symbol, or an SSA value, that is referenced by
|
||||
// a call-like operation. This represents the destination of the call.
|
||||
|
||||
// A call-like operation is one who transfers control from one sub-routine to
|
||||
// another. These operations may be traditional direct calls `call @foo`, or
|
||||
// indirect calls to other operations `call_indirect %foo`.
|
||||
/// Interface for call-like operations.
|
||||
def CallOpInterface : OpInterface<"CallOpInterface"> {
|
||||
let description = [{
|
||||
A call-like operation is one that transfers control from one sub-routine to
|
||||
another. These operations may be traditional direct calls `call @foo`, or
|
||||
indirect calls to other operations `call_indirect %foo`.
|
||||
}];
|
||||
|
||||
let methods = [
|
||||
// Returns the callee of this call-like operation. A `callee` is either a
|
||||
// reference to a symbol, via SymbolRefAttr, or a reference to a defined SSA
|
||||
// value.
|
||||
InterfaceMethod<"CallInterfaceCallable", "getCallableForCallee">,
|
||||
InterfaceMethod<[{
|
||||
Returns the callee of this call-like operation. A `callee` is either a
|
||||
reference to a symbol, via SymbolRefAttr, or a reference to a defined
|
||||
SSA value.
|
||||
}],
|
||||
"CallInterfaceCallable", "getCallableForCallee"
|
||||
>,
|
||||
];
|
||||
}
|
||||
|
||||
// A callable operation is one who represents a potential sub-routine, and may
|
||||
// be a target for a call-like operation (those providing the CallOpInterface
|
||||
// above). These operations may be traditional functional operation
|
||||
// `func @foo(...)`, as well as function producing operations
|
||||
// `%foo = dialect.create_function(...)`. These operations may produce multiple
|
||||
// callable regions, or subroutines.
|
||||
/// Interface for callable operations.
|
||||
def CallableOpInterface : OpInterface<"CallableOpInterface"> {
|
||||
let methods = [
|
||||
// Returns a region on the current operation that the given callable refers
|
||||
// to. This may return null in the case of an external callable object, e.g.
|
||||
// an external function.
|
||||
InterfaceMethod<"Region *", "getCallableRegion",
|
||||
(ins "CallInterfaceCallable":$callable)>,
|
||||
let description = [{
|
||||
A callable operation is one who represents a potential sub-routine, and may
|
||||
be a target for a call-like operation (those providing the CallOpInterface
|
||||
above). These operations may be traditional functional operation
|
||||
`func @foo(...)`, as well as function producing operations
|
||||
`%foo = dialect.create_function(...)`. These operations may produce multiple
|
||||
callable regions, or subroutines.
|
||||
}];
|
||||
|
||||
// Returns all of the callable regions of this operation.
|
||||
InterfaceMethod<"void", "getCallableRegions",
|
||||
(ins "SmallVectorImpl<Region *> &":$callables)>,
|
||||
let methods = [
|
||||
InterfaceMethod<[{
|
||||
Returns a region on the current operation that the given callable refers
|
||||
to. This may return null in the case of an external callable object,
|
||||
e.g. an external function.
|
||||
}],
|
||||
"Region *", "getCallableRegion", (ins "CallInterfaceCallable":$callable)
|
||||
>,
|
||||
InterfaceMethod<[{
|
||||
Returns all of the callable regions of this operation
|
||||
}],
|
||||
"void", "getCallableRegions",
|
||||
(ins "SmallVectorImpl<Region *> &":$callables)
|
||||
>,
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -73,48 +73,102 @@ def ViewTraits : NativeOpTrait<"linalg::ViewTraits">;
|
|||
def LinalgLibraryInterface : OpInterface<"LinalgOp"> {
|
||||
let methods = [
|
||||
/// Query the number of inputs and outputs from the operation.
|
||||
InterfaceMethod<"unsigned", "getNumInputs">,
|
||||
InterfaceMethod<"unsigned", "getNumOutputs">,
|
||||
InterfaceMethod<"unsigned", "getNumInputsAndOutputs">,
|
||||
InterfaceMethod<"Operation::operand_range", "getInputs">,
|
||||
InterfaceMethod<"Operation::operand_range", "getOutputs">,
|
||||
InterfaceMethod<"Operation::operand_range", "getInputsAndOutputs">,
|
||||
InterfaceMethod<
|
||||
"Query the number of inputs from the current operation.",
|
||||
"unsigned", "getNumInputs"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the number of outputs from the current operation.",
|
||||
"unsigned", "getNumOutputs"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the number of inputs and outputs from the current operation.",
|
||||
"unsigned", "getNumInputsAndOutputs"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the input operands from the current operation.",
|
||||
"Operation::operand_range", "getInputs"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the output operands from the current operation.",
|
||||
"Operation::operand_range", "getOutputs"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the input and output operands from the current operation.",
|
||||
"Operation::operand_range", "getInputsAndOutputs"
|
||||
>,
|
||||
|
||||
/// Query the number of each type of loop.
|
||||
InterfaceMethod<"unsigned", "getNumParallelLoops">,
|
||||
InterfaceMethod<"unsigned", "getNumReductionLoops">,
|
||||
InterfaceMethod<"unsigned", "getNumWindowLoops">,
|
||||
InterfaceMethod<"unsigned", "getNumLoops", (ins), [{
|
||||
InterfaceMethod<
|
||||
"Query the number of parallel loops within the current operation.",
|
||||
"unsigned", "getNumParallelLoops"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the number of reduction loops within the current operation.",
|
||||
"unsigned", "getNumReductionLoops"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the number of window loops within the current operation.",
|
||||
"unsigned", "getNumWindowLoops"
|
||||
>,
|
||||
InterfaceMethod<
|
||||
"Query the number of loops within the current operation.",
|
||||
"unsigned", "getNumLoops", (ins), [{
|
||||
return op.getNumParallelLoops() + op.getNumReductionLoops() +
|
||||
op.getNumWindowLoops();
|
||||
}]>,
|
||||
|
||||
/// Get a specific input/output at the given index.
|
||||
InterfaceMethod<"Value *", "getInput", (ins "unsigned":$i)>,
|
||||
InterfaceMethod<"Value *", "getOutput", (ins "unsigned":$i)>,
|
||||
InterfaceMethod<"Query the input for the given index.",
|
||||
"Value *", "getInput", (ins "unsigned":$i)
|
||||
>,
|
||||
InterfaceMethod<"Query the output for the given index.",
|
||||
"Value *", "getOutput", (ins "unsigned":$i)
|
||||
>,
|
||||
|
||||
/// Get the index of the given value, or None if the value is not an input.
|
||||
InterfaceMethod<"llvm::Optional<unsigned>", "getIndexOfInput",
|
||||
(ins "Value *":$view)>,
|
||||
InterfaceMethod<"llvm::Optional<unsigned>", "getIndexOfOutput",
|
||||
(ins "Value *":$view)>,
|
||||
InterfaceMethod<[{
|
||||
Query the index of the given input value, or `None` if the value is not
|
||||
an input.
|
||||
}],
|
||||
"llvm::Optional<unsigned>", "getIndexOfInput", (ins "Value *":$view)
|
||||
>,
|
||||
InterfaceMethod<[{
|
||||
Query the index of the given view value, or `None` if the value is not
|
||||
an view.
|
||||
}],
|
||||
"llvm::Optional<unsigned>", "getIndexOfOutput", (ins "Value *":$view)
|
||||
>,
|
||||
|
||||
/// Get the view type of the input/output at the given index.
|
||||
InterfaceMethod<"ViewType", "getInputViewType", (ins "unsigned":$i)>,
|
||||
InterfaceMethod<"ViewType", "getOutputViewType", (ins "unsigned":$i)>,
|
||||
InterfaceMethod<"Query the view type for the given input.",
|
||||
"ViewType", "getInputViewType", (ins "unsigned":$i)
|
||||
>,
|
||||
InterfaceMethod<"Query the view type for the given output.",
|
||||
"ViewType", "getOutputViewType", (ins "unsigned":$i)
|
||||
>,
|
||||
|
||||
/// Create an operation with the given location and operands.
|
||||
StaticInterfaceMethod<"Operation *", "create",
|
||||
StaticInterfaceMethod<[{
|
||||
Create an operation of the current type with the given location,
|
||||
operands, and attributes.
|
||||
}],
|
||||
"Operation *", "create",
|
||||
(ins "OpBuilder &":$builder, "Location":$loc,
|
||||
"ArrayRef<Value *>":$operands,
|
||||
"ArrayRef<NamedAttribute>":$attributes), [{
|
||||
return builder.create<ConcreteOp>(loc, ArrayRef<Type>{}, operands,
|
||||
attributes);
|
||||
}]>,
|
||||
}]
|
||||
>,
|
||||
|
||||
/// Clone an operation with the given location and operands. This is used to
|
||||
/// abstract away the optional underlying region creation.
|
||||
InterfaceMethod<"Operation *", "clone",
|
||||
InterfaceMethod<[{
|
||||
Clone the current operation with the given location and operands. This
|
||||
is used to abstract away the optional underlying region creation.
|
||||
}],
|
||||
"Operation *", "clone",
|
||||
(ins "OpBuilder &":$b, "Location":$loc, "ArrayRef<Value *>":$operands), [{
|
||||
BlockAndValueMapping map;
|
||||
unsigned numRegions = op.getOperation()->getNumRegions();
|
||||
|
@ -124,7 +178,8 @@ def LinalgLibraryInterface : OpInterface<"LinalgOp"> {
|
|||
op.getOperation()->getRegion(ridx).cloneInto(
|
||||
&res->getRegion(ridx), map);
|
||||
return res;
|
||||
}]>
|
||||
}]
|
||||
>
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
@ -1255,8 +1255,11 @@ class OpInterfaceTrait<string name> : NativeOpTrait<""> {
|
|||
// This class represents a single, optionally static, interface method.
|
||||
// Note: non-static interface methods have an implicit 'op' parameter
|
||||
// corresponding to an instance of the derived operation.
|
||||
class InterfaceMethod<string retTy, string methodName,
|
||||
class InterfaceMethod<string desc, string retTy, string methodName,
|
||||
dag args = (ins), code methodBody = [{}]> {
|
||||
// A human-readable description of what this method does.
|
||||
string description = desc;
|
||||
|
||||
/// The name of the interface method.
|
||||
string name = methodName;
|
||||
|
||||
|
@ -1271,12 +1274,15 @@ class InterfaceMethod<string retTy, string methodName,
|
|||
}
|
||||
|
||||
// This class represents a single static interface method.
|
||||
class StaticInterfaceMethod<string retTy, string methodName,
|
||||
class StaticInterfaceMethod<string desc, string retTy, string methodName,
|
||||
dag args = (ins), code methodBody = [{}]>
|
||||
: InterfaceMethod<retTy, methodName, args, methodBody>;
|
||||
: InterfaceMethod<desc, retTy, methodName, args, methodBody>;
|
||||
|
||||
// OpInterface represents an interface regarding an op.
|
||||
class OpInterface<string name> : OpInterfaceTrait<name> {
|
||||
// A human-readable description of what this interface does.
|
||||
string description = "";
|
||||
|
||||
// The name given to the c++ interface class.
|
||||
string cppClassName = name;
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
//===- DocGenUtilities.h - MLIR doc gen utilities ---------------*- C++ -*-===//
|
||||
//
|
||||
// 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.
|
||||
// =============================================================================
|
||||
//
|
||||
// This file defines common utilities for generating documents from tablgen
|
||||
// structures.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_TOOLS_MLIRTBLGEN_DOCGENUTILITIES_H_
|
||||
#define MLIR_TOOLS_MLIRTBLGEN_DOCGENUTILITIES_H_
|
||||
|
||||
namespace llvm {
|
||||
class raw_ostream;
|
||||
class StringRef;
|
||||
} // namespace llvm
|
||||
|
||||
namespace mlir {
|
||||
namespace tblgen {
|
||||
|
||||
// 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.
|
||||
void emitDescription(llvm::StringRef description, llvm::raw_ostream &os);
|
||||
|
||||
} // namespace tblgen
|
||||
} // namespace mlir
|
||||
|
||||
#endif // MLIR_TOOLS_MLIRTBLGEN_DOCGENUTILITIES_H_
|
|
@ -20,6 +20,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DocGenUtilities.h"
|
||||
#include "mlir/TableGen/GenInfo.h"
|
||||
#include "mlir/TableGen/Operator.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
|
@ -40,7 +41,7 @@ using mlir::tblgen::Operator;
|
|||
// 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.
|
||||
static void emitDescription(StringRef description, raw_ostream &os) {
|
||||
void mlir::tblgen::emitDescription(StringRef description, raw_ostream &os) {
|
||||
// Determine the minimum number of spaces in a line.
|
||||
size_t min_indent = -1;
|
||||
StringRef remaining = description;
|
||||
|
@ -94,7 +95,7 @@ static void emitOpDoc(const RecordKeeper &recordKeeper, raw_ostream &os) {
|
|||
os << "\n" << op.getSummary() << "\n";
|
||||
os << "\n### Description:\n";
|
||||
if (op.hasDescription())
|
||||
emitDescription(op.getDescription(), os);
|
||||
mlir::tblgen::emitDescription(op.getDescription(), os);
|
||||
|
||||
// Emit operands & type of operand. All operands are numbered, some may be
|
||||
// named too.
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "DocGenUtilities.h"
|
||||
#include "mlir/Support/STLExtras.h"
|
||||
#include "mlir/TableGen/GenInfo.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
@ -33,6 +34,10 @@ using namespace llvm;
|
|||
using namespace mlir;
|
||||
|
||||
namespace {
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpInterfaceMethod
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This struct represents a single method argument.
|
||||
struct MethodArgument {
|
||||
StringRef type, name;
|
||||
|
@ -67,6 +72,12 @@ public:
|
|||
return value.empty() ? llvm::Optional<StringRef>() : value;
|
||||
}
|
||||
|
||||
// Return the description of this method if it has one.
|
||||
llvm::Optional<StringRef> getDescription() const {
|
||||
auto value = def->getValueAsString("description");
|
||||
return value.empty() ? llvm::Optional<StringRef>() : value;
|
||||
}
|
||||
|
||||
// Arguments.
|
||||
ArrayRef<MethodArgument> getArguments() const { return arguments; }
|
||||
bool arg_empty() const { return arguments.empty(); }
|
||||
|
@ -79,6 +90,10 @@ protected:
|
|||
SmallVector<MethodArgument, 2> arguments;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpInterface
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Wrapper class with helper methods for accessing OpInterfaces defined in
|
||||
// TableGen.
|
||||
class OpInterface {
|
||||
|
@ -95,6 +110,12 @@ public:
|
|||
// Return the methods of this interface.
|
||||
ArrayRef<OpInterfaceMethod> getMethods() const { return methods; }
|
||||
|
||||
// Return the description of this method if it has one.
|
||||
llvm::Optional<StringRef> getDescription() const {
|
||||
auto value = def->getValueAsString("description");
|
||||
return value.empty() ? llvm::Optional<StringRef>() : value;
|
||||
}
|
||||
|
||||
protected:
|
||||
// The TableGen definition of this interface.
|
||||
const llvm::Record *def;
|
||||
|
@ -118,8 +139,11 @@ static void emitMethodNameAndArgs(const OpInterfaceMethod &method,
|
|||
os << ')';
|
||||
}
|
||||
|
||||
static void emitInterfaceDef(const Record &interfaceDef, raw_ostream &os) {
|
||||
OpInterface interface(&interfaceDef);
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GEN: Interface definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void emitInterfaceDef(OpInterface &interface, raw_ostream &os) {
|
||||
StringRef interfaceName = interface.getName();
|
||||
|
||||
// Insert the method definitions.
|
||||
|
@ -142,11 +166,17 @@ static bool emitInterfaceDefs(const RecordKeeper &recordKeeper,
|
|||
llvm::emitSourceFileHeader("Operation Interface Definitions", os);
|
||||
|
||||
auto defs = recordKeeper.getAllDerivedDefinitions("OpInterface");
|
||||
for (const auto *def : defs)
|
||||
emitInterfaceDef(*def, os);
|
||||
for (const auto *def : defs) {
|
||||
OpInterface interface(def);
|
||||
emitInterfaceDef(interface, os);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GEN: Interface declarations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
static void emitConceptDecl(OpInterface &interface, raw_ostream &os) {
|
||||
os << " class Concept {\n"
|
||||
<< " public:\n"
|
||||
|
@ -195,8 +225,7 @@ static void emitModelDecl(OpInterface &interface, raw_ostream &os) {
|
|||
os << " };\n";
|
||||
}
|
||||
|
||||
static void emitInterfaceDecl(const Record &interfaceDef, raw_ostream &os) {
|
||||
OpInterface interface(&interfaceDef);
|
||||
static void emitInterfaceDecl(OpInterface &interface, raw_ostream &os) {
|
||||
StringRef interfaceName = interface.getName();
|
||||
auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();
|
||||
|
||||
|
@ -227,11 +256,75 @@ static bool emitInterfaceDecls(const RecordKeeper &recordKeeper,
|
|||
llvm::emitSourceFileHeader("Operation Interface Declarations", os);
|
||||
|
||||
auto defs = recordKeeper.getAllDerivedDefinitions("OpInterface");
|
||||
for (const auto *def : defs)
|
||||
emitInterfaceDecl(*def, os);
|
||||
for (const auto *def : defs) {
|
||||
OpInterface interface(def);
|
||||
emitInterfaceDecl(interface, os);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GEN: Interface documentation
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Emit a string corresponding to a C++ type, followed by a space if necessary.
|
||||
static raw_ostream &emitCPPType(StringRef type, raw_ostream &os) {
|
||||
type = type.trim();
|
||||
os << type;
|
||||
if (type.back() != '&' && type.back() != '*')
|
||||
os << " ";
|
||||
return os;
|
||||
}
|
||||
|
||||
static void emitInterfaceDoc(const Record &interfaceDef, raw_ostream &os) {
|
||||
OpInterface interface(&interfaceDef);
|
||||
|
||||
// Emit the interface name followed by the description.
|
||||
os << "## " << interface.getName() << " (" << interfaceDef.getName() << ")";
|
||||
if (auto description = interface.getDescription())
|
||||
mlir::tblgen::emitDescription(*description, os);
|
||||
|
||||
// Emit the methods required by the interface.
|
||||
os << "\n### Methods:\n";
|
||||
for (const auto &method : interface.getMethods()) {
|
||||
// Emit the method name.
|
||||
os << "#### `" << method.getName() << "`\n\n```c++\n";
|
||||
|
||||
// Emit the method signature.
|
||||
if (method.isStatic())
|
||||
os << "static ";
|
||||
emitCPPType(method.getReturnType(), os) << method.getName() << '(';
|
||||
interleaveComma(method.getArguments(), os, [&](const MethodArgument &arg) {
|
||||
emitCPPType(arg.type, os) << arg.name;
|
||||
});
|
||||
os << ");\n```\n";
|
||||
|
||||
// Emit the description.
|
||||
if (auto description = method.getDescription())
|
||||
mlir::tblgen::emitDescription(*description, os);
|
||||
|
||||
// If the body is not provided, this method must be provided by the
|
||||
// operation.
|
||||
if (!method.getBody())
|
||||
os << "\nNOTE: This method *must* be implemented by the operation.\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
static bool emitInterfaceDocs(const RecordKeeper &recordKeeper,
|
||||
raw_ostream &os) {
|
||||
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
|
||||
os << "# Operation Interface definition\n";
|
||||
|
||||
auto defs = recordKeeper.getAllDerivedDefinitions("OpInterface");
|
||||
for (const auto *def : defs)
|
||||
emitInterfaceDoc(*def, os);
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GEN: Interface registration hooks
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Registers the operation interface generator to mlir-tblgen.
|
||||
static mlir::GenRegistration
|
||||
genInterfaceDecls("gen-op-interface-decls",
|
||||
|
@ -247,3 +340,11 @@ static mlir::GenRegistration
|
|||
[](const RecordKeeper &records, raw_ostream &os) {
|
||||
return emitInterfaceDefs(records, os);
|
||||
});
|
||||
|
||||
// Registers the operation interface document generator to mlir-tblgen.
|
||||
static mlir::GenRegistration
|
||||
genInterfaceDocs("gen-op-interface-doc",
|
||||
"Generate op interface documentation",
|
||||
[](const RecordKeeper &records, raw_ostream &os) {
|
||||
return emitInterfaceDocs(records, os);
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue