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

Reply via email to