mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
vkd3d-shader/ir: Flatten IF/ELSE/ENDIF control flow instructions.
This commit is contained in:
parent
f3d464de0e
commit
e1dddc01b7
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
@ -44,6 +44,7 @@ static const char * const shader_opcode_names[] =
|
||||
[VKD3DSIH_BEM ] = "bem",
|
||||
[VKD3DSIH_BFI ] = "bfi",
|
||||
[VKD3DSIH_BFREV ] = "bfrev",
|
||||
[VKD3DSIH_BRANCH ] = "branch",
|
||||
[VKD3DSIH_BREAK ] = "break",
|
||||
[VKD3DSIH_BREAKC ] = "breakc",
|
||||
[VKD3DSIH_BREAKP ] = "breakp",
|
||||
|
@ -312,6 +312,21 @@ void vsir_register_init(struct vkd3d_shader_register *reg, enum vkd3d_shader_reg
|
||||
reg->alignment = 0;
|
||||
}
|
||||
|
||||
static void vsir_src_param_init(struct vkd3d_shader_src_param *param, enum vkd3d_shader_register_type reg_type,
|
||||
enum vkd3d_data_type data_type, unsigned int idx_count)
|
||||
{
|
||||
vsir_register_init(¶m->reg, reg_type, data_type, idx_count);
|
||||
param->swizzle = 0;
|
||||
param->modifiers = VKD3DSPSM_NONE;
|
||||
}
|
||||
|
||||
static void vsir_src_param_init_label(struct vkd3d_shader_src_param *param, unsigned int label_id)
|
||||
{
|
||||
vsir_src_param_init(param, VKD3DSPR_LABEL, VKD3D_DATA_UINT, 1);
|
||||
param->reg.dimension = VSIR_DIMENSION_NONE;
|
||||
param->reg.idx[0].offset = label_id;
|
||||
}
|
||||
|
||||
void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
|
||||
enum vkd3d_shader_opcode handler_idx)
|
||||
{
|
||||
@ -320,6 +335,23 @@ void vsir_instruction_init(struct vkd3d_shader_instruction *ins, const struct vk
|
||||
ins->handler_idx = handler_idx;
|
||||
}
|
||||
|
||||
static bool vsir_instruction_init_label(struct vkd3d_shader_instruction *ins, const struct vkd3d_shader_location *location,
|
||||
unsigned int label_id, void *parser)
|
||||
{
|
||||
struct vkd3d_shader_src_param *src_param;
|
||||
|
||||
if (!(src_param = shader_parser_get_src_params(parser, 1)))
|
||||
return false;
|
||||
|
||||
vsir_src_param_init_label(src_param, label_id);
|
||||
|
||||
vsir_instruction_init(ins, location, VKD3DSIH_LABEL);
|
||||
ins->src = src_param;
|
||||
ins->src_count = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static enum vkd3d_result instruction_array_flatten_hull_shader_phases(struct vkd3d_shader_instruction_array *src_instructions)
|
||||
{
|
||||
struct hull_flattener flattener = {*src_instructions};
|
||||
@ -1476,6 +1508,324 @@ static enum vkd3d_result normalise_combined_samplers(struct vkd3d_shader_parser
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
struct cf_flattener_if_info
|
||||
{
|
||||
struct vkd3d_shader_src_param *false_param;
|
||||
uint32_t merge_block_id;
|
||||
unsigned int else_block_id;
|
||||
};
|
||||
|
||||
struct cf_flattener_info
|
||||
{
|
||||
union
|
||||
{
|
||||
struct cf_flattener_if_info if_;
|
||||
} u;
|
||||
|
||||
enum
|
||||
{
|
||||
VKD3D_BLOCK_IF,
|
||||
} current_block;
|
||||
bool inside_block;
|
||||
};
|
||||
|
||||
struct cf_flattener
|
||||
{
|
||||
struct vkd3d_shader_parser *parser;
|
||||
|
||||
struct vkd3d_shader_location location;
|
||||
bool allocation_failed;
|
||||
|
||||
struct vkd3d_shader_instruction *instructions;
|
||||
size_t instruction_capacity;
|
||||
size_t instruction_count;
|
||||
|
||||
unsigned int block_id;
|
||||
|
||||
unsigned int control_flow_depth;
|
||||
struct cf_flattener_info *control_flow_info;
|
||||
size_t control_flow_info_size;
|
||||
};
|
||||
|
||||
static struct vkd3d_shader_instruction *cf_flattener_require_space(struct cf_flattener *flattener, size_t count)
|
||||
{
|
||||
if (!vkd3d_array_reserve((void **)&flattener->instructions, &flattener->instruction_capacity,
|
||||
flattener->instruction_count + count, sizeof(*flattener->instructions)))
|
||||
{
|
||||
ERR("Failed to allocate instructions.\n");
|
||||
flattener->allocation_failed = true;
|
||||
return NULL;
|
||||
}
|
||||
return &flattener->instructions[flattener->instruction_count];
|
||||
}
|
||||
|
||||
static bool cf_flattener_copy_instruction(struct cf_flattener *flattener,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
struct vkd3d_shader_instruction *dst_ins;
|
||||
|
||||
if (instruction->handler_idx == VKD3DSIH_NOP)
|
||||
return true;
|
||||
|
||||
if (!(dst_ins = cf_flattener_require_space(flattener, 1)))
|
||||
return false;
|
||||
|
||||
*dst_ins = *instruction;
|
||||
++flattener->instruction_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
static unsigned int cf_flattener_alloc_block_id(struct cf_flattener *flattener)
|
||||
{
|
||||
return ++flattener->block_id;
|
||||
}
|
||||
|
||||
static struct vkd3d_shader_src_param *instruction_src_params_alloc(struct vkd3d_shader_instruction *ins,
|
||||
unsigned int count, struct cf_flattener *flattener)
|
||||
{
|
||||
struct vkd3d_shader_src_param *params = shader_parser_get_src_params(flattener->parser, count);
|
||||
if (!params)
|
||||
{
|
||||
flattener->allocation_failed = true;
|
||||
return NULL;
|
||||
}
|
||||
ins->src = params;
|
||||
ins->src_count = count;
|
||||
return params;
|
||||
}
|
||||
|
||||
static void cf_flattener_emit_label(struct cf_flattener *flattener, unsigned int label_id)
|
||||
{
|
||||
struct vkd3d_shader_instruction *ins;
|
||||
|
||||
if (!(ins = cf_flattener_require_space(flattener, 1)))
|
||||
return;
|
||||
if (vsir_instruction_init_label(ins, &flattener->location, label_id, flattener->parser))
|
||||
++flattener->instruction_count;
|
||||
else
|
||||
flattener->allocation_failed = true;
|
||||
}
|
||||
|
||||
/* For conditional branches, this returns the false target branch parameter. */
|
||||
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 true_id, unsigned int false_id,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct vkd3d_shader_src_param *src_params, *false_branch_param;
|
||||
struct vkd3d_shader_instruction *ins;
|
||||
|
||||
if (!(ins = cf_flattener_require_space(flattener, 1)))
|
||||
return NULL;
|
||||
vsir_instruction_init(ins, &flattener->location, VKD3DSIH_BRANCH);
|
||||
|
||||
if (condition)
|
||||
{
|
||||
if (!(src_params = instruction_src_params_alloc(ins, 4, flattener)))
|
||||
return NULL;
|
||||
src_params[0] = *condition;
|
||||
if (flags == VKD3D_SHADER_CONDITIONAL_OP_Z)
|
||||
{
|
||||
vsir_src_param_init_label(&src_params[1], false_id);
|
||||
vsir_src_param_init_label(&src_params[2], true_id);
|
||||
false_branch_param = &src_params[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
vsir_src_param_init_label(&src_params[1], true_id);
|
||||
vsir_src_param_init_label(&src_params[2], false_id);
|
||||
false_branch_param = &src_params[2];
|
||||
}
|
||||
vsir_src_param_init_label(&src_params[3], merge_block_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(src_params = instruction_src_params_alloc(ins, 1, flattener)))
|
||||
return NULL;
|
||||
vsir_src_param_init_label(&src_params[0], true_id);
|
||||
false_branch_param = NULL;
|
||||
}
|
||||
|
||||
++flattener->instruction_count;
|
||||
|
||||
return false_branch_param;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static struct cf_flattener_info *cf_flattener_push_control_flow_level(struct cf_flattener *flattener)
|
||||
{
|
||||
if (!vkd3d_array_reserve((void **)&flattener->control_flow_info, &flattener->control_flow_info_size,
|
||||
flattener->control_flow_depth + 1, sizeof(*flattener->control_flow_info)))
|
||||
{
|
||||
ERR("Failed to allocate control flow info structure.\n");
|
||||
flattener->allocation_failed = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &flattener->control_flow_info[flattener->control_flow_depth++];
|
||||
}
|
||||
|
||||
static void cf_flattener_pop_control_flow_level(struct cf_flattener *flattener)
|
||||
{
|
||||
struct cf_flattener_info *cf_info;
|
||||
|
||||
cf_info = &flattener->control_flow_info[--flattener->control_flow_depth];
|
||||
memset(cf_info, 0, sizeof(*cf_info));
|
||||
}
|
||||
|
||||
static enum vkd3d_result cf_flattener_iterate_instruction_array(struct cf_flattener *flattener)
|
||||
{
|
||||
struct vkd3d_shader_parser *parser = flattener->parser;
|
||||
struct vkd3d_shader_instruction_array *instructions;
|
||||
struct vkd3d_shader_instruction *dst_ins;
|
||||
unsigned int depth = 0;
|
||||
bool main_block_open;
|
||||
size_t i;
|
||||
|
||||
instructions = &parser->instructions;
|
||||
main_block_open = parser->shader_version.type != VKD3D_SHADER_TYPE_HULL;
|
||||
|
||||
if (!cf_flattener_require_space(flattener, instructions->count))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
for (i = 0; i < instructions->count; ++i)
|
||||
{
|
||||
const struct vkd3d_shader_instruction *instruction = &instructions->elements[i];
|
||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||
unsigned int merge_block_id, true_block_id;
|
||||
struct cf_flattener_info *cf_info;
|
||||
|
||||
flattener->location = instruction->location;
|
||||
|
||||
cf_info = flattener->control_flow_depth
|
||||
? &flattener->control_flow_info[flattener->control_flow_depth - 1] : NULL;
|
||||
|
||||
switch (instruction->handler_idx)
|
||||
{
|
||||
case VKD3DSIH_LABEL:
|
||||
vkd3d_shader_parser_error(parser, VKD3D_SHADER_ERROR_VSIR_NOT_IMPLEMENTED,
|
||||
"Aborting due to not yet implemented feature: Label instruction.");
|
||||
return VKD3D_ERROR_NOT_IMPLEMENTED;
|
||||
|
||||
case VKD3DSIH_IF:
|
||||
if (!(cf_info = cf_flattener_push_control_flow_level(flattener)))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
true_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,
|
||||
src, true_block_id, merge_block_id, instruction->flags);
|
||||
if (!cf_info->u.if_.false_param)
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
cf_flattener_emit_label(flattener, true_block_id);
|
||||
|
||||
cf_info->u.if_.merge_block_id = merge_block_id;
|
||||
cf_info->u.if_.else_block_id = 0;
|
||||
cf_info->inside_block = true;
|
||||
cf_info->current_block = VKD3D_BLOCK_IF;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_ELSE:
|
||||
if (cf_info->inside_block)
|
||||
cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id);
|
||||
|
||||
cf_info->u.if_.else_block_id = cf_flattener_alloc_block_id(flattener);
|
||||
cf_info->u.if_.false_param->reg.idx[0].offset = cf_info->u.if_.else_block_id;
|
||||
|
||||
cf_flattener_emit_label(flattener, cf_info->u.if_.else_block_id);
|
||||
|
||||
cf_info->inside_block = true;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_ENDIF:
|
||||
if (cf_info->inside_block)
|
||||
cf_flattener_emit_unconditional_branch(flattener, cf_info->u.if_.merge_block_id);
|
||||
|
||||
cf_flattener_emit_label(flattener, cf_info->u.if_.merge_block_id);
|
||||
|
||||
cf_flattener_pop_control_flow_level(flattener);
|
||||
break;
|
||||
|
||||
case VKD3DSIH_LOOP:
|
||||
case VKD3DSIH_SWITCH:
|
||||
++depth;
|
||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_ENDLOOP:
|
||||
case VKD3DSIH_ENDSWITCH:
|
||||
--depth;
|
||||
if (cf_info)
|
||||
cf_info->inside_block = true; /* Dead code removal ensures this is correct. */
|
||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_RET:
|
||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
if (cf_info)
|
||||
cf_info->inside_block = false;
|
||||
else if (!depth)
|
||||
main_block_open = false;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_BREAK:
|
||||
case VKD3DSIH_CONTINUE:
|
||||
if (cf_info)
|
||||
cf_info->inside_block = false;
|
||||
/* fall through */
|
||||
default:
|
||||
if (!cf_flattener_copy_instruction(flattener, instruction))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (main_block_open)
|
||||
{
|
||||
if (!(dst_ins = cf_flattener_require_space(flattener, 1)))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
vsir_instruction_init(dst_ins, &flattener->location, VKD3DSIH_RET);
|
||||
++flattener->instruction_count;
|
||||
}
|
||||
|
||||
return flattener->allocation_failed ? VKD3D_ERROR_OUT_OF_MEMORY : VKD3D_OK;
|
||||
}
|
||||
|
||||
static enum vkd3d_result flatten_control_flow_constructs(struct vkd3d_shader_parser *parser)
|
||||
{
|
||||
struct cf_flattener flattener = {0};
|
||||
enum vkd3d_result result;
|
||||
|
||||
flattener.parser = parser;
|
||||
result = cf_flattener_iterate_instruction_array(&flattener);
|
||||
|
||||
if (result >= 0)
|
||||
{
|
||||
vkd3d_free(parser->instructions.elements);
|
||||
parser->instructions.elements = flattener.instructions;
|
||||
parser->instructions.capacity = flattener.instruction_capacity;
|
||||
parser->instructions.count = flattener.instruction_count;
|
||||
parser->shader_desc.block_count = flattener.block_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
vkd3d_free(flattener.instructions);
|
||||
}
|
||||
|
||||
vkd3d_free(flattener.control_flow_info);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
|
||||
const struct vkd3d_shader_compile_info *compile_info)
|
||||
{
|
||||
@ -1504,6 +1854,9 @@ enum vkd3d_result vkd3d_shader_normalise(struct vkd3d_shader_parser *parser,
|
||||
if (result >= 0)
|
||||
remove_dead_code(parser);
|
||||
|
||||
if (result >= 0)
|
||||
result = flatten_control_flow_constructs(parser);
|
||||
|
||||
if (result >= 0)
|
||||
result = normalise_combined_samplers(parser);
|
||||
|
||||
|
@ -855,20 +855,6 @@ static void vkd3d_spirv_end_function_stream_insertion(struct vkd3d_spirv_builder
|
||||
builder->insertion_location = ~(size_t)0;
|
||||
}
|
||||
|
||||
struct vkd3d_spirv_op_branch_conditional
|
||||
{
|
||||
uint32_t opcode;
|
||||
uint32_t condition_id;
|
||||
uint32_t true_label;
|
||||
uint32_t false_label;
|
||||
};
|
||||
|
||||
static struct vkd3d_spirv_op_branch_conditional *vkd3d_spirv_as_op_branch_conditional(
|
||||
struct vkd3d_spirv_stream *stream, size_t location)
|
||||
{
|
||||
return (struct vkd3d_spirv_op_branch_conditional *)&stream->words[location];
|
||||
}
|
||||
|
||||
static void vkd3d_spirv_build_op_capability(struct vkd3d_spirv_stream *stream,
|
||||
SpvCapability cap)
|
||||
{
|
||||
@ -2267,14 +2253,6 @@ static const char *debug_vkd3d_symbol(const struct vkd3d_symbol *symbol)
|
||||
}
|
||||
}
|
||||
|
||||
struct vkd3d_if_cf_info
|
||||
{
|
||||
size_t stream_location;
|
||||
unsigned int id;
|
||||
uint32_t merge_block_id;
|
||||
uint32_t else_block_id;
|
||||
};
|
||||
|
||||
struct vkd3d_loop_cf_info
|
||||
{
|
||||
uint32_t header_block_id;
|
||||
@ -2298,14 +2276,12 @@ struct vkd3d_control_flow_info
|
||||
{
|
||||
union
|
||||
{
|
||||
struct vkd3d_if_cf_info if_;
|
||||
struct vkd3d_loop_cf_info loop;
|
||||
struct vkd3d_switch_cf_info switch_;
|
||||
} u;
|
||||
|
||||
enum
|
||||
{
|
||||
VKD3D_BLOCK_IF,
|
||||
VKD3D_BLOCK_LOOP,
|
||||
VKD3D_BLOCK_SWITCH,
|
||||
} current_block;
|
||||
@ -2365,7 +2341,6 @@ struct spirv_compiler
|
||||
|
||||
enum vkd3d_shader_type shader_type;
|
||||
|
||||
unsigned int branch_id;
|
||||
unsigned int loop_id;
|
||||
unsigned int switch_id;
|
||||
unsigned int control_flow_depth;
|
||||
@ -2380,7 +2355,6 @@ struct spirv_compiler
|
||||
struct vkd3d_push_constant_buffer_binding *push_constants;
|
||||
const struct vkd3d_shader_spirv_target_info *spirv_target_info;
|
||||
|
||||
bool main_block_open;
|
||||
bool after_declarations_section;
|
||||
struct shader_signature input_signature;
|
||||
struct shader_signature output_signature;
|
||||
@ -2422,6 +2396,9 @@ struct spirv_compiler
|
||||
unsigned int ssa_register_count;
|
||||
|
||||
uint64_t config_flags;
|
||||
|
||||
uint32_t *block_label_ids;
|
||||
unsigned int block_count;
|
||||
};
|
||||
|
||||
static bool is_in_default_phase(const struct spirv_compiler *compiler)
|
||||
@ -2471,6 +2448,7 @@ static void spirv_compiler_destroy(struct spirv_compiler *compiler)
|
||||
shader_signature_cleanup(&compiler->patch_constant_signature);
|
||||
|
||||
vkd3d_free(compiler->ssa_register_info);
|
||||
vkd3d_free(compiler->block_label_ids);
|
||||
|
||||
vkd3d_free(compiler);
|
||||
}
|
||||
@ -2806,6 +2784,14 @@ static struct vkd3d_string_buffer *vkd3d_shader_register_range_string(struct spi
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static uint32_t spirv_compiler_get_label_id(struct spirv_compiler *compiler, unsigned int block_id)
|
||||
{
|
||||
--block_id;
|
||||
if (!compiler->block_label_ids[block_id])
|
||||
compiler->block_label_ids[block_id] = vkd3d_spirv_alloc_id(&compiler->spirv_builder);
|
||||
return compiler->block_label_ids[block_id];
|
||||
}
|
||||
|
||||
static struct vkd3d_shader_descriptor_binding spirv_compiler_get_descriptor_binding(
|
||||
struct spirv_compiler *compiler, const struct vkd3d_shader_register *reg,
|
||||
const struct vkd3d_shader_register_range *range, enum vkd3d_shader_resource_type resource_type,
|
||||
@ -5550,7 +5536,6 @@ static void spirv_compiler_emit_initial_declarations(struct spirv_compiler *comp
|
||||
if (compiler->shader_type != VKD3D_SHADER_TYPE_HULL)
|
||||
{
|
||||
vkd3d_spirv_builder_begin_main_function(builder);
|
||||
compiler->main_block_open = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -7666,72 +7651,27 @@ static struct vkd3d_control_flow_info *spirv_compiler_find_innermost_breakable_c
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction);
|
||||
|
||||
static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *compiler,
|
||||
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;
|
||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||
uint32_t merge_block_id, val_id, condition_id, true_label;
|
||||
struct vkd3d_control_flow_info *cf_info;
|
||||
uint32_t merge_block_id, val_id;
|
||||
|
||||
cf_info = compiler->control_flow_depth
|
||||
? &compiler->control_flow_info[compiler->control_flow_depth - 1] : NULL;
|
||||
|
||||
switch (instruction->handler_idx)
|
||||
{
|
||||
case VKD3DSIH_IF:
|
||||
if (!(cf_info = spirv_compiler_push_control_flow_level(compiler)))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
val_id = spirv_compiler_emit_load_src(compiler, src, VKD3DSP_WRITEMASK_0);
|
||||
condition_id = spirv_compiler_emit_int_to_bool(compiler, instruction->flags, src->reg.data_type, 1, val_id);
|
||||
|
||||
true_label = vkd3d_spirv_alloc_id(builder);
|
||||
merge_block_id = vkd3d_spirv_alloc_id(builder);
|
||||
vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
|
||||
cf_info->u.if_.stream_location = vkd3d_spirv_stream_current_location(&builder->function_stream);
|
||||
vkd3d_spirv_build_op_branch_conditional(builder, condition_id, true_label, merge_block_id);
|
||||
|
||||
vkd3d_spirv_build_op_label(builder, true_label);
|
||||
|
||||
cf_info->u.if_.id = compiler->branch_id;
|
||||
cf_info->u.if_.merge_block_id = merge_block_id;
|
||||
cf_info->u.if_.else_block_id = 0;
|
||||
cf_info->inside_block = true;
|
||||
cf_info->current_block = VKD3D_BLOCK_IF;
|
||||
|
||||
vkd3d_spirv_build_op_name(builder, merge_block_id, "branch%u_merge", compiler->branch_id);
|
||||
vkd3d_spirv_build_op_name(builder, true_label, "branch%u_true", compiler->branch_id);
|
||||
++compiler->branch_id;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_ELSE:
|
||||
assert(compiler->control_flow_depth);
|
||||
assert(cf_info->current_block == VKD3D_BLOCK_IF);
|
||||
|
||||
if (cf_info->inside_block)
|
||||
vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
|
||||
|
||||
cf_info->u.if_.else_block_id = vkd3d_spirv_alloc_id(builder);
|
||||
vkd3d_spirv_as_op_branch_conditional(&builder->function_stream,
|
||||
cf_info->u.if_.stream_location)->false_label = cf_info->u.if_.else_block_id;
|
||||
vkd3d_spirv_build_op_name(builder,
|
||||
cf_info->u.if_.else_block_id, "branch%u_false", cf_info->u.if_.id);
|
||||
vkd3d_spirv_build_op_label(builder, cf_info->u.if_.else_block_id);
|
||||
cf_info->inside_block = true;
|
||||
break;
|
||||
|
||||
case VKD3DSIH_ENDIF:
|
||||
assert(compiler->control_flow_depth);
|
||||
assert(cf_info->current_block == VKD3D_BLOCK_IF);
|
||||
|
||||
if (cf_info->inside_block)
|
||||
vkd3d_spirv_build_op_branch(builder, cf_info->u.if_.merge_block_id);
|
||||
|
||||
vkd3d_spirv_build_op_label(builder, cf_info->u.if_.merge_block_id);
|
||||
|
||||
spirv_compiler_pop_control_flow_level(compiler);
|
||||
case VKD3DSIH_LABEL:
|
||||
if (cf_info)
|
||||
cf_info->inside_block = true;
|
||||
spirv_compiler_emit_label(compiler, instruction);
|
||||
break;
|
||||
|
||||
case VKD3DSIH_LOOP:
|
||||
@ -7968,8 +7908,6 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
|
||||
|
||||
if (cf_info)
|
||||
cf_info->inside_block = false;
|
||||
else
|
||||
compiler->main_block_open = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -7980,6 +7918,70 @@ static int spirv_compiler_emit_control_flow_instruction(struct spirv_compiler *c
|
||||
return VKD3D_OK;
|
||||
}
|
||||
|
||||
static bool spirv_compiler_init_blocks(struct spirv_compiler *compiler, unsigned int block_count)
|
||||
{
|
||||
compiler->block_count = block_count;
|
||||
|
||||
if (!(compiler->block_label_ids = vkd3d_calloc(block_count, sizeof(*compiler->block_label_ids))))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void spirv_compiler_emit_label(struct spirv_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||
unsigned int block_id = src->reg.idx[0].offset;
|
||||
uint32_t label_id;
|
||||
|
||||
label_id = spirv_compiler_get_label_id(compiler, block_id);
|
||||
vkd3d_spirv_build_op_label(builder, label_id);
|
||||
}
|
||||
|
||||
static void spirv_compiler_emit_merge(struct spirv_compiler *compiler,
|
||||
uint32_t merge_block_id)
|
||||
{
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
|
||||
if (!merge_block_id)
|
||||
return;
|
||||
|
||||
merge_block_id = spirv_compiler_get_label_id(compiler, merge_block_id);
|
||||
vkd3d_spirv_build_op_selection_merge(builder, merge_block_id, SpvSelectionControlMaskNone);
|
||||
}
|
||||
|
||||
static void spirv_compiler_emit_branch(struct spirv_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
struct vkd3d_spirv_builder *builder = &compiler->spirv_builder;
|
||||
const struct vkd3d_shader_src_param *src = instruction->src;
|
||||
uint32_t condition_id;
|
||||
|
||||
if (vsir_register_is_label(&src[0].reg))
|
||||
{
|
||||
vkd3d_spirv_build_op_branch(builder, spirv_compiler_get_label_id(compiler, src[0].reg.idx[0].offset));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!vkd3d_swizzle_is_scalar(src->swizzle))
|
||||
{
|
||||
WARN("Unexpected src swizzle %#x.\n", src->swizzle);
|
||||
spirv_compiler_warning(compiler, VKD3D_SHADER_WARNING_SPV_INVALID_SWIZZLE,
|
||||
"The swizzle for a branch condition value is not scalar.");
|
||||
}
|
||||
|
||||
condition_id = spirv_compiler_emit_load_src(compiler, &src[0], VKD3DSP_WRITEMASK_0);
|
||||
condition_id = spirv_compiler_emit_int_to_bool(compiler,
|
||||
VKD3D_SHADER_CONDITIONAL_OP_NZ, src[0].reg.data_type, 1, condition_id);
|
||||
/* Emit the merge immediately before the branch instruction. */
|
||||
spirv_compiler_emit_merge(compiler, src[3].reg.idx[0].offset);
|
||||
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[2].reg.idx[0].offset));
|
||||
}
|
||||
|
||||
static void spirv_compiler_emit_deriv_instruction(struct spirv_compiler *compiler,
|
||||
const struct vkd3d_shader_instruction *instruction)
|
||||
{
|
||||
@ -9730,11 +9732,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
|
||||
case VKD3DSIH_CONTINUE:
|
||||
case VKD3DSIH_CONTINUEP:
|
||||
case VKD3DSIH_DEFAULT:
|
||||
case VKD3DSIH_ELSE:
|
||||
case VKD3DSIH_ENDIF:
|
||||
case VKD3DSIH_ENDLOOP:
|
||||
case VKD3DSIH_ENDSWITCH:
|
||||
case VKD3DSIH_IF:
|
||||
case VKD3DSIH_LABEL:
|
||||
case VKD3DSIH_LOOP:
|
||||
case VKD3DSIH_RET:
|
||||
case VKD3DSIH_SWITCH:
|
||||
@ -9747,6 +9747,9 @@ static int spirv_compiler_handle_instruction(struct spirv_compiler *compiler,
|
||||
case VKD3DSIH_TEXKILL:
|
||||
spirv_compiler_emit_kill(compiler, instruction);
|
||||
break;
|
||||
case VKD3DSIH_BRANCH:
|
||||
spirv_compiler_emit_branch(compiler, instruction);
|
||||
break;
|
||||
case VKD3DSIH_DSX:
|
||||
case VKD3DSIH_DSX_COARSE:
|
||||
case VKD3DSIH_DSX_FINE:
|
||||
@ -9967,6 +9970,9 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
|
||||
if ((result = vkd3d_shader_normalise(parser, compile_info)) < 0)
|
||||
return result;
|
||||
|
||||
if (parser->shader_desc.block_count && !spirv_compiler_init_blocks(compiler, parser->shader_desc.block_count))
|
||||
return VKD3D_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
instructions = parser->instructions;
|
||||
memset(&parser->instructions, 0, sizeof(parser->instructions));
|
||||
|
||||
@ -9997,9 +10003,6 @@ static int spirv_compiler_generate_spirv(struct spirv_compiler *compiler,
|
||||
if (result < 0)
|
||||
return result;
|
||||
|
||||
if (compiler->main_block_open)
|
||||
vkd3d_spirv_build_op_return(builder);
|
||||
|
||||
if (!is_in_default_phase(compiler))
|
||||
spirv_compiler_leave_shader_phase(compiler);
|
||||
else
|
||||
|
@ -238,6 +238,7 @@ enum vkd3d_shader_opcode
|
||||
VKD3DSIH_BEM,
|
||||
VKD3DSIH_BFI,
|
||||
VKD3DSIH_BFREV,
|
||||
VKD3DSIH_BRANCH,
|
||||
VKD3DSIH_BREAK,
|
||||
VKD3DSIH_BREAKC,
|
||||
VKD3DSIH_BREAKP,
|
||||
@ -1016,6 +1017,7 @@ struct vkd3d_shader_desc
|
||||
|
||||
uint32_t temp_count;
|
||||
unsigned int ssa_count;
|
||||
unsigned int block_count;
|
||||
|
||||
struct
|
||||
{
|
||||
@ -1185,6 +1187,11 @@ static inline bool register_is_constant(const struct vkd3d_shader_register *reg)
|
||||
return (reg->type == VKD3DSPR_IMMCONST || reg->type == VKD3DSPR_IMMCONST64);
|
||||
}
|
||||
|
||||
static inline bool vsir_register_is_label(const struct vkd3d_shader_register *reg)
|
||||
{
|
||||
return reg->type == VKD3DSPR_LABEL;
|
||||
}
|
||||
|
||||
struct vkd3d_shader_param_node
|
||||
{
|
||||
struct vkd3d_shader_param_node *next;
|
||||
|
Loading…
Reference in New Issue
Block a user