Handle PHI in collapsed switch constructs.

Collapsed switch constructs only branch directly to the merge block.
This commit is contained in:
Hans-Kristian Arntzen 2022-07-04 13:55:00 +02:00
parent f46745095d
commit 963fdfdf68
3 changed files with 81 additions and 21 deletions

View File

@ -0,0 +1,11 @@
#version 450
layout(location = 0) out vec4 FragColor;
void main()
{
vec4 _17;
_17 = vec4(1.0);
FragColor = _17;
}

View File

@ -0,0 +1,38 @@
; SPIR-V
; Version: 1.0
; Generator: Khronos Glslang Reference Front End; 10
; Bound: 20
; Schema: 0
OpCapability Shader
%1 = OpExtInstImport "GLSL.std.450"
OpMemoryModel Logical GLSL450
OpEntryPoint Fragment %main "main" %FragColor %vIndex
OpExecutionMode %main OriginUpperLeft
OpSource GLSL 450
OpName %main "main"
OpName %FragColor "FragColor"
OpName %vIndex "vIndex"
OpDecorate %FragColor Location 0
OpDecorate %vIndex Flat
OpDecorate %vIndex Location 0
%void = OpTypeVoid
%3 = OpTypeFunction %void
%int = OpTypeInt 32 1
%int_0 = OpConstant %int 0
%float = OpTypeFloat 32
%v4float = OpTypeVector %float 4
%_ptr_Output_v4float = OpTypePointer Output %v4float
%FragColor = OpVariable %_ptr_Output_v4float Output
%float_1 = OpConstant %float 1
%15 = OpConstantComposite %v4float %float_1 %float_1 %float_1 %float_1
%_ptr_Input_int = OpTypePointer Input %int
%vIndex = OpVariable %_ptr_Input_int Input
%main = OpFunction %void None %3
%5 = OpLabel
OpSelectionMerge %9 None
OpSwitch %int_0 %9
%9 = OpLabel
%tmp = OpPhi %v4float %15 %5
OpStore %FragColor %tmp
OpReturn
OpFunctionEnd

View File

@ -15753,26 +15753,32 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// If there is only one default block, and no cases, this is a case where SPIRV-opt decided to emulate
// non-structured exits with the help of a switch block.
// This is buggy on FXC, so just emit the logical equivalent of a do { } while(false), which is more idiomatic.
bool degenerate_switch = block.default_block != block.merge_block && cases.empty();
bool block_like_switch = cases.empty();
if (degenerate_switch || is_legacy_es())
// If this is true, the switch is completely meaningless, and we should just avoid it.
bool collapsed_switch = block_like_switch && block.default_block == block.next_block;
if (!collapsed_switch)
{
// ESSL 1.0 is not guaranteed to support do/while.
if (is_legacy_es())
if (block_like_switch || is_legacy_es())
{
uint32_t counter = statement_count;
statement("for (int spvDummy", counter, " = 0; spvDummy", counter,
" < 1; spvDummy", counter, "++)");
// ESSL 1.0 is not guaranteed to support do/while.
if (is_legacy_es())
{
uint32_t counter = statement_count;
statement("for (int spvDummy", counter, " = 0; spvDummy", counter, " < 1; spvDummy", counter,
"++)");
}
else
statement("do");
}
else
statement("do");
{
emit_block_hints(block);
statement("switch (", to_unpacked_expression(block.condition), ")");
}
begin_scope();
}
else
{
emit_block_hints(block);
statement("switch (", to_unpacked_expression(block.condition), ")");
}
begin_scope();
for (size_t i = 0; i < num_blocks; i++)
{
@ -15782,7 +15788,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
if (literals.empty())
{
// Default case.
if (!degenerate_switch)
if (!block_like_switch)
{
if (is_legacy_es())
statement("else");
@ -15820,10 +15826,10 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
else
current_emitting_switch_fallthrough = false;
if (!degenerate_switch)
if (!block_like_switch)
begin_scope();
branch(block.self, target_block);
if (!degenerate_switch)
if (!block_like_switch)
end_scope();
current_emitting_switch_fallthrough = false;
@ -15837,7 +15843,7 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
// - Header -> Merge requires flushing PHI. In this case, we need to collect all cases and flush PHI there.
bool header_merge_requires_phi = flush_phi_required(block.self, block.next_block);
bool need_fallthrough_block = block.default_block == block.next_block || !literals_to_merge.empty();
if ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty())
if (!collapsed_switch && ((header_merge_requires_phi && need_fallthrough_block) || !literals_to_merge.empty()))
{
for (auto &case_literal : literals_to_merge)
statement("case ", to_case_label(case_literal, type.width, unsigned_case), label_suffix, ":");
@ -15856,10 +15862,15 @@ void CompilerGLSL::emit_block_chain(SPIRBlock &block)
end_scope();
}
if (degenerate_switch && !is_legacy_es())
end_scope_decl("while(false)");
if (!collapsed_switch)
{
if (block_like_switch && !is_legacy_es())
end_scope_decl("while(false)");
else
end_scope();
}
else
end_scope();
flush_phi(block.self, block.next_block);
if (block.need_ladder_break)
{