| Issue |
182145
|
| Summary |
[SPIR-V] Incorrect PHI value propagation through switch fallthrough
|
| Labels |
new issue
|
| Assignees |
|
| Reporter |
bob80905
|
Consider this shader:
```
RWBuffer<int> value;
RWStructuredBuffer<uint> Out : register(u1);
[numthreads(4, 1, 1)]
void main(uint3 threadID : SV_DispatchThreadID) {
bool B1 = false;
switch (value[threadID.x]) {
case 0: // threads 0 and 1; result is number of active lanes (2)
Out[threadID.x + 4] = WaveActiveCountBits(true); // threads 0 and 1
case 2:
B1 = true; // set b1 to true for thread 3
break;
default:
Out[threadID.x + 4] = WaveActiveCountBits(false); // thread 2; expect 0
break;
}
// should be 3 because B1 set to true for threads 0,1, and 3.
uint Count = WaveActiveCountBits(B1);
Out[threadID.x] = Count;
}
```
built with -T cs_6_5, targeted to SPIR-V.
Currently, the resulting IR is this:
```
OpCapability Shader
OpCapability ImageBuffer
OpCapability Int8
OpCapability GroupNonUniformBallot
OpMemoryModel Logical GLSL450
OpEntryPoint GLCompute %50 "main" %46 %48 %47
OpExecutionMode %50 LocalSize 4 1 1
OpSource Unknown 0
OpName %50 "main"
OpName %51 ".str"
OpName %52 ".str.2"
OpName %46 "value"
OpName %18 "spirv.SignedImage"
OpName %47 "Out"
OpName %17 "spirv.VulkanBuffer"
OpName %48 "__spirv_BuiltInGlobalInvocationId"
OpName %1 "entry"
OpName %2 "unreachable"
OpName %3 "new.header"
OpName %4 "entry._Z4mainDv3_j.exit_crit_edge"
OpName %5 "sw.bb.i"
OpName %6 "sw.default.i"
OpName %7 "new.header.new.exit"
OpName %8 "_Z4mainDv3_j.exit.sink.split"
OpName %9 "_Z4mainDv3_j.exit"
OpDecorate %46 DescriptorSet 0
OpDecorate %46 Binding 0
OpDecorate %47 DescriptorSet 0
OpDecorate %47 Binding 1
OpDecorate %15 ArrayStride 4
OpMemberDecorate %16 0 Offset 0
OpDecorate %16 Block
OpDecorate %48 BuiltIn GlobalInvocationId
%10 = OpTypeVoid
%11 = OpTypeFunction %10
%12 = OpTypeInt 32 0
%13 = OpTypePointer StorageBuffer %12
%14 = OpTypeBool
%15 = OpTypeRuntimeArray %12
%16 = OpTypeStruct %15
%17 = OpTypePointer StorageBuffer %16
%18 = OpTypeImage %12 Buffer 2 0 0 2 R32i
%19 = OpTypeInt 8 0
%20 = OpConstant %12 4
%21 = OpTypeArray %19 %20
%22 = OpConstant %12 6
%23 = OpTypeArray %19 %22
%24 = OpTypePointer Function %21
%25 = OpTypePointer Function %23
%26 = OpConstant %12 0
%27 = OpTypeVector %12 4
%28 = OpConstant %12 3
%29 = OpTypePointer UniformConstant %18
%30 = OpTypeVector %12 3
%31 = OpTypePointer Input %30
%32 = OpConstantTrue %14
%33 = OpConstant %12 1
%34 = OpConstant %19 116
%35 = OpConstant %19 79
%36 = OpConstant %19 0
%37 = OpConstant %19 101
%38 = OpConstant %19 117
%39 = OpConstant %19 108
%40 = OpConstant %19 97
%41 = OpConstant %19 118
%42 = OpUndef %12
%43 = OpUndef %14
%44 = OpConstantComposite %23 %41 %40 %39 %38 %37 %36
%45 = OpConstantComposite %21 %35 %38 %34 %36
%46 = OpVariable %29 UniformConstant
%47 = OpVariable %17 StorageBuffer
%48 = OpVariable %31 Input
%49 = OpConstantFalse %14
%50 = OpFunction %10 DontInline %11 ; -- Begin function main
%1 = OpLabel
%51 = OpVariable %25 Function %44
%52 = OpVariable %24 Function %45
%53 = OpCopyObject %17 %47
%54 = OpLoad %30 %48
%55 = OpCompositeExtract %12 %54 0
%56 = OpLoad %18 %46
%57 = OpImageRead %27 %56 %55 SignExtend
%58 = OpCompositeExtract %12 %57 0
OpSelectionMerge %9 None
OpBranchConditional %32 %3 %2
%2 = OpLabel
OpUnreachable
%3 = OpLabel
OpSelectionMerge %7 None
OpSwitch %58 %6 0 %5 2 %4
%4 = OpLabel
OpBranch %7
%5 = OpLabel
%59 = OpGroupNonUniformBallot %27 %28 %32
%60 = OpGroupNonUniformBallotBitCount %12 %28 Reduce %59
OpBranch %7
%6 = OpLabel
%61 = OpGroupNonUniformBallot %27 %28 %49
%62 = OpGroupNonUniformBallotBitCount %12 %28 Reduce %61
OpBranch %7
%7 = OpLabel
%63 = OpPhi %14 %49 %6 %32 %5 %43 %4
%64 = OpPhi %12 %62 %6 %60 %5 %42 %4
%65 = OpPhi %12 %33 %6 %33 %5 %26 %4
%66 = OpIEqual %14 %26 %65
OpBranchConditional %66 %9 %8
%8 = OpLabel
%67 = OpIAdd %12 %55 %20
%68 = OpAccessChain %13 %53 %26 %67
%69 = OpCopyObject %17 %47
OpStore %68 %64 Aligned 4
OpBranch %9
%9 = OpLabel
%70 = OpPhi %14 %32 %7 %63 %8
%71 = OpGroupNonUniformBallot %27 %28 %70
%72 = OpGroupNonUniformBallotBitCount %12 %28 Reduce %71
%73 = OpAccessChain %13 %53 %26 %55
%74 = OpCopyObject %17 %47
OpStore %73 %72 Aligned 4
OpReturn
OpFunctionEnd
; -- End function
```
Note the merge point after the switch statement, which is the assignment to %63. %63 is defined to have type %14, a bool type.
%63 represents B1 in the source.
Note that if the merge point is reached through block with label %4 representing `case 2:` (which is strange, that block with label %4 in the switch looks completely empty), then %43 is assigned to %63, and %43 is an undef bool type. This is bad.
The expected value to be assigned is `false`, since that is the default value of B1 before the switch executes.
For some reason, `undef` is the value propagated to phi for the `case 2:` case of the switch, which means for thread 3, B1 would be assigned undef.
So, across all lanes, at the end of the switch, the value of B1 would be [true, true, false, undef].
Some drivers treat this undef as true and others as false.
We should fix the value so that it is absolutely false.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs