google / shaderc

A collection of tools, libraries, and tests for Vulkan shader compilation.
Other
1.85k stars 362 forks source link

conditional statement is not translated to SPIR-V correctly #665

Open amerigomasini opened 5 years ago

amerigomasini commented 5 years ago

The following glsl function:

void clip(vec4 x) 
{
    if (x.x < 0.0 || x.y < 0.0 || x.z < 0.0 || x.w < 0.0)
        discard;
}

Yields this SPIR-V code:

  %clip_vf4_ = OpFunction %void None %24
        %x_0 = OpFunctionParameter %_ptr_Function_v4float
         %27 = OpLabel
        %119 = OpAccessChain %_ptr_Function_float %x_0 %uint_0
        %120 = OpLoad %float %119
        %121 = OpFOrdLessThan %bool %120 %float_0
        %122 = OpLogicalNot %bool %121
               OpSelectionMerge %124 None
               OpBranchConditional %122 %123 %124
        %123 = OpLabel
        %125 = OpAccessChain %_ptr_Function_float %x_0 %uint_1
        %126 = OpLoad %float %125
        %127 = OpFOrdLessThan %bool %126 %float_0
               OpBranch %124
        %124 = OpLabel
        %128 = OpPhi %bool %121 %27 %127 %123
        %129 = OpLogicalNot %bool %128
               OpSelectionMerge %131 None
               OpBranchConditional %129 %130 %131
        %130 = OpLabel
        %132 = OpAccessChain %_ptr_Function_float %x_0 %uint_2
        %133 = OpLoad %float %132
        %134 = OpFOrdLessThan %bool %133 %float_0
               OpBranch %131
        %131 = OpLabel
        %135 = OpPhi %bool %128 %124 %134 %130
        %136 = OpLogicalNot %bool %135
               OpSelectionMerge %138 None
               OpBranchConditional %136 %137 %138
        %137 = OpLabel
        %140 = OpAccessChain %_ptr_Function_float %x_0 %uint_3
        %141 = OpLoad %float %140
        %142 = OpFOrdLessThan %bool %141 %float_0
               OpBranch %138
        %138 = OpLabel
        %143 = OpPhi %bool %135 %131 %142 %137
               OpSelectionMerge %145 None
               OpBranchConditional %143 %144 %145
        %144 = OpLabel
               OpKill
        %145 = OpLabel
               OpReturn
               OpFunctionEnd

Executing this function with the value clip(vec4(-0.5, 1, 1, 1)); results in the fragment not being discarded, even though the x value is less than zero.

If I rewrite the glsl function, to the logically equivalent:

void clip(vec4 x) 
{
    if (x.x < 0.0)
        discard;
    else if (x.y < 0.0)
        discard;
    else if (x.z < 0.0)
        discard;
    else if (x.w < 0.0)
        discard;
}

It will yield this SPIR-V code:

  %clip_vf4_ = OpFunction %void None %24
        %x_0 = OpFunctionParameter %_ptr_Function_v4float
         %27 = OpLabel
        %119 = OpAccessChain %_ptr_Function_float %x_0 %uint_0
        %120 = OpLoad %float %119
        %121 = OpFOrdLessThan %bool %120 %float_0
               OpSelectionMerge %123 None
               OpBranchConditional %121 %122 %125
        %122 = OpLabel
               OpKill
        %125 = OpLabel
        %126 = OpAccessChain %_ptr_Function_float %x_0 %uint_1
        %127 = OpLoad %float %126
        %128 = OpFOrdLessThan %bool %127 %float_0
               OpSelectionMerge %130 None
               OpBranchConditional %128 %129 %132
        %129 = OpLabel
               OpKill
        %132 = OpLabel
        %133 = OpAccessChain %_ptr_Function_float %x_0 %uint_2
        %134 = OpLoad %float %133
        %135 = OpFOrdLessThan %bool %134 %float_0
               OpSelectionMerge %137 None
               OpBranchConditional %135 %136 %139
        %136 = OpLabel
               OpKill
        %139 = OpLabel
        %141 = OpAccessChain %_ptr_Function_float %x_0 %uint_3
        %142 = OpLoad %float %141
        %143 = OpFOrdLessThan %bool %142 %float_0
               OpSelectionMerge %145 None
               OpBranchConditional %143 %144 %145
        %144 = OpLabel
               OpKill
        %145 = OpLabel
               OpBranch %137
        %137 = OpLabel
               OpBranch %130
        %130 = OpLabel
               OpBranch %123
        %123 = OpLabel
               OpReturn
               OpFunctionEnd

Executing this new version of the function with the value clip(vec4(-0.5, 1, 1, 1)); results in the fragment being discarded as expected.

Is something wrong with the first glsl function, or is this something that should be corrected ?

zoddicus commented 5 years ago

This is likely a SPIRV-Cross bug, not a shaderc bug, since the actual translation logic is implemented there. Unless of course this is something that we are doing wrong when invoking spirv-cross. Sending dneto0 to triage, since he owns this side of the repo more. This might a good starter bug?