Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SPV_INTEL_float_controls2 extension preview #1611

Open
wants to merge 6 commits into
base: sycl
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
265 changes: 265 additions & 0 deletions sycl/doc/extensions/SPIRV/SPV_INTEL_float_controls2.asciidoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
SPV_INTEL_float_controls2
=========================

Name Strings
------------

SPV_INTEL_float_controls2

Contact
-------

To report problems or to provide input on this extension, please open a new issue at:
https://github.com/intel/llvm/issues

Contributors
------------

- Gang Chen, Intel
- Mariusz Merecki, Intel
- Aleksander Us, Intel
- Konstantin Vladimirov, Intel
- Rudenko Nikita, Intel



Notice
------

Copyright (c) 2020 Intel Corporation. All rights reserved.

Status
------

Working Draft

This is a preview extension specification, intended to provide early access to a feature for review and community feedback. When the feature matures, this specification may be released as a formal extension.

Because the interfaces defined by this specification are not final and are subject to change they are not intended to be used by shipping software products. If you are interested in using this feature in your software product, please let us know!


Version
-------

[width="40%",cols="25,25"]
|========================================
| Last Modified Date | 2020-12-03
| Revision | 4
|========================================

Dependencies
------------

This extension is written against the SPIR-V Specification,
Version 1.5, Revision 3, Unified

This extension requires SPIR-V 1.0.

Overview
--------

This extension adds new execution modes and decorations to control floating-point computations.
This extension adds execution modes with round to positive infinity and round to negative infinity default rounding
and execution modes specifying compliance with floating-point arithmetic (IEEE 754) standard.
This extension adds new decorations that can be applied to a function to control floating-point computations inside the function.


Extension Name
--------------

To use this extension within a SPIR-V module, the following
*OpExtension* must be present in the module:

----
OpExtension "SPV_INTEL_float_controls2"
----

Modifications to the SPIR-V Specification, Version 1.5, Revision 3, Unified
---------------------------------------------------------------------------

Modify Section 2.16.1, Universal Validation Rules:

Modify the Entry Point rules:

Add *RoundingModeRTPINTEL* and *RoundingModeRTNINTEL* to the list of execution modes in the third rule.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: I'd consider describing what "the third rule" is here, since the universal validation rules appear to have been changed in the latest SPIR-V 1.6 spec and I'm having a hard time finding the older SPIR-V 1.5 revision 3 spec.

Copy link
Contributor Author

@mmerecki mmerecki Sep 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I will quote the rule:

Add RoundingModeRTPINTEL and RoundingModeRTNINTEL to the list of execution modes in the following validation rule:


Add the following rule:

- Each OpEntryPoint must not set more than one of the *FloatingPointModeALTINTEL* or *FloatingPointModeALTINTEL* execution modes for any given _Target Width_.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a typo here? FloatingPointModeALTINTEL is listed twice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, thank you


Modify the Decoration rules, add the following rules:

- If an *OpFunction* is decorated by more than one *FunctionRoundingModeINTEL* for any given _Target Width_ the _FP Rounding Mode_ operands must match.
- If an *OpFunction* is decorated by more than one *FunctionDenormModeINTEL* for any given _Target Width_ the _FP Denorm Mode_ operands must match.
- If an *OpFunction* is decorated by more than one *FunctionFloatingPointModeINTEL* for any given _Target Width_ the _FP Operation Mode_ operands must match.

Modify Section 3.6, Execution Mode:

Add the following rule to the description of *DenormPreserve* execution mode:

If an instruction is inside of a function decorated with *FunctionDenormModeINTEL* with matching _Target Width_ operand, the denorm mode specified by *FunctionDenormModeINTEL* is applied and *DenormPreserve* is ignored.

Add the following rule to the description of *DenormFlushToZero* execution mode:

