forked from OSchip/llvm-project
[mlir][IR] Use tablegen for the BuiltinDialect and operations
This has been a long standing TODO, and cleans up a bit of IR/. This will also make it easier to move FuncOp out of IR/ at some point in the future. For now, Module.h and Function.h just forward BuiltinDialect.h. These files will be removed in a followup. Differential Revision: https://reviews.llvm.org/D91571
This commit is contained in:
parent
9faedb2d71
commit
c51e4c4f01
|
@ -0,0 +1,93 @@
|
|||
//===- BuiltinDialect.h - MLIR Builtin Dialect ------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This file contains the Builtin dialect and its operations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_IR_BUILTINDIALECT_H_
|
||||
#define MLIR_IR_BUILTINDIALECT_H_
|
||||
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/FunctionSupport.h"
|
||||
#include "mlir/IR/OwningOpRefBase.h"
|
||||
#include "mlir/IR/SymbolTable.h"
|
||||
#include "mlir/Interfaces/CallInterfaces.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dialect
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/BuiltinDialect.h.inc"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dialect Operations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/IR/BuiltinOps.h.inc"
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Dialect Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace mlir {
|
||||
/// This class acts as an owning reference to a module, and will automatically
|
||||
/// destroy the held module on destruction if the held module is valid.
|
||||
class OwningModuleRef : public OwningOpRefBase<ModuleOp> {
|
||||
public:
|
||||
using OwningOpRefBase<ModuleOp>::OwningOpRefBase;
|
||||
};
|
||||
} // end namespace mlir
|
||||
|
||||
namespace llvm {
|
||||
// Functions hash just like pointers.
|
||||
template <>
|
||||
struct DenseMapInfo<mlir::FuncOp> {
|
||||
static mlir::FuncOp getEmptyKey() {
|
||||
auto *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
|
||||
return mlir::FuncOp::getFromOpaquePointer(pointer);
|
||||
}
|
||||
static mlir::FuncOp getTombstoneKey() {
|
||||
auto *pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
|
||||
return mlir::FuncOp::getFromOpaquePointer(pointer);
|
||||
}
|
||||
static unsigned getHashValue(mlir::FuncOp val) {
|
||||
return hash_value(val.getAsOpaquePointer());
|
||||
}
|
||||
static bool isEqual(mlir::FuncOp lhs, mlir::FuncOp rhs) { return lhs == rhs; }
|
||||
};
|
||||
|
||||
/// Allow stealing the low bits of FuncOp.
|
||||
template <>
|
||||
struct PointerLikeTypeTraits<mlir::FuncOp> {
|
||||
static inline void *getAsVoidPointer(mlir::FuncOp val) {
|
||||
return const_cast<void *>(val.getAsOpaquePointer());
|
||||
}
|
||||
static inline mlir::FuncOp getFromVoidPointer(void *p) {
|
||||
return mlir::FuncOp::getFromOpaquePointer(p);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = 3;
|
||||
};
|
||||
|
||||
/// Allow stealing the low bits of ModuleOp.
|
||||
template <>
|
||||
struct PointerLikeTypeTraits<mlir::ModuleOp> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(mlir::ModuleOp val) {
|
||||
return const_cast<void *>(val.getAsOpaquePointer());
|
||||
}
|
||||
static inline mlir::ModuleOp getFromVoidPointer(void *p) {
|
||||
return mlir::ModuleOp::getFromOpaquePointer(p);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = 3;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // MLIR_IR_BUILTINDIALECT_H_
|
|
@ -0,0 +1,235 @@
|
|||
//===- BuiltinOps.td - Builtin operation definitions -------*- tablegen -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Defines the set of builtin MLIR operations.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BUILTIN_OPS
|
||||
#define BUILTIN_OPS
|
||||
|
||||
include "mlir/IR/SymbolInterfaces.td"
|
||||
include "mlir/Interfaces/CallInterfaces.td"
|
||||
|
||||
def Builtin_Dialect : Dialect {
|
||||
let summary =
|
||||
"A dialect containing the builtin Attributes, Operations, and Types";
|
||||
|
||||
let name = "";
|
||||
let cppNamespace = "::mlir";
|
||||
}
|
||||
|
||||
// Base class for Builtin dialect ops.
|
||||
class Builtin_Op<string mnemonic, list<OpTrait> traits = []> :
|
||||
Op<Builtin_Dialect, mnemonic, traits>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FuncOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def FuncOp : Builtin_Op<"func", [
|
||||
AffineScope, AutomaticAllocationScope, CallableOpInterface, FunctionLike,
|
||||
IsolatedFromAbove, Symbol
|
||||
]> {
|
||||
let summary = "An operation with a name containing a single `SSACFG` region";
|
||||
let description = [{
|
||||
Operations within the function cannot implicitly capture values defined
|
||||
outside of the function, i.e. Functions are `IsolatedFromAbove`. All
|
||||
external references must use function arguments or attributes that establish
|
||||
a symbolic connection (e.g. symbols referenced by name via a string
|
||||
attribute like SymbolRefAttr). An external function declaration (used when
|
||||
referring to a function declared in some other module) has no body. While
|
||||
the MLIR textual form provides a nice inline syntax for function arguments,
|
||||
they are internally represented as “block arguments” to the first block in
|
||||
the region.
|
||||
|
||||
Only dialect attribute names may be specified in the attribute dictionaries
|
||||
for function arguments, results, or the function itself.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
// External function definitions.
|
||||
func @abort()
|
||||
func @scribble(i32, i64, memref<? x 128 x f32, #layout_map0>) -> f64
|
||||
|
||||
// A function that returns its argument twice:
|
||||
func @count(%x: i64) -> (i64, i64)
|
||||
attributes {fruit: "banana"} {
|
||||
return %x, %x: i64, i64
|
||||
}
|
||||
|
||||
// A function with an argument attribute
|
||||
func @example_fn_arg(%x: i32 {swift.self = unit})
|
||||
|
||||
// A function with a result attribute
|
||||
func @example_fn_result() -> (f64 {dialectName.attrName = 0 : i64})
|
||||
|
||||
// A function with an attribute
|
||||
func @example_fn_attr() attributes {dialectName.attrName = false}
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins SymbolNameAttr:$sym_name,
|
||||
TypeAttr:$type,
|
||||
OptionalAttr<StrAttr>:$sym_visibility);
|
||||
let regions = (region AnyRegion:$body);
|
||||
|
||||
let builders = [OpBuilderDAG<(ins
|
||||
"StringRef":$name, "FunctionType":$type,
|
||||
CArg<"ArrayRef<NamedAttribute>", "{}">:$attrs,
|
||||
CArg<"ArrayRef<MutableDictionaryAttr>", "{}">:$argAttrs)
|
||||
>];
|
||||
let extraClassDeclaration = [{
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
ArrayRef<NamedAttribute> attrs = {});
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
iterator_range<dialect_attr_iterator> attrs);
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
ArrayRef<NamedAttribute> attrs,
|
||||
ArrayRef<MutableDictionaryAttr> argAttrs);
|
||||
|
||||
/// Create a deep copy of this function and all of its blocks, remapping any
|
||||
/// operands that use values outside of the function using the map that is
|
||||
/// provided (leaving them alone if no entry is present). If the mapper
|
||||
/// contains entries for function arguments, these arguments are not
|
||||
/// included in the new function. Replaces references to cloned sub-values
|
||||
/// with the corresponding value that is copied, and adds those mappings to
|
||||
/// the mapper.
|
||||
FuncOp clone(BlockAndValueMapping &mapper);
|
||||
FuncOp clone();
|
||||
|
||||
/// Clone the internal blocks and attributes from this function into dest.
|
||||
/// Any cloned blocks are appended to the back of dest. This function
|
||||
/// asserts that the attributes of the current function and dest are
|
||||
/// compatible.
|
||||
void cloneInto(FuncOp dest, BlockAndValueMapping &mapper);
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// CallableOpInterface
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// Returns the region on the current operation that is callable. This may
|
||||
/// return null in the case of an external callable object, e.g. an external
|
||||
/// function.
|
||||
Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
|
||||
|
||||
/// Returns the results types that the callable region produces when
|
||||
/// executed.
|
||||
ArrayRef<Type> getCallableResults() { return getType().getResults(); }
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// SymbolOpInterface Methods
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
bool isDeclaration() { return isExternal(); }
|
||||
|
||||
private:
|
||||
// This trait needs access to the hooks defined below.
|
||||
friend class OpTrait::FunctionLike<FuncOp>;
|
||||
|
||||
/// Returns the number of arguments. This is a hook for
|
||||
/// OpTrait::FunctionLike.
|
||||
unsigned getNumFuncArguments() { return getType().getInputs().size(); }
|
||||
|
||||
/// Returns the number of results. This is a hook for OpTrait::FunctionLike.
|
||||
unsigned getNumFuncResults() { return getType().getResults().size(); }
|
||||
|
||||
/// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
|
||||
/// attribute is present and checks if it holds a function type. Ensures
|
||||
/// getType, getNumFuncArguments, and getNumFuncResults can be called
|
||||
/// safely.
|
||||
LogicalResult verifyType() {
|
||||
auto type = getTypeAttr().getValue();
|
||||
if (!type.isa<FunctionType>())
|
||||
return emitOpError("requires '" + getTypeAttrName() +
|
||||
"' attribute of function type");
|
||||
return success();
|
||||
}
|
||||
}];
|
||||
let parser = [{ return ::parseFuncOp(parser, result); }];
|
||||
let printer = [{ return ::print(*this, p); }];
|
||||
let verifier = [{ return ::verify(*this); }];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ModuleOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def ModuleOp : Builtin_Op<"module", [
|
||||
AffineScope, IsolatedFromAbove, NoRegionArguments, SymbolTable, Symbol,
|
||||
SingleBlockImplicitTerminator<"ModuleTerminatorOp">
|
||||
]> {
|
||||
let summary = "A top level container operation";
|
||||
let description = [{
|
||||
A `module` represents a top-level container operation. It contains a single
|
||||
SSACFG region containing a single block which can contain any
|
||||
operations. Operations within this region cannot implicitly capture values
|
||||
defined outside the module, i.e. Modules are `IsolatedFromAbove`. Modules
|
||||
have an optional symbol name which can be used to refer to them in
|
||||
operations.
|
||||
|
||||
Example:
|
||||
|
||||
```mlir
|
||||
module {
|
||||
func @foo()
|
||||
}
|
||||
```
|
||||
}];
|
||||
|
||||
let arguments = (ins OptionalAttr<SymbolNameAttr>:$sym_name,
|
||||
OptionalAttr<StrAttr>:$sym_visibility);
|
||||
let regions = (region SizedRegion<1>:$body);
|
||||
|
||||
let assemblyFormat = "($sym_name^)? attr-dict-with-keyword $body";
|
||||
let builders = [OpBuilderDAG<(ins CArg<"Optional<StringRef>", "{}">:$name)>];
|
||||
let extraClassDeclaration = [{
|
||||
/// Construct a module from the given location with an optional name.
|
||||
static ModuleOp create(Location loc, Optional<StringRef> name = llvm::None);
|
||||
|
||||
/// Return the name of this module if present.
|
||||
Optional<StringRef> getName() { return sym_name(); }
|
||||
|
||||
/// Print the this module in the custom top-level form.
|
||||
void print(raw_ostream &os, OpPrintingFlags flags = llvm::None);
|
||||
void print(raw_ostream &os, AsmState &state,
|
||||
OpPrintingFlags flags = llvm::None);
|
||||
void dump();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// SymbolOpInterface Methods
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// A ModuleOp may optionally define a symbol.
|
||||
bool isOptionalSymbol() { return true; }
|
||||
}];
|
||||
let verifier = [{ return ::verify(*this); }];
|
||||
|
||||
// We need to ensure the block inside the region is properly terminated;
|
||||
// the auto-generated builders do not guarantee that.
|
||||
let skipDefaultBuilders = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ModuleTerminatorOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def ModuleTerminatorOp : Builtin_Op<"module_terminator", [
|
||||
Terminator, HasParent<"ModuleOp">
|
||||
]> {
|
||||
let summary = "A pseudo op that marks the end of a module";
|
||||
let description = [{
|
||||
`module_terminator` is a special terminator operation for the body of a
|
||||
`module`, it has no semantic meaning beyond keeping the body of a `module`
|
||||
well-formed.
|
||||
}];
|
||||
let assemblyFormat = "attr-dict";
|
||||
}
|
||||
|
||||
#endif // BUILTIN_OPS
|
|
@ -1,3 +1,11 @@
|
|||
add_mlir_interface(OpAsmInterface)
|
||||
add_mlir_interface(SymbolInterfaces)
|
||||
add_mlir_interface(RegionKindInterface)
|
||||
|
||||
set(LLVM_TARGET_DEFINITIONS BuiltinOps.td)
|
||||
mlir_tablegen(BuiltinOps.h.inc -gen-op-decls)
|
||||
mlir_tablegen(BuiltinOps.cpp.inc -gen-op-defs)
|
||||
mlir_tablegen(BuiltinDialect.h.inc -gen-dialect-decls)
|
||||
add_public_tablegen_target(MLIRBuiltinOpsIncGen)
|
||||
|
||||
add_mlir_doc(BuiltinOps -gen-op-doc Builtin Dialects/)
|
||||
|
|
|
@ -13,137 +13,7 @@
|
|||
#ifndef MLIR_IR_FUNCTION_H
|
||||
#define MLIR_IR_FUNCTION_H
|
||||
|
||||
#include "mlir/IR/Block.h"
|
||||
#include "mlir/IR/FunctionSupport.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/SymbolTable.h"
|
||||
#include "mlir/Interfaces/CallInterfaces.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
|
||||
namespace mlir {
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Function Operation.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// FuncOp represents a function, or an operation containing one region that
|
||||
/// forms a CFG(Control Flow Graph). The region of a function is not allowed to
|
||||
/// implicitly capture global values, and all external references must use
|
||||
/// Function arguments or attributes that establish a symbolic connection(e.g.
|
||||
/// symbols referenced by name via a string attribute).
|
||||
class FuncOp
|
||||
: public Op<FuncOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
|
||||
OpTrait::OneRegion, OpTrait::IsIsolatedFromAbove,
|
||||
OpTrait::FunctionLike, OpTrait::AutomaticAllocationScope,
|
||||
OpTrait::AffineScope, CallableOpInterface::Trait,
|
||||
SymbolOpInterface::Trait> {
|
||||
public:
|
||||
using Op::Op;
|
||||
using Op::print;
|
||||
|
||||
static StringRef getOperationName() { return "func"; }
|
||||
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
ArrayRef<NamedAttribute> attrs = {});
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
iterator_range<dialect_attr_iterator> attrs);
|
||||
static FuncOp create(Location location, StringRef name, FunctionType type,
|
||||
ArrayRef<NamedAttribute> attrs,
|
||||
ArrayRef<MutableDictionaryAttr> argAttrs);
|
||||
|
||||
static void build(OpBuilder &builder, OperationState &result, StringRef name,
|
||||
FunctionType type, ArrayRef<NamedAttribute> attrs = {},
|
||||
ArrayRef<MutableDictionaryAttr> argAttrs = {});
|
||||
|
||||
/// Operation hooks.
|
||||
static ParseResult parse(OpAsmParser &parser, OperationState &result);
|
||||
void print(OpAsmPrinter &p);
|
||||
LogicalResult verify();
|
||||
|
||||
/// Create a deep copy of this function and all of its blocks, remapping
|
||||
/// any operands that use values outside of the function using the map that is
|
||||
/// provided (leaving them alone if no entry is present). If the mapper
|
||||
/// contains entries for function arguments, these arguments are not included
|
||||
/// in the new function. Replaces references to cloned sub-values with the
|
||||
/// corresponding value that is copied, and adds those mappings to the mapper.
|
||||
FuncOp clone(BlockAndValueMapping &mapper);
|
||||
FuncOp clone();
|
||||
|
||||
/// Clone the internal blocks and attributes from this function into dest. Any
|
||||
/// cloned blocks are appended to the back of dest. This function asserts that
|
||||
/// the attributes of the current function and dest are compatible.
|
||||
void cloneInto(FuncOp dest, BlockAndValueMapping &mapper);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// CallableOpInterface
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Returns the region on the current operation that is callable. This may
|
||||
/// return null in the case of an external callable object, e.g. an external
|
||||
/// function.
|
||||
Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
|
||||
|
||||
/// Returns the results types that the callable region produces when executed.
|
||||
ArrayRef<Type> getCallableResults() { return getType().getResults(); }
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// SymbolOpInterface Methods
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
bool isDeclaration() { return isExternal(); }
|
||||
|
||||
private:
|
||||
// This trait needs access to the hooks defined below.
|
||||
friend class OpTrait::FunctionLike<FuncOp>;
|
||||
|
||||
/// Returns the number of arguments. This is a hook for OpTrait::FunctionLike.
|
||||
unsigned getNumFuncArguments() { return getType().getInputs().size(); }
|
||||
|
||||
/// Returns the number of results. This is a hook for OpTrait::FunctionLike.
|
||||
unsigned getNumFuncResults() { return getType().getResults().size(); }
|
||||
|
||||
/// Hook for OpTrait::FunctionLike, called after verifying that the 'type'
|
||||
/// attribute is present and checks if it holds a function type. Ensures
|
||||
/// getType, getNumFuncArguments, and getNumFuncResults can be called safely.
|
||||
LogicalResult verifyType() {
|
||||
auto type = getTypeAttr().getValue();
|
||||
if (!type.isa<FunctionType>())
|
||||
return emitOpError("requires '" + getTypeAttrName() +
|
||||
"' attribute of function type");
|
||||
return success();
|
||||
}
|
||||
};
|
||||
} // end namespace mlir
|
||||
|
||||
namespace llvm {
|
||||
|
||||
// Functions hash just like pointers.
|
||||
template <> struct DenseMapInfo<mlir::FuncOp> {
|
||||
static mlir::FuncOp getEmptyKey() {
|
||||
auto pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
|
||||
return mlir::FuncOp::getFromOpaquePointer(pointer);
|
||||
}
|
||||
static mlir::FuncOp getTombstoneKey() {
|
||||
auto pointer = llvm::DenseMapInfo<void *>::getTombstoneKey();
|
||||
return mlir::FuncOp::getFromOpaquePointer(pointer);
|
||||
}
|
||||
static unsigned getHashValue(mlir::FuncOp val) {
|
||||
return hash_value(val.getAsOpaquePointer());
|
||||
}
|
||||
static bool isEqual(mlir::FuncOp LHS, mlir::FuncOp RHS) { return LHS == RHS; }
|
||||
};
|
||||
|
||||
/// Allow stealing the low bits of FuncOp.
|
||||
template <> struct PointerLikeTypeTraits<mlir::FuncOp> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(mlir::FuncOp I) {
|
||||
return const_cast<void *>(I.getAsOpaquePointer());
|
||||
}
|
||||
static inline mlir::FuncOp getFromVoidPointer(void *P) {
|
||||
return mlir::FuncOp::getFromOpaquePointer(P);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = 3;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
// TODO: This is a temporary forward until Function.h is removed.
|
||||
#include "mlir/IR/BuiltinDialect.h"
|
||||
|
||||
#endif // MLIR_IR_FUNCTION_H
|
||||
|
|
|
@ -13,138 +13,7 @@
|
|||
#ifndef MLIR_IR_MODULE_H
|
||||
#define MLIR_IR_MODULE_H
|
||||
|
||||
#include "mlir/IR/OwningOpRefBase.h"
|
||||
#include "mlir/IR/SymbolTable.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
|
||||
namespace mlir {
|
||||
class ModuleTerminatorOp;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Module Operation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// ModuleOp represents a module, or an operation containing one region with a
|
||||
/// single block containing opaque operations. The region of a module is not
|
||||
/// allowed to implicitly capture global values, and all external references
|
||||
/// must use symbolic references via attributes(e.g. via a string name).
|
||||
class ModuleOp
|
||||
: public Op<
|
||||
ModuleOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
|
||||
OpTrait::IsIsolatedFromAbove, OpTrait::AffineScope,
|
||||
OpTrait::SymbolTable,
|
||||
OpTrait::SingleBlockImplicitTerminator<ModuleTerminatorOp>::Impl,
|
||||
SymbolOpInterface::Trait, OpTrait::NoRegionArguments> {
|
||||
public:
|
||||
using Op::Op;
|
||||
using Op::print;
|
||||
|
||||
static StringRef getOperationName() { return "module"; }
|
||||
|
||||
static void build(OpBuilder &builder, OperationState &result,
|
||||
Optional<StringRef> name = llvm::None);
|
||||
|
||||
/// Construct a module from the given location with an optional name.
|
||||
static ModuleOp create(Location loc, Optional<StringRef> name = llvm::None);
|
||||
|
||||
/// Operation hooks.
|
||||
static ParseResult parse(OpAsmParser &parser, OperationState &result);
|
||||
void print(OpAsmPrinter &p);
|
||||
LogicalResult verify();
|
||||
|
||||
/// Return body of this module.
|
||||
Region &getBodyRegion();
|
||||
Block *getBody();
|
||||
|
||||
/// Return the name of this module if present.
|
||||
Optional<StringRef> getName();
|
||||
|
||||
/// Print the this module in the custom top-level form.
|
||||
void print(raw_ostream &os, OpPrintingFlags flags = llvm::None);
|
||||
void print(raw_ostream &os, AsmState &state,
|
||||
OpPrintingFlags flags = llvm::None);
|
||||
void dump();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Body Management.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// Iteration over the operations in the module.
|
||||
using iterator = Block::iterator;
|
||||
|
||||
iterator begin() { return getBody()->begin(); }
|
||||
iterator end() { return getBody()->end(); }
|
||||
Operation &front() { return *begin(); }
|
||||
|
||||
/// This returns a range of operations of the given type 'T' held within the
|
||||
/// module.
|
||||
template <typename T> iterator_range<Block::op_iterator<T>> getOps() {
|
||||
return getBody()->getOps<T>();
|
||||
}
|
||||
|
||||
/// Insert the operation into the back of the body, before the terminator.
|
||||
void push_back(Operation *op) {
|
||||
insert(Block::iterator(getBody()->getTerminator()), op);
|
||||
}
|
||||
|
||||
/// Insert the operation at the given insertion point. Note: The operation is
|
||||
/// never inserted after the terminator, even if the insertion point is end().
|
||||
void insert(Operation *insertPt, Operation *op) {
|
||||
insert(Block::iterator(insertPt), op);
|
||||
}
|
||||
void insert(Block::iterator insertPt, Operation *op) {
|
||||
auto *body = getBody();
|
||||
if (insertPt == body->end())
|
||||
insertPt = Block::iterator(body->getTerminator());
|
||||
body->getOperations().insert(insertPt, op);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// SymbolOpInterface Methods
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// A ModuleOp may optionally define a symbol.
|
||||
bool isOptionalSymbol() { return true; }
|
||||
};
|
||||
|
||||
/// The ModuleTerminatorOp is a special terminator operation for the body of a
|
||||
/// ModuleOp, it has no semantic meaning beyond keeping the body of a ModuleOp
|
||||
/// well-formed.
|
||||
///
|
||||
/// This operation does _not_ have a custom syntax. However, ModuleOp will omit
|
||||
/// the terminator in their custom syntax for brevity.
|
||||
class ModuleTerminatorOp
|
||||
: public Op<ModuleTerminatorOp, OpTrait::ZeroOperands, OpTrait::ZeroResult,
|
||||
OpTrait::HasParent<ModuleOp>::Impl, OpTrait::IsTerminator> {
|
||||
public:
|
||||
using Op::Op;
|
||||
static StringRef getOperationName() { return "module_terminator"; }
|
||||
static void build(OpBuilder &, OperationState &) {}
|
||||
};
|
||||
|
||||
/// This class acts as an owning reference to a module, and will automatically
|
||||
/// destroy the held module on destruction if the held module is valid.
|
||||
class OwningModuleRef : public OwningOpRefBase<ModuleOp> {
|
||||
public:
|
||||
using OwningOpRefBase<ModuleOp>::OwningOpRefBase;
|
||||
};
|
||||
|
||||
} // end namespace mlir
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Allow stealing the low bits of ModuleOp.
|
||||
template <> struct PointerLikeTypeTraits<mlir::ModuleOp> {
|
||||
public:
|
||||
static inline void *getAsVoidPointer(mlir::ModuleOp I) {
|
||||
return const_cast<void *>(I.getAsOpaquePointer());
|
||||
}
|
||||
static inline mlir::ModuleOp getFromVoidPointer(void *P) {
|
||||
return mlir::ModuleOp::getFromOpaquePointer(P);
|
||||
}
|
||||
static constexpr int NumLowBitsAvailable = 3;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
// TODO: This is a temporary forward until Module.h is removed.
|
||||
#include "mlir/IR/BuiltinDialect.h"
|
||||
|
||||
#endif // MLIR_IR_MODULE_H
|
||||
|
|
|
@ -786,6 +786,132 @@ class VariadicSuccessors
|
|||
: public detail::MultiSuccessorTraitBase<ConcreteType, VariadicSuccessors> {
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SingleBlockImplicitTerminator
|
||||
|
||||
/// This class provides APIs and verifiers for ops with regions having a single
|
||||
/// block that must terminate with `TerminatorOpType`.
|
||||
template <typename TerminatorOpType>
|
||||
struct SingleBlockImplicitTerminator {
|
||||
template <typename ConcreteType>
|
||||
class Impl : public TraitBase<ConcreteType, Impl> {
|
||||
private:
|
||||
/// Builds a terminator operation without relying on OpBuilder APIs to avoid
|
||||
/// cyclic header inclusion.
|
||||
static Operation *buildTerminator(OpBuilder &builder, Location loc) {
|
||||
OperationState state(loc, TerminatorOpType::getOperationName());
|
||||
TerminatorOpType::build(builder, state);
|
||||
return Operation::create(state);
|
||||
}
|
||||
|
||||
public:
|
||||
static LogicalResult verifyTrait(Operation *op) {
|
||||
for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
|
||||
Region ®ion = op->getRegion(i);
|
||||
|
||||
// Empty regions are fine.
|
||||
if (region.empty())
|
||||
continue;
|
||||
|
||||
// Non-empty regions must contain a single basic block.
|
||||
if (std::next(region.begin()) != region.end())
|
||||
return op->emitOpError("expects region #")
|
||||
<< i << " to have 0 or 1 blocks";
|
||||
|
||||
Block &block = region.front();
|
||||
if (block.empty())
|
||||
return op->emitOpError() << "expects a non-empty block";
|
||||
Operation &terminator = block.back();
|
||||
if (isa<TerminatorOpType>(terminator))
|
||||
continue;
|
||||
|
||||
return op->emitOpError("expects regions to end with '" +
|
||||
TerminatorOpType::getOperationName() +
|
||||
"', found '" +
|
||||
terminator.getName().getStringRef() + "'")
|
||||
.attachNote()
|
||||
<< "in custom textual format, the absence of terminator implies "
|
||||
"'"
|
||||
<< TerminatorOpType::getOperationName() << '\'';
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Ensure that the given region has the terminator required by this trait.
|
||||
/// If OpBuilder is provided, use it to build the terminator and notify the
|
||||
/// OpBuilder litsteners accordingly. If only a Builder is provided, locally
|
||||
/// construct an OpBuilder with no listeners; this should only be used if no
|
||||
/// OpBuilder is available at the call site, e.g., in the parser.
|
||||
static void ensureTerminator(Region ®ion, Builder &builder,
|
||||
Location loc) {
|
||||
::mlir::impl::ensureRegionTerminator(region, builder, loc,
|
||||
buildTerminator);
|
||||
}
|
||||
static void ensureTerminator(Region ®ion, OpBuilder &builder,
|
||||
Location loc) {
|
||||
::mlir::impl::ensureRegionTerminator(region, builder, loc,
|
||||
buildTerminator);
|
||||
}
|
||||
|
||||
Block *getBody(unsigned idx = 0) {
|
||||
Region ®ion = this->getOperation()->getRegion(idx);
|
||||
assert(!region.empty() && "unexpected empty region");
|
||||
return ®ion.front();
|
||||
}
|
||||
Region &getBodyRegion(unsigned idx = 0) {
|
||||
return this->getOperation()->getRegion(idx);
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Single Region Utilities
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// The following are a set of methods only enabled when the parent
|
||||
/// operation has a single region. Each of these methods take an additional
|
||||
/// template parameter that represents the concrete operation so that we
|
||||
/// can use SFINAE to disable the methods for non-single region operations.
|
||||
template <typename OpT, typename T = void>
|
||||
using enable_if_single_region =
|
||||
typename std::enable_if_t<OpT::template hasTrait<OneRegion>(), T>;
|
||||
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT, Block::iterator> begin() {
|
||||
return getBody()->begin();
|
||||
}
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT, Block::iterator> end() {
|
||||
return getBody()->end();
|
||||
}
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT, Operation &> front() {
|
||||
return *begin();
|
||||
}
|
||||
|
||||
/// Insert the operation into the back of the body, before the terminator.
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT> push_back(Operation *op) {
|
||||
insert(Block::iterator(getBody()->getTerminator()), op);
|
||||
}
|
||||
|
||||
/// Insert the operation at the given insertion point. Note: The operation
|
||||
/// is never inserted after the terminator, even if the insertion point is
|
||||
/// end().
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT> insert(Operation *insertPt, Operation *op) {
|
||||
insert(Block::iterator(insertPt), op);
|
||||
}
|
||||
template <typename OpT = ConcreteType>
|
||||
enable_if_single_region<OpT> insert(Block::iterator insertPt,
|
||||
Operation *op) {
|
||||
auto *body = getBody();
|
||||
if (insertPt == body->end())
|
||||
insertPt = Block::iterator(body->getTerminator());
|
||||
body->getOperations().insert(insertPt, op);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Misc Traits
|
||||
|
||||
|
@ -1036,78 +1162,6 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/// This class provides APIs and verifiers for ops with regions having a single
|
||||
/// block that must terminate with `TerminatorOpType`.
|
||||
template <typename TerminatorOpType> struct SingleBlockImplicitTerminator {
|
||||
template <typename ConcreteType>
|
||||
class Impl : public TraitBase<ConcreteType, Impl> {
|
||||
private:
|
||||
/// Builds a terminator operation without relying on OpBuilder APIs to avoid
|
||||
/// cyclic header inclusion.
|
||||
static Operation *buildTerminator(OpBuilder &builder, Location loc) {
|
||||
OperationState state(loc, TerminatorOpType::getOperationName());
|
||||
TerminatorOpType::build(builder, state);
|
||||
return Operation::create(state);
|
||||
}
|
||||
|
||||
public:
|
||||
static LogicalResult verifyTrait(Operation *op) {
|
||||
for (unsigned i = 0, e = op->getNumRegions(); i < e; ++i) {
|
||||
Region ®ion = op->getRegion(i);
|
||||
|
||||
// Empty regions are fine.
|
||||
if (region.empty())
|
||||
continue;
|
||||
|
||||
// Non-empty regions must contain a single basic block.
|
||||
if (std::next(region.begin()) != region.end())
|
||||
return op->emitOpError("expects region #")
|
||||
<< i << " to have 0 or 1 blocks";
|
||||
|
||||
Block &block = region.front();
|
||||
if (block.empty())
|
||||
return op->emitOpError() << "expects a non-empty block";
|
||||
Operation &terminator = block.back();
|
||||
if (isa<TerminatorOpType>(terminator))
|
||||
continue;
|
||||
|
||||
return op->emitOpError("expects regions to end with '" +
|
||||
TerminatorOpType::getOperationName() +
|
||||
"', found '" +
|
||||
terminator.getName().getStringRef() + "'")
|
||||
.attachNote()
|
||||
<< "in custom textual format, the absence of terminator implies "
|
||||
"'"
|
||||
<< TerminatorOpType::getOperationName() << '\'';
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Ensure that the given region has the terminator required by this trait.
|
||||
/// If OpBuilder is provided, use it to build the terminator and notify the
|
||||
/// OpBuilder litsteners accordingly. If only a Builder is provided, locally
|
||||
/// construct an OpBuilder with no listeners; this should only be used if no
|
||||
/// OpBuilder is available at the call site, e.g., in the parser.
|
||||
static void ensureTerminator(Region ®ion, Builder &builder,
|
||||
Location loc) {
|
||||
::mlir::impl::ensureRegionTerminator(region, builder, loc,
|
||||
buildTerminator);
|
||||
}
|
||||
static void ensureTerminator(Region ®ion, OpBuilder &builder,
|
||||
Location loc) {
|
||||
::mlir::impl::ensureRegionTerminator(region, builder, loc,
|
||||
buildTerminator);
|
||||
}
|
||||
|
||||
Block *getBody(unsigned idx = 0) {
|
||||
Region ®ion = this->getOperation()->getRegion(idx);
|
||||
assert(!region.empty() && "unexpected empty region");
|
||||
return ®ion.front();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/// This class provides a verifier for ops that are expecting their parent
|
||||
/// to be one of the given parent ops
|
||||
template <typename... ParentOpTypes>
|
||||
|
|
|
@ -147,9 +147,9 @@ public:
|
|||
void replaceUsesOfWith(Value from, Value to);
|
||||
|
||||
/// Replace all uses of results of this operation with the provided 'values'.
|
||||
template <typename ValuesT,
|
||||
typename = decltype(std::declval<ValuesT>().begin())>
|
||||
void replaceAllUsesWith(ValuesT &&values) {
|
||||
template <typename ValuesT>
|
||||
std::enable_if_t<!std::is_convertible<ValuesT, Operation *>::value>
|
||||
replaceAllUsesWith(ValuesT &&values) {
|
||||
assert(std::distance(values.begin(), values.end()) == getNumResults() &&
|
||||
"expected 'values' to correspond 1-1 with the number of results");
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===- Function.cpp - MLIR Function Classes -------------------------------===//
|
||||
//===- BuiltinDialect.cpp - MLIR Builtin Dialect --------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
@ -6,19 +6,65 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/Function.h"
|
||||
#include "mlir/IR/BuiltinDialect.h"
|
||||
#include "mlir/IR/BlockAndValueMapping.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/FunctionImplementation.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/StandardTypes.h"
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/Twine.h"
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Function Operation.
|
||||
// Builtin Dialect
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
|
||||
using OpAsmDialectInterface::OpAsmDialectInterface;
|
||||
|
||||
LogicalResult getAlias(Attribute attr, raw_ostream &os) const override {
|
||||
if (attr.isa<AffineMapAttr>()) {
|
||||
os << "map";
|
||||
return success();
|
||||
}
|
||||
if (attr.isa<IntegerSetAttr>()) {
|
||||
os << "set";
|
||||
return success();
|
||||
}
|
||||
if (attr.isa<LocationAttr>()) {
|
||||
os << "loc";
|
||||
return success();
|
||||
}
|
||||
return failure();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
/// A builtin dialect to define types/etc that are necessary for the validity of
|
||||
/// the IR.
|
||||
void BuiltinDialect::initialize() {
|
||||
addTypes<ComplexType, BFloat16Type, Float16Type, Float32Type, Float64Type,
|
||||
FunctionType, IndexType, IntegerType, MemRefType, UnrankedMemRefType,
|
||||
NoneType, OpaqueType, RankedTensorType, TupleType,
|
||||
UnrankedTensorType, VectorType>();
|
||||
addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
|
||||
DenseStringElementsAttr, DictionaryAttr, FloatAttr,
|
||||
SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
|
||||
OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
|
||||
UnitAttr>();
|
||||
addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
|
||||
UnknownLoc>();
|
||||
addOperations<
|
||||
#define GET_OP_LIST
|
||||
#include "mlir/IR/BuiltinOps.cpp.inc"
|
||||
>();
|
||||
addInterfaces<BuiltinOpAsmDialectInterface>();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// FuncOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
|
||||
|
@ -41,14 +87,14 @@ FuncOp FuncOp::create(Location location, StringRef name, FunctionType type,
|
|||
return func;
|
||||
}
|
||||
|
||||
void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
|
||||
void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,
|
||||
FunctionType type, ArrayRef<NamedAttribute> attrs,
|
||||
ArrayRef<MutableDictionaryAttr> argAttrs) {
|
||||
result.addAttribute(SymbolTable::getSymbolAttrName(),
|
||||
builder.getStringAttr(name));
|
||||
result.addAttribute(getTypeAttrName(), TypeAttr::get(type));
|
||||
result.attributes.append(attrs.begin(), attrs.end());
|
||||
result.addRegion();
|
||||
state.addAttribute(SymbolTable::getSymbolAttrName(),
|
||||
builder.getStringAttr(name));
|
||||
state.addAttribute(getTypeAttrName(), TypeAttr::get(type));
|
||||
state.attributes.append(attrs.begin(), attrs.end());
|
||||
state.addRegion();
|
||||
|
||||
if (argAttrs.empty())
|
||||
return;
|
||||
|
@ -56,12 +102,10 @@ void FuncOp::build(OpBuilder &builder, OperationState &result, StringRef name,
|
|||
SmallString<8> argAttrName;
|
||||
for (unsigned i = 0, e = type.getNumInputs(); i != e; ++i)
|
||||
if (auto argDict = argAttrs[i].getDictionary(builder.getContext()))
|
||||
result.addAttribute(getArgAttrName(i, argAttrName), argDict);
|
||||
state.addAttribute(getArgAttrName(i, argAttrName), argDict);
|
||||
}
|
||||
|
||||
/// Parsing/Printing methods.
|
||||
|
||||
ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
|
||||
static ParseResult parseFuncOp(OpAsmParser &parser, OperationState &result) {
|
||||
auto buildFuncType = [](Builder &builder, ArrayRef<Type> argTypes,
|
||||
ArrayRef<Type> results, impl::VariadicFlag,
|
||||
std::string &) {
|
||||
|
@ -72,25 +116,25 @@ ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {
|
|||
buildFuncType);
|
||||
}
|
||||
|
||||
void FuncOp::print(OpAsmPrinter &p) {
|
||||
FunctionType fnType = getType();
|
||||
impl::printFunctionLikeOp(p, *this, fnType.getInputs(), /*isVariadic=*/false,
|
||||
static void print(FuncOp op, OpAsmPrinter &p) {
|
||||
FunctionType fnType = op.getType();
|
||||
impl::printFunctionLikeOp(p, op, fnType.getInputs(), /*isVariadic=*/false,
|
||||
fnType.getResults());
|
||||
}
|
||||
|
||||
LogicalResult FuncOp::verify() {
|
||||
static LogicalResult verify(FuncOp op) {
|
||||
// If this function is external there is nothing to do.
|
||||
if (isExternal())
|
||||
if (op.isExternal())
|
||||
return success();
|
||||
|
||||
// Verify that the argument list of the function and the arg list of the entry
|
||||
// block line up. The trait already verified that the number of arguments is
|
||||
// the same between the signature and the block.
|
||||
auto fnInputTypes = getType().getInputs();
|
||||
Block &entryBlock = front();
|
||||
auto fnInputTypes = op.getType().getInputs();
|
||||
Block &entryBlock = op.front();
|
||||
for (unsigned i = 0, e = entryBlock.getNumArguments(); i != e; ++i)
|
||||
if (fnInputTypes[i] != entryBlock.getArgument(i).getType())
|
||||
return emitOpError("type of entry block argument #")
|
||||
return op.emitOpError("type of entry block argument #")
|
||||
<< i << '(' << entryBlock.getArgument(i).getType()
|
||||
<< ") must match the type of the corresponding argument in "
|
||||
<< "function signature(" << fnInputTypes[i] << ')';
|
||||
|
@ -152,3 +196,46 @@ FuncOp FuncOp::clone() {
|
|||
BlockAndValueMapping mapper;
|
||||
return clone(mapper);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// ModuleOp
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ModuleOp::build(OpBuilder &builder, OperationState &state,
|
||||
Optional<StringRef> name) {
|
||||
ensureTerminator(*state.addRegion(), builder, state.location);
|
||||
if (name) {
|
||||
state.attributes.push_back(builder.getNamedAttr(
|
||||
mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a module from the given context.
|
||||
ModuleOp ModuleOp::create(Location loc, Optional<StringRef> name) {
|
||||
OpBuilder builder(loc->getContext());
|
||||
return builder.create<ModuleOp>(loc, name);
|
||||
}
|
||||
|
||||
static LogicalResult verify(ModuleOp op) {
|
||||
// Check that none of the attributes are non-dialect attributes, except for
|
||||
// the symbol related attributes.
|
||||
for (auto attr : op.getAttrs()) {
|
||||
if (!attr.first.strref().contains('.') &&
|
||||
!llvm::is_contained(
|
||||
ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
|
||||
mlir::SymbolTable::getVisibilityAttrName()},
|
||||
attr.first.strref()))
|
||||
return op.emitOpError()
|
||||
<< "can only contain dialect-specific attributes, found: '"
|
||||
<< attr.first << "'";
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// TableGen'd op method definitions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "mlir/IR/BuiltinOps.cpp.inc"
|
|
@ -5,16 +5,15 @@ add_mlir_library(MLIRIR
|
|||
Attributes.cpp
|
||||
Block.cpp
|
||||
Builders.cpp
|
||||
BuiltinDialect.cpp
|
||||
Diagnostics.cpp
|
||||
Dialect.cpp
|
||||
Dominance.cpp
|
||||
Function.cpp
|
||||
FunctionImplementation.cpp
|
||||
FunctionSupport.cpp
|
||||
IntegerSet.cpp
|
||||
Location.cpp
|
||||
MLIRContext.cpp
|
||||
Module.cpp
|
||||
Operation.cpp
|
||||
OperationSupport.cpp
|
||||
PatternMatch.cpp
|
||||
|
@ -33,10 +32,11 @@ add_mlir_library(MLIRIR
|
|||
${MLIR_MAIN_INCLUDE_DIR}/mlir/IR
|
||||
|
||||
DEPENDS
|
||||
MLIRBuiltinOpsIncGen
|
||||
MLIRCallInterfacesIncGen
|
||||
MLIROpAsmInterfaceIncGen
|
||||
MLIRSymbolInterfacesIncGen
|
||||
MLIRRegionKindInterfaceIncGen
|
||||
MLIRSymbolInterfacesIncGen
|
||||
|
||||
LINK_LIBS PUBLIC
|
||||
MLIRSupport
|
||||
|
|
|
@ -82,57 +82,6 @@ void mlir::registerMLIRContextCLOptions() {
|
|||
*clOptions;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Builtin Dialect
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
namespace {
|
||||
struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
|
||||
using OpAsmDialectInterface::OpAsmDialectInterface;
|
||||
|
||||
LogicalResult getAlias(Attribute attr, raw_ostream &os) const override {
|
||||
if (attr.isa<AffineMapAttr>()) {
|
||||
os << "map";
|
||||
return success();
|
||||
}
|
||||
if (attr.isa<IntegerSetAttr>()) {
|
||||
os << "set";
|
||||
return success();
|
||||
}
|
||||
if (attr.isa<LocationAttr>()) {
|
||||
os << "loc";
|
||||
return success();
|
||||
}
|
||||
return failure();
|
||||
}
|
||||
};
|
||||
|
||||
/// A builtin dialect to define types/etc that are necessary for the validity of
|
||||
/// the IR.
|
||||
struct BuiltinDialect : public Dialect {
|
||||
BuiltinDialect(MLIRContext *context)
|
||||
: Dialect(/*name=*/"", context, TypeID::get<BuiltinDialect>()) {
|
||||
addTypes<ComplexType, BFloat16Type, Float16Type, Float32Type, Float64Type,
|
||||
FunctionType, IndexType, IntegerType, MemRefType,
|
||||
UnrankedMemRefType, NoneType, OpaqueType, RankedTensorType,
|
||||
TupleType, UnrankedTensorType, VectorType>();
|
||||
addAttributes<AffineMapAttr, ArrayAttr, DenseIntOrFPElementsAttr,
|
||||
DenseStringElementsAttr, DictionaryAttr, FloatAttr,
|
||||
SymbolRefAttr, IntegerAttr, IntegerSetAttr, OpaqueAttr,
|
||||
OpaqueElementsAttr, SparseElementsAttr, StringAttr, TypeAttr,
|
||||
UnitAttr>();
|
||||
addAttributes<CallSiteLoc, FileLineColLoc, FusedLoc, NameLoc, OpaqueLoc,
|
||||
UnknownLoc>();
|
||||
addInterfaces<BuiltinOpAsmDialectInterface>();
|
||||
|
||||
// TODO: These operations should be moved to a different dialect when they
|
||||
// have been fully decoupled from the core.
|
||||
addOperations<FuncOp, ModuleOp, ModuleTerminatorOp>();
|
||||
}
|
||||
static StringRef getDialectNamespace() { return ""; }
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Locking Utilities
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -1,104 +0,0 @@
|
|||
//===- Module.cpp - MLIR Module Operation ---------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/Module.h"
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Module Operation.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
void ModuleOp::build(OpBuilder &builder, OperationState &result,
|
||||
Optional<StringRef> name) {
|
||||
ensureTerminator(*result.addRegion(), builder, result.location);
|
||||
if (name)
|
||||
result.attributes.push_back(builder.getNamedAttr(
|
||||
mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
|
||||
}
|
||||
|
||||
/// Construct a module from the given context.
|
||||
ModuleOp ModuleOp::create(Location loc, Optional<StringRef> name) {
|
||||
OperationState state(loc, "module");
|
||||
OpBuilder builder(loc->getContext());
|
||||
ModuleOp::build(builder, state, name);
|
||||
return cast<ModuleOp>(Operation::create(state));
|
||||
}
|
||||
|
||||
ParseResult ModuleOp::parse(OpAsmParser &parser, OperationState &result) {
|
||||
// If the name is present, parse it.
|
||||
StringAttr nameAttr;
|
||||
(void)parser.parseOptionalSymbolName(
|
||||
nameAttr, mlir::SymbolTable::getSymbolAttrName(), result.attributes);
|
||||
|
||||
// If module attributes are present, parse them.
|
||||
if (parser.parseOptionalAttrDictWithKeyword(result.attributes))
|
||||
return failure();
|
||||
|
||||
// Parse the module body.
|
||||
auto *body = result.addRegion();
|
||||
if (parser.parseRegion(*body, llvm::None, llvm::None))
|
||||
return failure();
|
||||
|
||||
// Ensure that this module has a valid terminator.
|
||||
ensureTerminator(*body, parser.getBuilder(), result.location);
|
||||
return success();
|
||||
}
|
||||
|
||||
void ModuleOp::print(OpAsmPrinter &p) {
|
||||
p << "module";
|
||||
|
||||
if (Optional<StringRef> name = getName()) {
|
||||
p << ' ';
|
||||
p.printSymbolName(*name);
|
||||
}
|
||||
|
||||
// Print the module attributes.
|
||||
p.printOptionalAttrDictWithKeyword(getAttrs(),
|
||||
{mlir::SymbolTable::getSymbolAttrName()});
|
||||
|
||||
// Print the region.
|
||||
p.printRegion(getOperation()->getRegion(0), /*printEntryBlockArgs=*/false,
|
||||
/*printBlockTerminators=*/false);
|
||||
}
|
||||
|
||||
LogicalResult ModuleOp::verify() {
|
||||
auto &bodyRegion = getOperation()->getRegion(0);
|
||||
|
||||
// The body must contain a single basic block.
|
||||
if (!llvm::hasSingleElement(bodyRegion))
|
||||
return emitOpError("expected body region to have a single block");
|
||||
|
||||
// Check that none of the attributes are non-dialect attributes, except for
|
||||
// the symbol related attributes.
|
||||
for (auto attr : getOperation()->getMutableAttrDict().getAttrs()) {
|
||||
if (!attr.first.strref().contains('.') &&
|
||||
!llvm::is_contained(
|
||||
ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
|
||||
mlir::SymbolTable::getVisibilityAttrName()},
|
||||
attr.first.strref()))
|
||||
return emitOpError(
|
||||
"can only contain dialect-specific attributes, found: '")
|
||||
<< attr.first << "'";
|
||||
}
|
||||
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Return body of this module.
|
||||
Region &ModuleOp::getBodyRegion() { return getOperation()->getRegion(0); }
|
||||
Block *ModuleOp::getBody() { return &getBodyRegion().front(); }
|
||||
|
||||
Optional<StringRef> ModuleOp::getName() {
|
||||
if (auto nameAttr =
|
||||
getAttrOfType<StringAttr>(mlir::SymbolTable::getSymbolAttrName()))
|
||||
return nameAttr.getValue();
|
||||
return llvm::None;
|
||||
}
|
|
@ -303,9 +303,10 @@ void OpClass::writeDeclTo(raw_ostream &os) const {
|
|||
os << "class " << className << " : public ::mlir::Op<" << className;
|
||||
for (const auto &trait : traitsVec)
|
||||
os << ", " << trait;
|
||||
os << "> {\npublic:\n";
|
||||
os << " using Op::Op;\n";
|
||||
os << " using Adaptor = " << className << "Adaptor;\n";
|
||||
os << "> {\npublic:\n"
|
||||
<< " using Op::Op;\n"
|
||||
<< " using Op::print;\n"
|
||||
<< " using Adaptor = " << className << "Adaptor;\n";
|
||||
|
||||
bool hasPrivateMethod = false;
|
||||
forAllMethods([&](const OpMethod &method) {
|
||||
|
|
Loading…
Reference in New Issue