Index: mlir/test/IR/properties.mlir =================================================================== --- mlir/test/IR/properties.mlir +++ mlir/test/IR/properties.mlir @@ -24,3 +24,12 @@ // GENERIC: "test.using_property_in_custom"() // GENERIC-SAME: prop = array test.using_property_in_custom [1, 4, 20] + +// CHECK: test.using_property_ref_in_custom +// CHECK-SAME: 1 + 4 = 5 +// GENERIC: "test.using_property_ref_in_custom"() +// GENERIC-SAME: <{ +// GENERIC-SAME: first = 1 +// GENERIC-SAME: second = 4 +// GENERIC-SAME: }> +test.using_property_ref_in_custom 1 + 4 = 5 Index: mlir/test/lib/Dialect/Test/TestDialect.cpp =================================================================== --- mlir/test/lib/Dialect/Test/TestDialect.cpp +++ mlir/test/lib/Dialect/Test/TestDialect.cpp @@ -1945,6 +1945,34 @@ printer << '[' << value << ']'; } +static bool parseIntProperty(OpAsmParser &parser, int64_t &value) { + return failed(parser.parseInteger(value)); +} + +static void printIntProperty(OpAsmPrinter &printer, Operation *op, + int64_t value) { + printer << value; +} + +static bool parseSumProperty(OpAsmParser &parser, int64_t &second, + int64_t first) { + int64_t sum; + auto loc = parser.getCurrentLocation(); + if (parser.parseInteger(second) || parser.parseEqual() || + parser.parseInteger(sum)) + return true; + if (sum != second + first) { + parser.emitError(loc, "Expected sum to equal first + second"); + return true; + } + return false; +} + +static void printSumProperty(OpAsmPrinter &printer, Operation *op, + int64_t second, int64_t first) { + printer << second << " = " << (second + first); +} + #include "TestOpEnums.cpp.inc" #include "TestOpInterfaces.cpp.inc" #include "TestTypeInterfaces.cpp.inc" Index: mlir/test/lib/Dialect/Test/TestOps.td =================================================================== --- mlir/test/lib/Dialect/Test/TestOps.td +++ mlir/test/lib/Dialect/Test/TestOps.td @@ -3349,6 +3349,11 @@ let arguments = (ins ArrayProperty<"int64_t", 3>:$prop); } +def TestOpUsingPropertyRefInCustom : TEST_Op<"using_property_ref_in_custom"> { + let assemblyFormat = "custom($first) `+` custom($second, ref($first)) attr-dict"; + let arguments = (ins IntProperty<"int64_t">:$first, IntProperty<"int64_t">:$second); +} + // Op with a properties struct defined out-of-line. The struct has custom // printer/parser. Index: mlir/test/mlir-tblgen/op-format-invalid.td =================================================================== --- mlir/test/mlir-tblgen/op-format-invalid.td +++ mlir/test/mlir-tblgen/op-format-invalid.td @@ -483,6 +483,11 @@ custom($prop, $prop) attr-dict }]>, Arguments<(ins IntProperty<"int64_t">:$prop)>; +// CHECK: error: property 'prop' must be bound before it is referenced +def VariableInvalidP : TestFormat_Op<[{ + custom(ref($prop)) attr-dict +}]>, Arguments<(ins IntProperty<"int64_t">:$prop)>; + //===----------------------------------------------------------------------===// // Coverage Checks //===----------------------------------------------------------------------===// Index: mlir/tools/mlir-tblgen/OpFormatGen.cpp =================================================================== --- mlir/tools/mlir-tblgen/OpFormatGen.cpp +++ mlir/tools/mlir-tblgen/OpFormatGen.cpp @@ -2957,12 +2957,18 @@ } if (const NamedProperty *property = findArg(op.getProperties(), name)) { - if (ctx != CustomDirectiveContext) + if (ctx != CustomDirectiveContext && ctx != RefDirectiveContext) return emitError( loc, "properties currently only supported in `custom` directive"); - if (!seenProperties.insert(property).second) - return emitError(loc, "property '" + name + "' is already bound"); + if (ctx == RefDirectiveContext) { + if (!seenProperties.count(property)) + return emitError(loc, "property '" + name + + "' must be bound before it is referenced"); + } else { + if (!seenProperties.insert(property).second) + return emitError(loc, "property '" + name + "' is already bound"); + } return create(property); }