-- v3: vkd3d-shader/ir: Remove dead code during normalisation.
From: Giovanni Mascellani gmascellani@codeweavers.com
The SPIR-V backend generates invalid SPIR-V code when VSIR has dead code (except for NOPs). --- libs/vkd3d-shader/ir.c | 82 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
diff --git a/libs/vkd3d-shader/ir.c b/libs/vkd3d-shader/ir.c index 6d7c89653..ffb1ff716 100644 --- a/libs/vkd3d-shader/ir.c +++ b/libs/vkd3d-shader/ir.c @@ -1260,6 +1260,85 @@ static enum vkd3d_result instruction_array_normalise_flat_constants(struct vkd3d return VKD3D_OK; }
+static void remove_dead_code(struct vkd3d_shader_parser *parser) +{ + size_t i, depth = 0; + bool dead = false; + + for (i = 0; i < parser->instructions.count; ++i) + { + struct vkd3d_shader_instruction *ins = &parser->instructions.elements[i]; + + switch (ins->handler_idx) + { + case VKD3DSIH_IF: + case VKD3DSIH_LOOP: + case VKD3DSIH_SWITCH: + if (dead) + { + vkd3d_shader_instruction_make_nop(ins); + ++depth; + } + break; + + case VKD3DSIH_ENDIF: + case VKD3DSIH_ENDLOOP: + case VKD3DSIH_ENDSWITCH: + case VKD3DSIH_ELSE: + if (dead) + { + if (depth > 0) + { + vkd3d_shader_instruction_make_nop(ins); + if (ins->handler_idx != VKD3DSIH_ELSE) + --depth; + } + else + { + dead = false; + } + } + break; + + case VKD3DSIH_BREAK: + case VKD3DSIH_RET: + case VKD3DSIH_CONTINUE: + if (dead) + { + vkd3d_shader_instruction_make_nop(ins); + } + else + { + dead = true; + depth = 0; + } + break; + + case VKD3DSIH_CASE: + case VKD3DSIH_DEFAULT: + if (dead) + { + if (depth == 0) + dead = false; + else + vkd3d_shader_instruction_make_nop(ins); + } + break; + + case VKD3DSIH_HS_CONTROL_POINT_PHASE: + case VKD3DSIH_HS_FORK_PHASE: + case VKD3DSIH_HS_JOIN_PHASE: + dead = false; + break; + + default: + if (dead) + vkd3d_shader_instruction_make_nop(ins); + break; + } + } +} + enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, const struct vkd3d_shader_compile_info *compile_info) { @@ -1287,6 +1366,9 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser, if (result >= 0) result = instruction_array_normalise_flat_constants(parser);
+ if (result >= 0) + remove_dead_code(parser); + if (result >= 0 && TRACE_ON()) vkd3d_shader_trace(instructions, &parser->shader_version);
I fixed some cases not being handled properly (or at all). Now tests should pass. So they do locally, at least.
In `spirv_compiler_emit_control_flow_instruction()`, `break` and `continue` set the depth not to zero but to the innermost breakable construct. Setting `depth` to zero in this patch seems to work, but a comment explaining exactly why would be helpful.