mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-25 21:36:05 +00:00
Revert "Introduce MLIR Op Properties"
This reverts commit d572cd1b067f1177a981a4711bf2e501eaa8117b. Some bots are broken and investigation is needed before relanding.
This commit is contained in:
parent
c3efd7ec57
commit
1e853421a4
@ -290,14 +290,12 @@ Syntax:
|
||||
operation ::= op-result-list? (generic-operation | custom-operation)
|
||||
trailing-location?
|
||||
generic-operation ::= string-literal `(` value-use-list? `)` successor-list?
|
||||
dictionary-properties? region-list? dictionary-attribute?
|
||||
`:` function-type
|
||||
region-list? dictionary-attribute? `:` function-type
|
||||
custom-operation ::= bare-id custom-operation-format
|
||||
op-result-list ::= op-result (`,` op-result)* `=`
|
||||
op-result ::= value-id (`:` integer-literal)
|
||||
successor-list ::= `[` successor (`,` successor)* `]`
|
||||
successor ::= caret-id (`:` block-arg-list)?
|
||||
dictionary-propertes ::= `<` dictionary-attribute `>`
|
||||
region-list ::= `(` region (`,` region)* `)`
|
||||
dictionary-attribute ::= `{` (attribute-entry (`,` attribute-entry)*)? `}`
|
||||
trailing-location ::= (`loc` `(` location `)`)?
|
||||
@ -314,10 +312,9 @@ semantics. For example, MLIR supports
|
||||
The internal representation of an operation is simple: an operation is
|
||||
identified by a unique string (e.g. `dim`, `tf.Conv2d`, `x86.repmovsb`,
|
||||
`ppc.eieio`, etc), can return zero or more results, take zero or more operands,
|
||||
has storage for [properties](#properties), has a dictionary of
|
||||
[attributes](#attributes), has zero or more successors, and zero or more
|
||||
enclosed [regions](#regions). The generic printing form includes all these
|
||||
elements literally, with a function type to indicate the types of the
|
||||
has a dictionary of [attributes](#attributes), has zero or more successors, and
|
||||
zero or more enclosed [regions](#regions). The generic printing form includes
|
||||
all these elements literally, with a function type to indicate the types of the
|
||||
results and operands.
|
||||
|
||||
Example:
|
||||
@ -331,11 +328,8 @@ Example:
|
||||
%foo, %bar = "foo_div"() : () -> (f32, i32)
|
||||
|
||||
// Invoke a TensorFlow function called tf.scramble with two inputs
|
||||
// and an attribute "fruit" stored in properties.
|
||||
%2 = "tf.scramble"(%result#0, %bar) <{fruit = "banana"}> : (f32, i32) -> f32
|
||||
|
||||
// Invoke an operation with some discardable attributes
|
||||
%foo, %bar = "foo_div"() {some_attr = "value", other_attr = 42 : i64} : () -> (f32, i32)
|
||||
// and an attribute "fruit".
|
||||
%2 = "tf.scramble"(%result#0, %bar) {fruit = "banana"} : (f32, i32) -> f32
|
||||
```
|
||||
|
||||
In addition to the basic syntax above, dialects may register known operations.
|
||||
@ -739,15 +733,6 @@ The [builtin dialect](Dialects/Builtin.md) defines a set of types that are
|
||||
directly usable by any other dialect in MLIR. These types cover a range from
|
||||
primitive integer and floating-point types, function types, and more.
|
||||
|
||||
## Properties
|
||||
|
||||
Properties are extra data members stored directly on an Operation class. They
|
||||
provide a way to store [inherent attributes](#attributes) and other arbitrary
|
||||
data. The semantics of the data is specific to a given operation, and may be
|
||||
exposed through [Interfaces](Interfaces.md) accessors and other methods.
|
||||
Properties can always be serialized to Attribute in order to be printed
|
||||
generically.
|
||||
|
||||
## Attributes
|
||||
|
||||
Syntax:
|
||||
@ -766,10 +751,9 @@ values. MLIR's builtin dialect provides a rich set of
|
||||
arrays, dictionaries, strings, etc.). Additionally, dialects can define their
|
||||
own [dialect attribute values](#dialect-attribute-values).
|
||||
|
||||
For dialects which haven't adopted properties yet, the top-level attribute
|
||||
dictionary attached to an operation has special semantics. The attribute
|
||||
entries are considered to be of two different kinds based on whether their
|
||||
dictionary key has a dialect prefix:
|
||||
The top-level attribute dictionary attached to an operation has special
|
||||
semantics. The attribute entries are considered to be of two different kinds
|
||||
based on whether their dictionary key has a dialect prefix:
|
||||
|
||||
- *inherent attributes* are inherent to the definition of an operation's
|
||||
semantics. The operation itself is expected to verify the consistency of
|
||||
@ -787,10 +771,6 @@ Note that attribute values are allowed to themselves be dictionary attributes,
|
||||
but only the top-level dictionary attribute attached to the operation is subject
|
||||
to the classification above.
|
||||
|
||||
When properties are adopted, only discardable attributes are stored in the
|
||||
top-level dictionary, while inherent attributes are stored in the properties
|
||||
storage.
|
||||
|
||||
### Attribute Value Aliases
|
||||
|
||||
```
|
||||
|
@ -145,11 +145,6 @@ public:
|
||||
/// Wrappers around the RewritePattern methods that pass the derived op type.
|
||||
void rewrite(Operation *op, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const final {
|
||||
if constexpr (SourceOp::hasProperties())
|
||||
rewrite(cast<SourceOp>(op),
|
||||
OpAdaptor(operands, op->getAttrDictionary(),
|
||||
cast<SourceOp>(op).getProperties()),
|
||||
rewriter);
|
||||
rewrite(cast<SourceOp>(op), OpAdaptor(operands, op->getAttrDictionary()),
|
||||
rewriter);
|
||||
}
|
||||
@ -159,11 +154,6 @@ public:
|
||||
LogicalResult
|
||||
matchAndRewrite(Operation *op, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const final {
|
||||
if constexpr (SourceOp::hasProperties())
|
||||
return matchAndRewrite(cast<SourceOp>(op),
|
||||
OpAdaptor(operands, op->getAttrDictionary(),
|
||||
cast<SourceOp>(op).getProperties()),
|
||||
rewriter);
|
||||
return matchAndRewrite(cast<SourceOp>(op),
|
||||
OpAdaptor(operands, op->getAttrDictionary()),
|
||||
rewriter);
|
||||
|
@ -103,9 +103,6 @@ class Dialect {
|
||||
|
||||
// If this dialect can be extended at runtime with new operations or types.
|
||||
bit isExtensible = 0;
|
||||
|
||||
// Whether inherent Attributes defined in ODS will be stored as Properties.
|
||||
bit usePropertiesForAttributes = 0;
|
||||
}
|
||||
|
||||
#endif // DIALECTBASE_TD
|
||||
|
@ -26,8 +26,6 @@
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/Support/TypeID.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <optional>
|
||||
|
||||
namespace mlir {
|
||||
class AsmParser;
|
||||
@ -464,35 +462,6 @@ public:
|
||||
return verifyRegionFn(op);
|
||||
}
|
||||
|
||||
/// Implementation for properties (unsupported right now here).
|
||||
std::optional<Attribute> getInherentAttr(Operation *op,
|
||||
StringRef name) final {
|
||||
llvm::report_fatal_error("Unsupported getInherentAttr on Dynamic dialects");
|
||||
}
|
||||
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final {
|
||||
llvm::report_fatal_error("Unsupported setInherentAttr on Dynamic dialects");
|
||||
}
|
||||
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final {}
|
||||
LogicalResult
|
||||
verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) final {
|
||||
return success();
|
||||
}
|
||||
int getOpPropertyByteSize() final { return 0; }
|
||||
void initProperties(OperationName opName, OpaqueProperties storage,
|
||||
OpaqueProperties init) final {}
|
||||
void deleteProperties(OpaqueProperties prop) final {}
|
||||
void populateDefaultProperties(OperationName opName,
|
||||
OpaqueProperties properties) final {}
|
||||
|
||||
LogicalResult setPropertiesFromAttr(Operation *op, Attribute attr,
|
||||
InFlightDiagnostic *diag) final {
|
||||
return failure();
|
||||
}
|
||||
Attribute getPropertiesAsAttr(Operation *op) final { return {}; }
|
||||
void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final {}
|
||||
llvm::hash_code hashProperties(OpaqueProperties prop) final { return {}; }
|
||||
|
||||
private:
|
||||
DynamicOpDefinition(
|
||||
StringRef name, ExtensibleDialect *dialect,
|
||||
|
@ -1,45 +0,0 @@
|
||||
//===- ODSSupport.h ---------------------------------------------*- 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 defines a number of support method for ODS generated code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_IR_ODSSUPPORT_H
|
||||
#define MLIR_IR_ODSSUPPORT_H
|
||||
|
||||
#include "mlir/IR/Attributes.h"
|
||||
|
||||
namespace mlir {
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Support for properties
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Convert an IntegerAttr attribute to an int64_t, or return an error if the
|
||||
/// attribute isn't an IntegerAttr. If the optional diagnostic is provided an
|
||||
/// error message is also emitted.
|
||||
LogicalResult convertFromAttribute(int64_t &storage, Attribute attr,
|
||||
InFlightDiagnostic *diag);
|
||||
|
||||
/// Convert the provided int64_t to an IntegerAttr attribute.
|
||||
Attribute convertToAttribute(MLIRContext *ctx, int64_t storage);
|
||||
|
||||
/// Convert a DenseI64ArrayAttr to the provided storage. It is expected that the
|
||||
/// storage has the same size as the array. An error is returned if the
|
||||
/// attribute isn't a DenseI64ArrayAttr or it does not have the same size. If
|
||||
/// the optional diagnostic is provided an error message is also emitted.
|
||||
LogicalResult convertFromAttribute(MutableArrayRef<int64_t> storage,
|
||||
Attribute attr, InFlightDiagnostic *diag);
|
||||
|
||||
/// Convert the provided ArrayRef<int64_t> to a DenseI64ArrayAttr attribute.
|
||||
Attribute convertToAttribute(MLIRContext *ctx, ArrayRef<int64_t> storage);
|
||||
|
||||
} // namespace mlir
|
||||
|
||||
#endif // MLIR_IR_ODSSUPPORT_H
|
@ -179,69 +179,6 @@ class TypeConstraint<Pred predicate, string summary = "",
|
||||
string cppClassName = cppClassNameParam;
|
||||
}
|
||||
|
||||
// Base class for defining properties.
|
||||
class Property<string storageTypeParam = "", string desc = ""> {
|
||||
// User-readable one line summary used in error reporting messages. If empty,
|
||||
// a generic message will be used.
|
||||
string summary = desc;
|
||||
// The full description of this property.
|
||||
string description = "";
|
||||
code storageType = storageTypeParam;
|
||||
code interfaceType = storageTypeParam;
|
||||
|
||||
// The expression to convert from the storage type to the Interface
|
||||
// type. For example, an enum can be stored as an int but returned as an
|
||||
// enum class.
|
||||
//
|
||||
// Format:
|
||||
// - `$_storage` will contain the property in the storage type.
|
||||
// - `$_ctxt` will contain an `MLIRContext *`.
|
||||
code convertFromStorage = "$_storage";
|
||||
|
||||
// The call expression to build a property storage from the interface type.
|
||||
//
|
||||
// Format:
|
||||
// - `$_storage` will contain the property in the storage type.
|
||||
// - `$_value` will contain the property in the user interface type.
|
||||
code assignToStorage = "$_storage = $_value";
|
||||
|
||||
// The call expression to convert from the storage type to an attribute.
|
||||
//
|
||||
// Format:
|
||||
// - `$_storage` is the storage type value.
|
||||
// - `$_ctxt` is a `MLIRContext *`.
|
||||
//
|
||||
// The expression must result in an Attribute.
|
||||
code convertToAttribute = [{
|
||||
convertToAttribute($_ctxt, $_storage)
|
||||
}];
|
||||
|
||||
// The call expression to convert from an Attribute to the storage type.
|
||||
//
|
||||
// Format:
|
||||
// - `$_storage` is the storage type value.
|
||||
// - `$_attr` is the attribute.
|
||||
// - `$_diag` is an optional Diagnostic pointer to emit error.
|
||||
//
|
||||
// The expression must return a LogicalResult
|
||||
code convertFromAttribute = [{
|
||||
return convertFromAttribute($_storage, $_attr, $_diag);
|
||||
}];
|
||||
|
||||
// The call expression to hash the property.
|
||||
//
|
||||
// Format:
|
||||
// - `$_storage` is the variable to hash.
|
||||
//
|
||||
// The expression should define a llvm::hash_code.
|
||||
code hashProperty = [{
|
||||
llvm::hash_value($_storage);
|
||||
}];
|
||||
|
||||
// Default value for the property.
|
||||
string defaultValue = ?;
|
||||
}
|
||||
|
||||
// Subclass for constraints on an attribute.
|
||||
class AttrConstraint<Pred predicate, string summary = ""> :
|
||||
Constraint<predicate, summary>;
|
||||
@ -1153,16 +1090,6 @@ class DefaultValuedStrAttr<Attr attr, string val>
|
||||
class DefaultValuedOptionalStrAttr<Attr attr, string val>
|
||||
: DefaultValuedOptionalAttr<attr, "\"" # val # "\"">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Primitive property kinds
|
||||
|
||||
class ArrayProperty<string storageTypeParam = "", int n, string desc = ""> :
|
||||
Property<storageTypeParam # "[" # n # "]", desc> {
|
||||
let interfaceType = "::llvm::ArrayRef<" # storageTypeParam # ">";
|
||||
let convertFromStorage = "$_storage";
|
||||
let assignToStorage = "::llvm::copy($_value, $_storage)";
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Primitive attribute kinds
|
||||
|
||||
|
@ -71,21 +71,6 @@ void ensureRegionTerminator(
|
||||
|
||||
} // namespace impl
|
||||
|
||||
/// Structure used by default as a "marker" when no "Properties" are set on an
|
||||
/// Operation.
|
||||
struct EmptyProperties {};
|
||||
|
||||
/// Traits to detect whether an Operation defined a `Properties` type, otherwise
|
||||
/// it'll default to `EmptyProperties`.
|
||||
template <class Op, class = void>
|
||||
struct PropertiesSelector {
|
||||
using type = EmptyProperties;
|
||||
};
|
||||
template <class Op>
|
||||
struct PropertiesSelector<Op, std::void_t<typename Op::Properties>> {
|
||||
using type = typename Op::Properties;
|
||||
};
|
||||
|
||||
/// This is the concrete base class that holds the operation pointer and has
|
||||
/// non-generic methods that only depend on State (to avoid having them
|
||||
/// instantiated on template types that don't affect them.
|
||||
@ -221,13 +206,6 @@ protected:
|
||||
/// in generic form.
|
||||
static void print(Operation *op, OpAsmPrinter &p, StringRef defaultDialect);
|
||||
|
||||
/// Parse properties as a Attribute.
|
||||
static ParseResult genericParseProperties(OpAsmParser &parser,
|
||||
Attribute &result);
|
||||
|
||||
/// Print the properties as a Attribute.
|
||||
static void genericPrintProperties(OpAsmPrinter &p, Attribute properties);
|
||||
|
||||
/// Print an operation name, eliding the dialect prefix if necessary.
|
||||
static void printOpName(Operation *op, OpAsmPrinter &p,
|
||||
StringRef defaultDialect);
|
||||
@ -236,14 +214,6 @@ protected:
|
||||
/// so we can cast it away here.
|
||||
explicit OpState(Operation *state) : state(state) {}
|
||||
|
||||
/// For all op which don't have properties, we keep a single instance of
|
||||
/// `EmptyProperties` to be used where a reference to a properties is needed:
|
||||
/// this allow to bind a pointer to the reference without triggering UB.
|
||||
static EmptyProperties &getEmptyProperties() {
|
||||
static EmptyProperties emptyProperties;
|
||||
return emptyProperties;
|
||||
}
|
||||
|
||||
private:
|
||||
Operation *state;
|
||||
|
||||
@ -1501,17 +1471,13 @@ namespace op_definition_impl {
|
||||
/// Returns true if this given Trait ID matches the IDs of any of the provided
|
||||
/// trait types `Traits`.
|
||||
template <template <typename T> class... Traits>
|
||||
inline bool hasTrait(TypeID traitID) {
|
||||
static bool hasTrait(TypeID traitID) {
|
||||
TypeID traitIDs[] = {TypeID::get<Traits>()...};
|
||||
for (unsigned i = 0, e = sizeof...(Traits); i != e; ++i)
|
||||
if (traitIDs[i] == traitID)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
template <>
|
||||
inline bool hasTrait<>(TypeID traitID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Trait Folding
|
||||
@ -1727,33 +1693,6 @@ public:
|
||||
(checkInterfaceTarget<Models>(), ...);
|
||||
info->attachInterface<Models...>();
|
||||
}
|
||||
/// Convert the provided attribute to a property and assigned it to the
|
||||
/// provided properties. This default implementation forwards to a free
|
||||
/// function `setPropertiesFromAttribute` that can be looked up with ADL in
|
||||
/// the namespace where the properties are defined. It can also be overridden
|
||||
/// in the derived ConcreteOp.
|
||||
template <typename PropertiesTy>
|
||||
static LogicalResult setPropertiesFromAttr(PropertiesTy &prop, Attribute attr,
|
||||
InFlightDiagnostic *diag) {
|
||||
return setPropertiesFromAttribute(prop, attr, diag);
|
||||
}
|
||||
/// Convert the provided properties to an attribute. This default
|
||||
/// implementation forwards to a free function `getPropertiesAsAttribute` that
|
||||
/// can be looked up with ADL in the namespace where the properties are
|
||||
/// defined. It can also be overridden in the derived ConcreteOp.
|
||||
template <typename PropertiesTy>
|
||||
static Attribute getPropertiesAsAttr(MLIRContext *ctx,
|
||||
const PropertiesTy &prop) {
|
||||
return getPropertiesAsAttribute(ctx, prop);
|
||||
}
|
||||
/// Hash the provided properties. This default implementation forwards to a
|
||||
/// free function `computeHash` that can be looked up with ADL in the
|
||||
/// namespace where the properties are defined. It can also be overridden in
|
||||
/// the derived ConcreteOp.
|
||||
template <typename PropertiesTy>
|
||||
static llvm::hash_code computePropertiesHash(const PropertiesTy &prop) {
|
||||
return computeHash(prop);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Trait to check if T provides a 'fold' method for a single result op.
|
||||
@ -1794,35 +1733,10 @@ private:
|
||||
template <typename T>
|
||||
using detect_has_print = llvm::is_detected<has_print, T>;
|
||||
|
||||
/// Trait to check if printProperties(OpAsmPrinter, T) exist
|
||||
template <typename T, typename... Args>
|
||||
using has_print_properties = decltype(printProperties(
|
||||
std::declval<OpAsmPrinter &>(), std::declval<T>()));
|
||||
template <typename T>
|
||||
using detect_has_print_properties =
|
||||
llvm::is_detected<has_print_properties, T>;
|
||||
|
||||
/// Trait to check if parseProperties(OpAsmParser, T) exist
|
||||
template <typename T, typename... Args>
|
||||
using has_parse_properties = decltype(parseProperties(
|
||||
std::declval<OpAsmParser &>(), std::declval<T &>()));
|
||||
template <typename T>
|
||||
using detect_has_parse_properties =
|
||||
llvm::is_detected<has_parse_properties, T>;
|
||||
|
||||
/// Trait to check if T provides a 'ConcreteEntity' type alias.
|
||||
template <typename T>
|
||||
using has_concrete_entity_t = typename T::ConcreteEntity;
|
||||
|
||||
public:
|
||||
/// Returns true if this operation defines a `Properties` inner type.
|
||||
static constexpr bool hasProperties() {
|
||||
return !std::is_same_v<
|
||||
typename ConcreteType::template InferredProperties<ConcreteType>,
|
||||
EmptyProperties>;
|
||||
}
|
||||
|
||||
private:
|
||||
/// A struct-wrapped type alias to T::ConcreteEntity if provided and to
|
||||
/// ConcreteType otherwise. This is akin to std::conditional but doesn't fail
|
||||
/// on the missing typedef. Useful for checking if the interface is targeting
|
||||
@ -1887,18 +1801,11 @@ private:
|
||||
foldSingleResultHook(Operation *op, ArrayRef<Attribute> operands,
|
||||
SmallVectorImpl<OpFoldResult> &results) {
|
||||
OpFoldResult result;
|
||||
if constexpr (has_fold_adaptor_single_result_v<ConcreteOpT>) {
|
||||
if constexpr (hasProperties()) {
|
||||
result = cast<ConcreteOpT>(op).fold(typename ConcreteOpT::FoldAdaptor(
|
||||
operands, op->getAttrDictionary(),
|
||||
cast<ConcreteOpT>(op).getProperties(), op->getRegions()));
|
||||
} else {
|
||||
result = cast<ConcreteOpT>(op).fold(typename ConcreteOpT::FoldAdaptor(
|
||||
operands, op->getAttrDictionary(), {}, op->getRegions()));
|
||||
}
|
||||
} else {
|
||||
if constexpr (has_fold_adaptor_single_result_v<ConcreteOpT>)
|
||||
result = cast<ConcreteOpT>(op).fold(typename ConcreteOpT::FoldAdaptor(
|
||||
operands, op->getAttrDictionary(), op->getRegions()));
|
||||
else
|
||||
result = cast<ConcreteOpT>(op).fold(operands);
|
||||
}
|
||||
|
||||
// If the fold failed or was in-place, try to fold the traits of the
|
||||
// operation.
|
||||
@ -1917,18 +1824,10 @@ private:
|
||||
SmallVectorImpl<OpFoldResult> &results) {
|
||||
auto result = LogicalResult::failure();
|
||||
if constexpr (has_fold_adaptor_v<ConcreteOpT>) {
|
||||
if constexpr (hasProperties()) {
|
||||
result = cast<ConcreteOpT>(op).fold(
|
||||
typename ConcreteOpT::FoldAdaptor(
|
||||
operands, op->getAttrDictionary(),
|
||||
cast<ConcreteOpT>(op).getProperties(), op->getRegions()),
|
||||
results);
|
||||
} else {
|
||||
result = cast<ConcreteOpT>(op).fold(
|
||||
typename ConcreteOpT::FoldAdaptor(operands, op->getAttrDictionary(),
|
||||
{}, op->getRegions()),
|
||||
results);
|
||||
}
|
||||
result = cast<ConcreteOpT>(op).fold(
|
||||
typename ConcreteOpT::FoldAdaptor(operands, op->getAttrDictionary(),
|
||||
op->getRegions()),
|
||||
results);
|
||||
} else {
|
||||
result = cast<ConcreteOpT>(op).fold(operands, results);
|
||||
}
|
||||
@ -1960,48 +1859,6 @@ private:
|
||||
};
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
using InferredProperties = typename PropertiesSelector<T>::type;
|
||||
template <typename T = ConcreteType>
|
||||
InferredProperties<T> &getProperties() {
|
||||
if constexpr (!hasProperties())
|
||||
return getEmptyProperties();
|
||||
return *getOperation()
|
||||
->getPropertiesStorage()
|
||||
.template as<InferredProperties<T> *>();
|
||||
}
|
||||
|
||||
/// This hook populates any unset default attrs when mapped to properties.
|
||||
template <typename T = ConcreteType>
|
||||
static void populateDefaultProperties(OperationName opName,
|
||||
InferredProperties<T> &properties) {}
|
||||
|
||||
/// Print the operation properties. Unless overridden, this method will try to
|
||||
/// dispatch to a `printProperties` free-function if it exists, and otherwise
|
||||
/// by converting the properties to an Attribute.
|
||||
template <typename T>
|
||||
static void printProperties(MLIRContext *ctx, OpAsmPrinter &p,
|
||||
const T &properties) {
|
||||
if constexpr (detect_has_print_properties<T>::value)
|
||||
return printProperties(p, properties);
|
||||
genericPrintProperties(p,
|
||||
ConcreteType::getPropertiesAsAttr(ctx, properties));
|
||||
}
|
||||
|
||||
/// Parser the properties. Unless overridden, this method will print by
|
||||
/// converting the properties to an Attribute.
|
||||
template <typename T = ConcreteType>
|
||||
static ParseResult parseProperties(OpAsmParser &parser,
|
||||
OperationState &result) {
|
||||
if constexpr (detect_has_parse_properties<InferredProperties<T>>::value) {
|
||||
return parseProperties(
|
||||
parser, result.getOrAddProperties<InferredProperties<T>>());
|
||||
}
|
||||
return genericParseProperties(parser, result.propertiesAttr);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Implementation of `PopulateDefaultAttrsFn` OperationName hook.
|
||||
static OperationName::PopulateDefaultAttrsFn getPopulateDefaultAttrsFn() {
|
||||
return ConcreteType::populateDefaultAttrs;
|
||||
|
@ -957,13 +957,13 @@ public:
|
||||
/// populated in `result`.
|
||||
template <typename AttrType>
|
||||
std::enable_if_t<detect_has_parse_method<AttrType>::value, ParseResult>
|
||||
parseCustomAttributeWithFallback(AttrType &result, Type type = {}) {
|
||||
parseCustomAttributeWithFallback(AttrType &result) {
|
||||
SMLoc loc = getCurrentLocation();
|
||||
|
||||
// Parse any kind of attribute.
|
||||
Attribute attr;
|
||||
if (parseCustomAttributeWithFallback(
|
||||
attr, type, [&](Attribute &result, Type type) -> ParseResult {
|
||||
attr, {}, [&](Attribute &result, Type type) -> ParseResult {
|
||||
result = AttrType::parse(*this, type);
|
||||
return success(!!result);
|
||||
}))
|
||||
@ -979,8 +979,8 @@ public:
|
||||
/// SFINAE parsing method for Attribute that don't implement a parse method.
|
||||
template <typename AttrType>
|
||||
std::enable_if_t<!detect_has_parse_method<AttrType>::value, ParseResult>
|
||||
parseCustomAttributeWithFallback(AttrType &result, Type type = {}) {
|
||||
return parseAttribute(result, type);
|
||||
parseCustomAttributeWithFallback(AttrType &result) {
|
||||
return parseAttribute(result);
|
||||
}
|
||||
|
||||
/// Parse an arbitrary optional attribute of a given type and return it in
|
||||
@ -1368,7 +1368,6 @@ public:
|
||||
std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
|
||||
std::nullopt,
|
||||
std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
|
||||
std::optional<Attribute> parsedPropertiesAttribute = std::nullopt,
|
||||
std::optional<FunctionType> parsedFnType = std::nullopt) = 0;
|
||||
|
||||
/// Parse a single SSA value operand name along with a result number if
|
||||
|
@ -22,12 +22,6 @@
|
||||
#include <optional>
|
||||
|
||||
namespace mlir {
|
||||
namespace detail {
|
||||
/// This is a "tag" used for mapping the properties storage in
|
||||
/// llvm::TrailingObjects.
|
||||
enum class OpProperties : char {};
|
||||
} // namespace detail
|
||||
|
||||
/// Operation is the basic unit of execution within MLIR.
|
||||
///
|
||||
/// The following documentation are recommended to understand this class:
|
||||
@ -73,35 +67,26 @@ enum class OpProperties : char {};
|
||||
/// Some operations like branches also refer to other Block, in which case they
|
||||
/// would have an array of `BlockOperand`.
|
||||
///
|
||||
/// An Operation may contain optionally a "Properties" object: this is a
|
||||
/// pre-defined C++ object with a fixed size. This object is owned by the
|
||||
/// operation and deleted with the operation. It can be converted to an
|
||||
/// Attribute on demand, or loaded from an Attribute.
|
||||
///
|
||||
///
|
||||
/// Finally an Operation also contain an optional `DictionaryAttr`, a Location,
|
||||
/// and a pointer to its parent Block (if any).
|
||||
class alignas(8) Operation final
|
||||
: public llvm::ilist_node_with_parent<Operation, Block>,
|
||||
private llvm::TrailingObjects<Operation, detail::OperandStorage,
|
||||
detail::OpProperties, BlockOperand, Region,
|
||||
OpOperand> {
|
||||
BlockOperand, Region, OpOperand> {
|
||||
public:
|
||||
/// Create a new Operation with the specific fields. This constructor
|
||||
/// populates the provided attribute list with default attributes if
|
||||
/// necessary.
|
||||
static Operation *create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
NamedAttrList &&attributes,
|
||||
OpaqueProperties properties, BlockRange successors,
|
||||
NamedAttrList &&attributes, BlockRange successors,
|
||||
unsigned numRegions);
|
||||
|
||||
/// Create a new Operation with the specific fields. This constructor uses an
|
||||
/// existing attribute dictionary to avoid uniquing a list of attributes.
|
||||
static Operation *create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
DictionaryAttr attributes,
|
||||
OpaqueProperties properties, BlockRange successors,
|
||||
DictionaryAttr attributes, BlockRange successors,
|
||||
unsigned numRegions);
|
||||
|
||||
/// Create a new Operation from the fields stored in `state`.
|
||||
@ -111,7 +96,6 @@ public:
|
||||
static Operation *create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
NamedAttrList &&attributes,
|
||||
OpaqueProperties properties,
|
||||
BlockRange successors = {},
|
||||
RegionRange regions = {});
|
||||
|
||||
@ -430,82 +414,24 @@ public:
|
||||
// constants to names. Attributes may be dynamically added and removed over
|
||||
// the lifetime of an operation.
|
||||
|
||||
/// Access an inherent attribute by name: returns an empty optional if there
|
||||
/// is no inherent attribute with this name.
|
||||
///
|
||||
/// This method is available as a transient facility in the migration process
|
||||
/// to use Properties instead.
|
||||
std::optional<Attribute> getInherentAttr(StringRef name);
|
||||
|
||||
/// Set an inherent attribute by name.
|
||||
///
|
||||
/// This method is available as a transient facility in the migration process
|
||||
/// to use Properties instead.
|
||||
void setInherentAttr(StringAttr name, Attribute value);
|
||||
|
||||
/// Access a discardable attribute by name, returns an null Attribute if the
|
||||
/// discardable attribute does not exist.
|
||||
Attribute getDiscardableAttr(StringRef name) { return attrs.get(name); }
|
||||
|
||||
/// Access a discardable attribute by name, returns an null Attribute if the
|
||||
/// discardable attribute does not exist.
|
||||
Attribute getDiscardableAttr(StringAttr name) { return attrs.get(name); }
|
||||
|
||||
/// Set a discardable attribute by name.
|
||||
void setDiscardableAttr(StringAttr name, Attribute value) {
|
||||
NamedAttrList attributes(attrs);
|
||||
if (attributes.set(name, value) != value)
|
||||
attrs = attributes.getDictionary(getContext());
|
||||
}
|
||||
|
||||
/// Return all of the discardable attributes on this operation.
|
||||
ArrayRef<NamedAttribute> getDiscardableAttrs() { return attrs.getValue(); }
|
||||
|
||||
/// Return all of the discardable attributes on this operation as a
|
||||
/// DictionaryAttr.
|
||||
DictionaryAttr getDiscardableAttrDictionary() { return attrs; }
|
||||
|
||||
/// Return all of the attributes on this operation.
|
||||
ArrayRef<NamedAttribute> getAttrs() {
|
||||
if (!getPropertiesStorage())
|
||||
return getDiscardableAttrs();
|
||||
return getAttrDictionary().getValue();
|
||||
}
|
||||
ArrayRef<NamedAttribute> getAttrs() { return attrs.getValue(); }
|
||||
|
||||
/// Return all of the attributes on this operation as a DictionaryAttr.
|
||||
DictionaryAttr getAttrDictionary();
|
||||
DictionaryAttr getAttrDictionary() { return attrs; }
|
||||
|
||||
/// Set the attributes from a dictionary on this operation.
|
||||
/// These methods are expensive: if the dictionnary only contains discardable
|
||||
/// attributes, `setDiscardableAttrs` is more efficient.
|
||||
void setAttrs(DictionaryAttr newAttrs);
|
||||
void setAttrs(ArrayRef<NamedAttribute> newAttrs);
|
||||
/// Set the discardable attribute dictionary on this operation.
|
||||
void setDiscardableAttrs(DictionaryAttr newAttrs) {
|
||||
/// Set the attribute dictionary on this operation.
|
||||
void setAttrs(DictionaryAttr newAttrs) {
|
||||
assert(newAttrs && "expected valid attribute dictionary");
|
||||
attrs = newAttrs;
|
||||
}
|
||||
void setDiscardableAttrs(ArrayRef<NamedAttribute> newAttrs) {
|
||||
setDiscardableAttrs(DictionaryAttr::get(getContext(), newAttrs));
|
||||
void setAttrs(ArrayRef<NamedAttribute> newAttrs) {
|
||||
setAttrs(DictionaryAttr::get(getContext(), newAttrs));
|
||||
}
|
||||
|
||||
/// Return the specified attribute if present, null otherwise.
|
||||
/// These methods are expensive: if the dictionnary only contains discardable
|
||||
/// attributes, `getDiscardableAttr` is more efficient.
|
||||
Attribute getAttr(StringAttr name) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
|
||||
return *inherentAttr;
|
||||
}
|
||||
return attrs.get(name);
|
||||
}
|
||||
Attribute getAttr(StringRef name) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
|
||||
return *inherentAttr;
|
||||
}
|
||||
return attrs.get(name);
|
||||
}
|
||||
Attribute getAttr(StringAttr name) { return attrs.get(name); }
|
||||
Attribute getAttr(StringRef name) { return attrs.get(name); }
|
||||
|
||||
template <typename AttrClass>
|
||||
AttrClass getAttrOfType(StringAttr name) {
|
||||
@ -518,20 +444,8 @@ public:
|
||||
|
||||
/// Return true if the operation has an attribute with the provided name,
|
||||
/// false otherwise.
|
||||
bool hasAttr(StringAttr name) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
|
||||
return (bool)*inherentAttr;
|
||||
}
|
||||
return attrs.contains(name);
|
||||
}
|
||||
bool hasAttr(StringRef name) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name))
|
||||
return (bool)*inherentAttr;
|
||||
}
|
||||
return attrs.contains(name);
|
||||
}
|
||||
bool hasAttr(StringAttr name) { return attrs.contains(name); }
|
||||
bool hasAttr(StringRef name) { return attrs.contains(name); }
|
||||
template <typename AttrClass, typename NameT>
|
||||
bool hasAttrOfType(NameT &&name) {
|
||||
return static_cast<bool>(
|
||||
@ -541,12 +455,6 @@ public:
|
||||
/// If the an attribute exists with the specified name, change it to the new
|
||||
/// value. Otherwise, add a new attribute with the specified name/value.
|
||||
void setAttr(StringAttr name, Attribute value) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name)) {
|
||||
setInherentAttr(name, value);
|
||||
return;
|
||||
}
|
||||
}
|
||||
NamedAttrList attributes(attrs);
|
||||
if (attributes.set(name, value) != value)
|
||||
attrs = attributes.getDictionary(getContext());
|
||||
@ -559,12 +467,6 @@ public:
|
||||
/// attribute that was erased, or nullptr if there was no attribute with such
|
||||
/// name.
|
||||
Attribute removeAttr(StringAttr name) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
if (std::optional<Attribute> inherentAttr = getInherentAttr(name)) {
|
||||
setInherentAttr(name, {});
|
||||
return *inherentAttr;
|
||||
}
|
||||
}
|
||||
NamedAttrList attributes(attrs);
|
||||
Attribute removedAttr = attributes.erase(name);
|
||||
if (removedAttr)
|
||||
@ -609,7 +511,7 @@ public:
|
||||
return dialect_attr_iterator(attrs.end(), attrs.end());
|
||||
}
|
||||
|
||||
/// Set the dialect attributes for this operation, and preserve all inherent.
|
||||
/// Set the dialect attributes for this operation, and preserve all dependent.
|
||||
template <typename DialectAttrT>
|
||||
void setDialectAttrs(DialectAttrT &&dialectAttrs) {
|
||||
NamedAttrList attrs;
|
||||
@ -833,44 +735,6 @@ public:
|
||||
/// handlers that may be listening.
|
||||
InFlightDiagnostic emitRemark(const Twine &message = {});
|
||||
|
||||
/// Returns the properties storage size.
|
||||
int getPropertiesStorageSize() const {
|
||||
return ((int)propertiesStorageSize) * 8;
|
||||
}
|
||||
/// Returns the properties storage.
|
||||
OpaqueProperties getPropertiesStorage() {
|
||||
if (propertiesStorageSize)
|
||||
return {
|
||||
reinterpret_cast<void *>(getTrailingObjects<detail::OpProperties>())};
|
||||
return {nullptr};
|
||||
}
|
||||
OpaqueProperties getPropertiesStorage() const {
|
||||
if (propertiesStorageSize)
|
||||
return {reinterpret_cast<void *>(const_cast<detail::OpProperties *>(
|
||||
getTrailingObjects<detail::OpProperties>()))};
|
||||
return {nullptr};
|
||||
}
|
||||
|
||||
/// Return the properties converted to an attribute.
|
||||
/// This is expensive, and mostly useful when dealing with unregistered
|
||||
/// operation. Returns an empty attribute if no properties are present.
|
||||
Attribute getPropertiesAsAttribute();
|
||||
|
||||
/// Set the properties from the provided attribute.
|
||||
/// This is an expensive operation that can fail if the attribute is not
|
||||
/// matching the expectations of the properties for this operation. This is
|
||||
/// mostly useful for unregistered operations or used when parsing the
|
||||
/// generic format. An optional diagnostic can be passed in for richer errors.
|
||||
LogicalResult setPropertiesFromAttribute(Attribute attr,
|
||||
InFlightDiagnostic *diagnostic);
|
||||
|
||||
/// Copy properties from an existing other properties object. The two objects
|
||||
/// must be the same type.
|
||||
void copyProperties(OpaqueProperties rhs);
|
||||
|
||||
/// Compute a hash for the op properties (if any).
|
||||
llvm::hash_code hashProperties();
|
||||
|
||||
private:
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Ordering
|
||||
@ -894,8 +758,7 @@ private:
|
||||
private:
|
||||
Operation(Location location, OperationName name, unsigned numResults,
|
||||
unsigned numSuccessors, unsigned numRegions,
|
||||
int propertiesStorageSize, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, bool hasOperandStorage);
|
||||
DictionaryAttr attributes, bool hasOperandStorage);
|
||||
|
||||
// Operations are deleted through the destroy() member because they are
|
||||
// allocated with malloc.
|
||||
@ -982,21 +845,13 @@ private:
|
||||
|
||||
const unsigned numResults;
|
||||
const unsigned numSuccs;
|
||||
const unsigned numRegions : 23;
|
||||
const unsigned numRegions : 31;
|
||||
|
||||
/// This bit signals whether this operation has an operand storage or not. The
|
||||
/// operand storage may be elided for operations that are known to never have
|
||||
/// operands.
|
||||
bool hasOperandStorage : 1;
|
||||
|
||||
/// The size of the storage for properties (if any), divided by 8: since the
|
||||
/// Properties storage will always be rounded up to the next multiple of 8 we
|
||||
/// save some bits here.
|
||||
unsigned char propertiesStorageSize : 8;
|
||||
/// This is the maximum size we support to allocate properties inline with an
|
||||
/// operation: this must match the bitwidth above.
|
||||
static constexpr int64_t propertiesCapacity = 8 * 256;
|
||||
|
||||
/// This holds the name of the operation.
|
||||
OperationName name;
|
||||
|
||||
@ -1016,9 +871,8 @@ private:
|
||||
friend class llvm::ilist_node_with_parent<Operation, Block>;
|
||||
|
||||
// This stuff is used by the TrailingObjects template.
|
||||
friend llvm::TrailingObjects<Operation, detail::OperandStorage,
|
||||
detail::OpProperties, BlockOperand, Region,
|
||||
OpOperand>;
|
||||
friend llvm::TrailingObjects<Operation, detail::OperandStorage, BlockOperand,
|
||||
Region, OpOperand>;
|
||||
size_t numTrailingObjects(OverloadToken<detail::OperandStorage>) const {
|
||||
return hasOperandStorage ? 1 : 0;
|
||||
}
|
||||
@ -1026,9 +880,6 @@ private:
|
||||
return numSuccs;
|
||||
}
|
||||
size_t numTrailingObjects(OverloadToken<Region>) const { return numRegions; }
|
||||
size_t numTrailingObjects(OverloadToken<detail::OpProperties>) const {
|
||||
return getPropertiesStorageSize();
|
||||
}
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &os, const Operation &op) {
|
||||
|
@ -14,10 +14,8 @@
|
||||
#ifndef MLIR_IR_OPERATIONSUPPORT_H
|
||||
#define MLIR_IR_OPERATIONSUPPORT_H
|
||||
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/BlockSupport.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/Diagnostics.h"
|
||||
#include "mlir/IR/Location.h"
|
||||
#include "mlir/IR/TypeRange.h"
|
||||
#include "mlir/IR/Types.h"
|
||||
@ -26,7 +24,6 @@
|
||||
#include "llvm/ADT/BitmaskEnum.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/STLFunctionalExtras.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/PointerLikeTypeTraits.h"
|
||||
#include "llvm/Support/TrailingObjects.h"
|
||||
#include <memory>
|
||||
@ -40,7 +37,6 @@ namespace mlir {
|
||||
class Dialect;
|
||||
class DictionaryAttr;
|
||||
class ElementsAttr;
|
||||
struct EmptyProperties;
|
||||
class MutableOperandRangeRange;
|
||||
class NamedAttrList;
|
||||
class Operation;
|
||||
@ -63,25 +59,6 @@ class ValueRange;
|
||||
template <typename ValueRangeT>
|
||||
class ValueTypeRange;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OpaqueProperties
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// Simple wrapper around a void* in order to express generically how to pass
|
||||
/// in op properties through APIs.
|
||||
class OpaqueProperties {
|
||||
public:
|
||||
OpaqueProperties(void *prop) : properties(prop) {}
|
||||
operator bool() const { return properties != nullptr; }
|
||||
template <typename Dest>
|
||||
Dest as() const {
|
||||
return static_cast<Dest>(const_cast<void *>(properties));
|
||||
}
|
||||
|
||||
private:
|
||||
void *properties;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// OperationName
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -121,26 +98,6 @@ public:
|
||||
virtual void printAssembly(Operation *, OpAsmPrinter &, StringRef) = 0;
|
||||
virtual LogicalResult verifyInvariants(Operation *) = 0;
|
||||
virtual LogicalResult verifyRegionInvariants(Operation *) = 0;
|
||||
/// Implementation for properties
|
||||
virtual std::optional<Attribute> getInherentAttr(Operation *,
|
||||
StringRef name) = 0;
|
||||
virtual void setInherentAttr(Operation *op, StringAttr name,
|
||||
Attribute value) = 0;
|
||||
virtual void populateInherentAttrs(Operation *op, NamedAttrList &attrs) = 0;
|
||||
virtual LogicalResult
|
||||
verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) = 0;
|
||||
virtual int getOpPropertyByteSize() = 0;
|
||||
virtual void initProperties(OperationName opName, OpaqueProperties storage,
|
||||
OpaqueProperties init) = 0;
|
||||
virtual void deleteProperties(OpaqueProperties) = 0;
|
||||
virtual void populateDefaultProperties(OperationName opName,
|
||||
OpaqueProperties properties) = 0;
|
||||
virtual LogicalResult setPropertiesFromAttr(Operation *, Attribute,
|
||||
InFlightDiagnostic *) = 0;
|
||||
virtual Attribute getPropertiesAsAttr(Operation *) = 0;
|
||||
virtual void copyProperties(OpaqueProperties, OpaqueProperties) = 0;
|
||||
virtual llvm::hash_code hashProperties(OpaqueProperties) = 0;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -201,25 +158,6 @@ protected:
|
||||
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final;
|
||||
LogicalResult verifyInvariants(Operation *) final;
|
||||
LogicalResult verifyRegionInvariants(Operation *) final;
|
||||
/// Implementation for properties
|
||||
std::optional<Attribute> getInherentAttr(Operation *op,
|
||||
StringRef name) final;
|
||||
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final;
|
||||
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final;
|
||||
LogicalResult
|
||||
verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) final;
|
||||
int getOpPropertyByteSize() final;
|
||||
void initProperties(OperationName opName, OpaqueProperties storage,
|
||||
OpaqueProperties init) final;
|
||||
void deleteProperties(OpaqueProperties) final;
|
||||
void populateDefaultProperties(OperationName opName,
|
||||
OpaqueProperties properties) final;
|
||||
LogicalResult setPropertiesFromAttr(Operation *, Attribute,
|
||||
InFlightDiagnostic *) final;
|
||||
Attribute getPropertiesAsAttr(Operation *) final;
|
||||
void copyProperties(OpaqueProperties, OpaqueProperties) final;
|
||||
llvm::hash_code hashProperties(OpaqueProperties) final;
|
||||
};
|
||||
|
||||
public:
|
||||
@ -371,68 +309,6 @@ public:
|
||||
return !isRegistered() || hasInterface(interfaceID);
|
||||
}
|
||||
|
||||
/// Lookup an inherent attribute by name, this method isn't recommended
|
||||
/// and may be removed in the future.
|
||||
std::optional<Attribute> getInherentAttr(Operation *op,
|
||||
StringRef name) const {
|
||||
return getImpl()->getInherentAttr(op, name);
|
||||
}
|
||||
|
||||
void setInherentAttr(Operation *op, StringAttr name, Attribute value) const {
|
||||
return getImpl()->setInherentAttr(op, name, value);
|
||||
}
|
||||
|
||||
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) const {
|
||||
return getImpl()->populateInherentAttrs(op, attrs);
|
||||
}
|
||||
/// This method exists for backward compatibility purpose when using
|
||||
/// properties to store inherent attributes, it enables validating the
|
||||
/// attributes when parsed from the older generic syntax pre-Properties.
|
||||
LogicalResult
|
||||
verifyInherentAttrs(NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) const {
|
||||
return getImpl()->verifyInherentAttrs(*this, attributes, getDiag);
|
||||
}
|
||||
/// This hooks return the number of bytes to allocate for the op properties.
|
||||
int getOpPropertyByteSize() const {
|
||||
return getImpl()->getOpPropertyByteSize();
|
||||
}
|
||||
|
||||
/// This hooks destroy the op properties.
|
||||
void destroyOpProperties(OpaqueProperties properties) const {
|
||||
getImpl()->deleteProperties(properties);
|
||||
}
|
||||
|
||||
/// Initialize the op properties.
|
||||
void initOpProperties(OpaqueProperties storage, OpaqueProperties init) const {
|
||||
getImpl()->initProperties(*this, storage, init);
|
||||
}
|
||||
|
||||
/// Set the default values on the ODS attribute in the properties.
|
||||
void populateDefaultProperties(OpaqueProperties properties) const {
|
||||
getImpl()->populateDefaultProperties(*this, properties);
|
||||
}
|
||||
|
||||
/// Return the op properties converted to an Attribute.
|
||||
Attribute getOpPropertiesAsAttribute(Operation *op) const {
|
||||
return getImpl()->getPropertiesAsAttr(op);
|
||||
}
|
||||
|
||||
/// Define the op properties from the provided Attribute.
|
||||
LogicalResult
|
||||
setOpPropertiesFromAttribute(Operation *op, Attribute properties,
|
||||
InFlightDiagnostic *diagnostic) const {
|
||||
return getImpl()->setPropertiesFromAttr(op, properties, diagnostic);
|
||||
}
|
||||
|
||||
void copyOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const {
|
||||
return getImpl()->copyProperties(lhs, rhs);
|
||||
}
|
||||
|
||||
llvm::hash_code hashOpProperties(OpaqueProperties properties) const {
|
||||
return getImpl()->hashProperties(properties);
|
||||
}
|
||||
|
||||
/// Return the dialect this operation is registered to if the dialect is
|
||||
/// loaded in the context, or nullptr if the dialect isn't loaded.
|
||||
Dialect *getDialect() const {
|
||||
@ -537,104 +413,6 @@ public:
|
||||
LogicalResult verifyRegionInvariants(Operation *op) final {
|
||||
return ConcreteOp::getVerifyRegionInvariantsFn()(op);
|
||||
}
|
||||
|
||||
/// Implementation for "Properties"
|
||||
|
||||
using Properties = std::remove_reference_t<
|
||||
decltype(std::declval<ConcreteOp>().getProperties())>;
|
||||
|
||||
std::optional<Attribute> getInherentAttr(Operation *op,
|
||||
StringRef name) final {
|
||||
if constexpr (hasProperties) {
|
||||
auto concreteOp = cast<ConcreteOp>(op);
|
||||
return ConcreteOp::getInherentAttr(concreteOp.getProperties(), name);
|
||||
}
|
||||
// If the op does not have support for properties, we dispatch back to the
|
||||
// dictionnary of discardable attributes for now.
|
||||
return cast<ConcreteOp>(op)->getDiscardableAttr(name);
|
||||
}
|
||||
void setInherentAttr(Operation *op, StringAttr name,
|
||||
Attribute value) final {
|
||||
if constexpr (hasProperties) {
|
||||
auto concreteOp = cast<ConcreteOp>(op);
|
||||
return ConcreteOp::setInherentAttr(concreteOp.getProperties(), name,
|
||||
value);
|
||||
}
|
||||
// If the op does not have support for properties, we dispatch back to the
|
||||
// dictionnary of discardable attributes for now.
|
||||
return cast<ConcreteOp>(op)->setDiscardableAttr(name, value);
|
||||
}
|
||||
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final {
|
||||
if constexpr (hasProperties) {
|
||||
auto concreteOp = cast<ConcreteOp>(op);
|
||||
ConcreteOp::populateInherentAttrs(concreteOp.getProperties(), attrs);
|
||||
}
|
||||
}
|
||||
LogicalResult
|
||||
verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) final {
|
||||
if constexpr (hasProperties)
|
||||
return ConcreteOp::verifyInherentAttrs(opName, attributes, getDiag);
|
||||
return success();
|
||||
}
|
||||
// Detect if the concrete operation defined properties.
|
||||
static constexpr bool hasProperties = !std::is_same_v<
|
||||
typename ConcreteOp::template InferredProperties<ConcreteOp>,
|
||||
EmptyProperties>;
|
||||
|
||||
int getOpPropertyByteSize() final {
|
||||
if constexpr (hasProperties)
|
||||
return sizeof(Properties);
|
||||
return 0;
|
||||
}
|
||||
void initProperties(OperationName opName, OpaqueProperties storage,
|
||||
OpaqueProperties init) final {
|
||||
using Properties =
|
||||
typename ConcreteOp::template InferredProperties<ConcreteOp>;
|
||||
if (init)
|
||||
new (storage.as<Properties *>()) Properties(*init.as<Properties *>());
|
||||
else
|
||||
new (storage.as<Properties *>()) Properties();
|
||||
if constexpr (hasProperties)
|
||||
ConcreteOp::populateDefaultProperties(opName,
|
||||
*storage.as<Properties *>());
|
||||
}
|
||||
void deleteProperties(OpaqueProperties prop) final {
|
||||
prop.as<Properties *>()->~Properties();
|
||||
}
|
||||
void populateDefaultProperties(OperationName opName,
|
||||
OpaqueProperties properties) final {
|
||||
if constexpr (hasProperties)
|
||||
ConcreteOp::populateDefaultProperties(opName,
|
||||
*properties.as<Properties *>());
|
||||
}
|
||||
|
||||
LogicalResult setPropertiesFromAttr(Operation *op, Attribute attr,
|
||||
InFlightDiagnostic *diag) final {
|
||||
if constexpr (hasProperties)
|
||||
return ConcreteOp::setPropertiesFromAttr(
|
||||
cast<ConcreteOp>(op).getProperties(), attr, diag);
|
||||
if (diag)
|
||||
*diag << "This operation does not support properties";
|
||||
return failure();
|
||||
}
|
||||
Attribute getPropertiesAsAttr(Operation *op) final {
|
||||
if constexpr (hasProperties) {
|
||||
auto concreteOp = cast<ConcreteOp>(op);
|
||||
return ConcreteOp::getPropertiesAsAttr(concreteOp->getContext(),
|
||||
concreteOp.getProperties());
|
||||
}
|
||||
return {};
|
||||
}
|
||||
void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final {
|
||||
*lhs.as<Properties *>() = *rhs.as<Properties *>();
|
||||
}
|
||||
llvm::hash_code hashProperties(OpaqueProperties prop) final {
|
||||
if constexpr (hasProperties)
|
||||
return ConcreteOp::computePropertiesHash(*prop.as<Properties *>());
|
||||
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
/// Lookup the registered operation information for the given operation.
|
||||
@ -822,11 +600,6 @@ public:
|
||||
assign(range.begin(), range.end());
|
||||
}
|
||||
|
||||
void clear() {
|
||||
attrs.clear();
|
||||
dictionarySorted.setPointerAndInt(nullptr, false);
|
||||
}
|
||||
|
||||
bool empty() const { return attrs.empty(); }
|
||||
|
||||
void reserve(size_type N) { attrs.reserve(N); }
|
||||
@ -921,19 +694,6 @@ struct OperationState {
|
||||
/// Regions that the op will hold.
|
||||
SmallVector<std::unique_ptr<Region>, 1> regions;
|
||||
|
||||
// If we're creating an unregistered operation, this Attribute is used to
|
||||
// build the properties. Otherwise it is ignored. For registered operations
|
||||
// see the `getOrAddProperties` method.
|
||||
Attribute propertiesAttr;
|
||||
|
||||
private:
|
||||
OpaqueProperties properties = nullptr;
|
||||
TypeID propertiesId;
|
||||
llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
|
||||
llvm::function_ref<void(OpaqueProperties, const OpaqueProperties)>
|
||||
propertiesSetter;
|
||||
friend class Operation;
|
||||
|
||||
public:
|
||||
OperationState(Location location, StringRef name);
|
||||
OperationState(Location location, OperationName name);
|
||||
@ -946,37 +706,6 @@ public:
|
||||
TypeRange types, ArrayRef<NamedAttribute> attributes = {},
|
||||
BlockRange successors = {},
|
||||
MutableArrayRef<std::unique_ptr<Region>> regions = {});
|
||||
OperationState(OperationState &&other) = default;
|
||||
OperationState(const OperationState &other) = default;
|
||||
OperationState &operator=(OperationState &&other) = default;
|
||||
OperationState &operator=(const OperationState &other) = default;
|
||||
~OperationState();
|
||||
|
||||
/// Get (or create) a properties of the provided type to be set on the
|
||||
/// operation on creation.
|
||||
template <typename T>
|
||||
T &getOrAddProperties() {
|
||||
if (!properties) {
|
||||
T *p = new T{};
|
||||
properties = p;
|
||||
propertiesDeleter = [](OpaqueProperties prop) {
|
||||
delete prop.as<const T *>();
|
||||
};
|
||||
propertiesSetter = [](OpaqueProperties new_prop,
|
||||
const OpaqueProperties prop) {
|
||||
*new_prop.as<T *>() = *prop.as<const T *>();
|
||||
};
|
||||
propertiesId = TypeID::get<T>();
|
||||
}
|
||||
assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
|
||||
return *properties.as<T *>();
|
||||
}
|
||||
OpaqueProperties getRawProperties() { return properties; }
|
||||
|
||||
// Set the properties defined on this OpState on the given operation,
|
||||
// optionally emit diagnostics on error through the provided diagnostic.
|
||||
LogicalResult setProperties(Operation *op,
|
||||
InFlightDiagnostic *diagnostic) const;
|
||||
|
||||
void addOperands(ValueRange newOperands);
|
||||
|
||||
|
@ -244,11 +244,11 @@ LogicalResult inferReturnTensorTypes(
|
||||
function_ref<
|
||||
LogicalResult(MLIRContext *, std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &retComponents)>
|
||||
componentTypeFn,
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes);
|
||||
|
||||
/// Verifies that the inferred result types match the actual result types for
|
||||
@ -281,7 +281,7 @@ public:
|
||||
static LogicalResult
|
||||
inferReturnTypes(MLIRContext *context, std::optional<Location> location,
|
||||
ValueRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
static_assert(
|
||||
ConcreteType::template hasTrait<InferShapedTypeOpInterface::Trait>(),
|
||||
@ -291,7 +291,7 @@ public:
|
||||
"requires InferTypeOpInterface to ensure succesful invocation");
|
||||
return ::mlir::detail::inferReturnTensorTypes(
|
||||
ConcreteType::inferReturnTypeComponents, context, location, operands,
|
||||
attributes, properties, regions, inferredReturnTypes);
|
||||
attributes, regions, inferredReturnTypes);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -44,7 +44,6 @@ def InferTypeOpInterface : OpInterface<"InferTypeOpInterface"> {
|
||||
"::std::optional<::mlir::Location>":$location,
|
||||
"::mlir::ValueRange":$operands,
|
||||
"::mlir::DictionaryAttr":$attributes,
|
||||
"::mlir::OpaqueProperties":$properties,
|
||||
"::mlir::RegionRange":$regions,
|
||||
"::llvm::SmallVectorImpl<::mlir::Type>&":$inferredReturnTypes)
|
||||
>,
|
||||
@ -76,14 +75,13 @@ def InferTypeOpInterface : OpInterface<"InferTypeOpInterface"> {
|
||||
"::std::optional<::mlir::Location>":$location,
|
||||
"::mlir::ValueRange":$operands,
|
||||
"::mlir::DictionaryAttr":$attributes,
|
||||
"::mlir::OpaqueProperties":$properties,
|
||||
"::mlir::RegionRange":$regions,
|
||||
"::llvm::SmallVectorImpl<::mlir::Type>&":$returnTypes),
|
||||
/*methodBody=*/[{}],
|
||||
/*defaultImplementation=*/[{
|
||||
llvm::SmallVector<Type, 4> inferredReturnTypes;
|
||||
if (failed(ConcreteOp::inferReturnTypes(context, location, operands,
|
||||
attributes, properties, regions,
|
||||
attributes, regions,
|
||||
inferredReturnTypes)))
|
||||
return failure();
|
||||
if (!ConcreteOp::isCompatibleReturnTypes(inferredReturnTypes,
|
||||
@ -149,7 +147,6 @@ def InferShapedTypeOpInterface : OpInterface<"InferShapedTypeOpInterface"> {
|
||||
"::std::optional<::mlir::Location>":$location,
|
||||
"::mlir::ValueShapeRange":$operands,
|
||||
"::mlir::DictionaryAttr":$attributes,
|
||||
"::mlir::OpaqueProperties":$properties,
|
||||
"::mlir::RegionRange":$regions,
|
||||
"::llvm::SmallVectorImpl<::mlir::ShapedTypeComponents>&":
|
||||
$inferredReturnShapes),
|
||||
|
@ -22,7 +22,6 @@
|
||||
#define MLIR_TABLEGEN_ARGUMENT_H_
|
||||
|
||||
#include "mlir/TableGen/Attribute.h"
|
||||
#include "mlir/TableGen/Property.h"
|
||||
#include "mlir/TableGen/Type.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include <string>
|
||||
@ -59,9 +58,8 @@ struct NamedTypeConstraint {
|
||||
TypeConstraint constraint;
|
||||
};
|
||||
|
||||
// Operation argument: either attribute, property, or operand
|
||||
using Argument = llvm::PointerUnion<NamedAttribute *, NamedProperty *,
|
||||
NamedTypeConstraint *>;
|
||||
// Operation argument: either attribute or operand
|
||||
using Argument = llvm::PointerUnion<NamedAttribute *, NamedTypeConstraint *>;
|
||||
|
||||
} // namespace tblgen
|
||||
} // namespace mlir
|
||||
|
@ -576,12 +576,7 @@ class ExtraClassDeclaration
|
||||
public:
|
||||
/// Create an extra class declaration.
|
||||
ExtraClassDeclaration(StringRef extraClassDeclaration,
|
||||
std::string extraClassDefinition = "")
|
||||
: ExtraClassDeclaration(extraClassDeclaration.str(),
|
||||
std::move(extraClassDefinition)) {}
|
||||
|
||||
ExtraClassDeclaration(std::string extraClassDeclaration,
|
||||
std::string extraClassDefinition = "")
|
||||
StringRef extraClassDefinition = "")
|
||||
: extraClassDeclaration(extraClassDeclaration),
|
||||
extraClassDefinition(extraClassDefinition) {}
|
||||
|
||||
@ -595,7 +590,7 @@ public:
|
||||
private:
|
||||
/// The string of the extra class declarations. It is re-indented before
|
||||
/// printed.
|
||||
std::string extraClassDeclaration;
|
||||
StringRef extraClassDeclaration;
|
||||
/// The string of the extra class definitions. It is re-indented before
|
||||
/// printed.
|
||||
std::string extraClassDefinition;
|
||||
|
@ -86,10 +86,6 @@ public:
|
||||
/// operations or types.
|
||||
bool isExtensible() const;
|
||||
|
||||
/// Default to use properties for storing Attributes for operations in this
|
||||
/// dialect.
|
||||
bool usePropertiesForAttributes() const;
|
||||
|
||||
// Returns whether two dialects are equal by checking the equality of the
|
||||
// underlying record.
|
||||
bool operator==(const Dialect &other) const;
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "mlir/TableGen/Attribute.h"
|
||||
#include "mlir/TableGen/Builder.h"
|
||||
#include "mlir/TableGen/Dialect.h"
|
||||
#include "mlir/TableGen/Property.h"
|
||||
#include "mlir/TableGen/Region.h"
|
||||
#include "mlir/TableGen/Successor.h"
|
||||
#include "mlir/TableGen/Trait.h"
|
||||
@ -167,14 +166,10 @@ public:
|
||||
unsigned getNumVariableLengthResults() const;
|
||||
|
||||
/// Op attribute iterators.
|
||||
using const_attribute_iterator = const NamedAttribute *;
|
||||
const_attribute_iterator attribute_begin() const;
|
||||
const_attribute_iterator attribute_end() const;
|
||||
llvm::iterator_range<const_attribute_iterator> getAttributes() const;
|
||||
using attribute_iterator = NamedAttribute *;
|
||||
attribute_iterator attribute_begin();
|
||||
attribute_iterator attribute_end();
|
||||
llvm::iterator_range<attribute_iterator> getAttributes();
|
||||
using attribute_iterator = const NamedAttribute *;
|
||||
attribute_iterator attribute_begin() const;
|
||||
attribute_iterator attribute_end() const;
|
||||
llvm::iterator_range<attribute_iterator> getAttributes() const;
|
||||
|
||||
int getNumAttributes() const { return attributes.size(); }
|
||||
int getNumNativeAttributes() const { return numNativeAttributes; }
|
||||
@ -190,27 +185,6 @@ public:
|
||||
const_value_iterator operand_end() const;
|
||||
const_value_range getOperands() const;
|
||||
|
||||
// Op properties iterators.
|
||||
using const_property_iterator = const NamedProperty *;
|
||||
const_property_iterator properties_begin() const {
|
||||
return properties.begin();
|
||||
}
|
||||
const_property_iterator properties_end() const { return properties.end(); }
|
||||
llvm::iterator_range<const_property_iterator> getProperties() const {
|
||||
return properties;
|
||||
}
|
||||
using property_iterator = NamedProperty *;
|
||||
property_iterator properties_begin() { return properties.begin(); }
|
||||
property_iterator properties_end() { return properties.end(); }
|
||||
llvm::iterator_range<property_iterator> getProperties() { return properties; }
|
||||
int getNumCoreAttributes() const { return properties.size(); }
|
||||
|
||||
// Op properties accessors.
|
||||
NamedProperty &getProperty(int index) { return properties[index]; }
|
||||
const NamedProperty &getProperty(int index) const {
|
||||
return properties[index];
|
||||
}
|
||||
|
||||
int getNumOperands() const { return operands.size(); }
|
||||
NamedTypeConstraint &getOperand(int index) { return operands[index]; }
|
||||
const NamedTypeConstraint &getOperand(int index) const {
|
||||
@ -379,9 +353,6 @@ private:
|
||||
/// computed upon request).
|
||||
SmallVector<NamedAttribute, 4> attributes;
|
||||
|
||||
/// The properties of the op.
|
||||
SmallVector<NamedProperty> properties;
|
||||
|
||||
/// The arguments of the op (operands and native attributes).
|
||||
SmallVector<Argument, 4> arguments;
|
||||
|
||||
|
@ -1,86 +0,0 @@
|
||||
//===- Property.h - Property wrapper class --------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Property wrapper to simplify using TableGen Record defining a MLIR
|
||||
// Property.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef MLIR_TABLEGEN_PROPERTY_H_
|
||||
#define MLIR_TABLEGEN_PROPERTY_H_
|
||||
|
||||
#include "mlir/Support/LLVM.h"
|
||||
#include "mlir/TableGen/Constraint.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
namespace llvm {
|
||||
class DefInit;
|
||||
class Record;
|
||||
} // namespace llvm
|
||||
|
||||
namespace mlir {
|
||||
namespace tblgen {
|
||||
class Dialect;
|
||||
class Type;
|
||||
|
||||
// Wrapper class providing helper methods for accessing MLIR Property defined
|
||||
// in TableGen. This class should closely reflect what is defined as class
|
||||
// `Property` in TableGen.
|
||||
class Property {
|
||||
public:
|
||||
explicit Property(const llvm::Record *record);
|
||||
explicit Property(const llvm::DefInit *init);
|
||||
|
||||
// Returns the storage type.
|
||||
StringRef getStorageType() const;
|
||||
|
||||
// Returns the interface type for this property.
|
||||
StringRef getInterfaceType() const;
|
||||
|
||||
// Returns the template getter method call which reads this property's
|
||||
// storage and returns the value as of the desired return type.
|
||||
StringRef getConvertFromStorageCall() const;
|
||||
|
||||
// Returns the template setter method call which reads this property's
|
||||
// in the provided interface type and assign it to the storage.
|
||||
StringRef getAssignToStorageCall() const;
|
||||
|
||||
// Returns the conversion method call which reads this property's
|
||||
// in the storage type and builds an attribute.
|
||||
StringRef getConvertToAttributeCall() const;
|
||||
|
||||
// Returns the setter method call which reads this property's
|
||||
// in the provided interface type and assign it to the storage.
|
||||
StringRef getConvertFromAttributeCall() const;
|
||||
|
||||
// Returns the code to compute the hash for this property.
|
||||
StringRef getHashPropertyCall() const;
|
||||
|
||||
// Returns whether this Property has a default value.
|
||||
bool hasDefaultValue() const;
|
||||
// Returns the default value for this Property.
|
||||
StringRef getDefaultValue() const;
|
||||
|
||||
// Returns the TableGen definition this Property was constructed from.
|
||||
const llvm::Record &getDef() const;
|
||||
|
||||
private:
|
||||
// The TableGen definition of this constraint.
|
||||
const llvm::Record *def;
|
||||
};
|
||||
|
||||
// A struct wrapping an op property and its name together
|
||||
struct NamedProperty {
|
||||
llvm::StringRef name;
|
||||
Property prop;
|
||||
};
|
||||
|
||||
} // namespace tblgen
|
||||
} // namespace mlir
|
||||
|
||||
#endif // MLIR_TABLEGEN_PROPERTY_H_
|
@ -526,14 +526,9 @@ public:
|
||||
LogicalResult
|
||||
matchAndRewrite(Operation *op, ArrayRef<Value> operands,
|
||||
ConversionPatternRewriter &rewriter) const final {
|
||||
auto sourceOp = cast<SourceOp>(op);
|
||||
if constexpr (SourceOp::hasProperties())
|
||||
return matchAndRewrite(sourceOp,
|
||||
OpAdaptor(operands, op->getAttrDictionary(),
|
||||
sourceOp.getProperties()),
|
||||
rewriter);
|
||||
return matchAndRewrite(
|
||||
sourceOp, OpAdaptor(operands, op->getAttrDictionary()), rewriter);
|
||||
return matchAndRewrite(cast<SourceOp>(op),
|
||||
OpAdaptor(operands, op->getAttrDictionary()),
|
||||
rewriter);
|
||||
}
|
||||
|
||||
/// Rewrite and Match methods that operate on the SourceOp type. These must be
|
||||
|
@ -225,16 +225,13 @@ public:
|
||||
public:
|
||||
using RangeT = ArrayRef<ValueRange>;
|
||||
using BaseT = typename SourceOp::template GenericAdaptor<RangeT>;
|
||||
using Properties = typename SourceOp::template InferredProperties<SourceOp>;
|
||||
|
||||
OpAdaptor(const OneToNTypeMapping *operandMapping,
|
||||
const OneToNTypeMapping *resultMapping,
|
||||
const ValueRange *convertedOperands, RangeT values,
|
||||
DictionaryAttr attrs = nullptr, Properties &properties = {},
|
||||
RegionRange regions = {})
|
||||
: BaseT(values, attrs, properties, regions),
|
||||
operandMapping(operandMapping), resultMapping(resultMapping),
|
||||
convertedOperands(convertedOperands) {}
|
||||
DictionaryAttr attrs = nullptr, RegionRange regions = {})
|
||||
: BaseT(values, attrs, regions), operandMapping(operandMapping),
|
||||
resultMapping(resultMapping), convertedOperands(convertedOperands) {}
|
||||
|
||||
/// Get the type mapping of the original operands to the converted operands.
|
||||
const OneToNTypeMapping &getOperandMapping() const {
|
||||
@ -274,8 +271,7 @@ public:
|
||||
valueRanges.push_back(values);
|
||||
}
|
||||
OpAdaptor adaptor(&operandMapping, &resultMapping, &convertedOperands,
|
||||
valueRanges, op->getAttrDictionary(),
|
||||
cast<SourceOp>(op).getProperties(), op->getRegions());
|
||||
valueRanges, op->getAttrDictionary(), op->getRegions());
|
||||
|
||||
// Call overload implemented by the derived class.
|
||||
return matchAndRewrite(cast<SourceOp>(op), adaptor, rewriter);
|
||||
|
@ -540,7 +540,6 @@ public:
|
||||
std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions =
|
||||
std::nullopt,
|
||||
std::optional<ArrayRef<NamedAttribute>> parsedAttributes = std::nullopt,
|
||||
std::optional<Attribute> propertiesAttribute = std::nullopt,
|
||||
std::optional<FunctionType> parsedFnType = std::nullopt);
|
||||
|
||||
/// Parse an operation instance that is in the generic form and insert it at
|
||||
@ -1076,8 +1075,7 @@ Value OperationParser::createForwardRefPlaceholder(SMLoc loc, Type type) {
|
||||
auto name = OperationName("builtin.unrealized_conversion_cast", getContext());
|
||||
auto *op = Operation::create(
|
||||
getEncodedSourceLocation(loc), name, type, /*operands=*/{},
|
||||
/*attributes=*/std::nullopt, /*properties=*/nullptr, /*successors=*/{},
|
||||
/*numRegions=*/0);
|
||||
/*attributes=*/std::nullopt, /*successors=*/{}, /*numRegions=*/0);
|
||||
forwardRefPlaceholders[op->getResult(0)] = loc;
|
||||
return op->getResult(0);
|
||||
}
|
||||
@ -1257,7 +1255,6 @@ ParseResult OperationParser::parseGenericOperationAfterOpName(
|
||||
std::optional<ArrayRef<Block *>> parsedSuccessors,
|
||||
std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
|
||||
std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
|
||||
std::optional<Attribute> propertiesAttribute,
|
||||
std::optional<FunctionType> parsedFnType) {
|
||||
|
||||
// Parse the operand list, if not explicitly provided.
|
||||
@ -1287,16 +1284,6 @@ ParseResult OperationParser::parseGenericOperationAfterOpName(
|
||||
result.addSuccessors(*parsedSuccessors);
|
||||
}
|
||||
|
||||
// Parse the properties, if not explicitly provided.
|
||||
if (propertiesAttribute) {
|
||||
result.propertiesAttr = *propertiesAttribute;
|
||||
} else if (consumeIf(Token::less)) {
|
||||
result.propertiesAttr = parseAttribute();
|
||||
if (!result.propertiesAttr)
|
||||
return failure();
|
||||
if (parseToken(Token::greater, "expected '>' to close properties"))
|
||||
return failure();
|
||||
}
|
||||
// Parse the region list, if not explicitly provided.
|
||||
if (!parsedRegions) {
|
||||
if (consumeIf(Token::l_paren)) {
|
||||
@ -1403,52 +1390,10 @@ Operation *OperationParser::parseGenericOperation() {
|
||||
if (parseGenericOperationAfterOpName(result))
|
||||
return nullptr;
|
||||
|
||||
// Operation::create() is not allowed to fail, however setting the properties
|
||||
// from an attribute is a failable operation. So we save the attribute here
|
||||
// and set it on the operation post-parsing.
|
||||
Attribute properties;
|
||||
std::swap(properties, result.propertiesAttr);
|
||||
|
||||
// If we don't have properties in the textual IR, but the operation now has
|
||||
// support for properties, we support some backward-compatible generic syntax
|
||||
// for the operation and as such we accept inherent attributes mixed in the
|
||||
// dictionary of discardable attributes. We pre-validate these here because
|
||||
// invalid attributes can't be casted to the properties storage and will be
|
||||
// silently dropped. For example an attribute { foo = 0 : i32 } that is
|
||||
// declared as F32Attr in ODS would have a C++ type of FloatAttr in the
|
||||
// properties array. When setting it we would do something like:
|
||||
//
|
||||
// properties.foo = dyn_cast<FloatAttr>(fooAttr);
|
||||
//
|
||||
// which would end up with a null Attribute. The diagnostic from the verifier
|
||||
// would be "missing foo attribute" instead of something like "expects a 32
|
||||
// bits float attribute but got a 32 bits integer attribute".
|
||||
if (!properties && !result.getRawProperties()) {
|
||||
Optional<RegisteredOperationName> info = result.name.getRegisteredInfo();
|
||||
if (info) {
|
||||
if (failed(info->verifyInherentAttrs(result.attributes, [&]() {
|
||||
return mlir::emitError(srcLocation) << "'" << name << "' op ";
|
||||
})))
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the operation and try to parse a location for it.
|
||||
Operation *op = opBuilder.create(result);
|
||||
if (parseTrailingLocationSpecifier(op))
|
||||
return nullptr;
|
||||
|
||||
// Try setting the properties for the operation, using a diagnostic to print
|
||||
// errors.
|
||||
if (properties) {
|
||||
InFlightDiagnostic diagnostic =
|
||||
mlir::emitError(srcLocation, "invalid properties ")
|
||||
<< properties << " for op " << name << ": ";
|
||||
if (failed(op->setPropertiesFromAttribute(properties, &diagnostic)))
|
||||
return nullptr;
|
||||
diagnostic.abandon();
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
@ -1516,11 +1461,10 @@ public:
|
||||
std::optional<ArrayRef<Block *>> parsedSuccessors,
|
||||
std::optional<MutableArrayRef<std::unique_ptr<Region>>> parsedRegions,
|
||||
std::optional<ArrayRef<NamedAttribute>> parsedAttributes,
|
||||
std::optional<Attribute> parsedPropertiesAttribute,
|
||||
std::optional<FunctionType> parsedFnType) final {
|
||||
return parser.parseGenericOperationAfterOpName(
|
||||
result, parsedUnresolvedOperands, parsedSuccessors, parsedRegions,
|
||||
parsedAttributes, parsedPropertiesAttribute, parsedFnType);
|
||||
parsedAttributes, parsedFnType);
|
||||
}
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Utilities
|
||||
@ -1989,23 +1933,10 @@ OperationParser::parseCustomOperation(ArrayRef<ResultRecord> resultIDs) {
|
||||
if (opAsmParser.didEmitError())
|
||||
return nullptr;
|
||||
|
||||
Attribute properties = opState.propertiesAttr;
|
||||
opState.propertiesAttr = Attribute{};
|
||||
|
||||
// Otherwise, create the operation and try to parse a location for it.
|
||||
Operation *op = opBuilder.create(opState);
|
||||
if (parseTrailingLocationSpecifier(op))
|
||||
return nullptr;
|
||||
|
||||
// Try setting the properties for the operation.
|
||||
if (properties) {
|
||||
InFlightDiagnostic diagnostic =
|
||||
mlir::emitError(srcLocation, "invalid properties ")
|
||||
<< properties << " for op " << op->getName().getStringRef() << ": ";
|
||||
if (failed(op->setPropertiesFromAttribute(properties, &diagnostic)))
|
||||
return nullptr;
|
||||
diagnostic.abandon();
|
||||
}
|
||||
return op;
|
||||
}
|
||||
|
||||
|
@ -340,8 +340,7 @@ static LogicalResult inferOperationTypes(OperationState &state) {
|
||||
|
||||
if (succeeded(inferInterface->inferReturnTypes(
|
||||
context, state.location, state.operands,
|
||||
state.attributes.getDictionary(context), state.getRawProperties(),
|
||||
state.regions, state.types)))
|
||||
state.attributes.getDictionary(context), state.regions, state.types)))
|
||||
return success();
|
||||
|
||||
// Diagnostic emitted by interface.
|
||||
|
@ -113,7 +113,6 @@ private:
|
||||
resultTypes.push_back(tokenType);
|
||||
auto *newOp = Operation::create(op->getLoc(), op->getName(), resultTypes,
|
||||
op->getOperands(), op->getAttrDictionary(),
|
||||
op->getPropertiesStorage(),
|
||||
op->getSuccessors(), op->getNumRegions());
|
||||
|
||||
// Clone regions into new op.
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "mlir/IR/Builders.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Matchers.h"
|
||||
#include "mlir/IR/OpDefinition.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "mlir/IR/TypeUtilities.h"
|
||||
#include "mlir/Interfaces/InferTypeOpInterface.h"
|
||||
@ -1355,10 +1354,9 @@ void ExtractAlignedPointerAsIndexOp::getAsmResultNames(
|
||||
/// shape of the source.
|
||||
LogicalResult ExtractStridedMetadataOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
ExtractStridedMetadataOpAdaptor extractAdaptor(
|
||||
operands, attributes, *properties.as<EmptyProperties *>(), regions);
|
||||
ExtractStridedMetadataOpAdaptor extractAdaptor(operands, attributes, regions);
|
||||
auto sourceType = extractAdaptor.getSource().getType().dyn_cast<MemRefType>();
|
||||
if (!sourceType)
|
||||
return failure();
|
||||
|
@ -833,8 +833,7 @@ class ExtractStridedMetadataOpReinterpretCastFolder
|
||||
SmallVector<Type> inferredReturnTypes;
|
||||
if (failed(extractStridedMetadataOp.inferReturnTypes(
|
||||
rewriter.getContext(), loc, {reinterpretCastOp.getSource()},
|
||||
/*attributes=*/{}, /*properties=*/nullptr, /*regions=*/{},
|
||||
inferredReturnTypes)))
|
||||
/*attributes=*/{}, /*regions=*/{}, inferredReturnTypes)))
|
||||
return rewriter.notifyMatchFailure(
|
||||
reinterpretCastOp, "reinterpret_cast source's type is incompatible");
|
||||
|
||||
|
@ -1779,7 +1779,7 @@ bool mlir::scf::insideMutuallyExclusiveBranches(Operation *a, Operation *b) {
|
||||
LogicalResult
|
||||
IfOp::inferReturnTypes(MLIRContext *ctx, std::optional<Location> loc,
|
||||
ValueRange operands, DictionaryAttr attrs,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (regions.empty())
|
||||
return failure();
|
||||
@ -1872,8 +1872,7 @@ void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,
|
||||
MLIRContext *ctx = builder.getContext();
|
||||
auto attrDict = DictionaryAttr::get(ctx, result.attributes);
|
||||
if (succeeded(inferReturnTypes(ctx, std::nullopt, result.operands, attrDict,
|
||||
/*properties=*/nullptr, result.regions,
|
||||
inferredReturnTypes))) {
|
||||
result.regions, inferredReturnTypes))) {
|
||||
result.addTypes(inferredReturnTypes);
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ void AssumingOp::build(
|
||||
|
||||
LogicalResult mlir::shape::AddOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<SizeType>() ||
|
||||
operands[1].getType().isa<SizeType>())
|
||||
@ -911,7 +911,7 @@ void ConstShapeOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
|
||||
|
||||
LogicalResult mlir::shape::ConstShapeOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
Builder b(context);
|
||||
auto shape = attributes.getAs<DenseIntElementsAttr>("shape");
|
||||
@ -1092,7 +1092,7 @@ OpFoldResult DimOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::DimOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
DimOpAdaptor dimOp(operands);
|
||||
inferredReturnTypes.assign({dimOp.getIndex().getType()});
|
||||
@ -1140,7 +1140,7 @@ OpFoldResult DivOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::DivOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<SizeType>() ||
|
||||
operands[1].getType().isa<SizeType>())
|
||||
@ -1361,7 +1361,7 @@ void GetExtentOp::build(OpBuilder &builder, OperationState &result, Value shape,
|
||||
|
||||
LogicalResult mlir::shape::GetExtentOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
inferredReturnTypes.assign({IndexType::get(context)});
|
||||
return success();
|
||||
@ -1399,7 +1399,7 @@ OpFoldResult IsBroadcastableOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::MeetOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands.empty())
|
||||
return failure();
|
||||
@ -1535,7 +1535,7 @@ void shape::RankOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
|
||||
|
||||
LogicalResult mlir::shape::RankOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<ShapeType>())
|
||||
inferredReturnTypes.assign({SizeType::get(context)});
|
||||
@ -1571,7 +1571,7 @@ OpFoldResult NumElementsOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::NumElementsOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<ShapeType>())
|
||||
inferredReturnTypes.assign({SizeType::get(context)});
|
||||
@ -1603,7 +1603,7 @@ OpFoldResult MaxOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::MaxOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType() == operands[1].getType())
|
||||
inferredReturnTypes.assign({operands[0].getType()});
|
||||
@ -1635,7 +1635,7 @@ OpFoldResult MinOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::MinOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType() == operands[1].getType())
|
||||
inferredReturnTypes.assign({operands[0].getType()});
|
||||
@ -1672,7 +1672,7 @@ OpFoldResult MulOp::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult mlir::shape::MulOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<SizeType>() ||
|
||||
operands[1].getType().isa<SizeType>())
|
||||
@ -1759,7 +1759,7 @@ void ShapeOfOp::getCanonicalizationPatterns(RewritePatternSet &patterns,
|
||||
|
||||
LogicalResult mlir::shape::ShapeOfOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType().isa<ValueShapeType>())
|
||||
inferredReturnTypes.assign({ShapeType::get(context)});
|
||||
|
@ -364,8 +364,7 @@ static LogicalResult resolveBroadcastShape(const ValueShapeRange &operands,
|
||||
|
||||
LogicalResult tosa::ArgMaxOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
IntegerAttr axis = attributes.get("axis").cast<IntegerAttr>();
|
||||
@ -390,8 +389,7 @@ LogicalResult tosa::ArgMaxOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::RFFT2dOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
|
||||
@ -417,8 +415,7 @@ LogicalResult tosa::RFFT2dOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::FFT2dOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
inferredReturnShapes.push_back(ShapedTypeComponents(operands.getShape(0)));
|
||||
inferredReturnShapes.push_back(ShapedTypeComponents(operands.getShape(1)));
|
||||
@ -427,8 +424,7 @@ LogicalResult tosa::FFT2dOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::ConcatOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
// Infer all dimension sizes by reducing based on inputs.
|
||||
int32_t axis =
|
||||
@ -488,8 +484,7 @@ LogicalResult tosa::ConcatOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::EqualOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outShape;
|
||||
if (resolveBroadcastShape(operands, outShape).failed()) {
|
||||
@ -510,8 +505,7 @@ bool tosa::EqualOp::isCompatibleReturnTypes(TypeRange l, TypeRange r) {
|
||||
|
||||
LogicalResult tosa::FullyConnectedOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
ShapeAdaptor weightShape = operands.getShape(1);
|
||||
@ -542,8 +536,7 @@ LogicalResult FullyConnectedOp::verify() { return verifyConvOp(*this); }
|
||||
|
||||
LogicalResult tosa::MatMulOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor lhsShape = operands.getShape(0);
|
||||
ShapeAdaptor rhsShape = operands.getShape(1);
|
||||
@ -569,8 +562,7 @@ LogicalResult tosa::MatMulOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::PadOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
ShapeAdaptor paddingShape = operands.getShape(1);
|
||||
@ -632,8 +624,7 @@ static SmallVector<int64_t> convertToMlirShape(ArrayRef<int64_t> shape) {
|
||||
|
||||
LogicalResult tosa::SliceOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
inferredReturnShapes.push_back(ShapedTypeComponents(
|
||||
convertToMlirShape(SliceOpAdaptor(operands, attributes).getSize())));
|
||||
@ -642,8 +633,7 @@ LogicalResult tosa::SliceOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::TableOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
|
||||
@ -659,8 +649,7 @@ LogicalResult tosa::TableOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::TileOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
TileOpAdaptor adaptor(operands, attributes);
|
||||
ArrayRef<int64_t> multiples = adaptor.getMultiples();
|
||||
@ -693,8 +682,7 @@ bool tosa::ReshapeOp::isCompatibleReturnTypes(TypeRange l, TypeRange r) {
|
||||
|
||||
LogicalResult tosa::ReshapeOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ReshapeOpAdaptor adaptor(operands, attributes);
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
@ -763,8 +751,7 @@ LogicalResult tosa::TransposeOp::getConstantPerms(SmallVector<int64_t> &perms) {
|
||||
|
||||
LogicalResult tosa::TransposeOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ShapeAdaptor inputShape = operands.getShape(0);
|
||||
ShapeAdaptor permsShape = operands.getShape(1);
|
||||
@ -831,8 +818,7 @@ LogicalResult tosa::TransposeOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::GatherOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outputShape;
|
||||
outputShape.resize(3, ShapedType::kDynamic);
|
||||
@ -857,8 +843,7 @@ LogicalResult tosa::GatherOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
ResizeOpAdaptor adaptor(operands, attributes);
|
||||
llvm::SmallVector<int64_t, 4> outputShape;
|
||||
@ -898,8 +883,7 @@ LogicalResult tosa::ResizeOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult tosa::ScatterOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outputShape;
|
||||
outputShape.resize(3, ShapedType::kDynamic);
|
||||
@ -958,7 +942,7 @@ static LogicalResult ReduceInferReturnTypes(
|
||||
LogicalResult OP::inferReturnTypeComponents( \
|
||||
MLIRContext *context, ::std::optional<Location> location, \
|
||||
ValueShapeRange operands, DictionaryAttr attributes, \
|
||||
OpaqueProperties properties, RegionRange regions, \
|
||||
RegionRange regions, \
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
|
||||
Type inputType = \
|
||||
operands.getType()[0].cast<TensorType>().getElementType(); \
|
||||
@ -994,7 +978,7 @@ static LogicalResult NAryInferReturnTypes(
|
||||
LogicalResult OP::inferReturnTypeComponents( \
|
||||
MLIRContext *context, ::std::optional<Location> location, \
|
||||
ValueShapeRange operands, DictionaryAttr attributes, \
|
||||
OpaqueProperties properties, RegionRange regions, \
|
||||
RegionRange regions, \
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) { \
|
||||
return NAryInferReturnTypes(operands, inferredReturnShapes); \
|
||||
}
|
||||
@ -1078,8 +1062,7 @@ static LogicalResult poolingInferReturnTypes(
|
||||
|
||||
LogicalResult Conv2DOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
|
||||
Conv2DOp::Adaptor adaptor(operands.getValues(), attributes);
|
||||
@ -1142,8 +1125,7 @@ LogicalResult Conv2DOp::verify() { return verifyConvOp(*this); }
|
||||
|
||||
LogicalResult Conv3DOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outputShape(5, ShapedType::kDynamic);
|
||||
Conv3DOp::Adaptor adaptor(operands.getValues(), attributes);
|
||||
@ -1216,24 +1198,21 @@ LogicalResult Conv3DOp::verify() { return verifyConvOp(*this); }
|
||||
|
||||
LogicalResult AvgPool2dOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
return poolingInferReturnTypes(operands, attributes, inferredReturnShapes);
|
||||
}
|
||||
|
||||
LogicalResult MaxPool2dOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
return poolingInferReturnTypes(operands, attributes, inferredReturnShapes);
|
||||
}
|
||||
|
||||
LogicalResult DepthwiseConv2DOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<int64_t> outputShape(4, ShapedType::kDynamic);
|
||||
DepthwiseConv2DOp::Adaptor adaptor(operands.getValues(), attributes);
|
||||
@ -1309,8 +1288,7 @@ LogicalResult DepthwiseConv2DOp::verify() { return verifyConvOp(*this); }
|
||||
|
||||
LogicalResult TransposeConv2DOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
TransposeConv2DOp::Adaptor adaptor(operands.getValues(), attributes);
|
||||
// outputShape is mutable.
|
||||
@ -1375,8 +1353,7 @@ LogicalResult TransposeConv2DOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult IfOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<tosa::YieldOp> yieldOps;
|
||||
for (Region *region : regions) {
|
||||
@ -1420,8 +1397,7 @@ LogicalResult IfOp::inferReturnTypeComponents(
|
||||
|
||||
LogicalResult WhileOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, ::std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
llvm::SmallVector<tosa::YieldOp> yieldOps;
|
||||
for (auto &block : *regions[1])
|
||||
|
@ -39,7 +39,6 @@ TosaOp createOpAndInfer(PatternRewriter &rewriter, Location loc, Type resultTy,
|
||||
if (shapeInterface
|
||||
.inferReturnTypeComponents(op.getContext(), op.getLoc(),
|
||||
op->getOperands(), op->getAttrDictionary(),
|
||||
op->getPropertiesStorage(),
|
||||
op->getRegions(), returnedShapes)
|
||||
.failed())
|
||||
return op;
|
||||
|
@ -218,9 +218,9 @@ void propagateShapesInRegion(Region ®ion) {
|
||||
|
||||
ValueShapeRange range(op.getOperands(), operandShape);
|
||||
if (shapeInterface
|
||||
.inferReturnTypeComponents(
|
||||
op.getContext(), op.getLoc(), range, op.getAttrDictionary(),
|
||||
op.getPropertiesStorage(), op.getRegions(), returnedShapes)
|
||||
.inferReturnTypeComponents(op.getContext(), op.getLoc(), range,
|
||||
op.getAttrDictionary(),
|
||||
op.getRegions(), returnedShapes)
|
||||
.succeeded()) {
|
||||
for (auto it : llvm::zip(op.getResults(), returnedShapes)) {
|
||||
Value result = std::get<0>(it);
|
||||
|
@ -1152,7 +1152,7 @@ void vector::ExtractOp::build(OpBuilder &builder, OperationState &result,
|
||||
LogicalResult
|
||||
ExtractOp::inferReturnTypes(MLIRContext *, std::optional<Location>,
|
||||
ValueRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange,
|
||||
RegionRange,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
ExtractOp::Adaptor op(operands, attributes);
|
||||
auto vectorType = op.getVector().getType().cast<VectorType>();
|
||||
@ -2084,7 +2084,7 @@ LogicalResult ShuffleOp::verify() {
|
||||
LogicalResult
|
||||
ShuffleOp::inferReturnTypes(MLIRContext *, std::optional<Location>,
|
||||
ValueRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange,
|
||||
RegionRange,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
ShuffleOp::Adaptor op(operands, attributes);
|
||||
auto v1Type = op.getV1().getType().cast<VectorType>();
|
||||
|
@ -2575,6 +2575,7 @@ void AsmPrinter::Impl::printOptionalAttrDict(ArrayRef<NamedAttribute> attrs,
|
||||
if (!filteredAttrs.empty())
|
||||
printFilteredAttributesFn(filteredAttrs);
|
||||
}
|
||||
|
||||
void AsmPrinter::Impl::printNamedAttribute(NamedAttribute attr) {
|
||||
// Print the name without quotes if possible.
|
||||
::printKeywordOrString(attr.getName().strref(), os);
|
||||
@ -3354,10 +3355,6 @@ void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {
|
||||
os << ']';
|
||||
}
|
||||
|
||||
// Print the properties.
|
||||
if (Attribute prop = op->getPropertiesAsAttribute())
|
||||
os << " <" << prop << '>';
|
||||
|
||||
// Print regions.
|
||||
if (op->getNumRegions() != 0) {
|
||||
os << " (";
|
||||
@ -3368,7 +3365,7 @@ void OperationPrinter::printGenericOp(Operation *op, bool printOpName) {
|
||||
os << ')';
|
||||
}
|
||||
|
||||
auto attrs = op->getDiscardableAttrs();
|
||||
auto attrs = op->getAttrs();
|
||||
printOptionalAttrDict(attrs);
|
||||
|
||||
// Print the type signature of the operation.
|
||||
@ -3512,10 +3509,6 @@ void OperationPrinter::printRegion(Region ®ion, bool printEntryBlockArgs,
|
||||
|
||||
void OperationPrinter::printAffineMapOfSSAIds(AffineMapAttr mapAttr,
|
||||
ValueRange operands) {
|
||||
if (!mapAttr) {
|
||||
os << "<<NULL AFFINE MAP>>";
|
||||
return;
|
||||
}
|
||||
AffineMap map = mapAttr.getValue();
|
||||
unsigned numDims = map.getNumDims();
|
||||
auto printValueName = [&](unsigned pos, bool isSymbol) {
|
||||
|
@ -22,7 +22,6 @@ add_mlir_library(MLIRIR
|
||||
IntegerSet.cpp
|
||||
Location.cpp
|
||||
MLIRContext.cpp
|
||||
ODSSupport.cpp
|
||||
Operation.cpp
|
||||
OperationSupport.cpp
|
||||
PatternMatch.cpp
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "mlir/IR/AffineExpr.h"
|
||||
#include "mlir/IR/AffineMap.h"
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/BuiltinDialect.h"
|
||||
#include "mlir/IR/Diagnostics.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
@ -802,64 +801,6 @@ OperationName::UnregisteredOpModel::verifyRegionInvariants(Operation *) {
|
||||
return success();
|
||||
}
|
||||
|
||||
Optional<Attribute>
|
||||
OperationName::UnregisteredOpModel::getInherentAttr(Operation *op,
|
||||
StringRef name) {
|
||||
auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
|
||||
if (!dict)
|
||||
return std::nullopt;
|
||||
if (Attribute attr = dict.get(name))
|
||||
return attr;
|
||||
return std::nullopt;
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::setInherentAttr(Operation *op,
|
||||
StringAttr name,
|
||||
Attribute value) {
|
||||
auto dict = dyn_cast_or_null<DictionaryAttr>(getPropertiesAsAttr(op));
|
||||
assert(dict);
|
||||
NamedAttrList attrs(dict);
|
||||
attrs.set(name, value);
|
||||
*op->getPropertiesStorage().as<Attribute *>() =
|
||||
attrs.getDictionary(op->getContext());
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::populateInherentAttrs(
|
||||
Operation *op, NamedAttrList &attrs) {}
|
||||
LogicalResult OperationName::UnregisteredOpModel::verifyInherentAttrs(
|
||||
OperationName opName, NamedAttrList &attributes,
|
||||
function_ref<InFlightDiagnostic()> getDiag) {
|
||||
return success();
|
||||
}
|
||||
int OperationName::UnregisteredOpModel::getOpPropertyByteSize() {
|
||||
return sizeof(Attribute);
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::initProperties(
|
||||
OperationName opName, OpaqueProperties storage, OpaqueProperties init) {
|
||||
new (storage.as<Attribute *>()) Attribute();
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::deleteProperties(
|
||||
OpaqueProperties prop) {
|
||||
prop.as<Attribute *>()->~Attribute();
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::populateDefaultProperties(
|
||||
OperationName opName, OpaqueProperties properties) {}
|
||||
LogicalResult OperationName::UnregisteredOpModel::setPropertiesFromAttr(
|
||||
Operation *op, Attribute attr, InFlightDiagnostic *diag) {
|
||||
*op->getPropertiesStorage().as<Attribute *>() = attr;
|
||||
return success();
|
||||
}
|
||||
Attribute
|
||||
OperationName::UnregisteredOpModel::getPropertiesAsAttr(Operation *op) {
|
||||
return *op->getPropertiesStorage().as<Attribute *>();
|
||||
}
|
||||
void OperationName::UnregisteredOpModel::copyProperties(OpaqueProperties lhs,
|
||||
OpaqueProperties rhs) {
|
||||
*lhs.as<Attribute *>() = *rhs.as<Attribute *>();
|
||||
}
|
||||
llvm::hash_code
|
||||
OperationName::UnregisteredOpModel::hashProperties(OpaqueProperties prop) {
|
||||
return llvm::hash_combine(*prop.as<Attribute *>());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// RegisteredOperationName
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -1,57 +0,0 @@
|
||||
//===- ODSSupport.cpp -----------------------------------------------------===//
|
||||
//
|
||||
// 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 out-of-line implementations of the support types that
|
||||
// Operation and related classes build on top of.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/ODSSupport.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Diagnostics.h"
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
LogicalResult mlir::convertFromAttribute(int64_t &storage,
|
||||
::mlir::Attribute attr,
|
||||
::mlir::InFlightDiagnostic *diag) {
|
||||
auto valueAttr = dyn_cast<IntegerAttr>(attr);
|
||||
if (!valueAttr) {
|
||||
if (diag)
|
||||
*diag << "expected IntegerAttr for key `value`";
|
||||
return failure();
|
||||
}
|
||||
storage = valueAttr.getValue().getSExtValue();
|
||||
return success();
|
||||
}
|
||||
Attribute mlir::convertToAttribute(MLIRContext *ctx, int64_t storage) {
|
||||
return IntegerAttr::get(IntegerType::get(ctx, 64), storage);
|
||||
}
|
||||
LogicalResult mlir::convertFromAttribute(MutableArrayRef<int64_t> storage,
|
||||
::mlir::Attribute attr,
|
||||
::mlir::InFlightDiagnostic *diag) {
|
||||
auto valueAttr = dyn_cast<DenseI64ArrayAttr>(attr);
|
||||
if (!valueAttr) {
|
||||
if (diag)
|
||||
*diag << "expected DenseI64ArrayAttr for key `value`";
|
||||
return failure();
|
||||
}
|
||||
if (valueAttr.size() != static_cast<int64_t>(storage.size())) {
|
||||
if (diag)
|
||||
*diag << "Size mismatch in attribute conversion: " << valueAttr.size()
|
||||
<< " vs " << storage.size();
|
||||
return failure();
|
||||
}
|
||||
llvm::copy(valueAttr.asArrayRef(), storage.begin());
|
||||
return success();
|
||||
}
|
||||
Attribute mlir::convertToAttribute(MLIRContext *ctx,
|
||||
ArrayRef<int64_t> storage) {
|
||||
return DenseI64ArrayAttr::get(ctx, storage);
|
||||
}
|
@ -7,17 +7,13 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/IR/Operation.h"
|
||||
#include "mlir/IR/Attributes.h"
|
||||
#include "mlir/IR/BuiltinAttributes.h"
|
||||
#include "mlir/IR/BuiltinTypes.h"
|
||||
#include "mlir/IR/Dialect.h"
|
||||
#include "mlir/IR/IRMapping.h"
|
||||
#include "mlir/IR/OpImplementation.h"
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "mlir/IR/TypeUtilities.h"
|
||||
#include "mlir/Interfaces/FoldInterfaces.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <numeric>
|
||||
|
||||
@ -29,31 +25,19 @@ using namespace mlir;
|
||||
|
||||
/// Create a new Operation from operation state.
|
||||
Operation *Operation::create(const OperationState &state) {
|
||||
Operation *op =
|
||||
create(state.location, state.name, state.types, state.operands,
|
||||
state.attributes.getDictionary(state.getContext()),
|
||||
state.properties, state.successors, state.regions);
|
||||
if (LLVM_UNLIKELY(state.propertiesAttr)) {
|
||||
assert(!state.properties);
|
||||
LogicalResult result =
|
||||
op->setPropertiesFromAttribute(state.propertiesAttr,
|
||||
/*diagnostic=*/nullptr);
|
||||
assert(result.succeeded() && "invalid properties in op creation");
|
||||
(void)result;
|
||||
}
|
||||
return op;
|
||||
return create(state.location, state.name, state.types, state.operands,
|
||||
state.attributes.getDictionary(state.getContext()),
|
||||
state.successors, state.regions);
|
||||
}
|
||||
|
||||
/// Create a new Operation with the specific fields.
|
||||
Operation *Operation::create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
NamedAttrList &&attributes,
|
||||
OpaqueProperties properties, BlockRange successors,
|
||||
NamedAttrList &&attributes, BlockRange successors,
|
||||
RegionRange regions) {
|
||||
unsigned numRegions = regions.size();
|
||||
Operation *op =
|
||||
create(location, name, resultTypes, operands, std::move(attributes),
|
||||
properties, successors, numRegions);
|
||||
Operation *op = create(location, name, resultTypes, operands,
|
||||
std::move(attributes), successors, numRegions);
|
||||
for (unsigned i = 0; i < numRegions; ++i)
|
||||
if (regions[i])
|
||||
op->getRegion(i).takeBody(*regions[i]);
|
||||
@ -63,23 +47,21 @@ Operation *Operation::create(Location location, OperationName name,
|
||||
/// Create a new Operation with the specific fields.
|
||||
Operation *Operation::create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
NamedAttrList &&attributes,
|
||||
OpaqueProperties properties, BlockRange successors,
|
||||
NamedAttrList &&attributes, BlockRange successors,
|
||||
unsigned numRegions) {
|
||||
// Populate default attributes.
|
||||
name.populateDefaultAttrs(attributes);
|
||||
|
||||
return create(location, name, resultTypes, operands,
|
||||
attributes.getDictionary(location.getContext()), properties,
|
||||
successors, numRegions);
|
||||
attributes.getDictionary(location.getContext()), successors,
|
||||
numRegions);
|
||||
}
|
||||
|
||||
/// Overload of create that takes an existing DictionaryAttr to avoid
|
||||
/// unnecessarily uniquing a list of attributes.
|
||||
Operation *Operation::create(Location location, OperationName name,
|
||||
TypeRange resultTypes, ValueRange operands,
|
||||
DictionaryAttr attributes,
|
||||
OpaqueProperties properties, BlockRange successors,
|
||||
DictionaryAttr attributes, BlockRange successors,
|
||||
unsigned numRegions) {
|
||||
assert(llvm::all_of(resultTypes, [](Type t) { return t; }) &&
|
||||
"unexpected null result type");
|
||||
@ -90,7 +72,6 @@ Operation *Operation::create(Location location, OperationName name,
|
||||
unsigned numSuccessors = successors.size();
|
||||
unsigned numOperands = operands.size();
|
||||
unsigned numResults = resultTypes.size();
|
||||
int opPropertiesAllocSize = name.getOpPropertyByteSize();
|
||||
|
||||
// If the operation is known to have no operands, don't allocate an operand
|
||||
// storage.
|
||||
@ -101,10 +82,8 @@ Operation *Operation::create(Location location, OperationName name,
|
||||
// into account the size of the operation, its trailing objects, and its
|
||||
// prefixed objects.
|
||||
size_t byteSize =
|
||||
totalSizeToAlloc<detail::OperandStorage, detail::OpProperties,
|
||||
BlockOperand, Region, OpOperand>(
|
||||
needsOperandStorage ? 1 : 0, opPropertiesAllocSize, numSuccessors,
|
||||
numRegions, numOperands);
|
||||
totalSizeToAlloc<detail::OperandStorage, BlockOperand, Region, OpOperand>(
|
||||
needsOperandStorage ? 1 : 0, numSuccessors, numRegions, numOperands);
|
||||
size_t prefixByteSize = llvm::alignTo(
|
||||
Operation::prefixAllocSize(numTrailingResults, numInlineResults),
|
||||
alignof(Operation));
|
||||
@ -112,9 +91,9 @@ Operation *Operation::create(Location location, OperationName name,
|
||||
void *rawMem = mallocMem + prefixByteSize;
|
||||
|
||||
// Create the new Operation.
|
||||
Operation *op = ::new (rawMem) Operation(
|
||||
location, name, numResults, numSuccessors, numRegions,
|
||||
opPropertiesAllocSize, attributes, properties, needsOperandStorage);
|
||||
Operation *op =
|
||||
::new (rawMem) Operation(location, name, numResults, numSuccessors,
|
||||
numRegions, attributes, needsOperandStorage);
|
||||
|
||||
assert((numSuccessors == 0 || op->mightHaveTrait<OpTrait::IsTerminator>()) &&
|
||||
"unexpected successors in a non-terminator operation");
|
||||
@ -143,22 +122,16 @@ Operation *Operation::create(Location location, OperationName name,
|
||||
for (unsigned i = 0; i != numSuccessors; ++i)
|
||||
new (&blockOperands[i]) BlockOperand(op, successors[i]);
|
||||
|
||||
// This must be done after properties are initalized.
|
||||
op->setAttrs(attributes);
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
Operation::Operation(Location location, OperationName name, unsigned numResults,
|
||||
unsigned numSuccessors, unsigned numRegions,
|
||||
int fullPropertiesStorageSize, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, bool hasOperandStorage)
|
||||
DictionaryAttr attributes, bool hasOperandStorage)
|
||||
: location(location), numResults(numResults), numSuccs(numSuccessors),
|
||||
numRegions(numRegions), hasOperandStorage(hasOperandStorage),
|
||||
propertiesStorageSize((fullPropertiesStorageSize + 7) / 8), name(name) {
|
||||
numRegions(numRegions), hasOperandStorage(hasOperandStorage), name(name),
|
||||
attrs(attributes) {
|
||||
assert(attributes && "unexpected null attribute dictionary");
|
||||
assert(fullPropertiesStorageSize <= propertiesCapacity &&
|
||||
"Properties size overflow");
|
||||
#ifndef NDEBUG
|
||||
if (!getDialect() && !getContext()->allowsUnregisteredDialects())
|
||||
llvm::report_fatal_error(
|
||||
@ -167,8 +140,6 @@ Operation::Operation(Location location, OperationName name, unsigned numResults,
|
||||
"allowUnregisteredDialects() on the MLIRContext, or use "
|
||||
"-allow-unregistered-dialect with the MLIR tool used.");
|
||||
#endif
|
||||
if (fullPropertiesStorageSize)
|
||||
name.initOpProperties(getPropertiesStorage(), properties);
|
||||
}
|
||||
|
||||
// Operations are deleted through the destroy() member because they are
|
||||
@ -197,8 +168,6 @@ Operation::~Operation() {
|
||||
// Explicitly destroy the regions.
|
||||
for (auto ®ion : getRegions())
|
||||
region.~Region();
|
||||
if (propertiesStorageSize)
|
||||
name.destroyOpProperties(getPropertiesStorage());
|
||||
}
|
||||
|
||||
/// Destroy this operation or one of its subclasses.
|
||||
@ -290,68 +259,6 @@ InFlightDiagnostic Operation::emitRemark(const Twine &message) {
|
||||
return diag;
|
||||
}
|
||||
|
||||
DictionaryAttr Operation::getAttrDictionary() {
|
||||
if (getPropertiesStorageSize()) {
|
||||
NamedAttrList attrsList = attrs;
|
||||
getName().populateInherentAttrs(this, attrsList);
|
||||
return attrsList.getDictionary(getContext());
|
||||
}
|
||||
return attrs;
|
||||
}
|
||||
|
||||
void Operation::setAttrs(DictionaryAttr newAttrs) {
|
||||
assert(newAttrs && "expected valid attribute dictionary");
|
||||
if (getPropertiesStorageSize()) {
|
||||
attrs = DictionaryAttr::get(getContext(), {});
|
||||
for (const NamedAttribute &attr : newAttrs)
|
||||
setAttr(attr.getName(), attr.getValue());
|
||||
return;
|
||||
}
|
||||
attrs = newAttrs;
|
||||
}
|
||||
void Operation::setAttrs(ArrayRef<NamedAttribute> newAttrs) {
|
||||
if (getPropertiesStorageSize()) {
|
||||
setAttrs(DictionaryAttr::get(getContext(), {}));
|
||||
for (const NamedAttribute &attr : newAttrs)
|
||||
setAttr(attr.getName(), attr.getValue());
|
||||
return;
|
||||
}
|
||||
attrs = DictionaryAttr::get(getContext(), newAttrs);
|
||||
}
|
||||
|
||||
std::optional<Attribute> Operation::getInherentAttr(StringRef name) {
|
||||
return getName().getInherentAttr(this, name);
|
||||
}
|
||||
|
||||
void Operation::setInherentAttr(StringAttr name, Attribute value) {
|
||||
getName().setInherentAttr(this, name, value);
|
||||
}
|
||||
|
||||
Attribute Operation::getPropertiesAsAttribute() {
|
||||
Optional<RegisteredOperationName> info = getRegisteredInfo();
|
||||
if (LLVM_UNLIKELY(!info))
|
||||
return *getPropertiesStorage().as<Attribute *>();
|
||||
return info->getOpPropertiesAsAttribute(this);
|
||||
}
|
||||
LogicalResult
|
||||
Operation::setPropertiesFromAttribute(Attribute attr,
|
||||
InFlightDiagnostic *diagnostic) {
|
||||
Optional<RegisteredOperationName> info = getRegisteredInfo();
|
||||
if (LLVM_UNLIKELY(!info)) {
|
||||
*getPropertiesStorage().as<Attribute *>() = attr;
|
||||
return success();
|
||||
}
|
||||
return info->setOpPropertiesFromAttribute(this, attr, diagnostic);
|
||||
}
|
||||
|
||||
void Operation::copyProperties(OpaqueProperties rhs) {
|
||||
name.copyOpProperties(getPropertiesStorage(), rhs);
|
||||
}
|
||||
|
||||
llvm::hash_code Operation::hashProperties() {
|
||||
return name.hashOpProperties(getPropertiesStorage());
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Operation Ordering
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -674,7 +581,7 @@ Operation *Operation::clone(IRMapping &mapper, CloneOptions options) {
|
||||
|
||||
// Create the new operation.
|
||||
auto *newOp = create(getLoc(), getName(), getResultTypes(), operands, attrs,
|
||||
getPropertiesStorage(), successors, getNumRegions());
|
||||
successors, getNumRegions());
|
||||
mapper.map(this, newOp);
|
||||
|
||||
// Clone the regions.
|
||||
@ -729,20 +636,6 @@ void OpState::printOpName(Operation *op, OpAsmPrinter &p,
|
||||
p.getStream() << name;
|
||||
}
|
||||
|
||||
/// Parse properties as a Attribute.
|
||||
ParseResult OpState::genericParseProperties(OpAsmParser &parser,
|
||||
Attribute &result) {
|
||||
if (parser.parseLess() || parser.parseAttribute(result) ||
|
||||
parser.parseGreater())
|
||||
return failure();
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Print the properties as a Attribute.
|
||||
void OpState::genericPrintProperties(OpAsmPrinter &p, Attribute properties) {
|
||||
p << "<" << properties << ">";
|
||||
}
|
||||
|
||||
/// Emit an error about fatal conditions with this operation, reporting up to
|
||||
/// any diagnostic handlers that may be listening.
|
||||
InFlightDiagnostic OpState::emitError(const Twine &message) {
|
||||
|
@ -193,23 +193,6 @@ OperationState::OperationState(Location location, StringRef name,
|
||||
: OperationState(location, OperationName(name, location.getContext()),
|
||||
operands, types, attributes, successors, regions) {}
|
||||
|
||||
OperationState::~OperationState() {
|
||||
if (properties)
|
||||
propertiesDeleter(properties);
|
||||
}
|
||||
|
||||
LogicalResult
|
||||
OperationState::setProperties(Operation *op,
|
||||
InFlightDiagnostic *diagnostic) const {
|
||||
if (LLVM_UNLIKELY(propertiesAttr)) {
|
||||
assert(!properties);
|
||||
return op->setPropertiesFromAttribute(propertiesAttr, diagnostic);
|
||||
}
|
||||
if (properties)
|
||||
propertiesSetter(op->getPropertiesStorage(), properties);
|
||||
return success();
|
||||
}
|
||||
|
||||
void OperationState::addOperands(ValueRange newOperands) {
|
||||
operands.append(newOperands.begin(), newOperands.end());
|
||||
}
|
||||
@ -650,9 +633,8 @@ llvm::hash_code OperationEquivalence::computeHash(
|
||||
// - Operation Name
|
||||
// - Attributes
|
||||
// - Result Types
|
||||
llvm::hash_code hash =
|
||||
llvm::hash_combine(op->getName(), op->getAttrDictionary(),
|
||||
op->getResultTypes(), op->hashProperties());
|
||||
llvm::hash_code hash = llvm::hash_combine(
|
||||
op->getName(), op->getAttrDictionary(), op->getResultTypes());
|
||||
|
||||
// - Operands
|
||||
ValueRange operands = op->getOperands();
|
||||
|
@ -220,15 +220,15 @@ LogicalResult mlir::detail::inferReturnTensorTypes(
|
||||
function_ref<
|
||||
LogicalResult(MLIRContext *, std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &retComponents)>
|
||||
componentTypeFn,
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
SmallVector<ShapedTypeComponents, 2> retComponents;
|
||||
if (failed(componentTypeFn(context, location, operands, attributes,
|
||||
properties, regions, retComponents)))
|
||||
if (failed(componentTypeFn(context, location, operands, attributes, regions,
|
||||
retComponents)))
|
||||
return failure();
|
||||
for (const auto &shapeAndType : retComponents) {
|
||||
Type elementTy = shapeAndType.getElementType();
|
||||
@ -249,12 +249,7 @@ LogicalResult mlir::detail::inferReturnTensorTypes(
|
||||
LogicalResult mlir::detail::verifyInferredResultTypes(Operation *op) {
|
||||
SmallVector<Type, 4> inferredReturnTypes(op->getResultTypes());
|
||||
auto retTypeFn = cast<InferTypeOpInterface>(op);
|
||||
auto result = retTypeFn.refineReturnTypes(
|
||||
op->getContext(), op->getLoc(), op->getOperands(),
|
||||
op->getAttrDictionary(), op->getPropertiesStorage(), op->getRegions(),
|
||||
inferredReturnTypes);
|
||||
if (failed(result))
|
||||
op->emitOpError() << "failed to infer returned types";
|
||||
|
||||
return result;
|
||||
return retTypeFn.refineReturnTypes(op->getContext(), op->getLoc(),
|
||||
op->getOperands(), op->getAttrDictionary(),
|
||||
op->getRegions(), inferredReturnTypes);
|
||||
}
|
||||
|
@ -1613,8 +1613,8 @@ void ByteCodeExecutor::executeCreateOperation(PatternRewriter &rewriter,
|
||||
// TODO: Handle failure.
|
||||
if (failed(inferInterface->inferReturnTypes(
|
||||
state.getContext(), state.location, state.operands,
|
||||
state.attributes.getDictionary(state.getContext()),
|
||||
state.getRawProperties(), state.regions, state.types)))
|
||||
state.attributes.getDictionary(state.getContext()), state.regions,
|
||||
state.types)))
|
||||
return;
|
||||
} else {
|
||||
// Otherwise, this is a fixed number of results.
|
||||
|
@ -24,7 +24,6 @@ llvm_add_library(MLIRTableGen STATIC
|
||||
Pass.cpp
|
||||
Pattern.cpp
|
||||
Predicate.cpp
|
||||
Property.cpp
|
||||
Region.cpp
|
||||
SideEffects.cpp
|
||||
Successor.cpp
|
||||
|
@ -133,18 +133,13 @@ static ::mlir::LogicalResult {0}(
|
||||
/// functions are stripped anyways.
|
||||
static const char *const attrConstraintCode = R"(
|
||||
static ::mlir::LogicalResult {0}(
|
||||
::mlir::Attribute attr, ::llvm::StringRef attrName, llvm::function_ref<::mlir::InFlightDiagnostic()> getDiag) {{
|
||||
if (attr && !({1}))
|
||||
return getDiag() << "attribute '" << attrName
|
||||
::mlir::Operation *op, ::mlir::Attribute attr, ::llvm::StringRef attrName) {
|
||||
if (attr && !({1})) {
|
||||
return op->emitOpError("attribute '") << attrName
|
||||
<< "' failed to satisfy constraint: {2}";
|
||||
}
|
||||
return ::mlir::success();
|
||||
}
|
||||
static ::mlir::LogicalResult {0}(
|
||||
::mlir::Operation *op, ::mlir::Attribute attr, ::llvm::StringRef attrName) {{
|
||||
return {0}(attr, attrName, [op]() {{
|
||||
return op->emitOpError();
|
||||
});
|
||||
}
|
||||
)";
|
||||
|
||||
/// Code for a successor constraint.
|
||||
|
@ -103,10 +103,6 @@ bool Dialect::isExtensible() const {
|
||||
return def->getValueAsBit("isExtensible");
|
||||
}
|
||||
|
||||
bool Dialect::usePropertiesForAttributes() const {
|
||||
return def->getValueAsBit("usePropertiesForAttributes");
|
||||
}
|
||||
|
||||
bool Dialect::operator==(const Dialect &other) const {
|
||||
return def == other.def;
|
||||
}
|
||||
|
@ -11,7 +11,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/TableGen/Operator.h"
|
||||
#include "mlir/TableGen/Argument.h"
|
||||
#include "mlir/TableGen/Predicate.h"
|
||||
#include "mlir/TableGen/Trait.h"
|
||||
#include "mlir/TableGen/Type.h"
|
||||
@ -323,23 +322,14 @@ auto Operator::getTraits() const -> llvm::iterator_range<const_trait_iterator> {
|
||||
return {trait_begin(), trait_end()};
|
||||
}
|
||||
|
||||
auto Operator::attribute_begin() const -> const_attribute_iterator {
|
||||
auto Operator::attribute_begin() const -> attribute_iterator {
|
||||
return attributes.begin();
|
||||
}
|
||||
auto Operator::attribute_end() const -> const_attribute_iterator {
|
||||
auto Operator::attribute_end() const -> attribute_iterator {
|
||||
return attributes.end();
|
||||
}
|
||||
auto Operator::getAttributes() const
|
||||
-> llvm::iterator_range<const_attribute_iterator> {
|
||||
return {attribute_begin(), attribute_end()};
|
||||
}
|
||||
auto Operator::attribute_begin() -> attribute_iterator {
|
||||
return attributes.begin();
|
||||
}
|
||||
auto Operator::attribute_end() -> attribute_iterator {
|
||||
return attributes.end();
|
||||
}
|
||||
auto Operator::getAttributes() -> llvm::iterator_range<attribute_iterator> {
|
||||
-> llvm::iterator_range<attribute_iterator> {
|
||||
return {attribute_begin(), attribute_end()};
|
||||
}
|
||||
|
||||
@ -552,7 +542,6 @@ void Operator::populateOpStructure() {
|
||||
auto &recordKeeper = def.getRecords();
|
||||
auto *typeConstraintClass = recordKeeper.getClass("TypeConstraint");
|
||||
auto *attrClass = recordKeeper.getClass("Attr");
|
||||
auto *propertyClass = recordKeeper.getClass("Property");
|
||||
auto *derivedAttrClass = recordKeeper.getClass("DerivedAttr");
|
||||
auto *opVarClass = recordKeeper.getClass("OpVariable");
|
||||
numNativeAttributes = 0;
|
||||
@ -587,14 +576,9 @@ void Operator::populateOpStructure() {
|
||||
"derived attributes not allowed in argument list");
|
||||
attributes.push_back({givenName, Attribute(argDef)});
|
||||
++numNativeAttributes;
|
||||
} else if (argDef->isSubClassOf(propertyClass)) {
|
||||
if (givenName.empty())
|
||||
PrintFatalError(argDef->getLoc(), "properties must be named");
|
||||
properties.push_back({givenName, Property(argDef)});
|
||||
} else {
|
||||
PrintFatalError(def.getLoc(),
|
||||
"unexpected def type; only defs deriving "
|
||||
"from TypeConstraint or Attr or Property are allowed");
|
||||
PrintFatalError(def.getLoc(), "unexpected def type; only defs deriving "
|
||||
"from TypeConstraint or Attr are allowed");
|
||||
}
|
||||
if (!givenName.empty())
|
||||
argumentsAndResultsIndex[givenName] = i;
|
||||
@ -624,7 +608,7 @@ void Operator::populateOpStructure() {
|
||||
// `attributes` because we will put their elements' pointers in `arguments`.
|
||||
// SmallVector may perform re-allocation under the hood when adding new
|
||||
// elements.
|
||||
int operandIndex = 0, attrIndex = 0, propIndex = 0;
|
||||
int operandIndex = 0, attrIndex = 0;
|
||||
for (unsigned i = 0; i != numArgs; ++i) {
|
||||
Record *argDef = dyn_cast<DefInit>(argumentValues->getArg(i))->getDef();
|
||||
if (argDef->isSubClassOf(opVarClass))
|
||||
@ -634,13 +618,11 @@ void Operator::populateOpStructure() {
|
||||
attrOrOperandMapping.push_back(
|
||||
{OperandOrAttribute::Kind::Operand, operandIndex});
|
||||
arguments.emplace_back(&operands[operandIndex++]);
|
||||
} else if (argDef->isSubClassOf(attrClass)) {
|
||||
} else {
|
||||
assert(argDef->isSubClassOf(attrClass));
|
||||
attrOrOperandMapping.push_back(
|
||||
{OperandOrAttribute::Kind::Attribute, attrIndex});
|
||||
arguments.emplace_back(&attributes[attrIndex++]);
|
||||
} else {
|
||||
assert(argDef->isSubClassOf(propertyClass));
|
||||
arguments.emplace_back(&properties[propIndex++]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,86 +0,0 @@
|
||||
//===- Property.cpp - Property wrapper class ----------------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Property wrapper to simplify using TableGen Record defining a MLIR
|
||||
// Property.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "mlir/TableGen/Property.h"
|
||||
#include "mlir/TableGen/Format.h"
|
||||
#include "mlir/TableGen/Operator.h"
|
||||
#include "llvm/TableGen/Record.h"
|
||||
|
||||
using namespace mlir;
|
||||
using namespace mlir::tblgen;
|
||||
|
||||
using llvm::DefInit;
|
||||
using llvm::Init;
|
||||
using llvm::Record;
|
||||
using llvm::StringInit;
|
||||
|
||||
// Returns the initializer's value as string if the given TableGen initializer
|
||||
// is a code or string initializer. Returns the empty StringRef otherwise.
|
||||
static StringRef getValueAsString(const Init *init) {
|
||||
if (const auto *str = dyn_cast<StringInit>(init))
|
||||
return str->getValue().trim();
|
||||
return {};
|
||||
}
|
||||
|
||||
Property::Property(const Record *record) : def(record) {
|
||||
assert((record->isSubClassOf("Property") || record->isSubClassOf("Attr")) &&
|
||||
"must be subclass of TableGen 'Property' class");
|
||||
}
|
||||
|
||||
Property::Property(const DefInit *init) : Property(init->getDef()) {}
|
||||
|
||||
StringRef Property::getStorageType() const {
|
||||
const auto *init = def->getValueInit("storageType");
|
||||
auto type = getValueAsString(init);
|
||||
if (type.empty())
|
||||
return "Property";
|
||||
return type;
|
||||
}
|
||||
|
||||
StringRef Property::getInterfaceType() const {
|
||||
const auto *init = def->getValueInit("interfaceType");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
StringRef Property::getConvertFromStorageCall() const {
|
||||
const auto *init = def->getValueInit("convertFromStorage");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
StringRef Property::getAssignToStorageCall() const {
|
||||
const auto *init = def->getValueInit("assignToStorage");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
StringRef Property::getConvertToAttributeCall() const {
|
||||
const auto *init = def->getValueInit("convertToAttribute");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
StringRef Property::getConvertFromAttributeCall() const {
|
||||
const auto *init = def->getValueInit("convertFromAttribute");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
StringRef Property::getHashPropertyCall() const {
|
||||
return getValueAsString(def->getValueInit("hashProperty"));
|
||||
}
|
||||
|
||||
bool Property::hasDefaultValue() const { return !getDefaultValue().empty(); }
|
||||
|
||||
StringRef Property::getDefaultValue() const {
|
||||
const auto *init = def->getValueInit("defaultValue");
|
||||
return getValueAsString(init);
|
||||
}
|
||||
|
||||
const llvm::Record &Property::getDef() const { return *def; }
|
@ -11,10 +11,10 @@
|
||||
// COM: bytecode contains
|
||||
// COM: module {
|
||||
// COM: version: 1.12
|
||||
// COM: "test.versionedB"() <{attribute = #test.attr_params<24, 42>}> : () -> ()
|
||||
// COM: "test.versionedB"() {attribute = #test.attr_params<24, 42>} : () -> ()
|
||||
// COM: }
|
||||
// RUN: mlir-opt %S/versioned-attr-1.12.mlirbc 2>&1 | FileCheck %s --check-prefix=CHECK1
|
||||
// CHECK1: "test.versionedB"() <{attribute = #test.attr_params<42, 24>}> : () -> ()
|
||||
// CHECK1: "test.versionedB"() {attribute = #test.attr_params<42, 24>} : () -> ()
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Test attribute upgrade
|
||||
@ -23,7 +23,7 @@
|
||||
// COM: bytecode contains
|
||||
// COM: module {
|
||||
// COM: version: 2.0
|
||||
// COM: "test.versionedB"() <{attribute = #test.attr_params<42, 24>}> : () -> ()
|
||||
// COM: "test.versionedB"() {attribute = #test.attr_params<42, 24>} : () -> ()
|
||||
// COM: }
|
||||
// RUN: mlir-opt %S/versioned-attr-2.0.mlirbc 2>&1 | FileCheck %s --check-prefix=CHECK2
|
||||
// CHECK2: "test.versionedB"() <{attribute = #test.attr_params<42, 24>}> : () -> ()
|
||||
// CHECK2: "test.versionedB"() {attribute = #test.attr_params<42, 24>} : () -> ()
|
||||
|
@ -11,10 +11,10 @@
|
||||
// COM: bytecode contains
|
||||
// COM: module {
|
||||
// COM: version: 2.0
|
||||
// COM: "test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
|
||||
// COM: "test.versionedA"() {dims = 123 : i64, modifier = false} : () -> ()
|
||||
// COM: }
|
||||
// RUN: mlir-opt %S/versioned-op-2.0.mlirbc 2>&1 | FileCheck %s --check-prefix=CHECK1
|
||||
// CHECK1: "test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
|
||||
// CHECK1: "test.versionedA"() {dims = 123 : i64, modifier = false} : () -> ()
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Test upgrade
|
||||
@ -23,10 +23,10 @@
|
||||
// COM: bytecode contains
|
||||
// COM: module {
|
||||
// COM: version: 1.12
|
||||
// COM: "test.versionedA"() <{dimensions = 123 : i64}> : () -> ()
|
||||
// COM: "test.versionedA"() {dimensions = 123 : i64} : () -> ()
|
||||
// COM: }
|
||||
// RUN: mlir-opt %S/versioned-op-1.12.mlirbc 2>&1 | FileCheck %s --check-prefix=CHECK2
|
||||
// CHECK2: "test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
|
||||
// CHECK2: "test.versionedA"() {dims = 123 : i64, modifier = false} : () -> ()
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Test forbidden downgrade
|
||||
@ -35,7 +35,7 @@
|
||||
// COM: bytecode contains
|
||||
// COM: module {
|
||||
// COM: version: 2.2
|
||||
// COM: "test.versionedA"() <{dims = 123 : i64, modifier = false}> : () -> ()
|
||||
// COM: "test.versionedA"() {dims = 123 : i64, modifier = false} : () -> ()
|
||||
// COM: }
|
||||
// RUN: not mlir-opt %S/versioned-op-2.2.mlirbc 2>&1 | FileCheck %s --check-prefix=ERR_NEW_VERSION
|
||||
// ERR_NEW_VERSION: current test dialect version is 2.0, can't parse version: 2.2
|
||||
|
@ -41,16 +41,16 @@ func.func @pack_unpack(%arg0: i1, %arg1: i2) -> (i1, i2) {
|
||||
//
|
||||
// CHECK-TUP-LABEL: func.func @materializations_tuple_args(
|
||||
// CHECK-TUP-SAME: %[[ARG0:.*]]: tuple<tuple<>, i1, tuple<tuple<i2>>>) -> (i1, i2) {
|
||||
// CHECK-TUP-DAG: %[[V0:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-TUP-DAG: %[[V1:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-TUP-DAG: %[[V2:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-TUP-DAG: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-TUP-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
|
||||
// CHECK-TUP-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-TUP-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-TUP-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[ARG0]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-TUP-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-TUP-DAG: %[[V9:.*]] = "test.get_tuple_element"(%[[V8]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
|
||||
// CHECK-TUP-DAG: %[[V0:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-TUP-DAG: %[[V1:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-TUP-DAG: %[[V2:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-TUP-DAG: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-TUP-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 0 : i32} : (tuple<i2>) -> i2
|
||||
// CHECK-TUP-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-TUP-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-TUP-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[ARG0]]) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-TUP-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-TUP-DAG: %[[V9:.*]] = "test.get_tuple_element"(%[[V8]]) {index = 0 : i32} : (tuple<i2>) -> i2
|
||||
// CHECK-TUP-DAG: return %[[V1]], %[[V9]] : i1, i2
|
||||
|
||||
// If we only convert the func ops, argument materializations are created from
|
||||
@ -64,11 +64,11 @@ func.func @pack_unpack(%arg0: i1, %arg1: i2) -> (i1, i2) {
|
||||
// CHECK-FUNC-DAG: %[[V1:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V2:.*]] = "test.make_tuple"(%[[V1]]) : (tuple<i2>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V3:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]], %[[V2]]) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
|
||||
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
|
||||
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) {index = 0 : i32} : (tuple<i2>) -> i2
|
||||
// CHECK-FUNC-DAG: return %[[V5]], %[[V8]] : i1, i2
|
||||
|
||||
// If we convert both tuple and func ops, basically everything disappears.
|
||||
@ -117,11 +117,11 @@ func.func @materializations_tuple_args(%arg0: tuple<tuple<>, i1, tuple<tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V1:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V2:.*]] = "test.make_tuple"(%[[V1]]) : (tuple<i2>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V3:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]], %[[V2]]) : (tuple<>, i1, tuple<tuple<i2>>) -> tuple<tuple<>, i1, tuple<tuple<i2>>>
|
||||
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 2 : i32}> : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
|
||||
// CHECK-FUNC-DAG: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 0 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK-FUNC-DAG: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 1 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> i1
|
||||
// CHECK-FUNC-DAG: %[[V6:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 2 : i32} : (tuple<tuple<>, i1, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK-FUNC-DAG: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK-FUNC-DAG: %[[V8:.*]] = "test.get_tuple_element"(%[[V7]]) {index = 0 : i32} : (tuple<i2>) -> i2
|
||||
// CHECK-FUNC-DAG: return %[[V5]], %[[V8]] : i1, i2
|
||||
|
||||
// If we convert both tuple and func ops, basically everything disappears.
|
||||
|
@ -36,13 +36,13 @@ func.func @if_result(%arg0: tuple<tuple<>, i1, tuple<i2>>, %arg1: i1) -> tuple<t
|
||||
// CHECK-NEXT: %[[V1:.*]] = "test.make_tuple"(%[[V0]], %[[ARG0]]) : (tuple<>, i1) -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V2:.*]] = scf.if %[[ARG1]] -> (i1) {
|
||||
// CHECK-NEXT: %[[V3:.*]] = "test.op"(%[[V1]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 0 : i32} : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 1 : i32} : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: scf.yield %[[V5]] : i1
|
||||
// CHECK-NEXT: } else {
|
||||
// CHECK-NEXT: %[[V6:.*]] = "test.source"() : () -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 0 : i32} : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 1 : i32} : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: scf.yield %[[V8]] : i1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: return %[[V2]] : i1
|
||||
@ -94,14 +94,14 @@ func.func @while_operands_results(%arg0: tuple<tuple<>, i1, tuple<i2>>, %arg1: i
|
||||
// CHECK-NEXT: %[[V1:.*]] = "test.make_tuple"() : () -> tuple<>
|
||||
// CHECK-NEXT: %[[V2:.*]] = "test.make_tuple"(%[[V1]], %[[ARG2]]) : (tuple<>, i1) -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V3:.*]] = "test.op"(%[[V2]]) : (tuple<tuple<>, i1>) -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: %[[V4:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 0 : i32} : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V5:.*]] = "test.get_tuple_element"(%[[V3]]) {index = 1 : i32} : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: scf.condition(%[[ARG1]]) %[[V5]] : i1
|
||||
// CHECK-NEXT: } do {
|
||||
// CHECK-NEXT: ^bb0(%[[ARG3:.*]]: i1):
|
||||
// CHECK-NEXT: %[[V6:.*]] = "test.source"() : () -> tuple<tuple<>, i1>
|
||||
// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 1 : i32}> : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 0 : i32} : (tuple<tuple<>, i1>) -> tuple<>
|
||||
// CHECK-NEXT: %[[V8:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 1 : i32} : (tuple<tuple<>, i1>) -> i1
|
||||
// CHECK-NEXT: scf.yield %[[V8]] : i1
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: return %[[V0]] : i1
|
||||
|
@ -98,7 +98,6 @@ func.func @shape_of(%value_arg : !shape.value_shape,
|
||||
// -----
|
||||
|
||||
func.func @shape_of_incompatible_return_types(%value_arg : tensor<1x2xindex>) {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'shape.shape_of' op inferred type(s) 'tensor<2xindex>' are incompatible with return type(s) of operation 'tensor<3xindex>'}}
|
||||
%0 = shape.shape_of %value_arg : tensor<1x2xindex> -> tensor<3xindex>
|
||||
return
|
||||
@ -269,7 +268,6 @@ func.func @fn(%arg: !shape.shape) -> !shape.witness {
|
||||
// Test that type inference flags the wrong return type.
|
||||
|
||||
func.func @const_shape() {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tensor<3xindex>' are incompatible with return type(s) of operation 'tensor<2xindex>'}}
|
||||
%0 = shape.const_shape [4, 5, 6] : tensor<2xindex>
|
||||
return
|
||||
@ -278,7 +276,6 @@ func.func @const_shape() {
|
||||
// -----
|
||||
|
||||
func.func @invalid_meet(%arg0 : !shape.shape, %arg1 : index) -> index {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{requires all sizes or shapes}}
|
||||
%result = shape.meet %arg0, %arg1 : !shape.shape, index -> index
|
||||
return %result : index
|
||||
@ -287,7 +284,6 @@ func.func @invalid_meet(%arg0 : !shape.shape, %arg1 : index) -> index {
|
||||
// -----
|
||||
|
||||
func.func @invalid_meet(%arg0 : tensor<2xindex>, %arg1 : tensor<3xindex>) -> tensor<?xindex> {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{unequal shape cardinality}}
|
||||
%result = shape.meet %arg0, %arg1 : tensor<2xindex>, tensor<3xindex> -> tensor<?xindex>
|
||||
return %result : tensor<?xindex>
|
||||
|
@ -39,7 +39,6 @@ func.func @test_conv2d(%arg0: tensor<1x29x29x4xi8>, %arg1: tensor<16x3x3x4xi8>,
|
||||
// -----
|
||||
|
||||
func.func @test_concat(%arg0 : tensor<2x1xf32>, %arg1 : tensor<2x2xf32>) -> tensor<?x?xf32> {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{Cannot concat tensors with different sizes on the non-axis dimension 1}}
|
||||
%0 = "tosa.concat"(%arg0, %arg1) {axis = 0 : i64} : (tensor<2x1xf32>, tensor<2x2xf32>) -> tensor<?x?xf32>
|
||||
return %0 : tensor<?x?xf32>
|
||||
@ -48,7 +47,6 @@ func.func @test_concat(%arg0 : tensor<2x1xf32>, %arg1 : tensor<2x2xf32>) -> tens
|
||||
// -----
|
||||
|
||||
func.func @test_concat_element_type_mismatch(%arg0 : tensor<1x2xf32>, %arg1 : tensor<2x2xf32>) -> tensor<?x?xi8> {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.concat' op inferred type(s) 'tensor<3x2xf32>' are incompatible with return type(s) of operation 'tensor<?x?xi8>}}
|
||||
%0 = "tosa.concat"(%arg0, %arg1) {axis = 0 : i64} : (tensor<1x2xf32>, tensor<2x2xf32>) -> tensor<?x?xi8>
|
||||
return %0 : tensor<?x?xi8>
|
||||
@ -102,7 +100,6 @@ func.func @test_fully_connected_non_const(%arg0: tensor<13x21x3xf32>, %arg1: ten
|
||||
// -----
|
||||
|
||||
func.func @test_reduce_sum_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.reduce_sum' op inferred type(s) 'tensor<1x3x4x5xf32>' are incompatible with return type(s) of operation 'tensor<1x3x4x5xi32>'}}
|
||||
%0 = "tosa.reduce_sum"(%arg0) {axis = 0 : i64} : (tensor<2x3x4x5xf32>) -> tensor<1x3x4x5xi32>
|
||||
return
|
||||
@ -111,7 +108,6 @@ func.func @test_reduce_sum_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// -----
|
||||
|
||||
func.func @test_reduce_max_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.reduce_max' op inferred type(s) 'tensor<2x3x4x1xf32>' are incompatible with return type(s) of operation 'tensor<2x3x4x1xi32>'}}
|
||||
%0 = "tosa.reduce_max"(%arg0) {axis = 3 : i64} : (tensor<2x3x4x5xf32>) -> tensor<2x3x4x1xi32>
|
||||
return
|
||||
@ -120,7 +116,6 @@ func.func @test_reduce_max_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// -----
|
||||
|
||||
func.func @test_reduce_min_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.reduce_min' op inferred type(s) 'tensor<2x1x4x5xf32>' are incompatible with return type(s) of operation 'tensor<2x1x4x5xi32>'}}
|
||||
%0 = "tosa.reduce_min"(%arg0) {axis = 1 : i64} : (tensor<2x3x4x5xf32>) -> tensor<2x1x4x5xi32>
|
||||
return
|
||||
@ -129,7 +124,6 @@ func.func @test_reduce_min_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// -----
|
||||
|
||||
func.func @test_reduce_prod_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.reduce_prod' op inferred type(s) 'tensor<2x1x4x5xf32>' are incompatible with return type(s) of operation 'tensor<2x3x4x5xf32>'}}
|
||||
%0 = "tosa.reduce_prod"(%arg0) {axis = 1 : i64} : (tensor<2x3x4x5xf32>) -> tensor<2x3x4x5xf32>
|
||||
return
|
||||
@ -138,7 +132,6 @@ func.func @test_reduce_prod_type_mismatch(%arg0 : tensor<2x3x4x5xf32>) -> () {
|
||||
// -----
|
||||
|
||||
func.func @test_reshape_type_mismatch(%arg0 : tensor<13x21x3xf32>) -> () {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{'tosa.reshape' op inferred type(s) 'tensor<13x21x3x1xf32>' are incompatible with return type(s) of operation 'tensor<13x21x3x1xi32>'}}
|
||||
%0 = "tosa.reshape"(%arg0) {new_shape = array<i64: 13, 21, 3, 1>} : (tensor<13x21x3xf32>) -> tensor<13x21x3x1xi32>
|
||||
return
|
||||
|
@ -7,7 +7,7 @@ func.func @add_to_worklist_after_inplace_update() {
|
||||
// worklist of the GreedyPatternRewriteDriver (regardless of the value of
|
||||
// config.max_iterations).
|
||||
|
||||
// CHECK: "test.any_attr_of_i32_str"() <{attr = 3 : i32}> : () -> ()
|
||||
// CHECK: "test.any_attr_of_i32_str"() {attr = 3 : i32} : () -> ()
|
||||
"test.any_attr_of_i32_str"() {attr = 0 : i32} : () -> ()
|
||||
return
|
||||
}
|
||||
|
@ -587,6 +587,11 @@ func.func @bad_arrow(%arg : !unreg.ptr<(i32)->)
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error @+1 {{attribute 'attr' occurs more than once in the attribute list}}
|
||||
test.format_symbol_name_attr_op @name { attr = "xx" }
|
||||
|
||||
// -----
|
||||
|
||||
func.func @forward_reference_type_check() -> (i8) {
|
||||
cf.br ^bb2
|
||||
|
||||
|
@ -1437,4 +1437,3 @@ test.dialect_custom_format_fallback custom_format_fallback
|
||||
// Check that an op with an optional result parses f80 as type.
|
||||
// CHECK: test.format_optional_result_d_op : f80
|
||||
test.format_optional_result_d_op : f80
|
||||
|
||||
|
@ -1,20 +0,0 @@
|
||||
// # RUN: mlir-opt %s -split-input-file | mlir-opt |FileCheck %s
|
||||
// # RUN: mlir-opt %s -mlir-print-op-generic -split-input-file | mlir-opt -mlir-print-op-generic | FileCheck %s --check-prefix=GENERIC
|
||||
|
||||
// CHECK: test.with_properties
|
||||
// CHECK-SAME: <{a = 32 : i64, array = array<i64: 1, 2, 3, 4>, b = "foo"}>
|
||||
// GENERIC: "test.with_properties"()
|
||||
// GENERIC-SAME: <{a = 32 : i64, array = array<i64: 1, 2, 3, 4>, b = "foo"}> : () -> ()
|
||||
test.with_properties <{a = 32 : i64, array = array<i64: 1, 2, 3, 4>, b = "foo"}>
|
||||
|
||||
// CHECK: test.with_nice_properties
|
||||
// CHECK-SAME: "foo bar" is -3
|
||||
// GENERIC: "test.with_nice_properties"()
|
||||
// GENERIC-SAME: <{prop = {label = "foo bar", value = -3 : i32}}> : () -> ()
|
||||
test.with_nice_properties "foo bar" is -3
|
||||
|
||||
// CHECK: test.with_wrapped_properties
|
||||
// CHECK-SAME: "content for properties"
|
||||
// GENERIC: "test.with_wrapped_properties"()
|
||||
// GENERIC-SAME: <{prop = "content for properties"}> : () -> ()
|
||||
test.with_wrapped_properties <{prop = "content for properties"}>
|
@ -12,5 +12,5 @@ func.func @test() -> i32 {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func.func @test
|
||||
// CHECK-NEXT: %[[C:.*]] = "test.constant"() <{value = 33 : i32}>
|
||||
// CHECK-NEXT: %[[C:.*]] = "test.constant"() {value = 33 : i32}
|
||||
// CHECK-NEXT: return %[[C]]
|
||||
|
@ -7,5 +7,5 @@ func.func @test() -> i32 {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func.func @test
|
||||
// CHECK-NEXT: %[[C:.*]] = "test.constant"() <{value = 5 : i32}>
|
||||
// CHECK-NEXT: %[[C:.*]] = "test.constant"() {value = 5 : i32}
|
||||
// CHECK-NEXT: return %[[C]]
|
||||
|
@ -345,8 +345,8 @@ func.func @failedSingleBlockImplicitTerminator_missing_terminator() {
|
||||
|
||||
// -----
|
||||
|
||||
// expected-error@+1 {{invalid properties {sym_name = "foo_2", sym_visibility} for op test.symbol: Invalid attribute `sym_visibility` in property conversion: unit}}
|
||||
"test.symbol"() <{sym_name = "foo_2", sym_visibility}> : () -> ()
|
||||
// expected-error@+1 {{op attribute 'sym_visibility' failed to satisfy constraint: string attribute}}
|
||||
"test.symbol"() {sym_name = "foo_2", sym_visibility} : () -> ()
|
||||
|
||||
// -----
|
||||
|
||||
@ -390,14 +390,14 @@ func.func @failedMissingOperandSizeAttr(%arg: i32) {
|
||||
// -----
|
||||
|
||||
func.func @failedOperandSizeAttrWrongType(%arg: i32) {
|
||||
// expected-error @+1 {{attribute 'operand_segment_sizes' failed to satisfy constraint: i32 dense array attribute}}
|
||||
// expected-error @+1 {{requires dense i32 array attribute 'operand_segment_sizes'}}
|
||||
"test.attr_sized_operands"(%arg, %arg, %arg, %arg) {operand_segment_sizes = 10} : (i32, i32, i32, i32) -> ()
|
||||
}
|
||||
|
||||
// -----
|
||||
|
||||
func.func @failedOperandSizeAttrWrongElementType(%arg: i32) {
|
||||
// expected-error @+1 {{attribute 'operand_segment_sizes' failed to satisfy constraint: i32 dense array attribute}}
|
||||
// expected-error @+1 {{requires dense i32 array attribute 'operand_segment_sizes'}}
|
||||
"test.attr_sized_operands"(%arg, %arg, %arg, %arg) {operand_segment_sizes = array<i64: 1, 1, 1, 1>} : (i32, i32, i32, i32) -> ()
|
||||
}
|
||||
|
||||
@ -655,7 +655,7 @@ func.func @failed_type_traits() {
|
||||
|
||||
// Check that we can query traits in attributes
|
||||
func.func @succeeded_attr_traits() {
|
||||
// CHECK: "test.attr_with_trait"() <{attr = #test.attr_with_trait}> : () -> ()
|
||||
// CHECK: "test.attr_with_trait"() {attr = #test.attr_with_trait} : () -> ()
|
||||
"test.attr_with_trait"() {attr = #test.attr_with_trait} : () -> ()
|
||||
return
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
// RUN: mlir-opt -test-int-range-inference %s | FileCheck %s
|
||||
|
||||
// CHECK-LABEL: func @constant
|
||||
// CHECK: %[[cst:.*]] = "test.constant"() <{value = 3 : index}
|
||||
// CHECK: %[[cst:.*]] = "test.constant"() {value = 3 : index}
|
||||
// CHECK: return %[[cst]]
|
||||
func.func @constant() -> index {
|
||||
%0 = test.with_bounds { umin = 3 : index, umax = 3 : index,
|
||||
@ -10,7 +10,7 @@ func.func @constant() -> index {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: func @increment
|
||||
// CHECK: %[[cst:.*]] = "test.constant"() <{value = 4 : index}
|
||||
// CHECK: %[[cst:.*]] = "test.constant"() {value = 4 : index}
|
||||
// CHECK: return %[[cst]]
|
||||
func.func @increment() -> index {
|
||||
%0 = test.with_bounds { umin = 3 : index, umax = 3 : index, smin = 0 : index, smax = 0x7fffffffffffffff : index }
|
||||
@ -103,8 +103,8 @@ func.func @func_args_unbound(%arg0 : index) -> index {
|
||||
|
||||
// CHECK-LABEL: func @propagate_across_while_loop_false()
|
||||
func.func @propagate_across_while_loop_false() -> index {
|
||||
// CHECK-DAG: %[[C0:.*]] = "test.constant"() <{value = 0
|
||||
// CHECK-DAG: %[[C1:.*]] = "test.constant"() <{value = 1
|
||||
// CHECK-DAG: %[[C0:.*]] = "test.constant"() {value = 0
|
||||
// CHECK-DAG: %[[C1:.*]] = "test.constant"() {value = 1
|
||||
%0 = test.with_bounds { umin = 0 : index, umax = 0 : index,
|
||||
smin = 0 : index, smax = 0 : index }
|
||||
%1 = scf.while : () -> index {
|
||||
@ -122,8 +122,8 @@ func.func @propagate_across_while_loop_false() -> index {
|
||||
|
||||
// CHECK-LABEL: func @propagate_across_while_loop
|
||||
func.func @propagate_across_while_loop(%arg0 : i1) -> index {
|
||||
// CHECK-DAG: %[[C0:.*]] = "test.constant"() <{value = 0
|
||||
// CHECK-DAG: %[[C1:.*]] = "test.constant"() <{value = 1
|
||||
// CHECK-DAG: %[[C0:.*]] = "test.constant"() {value = 0
|
||||
// CHECK-DAG: %[[C1:.*]] = "test.constant"() {value = 1
|
||||
%0 = test.with_bounds { umin = 0 : index, umax = 0 : index,
|
||||
smin = 0 : index, smax = 0 : index }
|
||||
%1 = scf.while : () -> index {
|
||||
@ -140,7 +140,7 @@ func.func @propagate_across_while_loop(%arg0 : i1) -> index {
|
||||
|
||||
// CHECK-LABEL: func @dont_propagate_across_infinite_loop()
|
||||
func.func @dont_propagate_across_infinite_loop() -> index {
|
||||
// CHECK: %[[C0:.*]] = "test.constant"() <{value = 0
|
||||
// CHECK: %[[C0:.*]] = "test.constant"() {value = 0
|
||||
%0 = test.with_bounds { umin = 0 : index, umax = 0 : index,
|
||||
smin = 0 : index, smax = 0 : index }
|
||||
// CHECK: %[[loopRes:.*]] = scf.while
|
||||
|
@ -10,8 +10,8 @@
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i1,
|
||||
// CHECK-SAME: %[[ARG1:.*]]: i32) -> (i1, i32) {
|
||||
// CHECK: %[[ARG_MATERIALIZED:.*]] = "test.make_tuple"(%[[ARG0]], %[[ARG1]]) : (i1, i32) -> tuple<i1, i32>
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) <{index = 0 : i32}> : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) <{index = 1 : i32}> : (tuple<i1, i32>) -> i32
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) {index = 0 : i32} : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) {index = 1 : i32} : (tuple<i1, i32>) -> i32
|
||||
// CHECK: return %[[RET0]], %[[RET1]] : i1, i32
|
||||
// CHECK-12N-LABEL: func @identity(
|
||||
// CHECK-12N-SAME: %[[ARG0:.*]]: i1,
|
||||
@ -61,12 +61,12 @@ func.func @recursive_decomposition(%arg0: tuple<tuple<tuple<i1>>>) -> tuple<tupl
|
||||
// CHECK: %[[V2:.*]] = "test.make_tuple"(%[[ARG1]]) : (i2) -> tuple<i2>
|
||||
// CHECK: %[[V3:.*]] = "test.make_tuple"(%[[V2]]) : (tuple<i2>) -> tuple<tuple<i2>>
|
||||
// CHECK: %[[V4:.*]] = "test.make_tuple"(%[[V0]], %[[V1]], %[[V3]]) : (tuple<>, tuple<i1>, tuple<tuple<i2>>) -> tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>
|
||||
// CHECK: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) <{index = 0 : i32}> : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK: %[[V6:.*]] = "test.get_tuple_element"(%[[V4]]) <{index = 1 : i32}> : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<i1>
|
||||
// CHECK: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) <{index = 0 : i32}> : (tuple<i1>) -> i1
|
||||
// CHECK: %[[V8:.*]] = "test.get_tuple_element"(%[[V4]]) <{index = 2 : i32}> : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK: %[[V9:.*]] = "test.get_tuple_element"(%[[V8]]) <{index = 0 : i32}> : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK: %[[V10:.*]] = "test.get_tuple_element"(%[[V9]]) <{index = 0 : i32}> : (tuple<i2>) -> i2
|
||||
// CHECK: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) {index = 0 : i32} : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<>
|
||||
// CHECK: %[[V6:.*]] = "test.get_tuple_element"(%[[V4]]) {index = 1 : i32} : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<i1>
|
||||
// CHECK: %[[V7:.*]] = "test.get_tuple_element"(%[[V6]]) {index = 0 : i32} : (tuple<i1>) -> i1
|
||||
// CHECK: %[[V8:.*]] = "test.get_tuple_element"(%[[V4]]) {index = 2 : i32} : (tuple<tuple<>, tuple<i1>, tuple<tuple<i2>>>) -> tuple<tuple<i2>>
|
||||
// CHECK: %[[V9:.*]] = "test.get_tuple_element"(%[[V8]]) {index = 0 : i32} : (tuple<tuple<i2>>) -> tuple<i2>
|
||||
// CHECK: %[[V10:.*]] = "test.get_tuple_element"(%[[V9]]) {index = 0 : i32} : (tuple<i2>) -> i2
|
||||
// CHECK: return %[[V7]], %[[V10]] : i1, i2
|
||||
// CHECK-12N-LABEL: func @mixed_recursive_decomposition(
|
||||
// CHECK-12N-SAME: %[[ARG0:.*]]: i1,
|
||||
@ -88,12 +88,12 @@ func.func private @callee(tuple<i1, i32>) -> tuple<i1, i32>
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i1,
|
||||
// CHECK-SAME: %[[ARG1:.*]]: i32) -> (i1, i32) {
|
||||
// CHECK: %[[ARG_MATERIALIZED:.*]] = "test.make_tuple"(%[[ARG0]], %[[ARG1]]) : (i1, i32) -> tuple<i1, i32>
|
||||
// CHECK: %[[CALL_ARG0:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) <{index = 0 : i32}> : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[CALL_ARG1:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) <{index = 1 : i32}> : (tuple<i1, i32>) -> i32
|
||||
// CHECK: %[[CALL_ARG0:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) {index = 0 : i32} : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[CALL_ARG1:.*]] = "test.get_tuple_element"(%[[ARG_MATERIALIZED]]) {index = 1 : i32} : (tuple<i1, i32>) -> i32
|
||||
// CHECK: %[[DECOMPOSED:.*]]:2 = call @callee(%[[CALL_ARG0]], %[[CALL_ARG1]]) : (i1, i32) -> (i1, i32)
|
||||
// CHECK: %[[CALL_RESULT_RECOMPOSED:.*]] = "test.make_tuple"(%[[DECOMPOSED]]#0, %[[DECOMPOSED]]#1) : (i1, i32) -> tuple<i1, i32>
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[CALL_RESULT_RECOMPOSED]]) <{index = 0 : i32}> : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[CALL_RESULT_RECOMPOSED]]) <{index = 1 : i32}> : (tuple<i1, i32>) -> i32
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[CALL_RESULT_RECOMPOSED]]) {index = 0 : i32} : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[CALL_RESULT_RECOMPOSED]]) {index = 1 : i32} : (tuple<i1, i32>) -> i32
|
||||
// CHECK: return %[[RET0]], %[[RET1]] : i1, i32
|
||||
// CHECK-12N-LABEL: func @caller(
|
||||
// CHECK-12N-SAME: %[[ARG0:.*]]: i1,
|
||||
@ -131,13 +131,13 @@ func.func @caller(%arg0: tuple<>) -> tuple<> {
|
||||
|
||||
// CHECK-LABEL: func @unconverted_op_result() -> (i1, i32) {
|
||||
// CHECK: %[[UNCONVERTED_VALUE:.*]] = "test.source"() : () -> tuple<i1, i32>
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) <{index = 0 : i32}> : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) <{index = 1 : i32}> : (tuple<i1, i32>) -> i32
|
||||
// CHECK: %[[RET0:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) {index = 0 : i32} : (tuple<i1, i32>) -> i1
|
||||
// CHECK: %[[RET1:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) {index = 1 : i32} : (tuple<i1, i32>) -> i32
|
||||
// CHECK: return %[[RET0]], %[[RET1]] : i1, i32
|
||||
// CHECK-12N-LABEL: func @unconverted_op_result() -> (i1, i32) {
|
||||
// CHECK-12N: %[[UNCONVERTED_VALUE:.*]] = "test.source"() : () -> tuple<i1, i32>
|
||||
// CHECK-12N: %[[RET0:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) <{index = 0 : i32}> : (tuple<i1, i32>) -> i1
|
||||
// CHECK-12N: %[[RET1:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) <{index = 1 : i32}> : (tuple<i1, i32>) -> i32
|
||||
// CHECK-12N: %[[RET0:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) {index = 0 : i32} : (tuple<i1, i32>) -> i1
|
||||
// CHECK-12N: %[[RET1:.*]] = "test.get_tuple_element"(%[[UNCONVERTED_VALUE]]) {index = 1 : i32} : (tuple<i1, i32>) -> i32
|
||||
// CHECK-12N: return %[[RET0]], %[[RET1]] : i1, i32
|
||||
func.func @unconverted_op_result() -> tuple<i1, i32> {
|
||||
%0 = "test.source"() : () -> (tuple<i1, i32>)
|
||||
@ -155,9 +155,9 @@ func.func @unconverted_op_result() -> tuple<i1, i32> {
|
||||
// CHECK: %[[V0:.*]] = "test.make_tuple"(%[[ARG1]]) : (i32) -> tuple<i32>
|
||||
// CHECK: %[[V1:.*]] = "test.make_tuple"(%[[ARG0]], %[[V0]]) : (i1, tuple<i32>) -> tuple<i1, tuple<i32>>
|
||||
// CHECK: %[[V2:.*]] = "test.op"(%[[V1]]) : (tuple<i1, tuple<i32>>) -> tuple<i1, tuple<i32>>
|
||||
// CHECK: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 0 : i32}> : (tuple<i1, tuple<i32>>) -> i1
|
||||
// CHECK: %[[V4:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 1 : i32}> : (tuple<i1, tuple<i32>>) -> tuple<i32>
|
||||
// CHECK: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) <{index = 0 : i32}> : (tuple<i32>) -> i32
|
||||
// CHECK: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) {index = 0 : i32} : (tuple<i1, tuple<i32>>) -> i1
|
||||
// CHECK: %[[V4:.*]] = "test.get_tuple_element"(%[[V2]]) {index = 1 : i32} : (tuple<i1, tuple<i32>>) -> tuple<i32>
|
||||
// CHECK: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) {index = 0 : i32} : (tuple<i32>) -> i32
|
||||
// CHECK: return %[[V3]], %[[V5]] : i1, i32
|
||||
// CHECK-12N-LABEL: func @nested_unconverted_op_result(
|
||||
// CHECK-12N-SAME: %[[ARG0:.*]]: i1,
|
||||
@ -165,9 +165,9 @@ func.func @unconverted_op_result() -> tuple<i1, i32> {
|
||||
// CHECK-12N: %[[V0:.*]] = "test.make_tuple"(%[[ARG1]]) : (i32) -> tuple<i32>
|
||||
// CHECK-12N: %[[V1:.*]] = "test.make_tuple"(%[[ARG0]], %[[V0]]) : (i1, tuple<i32>) -> tuple<i1, tuple<i32>>
|
||||
// CHECK-12N: %[[V2:.*]] = "test.op"(%[[V1]]) : (tuple<i1, tuple<i32>>) -> tuple<i1, tuple<i32>>
|
||||
// CHECK-12N: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 0 : i32}> : (tuple<i1, tuple<i32>>) -> i1
|
||||
// CHECK-12N: %[[V4:.*]] = "test.get_tuple_element"(%[[V2]]) <{index = 1 : i32}> : (tuple<i1, tuple<i32>>) -> tuple<i32>
|
||||
// CHECK-12N: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) <{index = 0 : i32}> : (tuple<i32>) -> i32
|
||||
// CHECK-12N: %[[V3:.*]] = "test.get_tuple_element"(%[[V2]]) {index = 0 : i32} : (tuple<i1, tuple<i32>>) -> i1
|
||||
// CHECK-12N: %[[V4:.*]] = "test.get_tuple_element"(%[[V2]]) {index = 1 : i32} : (tuple<i1, tuple<i32>>) -> tuple<i32>
|
||||
// CHECK-12N: %[[V5:.*]] = "test.get_tuple_element"(%[[V4]]) {index = 0 : i32} : (tuple<i32>) -> i32
|
||||
// CHECK-12N: return %[[V3]], %[[V5]] : i1, i32
|
||||
func.func @nested_unconverted_op_result(%arg: tuple<i1, tuple<i32>>) -> tuple<i1, tuple<i32>> {
|
||||
%0 = "test.op"(%arg) : (tuple<i1, tuple<i32>>) -> (tuple<i1, tuple<i32>>)
|
||||
@ -191,12 +191,12 @@ func.func private @callee(tuple<>, i1, tuple<i2>, i3, tuple<i4, i5>, i6) -> (tup
|
||||
// CHECK-SAME: %[[I5:.*]]: i5,
|
||||
// CHECK-SAME: %[[I6:.*]]: i6) -> (i1, i2, i3, i4, i5, i6) {
|
||||
// CHECK: %[[ARG_TUPLE:.*]] = "test.make_tuple"(%[[I4]], %[[I5]]) : (i4, i5) -> tuple<i4, i5>
|
||||
// CHECK: %[[ARG_TUPLE_0:.*]] = "test.get_tuple_element"(%[[ARG_TUPLE]]) <{index = 0 : i32}> : (tuple<i4, i5>) -> i4
|
||||
// CHECK: %[[ARG_TUPLE_1:.*]] = "test.get_tuple_element"(%[[ARG_TUPLE]]) <{index = 1 : i32}> : (tuple<i4, i5>) -> i5
|
||||
// CHECK: %[[ARG_TUPLE_0:.*]] = "test.get_tuple_element"(%[[ARG_TUPLE]]) {index = 0 : i32} : (tuple<i4, i5>) -> i4
|
||||
// CHECK: %[[ARG_TUPLE_1:.*]] = "test.get_tuple_element"(%[[ARG_TUPLE]]) {index = 1 : i32} : (tuple<i4, i5>) -> i5
|
||||
// CHECK: %[[CALL:.*]]:6 = call @callee(%[[I1]], %[[I2]], %[[I3]], %[[ARG_TUPLE_0]], %[[ARG_TUPLE_1]], %[[I6]]) : (i1, i2, i3, i4, i5, i6) -> (i1, i2, i3, i4, i5, i6)
|
||||
// CHECK: %[[RET_TUPLE:.*]] = "test.make_tuple"(%[[CALL]]#3, %[[CALL]]#4) : (i4, i5) -> tuple<i4, i5>
|
||||
// CHECK: %[[RET_TUPLE_0:.*]] = "test.get_tuple_element"(%[[RET_TUPLE]]) <{index = 0 : i32}> : (tuple<i4, i5>) -> i4
|
||||
// CHECK: %[[RET_TUPLE_1:.*]] = "test.get_tuple_element"(%[[RET_TUPLE]]) <{index = 1 : i32}> : (tuple<i4, i5>) -> i5
|
||||
// CHECK: %[[RET_TUPLE_0:.*]] = "test.get_tuple_element"(%[[RET_TUPLE]]) {index = 0 : i32} : (tuple<i4, i5>) -> i4
|
||||
// CHECK: %[[RET_TUPLE_1:.*]] = "test.get_tuple_element"(%[[RET_TUPLE]]) {index = 1 : i32} : (tuple<i4, i5>) -> i5
|
||||
// CHECK: return %[[CALL]]#0, %[[CALL]]#1, %[[CALL]]#2, %[[RET_TUPLE_0]], %[[RET_TUPLE_1]], %[[CALL]]#5 : i1, i2, i3, i4, i5, i6
|
||||
// CHECK-12N-LABEL: func @caller(
|
||||
// CHECK-12N-SAME: %[[I1:.*]]: i1,
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
// CHECK-LABEL: verifyDirectPattern
|
||||
func.func @verifyDirectPattern() -> i32 {
|
||||
// CHECK-NEXT: "test.legal_op_a"() <{status = "Success"}
|
||||
// CHECK-NEXT: "test.legal_op_a"() {status = "Success"}
|
||||
%result = "test.illegal_op_a"() : () -> (i32)
|
||||
// expected-remark@+1 {{op 'func.return' is not legalizable}}
|
||||
return %result : i32
|
||||
@ -10,7 +10,7 @@ func.func @verifyDirectPattern() -> i32 {
|
||||
|
||||
// CHECK-LABEL: verifyLargerBenefit
|
||||
func.func @verifyLargerBenefit() -> i32 {
|
||||
// CHECK-NEXT: "test.legal_op_a"() <{status = "Success"}
|
||||
// CHECK-NEXT: "test.legal_op_a"() {status = "Success"}
|
||||
%result = "test.illegal_op_c"() : () -> (i32)
|
||||
// expected-remark@+1 {{op 'func.return' is not legalizable}}
|
||||
return %result : i32
|
||||
|
@ -7,7 +7,7 @@ func.func @foo() -> i32 {
|
||||
// The new operation should be present in the output and contain an attribute
|
||||
// with value "42" that results from folding.
|
||||
|
||||
// CHECK: "test.op_in_place_fold"(%{{.*}}) <{attr = 42 : i32}
|
||||
// CHECK: "test.op_in_place_fold"(%{{.*}}) {attr = 42 : i32}
|
||||
%0 = "test.op_in_place_fold_anchor"(%c42) : (i32) -> (i32)
|
||||
return %0 : i32
|
||||
}
|
||||
|
@ -21,7 +21,6 @@
|
||||
#include "mlir/IR/ExtensibleDialect.h"
|
||||
#include "mlir/IR/FunctionImplementation.h"
|
||||
#include "mlir/IR/MLIRContext.h"
|
||||
#include "mlir/IR/ODSSupport.h"
|
||||
#include "mlir/IR/OperationSupport.h"
|
||||
#include "mlir/IR/PatternMatch.h"
|
||||
#include "mlir/IR/TypeUtilities.h"
|
||||
@ -44,36 +43,6 @@
|
||||
using namespace mlir;
|
||||
using namespace test;
|
||||
|
||||
Attribute MyPropStruct::asAttribute(MLIRContext *ctx) const {
|
||||
return StringAttr::get(ctx, content);
|
||||
}
|
||||
LogicalResult MyPropStruct::setFromAttr(MyPropStruct &prop, Attribute attr,
|
||||
InFlightDiagnostic *diag) {
|
||||
StringAttr strAttr = attr.dyn_cast<StringAttr>();
|
||||
if (!strAttr) {
|
||||
if (diag)
|
||||
*diag << "Expect StringAttr but got " << attr;
|
||||
return failure();
|
||||
}
|
||||
prop.content = strAttr.getValue();
|
||||
return success();
|
||||
}
|
||||
llvm::hash_code MyPropStruct::hash() const {
|
||||
return hash_value(StringRef(content));
|
||||
}
|
||||
|
||||
static LogicalResult setPropertiesFromAttribute(PropertiesWithCustomPrint &prop,
|
||||
Attribute attr,
|
||||
InFlightDiagnostic *diagnostic);
|
||||
static DictionaryAttr
|
||||
getPropertiesAsAttribute(MLIRContext *ctx,
|
||||
const PropertiesWithCustomPrint &prop);
|
||||
static llvm::hash_code computeHash(const PropertiesWithCustomPrint &prop);
|
||||
static void customPrintProperties(OpAsmPrinter &p,
|
||||
const PropertiesWithCustomPrint &prop);
|
||||
static ParseResult customParseProperties(OpAsmParser &parser,
|
||||
PropertiesWithCustomPrint &prop);
|
||||
|
||||
void test::registerTestDialect(DialectRegistry ®istry) {
|
||||
registry.insert<TestDialect>();
|
||||
}
|
||||
@ -545,7 +514,7 @@ Operation *TestDialect::materializeConstant(OpBuilder &builder, Attribute value,
|
||||
::mlir::LogicalResult FormatInferType2Op::inferReturnTypes(
|
||||
::mlir::MLIRContext *context, ::std::optional<::mlir::Location> location,
|
||||
::mlir::ValueRange operands, ::mlir::DictionaryAttr attributes,
|
||||
OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
inferredReturnTypes.assign({::mlir::IntegerType::get(context, 16)});
|
||||
return ::mlir::success();
|
||||
@ -1295,7 +1264,7 @@ LogicalResult TestOpWithVariadicResultsAndFolder::fold(
|
||||
}
|
||||
|
||||
OpFoldResult TestOpInPlaceFold::fold(FoldAdaptor adaptor) {
|
||||
if (adaptor.getOp() && !(*this)->getAttr("attr")) {
|
||||
if (adaptor.getOp() && !(*this)->hasAttr("attr")) {
|
||||
// The folder adds "attr" if not present.
|
||||
(*this)->setAttr("attr", adaptor.getOp());
|
||||
return getResult();
|
||||
@ -1328,7 +1297,7 @@ OpFoldResult TestOpFoldWithFoldAdaptor::fold(FoldAdaptor adaptor) {
|
||||
|
||||
LogicalResult OpWithInferTypeInterfaceOp::inferReturnTypes(
|
||||
MLIRContext *, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &inferredReturnTypes) {
|
||||
if (operands[0].getType() != operands[1].getType()) {
|
||||
return emitOptionalError(location, "operand type mismatch ",
|
||||
@ -1343,17 +1312,16 @@ LogicalResult OpWithInferTypeInterfaceOp::inferReturnTypes(
|
||||
// refineReturnType, currently only refineReturnType can be omitted.
|
||||
LogicalResult OpWithRefineTypeInterfaceOp::inferReturnTypes(
|
||||
MLIRContext *context, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &returnTypes) {
|
||||
returnTypes.clear();
|
||||
return OpWithRefineTypeInterfaceOp::refineReturnTypes(
|
||||
context, location, operands, attributes, properties, regions,
|
||||
returnTypes);
|
||||
context, location, operands, attributes, regions, returnTypes);
|
||||
}
|
||||
|
||||
LogicalResult OpWithRefineTypeInterfaceOp::refineReturnTypes(
|
||||
MLIRContext *, std::optional<Location> location, ValueRange operands,
|
||||
DictionaryAttr attributes, OpaqueProperties properties, RegionRange regions,
|
||||
DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<Type> &returnTypes) {
|
||||
if (operands[0].getType() != operands[1].getType()) {
|
||||
return emitOptionalError(location, "operand type mismatch ",
|
||||
@ -1372,8 +1340,7 @@ LogicalResult OpWithRefineTypeInterfaceOp::refineReturnTypes(
|
||||
|
||||
LogicalResult OpWithShapedTypeInferTypeInterfaceOp::inferReturnTypeComponents(
|
||||
MLIRContext *context, std::optional<Location> location,
|
||||
ValueShapeRange operands, DictionaryAttr attributes,
|
||||
OpaqueProperties properties, RegionRange regions,
|
||||
ValueShapeRange operands, DictionaryAttr attributes, RegionRange regions,
|
||||
SmallVectorImpl<ShapedTypeComponents> &inferredReturnShapes) {
|
||||
// Create return type consisting of the last element of the first operand.
|
||||
auto operandType = operands.front().getType();
|
||||
@ -1830,59 +1797,6 @@ OpFoldResult ManualCppOpWithFold::fold(ArrayRef<Attribute> attributes) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static LogicalResult
|
||||
setPropertiesFromAttribute(PropertiesWithCustomPrint &prop, Attribute attr,
|
||||
InFlightDiagnostic *diagnostic) {
|
||||
DictionaryAttr dict = dyn_cast<DictionaryAttr>(attr);
|
||||
if (!dict) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected DictionaryAttr to set TestProperties";
|
||||
return failure();
|
||||
}
|
||||
auto label = dict.getAs<mlir::StringAttr>("label");
|
||||
if (!label) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected StringAttr for key `label`";
|
||||
return failure();
|
||||
}
|
||||
auto valueAttr = dict.getAs<IntegerAttr>("value");
|
||||
if (!valueAttr) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected IntegerAttr for key `value`";
|
||||
return failure();
|
||||
}
|
||||
|
||||
prop.label = std::make_shared<std::string>(label.getValue());
|
||||
prop.value = valueAttr.getValue().getSExtValue();
|
||||
return success();
|
||||
}
|
||||
static DictionaryAttr
|
||||
getPropertiesAsAttribute(MLIRContext *ctx,
|
||||
const PropertiesWithCustomPrint &prop) {
|
||||
SmallVector<NamedAttribute> attrs;
|
||||
Builder b{ctx};
|
||||
attrs.push_back(b.getNamedAttr("label", b.getStringAttr(*prop.label)));
|
||||
attrs.push_back(b.getNamedAttr("value", b.getI32IntegerAttr(prop.value)));
|
||||
return b.getDictionaryAttr(attrs);
|
||||
}
|
||||
static llvm::hash_code computeHash(const PropertiesWithCustomPrint &prop) {
|
||||
return llvm::hash_combine(prop.value, StringRef(*prop.label));
|
||||
}
|
||||
static void customPrintProperties(OpAsmPrinter &p,
|
||||
const PropertiesWithCustomPrint &prop) {
|
||||
p.printKeywordOrString(*prop.label);
|
||||
p << " is " << prop.value;
|
||||
}
|
||||
static ParseResult customParseProperties(OpAsmParser &parser,
|
||||
PropertiesWithCustomPrint &prop) {
|
||||
std::string label;
|
||||
if (parser.parseKeywordOrString(&label) || parser.parseKeyword("is") ||
|
||||
parser.parseInteger(prop.value))
|
||||
return failure();
|
||||
prop.label = std::make_shared<std::string>(std::move(label));
|
||||
return success();
|
||||
}
|
||||
|
||||
#include "TestOpEnums.cpp.inc"
|
||||
#include "TestOpInterfaces.cpp.inc"
|
||||
#include "TestTypeInterfaces.cpp.inc"
|
||||
|
@ -42,8 +42,6 @@
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
#include "mlir/Interfaces/ViewLikeInterface.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace mlir {
|
||||
class DLTIDialect;
|
||||
class RewritePatternSet;
|
||||
@ -56,30 +54,6 @@ class RewritePatternSet;
|
||||
#include "TestOpInterfaces.h.inc"
|
||||
#include "TestOpsDialect.h.inc"
|
||||
|
||||
namespace test {
|
||||
// Define some classes to exercises the Properties feature.
|
||||
|
||||
struct PropertiesWithCustomPrint {
|
||||
/// A shared_ptr to a const object is safe: it is equivalent to a value-based
|
||||
/// member. Here the label will be deallocated when the last operation
|
||||
/// refering to it is destroyed. However there is no pool-allocation: this is
|
||||
/// offloaded to the client.
|
||||
std::shared_ptr<const std::string> label;
|
||||
int value;
|
||||
};
|
||||
class MyPropStruct {
|
||||
public:
|
||||
std::string content;
|
||||
// These three methods are invoked through the `MyStructProperty` wrapper
|
||||
// defined in TestOps.td
|
||||
mlir::Attribute asAttribute(mlir::MLIRContext *ctx) const;
|
||||
static mlir::LogicalResult setFromAttr(MyPropStruct &prop,
|
||||
mlir::Attribute attr,
|
||||
mlir::InFlightDiagnostic *diag);
|
||||
llvm::hash_code hash() const;
|
||||
};
|
||||
} // namespace test
|
||||
|
||||
#define GET_OP_CLASSES
|
||||
#include "TestOps.h.inc"
|
||||
|
||||
|
@ -24,7 +24,6 @@ def Test_Dialect : Dialect {
|
||||
let useDefaultTypePrinterParser = 0;
|
||||
let useDefaultAttributePrinterParser = 1;
|
||||
let isExtensible = 1;
|
||||
let usePropertiesForAttributes = 1;
|
||||
let dependentDialects = ["::mlir::DLTIDialect"];
|
||||
|
||||
let extraClassDeclaration = [{
|
||||
|
@ -430,7 +430,7 @@ def VariadicRegionInferredTypesOp : TEST_Op<"variadic_region_inferred",
|
||||
let extraClassDeclaration = [{
|
||||
static mlir::LogicalResult inferReturnTypes(mlir::MLIRContext *context,
|
||||
std::optional<::mlir::Location> location, mlir::ValueRange operands,
|
||||
mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, mlir::RegionRange regions,
|
||||
mlir::DictionaryAttr attributes, mlir::RegionRange regions,
|
||||
llvm::SmallVectorImpl<mlir::Type> &inferredReturnTypes) {
|
||||
inferredReturnTypes.assign({mlir::IntegerType::get(context, 16)});
|
||||
return mlir::success();
|
||||
@ -2524,7 +2524,7 @@ def FormatInferTypeOp : TEST_Op<"format_infer_type", [InferTypeOpInterface]> {
|
||||
let extraClassDeclaration = [{
|
||||
static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
|
||||
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
|
||||
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
inferredReturnTypes.assign({::mlir::IntegerType::get(context, 16)});
|
||||
return ::mlir::success();
|
||||
@ -2547,7 +2547,7 @@ class FormatInferAllTypesBaseOp<string mnemonic, list<Trait> traits = []>
|
||||
let extraClassDeclaration = [{
|
||||
static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
|
||||
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
|
||||
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
::mlir::TypeRange operandTypes = operands.getTypes();
|
||||
inferredReturnTypes.assign(operandTypes.begin(), operandTypes.end());
|
||||
@ -2594,7 +2594,7 @@ def FormatInferTypeRegionsOp
|
||||
let extraClassDeclaration = [{
|
||||
static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
|
||||
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
|
||||
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
if (regions.empty())
|
||||
return ::mlir::failure();
|
||||
@ -2615,10 +2615,9 @@ def FormatInferTypeVariadicOperandsOp
|
||||
let extraClassDeclaration = [{
|
||||
static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *context,
|
||||
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
|
||||
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
FormatInferTypeVariadicOperandsOpAdaptor adaptor(
|
||||
operands, attributes, *properties.as<Properties *>(), {});
|
||||
FormatInferTypeVariadicOperandsOpAdaptor adaptor(operands, attributes);
|
||||
auto aTypes = adaptor.getA().getTypes();
|
||||
auto bTypes = adaptor.getB().getTypes();
|
||||
inferredReturnTypes.append(aTypes.begin(), aTypes.end());
|
||||
@ -2824,7 +2823,7 @@ class TableGenBuildInferReturnTypeBaseOp<string mnemonic,
|
||||
let extraClassDeclaration = [{
|
||||
static ::mlir::LogicalResult inferReturnTypes(::mlir::MLIRContext *,
|
||||
::std::optional<::mlir::Location> location, ::mlir::ValueRange operands,
|
||||
::mlir::DictionaryAttr attributes, mlir::OpaqueProperties properties, ::mlir::RegionRange regions,
|
||||
::mlir::DictionaryAttr attributes, ::mlir::RegionRange regions,
|
||||
::llvm::SmallVectorImpl<::mlir::Type> &inferredReturnTypes) {
|
||||
inferredReturnTypes.assign({operands[0].getType()});
|
||||
return ::mlir::success();
|
||||
@ -3281,77 +3280,4 @@ def TestVersionedOpB : TEST_Op<"versionedB"> {
|
||||
);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Test Properties
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
// Op with a properties struct defined inline.
|
||||
def TestOpWithProperties : TEST_Op<"with_properties"> {
|
||||
let assemblyFormat = "prop-dict attr-dict";
|
||||
let arguments = (ins
|
||||
Property<"int64_t">:$a,
|
||||
StrAttr:$b, // Attributes can directly be used here.
|
||||
ArrayProperty<"int64_t", 4>:$array // example of an array
|
||||
);
|
||||
}
|
||||
|
||||
// Demonstrate how to wrap an existing C++ class named MyPropStruct.
|
||||
def MyStructProperty : Property<"MyPropStruct"> {
|
||||
let convertToAttribute = "$_storage.asAttribute($_ctxt)";
|
||||
let convertFromAttribute = "return MyPropStruct::setFromAttr($_storage, $_attr, $_diag);";
|
||||
let hashProperty = "$_storage.hash();";
|
||||
}
|
||||
|
||||
def TestOpWithWrappedProperties : TEST_Op<"with_wrapped_properties"> {
|
||||
let assemblyFormat = "prop-dict attr-dict";
|
||||
let arguments = (ins
|
||||
MyStructProperty:$prop
|
||||
);
|
||||
}
|
||||
|
||||
// Op with a properties struct defined out-of-line. The struct has custom
|
||||
// printer/parser.
|
||||
|
||||
def PropertiesWithCustomPrint : Property<"PropertiesWithCustomPrint"> {
|
||||
let convertToAttribute = [{
|
||||
getPropertiesAsAttribute($_ctxt, $_storage)
|
||||
}];
|
||||
let convertFromAttribute = [{
|
||||
return setPropertiesFromAttribute($_storage, $_attr, $_diag);
|
||||
}];
|
||||
let hashProperty = [{
|
||||
computeHash($_storage);
|
||||
}];
|
||||
}
|
||||
|
||||
def TestOpWithNiceProperties : TEST_Op<"with_nice_properties"> {
|
||||
let assemblyFormat = "prop-dict attr-dict";
|
||||
let arguments = (ins
|
||||
PropertiesWithCustomPrint:$prop
|
||||
);
|
||||
let extraClassDeclaration = [{
|
||||
void printProperties(::mlir::MLIRContext *ctx, ::mlir::OpAsmPrinter &p,
|
||||
const Properties &prop);
|
||||
static ::mlir::ParseResult parseProperties(::mlir::OpAsmParser &parser,
|
||||
::mlir::OperationState &result);
|
||||
}];
|
||||
let extraClassDefinition = [{
|
||||
void TestOpWithNiceProperties::printProperties(::mlir::MLIRContext *ctx,
|
||||
::mlir::OpAsmPrinter &p, const Properties &prop) {
|
||||
customPrintProperties(p, prop.prop);
|
||||
}
|
||||
::mlir::ParseResult TestOpWithNiceProperties::parseProperties(
|
||||
::mlir::OpAsmParser &parser,
|
||||
::mlir::OperationState &result) {
|
||||
Properties &prop = result.getOrAddProperties<Properties>();
|
||||
if (customParseProperties(parser, prop.prop))
|
||||
return failure();
|
||||
return success();
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif // TEST_OPS
|
||||
|
@ -434,8 +434,7 @@ static void invokeCreateWithInferredReturnType(Operation *op) {
|
||||
SmallVector<Type, 2> inferredReturnTypes;
|
||||
if (succeeded(OpTy::inferReturnTypes(
|
||||
context, std::nullopt, values, op->getAttrDictionary(),
|
||||
op->getPropertiesStorage(), op->getRegions(),
|
||||
inferredReturnTypes))) {
|
||||
op->getRegions(), inferredReturnTypes))) {
|
||||
OperationState state(location, OpTy::getOperationName());
|
||||
// TODO: Expand to regions.
|
||||
OpTy::build(b, state, values, op->getAttrs());
|
||||
|
@ -69,8 +69,8 @@ def OpC : NS_Op<"op_c"> {
|
||||
|
||||
/// Test that an attribute contraint was generated.
|
||||
// CHECK: static ::mlir::LogicalResult [[$A_ATTR_CONSTRAINT:__mlir_ods_local_attr_constraint.*]](
|
||||
// CHECK: if (attr && !((attrPred(attr, *op))))
|
||||
// CHECK-NEXT: return getDiag() << "attribute '" << attrName
|
||||
// CHECK: if (attr && !((attrPred(attr, *op)))) {
|
||||
// CHECK-NEXT: return op->emitOpError("attribute '") << attrName
|
||||
// CHECK-NEXT: << "' failed to satisfy constraint: an attribute";
|
||||
|
||||
/// Test that duplicate attribute constraint was not generated.
|
||||
@ -78,9 +78,8 @@ def OpC : NS_Op<"op_c"> {
|
||||
|
||||
/// Test that a attribute constraint with a different description was generated.
|
||||
// CHECK: static ::mlir::LogicalResult [[$O_ATTR_CONSTRAINT:__mlir_ods_local_attr_constraint.*]](
|
||||
// CHECK: static ::mlir::LogicalResult [[$O_ATTR_CONSTRAINT:__mlir_ods_local_attr_constraint.*]](
|
||||
// CHECK: if (attr && !((attrPred(attr, *op))))
|
||||
// CHECK-NEXT: return getDiag() << "attribute '" << attrName
|
||||
// CHECK: if (attr && !((attrPred(attr, *op)))) {
|
||||
// CHECK-NEXT: return op->emitOpError("attribute '") << attrName
|
||||
// CHECK-NEXT: << "' failed to satisfy constraint: another attribute";
|
||||
|
||||
/// Test that a successor contraint was generated.
|
||||
|
@ -34,13 +34,13 @@ def OpUsingAllOfThose : Op<Test_Dialect, "OpUsingAllOfThose"> {
|
||||
// CHECK-NEXT: << " must be TypeInterfaceInNamespace instance, but got " << type;
|
||||
|
||||
// CHECK: static ::mlir::LogicalResult {{__mlir_ods_local_attr_constraint.*}}(
|
||||
// CHECK: if (attr && !((attr.isa<TopLevelAttrInterface>())))
|
||||
// CHECK-NEXT: return getDiag() << "attribute '" << attrName
|
||||
// CHECK: if (attr && !((attr.isa<TopLevelAttrInterface>()))) {
|
||||
// CHECK-NEXT: return op->emitOpError("attribute '") << attrName
|
||||
// CHECK-NEXT: << "' failed to satisfy constraint: TopLevelAttrInterface instance";
|
||||
|
||||
// CHECK: static ::mlir::LogicalResult {{__mlir_ods_local_attr_constraint.*}}(
|
||||
// CHECK: if (attr && !((attr.isa<test::AttrInterfaceInNamespace>())))
|
||||
// CHECK-NEXT: return getDiag() << "attribute '" << attrName
|
||||
// CHECK: if (attr && !((attr.isa<test::AttrInterfaceInNamespace>()))) {
|
||||
// CHECK-NEXT: return op->emitOpError("attribute '") << attrName
|
||||
// CHECK-NEXT: << "' failed to satisfy constraint: AttrInterfaceInNamespace instance";
|
||||
|
||||
// CHECK: TopLevelAttrInterface OpUsingAllOfThose::getAttr1()
|
||||
|
@ -68,7 +68,7 @@ def AOp : NS_Op<"a_op", []> {
|
||||
|
||||
// DEF: ::mlir::LogicalResult AOpAdaptor::verify
|
||||
// DEF: ::mlir::Attribute tblgen_aAttr;
|
||||
// DEF: while (true) {
|
||||
// DEF-NEXT: while (true) {
|
||||
// DEF-NEXT: if (namedAttrIt == namedAttrRange.end())
|
||||
// DEF-NEXT: return emitError(loc, "'test.a_op' op ""requires attribute 'aAttr'");
|
||||
// DEF-NEXT: if (namedAttrIt->getName() == AOp::getAAttrAttrName(*odsOpName)) {
|
||||
@ -217,10 +217,10 @@ def AgetOp : Op<Test2_Dialect, "a_get_op", []> {
|
||||
|
||||
// DEF: ::mlir::LogicalResult AgetOpAdaptor::verify
|
||||
// DEF: ::mlir::Attribute tblgen_aAttr;
|
||||
// DEF: while (true)
|
||||
// DEF-NEXT: while (true)
|
||||
// DEF: ::mlir::Attribute tblgen_bAttr;
|
||||
// DEF-NEXT: ::mlir::Attribute tblgen_cAttr;
|
||||
// DEF: while (true)
|
||||
// DEF-NEXT: while (true)
|
||||
// DEF: if (tblgen_aAttr && !((some-condition)))
|
||||
// DEF-NEXT: return emitError(loc, "'test2.a_get_op' op ""attribute 'aAttr' failed to satisfy constraint: some attribute kind");
|
||||
// DEF: if (tblgen_bAttr && !((some-condition)))
|
||||
|
@ -126,7 +126,7 @@ def NS_AOp : NS_Op<"a_op", [IsolatedFromAbove, IsolatedFromAbove]> {
|
||||
|
||||
// DEFS-LABEL: NS::AOp definitions
|
||||
|
||||
// DEFS: AOpGenericAdaptorBase::AOpGenericAdaptorBase(::mlir::DictionaryAttr attrs, ::mlir::EmptyProperties properties, ::mlir::RegionRange regions) : odsAttrs(attrs), odsRegions(regions)
|
||||
// DEFS: AOpGenericAdaptorBase::AOpGenericAdaptorBase(::mlir::DictionaryAttr attrs, ::mlir::RegionRange regions) : odsAttrs(attrs), odsRegions(regions)
|
||||
// DEFS: ::mlir::RegionRange AOpGenericAdaptorBase::getSomeRegions()
|
||||
// DEFS-NEXT: return odsRegions.drop_front(1);
|
||||
// DEFS: ::mlir::RegionRange AOpGenericAdaptorBase::getRegions()
|
||||
|
@ -64,7 +64,7 @@ def OptionalGroupA : TestFormat_Op<[{
|
||||
// CHECK-NEXT: result.addAttribute("a", parser.getBuilder().getUnitAttr())
|
||||
// CHECK: parser.parseKeyword("bar")
|
||||
// CHECK-LABEL: OptionalGroupB::print
|
||||
// CHECK: if (!getAAttr())
|
||||
// CHECK: if (!(*this)->getAttr("a"))
|
||||
// CHECK-NEXT: odsPrinter << ' ' << "foo"
|
||||
// CHECK-NEXT: else
|
||||
// CHECK-NEXT: odsPrinter << ' ' << "bar"
|
||||
@ -74,8 +74,7 @@ def OptionalGroupB : TestFormat_Op<[{
|
||||
|
||||
// Optional group anchored on a default-valued attribute:
|
||||
// CHECK-LABEL: OptionalGroupC::parse
|
||||
|
||||
// CHECK: if (getAAttr() && getAAttr() != ::mlir::OpBuilder((*this)->getContext()).getStringAttr("default")) {
|
||||
// CHECK: if ((*this)->getAttr("a") != ::mlir::OpBuilder((*this)->getContext()).getStringAttr("default")) {
|
||||
// CHECK-NEXT: odsPrinter << ' ';
|
||||
// CHECK-NEXT: odsPrinter.printAttributeWithoutType(getAAttr());
|
||||
// CHECK-NEXT: }
|
||||
|
@ -152,7 +152,7 @@ def OpL3 : NS_Op<"op_with_all_types_constraint",
|
||||
|
||||
// CHECK-LABEL: LogicalResult OpL3::inferReturnTypes
|
||||
// CHECK-NOT: }
|
||||
// CHECK: ::mlir::Type odsInferredType0 = odsInferredTypeAttr0.getType();
|
||||
// CHECK: ::mlir::Type odsInferredType0 = attributes.get("a").cast<::mlir::TypedAttr>().getType();
|
||||
// CHECK: inferredReturnTypes[0] = odsInferredType0;
|
||||
|
||||
def OpL4 : NS_Op<"two_inference_edges", [
|
||||
|
@ -5,8 +5,8 @@ func.func @verifyFusedLocs(%arg0 : i32) -> i32 {
|
||||
%0 = "test.op_a"(%arg0) {attr = 10 : i32} : (i32) -> i32 loc("a")
|
||||
%result = "test.op_a"(%0) {attr = 20 : i32} : (i32) -> i32 loc("b")
|
||||
|
||||
// CHECK: "test.op_b"(%arg0) <{attr = 10 : i32}> : (i32) -> i32 loc("a")
|
||||
// CHECK: "test.op_b"(%arg0) <{attr = 20 : i32}> : (i32) -> i32 loc(fused["b", "a"])
|
||||
// CHECK: "test.op_b"(%arg0) {attr = 10 : i32} : (i32) -> i32 loc("a")
|
||||
// CHECK: "test.op_b"(%arg0) {attr = 20 : i32} : (i32) -> i32 loc(fused["b", "a"])
|
||||
return %result : i32
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ func.func @verifyZeroArg() -> i32 {
|
||||
// CHECK-LABEL: testIgnoreArgMatch
|
||||
// CHECK-SAME: (%{{[a-z0-9]*}}: i32 loc({{[^)]*}}), %[[ARG1:[a-z0-9]*]]: i32 loc({{[^)]*}}),
|
||||
func.func @testIgnoreArgMatch(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: f32) {
|
||||
// CHECK: "test.ignore_arg_match_dst"(%[[ARG1]]) <{f = 15 : i64}>
|
||||
// CHECK: "test.ignore_arg_match_dst"(%[[ARG1]]) {f = 15 : i64}
|
||||
"test.ignore_arg_match_src"(%arg0, %arg1, %arg2) {d = 42, e = 24, f = 15} : (i32, i32, i32) -> ()
|
||||
|
||||
// CHECK: test.ignore_arg_match_src
|
||||
@ -57,7 +57,7 @@ func.func @testIgnoreArgMatch(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: f32) {
|
||||
// CHECK-LABEL: verifyInterleavedOperandAttribute
|
||||
// CHECK-SAME: %[[ARG0:.*]]: i32 loc({{[^)]*}}), %[[ARG1:.*]]: i32 loc({{[^)]*}})
|
||||
func.func @verifyInterleavedOperandAttribute(%arg0: i32, %arg1: i32) {
|
||||
// CHECK: "test.interleaved_operand_attr2"(%[[ARG0]], %[[ARG1]]) <{attr1 = 15 : i64, attr2 = 42 : i64}>
|
||||
// CHECK: "test.interleaved_operand_attr2"(%[[ARG0]], %[[ARG1]]) {attr1 = 15 : i64, attr2 = 42 : i64}
|
||||
"test.interleaved_operand_attr1"(%arg0, %arg1) {attr1 = 15, attr2 = 42} : (i32, i32) -> ()
|
||||
return
|
||||
}
|
||||
@ -69,13 +69,13 @@ func.func @verifyBenefit(%arg0 : i32) -> i32 {
|
||||
%2 = "test.op_g"(%1) : (i32) -> i32
|
||||
|
||||
// CHECK: "test.op_f"(%arg0)
|
||||
// CHECK: "test.op_b"(%arg0) <{attr = 34 : i32}>
|
||||
// CHECK: "test.op_b"(%arg0) {attr = 34 : i32}
|
||||
return %0 : i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: verifyNativeCodeCall
|
||||
func.func @verifyNativeCodeCall(%arg0: i32, %arg1: i32) -> (i32, i32) {
|
||||
// CHECK: %0 = "test.native_code_call2"(%arg0) <{attr = [42, 24]}> : (i32) -> i32
|
||||
// CHECK: %0 = "test.native_code_call2"(%arg0) {attr = [42, 24]} : (i32) -> i32
|
||||
// CHECK: return %0, %arg1
|
||||
%0 = "test.native_code_call1"(%arg0, %arg1) {choice = true, attr1 = 42, attr2 = 24} : (i32, i32) -> (i32)
|
||||
%1 = "test.native_code_call1"(%arg0, %arg1) {choice = false, attr1 = 42, attr2 = 24} : (i32, i32) -> (i32)
|
||||
@ -215,7 +215,7 @@ func.func @symbolBinding(%arg0: i32) -> i32 {
|
||||
// An op with one use is matched.
|
||||
// CHECK: %0 = "test.symbol_binding_b"(%arg0)
|
||||
// CHECK: %1 = "test.symbol_binding_c"(%0)
|
||||
// CHECK: %2 = "test.symbol_binding_d"(%0, %1) <{attr = 42 : i64}>
|
||||
// CHECK: %2 = "test.symbol_binding_d"(%0, %1) {attr = 42 : i64}
|
||||
%0 = "test.symbol_binding_a"(%arg0) {attr = 42} : (i32) -> (i32)
|
||||
|
||||
// An op without any use is not matched.
|
||||
@ -239,21 +239,21 @@ func.func @symbolBindingNoResult(%arg0: i32) {
|
||||
|
||||
// CHECK-LABEL: succeedMatchOpAttr
|
||||
func.func @succeedMatchOpAttr() -> i32 {
|
||||
// CHECK: "test.match_op_attribute2"() <{default_valued_attr = 3 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}>
|
||||
// CHECK: "test.match_op_attribute2"() {default_valued_attr = 3 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}
|
||||
%0 = "test.match_op_attribute1"() {required_attr = 1: i32, optional_attr = 2: i32, default_valued_attr = 3: i32, more_attr = 4: i32} : () -> (i32)
|
||||
return %0: i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: succeedMatchMissingOptionalAttr
|
||||
func.func @succeedMatchMissingOptionalAttr() -> i32 {
|
||||
// CHECK: "test.match_op_attribute2"() <{default_valued_attr = 3 : i32, more_attr = 4 : i32, required_attr = 1 : i32}>
|
||||
// CHECK: "test.match_op_attribute2"() {default_valued_attr = 3 : i32, more_attr = 4 : i32, required_attr = 1 : i32}
|
||||
%0 = "test.match_op_attribute1"() {required_attr = 1: i32, default_valued_attr = 3: i32, more_attr = 4: i32} : () -> (i32)
|
||||
return %0: i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: succeedMatchMissingDefaultValuedAttr
|
||||
func.func @succeedMatchMissingDefaultValuedAttr() -> i32 {
|
||||
// CHECK: "test.match_op_attribute2"() <{default_valued_attr = 42 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}>
|
||||
// CHECK: "test.match_op_attribute2"() {default_valued_attr = 42 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}
|
||||
%0 = "test.match_op_attribute1"() {required_attr = 1: i32, optional_attr = 2: i32, more_attr = 4: i32} : () -> (i32)
|
||||
return %0: i32
|
||||
}
|
||||
@ -267,7 +267,7 @@ func.func @failedMatchAdditionalConstraintNotSatisfied() -> i32 {
|
||||
|
||||
// CHECK-LABEL: verifyConstantAttr
|
||||
func.func @verifyConstantAttr(%arg0 : i32) -> i32 {
|
||||
// CHECK: "test.op_b"(%arg0) <{attr = 17 : i32}> : (i32) -> i32 loc("a")
|
||||
// CHECK: "test.op_b"(%arg0) {attr = 17 : i32} : (i32) -> i32 loc("a")
|
||||
%0 = "test.op_c"(%arg0) : (i32) -> i32 loc("a")
|
||||
return %0 : i32
|
||||
}
|
||||
@ -275,12 +275,12 @@ func.func @verifyConstantAttr(%arg0 : i32) -> i32 {
|
||||
// CHECK-LABEL: verifyUnitAttr
|
||||
func.func @verifyUnitAttr() -> (i32, i32) {
|
||||
// Unit attribute present in the matched op is propagated as attr2.
|
||||
// CHECK: "test.match_op_attribute4"() <{attr1, attr2}> : () -> i32
|
||||
// CHECK: "test.match_op_attribute4"() {attr1, attr2} : () -> i32
|
||||
%0 = "test.match_op_attribute3"() {attr} : () -> i32
|
||||
|
||||
// Since the original op doesn't have the unit attribute, the new op
|
||||
// only has the constant-constructed unit attribute attr1.
|
||||
// CHECK: "test.match_op_attribute4"() <{attr1}> : () -> i32
|
||||
// CHECK: "test.match_op_attribute4"() {attr1} : () -> i32
|
||||
%1 = "test.match_op_attribute3"() : () -> i32
|
||||
return %0, %1 : i32, i32
|
||||
}
|
||||
@ -291,7 +291,7 @@ func.func @verifyUnitAttr() -> (i32, i32) {
|
||||
|
||||
// CHECK-LABEL: testConstOp
|
||||
func.func @testConstOp() -> (i32) {
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() {value = 1
|
||||
%0 = "test.constant"() {value = 1 : i32} : () -> i32
|
||||
|
||||
// CHECK-NEXT: return [[C0]]
|
||||
@ -300,7 +300,7 @@ func.func @testConstOp() -> (i32) {
|
||||
|
||||
// CHECK-LABEL: testConstOpUsed
|
||||
func.func @testConstOpUsed() -> (i32) {
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() {value = 1
|
||||
%0 = "test.constant"() {value = 1 : i32} : () -> i32
|
||||
|
||||
// CHECK-NEXT: [[V0:%.+]] = "test.op_s"([[C0]])
|
||||
@ -312,11 +312,11 @@ func.func @testConstOpUsed() -> (i32) {
|
||||
|
||||
// CHECK-LABEL: testConstOpReplaced
|
||||
func.func @testConstOpReplaced() -> (i32) {
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
|
||||
// CHECK-NEXT: [[C0:%.+]] = "test.constant"() {value = 1
|
||||
%0 = "test.constant"() {value = 1 : i32} : () -> i32
|
||||
%1 = "test.constant"() {value = 2 : i32} : () -> i32
|
||||
|
||||
// CHECK: [[V0:%.+]] = "test.op_s"([[C0]]) <{value = 2 : i32}
|
||||
// CHECK: [[V0:%.+]] = "test.op_s"([[C0]]) {value = 2 : i32}
|
||||
%2 = "test.op_r"(%0, %1) : (i32, i32) -> i32
|
||||
|
||||
// CHECK: [[V0]]
|
||||
@ -325,10 +325,10 @@ func.func @testConstOpReplaced() -> (i32) {
|
||||
|
||||
// CHECK-LABEL: testConstOpMatchFailure
|
||||
func.func @testConstOpMatchFailure() -> (i64) {
|
||||
// CHECK-DAG: [[C0:%.+]] = "test.constant"() <{value = 1
|
||||
// CHECK-DAG: [[C0:%.+]] = "test.constant"() {value = 1
|
||||
%0 = "test.constant"() {value = 1 : i64} : () -> i64
|
||||
|
||||
// CHECK-DAG: [[C1:%.+]] = "test.constant"() <{value = 2
|
||||
// CHECK-DAG: [[C1:%.+]] = "test.constant"() {value = 2
|
||||
%1 = "test.constant"() {value = 2 : i64} : () -> i64
|
||||
|
||||
// CHECK: [[V0:%.+]] = "test.op_r"([[C0]], [[C1]])
|
||||
@ -340,7 +340,7 @@ func.func @testConstOpMatchFailure() -> (i64) {
|
||||
|
||||
// CHECK-LABEL: testConstOpMatchNonConst
|
||||
func.func @testConstOpMatchNonConst(%arg0 : i32) -> (i32) {
|
||||
// CHECK-DAG: [[C0:%.+]] = "test.constant"() <{value = 1
|
||||
// CHECK-DAG: [[C0:%.+]] = "test.constant"() {value = 1
|
||||
%0 = "test.constant"() {value = 1 : i32} : () -> i32
|
||||
|
||||
// CHECK: [[V0:%.+]] = "test.op_r"([[C0]], %arg0)
|
||||
@ -358,14 +358,14 @@ func.func @testConstOpMatchNonConst(%arg0 : i32) -> (i32) {
|
||||
|
||||
// CHECK-LABEL: verifyI32EnumAttr
|
||||
func.func @verifyI32EnumAttr() -> i32 {
|
||||
// CHECK: "test.i32_enum_attr"() <{attr = 10 : i32}
|
||||
// CHECK: "test.i32_enum_attr"() {attr = 10 : i32}
|
||||
%0 = "test.i32_enum_attr"() {attr = 5: i32} : () -> i32
|
||||
return %0 : i32
|
||||
}
|
||||
|
||||
// CHECK-LABEL: verifyI64EnumAttr
|
||||
func.func @verifyI64EnumAttr() -> i32 {
|
||||
// CHECK: "test.i64_enum_attr"() <{attr = 10 : i64}
|
||||
// CHECK: "test.i64_enum_attr"() {attr = 10 : i64}
|
||||
%0 = "test.i64_enum_attr"() {attr = 5: i64} : () -> i32
|
||||
return %0 : i32
|
||||
}
|
||||
@ -522,7 +522,7 @@ func.func @generateVariadicOutputOpInNestedPattern() -> (i32) {
|
||||
// CHECK-LABEL: redundantTest
|
||||
func.func @redundantTest(%arg0: i32) -> i32 {
|
||||
%0 = "test.op_m"(%arg0) : (i32) -> i32
|
||||
// CHECK: "test.op_m"(%arg0) <{optional_attr = 314159265 : i32}> : (i32) -> i32
|
||||
// CHECK: "test.op_m"(%arg0) {optional_attr = 314159265 : i32} : (i32) -> i32
|
||||
return %0 : i32
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ func.func @testCreateFunctions(%arg0 : tensor<10xf32, !test.smpla>, %arg1 : tens
|
||||
// -----
|
||||
|
||||
func.func @testReturnTypeOpInterface(%arg0 : tensor<10xf32>) {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{incompatible with return type}}
|
||||
%bad = "test.op_with_infer_type_if"(%arg0, %arg0) : (tensor<10xf32>, tensor<10xf32>) -> tensor<*xf32>
|
||||
return
|
||||
@ -33,7 +32,6 @@ func.func @testReturnTypeOpInterface(%arg0 : tensor<10xf32>) {
|
||||
// -----
|
||||
|
||||
func.func @testReturnTypeOpInterfaceMismatch(%arg0 : tensor<10xf32>, %arg1 : tensor<20xf32>) {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{operand type mismatch}}
|
||||
%bad = "test.op_with_infer_type_if"(%arg0, %arg1) : (tensor<10xf32>, tensor<20xf32>) -> tensor<*xf32>
|
||||
return
|
||||
@ -42,7 +40,6 @@ func.func @testReturnTypeOpInterfaceMismatch(%arg0 : tensor<10xf32>, %arg1 : ten
|
||||
// -----
|
||||
|
||||
func.func @testReturnTypeOpInterface(%arg0 : tensor<10xf32>) {
|
||||
// expected-error@+2 {{failed to infer returned types}}
|
||||
// expected-error@+1 {{required first operand and result to match}}
|
||||
%bad = "test.op_with_refine_type_if"(%arg0, %arg0) : (tensor<10xf32>, tensor<10xf32>) -> tensor<*xf32>
|
||||
return
|
||||
|
@ -177,7 +177,6 @@ FormatToken FormatLexer::lexIdentifier(const char *tokStart) {
|
||||
StringSwitch<FormatToken::Kind>(str)
|
||||
.Case("attr-dict", FormatToken::kw_attr_dict)
|
||||
.Case("attr-dict-with-keyword", FormatToken::kw_attr_dict_w_keyword)
|
||||
.Case("prop-dict", FormatToken::kw_prop_dict)
|
||||
.Case("custom", FormatToken::kw_custom)
|
||||
.Case("functional-type", FormatToken::kw_functional_type)
|
||||
.Case("oilist", FormatToken::kw_oilist)
|
||||
|
@ -60,7 +60,6 @@ public:
|
||||
keyword_start,
|
||||
kw_attr_dict,
|
||||
kw_attr_dict_w_keyword,
|
||||
kw_prop_dict,
|
||||
kw_custom,
|
||||
kw_functional_type,
|
||||
kw_oilist,
|
||||
@ -288,7 +287,6 @@ public:
|
||||
/// These are the kinds of directives.
|
||||
enum Kind {
|
||||
AttrDict,
|
||||
PropDict,
|
||||
Custom,
|
||||
FunctionalType,
|
||||
OIList,
|
||||
|
@ -37,6 +37,5 @@ OpClass::OpClass(StringRef name, StringRef extraClassDeclaration,
|
||||
void OpClass::finalize() {
|
||||
Class::finalize();
|
||||
declare<VisibilityDeclaration>(Visibility::Public);
|
||||
declare<ExtraClassDeclaration>(extraClassDeclaration.str(),
|
||||
extraClassDefinition);
|
||||
declare<ExtraClassDeclaration>(extraClassDeclaration, extraClassDefinition);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -132,14 +132,6 @@ private:
|
||||
bool withKeyword;
|
||||
};
|
||||
|
||||
/// This class represents the `prop-dict` directive. This directive represents
|
||||
/// the properties of the operation, expressed as a directionary.
|
||||
class PropDictDirective
|
||||
: public DirectiveElementBase<DirectiveElement::PropDict> {
|
||||
public:
|
||||
explicit PropDictDirective() = default;
|
||||
};
|
||||
|
||||
/// This class represents the `functional-type` directive. This directive takes
|
||||
/// two arguments and formats them, respectively, as the inputs and results of a
|
||||
/// FunctionType.
|
||||
@ -302,9 +294,8 @@ struct OperationFormat {
|
||||
};
|
||||
|
||||
OperationFormat(const Operator &op)
|
||||
: useProperties(op.getDialect().usePropertiesForAttributes() &&
|
||||
!op.getAttributes().empty()),
|
||||
opCppClassName(op.getCppClassName()) {
|
||||
|
||||
{
|
||||
operandTypes.resize(op.getNumOperands(), TypeResolution());
|
||||
resultTypes.resize(op.getNumResults(), TypeResolution());
|
||||
|
||||
@ -360,12 +351,6 @@ struct OperationFormat {
|
||||
/// A flag indicating if this operation has the SingleBlock trait.
|
||||
bool hasSingleBlockTrait;
|
||||
|
||||
/// Indicate whether attribute are stored in properties.
|
||||
bool useProperties;
|
||||
|
||||
/// The Operation class name
|
||||
StringRef opCppClassName;
|
||||
|
||||
/// A map of buildable types to indices.
|
||||
llvm::MapVector<StringRef, int, llvm::StringMap<int>> buildableTypes;
|
||||
|
||||
@ -404,7 +389,8 @@ static bool shouldFormatSymbolNameAttr(const NamedAttribute *attr) {
|
||||
/// {0}: The name of the attribute.
|
||||
/// {1}: The type for the attribute.
|
||||
const char *const attrParserCode = R"(
|
||||
if (parser.parseCustomAttributeWithFallback({0}Attr, {1})) {{
|
||||
if (parser.parseCustomAttributeWithFallback({0}Attr, {1}, "{0}",
|
||||
result.attributes)) {{
|
||||
return ::mlir::failure();
|
||||
}
|
||||
)";
|
||||
@ -414,29 +400,30 @@ const char *const attrParserCode = R"(
|
||||
/// {0}: The name of the attribute.
|
||||
/// {1}: The type for the attribute.
|
||||
const char *const genericAttrParserCode = R"(
|
||||
if (parser.parseAttribute({0}Attr, {1}))
|
||||
if (parser.parseAttribute({0}Attr, {1}, "{0}", result.attributes))
|
||||
return ::mlir::failure();
|
||||
)";
|
||||
|
||||
const char *const optionalAttrParserCode = R"(
|
||||
::mlir::OptionalParseResult parseResult{0}Attr =
|
||||
parser.parseOptionalAttribute({0}Attr, {1});
|
||||
if (parseResult{0}Attr.has_value() && failed(*parseResult{0}Attr))
|
||||
return ::mlir::failure();
|
||||
if (parseResult{0}Attr.has_value() && succeeded(*parseResult{0}Attr))
|
||||
{
|
||||
::mlir::OptionalParseResult parseResult =
|
||||
parser.parseOptionalAttribute({0}Attr, {1}, "{0}", result.attributes);
|
||||
if (parseResult.has_value() && failed(*parseResult))
|
||||
return ::mlir::failure();
|
||||
}
|
||||
)";
|
||||
|
||||
/// The code snippet used to generate a parser call for a symbol name attribute.
|
||||
///
|
||||
/// {0}: The name of the attribute.
|
||||
const char *const symbolNameAttrParserCode = R"(
|
||||
if (parser.parseSymbolName({0}Attr))
|
||||
if (parser.parseSymbolName({0}Attr, "{0}", result.attributes))
|
||||
return ::mlir::failure();
|
||||
)";
|
||||
const char *const optionalSymbolNameAttrParserCode = R"(
|
||||
// Parsing an optional symbol name doesn't fail, so no need to check the
|
||||
// result.
|
||||
(void)parser.parseOptionalSymbolName({0}Attr);
|
||||
(void)parser.parseOptionalSymbolName({0}Attr, "{0}", result.attributes);
|
||||
)";
|
||||
|
||||
/// The code snippet used to generate a parser call for an enum attribute.
|
||||
@ -447,7 +434,6 @@ const char *const optionalSymbolNameAttrParserCode = R"(
|
||||
/// {3}: The constant builder call to create an attribute of the enum type.
|
||||
/// {4}: The set of allowed enum keywords.
|
||||
/// {5}: The error message on failure when the enum isn't present.
|
||||
/// {6}: The attribute assignment expression
|
||||
const char *const enumAttrParserCode = R"(
|
||||
{
|
||||
::llvm::StringRef attrStr;
|
||||
@ -474,7 +460,7 @@ const char *const enumAttrParserCode = R"(
|
||||
<< "{0} attribute specification: \"" << attrStr << '"';;
|
||||
|
||||
{0}Attr = {3};
|
||||
{6}
|
||||
result.addAttribute("{0}", {0}Attr);
|
||||
}
|
||||
}
|
||||
)";
|
||||
@ -586,7 +572,6 @@ const char *const inferReturnTypesParserCode = R"(
|
||||
if (::mlir::failed({0}::inferReturnTypes(parser.getContext(),
|
||||
result.location, result.operands,
|
||||
result.attributes.getDictionary(parser.getContext()),
|
||||
result.getRawProperties(),
|
||||
result.regions, inferredReturnTypes)))
|
||||
return ::mlir::failure();
|
||||
result.addTypes(inferredReturnTypes);
|
||||
@ -945,9 +930,7 @@ static void genCustomParameterParser(FormatElement *param, MethodBody &body) {
|
||||
}
|
||||
|
||||
/// Generate the parser for a custom directive.
|
||||
static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body,
|
||||
bool useProperties,
|
||||
StringRef opCppClassName) {
|
||||
static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body) {
|
||||
body << " {\n";
|
||||
|
||||
// Preprocess the directive variables.
|
||||
@ -1020,15 +1003,9 @@ static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body,
|
||||
const NamedAttribute *var = attr->getVar();
|
||||
if (var->attr.isOptional() || var->attr.hasDefaultValue())
|
||||
body << llvm::formatv(" if ({0}Attr)\n ", var->name);
|
||||
if (useProperties) {
|
||||
body << formatv(
|
||||
" result.getOrAddProperties<{1}::Properties>().{0} = {0}Attr;\n",
|
||||
var->name, opCppClassName);
|
||||
} else {
|
||||
body << llvm::formatv(" result.addAttribute(\"{0}\", {0}Attr);\n",
|
||||
var->name);
|
||||
}
|
||||
|
||||
body << llvm::formatv(" result.addAttribute(\"{0}\", {0}Attr);\n",
|
||||
var->name);
|
||||
} else if (auto *operand = dyn_cast<OperandVariable>(param)) {
|
||||
const NamedTypeConstraint *var = operand->getVar();
|
||||
if (var->isOptional()) {
|
||||
@ -1064,8 +1041,7 @@ static void genCustomDirectiveParser(CustomDirective *dir, MethodBody &body,
|
||||
|
||||
/// Generate the parser for a enum attribute.
|
||||
static void genEnumAttrParser(const NamedAttribute *var, MethodBody &body,
|
||||
FmtContext &attrTypeCtx, bool parseAsOptional,
|
||||
bool useProperties, StringRef opCppClassName) {
|
||||
FmtContext &attrTypeCtx, bool parseAsOptional) {
|
||||
Attribute baseAttr = var->attr.getBaseAttr();
|
||||
const EnumAttr &enumAttr = cast<EnumAttr>(baseAttr);
|
||||
std::vector<EnumAttrCase> cases = enumAttr.getAllCases();
|
||||
@ -1100,68 +1076,46 @@ static void genEnumAttrParser(const NamedAttribute *var, MethodBody &body,
|
||||
});
|
||||
errorMessageOS << "]\");";
|
||||
}
|
||||
std::string attrAssignment;
|
||||
if (useProperties) {
|
||||
attrAssignment =
|
||||
formatv(" "
|
||||
"result.getOrAddProperties<{1}::Properties>().{0} = {0}Attr;",
|
||||
var->name, opCppClassName);
|
||||
} else {
|
||||
attrAssignment =
|
||||
formatv("result.addAttribute(\"{0}\", {0}Attr);", var->name);
|
||||
}
|
||||
|
||||
body << formatv(enumAttrParserCode, var->name, enumAttr.getCppNamespace(),
|
||||
enumAttr.getStringToSymbolFnName(), attrBuilderStr,
|
||||
validCaseKeywordsStr, errorMessage, attrAssignment);
|
||||
validCaseKeywordsStr, errorMessage);
|
||||
}
|
||||
|
||||
// Generate the parser for an attribute.
|
||||
static void genAttrParser(AttributeVariable *attr, MethodBody &body,
|
||||
FmtContext &attrTypeCtx, bool parseAsOptional,
|
||||
bool useProperties, StringRef opCppClassName) {
|
||||
FmtContext &attrTypeCtx, bool parseAsOptional) {
|
||||
const NamedAttribute *var = attr->getVar();
|
||||
|
||||
// Check to see if we can parse this as an enum attribute.
|
||||
if (canFormatEnumAttr(var))
|
||||
return genEnumAttrParser(var, body, attrTypeCtx, parseAsOptional,
|
||||
useProperties, opCppClassName);
|
||||
return genEnumAttrParser(var, body, attrTypeCtx, parseAsOptional);
|
||||
|
||||
// Check to see if we should parse this as a symbol name attribute.
|
||||
if (shouldFormatSymbolNameAttr(var)) {
|
||||
body << formatv(parseAsOptional ? optionalSymbolNameAttrParserCode
|
||||
: symbolNameAttrParserCode,
|
||||
var->name);
|
||||
} else {
|
||||
|
||||
// If this attribute has a buildable type, use that when parsing the
|
||||
// attribute.
|
||||
std::string attrTypeStr;
|
||||
if (std::optional<StringRef> typeBuilder = attr->getTypeBuilder()) {
|
||||
llvm::raw_string_ostream os(attrTypeStr);
|
||||
os << tgfmt(*typeBuilder, &attrTypeCtx);
|
||||
} else {
|
||||
attrTypeStr = "::mlir::Type{}";
|
||||
}
|
||||
if (parseAsOptional) {
|
||||
body << formatv(optionalAttrParserCode, var->name, attrTypeStr);
|
||||
} else {
|
||||
if (attr->shouldBeQualified() ||
|
||||
var->attr.getStorageType() == "::mlir::Attribute")
|
||||
body << formatv(genericAttrParserCode, var->name, attrTypeStr);
|
||||
else
|
||||
body << formatv(attrParserCode, var->name, attrTypeStr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (useProperties) {
|
||||
body << formatv(
|
||||
" if ({0}Attr) result.getOrAddProperties<{1}::Properties>().{0} = "
|
||||
"{0}Attr;\n",
|
||||
var->name, opCppClassName);
|
||||
|
||||
// If this attribute has a buildable type, use that when parsing the
|
||||
// attribute.
|
||||
std::string attrTypeStr;
|
||||
if (std::optional<StringRef> typeBuilder = attr->getTypeBuilder()) {
|
||||
llvm::raw_string_ostream os(attrTypeStr);
|
||||
os << tgfmt(*typeBuilder, &attrTypeCtx);
|
||||
} else {
|
||||
body << formatv(
|
||||
" if ({0}Attr) result.attributes.append(\"{0}\", {0}Attr);\n",
|
||||
var->name);
|
||||
attrTypeStr = "::mlir::Type{}";
|
||||
}
|
||||
if (parseAsOptional) {
|
||||
body << formatv(optionalAttrParserCode, var->name, attrTypeStr);
|
||||
} else {
|
||||
if (attr->shouldBeQualified() ||
|
||||
var->attr.getStorageType() == "::mlir::Attribute")
|
||||
body << formatv(genericAttrParserCode, var->name, attrTypeStr);
|
||||
else
|
||||
body << formatv(attrParserCode, var->name, attrTypeStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1216,15 +1170,8 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
|
||||
|
||||
if (!thenGroup == optional->isInverted()) {
|
||||
// Add the anchor unit attribute to the operation state.
|
||||
if (useProperties) {
|
||||
body << formatv(
|
||||
" result.getOrAddProperties<{1}::Properties>().{0} = "
|
||||
"parser.getBuilder().getUnitAttr();",
|
||||
anchorAttr->getVar()->name, opCppClassName);
|
||||
} else {
|
||||
body << " result.addAttribute(\"" << anchorAttr->getVar()->name
|
||||
<< "\", parser.getBuilder().getUnitAttr());\n";
|
||||
}
|
||||
body << " result.addAttribute(\"" << anchorAttr->getVar()->name
|
||||
<< "\", parser.getBuilder().getUnitAttr());\n";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1243,8 +1190,7 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
|
||||
// parsing of the rest of the elements.
|
||||
FormatElement *firstElement = thenElements.front();
|
||||
if (auto *attrVar = dyn_cast<AttributeVariable>(firstElement)) {
|
||||
genAttrParser(attrVar, body, attrTypeCtx, /*parseAsOptional=*/true,
|
||||
useProperties, opCppClassName);
|
||||
genAttrParser(attrVar, body, attrTypeCtx, /*parseAsOptional=*/true);
|
||||
body << " if (" << attrVar->getVar()->name << "Attr) {\n";
|
||||
} else if (auto *literal = dyn_cast<LiteralElement>(firstElement)) {
|
||||
body << " if (::mlir::succeeded(parser.parseOptional";
|
||||
@ -1302,15 +1248,8 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
|
||||
body << formatv(oilistParserCode, lelementName);
|
||||
if (AttributeVariable *unitAttrElem =
|
||||
oilist->getUnitAttrParsingElement(pelement)) {
|
||||
if (useProperties) {
|
||||
body << formatv(
|
||||
" result.getOrAddProperties<{1}::Properties>().{0} = "
|
||||
"parser.getBuilder().getUnitAttr();",
|
||||
unitAttrElem->getVar()->name, opCppClassName);
|
||||
} else {
|
||||
body << " result.addAttribute(\"" << unitAttrElem->getVar()->name
|
||||
<< "\", UnitAttr::get(parser.getContext()));\n";
|
||||
}
|
||||
body << " result.addAttribute(\"" << unitAttrElem->getVar()->name
|
||||
<< "\", UnitAttr::get(parser.getContext()));\n";
|
||||
} else {
|
||||
for (FormatElement *el : pelement)
|
||||
genElementParser(el, body, attrTypeCtx);
|
||||
@ -1336,8 +1275,7 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
|
||||
} else if (auto *attr = dyn_cast<AttributeVariable>(element)) {
|
||||
bool parseAsOptional =
|
||||
(genCtx == GenContext::Normal && attr->getVar()->attr.isOptional());
|
||||
genAttrParser(attr, body, attrTypeCtx, parseAsOptional, useProperties,
|
||||
opCppClassName);
|
||||
genAttrParser(attr, body, attrTypeCtx, parseAsOptional);
|
||||
|
||||
} else if (auto *operand = dyn_cast<OperandVariable>(element)) {
|
||||
ArgumentLengthKind lengthKind = getArgumentLengthKind(operand->getVar());
|
||||
@ -1373,27 +1311,13 @@ void OperationFormat::genElementParser(FormatElement *element, MethodBody &body,
|
||||
|
||||
/// Directives.
|
||||
} else if (auto *attrDict = dyn_cast<AttrDictDirective>(element)) {
|
||||
body.indent() << "{\n";
|
||||
body.indent() << "auto loc = parser.getCurrentLocation();(void)loc;\n"
|
||||
<< "if (parser.parseOptionalAttrDict"
|
||||
<< (attrDict->isWithKeyword() ? "WithKeyword" : "")
|
||||
<< "(result.attributes))\n"
|
||||
<< " return ::mlir::failure();\n";
|
||||
if (useProperties) {
|
||||
body << "if (failed(verifyInherentAttrs(result.name, result.attributes, "
|
||||
"[&]() {\n"
|
||||
<< " return parser.emitError(loc) << \"'\" << "
|
||||
"result.name.getStringRef() << \"' op \";\n"
|
||||
<< " })))\n"
|
||||
<< " return ::mlir::failure();\n";
|
||||
}
|
||||
body.unindent() << "}\n";
|
||||
body.unindent();
|
||||
} else if (auto *attrDict = dyn_cast<PropDictDirective>(element)) {
|
||||
body << " if (parseProperties(parser, result))\n"
|
||||
body << " if (parser.parseOptionalAttrDict"
|
||||
<< (attrDict->isWithKeyword() ? "WithKeyword" : "")
|
||||
<< "(result.attributes))\n"
|
||||
<< " return ::mlir::failure();\n";
|
||||
} else if (auto *customDir = dyn_cast<CustomDirective>(element)) {
|
||||
genCustomDirectiveParser(customDir, body, useProperties, opCppClassName);
|
||||
genCustomDirectiveParser(customDir, body);
|
||||
|
||||
} else if (isa<OperandsDirective>(element)) {
|
||||
body << " ::llvm::SMLoc allOperandLoc = parser.getCurrentLocation();\n"
|
||||
<< " if (parser.parseOperandList(allOperands))\n"
|
||||
@ -1647,16 +1571,8 @@ void OperationFormat::genParserVariadicSegmentResolution(Operator &op,
|
||||
MethodBody &body) {
|
||||
if (!allOperands) {
|
||||
if (op.getTrait("::mlir::OpTrait::AttrSizedOperandSegments")) {
|
||||
if (op.getDialect().usePropertiesForAttributes()) {
|
||||
body << formatv(" "
|
||||
"result.getOrAddProperties<{0}::Properties>().operand_"
|
||||
"segment_sizes = "
|
||||
"(parser.getBuilder().getDenseI32ArrayAttr({{",
|
||||
op.getCppClassName());
|
||||
} else {
|
||||
body << " result.addAttribute(\"operand_segment_sizes\", "
|
||||
<< "parser.getBuilder().getDenseI32ArrayAttr({";
|
||||
}
|
||||
body << " result.addAttribute(\"operand_segment_sizes\", "
|
||||
<< "parser.getBuilder().getDenseI32ArrayAttr({";
|
||||
auto interleaveFn = [&](const NamedTypeConstraint &operand) {
|
||||
// If the operand is variadic emit the parsed size.
|
||||
if (operand.isVariableLength())
|
||||
@ -1670,36 +1586,18 @@ void OperationFormat::genParserVariadicSegmentResolution(Operator &op,
|
||||
for (const NamedTypeConstraint &operand : op.getOperands()) {
|
||||
if (!operand.isVariadicOfVariadic())
|
||||
continue;
|
||||
if (op.getDialect().usePropertiesForAttributes()) {
|
||||
body << llvm::formatv(
|
||||
" result.getOrAddProperties<{0}::Properties>().{1} = "
|
||||
"parser.getBuilder().getDenseI32ArrayAttr({2}OperandGroupSizes);\n",
|
||||
op.getCppClassName(),
|
||||
operand.constraint.getVariadicOfVariadicSegmentSizeAttr(),
|
||||
operand.name);
|
||||
} else {
|
||||
body << llvm::formatv(
|
||||
" result.addAttribute(\"{0}\", "
|
||||
"parser.getBuilder().getDenseI32ArrayAttr({1}OperandGroupSizes));"
|
||||
"\n",
|
||||
operand.constraint.getVariadicOfVariadicSegmentSizeAttr(),
|
||||
operand.name);
|
||||
}
|
||||
body << llvm::formatv(
|
||||
" result.addAttribute(\"{0}\", "
|
||||
"parser.getBuilder().getDenseI32ArrayAttr({1}OperandGroupSizes));\n",
|
||||
operand.constraint.getVariadicOfVariadicSegmentSizeAttr(),
|
||||
operand.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!allResultTypes &&
|
||||
op.getTrait("::mlir::OpTrait::AttrSizedResultSegments")) {
|
||||
if (op.getDialect().usePropertiesForAttributes()) {
|
||||
body << formatv(
|
||||
" "
|
||||
"result.getOrAddProperties<{0}::Properties>().result_segment_sizes = "
|
||||
"(parser.getBuilder().getDenseI32ArrayAttr({{",
|
||||
op.getCppClassName());
|
||||
} else {
|
||||
body << " result.addAttribute(\"result_segment_sizes\", "
|
||||
<< "parser.getBuilder().getDenseI32ArrayAttr({";
|
||||
}
|
||||
body << " result.addAttribute(\"result_segment_sizes\", "
|
||||
<< "parser.getBuilder().getDenseI32ArrayAttr({";
|
||||
auto interleaveFn = [&](const NamedTypeConstraint &result) {
|
||||
// If the result is variadic emit the parsed size.
|
||||
if (result.isVariableLength())
|
||||
@ -1743,14 +1641,6 @@ const char *enumAttrBeginPrinterCode = R"(
|
||||
auto caseValueStr = {1}(caseValue);
|
||||
)";
|
||||
|
||||
/// Generate the printer for the 'prop-dict' directive.
|
||||
static void genPropDictPrinter(OperationFormat &fmt, Operator &op,
|
||||
MethodBody &body) {
|
||||
body << " _odsPrinter << \" \";\n"
|
||||
<< " printProperties(this->getContext(), _odsPrinter, "
|
||||
"getProperties());\n";
|
||||
}
|
||||
|
||||
/// Generate the printer for the 'attr-dict' directive.
|
||||
static void genAttrDictPrinter(OperationFormat &fmt, Operator &op,
|
||||
MethodBody &body, bool withKeyword) {
|
||||
@ -2008,7 +1898,7 @@ static void genOptionalGroupPrinterAnchor(FormatElement *anchor,
|
||||
})
|
||||
.Case<AttributeVariable>([&](AttributeVariable *element) {
|
||||
Attribute attr = element->getVar()->attr;
|
||||
body << op.getGetterName(element->getVar()->name) << "Attr()";
|
||||
body << "(*this)->getAttr(\"" << element->getVar()->name << "\")";
|
||||
if (attr.isOptional())
|
||||
return; // done
|
||||
if (attr.hasDefaultValue()) {
|
||||
@ -2016,8 +1906,7 @@ static void genOptionalGroupPrinterAnchor(FormatElement *anchor,
|
||||
// default value.
|
||||
FmtContext fctx;
|
||||
fctx.withBuilder("::mlir::OpBuilder((*this)->getContext())");
|
||||
body << " && " << op.getGetterName(element->getVar()->name)
|
||||
<< "Attr() != "
|
||||
body << " != "
|
||||
<< tgfmt(attr.getConstBuilderTemplate(), &fctx,
|
||||
attr.getDefaultValue());
|
||||
return;
|
||||
@ -2174,13 +2063,6 @@ void OperationFormat::genElementPrinter(FormatElement *element,
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit the attribute dictionary.
|
||||
if (auto *propDict = dyn_cast<PropDictDirective>(element)) {
|
||||
genPropDictPrinter(*this, op, body);
|
||||
lastWasPunctuation = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// Optionally insert a space before the next element. The AttrDict printer
|
||||
// already adds a space as necessary.
|
||||
if (shouldEmitSpace || !lastWasPunctuation)
|
||||
@ -2418,7 +2300,6 @@ private:
|
||||
ConstArgument findSeenArg(StringRef name);
|
||||
|
||||
/// Parse the various different directives.
|
||||
FailureOr<FormatElement *> parsePropDictDirective(SMLoc loc, Context context);
|
||||
FailureOr<FormatElement *> parseAttrDictDirective(SMLoc loc, Context context,
|
||||
bool withKeyword);
|
||||
FailureOr<FormatElement *> parseFunctionalTypeDirective(SMLoc loc,
|
||||
@ -2448,7 +2329,6 @@ private:
|
||||
// The following are various bits of format state used for verification
|
||||
// during parsing.
|
||||
bool hasAttrDict = false;
|
||||
bool hasPropDict = false;
|
||||
bool hasAllRegions = false, hasAllSuccessors = false;
|
||||
bool canInferResultTypes = false;
|
||||
llvm::SmallBitVector seenOperandTypes, seenResultTypes;
|
||||
@ -2993,8 +2873,6 @@ FailureOr<FormatElement *>
|
||||
OpFormatParser::parseDirectiveImpl(SMLoc loc, FormatToken::Kind kind,
|
||||
Context ctx) {
|
||||
switch (kind) {
|
||||
case FormatToken::kw_prop_dict:
|
||||
return parsePropDictDirective(loc, ctx);
|
||||
case FormatToken::kw_attr_dict:
|
||||
return parseAttrDictDirective(loc, ctx,
|
||||
/*withKeyword=*/false);
|
||||
@ -3047,23 +2925,6 @@ OpFormatParser::parseAttrDictDirective(SMLoc loc, Context context,
|
||||
return create<AttrDictDirective>(withKeyword);
|
||||
}
|
||||
|
||||
FailureOr<FormatElement *>
|
||||
OpFormatParser::parsePropDictDirective(SMLoc loc, Context context) {
|
||||
if (context == TypeDirectiveContext)
|
||||
return emitError(loc, "'prop-dict' directive can only be used as a "
|
||||
"top-level directive");
|
||||
|
||||
if (context == RefDirectiveContext)
|
||||
llvm::report_fatal_error("'ref' of 'prop-dict' unsupported");
|
||||
// Otherwise, this is a top-level context.
|
||||
|
||||
if (hasPropDict)
|
||||
return emitError(loc, "'prop-dict' directive has already been seen");
|
||||
hasPropDict = true;
|
||||
|
||||
return create<PropDictDirective>();
|
||||
}
|
||||
|
||||
LogicalResult OpFormatParser::verifyCustomDirectiveArguments(
|
||||
SMLoc loc, ArrayRef<FormatElement *> arguments) {
|
||||
for (FormatElement *argument : arguments) {
|
||||
|
@ -25,7 +25,7 @@ static Operation *createOp(MLIRContext *context, Location loc,
|
||||
context->allowUnregisteredDialects();
|
||||
return Operation::create(loc, OperationName(operationName, context),
|
||||
std::nullopt, std::nullopt, std::nullopt,
|
||||
OpaqueProperties(nullptr), std::nullopt, numRegions);
|
||||
std::nullopt, numRegions);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -38,10 +38,10 @@ TEST(Adaptor, GenericAdaptorsOperandAccess) {
|
||||
// Using optional instead of plain int here to differentiate absence of
|
||||
// value from the value 0.
|
||||
SmallVector<std::optional<int>> v = {0, 4};
|
||||
OIListSimple::Properties prop;
|
||||
prop.operand_segment_sizes = builder.getDenseI32ArrayAttr({1, 0, 1});
|
||||
OIListSimple::GenericAdaptor<ArrayRef<std::optional<int>>> d(v, {}, prop,
|
||||
{});
|
||||
OIListSimple::GenericAdaptor<ArrayRef<std::optional<int>>> d(
|
||||
v, builder.getDictionaryAttr({builder.getNamedAttr(
|
||||
"operand_segment_sizes",
|
||||
builder.getDenseI32ArrayAttr({1, 0, 1}))}));
|
||||
EXPECT_EQ(d.getArg0(), 0);
|
||||
EXPECT_EQ(d.getArg1(), std::nullopt);
|
||||
EXPECT_EQ(d.getArg2(), 4);
|
||||
@ -51,10 +51,9 @@ TEST(Adaptor, GenericAdaptorsOperandAccess) {
|
||||
FormatVariadicOfVariadicOperand::FoldAdaptor e({});
|
||||
{
|
||||
SmallVector<int> v = {0, 1, 2, 3, 4};
|
||||
FormatVariadicOfVariadicOperand::Properties prop;
|
||||
prop.operand_segments = builder.getDenseI32ArrayAttr({3, 2, 0});
|
||||
FormatVariadicOfVariadicOperand::GenericAdaptor<ArrayRef<int>> f(v, {},
|
||||
prop, {});
|
||||
FormatVariadicOfVariadicOperand::GenericAdaptor<ArrayRef<int>> f(
|
||||
v, builder.getDictionaryAttr({builder.getNamedAttr(
|
||||
"operand_segments", builder.getDenseI32ArrayAttr({3, 2, 0}))}));
|
||||
SmallVector<ArrayRef<int>> operand = f.getOperand();
|
||||
ASSERT_EQ(operand.size(), (std::size_t)3);
|
||||
EXPECT_THAT(operand[0], ElementsAre(0, 1, 2));
|
||||
|
@ -9,7 +9,6 @@ add_mlir_unittest(MLIRIRTests
|
||||
PatternMatchTest.cpp
|
||||
ShapedTypeTest.cpp
|
||||
TypeTest.cpp
|
||||
OpPropertiesTest.cpp
|
||||
|
||||
DEPENDS
|
||||
MLIRTestInterfaceIncGen
|
||||
|
@ -1,358 +0,0 @@
|
||||
//===- TestOpProperties.cpp - Test all properties-related APIs ------------===//
|
||||
//
|
||||
// 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/OpDefinition.h"
|
||||
#include "mlir/Parser/Parser.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include <optional>
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
namespace {
|
||||
/// Simple structure definining a struct to define "properties" for a given
|
||||
/// operation. Default values are honored when creating an operation.
|
||||
struct TestProperties {
|
||||
int a = -1;
|
||||
float b = -1.;
|
||||
std::vector<int64_t> array = {-33};
|
||||
/// A shared_ptr to a const object is safe: it is equivalent to a value-based
|
||||
/// member. Here the label will be deallocated when the last operation
|
||||
/// referring to it is destroyed. However there is no pool-allocation: this is
|
||||
/// offloaded to the client.
|
||||
std::shared_ptr<const std::string> label;
|
||||
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestProperties)
|
||||
};
|
||||
|
||||
/// Convert a DictionaryAttr to a TestProperties struct, optionally emit errors
|
||||
/// through the provided diagnostic if any. This is used for example during
|
||||
/// parsing with the generic format.
|
||||
static LogicalResult
|
||||
setPropertiesFromAttribute(TestProperties &prop, Attribute attr,
|
||||
InFlightDiagnostic *diagnostic) {
|
||||
DictionaryAttr dict = dyn_cast<DictionaryAttr>(attr);
|
||||
if (!dict) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected DictionaryAttr to set TestProperties";
|
||||
return failure();
|
||||
}
|
||||
auto aAttr = dict.getAs<IntegerAttr>("a");
|
||||
if (!aAttr) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected IntegerAttr for key `a`";
|
||||
return failure();
|
||||
}
|
||||
auto bAttr = dict.getAs<FloatAttr>("b");
|
||||
if (!bAttr ||
|
||||
&bAttr.getValue().getSemantics() != &llvm::APFloatBase::IEEEsingle()) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected FloatAttr for key `b`";
|
||||
return failure();
|
||||
}
|
||||
|
||||
auto arrayAttr = dict.getAs<DenseI64ArrayAttr>("array");
|
||||
if (!arrayAttr) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected DenseI64ArrayAttr for key `array`";
|
||||
return failure();
|
||||
}
|
||||
|
||||
auto label = dict.getAs<mlir::StringAttr>("label");
|
||||
if (!label) {
|
||||
if (diagnostic)
|
||||
*diagnostic << "expected StringAttr for key `label`";
|
||||
return failure();
|
||||
}
|
||||
|
||||
prop.a = aAttr.getValue().getSExtValue();
|
||||
prop.b = bAttr.getValue().convertToFloat();
|
||||
prop.array.assign(arrayAttr.asArrayRef().begin(),
|
||||
arrayAttr.asArrayRef().end());
|
||||
prop.label = std::make_shared<std::string>(label.getValue());
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Convert a TestProperties struct to a DictionaryAttr, this is used for
|
||||
/// example during printing with the generic format.
|
||||
static Attribute getPropertiesAsAttribute(MLIRContext *ctx,
|
||||
const TestProperties &prop) {
|
||||
SmallVector<NamedAttribute> attrs;
|
||||
Builder b{ctx};
|
||||
attrs.push_back(b.getNamedAttr("a", b.getI32IntegerAttr(prop.a)));
|
||||
attrs.push_back(b.getNamedAttr("b", b.getF32FloatAttr(prop.b)));
|
||||
attrs.push_back(b.getNamedAttr("array", b.getDenseI64ArrayAttr(prop.array)));
|
||||
attrs.push_back(b.getNamedAttr(
|
||||
"label", b.getStringAttr(prop.label ? *prop.label : "<nullptr>")));
|
||||
return b.getDictionaryAttr(attrs);
|
||||
}
|
||||
|
||||
inline llvm::hash_code computeHash(const TestProperties &prop) {
|
||||
// We hash `b` which is a float using its underlying array of char:
|
||||
unsigned char const *p = reinterpret_cast<unsigned char const *>(&prop.b);
|
||||
ArrayRef<unsigned char> bBytes{p, sizeof(prop.b)};
|
||||
return llvm::hash_combine(
|
||||
prop.a, llvm::hash_combine_range(bBytes.begin(), bBytes.end()),
|
||||
llvm::hash_combine_range(prop.array.begin(), prop.array.end()),
|
||||
StringRef(*prop.label));
|
||||
}
|
||||
|
||||
/// A custom operation for the purpose of showcasing how to use "properties".
|
||||
class OpWithProperties : public Op<OpWithProperties> {
|
||||
public:
|
||||
// Begin boilerplate
|
||||
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OpWithProperties)
|
||||
using Op::Op;
|
||||
static ArrayRef<StringRef> getAttributeNames() { return {}; }
|
||||
static StringRef getOperationName() {
|
||||
return "test_op_properties.op_with_properties";
|
||||
}
|
||||
// End boilerplate
|
||||
|
||||
// This alias is the only definition needed for enabling "properties" for this
|
||||
// operation.
|
||||
using Properties = TestProperties;
|
||||
static std::optional<mlir::Attribute> getInherentAttr(const Properties &prop,
|
||||
StringRef name) {
|
||||
return std::nullopt;
|
||||
}
|
||||
static void setInherentAttr(Properties &prop, StringRef name,
|
||||
mlir::Attribute value) {}
|
||||
static void populateInherentAttrs(const Properties &prop,
|
||||
NamedAttrList &attrs) {}
|
||||
static LogicalResult
|
||||
verifyInherentAttrs(OperationName opName, NamedAttrList &attrs,
|
||||
function_ref<InFlightDiagnostic()> getDiag) {
|
||||
return success();
|
||||
}
|
||||
};
|
||||
|
||||
// A trivial supporting dialect to register the above operation.
|
||||
class TestOpPropertiesDialect : public Dialect {
|
||||
public:
|
||||
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestOpPropertiesDialect)
|
||||
static constexpr StringLiteral getDialectNamespace() {
|
||||
return StringLiteral("test_op_properties");
|
||||
}
|
||||
explicit TestOpPropertiesDialect(MLIRContext *context)
|
||||
: Dialect(getDialectNamespace(), context,
|
||||
TypeID::get<TestOpPropertiesDialect>()) {
|
||||
addOperations<OpWithProperties>();
|
||||
}
|
||||
};
|
||||
|
||||
constexpr StringLiteral mlirSrc = R"mlir(
|
||||
"test_op_properties.op_with_properties"()
|
||||
<{a = -42 : i32,
|
||||
b = -4.200000e+01 : f32,
|
||||
array = array<i64: 40, 41>,
|
||||
label = "bar foo"}> : () -> ()
|
||||
)mlir";
|
||||
|
||||
TEST(OpPropertiesTest, Properties) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
ParserConfig config(&context);
|
||||
// Parse the operation with some properties.
|
||||
OwningOpRef<Operation *> op = parseSourceString(mlirSrc, config);
|
||||
ASSERT_TRUE(op.get() != nullptr);
|
||||
auto opWithProp = dyn_cast<OpWithProperties>(op.get());
|
||||
ASSERT_TRUE(opWithProp);
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
opWithProp.print(os);
|
||||
ASSERT_STREQ("\"test_op_properties.op_with_properties\"() "
|
||||
"<{a = -42 : i32, "
|
||||
"array = array<i64: 40, 41>, "
|
||||
"b = -4.200000e+01 : f32, "
|
||||
"label = \"bar foo\"}> : () -> ()\n",
|
||||
os.str().c_str());
|
||||
}
|
||||
// Get a mutable reference to the properties for this operation and modify it
|
||||
// in place one member at a time.
|
||||
TestProperties &prop = opWithProp.getProperties();
|
||||
prop.a = 42;
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
opWithProp.print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = 42"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = -4.200000e+01"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: 40, 41>"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("label = \"bar foo\""));
|
||||
}
|
||||
prop.b = 42.;
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
opWithProp.print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = 42"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = 4.200000e+01"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: 40, 41>"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("label = \"bar foo\""));
|
||||
}
|
||||
prop.array.push_back(42);
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
opWithProp.print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = 42"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = 4.200000e+01"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: 40, 41, 42>"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("label = \"bar foo\""));
|
||||
}
|
||||
prop.label = std::make_shared<std::string>("foo bar");
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
opWithProp.print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = 42"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = 4.200000e+01"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: 40, 41, 42>"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("label = \"foo bar\""));
|
||||
}
|
||||
}
|
||||
|
||||
// Test diagnostic emission when using invalid dictionary.
|
||||
TEST(OpPropertiesTest, FailedProperties) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
std::string diagnosticStr;
|
||||
context.getDiagEngine().registerHandler([&](Diagnostic &diag) {
|
||||
diagnosticStr += diag.str();
|
||||
return success();
|
||||
});
|
||||
|
||||
// Parse the operation with some properties.
|
||||
ParserConfig config(&context);
|
||||
|
||||
// Parse an operation with invalid (incomplete) properties.
|
||||
OwningOpRef<Operation *> owningOp =
|
||||
parseSourceString("\"test_op_properties.op_with_properties\"() "
|
||||
"<{a = -42 : i32}> : () -> ()\n",
|
||||
config);
|
||||
ASSERT_EQ(owningOp.get(), nullptr);
|
||||
EXPECT_STREQ(
|
||||
"invalid properties {a = -42 : i32} for op "
|
||||
"test_op_properties.op_with_properties: expected FloatAttr for key `b`",
|
||||
diagnosticStr.c_str());
|
||||
diagnosticStr.clear();
|
||||
|
||||
owningOp = parseSourceString(mlirSrc, config);
|
||||
Operation *op = owningOp.get();
|
||||
ASSERT_TRUE(op != nullptr);
|
||||
Location loc = op->getLoc();
|
||||
auto opWithProp = dyn_cast<OpWithProperties>(op);
|
||||
ASSERT_TRUE(opWithProp);
|
||||
|
||||
OperationState state(loc, op->getName());
|
||||
Builder b{&context};
|
||||
NamedAttrList attrs;
|
||||
attrs.push_back(b.getNamedAttr("a", b.getStringAttr("foo")));
|
||||
state.propertiesAttr = attrs.getDictionary(&context);
|
||||
{
|
||||
auto diag = op->emitError("setting properties failed: ");
|
||||
auto result = state.setProperties(op, &diag);
|
||||
EXPECT_TRUE(result.failed());
|
||||
}
|
||||
EXPECT_STREQ("setting properties failed: expected IntegerAttr for key `a`",
|
||||
diagnosticStr.c_str());
|
||||
}
|
||||
|
||||
TEST(OpPropertiesTest, DefaultValues) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
OperationState state(UnknownLoc::get(&context),
|
||||
"test_op_properties.op_with_properties");
|
||||
Operation *op = Operation::create(state);
|
||||
ASSERT_TRUE(op != nullptr);
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
op->print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = -1"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = -1"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: -33>"));
|
||||
}
|
||||
op->erase();
|
||||
}
|
||||
|
||||
TEST(OpPropertiesTest, Cloning) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
ParserConfig config(&context);
|
||||
// Parse the operation with some properties.
|
||||
OwningOpRef<Operation *> op = parseSourceString(mlirSrc, config);
|
||||
ASSERT_TRUE(op.get() != nullptr);
|
||||
auto opWithProp = dyn_cast<OpWithProperties>(op.get());
|
||||
ASSERT_TRUE(opWithProp);
|
||||
Operation *clone = opWithProp->clone();
|
||||
|
||||
// Check that op and its clone prints equally
|
||||
std::string opStr;
|
||||
std::string cloneStr;
|
||||
{
|
||||
llvm::raw_string_ostream os(opStr);
|
||||
op.get()->print(os);
|
||||
}
|
||||
{
|
||||
llvm::raw_string_ostream os(cloneStr);
|
||||
clone->print(os);
|
||||
}
|
||||
clone->erase();
|
||||
EXPECT_STREQ(opStr.c_str(), cloneStr.c_str());
|
||||
}
|
||||
|
||||
TEST(OpPropertiesTest, Equivalence) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
ParserConfig config(&context);
|
||||
// Parse the operation with some properties.
|
||||
OwningOpRef<Operation *> op = parseSourceString(mlirSrc, config);
|
||||
ASSERT_TRUE(op.get() != nullptr);
|
||||
auto opWithProp = dyn_cast<OpWithProperties>(op.get());
|
||||
ASSERT_TRUE(opWithProp);
|
||||
llvm::hash_code reference = OperationEquivalence::computeHash(opWithProp);
|
||||
TestProperties &prop = opWithProp.getProperties();
|
||||
prop.a = 42;
|
||||
EXPECT_NE(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
prop.a = -42;
|
||||
EXPECT_EQ(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
prop.b = 42.;
|
||||
EXPECT_NE(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
prop.b = -42.;
|
||||
EXPECT_EQ(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
prop.array.push_back(42);
|
||||
EXPECT_NE(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
prop.array.pop_back();
|
||||
EXPECT_EQ(reference, OperationEquivalence::computeHash(opWithProp));
|
||||
}
|
||||
|
||||
TEST(OpPropertiesTest, getOrAddProperties) {
|
||||
MLIRContext context;
|
||||
context.getOrLoadDialect<TestOpPropertiesDialect>();
|
||||
OperationState state(UnknownLoc::get(&context),
|
||||
"test_op_properties.op_with_properties");
|
||||
// Test `getOrAddProperties` API on OperationState.
|
||||
TestProperties &prop = state.getOrAddProperties<TestProperties>();
|
||||
prop.a = 1;
|
||||
prop.b = 2;
|
||||
prop.array = {3, 4, 5};
|
||||
Operation *op = Operation::create(state);
|
||||
ASSERT_TRUE(op != nullptr);
|
||||
{
|
||||
std::string output;
|
||||
llvm::raw_string_ostream os(output);
|
||||
op->print(os);
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("a = 1"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("b = 2"));
|
||||
EXPECT_TRUE(StringRef(os.str()).contains("array = array<i64: 3, 4, 5>"));
|
||||
}
|
||||
op->erase();
|
||||
}
|
||||
|
||||
} // namespace
|
@ -22,9 +22,9 @@ static Operation *createOp(MLIRContext *context,
|
||||
ArrayRef<Type> resultTypes = std::nullopt,
|
||||
unsigned int numRegions = 0) {
|
||||
context->allowUnregisteredDialects();
|
||||
return Operation::create(
|
||||
UnknownLoc::get(context), OperationName("foo.bar", context), resultTypes,
|
||||
operands, std::nullopt, nullptr, std::nullopt, numRegions);
|
||||
return Operation::create(UnknownLoc::get(context),
|
||||
OperationName("foo.bar", context), resultTypes,
|
||||
operands, std::nullopt, std::nullopt, numRegions);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -13,9 +13,9 @@ using namespace mlir;
|
||||
|
||||
static Operation *createOp(MLIRContext *context) {
|
||||
context->allowUnregisteredDialects();
|
||||
return Operation::create(
|
||||
UnknownLoc::get(context), OperationName("foo.bar", context), std::nullopt,
|
||||
std::nullopt, std::nullopt, /*properties=*/nullptr, std::nullopt, 0);
|
||||
return Operation::create(UnknownLoc::get(context),
|
||||
OperationName("foo.bar", context), std::nullopt,
|
||||
std::nullopt, std::nullopt, std::nullopt, 0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
Loading…
x
Reference in New Issue
Block a user