If an instruction is inside of a function decorated with *FunctionDenormModeINTEL* with matching _Target Width_ operand, the denorm mode specified by *FunctionDenormModeINTEL* is applied and *DenormFlushToZero* is ignored.
Comment on lines +98 to +104
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's fine if we defer this to a client API environment spec, but so we're thinking about it: How should these execution modes and decorations interact with program build options like -cl-denorms-are-zero? Does the decoration or the build option "win"?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does -cl-denorms-are-zero build option cause that the corresponding DenormPreserve Execution Mode is present in the shader?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -cl-denorms-are-zero build option is be specified when compiling SPIR-V, not when generating SPIR-V, so I think we'd need to work out the interactions between the build option and the execution mode. I don't think this has been an issue before now because most of the compute consumers haven't moved to SPIR-V 1.4 (and hence don't need to worry about DenormPreserve), but it's something we'll need to figure out eventually.

Do we have a recommendation how this should work?


Add the following rule to the description of *RoundingModeRTE* execution mode:

If an instruction is not decorated with *FPRoundingMode* and does not define a rounding mode in its description and is inside of a function decorated
with *FunctionRoundingModeINTEL* with matching _Target Width_ operand, the rounding mode specified by *FunctionRoundingModeINTEL* is applied and *RoundingModeRTE* is ignored.

Add the following rule to the description of *RoundingModeRTZ* execution mode:

If an instruction is not decorated with *FPRoundingMode* and does not define a rounding mode in its description and is inside of a function decorated
with *FunctionRoundingModeINTEL* with matching _Target Width_ operand, the rounding mode specified by *FunctionRoundingModeINTEL* is applied and *RoundingModeRTZ* is ignored.

Add the following rows to the Execution Mode table:
--
[cols="1,20,10,10",options="header",width = "80%"]
|====
2+^| Execution Mode | Extra Operands | Enabling Capabilities
| 5620 | *RoundingModeRTPINTEL* +
The default rounding mode for floating-point arithmetic and conversions instructions must be round to positive infinity.
If an instruction is decorated with *FPRoundingMode* or defines a rounding mode in its description, that rounding mode is applied and *RoundingModeRTPINTEL* is ignored.
If an instruction is not decorated with *FPRoundingMode* and does not define a rounding mode in its description and is inside of a function decorated
with *FunctionRoundingModeINTEL* with matching _Target Width_ operand, the rounding mode specified by *FunctionRoundingModeINTEL* is applied and *RoundingModeRTPINTEL* is ignored. +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to define "matching Target Width" a little more precisely, especially for operations like OpFConvert where there is a source width and a destination width.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this sentence, "matching" was supposed to mean the same Target Width operands in the RoundingModeRTPINTEL execution mode and FunctionRoundingModeINTEL decoration.

Would the following text be better:

If an instruction is not decorated with FPRoundingMode and does not define a rounding mode in its description and is inside of a function decorated with FunctionRoundingModeINTEL whose Target Width operand is the same as RoundingModeRTPINTEL Target Width operand, the rounding mode specified by FunctionRoundingModeINTEL is applied and RoundingModeRTPINTEL is ignored.

Only affects arithmetic instructions operating on a floating-point type whose component width is Target Width and conversion instructions whose result type component width is Target Width.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I think my previous comment was unclear.

For OpFConvert there is the width of the source operand and the width of the result. Which one of these is checked to determine if the Target Width is matched?

This text kind of makes it seem like it is the source operand that gets checked (due to "operating on"):

Only affects instructions operating on a floating-point type whose component width is Target Width.

That might be a little surprising though, so I'd recommend being a little more precise and explicit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This text kind of makes it seem like it is the source operand that gets checked (due to "operating on"):

Only affects instructions operating on a floating-point type whose component width is Target Width.

That might be a little surprising though, so I'd recommend being a little more precise and explicit.

In my previous comment I proposed an updated text:

Only affects arithmetic instructions operating on a floating-point type whose component width is Target Width and conversion instructions whose result type component width is Target Width.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I think I missed this trying to parse the sentence about the rounding modes.

