Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/KhronosGroup/SPIRV-Cross.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans-Kristian Arntzen <post@arntzen-software.no>2022-07-04 16:17:52 +0300
committerGitHub <noreply@github.com>2022-07-04 16:17:52 +0300
commitd8d051381f65b9606fb8016c79b7c3bab872eec3 (patch)
treeb915cff2bfc89990e7b64301bd1a8f60eedf0c67
parentf46745095d70ebda0887e62a7ee8545d11dd6bbc (diff)
parent963fdfdf68647680c6c2bf119ad98ea05d3d8235 (diff)
Merge pull request #1970 from KhronosGroup/fix-1969
Handle PHI in collapsed switch constructs.
-rw-r--r--reference/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag11
-rw-r--r--shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag38
-rw-r--r--spirv_glsl.cpp53
3 files changed, 81 insertions, 21 deletions
diff --git a/reference/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag b/reference/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
new file mode 100644
index 00000000..a6f3e694
--- /dev/null
+++ b/reference/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
@@ -0,0 +1,11 @@
+#version 450
+
+layout(location = 0) out vec4 FragColor;
+
+void main()
+{
+ vec4 _17;
+ _17 = vec4(1.0);
+ FragColor = _17;
+}
+
diff --git a/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag b/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
new file mode 100644
index 00000000..d5a07b54
--- /dev/null
+++ b/shaders-no-opt/asm/frag/collapsed-switch-phi-flush.asm.frag
@@ -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
diff --git a/spirv_glsl.cpp b/spirv_glsl.cpp
index 6af72df6..9936c404 100644
--- a/spirv_glsl.cpp
+++ b/spirv_glsl.cpp
@@ -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");
- }
- else
- {
- emit_block_hints(block);
- statement("switch (", to_unpacked_expression(block.condition), ")");
+ {
+ emit_block_hints(block);
+ statement("switch (", to_unpacked_expression(block.condition), ")");
+ }
+ begin_scope();
}
- 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)
{