mirror of
https://github.com/KhronosGroup/SPIRV-Cross.git
synced 2024-11-09 22:00:05 +00:00
Handle PHI in collapsed switch constructs.
Collapsed switch constructs only branch directly to the merge block.
This commit is contained in:
parent
f46745095d
commit
963fdfdf68
@ -0,0 +1,11 @@
|
||||
#version 450
|
||||
|
||||
layout(location = 0) out vec4 FragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
vec4 _17;
|
||||
_17 = vec4(1.0);
|
||||
FragColor = _17;
|
||||
}
|
||||
|
38
shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
Normal file
38
shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
Normal 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
|
@ -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)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user