libs/vkd3d-shader: Add support for switch breaks nested in conditional branches.

This commit is contained in:
Józef Kucia
2017-08-01 13:55:49 +02:00
parent 6b93e6ce99
commit eb4c98db17

View File

@@ -3592,14 +3592,15 @@ static void vkd3d_dxbc_compiler_pop_control_flow_level(struct vkd3d_dxbc_compile
memset(cf_info, 0, sizeof(*cf_info)); memset(cf_info, 0, sizeof(*cf_info));
} }
static struct vkd3d_control_flow_info *vkd3d_dxbc_compiler_find_innermost_loop( static struct vkd3d_control_flow_info *vkd3d_dxbc_compiler_find_innermost_breakable_cf_construct(
struct vkd3d_dxbc_compiler *compiler) struct vkd3d_dxbc_compiler *compiler)
{ {
int depth; int depth;
for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth) for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
{ {
if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP) if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP
|| compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
return &compiler->control_flow_info[depth]; return &compiler->control_flow_info[depth];
} }
@@ -3813,19 +3814,9 @@ static void vkd3d_dxbc_compiler_emit_control_flow_instruction(struct vkd3d_dxbc_
case VKD3DSIH_BREAK: case VKD3DSIH_BREAK:
{ {
const struct vkd3d_control_flow_info *loop_cf_info; struct vkd3d_control_flow_info *breakable_cf_info;
if (cf_info->current_block == VKD3D_BLOCK_SWITCH) if (!(breakable_cf_info = vkd3d_dxbc_compiler_find_innermost_breakable_cf_construct(compiler)))
{
if (cf_info->u.switch_.inside_block)
{
vkd3d_spirv_build_op_branch(builder, cf_info->u.switch_.merge_block_id);
cf_info->u.switch_.inside_block = false;
}
return;
}
if (!(loop_cf_info = vkd3d_dxbc_compiler_find_innermost_loop(compiler)))
{ {
FIXME("Unhandled break instruction.\n"); FIXME("Unhandled break instruction.\n");
return; return;
@@ -3833,14 +3824,26 @@ static void vkd3d_dxbc_compiler_emit_control_flow_instruction(struct vkd3d_dxbc_
assert(compiler->control_flow_depth); assert(compiler->control_flow_depth);
vkd3d_spirv_build_op_branch(builder, loop_cf_info->u.loop.merge_block_id); if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
{
vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.loop.merge_block_id);
}
else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
{
if (breakable_cf_info->u.switch_.inside_block)
{
vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.switch_.merge_block_id);
if (breakable_cf_info == cf_info)
breakable_cf_info->u.switch_.inside_block = false;
}
}
if (cf_info->current_block == VKD3D_BLOCK_IF) if (cf_info->current_block == VKD3D_BLOCK_IF)
{ {
vkd3d_spirv_build_op_label(builder, cf_info->u.branch.else_block_id); vkd3d_spirv_build_op_label(builder, cf_info->u.branch.else_block_id);
cf_info->current_block = VKD3D_BLOCK_ELSE; cf_info->current_block = VKD3D_BLOCK_ELSE;
} }
else else if (cf_info->current_block != VKD3D_BLOCK_SWITCH)
{ {
cf_info->current_block = VKD3D_BLOCK_NONE; cf_info->current_block = VKD3D_BLOCK_NONE;
} }