[RFC] Properties and attributes - where we can go from here

This post is a summary of discussions I had with @fabianmc and @mehdi_amini at the LLVM Developers’ Meeting and draws on previous ODMs on this topic.

At a high-level, the current system for non-attribute properties is a bit too incremental and a bit hard to intronspect. However, one realization is that both current attributes and current non-attribute properties are kinds of data you can have in your program / attach to an operation.

That is, we can re-root the Attribute hierarchy under a more general Property hierarchy by observing that:

  • An Attribute is a frozen property - it’s a pointer to some uniqued, immutable data that lives in the MLIR context
  • All the current *Props (the non-attribute properties) are inline properties - they’re mutable data that lives directly in an operation’s Properties struct
  • The Resources that got added a long time ago are also a kind of property: they’re (pointers to) a blob of data that lives outside the MLIR context

All of these types of property can be unified into one hierarchy. While for inline properties, we’d still store them directly as a C++ storage type, we could have a notion of a PropRef, which’d wrap a pointer to a property (frozen, inline, etc.) along with a reference to its registration in the MLIRContext (or a TypeID or so on - the details can be worked out). That is, we’d have a class that’s something like UniProp and you’d be able to dyn_cast<UnitProp> a PropRef, which’d get you, fundamentally, a bool*.

This does mean that properties would need to be registered (probably by dialects) on the MLIR context, but that’s just adding more tablegen. This also allows for generic parsing/printing of these things (since inline properties would get some sort of mnemonic name, most likely), simplifying FFI a bunch.

This could also, with some friction (needing to get an opaque reference) allow attaching interfaces to inline properties via the context.

One point that didn’t get fully discussed at the meeting but that I have had some thoughts about is parametrized properties / property factories. That is, we want to be able to take an inline property, (such as I64Prop or MyEnumProp) and make OptionalProp<I64Prop> or ArrayProp<MyEnumProp> (which have storage type std::optional<int64_t> and SmallVector<MyEnum>, respectively). You’d have some mechanism to say that, for example, OptionalProp takes one [inline] property parameter at that, say, FixedSizeArrayProp (which you’ll want for the std::arrays currently used for operand_segment_sizes takes an integer parameter (or maybe an int + an ilnile property) so that a dialect could ensure all the cases of OptionalProp etc. it needs are registered.

(Or you’d just do some magic with templates, and make OptionalProp<I64Prop> the thing that gets a registration and a type ID. I’m not sure exactly how to handle this one.)

1 Like