[llvm-branch-commits] [mlir] [mlir] Improve EnumProp, making it take an EnumInfo (PR #132349)
Krzysztof Drewniak via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Sun Mar 23 18:33:43 PDT 2025
https://github.com/krzysz00 updated https://github.com/llvm/llvm-project/pull/132349
>From b7e84740dbe3795a87deb0e7b7fe5d92d181f7b1 Mon Sep 17 00:00:00 2001
From: Krzysztof Drewniak <krzysdrewniak at gmail.com>
Date: Thu, 20 Mar 2025 23:08:31 -0700
Subject: [PATCH] [mlir] Improve EnumProp, making it take an EnumInfo
This commit improves the `EnumProp` class, causing it to wrap around
an `EnumInfo` just like` EnumAttr` does. This EnumProp also has logic
for converting to/from an integer attribute and for being read and
written as bitcode.
The following variants of `EnumProp` are provided:
- `EnumPropWithAttrForm` - an EnumProp that can be constructed
from (and will be converted to, if `storeInCustomAttribute` is true) a
custom attribute, like an `EnumAttr`, instead of a plain integer. This
is meant for backwards compatibility with code that uses enum
attributes.
`NamedEnumProp` adds a "`mnemonic` `<` $enum `>`" syntax around the
enum, replicating a common pattern seen in MLIR printers and
allowing for reduced ambiguity.
`NamedEnumPropWithAttrForm` combines both of these extensions.
(Sadly, bitcode auto-upgrade is hampered by the lack of the ability to optionally parse an attribute.)
---
mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td | 14 +-
mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 8 +-
mlir/include/mlir/IR/EnumAttr.td | 134 ++++++++++++++++++
mlir/include/mlir/IR/Properties.td | 19 ---
mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 64 ---------
mlir/test/IR/enum-attr-invalid.mlir | 75 ++++++++++
mlir/test/IR/enum-attr-roundtrip.mlir | 45 ++++++
mlir/test/lib/Dialect/Test/TestOps.td | 46 ++++++
8 files changed, 313 insertions(+), 92 deletions(-)
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
index a9de787806452..34a30a00790ea 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td
@@ -485,17 +485,16 @@ def DISubprogramFlags : I32BitEnumAttr<
// IntegerOverflowFlags
//===----------------------------------------------------------------------===//
-def IOFnone : I32BitEnumAttrCaseNone<"none">;
-def IOFnsw : I32BitEnumAttrCaseBit<"nsw", 0>;
-def IOFnuw : I32BitEnumAttrCaseBit<"nuw", 1>;
+def IOFnone : I32BitEnumCaseNone<"none">;
+def IOFnsw : I32BitEnumCaseBit<"nsw", 0>;
+def IOFnuw : I32BitEnumCaseBit<"nuw", 1>;
-def IntegerOverflowFlags : I32BitEnumAttr<
+def IntegerOverflowFlags : I32BitEnum<
"IntegerOverflowFlags",
"LLVM integer overflow flags",
[IOFnone, IOFnsw, IOFnuw]> {
let separator = ", ";
let cppNamespace = "::mlir::LLVM";
- let genSpecializedAttr = 0;
let printBitEnumPrimaryGroups = 1;
}
@@ -504,6 +503,11 @@ def LLVM_IntegerOverflowFlagsAttr :
let assemblyFormat = "`<` $value `>`";
}
+def LLVM_IntegerOverflowFlagsProp :
+ NamedEnumPropWithAttrForm<IntegerOverflowFlags, "overflow", LLVM_IntegerOverflowFlagsAttr> {
+ let defaultValue = enum.cppType # "::" # "none";
+}
+
//===----------------------------------------------------------------------===//
// FastmathFlags
//===----------------------------------------------------------------------===//
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 90cc851c0a3b2..75f23e5b46c5f 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -60,7 +60,7 @@ class LLVM_IntArithmeticOpWithOverflowFlag<string mnemonic, string instName,
list<Trait> traits = []> :
LLVM_ArithmeticOpBase<AnySignlessInteger, mnemonic, instName,
!listconcat([DeclareOpInterfaceMethods<IntegerOverflowFlagsInterface>], traits)> {
- dag iofArg = (ins EnumProp<"IntegerOverflowFlags", "", "IntegerOverflowFlags::none">:$overflowFlags);
+ dag iofArg = (ins LLVM_IntegerOverflowFlagsProp:$overflowFlags);
let arguments = !con(commonArgs, iofArg);
string mlirBuilder = [{
@@ -69,7 +69,7 @@ class LLVM_IntArithmeticOpWithOverflowFlag<string mnemonic, string instName,
$res = op;
}];
let assemblyFormat = [{
- $lhs `,` $rhs `` custom<OverflowFlags>($overflowFlags) attr-dict `:` type($res)
+ $lhs `,` $rhs ($overflowFlags^)? attr-dict `:` type($res)
}];
string llvmBuilder =
"$res = builder.Create" # instName #
@@ -563,10 +563,10 @@ class LLVM_CastOpWithOverflowFlag<string mnemonic, string instName, Type type,
Type resultType, list<Trait> traits = []> :
LLVM_Op<mnemonic, !listconcat([Pure], [DeclareOpInterfaceMethods<IntegerOverflowFlagsInterface>], traits)>,
LLVM_Builder<"$res = builder.Create" # instName # "($arg, $_resultType, /*Name=*/\"\", op.hasNoUnsignedWrap(), op.hasNoSignedWrap());"> {
- let arguments = (ins type:$arg, EnumProp<"IntegerOverflowFlags", "", "IntegerOverflowFlags::none">:$overflowFlags);
+ let arguments = (ins type:$arg, LLVM_IntegerOverflowFlagsProp:$overflowFlags);
let results = (outs resultType:$res);
let builders = [LLVM_OneResultOpBuilder];
- let assemblyFormat = "$arg `` custom<OverflowFlags>($overflowFlags) attr-dict `:` type($arg) `to` type($res)";
+ let assemblyFormat = "$arg ($overflowFlags^)? attr-dict `:` type($arg) `to` type($res)";
string llvmInstName = instName;
string mlirBuilder = [{
auto op = $_builder.create<$_qualCppClassName>(
diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td
index e5406546b1950..aedda1d952eb6 100644
--- a/mlir/include/mlir/IR/EnumAttr.td
+++ b/mlir/include/mlir/IR/EnumAttr.td
@@ -10,6 +10,7 @@
#define ENUMATTR_TD
include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/Properties.td"
//===----------------------------------------------------------------------===//
// Enum attribute kinds
@@ -551,6 +552,139 @@ class EnumAttr<Dialect dialect, EnumInfo enumInfo, string name = "",
let assemblyFormat = "$value";
}
+// A property wrapping by a C++ enum. This class will automatically create bytecode
+// serialization logic for the given enum, as well as arranging for parser and
+// printer calls.
+class EnumProp<EnumInfo enumInfo> : Property<enumInfo.cppType, enumInfo.summary> {
+ EnumInfo enum = enumInfo;
+
+ let description = enum.description;
+ let predicate = !if(
+ !isa<BitEnumBase>(enum),
+ CPred<"(static_cast<" # enum.underlyingType # ">($_self) & ~" # !cast<BitEnumBase>(enum).validBits # ") == 0">,
+ Or<!foreach(case, enum.enumerants, CPred<"$_self == " # enum.cppType # "::" # case.symbol>)>);
+
+ let convertFromAttribute = [{
+ auto intAttr = ::mlir::dyn_cast_if_present<::mlir::IntegerAttr>($_attr);
+ if (!intAttr) {
+ return $_diag() << "expected IntegerAttr storage for }] #
+ enum.cppType # [{";
+ }
+ $_storage = static_cast<}] # enum.cppType # [{>(intAttr.getValue().getZExtValue());
+ return ::mlir::success();
+ }];
+
+ let convertToAttribute = [{
+ return ::mlir::IntegerAttr::get(::mlir::IntegerType::get($_ctxt, }] # enum.bitwidth
+ # [{), static_cast<}] # enum.underlyingType #[{>($_storage));
+ }];
+
+ let writeToMlirBytecode = [{
+ $_writer.writeVarInt(static_cast<uint64_t>($_storage));
+ }];
+
+ let readFromMlirBytecode = [{
+ uint64_t rawValue;
+ if (::mlir::failed($_reader.readVarInt(rawValue)))
+ return ::mlir::failure();
+ $_storage = static_cast<}] # enum.cppType # [{>(rawValue);
+ }];
+
+ let optionalParser = [{
+ auto value = ::mlir::FieldParser<std::optional<}] # enum.cppType # [{>>::parse($_parser);
+ if (::mlir::failed(value))
+ return ::mlir::failure();
+ if (!(value->has_value()))
+ return std::nullopt;
+ $_storage = std::move(**value);
+ }];
+}
+
+// Enum property that can have been (or, if `storeInCustomAttribute` is true, will also
+// be stored as) an attribute, in addition to being stored as an integer attribute.
+class EnumPropWithAttrForm<EnumInfo enumInfo, Attr attributeForm>
+ : EnumProp<enumInfo> {
+ Attr attrForm = attributeForm;
+ bit storeInCustomAttribute = 0;
+
+ let convertFromAttribute = [{
+ auto customAttr = ::mlir::dyn_cast_if_present<}]
+ # attrForm.storageType # [{>($_attr);
+ if (customAttr) {
+ $_storage = customAttr.getValue();
+ return ::mlir::success();
+ }
+ auto intAttr = ::mlir::dyn_cast_if_present<::mlir::IntegerAttr>($_attr);
+ if (!intAttr) {
+ return $_diag() << "expected }] # attrForm.storageType
+ # [{ or IntegerAttr storage for }] # enum.cppType # [{";
+ }
+ $_storage = static_cast<}] # enum.cppType # [{>(intAttr.getValue().getZExtValue());
+ return ::mlir::success();
+ }];
+
+ let convertToAttribute = !if(storeInCustomAttribute, [{
+ return }] # attrForm.storageType # [{::get($_ctxt, $_storage);
+ }], [{
+ return ::mlir::IntegerAttr::get(::mlir::IntegerType::get($_ctxt, }] # enumInfo.bitwidth
+ # [{), static_cast<}] # enum.underlyingType #[{>($_storage));
+ }]);
+}
+
+class _namedEnumPropFields<string cppType, string mnemonic> {
+ code parser = [{
+ if ($_parser.parseKeyword("}] # mnemonic # [{")
+ || $_parser.parseLess()) {
+ return ::mlir::failure();
+ }
+ auto parseRes = ::mlir::FieldParser<}] # cppType # [{>::parse($_parser);
+ if (::mlir::failed(parseRes) ||
+ ::mlir::failed($_parser.parseGreater())) {
+ return ::mlir::failure();
+ }
+ $_storage = *parseRes;
+ }];
+
+ code optionalParser = [{
+ if ($_parser.parseOptionalKeyword("}] # mnemonic # [{")) {
+ return std::nullopt;
+ }
+ if ($_parser.parseLess()) {
+ return ::mlir::failure();
+ }
+ auto parseRes = ::mlir::FieldParser<}] # cppType # [{>::parse($_parser);
+ if (::mlir::failed(parseRes) ||
+ ::mlir::failed($_parser.parseGreater())) {
+ return ::mlir::failure();
+ }
+ $_storage = *parseRes;
+ }];
+
+ code printer = [{
+ $_printer << "}] # mnemonic # [{<" << $_storage << ">";
+ }];
+}
+
+// An EnumProp which, when printed, is surrounded by mnemonic<>.
+// For example, if the enum can be a, b, or c, and the mnemonic is foo,
+// the format of this property will be "foo<a>", "foo<b>", or "foo<c>".
+class NamedEnumProp<EnumInfo enumInfo, string name>
+ : EnumProp<enumInfo> {
+ string mnemonic = name;
+ let parser = _namedEnumPropFields<enum.cppType, mnemonic>.parser;
+ let optionalParser = _namedEnumPropFields<enum.cppType, mnemonic>.optionalParser;
+ let printer = _namedEnumPropFields<enum.cppType, mnemonic>.printer;
+}
+
+// A `NamedEnumProp` with an attribute form as in `EnumPropWithAttrForm`.
+class NamedEnumPropWithAttrForm<EnumInfo enumInfo, string name, Attr attributeForm>
+ : EnumPropWithAttrForm<enumInfo, attributeForm> {
+ string mnemonic = name;
+ let parser = _namedEnumPropFields<enum.cppType, mnemonic>.parser;
+ let optionalParser = _namedEnumPropFields<enum.cppType, mnemonic>.optionalParser;
+ let printer = _namedEnumPropFields<enumInfo.cppType, mnemonic>.printer;
+}
+
class _symbolToValue<EnumInfo enumInfo, string case> {
defvar cases =
!filter(iter, enumInfo.enumerants, !eq(iter.str, case));
diff --git a/mlir/include/mlir/IR/Properties.td b/mlir/include/mlir/IR/Properties.td
index 212b85876c8df..ef48d6e4f9d78 100644
--- a/mlir/include/mlir/IR/Properties.td
+++ b/mlir/include/mlir/IR/Properties.td
@@ -238,25 +238,6 @@ def I64Prop : IntProp<"int64_t">;
def I32Property : IntProp<"int32_t">, Deprecated<"moved to shorter name I32Prop">;
def I64Property : IntProp<"int64_t">, Deprecated<"moved to shorter name I64Prop">;
-class EnumProp<string storageTypeParam, string desc = "", string default = ""> :
- Property<storageTypeParam, desc> {
- // TODO: implement predicate for enum validity.
- let writeToMlirBytecode = [{
- $_writer.writeVarInt(static_cast<uint64_t>($_storage));
- }];
- let readFromMlirBytecode = [{
- uint64_t val;
- if (failed($_reader.readVarInt(val)))
- return ::mlir::failure();
- $_storage = static_cast<}] # storageTypeParam # [{>(val);
- }];
- let defaultValue = default;
-}
-
-class EnumProperty<string storageTypeParam, string desc = "", string default = ""> :
- EnumProp<storageTypeParam, desc, default>,
- Deprecated<"moved to shorter name EnumProp">;
-
// Note: only a class so we can deprecate the old name
class _cls_StringProp : Property<"std::string", "string"> {
let interfaceType = "::llvm::StringRef";
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 5370de501a85c..2c28eba198d91 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -49,70 +49,6 @@ using mlir::LLVM::tailcallkind::getMaxEnumValForTailCallKind;
#include "mlir/Dialect/LLVMIR/LLVMOpsDialect.cpp.inc"
-//===----------------------------------------------------------------------===//
-// Property Helpers
-//===----------------------------------------------------------------------===//
-
-//===----------------------------------------------------------------------===//
-// IntegerOverflowFlags
-
-namespace mlir {
-static Attribute convertToAttribute(MLIRContext *ctx,
- IntegerOverflowFlags flags) {
- return IntegerOverflowFlagsAttr::get(ctx, flags);
-}
-
-static LogicalResult
-convertFromAttribute(IntegerOverflowFlags &flags, Attribute attr,
- function_ref<InFlightDiagnostic()> emitError) {
- auto flagsAttr = dyn_cast<IntegerOverflowFlagsAttr>(attr);
- if (!flagsAttr) {
- return emitError() << "expected 'overflowFlags' attribute to be an "
- "IntegerOverflowFlagsAttr, but got "
- << attr;
- }
- flags = flagsAttr.getValue();
- return success();
-}
-} // namespace mlir
-
-static ParseResult parseOverflowFlags(AsmParser &p,
- IntegerOverflowFlags &flags) {
- if (failed(p.parseOptionalKeyword("overflow"))) {
- flags = IntegerOverflowFlags::none;
- return success();
- }
- if (p.parseLess())
- return failure();
- do {
- StringRef kw;
- SMLoc loc = p.getCurrentLocation();
- if (p.parseKeyword(&kw))
- return failure();
- std::optional<IntegerOverflowFlags> flag =
- symbolizeIntegerOverflowFlags(kw);
- if (!flag)
- return p.emitError(loc,
- "invalid overflow flag: expected nsw, nuw, or none");
- flags = flags | *flag;
- } while (succeeded(p.parseOptionalComma()));
- return p.parseGreater();
-}
-
-static void printOverflowFlags(AsmPrinter &p, Operation *op,
- IntegerOverflowFlags flags) {
- if (flags == IntegerOverflowFlags::none)
- return;
- p << " overflow<";
- SmallVector<StringRef, 2> strs;
- if (bitEnumContainsAny(flags, IntegerOverflowFlags::nsw))
- strs.push_back("nsw");
- if (bitEnumContainsAny(flags, IntegerOverflowFlags::nuw))
- strs.push_back("nuw");
- llvm::interleaveComma(strs, p);
- p << ">";
-}
-
//===----------------------------------------------------------------------===//
// Attribute Helpers
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/IR/enum-attr-invalid.mlir b/mlir/test/IR/enum-attr-invalid.mlir
index 923736f28dadb..2f240a56c9874 100644
--- a/mlir/test/IR/enum-attr-invalid.mlir
+++ b/mlir/test/IR/enum-attr-invalid.mlir
@@ -28,3 +28,78 @@ func.func @test_parse_invalid_attr() -> () {
// expected-error at +1 {{failed to parse TestEnumAttr parameter 'value'}}
test.op_with_enum 1 : index
}
+
+// -----
+
+func.func @test_non_keyword_prop_enum() -> () {
+ // expected-error at +2 {{expected keyword for a test enum}}
+ // expected-error at +1 {{invalid value for property value, expected a test enum}}
+ test.op_with_enum_prop 0
+ return
+}
+
+// -----
+
+func.func @test_wrong_keyword_prop_enum() -> () {
+ // expected-error at +2 {{expected one of [first, second, third] for a test enum, got: fourth}}
+ // expected-error at +1 {{invalid value for property value, expected a test enum}}
+ test.op_with_enum_prop fourth
+}
+
+// -----
+
+func.func @test_bad_integer() -> () {
+ // expected-error at +1 {{op property 'value' failed to satisfy constraint: a test enum}}
+ "test.op_with_enum_prop"() <{value = 4 : i32}> {} : () -> ()
+}
+
+// -----
+
+func.func @test_bit_enum_prop_not_keyword() -> () {
+ // expected-error at +2 {{expected keyword for a test bit enum}}
+ // expected-error at +1 {{invalid value for property value1, expected a test bit enum}}
+ test.op_with_bit_enum_prop 0
+ return
+}
+
+// -----
+
+func.func @test_bit_enum_prop_wrong_keyword() -> () {
+ // expected-error at +2 {{expected one of [read, write, execute] for a test bit enum, got: chroot}}
+ // expected-error at +1 {{invalid value for property value1, expected a test bit enum}}
+ test.op_with_bit_enum_prop read, chroot : ()
+ return
+}
+
+// -----
+
+func.func @test_bit_enum_prop_bad_value() -> () {
+ // expected-error at +1 {{op property 'value2' failed to satisfy constraint: a test bit enum}}
+ "test.op_with_bit_enum_prop"() <{value1 = 7 : i32, value2 = 8 : i32}> {} : () -> ()
+ return
+}
+
+// -----
+
+func.func @test_bit_enum_prop_named_wrong_keyword() -> () {
+ // expected-error at +2 {{expected 'bit_enum'}}
+ // expected-error at +1 {{invalid value for property value1, expected a test bit enum}}
+ test.op_with_bit_enum_prop_named foo<read, execute>
+ return
+}
+
+// -----
+
+func.func @test_bit_enum_prop_named_not_open() -> () {
+ // expected-error at +2 {{expected '<'}}
+ // expected-error at +1 {{invalid value for property value1, expected a test bit enum}}
+ test.op_with_bit_enum_prop_named bit_enum read, execute>
+}
+
+// -----
+
+func.func @test_bit_enum_prop_named_not_closed() -> () {
+ // expected-error at +2 {{expected '>'}}
+ // expected-error at +1 {{invalid value for property value1, expected a test bit enum}}
+ test.op_with_bit_enum_prop_named bit_enum<read, execute +
+}
diff --git a/mlir/test/IR/enum-attr-roundtrip.mlir b/mlir/test/IR/enum-attr-roundtrip.mlir
index 36e605bdbff4d..f1f09f977b7d9 100644
--- a/mlir/test/IR/enum-attr-roundtrip.mlir
+++ b/mlir/test/IR/enum-attr-roundtrip.mlir
@@ -35,3 +35,48 @@ func.func @test_match_op_with_bit_enum() -> () {
test.op_with_bit_enum <execute, write> tag 0 : i32
return
}
+
+// CHECK-LABEL: @test_enum_prop
+func.func @test_enum_prop() -> () {
+ // CHECK: test.op_with_enum_prop first
+ test.op_with_enum_prop first
+
+ // CHECK: test.op_with_enum_prop first
+ "test.op_with_enum_prop"() <{value = 0 : i32}> {} : () -> ()
+
+ // CHECK: test.op_with_enum_prop_attr_form <{value = 0 : i32}>
+ test.op_with_enum_prop_attr_form <{value = 0 : i32}>
+ // CHECK: test.op_with_enum_prop_attr_form <{value = 1 : i32}>
+ test.op_with_enum_prop_attr_form <{value = #test<enum second>}>
+
+ // CHECK: test.op_with_enum_prop_attr_form_always <{value = #test<enum first>}>
+ test.op_with_enum_prop_attr_form_always <{value = #test<enum first>}>
+ // CHECK: test.op_with_enum_prop_attr_form_always <{value = #test<enum second>}
+ test.op_with_enum_prop_attr_form_always <{value = #test<enum second>}>
+
+ return
+}
+
+// CHECK-LABEL @test_bit_enum_prop()
+func.func @test_bit_enum_prop() -> () {
+ // CHECK: test.op_with_bit_enum_prop read : ()
+ test.op_with_bit_enum_prop read read : ()
+
+ // CHECK: test.op_with_bit_enum_prop read, write write, execute
+ test.op_with_bit_enum_prop read, write write, execute : ()
+
+ // CHECK: test.op_with_bit_enum_prop read, execute write
+ "test.op_with_bit_enum_prop"() <{value1 = 5 : i32, value2 = 2 : i32}> {} : () -> ()
+
+ // CHECK: test.op_with_bit_enum_prop read, write, execute
+ test.op_with_bit_enum_prop read, write, execute : ()
+
+ // CHECK: test.op_with_bit_enum_prop_named bit_enum<read>{{$}}
+ test.op_with_bit_enum_prop_named bit_enum<read> bit_enum<read>
+ // CHECK: test.op_with_bit_enum_prop_named bit_enum<read, write> bit_enum<write, execute>
+ test.op_with_bit_enum_prop_named bit_enum<read, write> bit_enum<write, execute>
+ // CHECK: test.op_with_bit_enum_prop_named bit_enum<read, write, execute>
+ test.op_with_bit_enum_prop_named bit_enum<read, write, execute>
+
+ return
+}
diff --git a/mlir/test/lib/Dialect/Test/TestOps.td b/mlir/test/lib/Dialect/Test/TestOps.td
index 94c722038f1cc..f314720f7fab5 100644
--- a/mlir/test/lib/Dialect/Test/TestOps.td
+++ b/mlir/test/lib/Dialect/Test/TestOps.td
@@ -423,6 +423,52 @@ def : Pat<(OpWithEnum ConstantEnumCase<TestEnumAttr, "first">:$value,
(OpWithEnum ConstantEnumCase<TestEnumAttr, "second">,
ConstantAttr<I32Attr, "1">)>;
+//===----------------------------------------------------------------------===//
+// Test Enum Properties
+//===----------------------------------------------------------------------===//
+
+// Define the enum property.
+def TestEnumProp : EnumProp<TestEnum>;
+// Define an op that contains the enum property.
+def OpWithEnumProp : TEST_Op<"op_with_enum_prop"> {
+ let arguments = (ins TestEnumProp:$value);
+ let assemblyFormat = "$value attr-dict";
+}
+
+def TestEnumPropAttrForm : EnumPropWithAttrForm<TestEnum, TestEnumAttr>;
+def OpWithEnumPropAttrForm : TEST_Op<"op_with_enum_prop_attr_form"> {
+ let arguments = (ins TestEnumPropAttrForm:$value);
+ let assemblyFormat = "prop-dict attr-dict";
+}
+
+def TestEnumPropAttrFormAlways : EnumPropWithAttrForm<TestEnum, TestEnumAttr> {
+ let storeInCustomAttribute = 1;
+}
+def OpWithEnumPropAttrFormAlways : TEST_Op<"op_with_enum_prop_attr_form_always"> {
+ let arguments = (ins TestEnumPropAttrFormAlways:$value);
+ let assemblyFormat = "prop-dict attr-dict";
+}
+
+def TestBitEnumProp : EnumProp<TestBitEnum> {
+ let defaultValue = TestBitEnum.cppType # "::Read";
+}
+def OpWithTestBitEnum : TEST_Op<"op_with_bit_enum_prop"> {
+ let arguments = (ins
+ TestBitEnumProp:$value1,
+ TestBitEnumProp:$value2);
+ let assemblyFormat = "$value1 ($value2^)? attr-dict `:` `(``)`";
+}
+
+def TestBitEnumPropNamed : NamedEnumProp<TestBitEnum, "bit_enum"> {
+ let defaultValue = TestBitEnum.cppType # "::Read";
+}
+def OpWithBitEnumPropNamed : TEST_Op<"op_with_bit_enum_prop_named"> {
+ let arguments = (ins
+ TestBitEnumPropNamed:$value1,
+ TestBitEnumPropNamed:$value2);
+ let assemblyFormat = "$value1 ($value2^)? attr-dict";
+}
+
//===----------------------------------------------------------------------===//
// Test Bit Enum Attributes
//===----------------------------------------------------------------------===//
More information about the llvm-branch-commits
mailing list