-
Notifications
You must be signed in to change notification settings - Fork 692
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
[SPIR-V] Don't lower switch statements to OpSwitch #6957
Comments
HLSL is not supposed to support fall-through. FXC produces errors if you try to fall through:
Allowing it presents problems with keeping control flow structured, which was why it was disallowed originally in HLSL. I'm of the opinion that we should disallow fall-through in DXC and HLSL on Clang. While we could consider this an HLSL 202x change, I consider it a bug that DXC allowed it in the first place, especially since using it could lead to undefined behavior or driver/runtime bugs. |
Given that we know users are relying on this feature working as implemented in DXC (they've filed bugs about it), and the fact that HLSL has no specification (yet). The language is defined by the behavior of the reference compiler, which today is DXC. HLSL 2016+ all currently support |
I agree with @llvm-beanz. Users have been using fallthroughs for so long that they will expect to be able to continue going forward. After some discussion, my team will not be fixing this in DXC. However, we would be willing to accept an fix. My suggested fix is to write a pass in spirv-opt that will transform all OpSwitch into code that is well defined. Trying to generate the correct code in DXC would be too cumbersome. The spirv-opt pass would have a couple tricky situations in order to avoid breaking structured control flow. Suppose you have something like:
The regular way of translating this would be:
This does not work for spir-v because the gotos violate structure control flow. Instead we would want something like:
This example shows most of the tricky situation:
I would do a few things to make it simpler:
|
The one tricky case your example above misses is the case of a conditional break. Something like: switch (Val) {
case 0:
Something();
if (OtherVal == Val)
break;
if (OtherVal % 2 == 0)
break;
case 1:
SomethingElse();
break;
} I think your transformation suggestion above can handle this case as well, by doing something like: uint case_id;
switch(Val) {
case 0:
case_id = 0;
break;
case 1:
case_id = 1;
break;
}
if (case_id == 0) {
bool fallthrough = true;
Something();
if (OtherVal == Val)
fallthrough = false;
if (!fallthrough) {
if (OtherVal % 2 == 0)
fallthrough = false;
}
if (fallthrough)
case_id = 1;
}
if (case_id == 1) {
SomethingElse();
} |
What you have would work too. But, I don't think we need the
I believe this is easier to generate. I don't know which is better for drivers. |
Description
OpSwitch
even as defined with SPV_KHR_maximal_reconvergence, doesn't require converging on switch cases that have fall through.The only way to get SPIR-V to implement switch statements that converge correctly is with
OpBranch
instead.Steps to Reproduce
Given the following HLSL:
CE
If given the input
[ 0, 0, 1, 2]
, the computed output should be[ 42, 42, 40, 40 ]
.Actual Behavior
Even with the KHR maximal reconvergence extension the
OpSwitch
is not guaranteed to converge the tangles between case 0 and the default case.However, if instead these were generated as a chain of
OpBranch
statements, the control flow would converge at each newOpBranch
, which would result in the correct tangle grouping.Environment
The text was updated successfully, but these errors were encountered: