[RFC] Optional parameter tuples

Hi,

this is an RFC for optional, named parameter tuples for intrinsics. The proposed syntax is:

%z = call @llvm.some.intrinsic(%a, %b) optional_tuple(%x, %y, %z)

where from the perspective of the call site %x, %y and %z are simply additional parameters.

Optional parameter tuples would be very useful for constrained fp intrinsics and vector predication. Some examples:

Hey Simon,

It wasn’t clear from your RFC: why can’t you just have these optional parameter tuples be normal function arguments to the intrinsics?

Cheers,
-Neil.

Hi Neil,

we want to make the representation more concise.

One more thing i just realized is that we could use the tuple types to mask optimizations that do not expect them*.
Eg standard fp optimizations could claim that they handle `llvm.fadd` unless there are any parameter tuples on it.
Likewise, we can then implement a masked constrainedfp, SIMD fadd optimization pass that handles `llvm.fadd` with `fpenv` and/or `mask`.

*: (this comes on the heels of a second to-be-published RFC on generalizing the pattern match logic in LLVM...)

- Simon

Hi,

this is an RFC for optional, named parameter tuples for intrinsics. The proposed syntax is:

%z = call @llvm.some.intrinsic(%a, %b) optional_tuple(%x, %y, %z)

where from the perspective of the call site %x, %y and %z are simply additional parameters.

Optional parameter tuples would be very useful for constrained fp intrinsics and vector predication. Some examples:

; Default fpenv fadd (isomorphic to the fadd instruction)
%z = call double @llvm.fadd(%a, %b)

; Constrained fp add
%x = call double @llvm.fadd(%a, %b) fpenv(metadata !fpround.tonearest, metadata !fpexcept.strict)

; Constrained fp add with vector predication (https://reviews.llvm.org/D57504)
%x = call <256 x double> @llvm.fadd(%a, %b) mask(<256 x i1> %mask), evl(i32 %evl), fpenv(metadata !fpround.tozero, metadata !fpexcept.strict)

For constrained fp and VP, we only require a very restricted form of this. That is:

- Tuples are only allowed on intrinsic function calls.

- There is a builtin list of allowed tuple types (eg tablegen file).

- Tuple types are opt in: Intrinsics define a list of permissible tuple types.

- Tuple parameters have default values when a tuple is absent at a call site. Eg, for `fpenv` the default fp environment `fpenv(fpround.tonearest, fpexcept.ignore)` is implied in the first example above.

Btw, different to operand bundles, optional parameter tuples are much more restricted and do not imply side effects of any kind. We might want to re-use the OpBundle logic for this though.

I feel this would be the right way forward, especially since your "tuple names" are basically operand bundle tags.

You could express
   %z = call @llvm.some.intrinsic(%a, %b) optional_tuple(%x, %y, %z)
as
   %z = call @llvm.some.intrinsic(%a, %b) ["optional_tuple"(%x, %y, %z)]
or
   %x = call <256 x double> @llvm.fadd(%a, %b) mask(<256 x i1> %mask), evl(i32 %evl), fpenv(metadata !fpround.tozero, metadata !fpexcept.strict)
as
   %x = call <256 x double> @llvm.fadd(%a, %b) ["mask"(<256 x i1> %mask), "evl"(i32 %evl), "fpenv"(metadata !fpround.tozero, metadata !fpexcept.strict)]

Operand bundles tags can come with special semantics so we can teach
parts to not "assume the worst" for such uses. I say this also because
we are already heading that way for `llvm.assume`:
  https://reviews.llvm.org/D74209

Cheers,
  Johannes

+1 for operand bundles, I think they are what you are looking for.

Hi Simon,

For constrained fp and VP, we only require a very restricted form of this. That is:

- Tuples are only allowed on intrinsic function calls.

- There is a builtin list of allowed tuple types (eg tablegen file).

- Tuple types are opt in: Intrinsics define a list of permissible tuple types.

- Tuple parameters have default values when a tuple is absent at a call site. Eg, for `fpenv` the default fp environment `fpenv(fpround.tonearest, fpexcept.ignore)` is implied in the first example above.

This seems a pretty interesting idea. It's something we could consider
long-term for the AMDGPU image.sample intrinsics. Image sample
intrinsics have fairly complex "address" parameters, consisting of a
"body" (s,t,r coordinates, depending on the image dimensionality) and
optional extra parameters such as "lod bias", "z compare reference
variable", "texel offsets". Those optional extra parameters could be
an application of optional parameter tuples.

Have you given any thought to how this would be presented in
MachineIR, especially through the GlobalISel path?

Cheers,
Nicolai

Hi Nicolai,

Coming back to this discussion..

Hi Simon,

For constrained fp and VP, we only require a very restricted form of this. That is:

- Tuples are only allowed on intrinsic function calls.

- There is a builtin list of allowed tuple types (eg tablegen file).

- Tuple types are opt in: Intrinsics define a list of permissible tuple types.

- Tuple parameters have default values when a tuple is absent at a call site. Eg, for `fpenv` the default fp environment `fpenv(fpround.tonearest, fpexcept.ignore)` is implied in the first example above.

This seems a pretty interesting idea. It's something we could consider
long-term for the AMDGPU image.sample intrinsics. Image sample
intrinsics have fairly complex "address" parameters, consisting of a
"body" (s,t,r coordinates, depending on the image dimensionality) and
optional extra parameters such as "lod bias", "z compare reference
variable", "texel offsets". Those optional extra parameters could be
an application of optional parameter tuples.

Have you given any thought to how this would be presented in
MachineIR, especially through the GlobalISel path?

To get things off the ground quickly, the optional parameters on
IR-level could be lowered to regular, explicit parameters (or SDNode
properties). So, omitting a tuple in IR would mean passing a default
parameter in ISel. This default parameter on isel level could be a
special \bottom token that implies that this parameter is not set.

- Simon

> Hi Simon,
>
>> For constrained fp and VP, we only require a very restricted form of this. That is:
>>
>> - Tuples are only allowed on intrinsic function calls.
>>
>> - There is a builtin list of allowed tuple types (eg tablegen file).
>>
>> - Tuple types are opt in: Intrinsics define a list of permissible tuple types.
>>
>> - Tuple parameters have default values when a tuple is absent at a call site. Eg, for `fpenv` the default fp environment `fpenv(fpround.tonearest, fpexcept.ignore)` is implied in the first example above.
> This seems a pretty interesting idea. It's something we could consider
> long-term for the AMDGPU image.sample intrinsics. Image sample
> intrinsics have fairly complex "address" parameters, consisting of a
> "body" (s,t,r coordinates, depending on the image dimensionality) and
> optional extra parameters such as "lod bias", "z compare reference
> variable", "texel offsets". Those optional extra parameters could be
> an application of optional parameter tuples.
>
> Have you given any thought to how this would be presented in
> MachineIR, especially through the GlobalISel path?

To get things off the ground quickly, the optional parameters on
IR-level could be lowered to regular, explicit parameters (or SDNode
properties). So, omitting a tuple in IR would mean passing a default
parameter in ISel. This default parameter on isel level could be a
special \bottom token that implies that this parameter is not set.

Sure, that seems reasonable.

Cheers,
Nicolai