mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
vkd3d-shader/ir: Flatten LOOP/BREAK/CONTINUE/ENDLOOP control flow instructions.
This commit is contained in:
parent
e1dddc01b7
commit
dcb8527327
Notes:
Alexandre Julliard
2024-01-17 22:42:55 +01:00
Approved-by: Giovanni Mascellani (@giomasce) Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/450
@ -1515,16 +1515,26 @@ struct cf_flattener_if_info
|
|||||||
unsigned int else_block_id;
|
unsigned int else_block_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cf_flattener_loop_info
|
||||||
|
{
|
||||||
|
unsigned int header_block_id;
|
||||||
|
unsigned int continue_block_id;
|
||||||
|
uint32_t merge_block_id;
|
||||||
|
};
|
||||||
|
|
||||||
struct cf_flattener_info
|
struct cf_flattener_info
|
||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct cf_flattener_if_info if_;
|
struct cf_flattener_if_info if_;
|
||||||
|
struct cf_flattener_loop_info loop;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
VKD3D_BLOCK_IF,
|
VKD3D_BLOCK_IF,
|
||||||
|
VKD3D_BLOCK_LOOP,
|
||||||
|
VKD3D_BLOCK_SWITCH,
|
||||||
} current_block;
|
} current_block;
|
||||||
bool inside_block;
|
bool inside_block;
|
||||||
};
|
};
|
||||||
@ -1608,8 +1618,8 @@ static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int
|
|||||||
|
|
||||||
/* For conditional branches, this returns the false target branch parameter. */
|
/* For conditional branches, this returns the false target branch parameter. */
|
||||||
static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener,
|
static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flattener *flattener,
|
||||||
unsigned int merge_block_id, const struct vkd3d_shader_src_param *condition,
|
unsigned int merge_block_id, unsigned int continue_block_id,
|
||||||
unsigned int true_id, unsigned int false_id,
|
const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int false_id,
|
||||||
unsigned int flags)
|
unsigned int flags)
|
||||||
{
|
{
|
||||||
struct vkd3d_shader_src_param *src_params, *false_branch_param;
|
struct vkd3d_shader_src_param *src_params, *false_branch_param;
|
||||||
@ -1621,7 +1631,7 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten
|
|||||||
|
|
||||||
if (condition)
|
if (condition)
|
||||||
{
|
{
|
||||||
if (!(src_params = instruction_src_params_alloc(ins, 4, flattener)))
|
if (!(src_params = instruction_src_params_alloc(ins, 4 + !!continue_block_id, flattener)))
|
||||||
return NULL;
|
return NULL;
|
||||||
src_params[0] = *condition;
|
src_params[0] = *condition;
|
||||||
if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z)
|
if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z)
|
||||||
@ -1637,12 +1647,21 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten
|
|||||||
false_branch_param = &src_params[2];
|
false_branch_param = &src_params[2];
|
||||||
}
|
}
|
||||||
vsir_src_param_init_label(&src_params[3], merge_block_id);
|
vsir_src_param_init_label(&src_params[3], merge_block_id);
|
||||||
|
if (continue_block_id)
|
||||||
|
vsir_src_param_init_label(&src_params[4], continue_block_id);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!(src_params = instruction_src_params_alloc(ins, 1, flattener)))
|
if (!(src_params = instruction_src_params_alloc(ins, merge_block_id ? 3 : 1, flattener)))
|
||||||
return NULL;
|
return NULL;
|
||||||
vsir_src_param_init_label(&src_params[0], true_id);
|
vsir_src_param_init_label(&src_params[0], true_id);
|
||||||
|
if (merge_block_id)
|
||||||
|
{
|
||||||
|
/* An unconditional branch may only have merge information for a loop, which
|
||||||
|
* must have both a merge block and continue block. */
|
||||||
|
vsir_src_param_init_label(&src_params[1], merge_block_id);
|
||||||
|
vsir_src_param_init_label(&src_params[2], continue_block_id);
|
||||||
|
}
|
||||||
false_branch_param = NULL;
|
false_branch_param = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1651,9 +1670,19 @@ static struct vkd3d_shader_src_param *cf_flattener_emit_branch(struct cf_flatten
|
|||||||
return false_branch_param;
|
return false_branch_param;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cf_flattener_emit_conditional_branch_and_merge(struct cf_flattener *flattener,
|
||||||
|
const struct vkd3d_shader_src_param *condition, unsigned int true_id, unsigned int flags)
|
||||||
|
{
|
||||||
|
unsigned int merge_block_id;
|
||||||
|
|
||||||
|
merge_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
|
cf_flattener_emit_branch(flattener, merge_block_id, 0, condition, true_id, merge_block_id, flags);
|
||||||
|
cf_flattener_emit_label(flattener, merge_block_id);
|
||||||
|
}
|
||||||
|
|
||||||
static void cf_flattener_emit_unconditional_branch(struct cf_flattener *flattener, unsigned int target_block_id)
|
static void cf_flattener_emit_unconditional_branch(struct cf_flattener *flattener, unsigned int target_block_id)
|
||||||
{
|
{
|
||||||
cf_flattener_emit_branch(flattener, 0, NULL, target_block_id, 0, 0);
|
cf_flattener_emit_branch(flattener, 0, 0, NULL, target_block_id, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener)
|
static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener)
|
||||||
@ -1677,12 +1706,38 @@ static void cf_flattener_pop_control_flow_level(struct cf_flattener *flattener)
|
|||||||
memset(cf_info, 0, sizeof(*cf_info));
|
memset(cf_info, 0, sizeof(*cf_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct cf_flattener_info *cf_flattener_find_innermost_loop(struct cf_flattener *flattener)
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth)
|
||||||
|
{
|
||||||
|
if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP)
|
||||||
|
return &flattener->control_flow_info[depth];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cf_flattener_info *cf_flattener_find_innermost_breakable_cf_construct(struct cf_flattener *flattener)
|
||||||
|
{
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
for (depth = flattener->control_flow_depth - 1; depth >= 0; --depth)
|
||||||
|
{
|
||||||
|
if (flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP
|
||||||
|
|| flattener->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
|
||||||
|
return &flattener->control_flow_info[depth];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener)
|
static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener)
|
||||||
{
|
{
|
||||||
struct vkd3d_shader_parser *parser = flattener->parser;
|
struct vkd3d_shader_parser *parser = flattener->parser;
|
||||||
struct vkd3d_shader_instruction_array *instructions;
|
struct vkd3d_shader_instruction_array *instructions;
|
||||||
struct vkd3d_shader_instruction *dst_ins;
|
struct vkd3d_shader_instruction *dst_ins;
|
||||||
unsigned int depth = 0;
|
|
||||||
bool main_block_open;
|
bool main_block_open;
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
@ -1694,9 +1749,9 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
|
|||||||
|
|
||||||
for (i = 0; i < instructions->count; ++i)
|
for (i = 0; i < instructions->count; ++i)
|
||||||
{
|
{
|
||||||
|
unsigned int loop_header_block_id, loop_body_block_id, continue_block_id, merge_block_id, true_block_id;
|
||||||
const struct vkd3d_shader_instruction *instruction = &instructions->elements[i];
|
const struct vkd3d_shader_instruction *instruction = &instructions->elements[i];
|
||||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||||
unsigned int merge_block_id, true_block_id;
|
|
||||||
struct cf_flattener_info *cf_info;
|
struct cf_flattener_info *cf_info;
|
||||||
|
|
||||||
flattener->location = instruction->location;
|
flattener->location = instruction->location;
|
||||||
@ -1717,7 +1772,7 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
|
|||||||
|
|
||||||
true_block_id = cf_flattener_alloc_block_id(flattener);
|
true_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
merge_block_id = cf_flattener_alloc_block_id(flattener);
|
merge_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id,
|
cf_info->u.if_.false_param = cf_flattener_emit_branch(flattener, merge_block_id, 0,
|
||||||
src, true_block_id, merge_block_id, instruction->flags);
|
src, true_block_id, merge_block_id, instruction->flags);
|
||||||
if (!cf_info->u.if_.false_param)
|
if (!cf_info->u.if_.false_param)
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
@ -1752,20 +1807,126 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VKD3DSIH_LOOP:
|
case VKD3DSIH_LOOP:
|
||||||
|
if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
loop_header_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
|
loop_body_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
|
continue_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
|
merge_block_id = cf_flattener_alloc_block_id(flattener);
|
||||||
|
|
||||||
|
cf_flattener_emit_unconditional_branch(flattener, loop_header_block_id);
|
||||||
|
cf_flattener_emit_label(flattener, loop_header_block_id);
|
||||||
|
cf_flattener_emit_branch(flattener, merge_block_id, continue_block_id,
|
||||||
|
NULL, loop_body_block_id, 0, 0);
|
||||||
|
|
||||||
|
cf_flattener_emit_label(flattener, loop_body_block_id);
|
||||||
|
|
||||||
|
cf_info->u.loop.header_block_id = loop_header_block_id;
|
||||||
|
cf_info->u.loop.continue_block_id = continue_block_id;
|
||||||
|
cf_info->u.loop.merge_block_id = merge_block_id;
|
||||||
|
cf_info->current_block = VKD3D_BLOCK_LOOP;
|
||||||
|
cf_info->inside_block = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VKD3DSIH_ENDLOOP:
|
||||||
|
if (cf_info->inside_block)
|
||||||
|
cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.continue_block_id);
|
||||||
|
|
||||||
|
cf_flattener_emit_label(flattener, cf_info->u.loop.continue_block_id);
|
||||||
|
cf_flattener_emit_unconditional_branch(flattener, cf_info->u.loop.header_block_id);
|
||||||
|
cf_flattener_emit_label(flattener, cf_info->u.loop.merge_block_id);
|
||||||
|
|
||||||
|
cf_flattener_pop_control_flow_level(flattener);
|
||||||
|
break;
|
||||||
|
|
||||||
case VKD3DSIH_SWITCH:
|
case VKD3DSIH_SWITCH:
|
||||||
++depth;
|
if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
|
||||||
|
cf_info->current_block = VKD3D_BLOCK_SWITCH;
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VKD3DSIH_ENDSWITCH:
|
||||||
|
cf_flattener_pop_control_flow_level(flattener);
|
||||||
|
|
||||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VKD3DSIH_ENDLOOP:
|
case VKD3DSIH_BREAK:
|
||||||
case VKD3DSIH_ENDSWITCH:
|
{
|
||||||
--depth;
|
struct cf_flattener_info *breakable_cf_info;
|
||||||
if (cf_info)
|
|
||||||
cf_info->inside_block = true; /* Dead code removal ensures this is correct. */
|
if (!(breakable_cf_info = cf_flattener_find_innermost_breakable_cf_construct(flattener)))
|
||||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
{
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
FIXME("Unhandled break instruction.\n");
|
||||||
|
return VKD3D_ERROR_INVALID_SHADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
|
||||||
|
{
|
||||||
|
cf_flattener_emit_unconditional_branch(flattener, breakable_cf_info->u.loop.merge_block_id);
|
||||||
|
}
|
||||||
|
else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
|
||||||
|
{
|
||||||
|
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||||
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
cf_info->inside_block = false;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VKD3DSIH_BREAKP:
|
||||||
|
{
|
||||||
|
struct cf_flattener_info *loop_cf_info;
|
||||||
|
|
||||||
|
if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
|
||||||
|
{
|
||||||
|
ERR("Invalid 'breakc' instruction outside loop.\n");
|
||||||
|
return VKD3D_ERROR_INVALID_SHADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
cf_flattener_emit_conditional_branch_and_merge(flattener,
|
||||||
|
src, loop_cf_info->u.loop.merge_block_id, instruction->flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VKD3DSIH_CONTINUE:
|
||||||
|
{
|
||||||
|
struct cf_flattener_info *loop_cf_info;
|
||||||
|
|
||||||
|
if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
|
||||||
|
{
|
||||||
|
ERR("Invalid 'continue' instruction outside loop.\n");
|
||||||
|
return VKD3D_ERROR_INVALID_SHADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
cf_flattener_emit_unconditional_branch(flattener, loop_cf_info->u.loop.continue_block_id);
|
||||||
|
|
||||||
|
cf_info->inside_block = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case VKD3DSIH_CONTINUEP:
|
||||||
|
{
|
||||||
|
struct cf_flattener_info *loop_cf_info;
|
||||||
|
|
||||||
|
if (!(loop_cf_info = cf_flattener_find_innermost_loop(flattener)))
|
||||||
|
{
|
||||||
|
ERR("Invalid 'continuec' instruction outside loop.\n");
|
||||||
|
return VKD3D_ERROR_INVALID_SHADER;
|
||||||
|
}
|
||||||
|
|
||||||
|
cf_flattener_emit_conditional_branch_and_merge(flattener,
|
||||||
|
src, loop_cf_info->u.loop.continue_block_id, instruction->flags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case VKD3DSIH_RET:
|
case VKD3DSIH_RET:
|
||||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||||
@ -1773,15 +1934,10 @@ static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flatte
|
|||||||
|
|
||||||
if (cf_info)
|
if (cf_info)
|
||||||
cf_info->inside_block = false;
|
cf_info->inside_block = false;
|
||||||
else if (!depth)
|
else
|
||||||
main_block_open = false;
|
main_block_open = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VKD3DSIH_BREAK:
|
|
||||||
case VKD3DSIH_CONTINUE:
|
|
||||||
if (cf_info)
|
|
||||||
cf_info->inside_block = false;
|
|
||||||
/* fall through */
|
|
||||||
default:
|
default:
|
||||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
|
@ -2253,13 +2253,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vkd3d_loop_cf_info
|
|
||||||
{
|
|
||||||
uint32_t header_block_id;
|
|
||||||
uint32_t continue_block_id;
|
|
||||||
uint32_t merge_block_id;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct vkd3d_switch_cf_info
|
struct vkd3d_switch_cf_info
|
||||||
{
|
{
|
||||||
size_t stream_location;
|
size_t stream_location;
|
||||||
@ -2276,13 +2269,11 @@ struct vkd3d_control_flow_info
|
|||||||
{
|
{
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
struct vkd3d_loop_cf_info loop;
|
|
||||||
struct vkd3d_switch_cf_info switch_;
|
struct vkd3d_switch_cf_info switch_;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
VKD3D_BLOCK_LOOP,
|
|
||||||
VKD3D_BLOCK_SWITCH,
|
VKD3D_BLOCK_SWITCH,
|
||||||
} current_block;
|
} current_block;
|
||||||
bool inside_block;
|
bool inside_block;
|
||||||
@ -2341,7 +2332,6 @@ struct spirv_compiler
|
|||||||
|
|
||||||
enum vkd3d_shader_type shader_type;
|
enum vkd3d_shader_type shader_type;
|
||||||
|
|
||||||
unsigned int loop_id;
|
|
||||||
unsigned int switch_id;
|
unsigned int switch_id;
|
||||||
unsigned int control_flow_depth;
|
unsigned int control_flow_depth;
|
||||||
struct vkd3d_control_flow_info *control_flow_info;
|
struct vkd3d_control_flow_info *control_flow_info;
|
||||||
@ -7622,20 +7612,6 @@ static void spirv_compiler_pop_control_flow_level(struct spirv_compiler *compile
|
|||||||
memset(cf_info, 0, sizeof(*cf_info));
|
memset(cf_info, 0, sizeof(*cf_info));
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_loop(
|
|
||||||
struct spirv_compiler *compiler)
|
|
||||||
{
|
|
||||||
int depth;
|
|
||||||
|
|
||||||
for (depth = compiler->control_flow_depth - 1; depth >= 0; --depth)
|
|
||||||
{
|
|
||||||
if (compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_LOOP)
|
|
||||||
return &compiler->control_flow_info[depth];
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_cf_construct(
|
static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_cf_construct(
|
||||||
struct spirv_compiler *compiler)
|
struct spirv_compiler *compiler)
|
||||||
{
|
{
|
||||||
@ -7643,8 +7619,7 @@ static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_c
|
|||||||
|
|
||||||
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_SWITCH)
|
||||||
|| compiler->control_flow_info[depth].current_block == VKD3D_BLOCK_SWITCH)
|
|
||||||
return &compiler->control_flow_info[depth];
|
return &compiler->control_flow_info[depth];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7657,7 +7632,6 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
|
|||||||
static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler,
|
static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler,
|
||||||
const struct vkd3d_shader_instruction *instruction)
|
const struct vkd3d_shader_instruction *instruction)
|
||||||
{
|
{
|
||||||
uint32_t loop_header_block_id, loop_body_block_id, continue_block_id;
|
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||||
struct vkd3d_control_flow_info *cf_info;
|
struct vkd3d_control_flow_info *cf_info;
|
||||||
@ -7674,51 +7648,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
|
|||||||
spirv_compiler_emit_label(compiler, instruction);
|
spirv_compiler_emit_label(compiler, instruction);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VKD3DSIH_LOOP:
|
|
||||||
if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
|
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
|
||||||
|
|
||||||
loop_header_block_id = vkd3d_spirv_alloc_id(builder);
|
|
||||||
loop_body_block_id = vkd3d_spirv_alloc_id(builder);
|
|
||||||
continue_block_id = vkd3d_spirv_alloc_id(builder);
|
|
||||||
merge_block_id = vkd3d_spirv_alloc_id(builder);
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_branch(builder, loop_header_block_id);
|
|
||||||
vkd3d_spirv_build_op_label(builder, loop_header_block_id);
|
|
||||||
vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone);
|
|
||||||
vkd3d_spirv_build_op_branch(builder, loop_body_block_id);
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_label(builder, loop_body_block_id);
|
|
||||||
|
|
||||||
cf_info->u.loop.header_block_id = loop_header_block_id;
|
|
||||||
cf_info->u.loop.continue_block_id = continue_block_id;
|
|
||||||
cf_info->u.loop.merge_block_id = merge_block_id;
|
|
||||||
cf_info->current_block = VKD3D_BLOCK_LOOP;
|
|
||||||
cf_info->inside_block = true;
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_name(builder, loop_header_block_id, "loop%u_header", compiler->loop_id);
|
|
||||||
vkd3d_spirv_build_op_name(builder, loop_body_block_id, "loop%u_body", compiler->loop_id);
|
|
||||||
vkd3d_spirv_build_op_name(builder, continue_block_id, "loop%u_continue", compiler->loop_id);
|
|
||||||
vkd3d_spirv_build_op_name(builder, merge_block_id, "loop%u_merge", compiler->loop_id);
|
|
||||||
++compiler->loop_id;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VKD3DSIH_ENDLOOP:
|
|
||||||
assert(compiler->control_flow_depth);
|
|
||||||
assert(cf_info->current_block == VKD3D_BLOCK_LOOP);
|
|
||||||
|
|
||||||
/* The loop block may have already been ended by an unconditional
|
|
||||||
* break instruction right before the end of the loop. */
|
|
||||||
if (cf_info->inside_block)
|
|
||||||
vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.continue_block_id);
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_label(builder, cf_info->u.loop.continue_block_id);
|
|
||||||
vkd3d_spirv_build_op_branch(builder, cf_info->u.loop.header_block_id);
|
|
||||||
vkd3d_spirv_build_op_label(builder, cf_info->u.loop.merge_block_id);
|
|
||||||
|
|
||||||
spirv_compiler_pop_control_flow_level(compiler);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case VKD3DSIH_SWITCH:
|
case VKD3DSIH_SWITCH:
|
||||||
if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
|
if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
|
||||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||||
@ -7835,11 +7764,7 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
|
|||||||
return VKD3D_ERROR_INVALID_SHADER;
|
return VKD3D_ERROR_INVALID_SHADER;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (breakable_cf_info->current_block == VKD3D_BLOCK_LOOP)
|
if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
|
||||||
{
|
|
||||||
vkd3d_spirv_build_op_branch(builder, breakable_cf_info->u.loop.merge_block_id);
|
|
||||||
}
|
|
||||||
else if (breakable_cf_info->current_block == VKD3D_BLOCK_SWITCH)
|
|
||||||
{
|
{
|
||||||
/* The current case block may have already been ended by an
|
/* The current case block may have already been ended by an
|
||||||
* unconditional continue instruction. */
|
* unconditional continue instruction. */
|
||||||
@ -7851,58 +7776,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case VKD3DSIH_BREAKP:
|
|
||||||
{
|
|
||||||
struct vkd3d_control_flow_info *loop_cf_info;
|
|
||||||
|
|
||||||
assert(compiler->control_flow_depth);
|
|
||||||
|
|
||||||
if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
|
|
||||||
{
|
|
||||||
ERR("Invalid 'breakc' instruction outside loop.\n");
|
|
||||||
return VKD3D_ERROR_INVALID_SHADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_block_id = spirv_compiler_emit_conditional_branch(compiler,
|
|
||||||
instruction, loop_cf_info->u.loop.merge_block_id);
|
|
||||||
vkd3d_spirv_build_op_label(builder, merge_block_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VKD3DSIH_CONTINUE:
|
|
||||||
{
|
|
||||||
struct vkd3d_control_flow_info *loop_cf_info;
|
|
||||||
|
|
||||||
assert(compiler->control_flow_depth);
|
|
||||||
|
|
||||||
if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
|
|
||||||
{
|
|
||||||
ERR("Invalid 'continue' instruction outside loop.\n");
|
|
||||||
return VKD3D_ERROR_INVALID_SHADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
vkd3d_spirv_build_op_branch(builder, loop_cf_info->u.loop.continue_block_id);
|
|
||||||
|
|
||||||
cf_info->inside_block = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VKD3DSIH_CONTINUEP:
|
|
||||||
{
|
|
||||||
struct vkd3d_control_flow_info *loop_cf_info;
|
|
||||||
|
|
||||||
if (!(loop_cf_info = spirv_compiler_find_innermost_loop(compiler)))
|
|
||||||
{
|
|
||||||
ERR("Invalid 'continuec' instruction outside loop.\n");
|
|
||||||
return VKD3D_ERROR_INVALID_SHADER;
|
|
||||||
}
|
|
||||||
|
|
||||||
merge_block_id = spirv_compiler_emit_conditional_branch(compiler,
|
|
||||||
instruction, loop_cf_info->u.loop.continue_block_id);
|
|
||||||
vkd3d_spirv_build_op_label(builder, merge_block_id);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case VKD3DSIH_RET:
|
case VKD3DSIH_RET:
|
||||||
spirv_compiler_emit_return(compiler, instruction);
|
spirv_compiler_emit_return(compiler, instruction);
|
||||||
|
|
||||||
@ -7941,7 +7814,7 @@ static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler,
|
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler,
|
||||||
uint32_t merge_block_id)
|
uint32_t merge_block_id, uint32_t continue_block_id)
|
||||||
{
|
{
|
||||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||||
|
|
||||||
@ -7949,7 +7822,15 @@ static void spirv_compiler_emit_merge(struct spirv_compiler *compiler,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id);
|
merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id);
|
||||||
vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
|
if (!continue_block_id)
|
||||||
|
{
|
||||||
|
vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
continue_block_id = spirv_compiler_get_label_id(compiler, continue_block_id);
|
||||||
|
vkd3d_spirv_build_op_loop_merge(builder, merge_block_id, continue_block_id, SpvLoopControlMaskNone);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
|
static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
|
||||||
@ -7961,6 +7842,11 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
|
|||||||
|
|
||||||
if (vsir_register_is_label(&src[0].reg))
|
if (vsir_register_is_label(&src[0].reg))
|
||||||
{
|
{
|
||||||
|
if (instruction->src_count > 1)
|
||||||
|
{
|
||||||
|
/* Loop merge only. Must have a merge block and a continue block. */
|
||||||
|
spirv_compiler_emit_merge(compiler, src[1].reg.idx[0].offset, src[2].reg.idx[0].offset);
|
||||||
|
}
|
||||||
vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset));
|
vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -7976,7 +7862,8 @@ static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
|
|||||||
condition_id = spirv_compiler_emit_int_to_bool(compiler,
|
condition_id = spirv_compiler_emit_int_to_bool(compiler,
|
||||||
VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id);
|
VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id);
|
||||||
/* Emit the merge immediately before the branch instruction. */
|
/* Emit the merge immediately before the branch instruction. */
|
||||||
spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset);
|
spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset,
|
||||||
|
(instruction->src_count > 4) ? src[4].reg.idx[0].offset : 0);
|
||||||
vkd3d_spirv_build_op_branch_conditional(builder, condition_id,
|
vkd3d_spirv_build_op_branch_conditional(builder, condition_id,
|
||||||
spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset),
|
spirv_compiler_get_label_id(compiler, src[1].reg.idx[0].offset),
|
||||||
spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset));
|
spirv_compiler_get_label_id(compiler, src[2].reg.idx[0].offset));
|
||||||
|
Loading…
Reference in New Issue
Block a user