Do we need to differentiate between arithmetic and conversion instructions, or can we always look at the result type component width to determine if it matches the target width?

Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
| <<Literal, 'Literal'>> _Target Width_ | *RoundToInfinityINTEL*
| 5621 | *RoundingModeRTNINTEL* +
The default rounding mode for floating-point arithmetic and conversions instructions must be round to negative infinity. +
If an instruction is decorated with *FPRoundingMode* or defines a rounding mode in its description, that rounding mode is applied and *RoundingModeRTNINTEL* is ignored.
If an instruction is not decorated with *FPRoundingMode* and does not define a rounding mode in its description and is inside of a function decorated
with *FunctionRoundingModeINTEL* with matching _Target Width_ operand, the rounding mode specified by *FunctionRoundingModeINTEL* is applied and *RoundingModeRTNINTEL* is ignored. +
Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
| <<Literal, 'Literal'>> _Target Width_ | *RoundToInfinityINTEL*
| 5622 | *FloatingPointModeALTINTEL* +
The default floating-point operation mode for floating-point arithmetic and conversions instructions must be the Alternative Floating-Point Mode as specified by the client API.
If an instruction defines a floating-point operation mode in its description, that floating-point operation mode is applied and *FloatingPointModeALTINTEL* is ignored.
If an instruction does not define a floating-point operation mode in its description and is inside of a function decorated with *FunctionFloatControlINTEL* with matching _Target Width_ operand,
the floating-point operation mode specified by *FunctionFloatControlINTEL* is applied and *FloatingPointModeALTINTEL* is ignored. +
Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
| <<Literal, 'Literal'>> _Target Width_ | *FloatingPointModeINTEL*
| 5623 | *FloatingPointModeIEEEINTEL* +
bader marked this conversation as resolved.
Show resolved Hide resolved
The default floating-point operation mode for floating-point arithmetic and conversions instructions must be the IEEE 754 Mode as specified by the client API.
If an instruction defines a floating-point operation mode in its description, that floating-point operation mode is applied and *FloatingPointModeIEEEINTEL* is ignored.
If an instruction does not define a floating-point operation mode in its description and is inside of a function decorated with *FunctionFloatControlINTEL* with matching _Target Width_ operand,
the floating-point operation mode specified by *FunctionFloatControlINTEL* is applied and *FloatingPointModeIEEEINTEL* is ignored. +
Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
| <<Literal, 'Literal'>> _Target Width_ | *FloatingPointModeINTEL*
|====
--
Modify Section 3 Binary form, add new sub-sections after 3.16 FP Rounding Mode:
--
[[FP_Denorm_Mode]]*3.17. FP Denorm Mode*

Denormalized values handling mode.

[cols="^.^1,15,15",options="header",width = "50%"]
|====
2+^.^| FP Denorm Mode | Enabling Capabilities
| 0 | *Preserve* +
Denormalized values must be preserved. |
| 1 | *FlushToZero* +
Denormalized values must be flushed to zero. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirming: For the FlushToZero denorm mode denormalized values must be flushed to zero? Or is it possible that some implementations may still preserve denorms? I'm reminded of this text for the -cl-denorms-are-zero build option (link, emphasis mine):

This option controls how single precision and double precision denormalized numbers are handled. If specified as a build option, the single precision denormalized numbers may be flushed to zero; double precision denormalized numbers may also be flushed to zero if the optional extension for double precision is supported. This is intended to be a performance hint and the OpenCL compiler can choose not to flush denorms to zero if the device supports single precision (or double precision) denormalized numbers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already have corresponding execution modes whose description uses "is flushed to zero" or "is preserved". We could do the same here (instead of must ) and defer to Client API spec.
Note: Vulkan spec defines a list of instructions that must flush to zero or preserve. Other instructions may flush to zero or preserve.

|====
[[FP_Operation_Mode]]*3.18. FP Operation Mode*

Floating-point operation mode.

[cols="^.^1,15,15",options="header",width = "50%"]
|====
2+^.^| FP Operation Mode | Enabling Capabilities
| 0 | *IEEE* +
Floating-point operation mode is IEEE 754 Mode. |
| 1 | *ALT* +
Floating-point operation mode is Alternative Mode. |
|====
--

Modify Section 3.20, Decoration, add the following rows to the Decoration table:

