[PSA] New improved `fold` method signature has landed (please update your downstream projects)

Hello everyone!

The patches for the RFC “A better fold API using more generic adaptors” have now landed, which means the migration status has now started.

The first phase (starting now), remains fully source compatible for the time being, but using the old fold method signature is now considered deprecated and pending removal.

Summary of changes

When the new fold method signature is to be generated for a dialect (by setting the useFoldAPI field of a Dialect in TableGen to kEmitFoldAdaptorFolder), the fold method will now have the siganture:

OpFoldResult fold(FoldAdaptor adaptor);

for single result operations, and

LogicalResult fold(FoldAdaptor adaptor, SmallVectorImpl<OpFoldResult>& results);

for multi result operations.

FoldAdaptor is a new type alias within the Op class generated by TableGen, which is conceptually the same as Adaptor, except that instead of operating on ValueRange and Value, it operates on ArrayRef<Attribute> and Attribute. This is implemented through a generic adaptor class that can also be used with other range and value types.

How to upgrade

Updating has to be done on a per-dialect basis, as the generation of the fold API is a dialect option.
As a first step add let useFoldAPI = kEmitFoldAdaptorFolder; to your dialect in TableGen.
This will lead to Operations in the dialect emitting the new signatures in the header.

You’ll now have to update your cpp files. Simply replace the ArrayRef<Attribute> parameter within fold with just FoldAdaptor (no qualification required!).
For your convenience (and without warranty), you can also use the following sed command:

sed -r 's/::fold[(]((::)?(llvm|mlir)::)?ArrayRef<((::)?mlir::)?Attribute>\s*\w+/::fold(FoldAdaptor adaptor/g'

to automatically do this change for you.

The last step is simply adjusting any usage of what was previously ArrayRef. The Adaptor has the exact same getters as the Op and these should now be used to access single operands.

Example: Given an Op with (ins I32:$a, Variadic<I32>:$b, Optional<F64>:$c), you can use adaptor.getA() returning an Attribute, adaptor.getB() returning ArrayRef<Attribute> and adaptor.getC() returning Attribute to access each corresponding attribute for an operand.
Note that it is not possible to distinguish between the Optional c not being present and it not being a constant. If this is required, you can use the Op classes getC() to distinguish such cases.

If you have any functions or similar that still expect ArrayRef<Attribute> of ALL operands you may also fall back to the old style API using adaptor.getOperands(). This returns the underlying ArrayRef<Attributer> from the old fold method.

Future Changes

In-tree dialects are now in the process of being updated to the new API. Afterwards a patch may land, causing TableGen to warn on the use of the old API, warning about the deprecation, but not requiring immediate code changes.

The next PSA (likely in a month or two, depending on state of the ecosystem) will then announce that the default value for useFoldAPI will have switched to kEmitFoldAdaptorFolder. Users not yet switched will have the chance to still get the old signature by explicitly setting this value to kEmitRawAttributesFolder.

A last PSA will then anncounce the removal of the useFoldAPI option and the old ArrayRef<Attribute> signature entirely.