Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
//===- OpInterfacesGen.cpp - MLIR op interface utility 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
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
//
|
2019-12-24 01:35:36 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
//
|
|
|
|
// OpInterfacesGen generates definitions for operation interfaces.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-09-25 03:45:11 +08:00
|
|
|
#include "DocGenUtilities.h"
|
2020-01-22 01:40:22 +08:00
|
|
|
#include "mlir/TableGen/Format.h"
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
#include "mlir/TableGen/GenInfo.h"
|
2020-07-01 06:42:52 +08:00
|
|
|
#include "mlir/TableGen/Interfaces.h"
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringExtras.h"
|
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
#include "llvm/TableGen/Error.h"
|
|
|
|
#include "llvm/TableGen/Record.h"
|
|
|
|
#include "llvm/TableGen/TableGenBackend.h"
|
|
|
|
|
|
|
|
using namespace mlir;
|
2020-07-01 06:42:52 +08:00
|
|
|
using mlir::tblgen::Interface;
|
|
|
|
using mlir::tblgen::InterfaceMethod;
|
2019-10-01 03:42:31 +08:00
|
|
|
using mlir::tblgen::OpInterface;
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
/// 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Emit the method name and argument list for the given method. If 'addThisArg'
|
|
|
|
/// is true, then an argument is added to the beginning of the argument list for
|
|
|
|
/// the concrete value.
|
|
|
|
static void emitMethodNameAndArgs(const InterfaceMethod &method,
|
|
|
|
raw_ostream &os, StringRef valueType,
|
|
|
|
bool addThisArg, bool addConst) {
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
os << method.getName() << '(';
|
2021-03-24 16:25:25 +08:00
|
|
|
if (addThisArg) {
|
|
|
|
if (addConst)
|
|
|
|
os << "const ";
|
|
|
|
os << "const Concept *impl, ";
|
2020-07-01 06:42:52 +08:00
|
|
|
emitCPPType(valueType, os)
|
|
|
|
<< "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");
|
2021-03-24 16:25:25 +08:00
|
|
|
}
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(method.getArguments(), os,
|
2020-07-01 06:42:52 +08:00
|
|
|
[&](const InterfaceMethod::Argument &arg) {
|
2020-04-15 05:53:28 +08:00
|
|
|
os << arg.type << " " << arg.name;
|
|
|
|
});
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
os << ')';
|
2020-07-01 06:42:52 +08:00
|
|
|
if (addConst)
|
|
|
|
os << " const";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
}
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
/// Get an array of all OpInterface definitions but exclude those subclassing
|
|
|
|
/// "DeclareOpInterfaceMethods".
|
|
|
|
static std::vector<llvm::Record *>
|
|
|
|
getAllOpInterfaceDefinitions(const llvm::RecordKeeper &recordKeeper) {
|
|
|
|
std::vector<llvm::Record *> defs =
|
2019-12-14 05:57:49 +08:00
|
|
|
recordKeeper.getAllDerivedDefinitions("OpInterface");
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
llvm::erase_if(defs, [](const llvm::Record *def) {
|
2019-12-14 05:57:49 +08:00
|
|
|
return def->isSubClassOf("DeclareOpInterfaceMethods");
|
|
|
|
});
|
|
|
|
return defs;
|
|
|
|
}
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
namespace {
|
|
|
|
/// This struct is the base generator used when processing tablegen interfaces.
|
|
|
|
class InterfaceGenerator {
|
|
|
|
public:
|
|
|
|
bool emitInterfaceDefs();
|
|
|
|
bool emitInterfaceDecls();
|
|
|
|
bool emitInterfaceDocs();
|
|
|
|
|
|
|
|
protected:
|
|
|
|
InterfaceGenerator(std::vector<llvm::Record *> &&defs, raw_ostream &os)
|
|
|
|
: defs(std::move(defs)), os(os) {}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void emitConceptDecl(const Interface &interface);
|
|
|
|
void emitModelDecl(const Interface &interface);
|
|
|
|
void emitModelMethodsDef(const Interface &interface);
|
|
|
|
void emitTraitDecl(const Interface &interface, StringRef interfaceName,
|
2020-07-01 06:42:52 +08:00
|
|
|
StringRef interfaceTraitsName);
|
2022-01-18 14:47:33 +08:00
|
|
|
void emitInterfaceDecl(const Interface &interface);
|
2020-07-01 06:42:52 +08:00
|
|
|
|
|
|
|
/// The set of interface records to emit.
|
|
|
|
std::vector<llvm::Record *> defs;
|
|
|
|
// The stream to emit to.
|
|
|
|
raw_ostream &os;
|
|
|
|
/// The C++ value type of the interface, e.g. Operation*.
|
|
|
|
StringRef valueType;
|
|
|
|
/// The C++ base interface type.
|
|
|
|
StringRef interfaceBaseType;
|
|
|
|
/// The name of the typename for the value template.
|
|
|
|
StringRef valueTemplate;
|
|
|
|
/// The format context to use for methods.
|
|
|
|
tblgen::FmtContext nonStaticMethodFmt;
|
|
|
|
tblgen::FmtContext traitMethodFmt;
|
2022-01-08 09:41:06 +08:00
|
|
|
tblgen::FmtContext extraDeclsFmt;
|
2020-07-01 06:42:52 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/// A specialized generator for attribute interfaces.
|
|
|
|
struct AttrInterfaceGenerator : public InterfaceGenerator {
|
|
|
|
AttrInterfaceGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
|
|
|
|
: InterfaceGenerator(records.getAllDerivedDefinitions("AttrInterface"),
|
|
|
|
os) {
|
|
|
|
valueType = "::mlir::Attribute";
|
2020-11-24 20:57:18 +08:00
|
|
|
interfaceBaseType = "AttributeInterface";
|
2020-07-01 06:42:52 +08:00
|
|
|
valueTemplate = "ConcreteAttr";
|
|
|
|
StringRef castCode = "(tablegen_opaque_val.cast<ConcreteAttr>())";
|
|
|
|
nonStaticMethodFmt.addSubst("_attr", castCode).withSelf(castCode);
|
|
|
|
traitMethodFmt.addSubst("_attr",
|
|
|
|
"(*static_cast<const ConcreteAttr *>(this))");
|
2022-01-08 09:41:06 +08:00
|
|
|
extraDeclsFmt.addSubst("_attr", "(*this)");
|
2020-07-01 06:42:52 +08:00
|
|
|
}
|
|
|
|
};
|
2020-08-27 14:37:23 +08:00
|
|
|
/// A specialized generator for operation interfaces.
|
2020-07-01 06:42:52 +08:00
|
|
|
struct OpInterfaceGenerator : public InterfaceGenerator {
|
|
|
|
OpInterfaceGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
|
|
|
|
: InterfaceGenerator(getAllOpInterfaceDefinitions(records), os) {
|
|
|
|
valueType = "::mlir::Operation *";
|
|
|
|
interfaceBaseType = "OpInterface";
|
|
|
|
valueTemplate = "ConcreteOp";
|
|
|
|
StringRef castCode = "(llvm::cast<ConcreteOp>(tablegen_opaque_val))";
|
2021-03-24 16:25:25 +08:00
|
|
|
nonStaticMethodFmt.addSubst("_this", "impl")
|
|
|
|
.withOp(castCode)
|
|
|
|
.withSelf(castCode);
|
2020-07-01 06:42:52 +08:00
|
|
|
traitMethodFmt.withOp("(*static_cast<ConcreteOp *>(this))");
|
2022-01-08 09:41:06 +08:00
|
|
|
extraDeclsFmt.withOp("(*this)");
|
2020-07-01 06:42:52 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
/// A specialized generator for type interfaces.
|
|
|
|
struct TypeInterfaceGenerator : public InterfaceGenerator {
|
|
|
|
TypeInterfaceGenerator(const llvm::RecordKeeper &records, raw_ostream &os)
|
|
|
|
: InterfaceGenerator(records.getAllDerivedDefinitions("TypeInterface"),
|
|
|
|
os) {
|
|
|
|
valueType = "::mlir::Type";
|
|
|
|
interfaceBaseType = "TypeInterface";
|
|
|
|
valueTemplate = "ConcreteType";
|
|
|
|
StringRef castCode = "(tablegen_opaque_val.cast<ConcreteType>())";
|
|
|
|
nonStaticMethodFmt.addSubst("_type", castCode).withSelf(castCode);
|
|
|
|
traitMethodFmt.addSubst("_type",
|
|
|
|
"(*static_cast<const ConcreteType *>(this))");
|
2022-01-08 09:41:06 +08:00
|
|
|
extraDeclsFmt.addSubst("_type", "(*this)");
|
2020-07-01 06:42:52 +08:00
|
|
|
}
|
|
|
|
};
|
2021-12-08 02:27:58 +08:00
|
|
|
} // namespace
|
2020-07-01 06:42:52 +08:00
|
|
|
|
2019-09-25 03:45:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GEN: Interface definitions
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-01-02 09:26:44 +08:00
|
|
|
static void emitInterfaceDef(const Interface &interface, StringRef valueType,
|
2020-07-01 06:42:52 +08:00
|
|
|
raw_ostream &os) {
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
StringRef interfaceName = interface.getName();
|
2020-07-13 05:11:39 +08:00
|
|
|
StringRef cppNamespace = interface.getCppNamespace();
|
|
|
|
cppNamespace.consume_front("::");
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
|
|
|
// Insert the method definitions.
|
2020-07-01 06:42:52 +08:00
|
|
|
bool isOpInterface = isa<OpInterface>(interface);
|
2019-08-23 02:31:01 +08:00
|
|
|
for (auto &method : interface.getMethods()) {
|
2020-07-13 05:11:39 +08:00
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
if (!cppNamespace.empty())
|
|
|
|
os << cppNamespace << "::";
|
|
|
|
os << interfaceName << "::";
|
2020-07-01 06:42:52 +08:00
|
|
|
emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
|
|
|
|
/*addConst=*/!isOpInterface);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
|
|
|
// Forward to the method on the concrete operation type.
|
|
|
|
os << " {\n return getImpl()->" << method.getName() << '(';
|
2020-07-01 06:42:52 +08:00
|
|
|
if (!method.isStatic()) {
|
2021-03-24 16:25:25 +08:00
|
|
|
os << "getImpl(), ";
|
2020-07-01 06:42:52 +08:00
|
|
|
os << (isOpInterface ? "getOperation()" : "*this");
|
|
|
|
os << (method.arg_empty() ? "" : ", ");
|
|
|
|
}
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(
|
2019-10-01 03:42:31 +08:00
|
|
|
method.getArguments(), os,
|
2020-07-01 06:42:52 +08:00
|
|
|
[&](const InterfaceMethod::Argument &arg) { os << arg.name; });
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
os << ");\n }\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
bool InterfaceGenerator::emitInterfaceDefs() {
|
|
|
|
llvm::emitSourceFileHeader("Interface Definitions", os);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
for (const auto *def : defs)
|
|
|
|
emitInterfaceDef(Interface(def), valueType, os);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-25 03:45:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GEN: Interface declarations
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void InterfaceGenerator::emitConceptDecl(const Interface &interface) {
|
2020-10-28 07:03:07 +08:00
|
|
|
os << " struct Concept {\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2019-08-23 02:31:01 +08:00
|
|
|
// Insert each of the pure virtual concept methods.
|
|
|
|
for (auto &method : interface.getMethods()) {
|
2020-10-28 07:03:07 +08:00
|
|
|
os << " ";
|
2020-07-01 06:42:52 +08:00
|
|
|
emitCPPType(method.getReturnType(), os);
|
2020-10-28 07:03:07 +08:00
|
|
|
os << "(*" << method.getName() << ")(";
|
2021-03-24 16:25:25 +08:00
|
|
|
if (!method.isStatic()) {
|
|
|
|
os << "const Concept *impl, ";
|
2020-10-28 07:03:07 +08:00
|
|
|
emitCPPType(valueType, os) << (method.arg_empty() ? "" : ", ");
|
2021-03-24 16:25:25 +08:00
|
|
|
}
|
2020-10-28 07:03:07 +08:00
|
|
|
llvm::interleaveComma(
|
|
|
|
method.getArguments(), os,
|
|
|
|
[&](const InterfaceMethod::Argument &arg) { os << arg.type; });
|
|
|
|
os << ");\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
}
|
|
|
|
os << " };\n";
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void InterfaceGenerator::emitModelDecl(const Interface &interface) {
|
2021-06-14 23:26:17 +08:00
|
|
|
// Emit the basic model and the fallback model.
|
2021-03-24 16:25:25 +08:00
|
|
|
for (const char *modelClass : {"Model", "FallbackModel"}) {
|
|
|
|
os << " template<typename " << valueTemplate << ">\n";
|
|
|
|
os << " class " << modelClass << " : public Concept {\n public:\n";
|
2021-06-14 23:26:17 +08:00
|
|
|
os << " using Interface = " << interface.getCppNamespace()
|
|
|
|
<< (interface.getCppNamespace().empty() ? "" : "::")
|
|
|
|
<< interface.getName() << ";\n";
|
2021-03-24 16:25:25 +08:00
|
|
|
os << " " << modelClass << "() : Concept{";
|
|
|
|
llvm::interleaveComma(
|
|
|
|
interface.getMethods(), os,
|
|
|
|
[&](const InterfaceMethod &method) { os << method.getName(); });
|
|
|
|
os << "} {}\n\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2021-03-24 16:25:25 +08:00
|
|
|
// Insert each of the virtual method overrides.
|
|
|
|
for (auto &method : interface.getMethods()) {
|
|
|
|
emitCPPType(method.getReturnType(), os << " static inline ");
|
|
|
|
emitMethodNameAndArgs(method, os, valueType,
|
|
|
|
/*addThisArg=*/!method.isStatic(),
|
|
|
|
/*addConst=*/false);
|
|
|
|
os << ";\n";
|
|
|
|
}
|
|
|
|
os << " };\n";
|
2020-11-16 00:49:37 +08:00
|
|
|
}
|
2021-06-14 23:26:17 +08:00
|
|
|
|
2021-06-16 22:31:17 +08:00
|
|
|
// Emit the template for the external model.
|
2021-06-14 23:26:17 +08:00
|
|
|
os << " template<typename ConcreteModel, typename " << valueTemplate
|
|
|
|
<< ">\n";
|
|
|
|
os << " class ExternalModel : public FallbackModel<ConcreteModel> {\n";
|
|
|
|
os << " public:\n";
|
|
|
|
|
|
|
|
// Emit declarations for methods that have default implementations. Other
|
|
|
|
// methods are expected to be implemented by the concrete derived model.
|
|
|
|
for (auto &method : interface.getMethods()) {
|
|
|
|
if (!method.getDefaultImplementation())
|
|
|
|
continue;
|
|
|
|
os << " ";
|
|
|
|
if (method.isStatic())
|
|
|
|
os << "static ";
|
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
os << method.getName() << "(";
|
|
|
|
if (!method.isStatic()) {
|
|
|
|
emitCPPType(valueType, os);
|
|
|
|
os << "tablegen_opaque_val";
|
|
|
|
if (!method.arg_empty())
|
|
|
|
os << ", ";
|
|
|
|
}
|
|
|
|
llvm::interleaveComma(method.getArguments(), os,
|
|
|
|
[&](const InterfaceMethod::Argument &arg) {
|
|
|
|
emitCPPType(arg.type, os);
|
|
|
|
os << arg.name;
|
|
|
|
});
|
|
|
|
os << ")";
|
|
|
|
if (!method.isStatic())
|
|
|
|
os << " const";
|
|
|
|
os << ";\n";
|
|
|
|
}
|
|
|
|
os << " };\n";
|
2020-11-16 00:49:37 +08:00
|
|
|
}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void InterfaceGenerator::emitModelMethodsDef(const Interface &interface) {
|
2020-11-16 00:49:37 +08:00
|
|
|
for (auto &method : interface.getMethods()) {
|
|
|
|
os << "template<typename " << valueTemplate << ">\n";
|
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
os << "detail::" << interface.getName() << "InterfaceTraits::Model<"
|
|
|
|
<< valueTemplate << ">::";
|
|
|
|
emitMethodNameAndArgs(method, os, valueType,
|
|
|
|
/*addThisArg=*/!method.isStatic(),
|
|
|
|
/*addConst=*/false);
|
|
|
|
os << " {\n ";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
|
|
|
// Check for a provided body to the function.
|
2020-07-01 06:42:52 +08:00
|
|
|
if (Optional<StringRef> body = method.getBody()) {
|
|
|
|
if (method.isStatic())
|
|
|
|
os << body->trim();
|
|
|
|
else
|
|
|
|
os << tblgen::tgfmt(body->trim(), &nonStaticMethodFmt);
|
2020-11-16 00:49:37 +08:00
|
|
|
os << "\n}\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Forward to the method on the concrete operation type.
|
2020-07-01 06:42:52 +08:00
|
|
|
if (method.isStatic())
|
|
|
|
os << "return " << valueTemplate << "::";
|
|
|
|
else
|
|
|
|
os << tblgen::tgfmt("return $_self.", &nonStaticMethodFmt);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
|
|
|
// Add the arguments to the call.
|
|
|
|
os << method.getName() << '(';
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(
|
2019-10-01 03:42:31 +08:00
|
|
|
method.getArguments(), os,
|
2020-07-01 06:42:52 +08:00
|
|
|
[&](const InterfaceMethod::Argument &arg) { os << arg.name; });
|
2020-11-16 00:49:37 +08:00
|
|
|
os << ");\n}\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
}
|
2021-03-24 16:25:25 +08:00
|
|
|
|
|
|
|
for (auto &method : interface.getMethods()) {
|
|
|
|
os << "template<typename " << valueTemplate << ">\n";
|
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
os << "detail::" << interface.getName() << "InterfaceTraits::FallbackModel<"
|
|
|
|
<< valueTemplate << ">::";
|
|
|
|
emitMethodNameAndArgs(method, os, valueType,
|
|
|
|
/*addThisArg=*/!method.isStatic(),
|
|
|
|
/*addConst=*/false);
|
|
|
|
os << " {\n ";
|
|
|
|
|
|
|
|
// Forward to the method on the concrete Model implementation.
|
|
|
|
if (method.isStatic())
|
|
|
|
os << "return " << valueTemplate << "::";
|
|
|
|
else
|
|
|
|
os << "return static_cast<const " << valueTemplate << " *>(impl)->";
|
|
|
|
|
|
|
|
// Add the arguments to the call.
|
|
|
|
os << method.getName() << '(';
|
|
|
|
if (!method.isStatic())
|
|
|
|
os << "tablegen_opaque_val" << (method.arg_empty() ? "" : ", ");
|
|
|
|
llvm::interleaveComma(
|
|
|
|
method.getArguments(), os,
|
|
|
|
[&](const InterfaceMethod::Argument &arg) { os << arg.name; });
|
|
|
|
os << ");\n}\n";
|
|
|
|
}
|
2021-06-14 23:26:17 +08:00
|
|
|
|
|
|
|
// Emit default implementations for the external model.
|
|
|
|
for (auto &method : interface.getMethods()) {
|
|
|
|
if (!method.getDefaultImplementation())
|
|
|
|
continue;
|
|
|
|
os << "template<typename ConcreteModel, typename " << valueTemplate
|
|
|
|
<< ">\n";
|
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
os << "detail::" << interface.getName()
|
|
|
|
<< "InterfaceTraits::ExternalModel<ConcreteModel, " << valueTemplate
|
|
|
|
<< ">::";
|
|
|
|
|
|
|
|
os << method.getName() << "(";
|
|
|
|
if (!method.isStatic()) {
|
|
|
|
emitCPPType(valueType, os);
|
|
|
|
os << "tablegen_opaque_val";
|
|
|
|
if (!method.arg_empty())
|
|
|
|
os << ", ";
|
|
|
|
}
|
|
|
|
llvm::interleaveComma(method.getArguments(), os,
|
|
|
|
[&](const InterfaceMethod::Argument &arg) {
|
|
|
|
emitCPPType(arg.type, os);
|
|
|
|
os << arg.name;
|
|
|
|
});
|
|
|
|
os << ")";
|
|
|
|
if (!method.isStatic())
|
|
|
|
os << " const";
|
|
|
|
|
|
|
|
os << " {\n";
|
|
|
|
|
|
|
|
// Use the empty context for static methods.
|
|
|
|
tblgen::FmtContext ctx;
|
|
|
|
os << tblgen::tgfmt(method.getDefaultImplementation()->trim(),
|
|
|
|
method.isStatic() ? &ctx : &nonStaticMethodFmt);
|
|
|
|
os << "\n}\n";
|
|
|
|
}
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void InterfaceGenerator::emitTraitDecl(const Interface &interface,
|
2020-07-01 06:42:52 +08:00
|
|
|
StringRef interfaceName,
|
|
|
|
StringRef interfaceTraitsName) {
|
|
|
|
os << llvm::formatv(" template <typename {3}>\n"
|
|
|
|
" struct {0}Trait : public ::mlir::{2}<{0},"
|
|
|
|
" detail::{1}>::Trait<{3}> {{\n",
|
|
|
|
interfaceName, interfaceTraitsName, interfaceBaseType,
|
|
|
|
valueTemplate);
|
2019-12-19 03:02:35 +08:00
|
|
|
|
|
|
|
// Insert the default implementation for any methods.
|
2020-07-01 06:42:52 +08:00
|
|
|
bool isOpInterface = isa<OpInterface>(interface);
|
2019-12-19 03:02:35 +08:00
|
|
|
for (auto &method : interface.getMethods()) {
|
2020-01-22 01:40:22 +08:00
|
|
|
// Flag interface methods named verifyTrait.
|
|
|
|
if (method.getName() == "verifyTrait")
|
|
|
|
PrintFatalError(
|
|
|
|
formatv("'verifyTrait' method cannot be specified as interface "
|
2020-07-01 06:42:52 +08:00
|
|
|
"method for '{0}'; use the 'verify' field instead",
|
2020-01-22 01:40:22 +08:00
|
|
|
interfaceName));
|
2019-12-19 03:02:35 +08:00
|
|
|
auto defaultImpl = method.getDefaultImplementation();
|
|
|
|
if (!defaultImpl)
|
|
|
|
continue;
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
os << " " << (method.isStatic() ? "static " : "");
|
|
|
|
emitCPPType(method.getReturnType(), os);
|
|
|
|
emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
|
2021-06-14 23:26:03 +08:00
|
|
|
/*addConst=*/!isOpInterface && !method.isStatic());
|
2020-07-01 06:42:52 +08:00
|
|
|
os << " {\n " << tblgen::tgfmt(defaultImpl->trim(), &traitMethodFmt)
|
|
|
|
<< "\n }\n";
|
2019-12-19 03:02:35 +08:00
|
|
|
}
|
|
|
|
|
2020-01-22 01:40:22 +08:00
|
|
|
if (auto verify = interface.getVerify()) {
|
2020-07-01 06:42:52 +08:00
|
|
|
assert(isa<OpInterface>(interface) && "only OpInterface supports 'verify'");
|
|
|
|
|
|
|
|
tblgen::FmtContext verifyCtx;
|
|
|
|
verifyCtx.withOp("op");
|
2022-02-26 02:17:30 +08:00
|
|
|
os << llvm::formatv(
|
|
|
|
" static ::mlir::LogicalResult {0}(::mlir::Operation *op) ",
|
|
|
|
(interface.verifyWithRegions() ? "verifyRegionTrait"
|
|
|
|
: "verifyTrait"))
|
|
|
|
<< "{\n " << tblgen::tgfmt(verify->trim(), &verifyCtx)
|
|
|
|
<< "\n }\n";
|
2020-01-22 01:40:22 +08:00
|
|
|
}
|
2020-04-28 03:57:32 +08:00
|
|
|
if (auto extraTraitDecls = interface.getExtraTraitClassDeclaration())
|
2020-07-01 06:42:52 +08:00
|
|
|
os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";
|
2022-01-08 09:41:06 +08:00
|
|
|
if (auto extraTraitDecls = interface.getExtraSharedClassDeclaration())
|
|
|
|
os << tblgen::tgfmt(*extraTraitDecls, &traitMethodFmt) << "\n";
|
2020-01-22 01:40:22 +08:00
|
|
|
|
2019-12-19 03:02:35 +08:00
|
|
|
os << " };\n";
|
|
|
|
}
|
|
|
|
|
2022-01-18 14:47:33 +08:00
|
|
|
void InterfaceGenerator::emitInterfaceDecl(const Interface &interface) {
|
2020-07-13 05:11:39 +08:00
|
|
|
llvm::SmallVector<StringRef, 2> namespaces;
|
|
|
|
llvm::SplitString(interface.getCppNamespace(), namespaces, "::");
|
|
|
|
for (StringRef ns : namespaces)
|
|
|
|
os << "namespace " << ns << " {\n";
|
|
|
|
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
StringRef interfaceName = interface.getName();
|
|
|
|
auto interfaceTraitsName = (interfaceName + "InterfaceTraits").str();
|
|
|
|
|
2020-11-16 00:49:37 +08:00
|
|
|
// Emit a forward declaration of the interface class so that it becomes usable
|
|
|
|
// in the signature of its methods.
|
|
|
|
os << "class " << interfaceName << ";\n";
|
|
|
|
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
// Emit the traits struct containing the concept and model declarations.
|
|
|
|
os << "namespace detail {\n"
|
|
|
|
<< "struct " << interfaceTraitsName << " {\n";
|
2020-07-01 06:42:52 +08:00
|
|
|
emitConceptDecl(interface);
|
|
|
|
emitModelDecl(interface);
|
2021-06-16 22:31:17 +08:00
|
|
|
os << "};";
|
|
|
|
|
|
|
|
// Emit the derived trait for the interface.
|
|
|
|
os << "template <typename " << valueTemplate << ">\n";
|
|
|
|
os << "struct " << interface.getName() << "Trait;\n";
|
|
|
|
|
2021-12-08 02:27:58 +08:00
|
|
|
os << "\n} // namespace detail\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
|
|
|
// Emit the main interface class declaration.
|
2020-07-01 06:42:52 +08:00
|
|
|
os << llvm::formatv("class {0} : public ::mlir::{3}<{1}, detail::{2}> {\n"
|
|
|
|
"public:\n"
|
|
|
|
" using ::mlir::{3}<{1}, detail::{2}>::{3};\n",
|
|
|
|
interfaceName, interfaceName, interfaceTraitsName,
|
|
|
|
interfaceBaseType);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2021-06-16 22:31:17 +08:00
|
|
|
// Emit a utility wrapper trait class.
|
|
|
|
os << llvm::formatv(" template <typename {1}>\n"
|
|
|
|
" struct Trait : public detail::{0}Trait<{1}> {{};\n",
|
|
|
|
interfaceName, valueTemplate);
|
2019-12-19 03:02:35 +08:00
|
|
|
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
// Insert the method declarations.
|
2020-07-01 06:42:52 +08:00
|
|
|
bool isOpInterface = isa<OpInterface>(interface);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
for (auto &method : interface.getMethods()) {
|
2020-07-01 06:42:52 +08:00
|
|
|
emitCPPType(method.getReturnType(), os << " ");
|
|
|
|
emitMethodNameAndArgs(method, os, valueType, /*addThisArg=*/false,
|
|
|
|
/*addConst=*/!isOpInterface);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
os << ";\n";
|
|
|
|
}
|
[mlir] Allow adding extra class declarations to interfaces.
Summary: This matches the similar feature on operation definitions.
Reviewers: jpienaar, antiagainst
Reviewed By: jpienaar, antiagainst
Subscribers: mehdi_amini, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D74438
2020-02-16 15:54:28 +08:00
|
|
|
|
|
|
|
// Emit any extra declarations.
|
|
|
|
if (Optional<StringRef> extraDecls = interface.getExtraClassDeclaration())
|
|
|
|
os << *extraDecls << "\n";
|
2022-01-08 09:41:06 +08:00
|
|
|
if (Optional<StringRef> extraDecls =
|
|
|
|
interface.getExtraSharedClassDeclaration())
|
|
|
|
os << tblgen::tgfmt(*extraDecls, &extraDeclsFmt);
|
[mlir] Allow adding extra class declarations to interfaces.
Summary: This matches the similar feature on operation definitions.
Reviewers: jpienaar, antiagainst
Reviewed By: jpienaar, antiagainst
Subscribers: mehdi_amini, burmako, shauheen, antiagainst, nicolasvasilache, arpith-jacob, mgester, lucyrfox, liufengdb, Joonsoo, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D74438
2020-02-16 15:54:28 +08:00
|
|
|
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
os << "};\n";
|
2020-07-13 05:11:39 +08:00
|
|
|
|
2021-06-16 22:31:17 +08:00
|
|
|
os << "namespace detail {\n";
|
|
|
|
emitTraitDecl(interface, interfaceName, interfaceTraitsName);
|
|
|
|
os << "}// namespace detail\n";
|
|
|
|
|
2020-11-16 00:49:37 +08:00
|
|
|
emitModelMethodsDef(interface);
|
|
|
|
|
2020-07-13 05:11:39 +08:00
|
|
|
for (StringRef ns : llvm::reverse(namespaces))
|
|
|
|
os << "} // namespace " << ns << "\n";
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
}
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
bool InterfaceGenerator::emitInterfaceDecls() {
|
|
|
|
llvm::emitSourceFileHeader("Interface Declarations", os);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
for (const auto *def : defs)
|
|
|
|
emitInterfaceDecl(Interface(def));
|
2019-09-25 03:45:11 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GEN: Interface documentation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
static void emitInterfaceDoc(const llvm::Record &interfaceDef,
|
|
|
|
raw_ostream &os) {
|
|
|
|
Interface interface(&interfaceDef);
|
2019-09-25 03:45:11 +08:00
|
|
|
|
|
|
|
// Emit the interface name followed by the description.
|
2021-03-15 18:10:32 +08:00
|
|
|
os << "## " << interface.getName() << " (`" << interfaceDef.getName()
|
|
|
|
<< "`)\n\n";
|
2019-09-25 03:45:11 +08:00
|
|
|
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() << '(';
|
2020-04-15 05:53:28 +08:00
|
|
|
llvm::interleaveComma(method.getArguments(), os,
|
2020-07-01 06:42:52 +08:00
|
|
|
[&](const InterfaceMethod::Argument &arg) {
|
2020-04-15 05:53:28 +08:00
|
|
|
emitCPPType(arg.type, os) << arg.name;
|
|
|
|
});
|
2019-09-25 03:45:11 +08:00
|
|
|
os << ");\n```\n";
|
|
|
|
|
|
|
|
// Emit the description.
|
|
|
|
if (auto description = method.getDescription())
|
|
|
|
mlir::tblgen::emitDescription(*description, os);
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
// If the body is not provided, this method must be provided by the user.
|
2019-09-25 03:45:11 +08:00
|
|
|
if (!method.getBody())
|
2020-07-01 06:42:52 +08:00
|
|
|
os << "\nNOTE: This method *must* be implemented by the user.\n\n";
|
2019-09-25 03:45:11 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
bool InterfaceGenerator::emitInterfaceDocs() {
|
2019-09-25 03:45:11 +08:00
|
|
|
os << "<!-- Autogenerated by mlir-tblgen; don't manually edit -->\n";
|
2020-07-01 06:42:52 +08:00
|
|
|
os << "# " << interfaceBaseType << " definitions\n";
|
2019-09-25 03:45:11 +08:00
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
for (const auto *def : defs)
|
2019-09-25 03:45:11 +08:00
|
|
|
emitInterfaceDoc(*def, os);
|
Add support for generating operation interfaces from the ODS framework.
Operation interfaces generally require a bit of boilerplate code to connect all of the pieces together. This cl introduces mechanisms in the ODS to allow for generating operation interfaces via the 'OpInterface' class.
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. There are two types of methods that can be used with an interface, `InterfaceMethod` and `StaticInterfaceMethod`. They are both comprised of the same core components, with the distinction that `StaticInterfaceMethod` models a static method on the derived operation.
An `InterfaceMethod` is comprised of the following components:
* ReturnType
- A string corresponding to the c++ return type of the method.
* MethodName
- A string corresponding to the desired name of the method.
* Arguments
- A dag of strings that correspond to a c++ type and variable name
respectively.
* MethodBody (Optional)
- An optional explicit implementation of the interface method.
def MyInterface : OpInterface<"MyInterface"> {
let methods = [
// A simple non-static method with no inputs.
InterfaceMethod<"unsigned", "foo">,
// A new non-static method accepting an input argument.
InterfaceMethod<"Value *", "bar", (ins "unsigned":$i)>,
// Query a static property of the derived operation.
StaticInterfaceMethod<"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), [{
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();
}]>,
];
PiperOrigin-RevId: 264754898
2019-08-22 11:57:23 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-09-25 03:45:11 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// GEN: Interface registration hooks
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-07-01 06:42:52 +08:00
|
|
|
namespace {
|
2021-07-22 20:06:52 +08:00
|
|
|
template <typename GeneratorT>
|
|
|
|
struct InterfaceGenRegistration {
|
|
|
|
InterfaceGenRegistration(StringRef genArg, StringRef genDesc)
|
2020-07-01 06:42:52 +08:00
|
|
|
: genDeclArg(("gen-" + genArg + "-interface-decls").str()),
|
|
|
|
genDefArg(("gen-" + genArg + "-interface-defs").str()),
|
|
|
|
genDocArg(("gen-" + genArg + "-interface-docs").str()),
|
2021-07-22 20:06:52 +08:00
|
|
|
genDeclDesc(("Generate " + genDesc + " interface declarations").str()),
|
|
|
|
genDefDesc(("Generate " + genDesc + " interface definitions").str()),
|
|
|
|
genDocDesc(("Generate " + genDesc + " interface documentation").str()),
|
|
|
|
genDecls(genDeclArg, genDeclDesc,
|
2020-07-01 06:42:52 +08:00
|
|
|
[](const llvm::RecordKeeper &records, raw_ostream &os) {
|
|
|
|
return GeneratorT(records, os).emitInterfaceDecls();
|
|
|
|
}),
|
2021-07-22 20:06:52 +08:00
|
|
|
genDefs(genDefArg, genDefDesc,
|
2020-07-01 06:42:52 +08:00
|
|
|
[](const llvm::RecordKeeper &records, raw_ostream &os) {
|
|
|
|
return GeneratorT(records, os).emitInterfaceDefs();
|
|
|
|
}),
|
2021-07-22 20:06:52 +08:00
|
|
|
genDocs(genDocArg, genDocDesc,
|
2020-07-01 06:42:52 +08:00
|
|
|
[](const llvm::RecordKeeper &records, raw_ostream &os) {
|
|
|
|
return GeneratorT(records, os).emitInterfaceDocs();
|
|
|
|
}) {}
|
|
|
|
|
|
|
|
std::string genDeclArg, genDefArg, genDocArg;
|
2021-07-22 20:06:52 +08:00
|
|
|
std::string genDeclDesc, genDefDesc, genDocDesc;
|
2020-07-01 06:42:52 +08:00
|
|
|
mlir::GenRegistration genDecls, genDefs, genDocs;
|
|
|
|
};
|
2021-12-08 02:27:58 +08:00
|
|
|
} // namespace
|
2020-07-01 06:42:52 +08:00
|
|
|
|
2021-07-22 20:06:52 +08:00
|
|
|
static InterfaceGenRegistration<AttrInterfaceGenerator> attrGen("attr",
|
|
|
|
"attribute");
|
|
|
|
static InterfaceGenRegistration<OpInterfaceGenerator> opGen("op", "op");
|
|
|
|
static InterfaceGenRegistration<TypeInterfaceGenerator> typeGen("type", "type");
|