-
Notifications
You must be signed in to change notification settings - Fork 251
Implement extension SPV_KHR_float_controls2 #3475
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
base: main
Are you sure you want to change the base?
Implement extension SPV_KHR_float_controls2 #3475
Conversation
We shouldn't, as you have quoted: "This rule implies that a function appearing in both call graphs of two distinct entry points may behave differently in each case.". Runtime should be able to pass fast math controls from a caller to a callee.
I'm a bit worried about bloating size of SPIR-V modules in this case. In general I'd suggest to align behaviour of the translator and SPIR-V backend in areas where it's possible. So I'd expect llvm-spirv's implementation resulting in the same SPIR-V as llvm/llvm-project#146941 aka there should be FPFastMathDefault set. |
|
I'll go on vacation in a few hours, and I'm afraid I will not have time to review this before I leave. Feel free to merge this without my approval, and I'll make sure I review when I'm back, even if it's a post-merge review. I did want to bring up a couple of related issues, though. Hopefully they can be resolved by this PR. |
Then the current implementation should be good, since it doesn't propagate anything.
I see. Then I should fix this implementation to always emit a |
I've addressed this in b691977 . This commit emits an |
|
This one is tricky. I've added a commit related to this, but I'll file a separate patch since this issue is not related to the |
cd6a10d to
57840f3
Compare
Fine with me. Most (if not all) of the folks working on the translator are currently on holidays (including myself), so guess review will be done a bit later :) (unless there is a super urgency - in this case I can take a look before New Year) |
No problem! It's not urgent. |
test/extensions/KHR/SPV_KHR_float_controls2/execution_mode_default.ll
Outdated
Show resolved
Hide resolved
14519f7 to
8fa049e
Compare
MrSidims
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
I'd like to hear from @maarquitos14 before merging.
|
Just in case, I'd like to bring the attention to one of my previous messages about the issue #3125 : Currently, this PR maps LLVM's In the issue it is suggested that we'd better translate Then, if we map LLVM's to SPIRV and back to LLVM we end up with different semantics: To avoid this, we could translate |
Thanks for bringing the attention back. I believe we should do one thing at a time and fix behaviour in unrelated to this PR patch. |
8fa049e to
dd4806c
Compare
I plan to look at this today/tomorrow. |
That works for me, thanks. Just highlighted it here to make sure it worked well with the current implementation. |
@jmmartinez ping me if you do create a separate patch for this. |
maarquitos14
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First pass. I'll do a second pass to check tests.
lib/SPIRV/SPIRVWriter.cpp
Outdated
|
|
||
| case spv::ExecutionModeSignedZeroInfNanPreserve: | ||
| // With SPV_KHR_float_controls2 this is deprecated | ||
| if (BM->hasCapability(CapabilityFloatControls2)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need to add FPFastMathDefault execution mode too? It is required to set the equivalent of SignedZeroInfNanPreserve, isn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, since the default fast-math flags are all disabled, both are preserved (ContractionOff/SignedZeroInfNanPreserve disable the contract/nsz ninf nnan flags).
I should add a comment explaining how these are preserved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, I see what you mean. However, I vaguely recall that having no flags isn't the same as having all flags set to zero from my implementation of this extension in the SPIRV BE. Let me try and find that again.
Also, a comment would help anyway :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If an operation is decorated with FPFastMathMode then the flags from that decoration apply. Otherwise, if the current entry point sets any FPFastMathDefault execution mode then all flags specified for any operand type or for the result type of the operation apply. If the operation is not decorated with FPFastMathMode and the entry point sets no FPFastMathDefault execution modes then the flags to be applied are determined by the client API and not by SPIR-V.
My understanding of this quote from the spec is that no decoration is not the same than decoration with all flags set to zero: all flags set to zero clearly specify the fast math mode, while no decoration means the client API can decide. Do you agree?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree.
Currently, if float_controls2 is available, we enable it always with all the flags set to zero. Then an LLVM floating-point operation with no flags has the same semantics in SPIRV.
However, I think there is a problem in my implementation: functions getting called by kernels.
Currently the FastMathModeDefault are not preserved when doing spirv->llvm-ir->spirv. When doing spirv->llvm-ir we set the FastMathModeDefault into the kernel operations, but we cannot do that on the called functions. Then, when doing llvm-ir->spirv we end up with the right flags on the kernel, but stricter flags (all set to 0 propagated through the new FastMathModeDefault) on the called function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a second contradicting thought. In fact, depending on how you see it, setting no flags in SPIRV can also be seen as enabling all rewrite flags in LLVM: contract / reassociate / ... are all permitted and is up to the client to decide if it optimizes it or not.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exactly, setting everything to zero might prevent possible client optimizations. I think we shouldn't do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated the PR. With f8ace92 we preserve the flags.
From SPIRV->LLVM we preserve the FastMathModeDefault in the !spirv.ExecutionMode metadata. Then when doing LLVM->SPIRV the metadata is lowered into the original FastMathModeDefault.
We set the default execution to 0 only when:
FastMathModeDefaultin!spirv.ExecutionModewas 0 to begin with- We're adding the
ContractionOffExecutionMode - We're adding the
SignedZeroInfNanPreserve
For these last 2, since these execution-modes are deprecated with FloatControls2, we have to translate them to something equivalent. We cannot unset some flags and leave others for the client API. For simplicity, I've chosen to set all the flags to 0.
This can be argued though.
In both cases, I've chosen to preserve the fast-math flags that are attached to the instructions. (Fadd with contract flags will still be translated to fadd contract even if ContracitonOff was set).
| entry: | ||
| ; IR-LABEL: define {{.*}} @foo | ||
| ; IR-NEXT: entry: | ||
| ; IR-NEXT: %rh = fadd contract half %ah, %bh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My understanding is that you don't check decorations in SPIRV because you assume that they have to be present in SPIRV if they are present in the reverse translation. Am I right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sort of. I wanted to check only that the ExecutionModeId was set correctly (the flags set on the instructions are verified in other tests). And reverse translated it to ensure the contract flag doesn't get overridden by it.
I can add the checks for the individual instructions if it make more sense.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As long as the intent is clearly specified in the test, I'm happy with that. Can you add a comment explaining this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added:
; By default, do not set the execution-mode when the extension is used.
; This test doesn't verify directly that the instructions have the SPIRV
; 'contract' flag (this is done in another test).
; As a sanity check, we still reverse-translate and check the IR.
test/extensions/KHR/SPV_KHR_float_controls2/execution_mode_id.spvasm
Outdated
Show resolved
Hide resolved
test/extensions/KHR/SPV_KHR_float_controls2/execution_mode_default.ll
Outdated
Show resolved
Hide resolved
test/extensions/KHR/SPV_KHR_float_controls2/extension_not_needed.ll
Outdated
Show resolved
Hide resolved
test/extensions/KHR/SPV_KHR_float_controls2/extension_not_needed_but_used.ll
Outdated
Show resolved
Hide resolved
2abce3e to
1108325
Compare
| // Get the scalar type to handle vector operands. And get the first operand | ||
| // type (instead of the result) due to fcmp instructions. | ||
| Type *FloatType = Inst->getOperand(0)->getType()->getScalarType(); | ||
| auto Func2FMF = FuncToFastMathFlags.find({Inst->getFunction(), FloatType}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm tempted to remove this FuncToFastMathFlags stuff.
It's used to set the FPFastMathFlags that are attached to the execution mode to the individual instructions of a kernel.
But since we're preserving the FPFastMathFlags in the metadata; I'm thinking that this is not needed anymore.
@maarquitos14 should I remove this ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe that this logic should be still placed somewhere as the middleend and backend are unlikely to know about this metadata out of the box and honestly it feels like for optimization passes it's easier to work with individual instruction flags. IMHO resolving ExecutionMode to FP flag right away in the SPIR-V consumer won't harm and actually make implementation lower-level drivers friendly.
MrSidims
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Functionally LGTM, but lets make tests passing :)
test/extensions/KHR/SPV_KHR_float_controls2/execution_mode_contract_off.ll
Outdated
Show resolved
Hide resolved
test/extensions/KHR/SPV_KHR_float_controls2/execution_mode_contract_off.ll
Outdated
Show resolved
Hide resolved
| ; SPIRV-ON-DAG: ExecutionModeId [[FOO]] 6028 [[HALF:[0-9]+]] [[ZERO:[0-9]+]] | ||
| ; SPIRV-ON-DAG: ExecutionModeId [[FOO]] 6028 [[FLOAT:[0-9]+]] [[ZERO]] | ||
| ; SPIRV-ON-DAG: ExecutionModeId [[FOO]] 6028 [[DOUBLE:[0-9]+]] [[ZERO]] | ||
| ; SPIRV-ON-DAG: TypeFloat [[HALF]] 16 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test is currently failing, not 100% why. May be we should move this line before checks of ExecutionModeId to ensure correct REGEX variables definition:
; SPIRV-ON-DAG: TypeFloat [[#HALF:]] 16
...
; SPIRV-ON-DAG: ExecutionModeId [[#FOO]] 6028 [[#HALF]] [[#ZERO]]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's weird. I haven't managed to reproduce the issue. But I think I know what the problem is: I'm scanning the TypeMap and there is no guarantee of the order of its elements. I'll fix this to always generate the same code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed in the last commit by sorting the floating-point types by bit-width and encoding.
My bad ! In my defense... It passed in my machine. There was one matrix test failing though (but also over main so I didn't look much into it). |
With this extension, the execution modes `ContractionOff and `SignedZeroInfNanPreserve` are deprecated and we should use `FPFastMathDefault` instead. Additionally, the `FPFastMathMode` mode `Fast` bit is also deprecated.
Before, the extension would be used only when an operation having fast-math flags that can only be represented using float_controls2 was enabled. Afer this patch, the extension is added if floating-point types are used in the module.
…tractionOff and SignedZeroInfNanPreserve to FPFastMathDefault 0
1108325 to
ebdcd76
Compare
9633e0d to
2c6901c
Compare
First attempt at implementing SPV_KHR_float_controls2.
Some highlights:
ExecutionModeFPFastMathDefaultfor every kernel, and if instructions in that kernel do not specify a particularFPFastMathMode, we use the kernel one (question below).afnflag. If we mapfadd fast float %a, %bto SPIRV and back, it becomesfadd reassoc nnan ninf nsz arcp contract float %a, %blosing theafnflag.Some questions:
FPFastMathMode? Should we propagate the attribute down to the callees?ExecutionModeFPFastMathDefaultwhen writing SPIRV. Instead it writes the appropriateFPFastMathModefor every instruction. In that case, should we emit a "zero"FPFastMathModefor instructions without any fast-math-flags ?