--
[cols="1,20,5,5,10",options="header",width = "80%"]
|====
2+^| Decoration 2+| Extra Operands | Enabling Capabilities
| 5822 | *FunctionRoundingModeINTEL* +
Apply to a function to overwrite the default rounding mode for all floating-point arithmetic and conversion instructions inside the function.
bader marked this conversation as resolved.
Show resolved Hide resolved
If an instruction is decorated with *FPRoundingMode* or defines a rounding mode in its description, that rounding mode is applied and *FunctionRoundingModeINTEL* is ignored.
Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
|<<Literal, 'Literal'>> +
_Target Width_|<<FP_Rounding_Mode, 'FP Rounding Mode'>> +
_FP Rounding Mode_| *FunctionFloatControlINTEL*
| 5823 | *FunctionDenormModeINTEL* +
Apply to a function to overwrite the default mode of handling denormalized values for all floating-point arithmetic and conversion instructions inside the function.
If an instruction defines a mode of handling denormalized values in its description, that denorm mode is applied and *FunctionDenormModeINTEL* is ignored.

Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
|<<Literal, 'Literal'>> +
_Target Width_|<<FP_Denorm_Mode, 'FP Denorm Mode'>> +
_FP Denorm Mode_| *FunctionFloatControlINTEL*
| 6080 | *FunctionFloatingPointModeINTEL* +
Apply to a function to overwrite the default floating-point operation mode for all floating-point arithmetic and conversion instructions inside the function.
If an instruction defines a floating-point operation mode in its description, that floating-point operation mode is applied and *FunctionFloatControlINTEL* is ignored.
Only affects instructions operating on a floating-point type whose component width is _Target Width_.

_Target Width_ is an unsigned 32-bit integer.
|<<Literal, 'Literal'>> +
_Target Width_|<<FP_Operation_Mode, 'FP_Operation_Mode'>> +
_FP Operation Mode_| *FunctionFloatControlINTEL*
|====

Modify Section 3.31, Capability, add the following rows the 'Capability' table:
--
[cols="1,20,10",options="header",width = "80%"]
|====
2+^| Capability | Implicitly Declares
| 5582 | *RoundToInfinityINTEL* +
Module uses *RoundingModeRTNINTEL* or *RoundingModeRTPINTEL* execution modes.
|
| 5583 | *FloatingPointModeINTEL* +
Module uses *FloatingPointModeIEEEINTEL* or *FloatingPointModeALTINTEL* execution modes.
|
| 5821 | *FunctionFloatControlINTEL* +
Module uses *FunctionRoundingModeINTEL*, *FunctionDenormModeINTEL* or *FunctionFloatingPointModeINTEL* decorations.
|
|====
--

Issues
------

1) Isn't having the *FloatingPointModeIEEEINTEL* execution mode and *FunctionFloatingPointModeINTEL* decoration redundant?

Discussion: The intention is that the execution modes set the default rounding/denorm/floating-point modes for the entire entry point.
Decorations allow to overwrite the rounding/denorm/floating-point mode for all arithmetic and conversion instructions in a single function.
The same result could be achieved with decorations alone but would potentially require decorating each function in a module and/or duplication
of functions that have to be used in two entry points with different default rounding/denorm/floating-point mode.

Resolved: Keep both, the execution modes and corresponding function decorations.
--

Revision History
----------------

[cols="5,15,15,70"]
[grid="rows"]
[options="header"]
|========================================
|Rev|Date|Author|Changes
|1|2020-04-17|Mariusz Merecki|Initial revision
|2|2020-04-24|Mariusz Merecki|Assigned token numbers to *RoundToInfinityINTEL* and *FloatingPointModeINTEL*
|3|2020-08-03|Mariusz Merecki|Rebased to SPIR-V Version 1.5, Revision 3, Unified. Added *FunctionFloatControlINTEL* capability and *FunctionRoundingModeINTEL*, *FunctionDenormModeINTEL*, *FunctionFloatingPointModeINTEL* decorations
|4|2020-12-03|Mariusz Merecki|Described relation between execution modes and function scope and instruction scope decorations. Added validation rules.
|========================================