llvm-project/mlir/lib/IR/ODSSupport.cpp
Krzysztof Drewniak 8955e285e1
[mlir] Add property combinators, initial ODS support (#94732)
While we have had a Properties.td that allowed for defining
non-attribute-backed properties, such properties were not plumbed
through the basic autogeneration facilities available to attributes,
forcing those who want to migrate to the new system to write such code
by hand.

## Potentially breaking changes

- The `setFoo()` methods on `Properties` struct no longer take their
inputs by const reference. Those wishing to pass non-owned values of a
property by reference to constructors and setters should set the
interface type to `const [storageType]&`
- Adapters and operations now define getters and setters for properties
listed in ODS, which may conflict with custom getters.
- Builders now include properties listed in ODS specifications,
potentially conflicting with custom builders with the same type
signature.

## Extensions to the `Property` class

This commit  adds several fields to the `Property` class, including:
- `parser`, `optionalParser`, and `printer` (for parsing/printing
properties of a given type in ODS syntax)
- `storageTypeValueOverride`, an extension of `defaultValue` to allow
the storage and interface type defaults to differ
- `baseProperty` (allowing for classes like `DefaultValuedProperty`)

Existing fields have also had their documentation comments updated.

This commit does not add a `PropertyConstraint` analogous to
`AttrConstraint`, but this is a natural evolution of the work here.

This commit also adds the concrete property kinds `I32Property`,
`I64Property`, `UnitProperty` (and special handling for it like for
UnitAttr), and `BoolProperty`.

## Property combinators

`Properties.td` also now includes several ways to combine properties.

One is `ArrayProperty<Property elem>`, which now stores a
variable-length array of some property as
`SmallVector<elem.storageType>` and uses `ArrayRef<elem.storageType>` as
its interface type. It has `IntArrayProperty` subclasses that change its
conversion to attributes to use `DenseI[N]Attr`s instead of an
`ArrayAttr`.

Similarly, `OptionalProperty<Property p>` wraps a property's storage in
`std::optional<>` and adds a `std::nullopt` default value. In the case
where the underlying property can be parsed optionally but doesn't have
its own default value, `OptionalProperty` can piggyback off the optional
parser to produce a cleaner syntax, as opposed to its general form,
which is either `none` or `some<[value]>`.

(Note that `OptionalProperty` can be nested if desired).

  ## Autogeneration changes

Operations and adaptors now support getters and setters for properties
like those for attributes. Unlike for attributes, there aren't separate
value and attribute forms, since there is no `FooAttr()` available for a
`getFooAttr()` to return.

The largest change is to operation formats. Previously, properties could
only be used in custom directives. Now, they can be used anywhere an
attribute could be used, and have parsers and printers defined in their
tablegen records.

These updates include special `UnitProperty` logic like that used for
`UnitAttr`.

## Misc.

Some attempt has been made to test the new functionality.

This commit takes tentative steps towards updating the documentation to
account for properties. A full update will be in order once any followup
work has been completed and the interfaces have stabilized.

---------

Co-authored-by: Mehdi Amini <joker.eph@gmail.com>
Co-authored-by: Christian Ulmann <christianulmann@gmail.com>
2024-07-26 09:35:06 -05:00

142 lines
5.4 KiB
C++

//===- 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, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
auto valueAttr = dyn_cast<IntegerAttr>(attr);
if (!valueAttr) {
emitError() << "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(int32_t &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
auto valueAttr = dyn_cast<IntegerAttr>(attr);
if (!valueAttr) {
emitError() << "expected IntegerAttr for key `value`";
return failure();
}
storage = valueAttr.getValue().getSExtValue();
return success();
}
Attribute mlir::convertToAttribute(MLIRContext *ctx, int32_t storage) {
return IntegerAttr::get(IntegerType::get(ctx, 32), storage);
}
LogicalResult
mlir::convertFromAttribute(std::string &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
auto valueAttr = dyn_cast<StringAttr>(attr);
if (!valueAttr)
return emitError()
<< "expected string property to come from string attribute";
storage = valueAttr.getValue().str();
return success();
}
Attribute mlir::convertToAttribute(MLIRContext *ctx,
const std::string &storage) {
return StringAttr::get(ctx, storage);
}
LogicalResult
mlir::convertFromAttribute(bool &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
auto valueAttr = dyn_cast<BoolAttr>(attr);
if (!valueAttr)
return emitError()
<< "expected string property to come from string attribute";
storage = valueAttr.getValue();
return success();
}
Attribute mlir::convertToAttribute(MLIRContext *ctx, bool storage) {
return BoolAttr::get(ctx, storage);
}
template <typename DenseArrayTy, typename T>
LogicalResult
convertDenseArrayFromAttr(MutableArrayRef<T> storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError,
StringRef denseArrayTyStr) {
auto valueAttr = dyn_cast<DenseArrayTy>(attr);
if (!valueAttr) {
emitError() << "expected " << denseArrayTyStr << " for key `value`";
return failure();
}
if (valueAttr.size() != static_cast<int64_t>(storage.size())) {
emitError() << "size mismatch in attribute conversion: " << valueAttr.size()
<< " vs " << storage.size();
return failure();
}
llvm::copy(valueAttr.asArrayRef(), storage.begin());
return success();
}
LogicalResult
mlir::convertFromAttribute(MutableArrayRef<int64_t> storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
return convertDenseArrayFromAttr<DenseI64ArrayAttr>(storage, attr, emitError,
"DenseI64ArrayAttr");
}
LogicalResult
mlir::convertFromAttribute(MutableArrayRef<int32_t> storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
return convertDenseArrayFromAttr<DenseI32ArrayAttr>(storage, attr, emitError,
"DenseI32ArrayAttr");
}
template <typename DenseArrayTy, typename T>
LogicalResult
convertDenseArrayFromAttr(SmallVectorImpl<T> &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError,
StringRef denseArrayTyStr) {
auto valueAttr = dyn_cast<DenseArrayTy>(attr);
if (!valueAttr) {
emitError() << "expected " << denseArrayTyStr << " for key `value`";
return failure();
}
storage.resize_for_overwrite(valueAttr.size());
llvm::copy(valueAttr.asArrayRef(), storage.begin());
return success();
}
LogicalResult
mlir::convertFromAttribute(SmallVectorImpl<int64_t> &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
return convertDenseArrayFromAttr<DenseI64ArrayAttr>(storage, attr, emitError,
"DenseI64ArrayAttr");
}
LogicalResult
mlir::convertFromAttribute(SmallVectorImpl<int32_t> &storage, Attribute attr,
function_ref<InFlightDiagnostic()> emitError) {
return convertDenseArrayFromAttr<DenseI32ArrayAttr>(storage, attr, emitError,
"DenseI32ArrayAttr");
}
Attribute mlir::convertToAttribute(MLIRContext *ctx,
ArrayRef<int64_t> storage) {
return DenseI64ArrayAttr::get(ctx, storage);
}