mirror of
https://gitlab.winehq.org/wine/vkd3d.git
synced 2024-11-21 16:46:41 -08:00
vkd3d-shader/hlsl: Split deref-offset into a node and a constant uint.
This uint will be used for the following: - Since SM4's relative addressing (the capability of passing a register as an index to another register) only has whole-register granularity, we will need to make the offset node express the offset in whole-registers and specify the register component in this uint, otherwise we would have to add additional / and % operations in the output binary. - If, after we apply constant folding and copy propagation, we determine that the offset is a single constant node, we can store all the offset in this uint constant, and remove the offset src. This allows DCE to remove a good bunch of the nodes previously required only for the offset constants, which makes the output more liteweight and readable, and simplifies the implementation of relative addressing when writing tpf in the following patches. In dump_deref(), we use "c" to indicate components instead of whole registers. Since now both the offset node and the offset uint are in components a lowered deref would look like: var[@42c + 2c] But, once we express the offset node in whole registers we will remove the "c" from the node part: var[@22 + 3c]
This commit is contained in:
parent
81be47c00b
commit
61a17643a2
Notes:
Alexandre Julliard
2023-10-31 22:38:12 +01:00
Approved-by: Giovanni Mascellani (@giomasce) Approved-by: Zebediah Figura (@zfigura) Approved-by: Henri Verbeet (@hverbeet) Approved-by: Alexandre Julliard (@julliard) Merge-Request: https://gitlab.winehq.org/wine/vkd3d/-/merge_requests/396
@ -513,6 +513,7 @@ static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hl
|
||||
deref->var = var;
|
||||
deref->path_len = path_len;
|
||||
deref->offset.node = NULL;
|
||||
deref->const_offset = 0;
|
||||
deref->data_type = NULL;
|
||||
|
||||
if (path_len == 0)
|
||||
@ -541,6 +542,7 @@ bool hlsl_init_deref_from_index_chain(struct hlsl_ctx *ctx, struct hlsl_deref *d
|
||||
deref->path = NULL;
|
||||
deref->path_len = 0;
|
||||
deref->offset.node = NULL;
|
||||
deref->const_offset = 0;
|
||||
|
||||
assert(chain);
|
||||
if (chain->type == HLSL_IR_INDEX)
|
||||
@ -1137,6 +1139,7 @@ void hlsl_cleanup_deref(struct hlsl_deref *deref)
|
||||
deref->path_len = 0;
|
||||
|
||||
hlsl_src_remove(&deref->offset);
|
||||
deref->const_offset = 0;
|
||||
}
|
||||
|
||||
/* Initializes a simple variable dereference, so that it can be passed to load/store functions. */
|
||||
@ -2411,21 +2414,37 @@ static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_der
|
||||
if (deref->var)
|
||||
{
|
||||
vkd3d_string_buffer_printf(buffer, "%s", deref->var->name);
|
||||
if (deref->path_len)
|
||||
if (!hlsl_deref_is_lowered(deref))
|
||||
{
|
||||
vkd3d_string_buffer_printf(buffer, "[");
|
||||
for (i = 0; i < deref->path_len; ++i)
|
||||
if (deref->path_len)
|
||||
{
|
||||
vkd3d_string_buffer_printf(buffer, "[");
|
||||
dump_src(buffer, &deref->path[i]);
|
||||
for (i = 0; i < deref->path_len; ++i)
|
||||
{
|
||||
vkd3d_string_buffer_printf(buffer, "[");
|
||||
dump_src(buffer, &deref->path[i]);
|
||||
vkd3d_string_buffer_printf(buffer, "]");
|
||||
}
|
||||
vkd3d_string_buffer_printf(buffer, "]");
|
||||
}
|
||||
vkd3d_string_buffer_printf(buffer, "]");
|
||||
}
|
||||
else if (deref->offset.node)
|
||||
else
|
||||
{
|
||||
bool show_rel, show_const;
|
||||
|
||||
show_rel = deref->offset.node;
|
||||
show_const = deref->const_offset != 0 || !show_rel;
|
||||
|
||||
vkd3d_string_buffer_printf(buffer, "[");
|
||||
dump_src(buffer, &deref->offset);
|
||||
if (show_rel)
|
||||
{
|
||||
dump_src(buffer, &deref->offset);
|
||||
vkd3d_string_buffer_printf(buffer, "c");
|
||||
}
|
||||
if (show_rel && show_const)
|
||||
vkd3d_string_buffer_printf(buffer, " + ");
|
||||
if (show_const)
|
||||
vkd3d_string_buffer_printf(buffer, "%uc", deref->const_offset);
|
||||
vkd3d_string_buffer_printf(buffer, "]");
|
||||
}
|
||||
}
|
||||
|
@ -638,14 +638,16 @@ struct hlsl_deref
|
||||
unsigned int path_len;
|
||||
struct hlsl_src *path;
|
||||
|
||||
/* Single instruction node of data type uint used to represent the register offset (in register
|
||||
* components, within the pertaining regset), from the start of the variable, of the part
|
||||
* referenced.
|
||||
* The path is lowered to this single offset -- whose value may vary between SM1 and SM4 --
|
||||
* before writing the bytecode.
|
||||
/* Before writing the bytecode, deref paths are lowered into an offset (within the pertaining
|
||||
* regset) from the start of the variable, to the part of the variable that is referenced.
|
||||
* This offset is stored using two fields, one for a variable part and other for a constant
|
||||
* part, which are added together:
|
||||
* - offset: An offset given by an instruction node, in number of register components.
|
||||
* - const_offset: A constant number of register components.
|
||||
* Since the type information cannot longer be retrieved from the offset alone, the type is
|
||||
* stored in the data_type field, which remains NULL if the deref hasn't been lowered yet. */
|
||||
struct hlsl_src offset;
|
||||
unsigned int const_offset;
|
||||
struct hlsl_type *data_type;
|
||||
};
|
||||
|
||||
|
@ -23,8 +23,8 @@
|
||||
|
||||
/* TODO: remove when no longer needed, only used for new_offset_instr_from_deref() */
|
||||
static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, struct hlsl_block *block,
|
||||
struct hlsl_type *type, struct hlsl_ir_node *offset, struct hlsl_ir_node *idx,
|
||||
enum hlsl_regset regset, const struct vkd3d_shader_location *loc)
|
||||
struct hlsl_type *type, struct hlsl_ir_node *base_offset, struct hlsl_ir_node *idx,
|
||||
enum hlsl_regset regset, unsigned int *offset_component, const struct vkd3d_shader_location *loc)
|
||||
{
|
||||
struct hlsl_ir_node *idx_offset = NULL;
|
||||
struct hlsl_ir_node *c;
|
||||
@ -32,7 +32,7 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
|
||||
switch (type->class)
|
||||
{
|
||||
case HLSL_CLASS_VECTOR:
|
||||
idx_offset = idx;
|
||||
*offset_component += hlsl_ir_constant(idx)->value.u[0].u;
|
||||
break;
|
||||
|
||||
case HLSL_CLASS_MATRIX:
|
||||
@ -67,8 +67,16 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
|
||||
{
|
||||
unsigned int field_idx = hlsl_ir_constant(idx)->value.u[0].u;
|
||||
struct hlsl_struct_field *field = &type->e.record.fields[field_idx];
|
||||
unsigned int field_offset = field->reg_offset[regset];
|
||||
|
||||
if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset[regset], loc)))
|
||||
if (regset == HLSL_REGSET_NUMERIC)
|
||||
{
|
||||
assert(*offset_component == 0);
|
||||
*offset_component = field_offset % 4;
|
||||
field_offset -= *offset_component;
|
||||
}
|
||||
|
||||
if (!(c = hlsl_new_uint_constant(ctx, field_offset, loc)))
|
||||
return NULL;
|
||||
hlsl_block_add_instr(block, c);
|
||||
|
||||
@ -81,27 +89,33 @@ static struct hlsl_ir_node *new_offset_from_path_index(struct hlsl_ctx *ctx, str
|
||||
vkd3d_unreachable();
|
||||
}
|
||||
|
||||
if (offset)
|
||||
if (idx_offset)
|
||||
{
|
||||
if (!(idx_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, idx_offset)))
|
||||
if (!(base_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, base_offset, idx_offset)))
|
||||
return NULL;
|
||||
hlsl_block_add_instr(block, idx_offset);
|
||||
hlsl_block_add_instr(block, base_offset);
|
||||
}
|
||||
|
||||
return idx_offset;
|
||||
return base_offset;
|
||||
}
|
||||
|
||||
/* TODO: remove when no longer needed, only used for replace_deref_path_with_offset() */
|
||||
static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, struct hlsl_block *block,
|
||||
const struct hlsl_deref *deref, const struct vkd3d_shader_location *loc)
|
||||
const struct hlsl_deref *deref, unsigned int *offset_component, const struct vkd3d_shader_location *loc)
|
||||
{
|
||||
enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref);
|
||||
struct hlsl_ir_node *offset = NULL;
|
||||
struct hlsl_ir_node *offset;
|
||||
struct hlsl_type *type;
|
||||
unsigned int i;
|
||||
|
||||
*offset_component = 0;
|
||||
|
||||
hlsl_block_init(block);
|
||||
|
||||
if (!(offset = hlsl_new_uint_constant(ctx, 0, loc)))
|
||||
return NULL;
|
||||
hlsl_block_add_instr(block, offset);
|
||||
|
||||
assert(deref->var);
|
||||
type = deref->var->data_type;
|
||||
|
||||
@ -112,7 +126,7 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st
|
||||
hlsl_block_init(&idx_block);
|
||||
|
||||
if (!(offset = new_offset_from_path_index(ctx, &idx_block, type, offset, deref->path[i].node,
|
||||
regset, loc)))
|
||||
regset, offset_component, loc)))
|
||||
{
|
||||
hlsl_block_cleanup(&idx_block);
|
||||
return NULL;
|
||||
@ -130,9 +144,10 @@ static struct hlsl_ir_node *new_offset_instr_from_deref(struct hlsl_ctx *ctx, st
|
||||
static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref,
|
||||
struct hlsl_ir_node *instr)
|
||||
{
|
||||
struct hlsl_type *type;
|
||||
unsigned int offset_component;
|
||||
struct hlsl_ir_node *offset;
|
||||
struct hlsl_block block;
|
||||
struct hlsl_type *type;
|
||||
|
||||
assert(deref->var);
|
||||
assert(!hlsl_deref_is_lowered(deref));
|
||||
@ -149,12 +164,13 @@ static bool replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_der
|
||||
|
||||
deref->data_type = type;
|
||||
|
||||
if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &instr->loc)))
|
||||
if (!(offset = new_offset_instr_from_deref(ctx, &block, deref, &offset_component, &instr->loc)))
|
||||
return false;
|
||||
list_move_before(&instr->entry, &block.instrs);
|
||||
|
||||
hlsl_cleanup_deref(deref);
|
||||
hlsl_src_from_node(&deref->offset, offset);
|
||||
deref->const_offset = offset_component;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -4439,30 +4455,28 @@ bool hlsl_regset_index_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref
|
||||
|
||||
bool hlsl_offset_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, unsigned int *offset)
|
||||
{
|
||||
enum hlsl_regset regset = hlsl_deref_get_regset(ctx, deref);
|
||||
struct hlsl_ir_node *offset_node = deref->offset.node;
|
||||
enum hlsl_regset regset;
|
||||
unsigned int size;
|
||||
|
||||
if (!offset_node)
|
||||
*offset = deref->const_offset;
|
||||
|
||||
if (offset_node)
|
||||
{
|
||||
*offset = 0;
|
||||
return true;
|
||||
/* We should always have generated a cast to UINT. */
|
||||
assert(offset_node->data_type->class == HLSL_CLASS_SCALAR
|
||||
&& offset_node->data_type->base_type == HLSL_TYPE_UINT);
|
||||
|
||||
if (offset_node->type != HLSL_IR_CONSTANT)
|
||||
return false;
|
||||
|
||||
*offset += hlsl_ir_constant(offset_node)->value.u[0].u;
|
||||
}
|
||||
|
||||
/* We should always have generated a cast to UINT. */
|
||||
assert(offset_node->data_type->class == HLSL_CLASS_SCALAR
|
||||
&& offset_node->data_type->base_type == HLSL_TYPE_UINT);
|
||||
|
||||
if (offset_node->type != HLSL_IR_CONSTANT)
|
||||
return false;
|
||||
|
||||
*offset = hlsl_ir_constant(offset_node)->value.u[0].u;
|
||||
regset = hlsl_deref_get_regset(ctx, deref);
|
||||
|
||||
size = deref->var->data_type->reg_size[regset];
|
||||
if (*offset >= size)
|
||||
{
|
||||
hlsl_error(ctx, &deref->offset.node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
|
||||
hlsl_error(ctx, &offset_node->loc, VKD3D_SHADER_ERROR_HLSL_OFFSET_OUT_OF_BOUNDS,
|
||||
"Dereference is out of bounds. %u/%u", *offset, size);
|
||||
return false;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user