From: Francisco Casas Subject: [PATCH vkd3d 07/12] vkd3d-shader/hlsl: Replace register offsets with index paths in parse code. Message-Id: <20220701212435.76394-7-fcasas@codeweavers.com> Date: Fri, 1 Jul 2022 17:24:30 -0400 The transform_deref_paths_into_offsets pass turns these index paths back into register offsets, they should not be used anywhere before that. Signed-off-by: Francisco Casas --- The idea is that we can move this pass forward as we translate more passes to work with index paths. This, until register offsets can be totally removed, after we implement the SMxIRs and their translations. The aim is to have 3 ways of initializing load/store nodes when using index paths: * One that initializes the node from a another's node deref and and optional index to be appended to that deref's path. * One that initializes the node from a deref and the index of a single basic component within it. This one also generates constant nodes for the required path, so it also initializes an instruction block whose instructions must be inserted in the instruction list. * One that initializes the node directly for a whole variable. These functions are already present: hlsl_new_var_load() and hlsl_new_simple_store(). The signatures of these functions were placed nearby in hlsl.h hlsl_new_resource_load() was modified to receive deref arguments instead of var+offset pairs. It is worth noting that the use of index paths allows to remove the data type argument when initializing store/loads because it can now be deducted from the variable and the hlsl_deref. Applying an index over a matrix derefence retrieves a vector. If the matrix is row_major, this corresponds to a row, otherwise, it corresponds to a column. So, the code should take matrix majority into account, at least until the split_matrix_copies pass. The first index in a path after a loading a struct should be an hlsl_ir_constant, since the field that's being addressed is always known at parse-time. hlsl_get_direct_var_deref() can be used to create a deref value that can be passed by reference in the first 2 cases. This value shall not be modified after being created. Signed-off-by: Francisco Casas --- libs/vkd3d-shader/hlsl.c | 371 +++++++++++++++++++++++++++---- libs/vkd3d-shader/hlsl.h | 35 ++- libs/vkd3d-shader/hlsl.y | 147 +++++------- libs/vkd3d-shader/hlsl_codegen.c | 71 ++++++ 4 files changed, 469 insertions(+), 155 deletions(-) diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 17ccd305..c7416054 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -249,39 +249,51 @@ static struct hlsl_type *hlsl_new_type(struct hlsl_ctx *ctx, const char *name, e return type; } -/* Returns the register offset of a given component within a type, given its index. - * *comp_type will be set to the type of the component. */ -unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, - unsigned int idx, struct hlsl_type **comp_type) +/* Returns the path of a given component within a type, given its index. + * *comp_type will be set to the type of the component. + * *path_len will be set to the lenght of the path. + * Memory should be free afterwards. + */ +unsigned int *hlsl_compute_component_path(struct hlsl_ctx *ctx, struct hlsl_type *type, + unsigned int idx, struct hlsl_type **comp_type, unsigned int *path_len) { + unsigned int *path; + switch (type->type) { case HLSL_CLASS_SCALAR: + case HLSL_CLASS_OBJECT: + { + assert(idx == 0); + *comp_type = type; + *path_len = 0; + path = hlsl_alloc(ctx, 0 * sizeof(unsigned int)); + return path; + } case HLSL_CLASS_VECTOR: { assert(idx < type->dimx * type->dimy); *comp_type = hlsl_get_scalar_type(ctx, type->base_type); - return idx; + *path_len = 1; + if (!(path = hlsl_alloc(ctx, 1 * sizeof(unsigned int)))) + return NULL; + path[0] = idx; + return path; } case HLSL_CLASS_MATRIX: { - unsigned int minor, major, x = idx % type->dimx, y = idx / type->dimx; + unsigned int y = idx / type->dimx, x = idx % type->dimx; + bool row_major = hlsl_type_is_row_major(type); assert(idx < type->dimx * type->dimy); - if (hlsl_type_is_row_major(type)) - { - minor = x; - major = y; - } - else - { - minor = y; - major = x; - } - *comp_type = hlsl_get_scalar_type(ctx, type->base_type); - return 4 * major + minor; + *path_len = 2; + if (!(path = hlsl_alloc(ctx, 2 * sizeof(unsigned int)))) + return NULL; + path[0] = row_major? y : x; + path[1] = row_major? x : y; + return path; } case HLSL_CLASS_ARRAY: @@ -289,45 +301,64 @@ unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, struct hlsl_typ unsigned int elem_comp_count = hlsl_type_component_count(type->e.array.type); unsigned int array_idx = idx / elem_comp_count; unsigned int idx_in_elem = idx % elem_comp_count; + unsigned int elem_path_len; + unsigned int *elem_path; - assert(array_idx < type->e.array.elements_count); + elem_path = hlsl_compute_component_path(ctx, type->e.array.type, idx_in_elem, comp_type, &elem_path_len); + if (elem_path_len && !elem_path) + return NULL; - return array_idx * hlsl_type_get_array_element_reg_size(type->e.array.type) + - hlsl_compute_component_offset(ctx, type->e.array.type, idx_in_elem, comp_type); + *path_len = elem_path_len + 1; + if (!(path = hlsl_alloc(ctx, (*path_len) * sizeof(unsigned int)))) + { + vkd3d_free(elem_path); + return NULL; + } + memcpy(path + 1, elem_path, elem_path_len * sizeof(unsigned int)); + vkd3d_free(elem_path); + path[0] = array_idx; + return path; } case HLSL_CLASS_STRUCT: { struct hlsl_struct_field *field; - unsigned int elem_comp_count, i; + unsigned int field_comp_count, i; for (i = 0; i < type->e.record.field_count; ++i) { field = &type->e.record.fields[i]; - elem_comp_count = hlsl_type_component_count(field->type); + field_comp_count = hlsl_type_component_count(field->type); - if (idx < elem_comp_count) + if (idx < field_comp_count) { - return field->reg_offset + - hlsl_compute_component_offset(ctx, field->type, idx, comp_type); + unsigned int field_path_len; + unsigned int *field_path; + + field_path = hlsl_compute_component_path(ctx, field->type, idx, comp_type, &field_path_len); + if (field_path_len && !field_path) + return NULL; + + *path_len = field_path_len + 1; + if (!(path = hlsl_alloc(ctx, (*path_len) * sizeof(unsigned int)))) + { + vkd3d_free(field_path); + return NULL; + } + memcpy(path + 1, field_path, field_path_len * sizeof(unsigned int)); + vkd3d_free(field_path); + path[0] = i; + return path; } - idx -= elem_comp_count; + idx -= field_comp_count; } - assert(0); - return 0; - } - - case HLSL_CLASS_OBJECT: - { - assert(idx == 0); - *comp_type = type; - return 0; + return NULL; } } assert(0); - return 0; + return NULL; } struct hlsl_type *hlsl_get_type_from_path_index(struct hlsl_ctx *ctx, const struct hlsl_type *type, @@ -733,6 +764,62 @@ static bool type_is_single_reg(const struct hlsl_type *type) return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR; } +static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_ir_var *var, + unsigned int path_len) +{ + deref->var = var; + deref->path_len = path_len; + deref->offset.node = NULL; + + if (path_len == 0) + { + deref->path = NULL; + return true; + } + + if (!(deref->path = hlsl_alloc(ctx, sizeof(*deref->path) * deref->path_len))) + { + deref->var = NULL; + deref->path_len = 0; + return false; + } + + return true; +} + +static bool deref_copy(struct hlsl_ctx *ctx, struct hlsl_deref *deref, struct hlsl_deref *other) +{ + unsigned int i; + + if (!other) + { + deref->var = NULL; + deref->path = NULL; + deref->path_len = 0; + return true; + } + + if (!init_deref(ctx, deref, other->var, other->path_len)) + return false; + + for (i = 0; i < deref->path_len; ++i) + hlsl_src_from_node(&deref->path[i], other->path[i].node); + + hlsl_src_from_node(&deref->offset, other->offset.node); + + return true; +} + +static struct hlsl_type *get_type_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref) +{ + struct hlsl_type *type = deref->var->data_type; + unsigned int i; + + for (i = 0; i < deref->path_len; ++i) + type = hlsl_get_type_from_path_index(ctx, type, deref->path[i].node); + return type; +} + struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_ir_node *offset, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) { @@ -745,16 +832,113 @@ struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *v return NULL; init_node(&store->node, HLSL_IR_STORE, NULL, loc); - store->lhs.var = var; + init_deref(ctx, &store->lhs, var, 0); hlsl_src_from_node(&store->lhs.offset, offset); hlsl_src_from_node(&store->rhs, rhs); store->writemask = writemask; return store; } +/* Returns a simple variable derefence, so that the value can be stored and then passed by reference + * to load/store functions. It shall not be modified afterwards. */ +struct hlsl_deref hlsl_get_direct_var_deref(struct hlsl_ir_var *var) +{ + struct hlsl_deref deref = {}; + + deref.var = var; + return deref; +} + struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs) { - return hlsl_new_store(ctx, lhs, NULL, rhs, 0, rhs->loc); + struct hlsl_deref lhs_deref = hlsl_get_direct_var_deref(lhs); + + return hlsl_new_store_index(ctx, &lhs_deref, NULL, rhs, 0, rhs->loc); +} + +struct hlsl_ir_store *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hlsl_deref *lhs, + struct hlsl_ir_node *idx, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_store *store; + unsigned int i; + + assert(lhs); + + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) + return NULL; + init_node(&store->node, HLSL_IR_STORE, NULL, loc); + + if (!init_deref(ctx, &store->lhs, lhs->var, lhs->path_len + !!idx)) + return NULL; + for (i = 0; i < lhs->path_len; ++i) + hlsl_src_from_node(&store->lhs.path[i], lhs->path[i].node); + if (idx) + hlsl_src_from_node(&store->lhs.path[i], idx); + + hlsl_src_from_node(&store->rhs, rhs); + + if (!writemask && type_is_single_reg(rhs->data_type)) + writemask = (1 << rhs->data_type->dimx) - 1; + store->writemask = writemask; + + return store; +} + +struct hlsl_ir_store *hlsl_new_store_component(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct hlsl_deref *lhs, unsigned int comp, struct hlsl_ir_node *rhs) +{ + struct hlsl_type *type, *comp_type; + unsigned int *path, path_len, i; + struct hlsl_ir_store *store; + struct hlsl_ir_constant *c; + + list_init(&block->instrs); + + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) + return NULL; + init_node(&store->node, HLSL_IR_STORE, NULL, rhs->loc); + + type = get_type_from_deref(ctx, lhs); + path = hlsl_compute_component_path(ctx, type, comp, &comp_type, &path_len); + if (path_len && !path) + { + vkd3d_free(store); + return NULL; + } + + if (!init_deref(ctx, &store->lhs, lhs->var, lhs->path_len + path_len)) + { + vkd3d_free(path); + vkd3d_free(store); + return NULL; + } + + for (i = 0; i < lhs->path_len; ++i) + hlsl_src_from_node(&store->lhs.path[i], lhs->path[i].node); + for (i = 0; i < path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, path[i], &rhs->loc))) + { + vkd3d_free(path); + hlsl_free_instr_list(&block->instrs); + hlsl_free_deref(&store->lhs); + vkd3d_free(store); + return NULL; + } + list_add_tail(&block->instrs, &c->node.entry); + + hlsl_src_from_node(&store->lhs.path[lhs->path_len + i], &c->node); + } + vkd3d_free(path); + + hlsl_src_from_node(&store->rhs, rhs); + + if (type_is_single_reg(rhs->data_type)) + store->writemask = (1 << rhs->data_type->dimx) - 1; + + list_add_tail(&block->instrs, &store->node.entry); + + return store; } struct hlsl_ir_constant *hlsl_new_constant(struct hlsl_ctx *ctx, struct hlsl_type *type, @@ -848,21 +1032,103 @@ struct hlsl_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var if (!(load = hlsl_alloc(ctx, sizeof(*load)))) return NULL; init_node(&load->node, HLSL_IR_LOAD, type, loc); - load->src.var = var; + init_deref(ctx, &load->src, var, 0); hlsl_src_from_node(&load->src.offset, offset); return load; } +struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, + struct hlsl_ir_node *idx, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_load *load; + struct hlsl_type *type; + unsigned int i; + + type = get_type_from_deref(ctx, deref); + if (idx) + type = hlsl_get_type_from_path_index(ctx, type, idx); + + if (!(load = hlsl_alloc(ctx, sizeof(*load)))) + return NULL; + init_node(&load->node, HLSL_IR_LOAD, type, loc); + + if (!init_deref(ctx, &load->src, deref->var, deref->path_len + !!idx)) + { + vkd3d_free(load); + return NULL; + } + for (i = 0; i < deref->path_len; ++i) + hlsl_src_from_node(&load->src.path[i], deref->path[i].node); + if (idx) + hlsl_src_from_node(&load->src.path[i], idx); + + return load; +} + struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, - const struct vkd3d_shader_location loc) + struct vkd3d_shader_location loc) { - return hlsl_new_load(ctx, var, NULL, var->data_type, loc); + struct hlsl_deref var_deref = hlsl_get_direct_var_deref(var); + + return hlsl_new_load_index(ctx, &var_deref, NULL, loc); +} + +struct hlsl_ir_load *hlsl_new_load_component(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct hlsl_deref *deref, unsigned int comp, struct vkd3d_shader_location loc) +{ + struct hlsl_type *type, *comp_type; + unsigned int *path, path_len, i; + struct hlsl_ir_constant *c; + struct hlsl_ir_load *load; + + list_init(&block->instrs); + + type = get_type_from_deref(ctx, deref); + path = hlsl_compute_component_path(ctx, type, comp, &comp_type, &path_len); + if (path_len && !path) + return NULL; + + if (!(load = hlsl_alloc(ctx, sizeof(*load)))) + { + vkd3d_free(path); + return NULL; + } + init_node(&load->node, HLSL_IR_LOAD, comp_type, loc); + + + if (!init_deref(ctx, &load->src, deref->var, deref->path_len + path_len)) + { + vkd3d_free(path); + vkd3d_free(load); + return NULL; + } + + for (i = 0; i < deref->path_len; ++i) + hlsl_src_from_node(&load->src.path[i], deref->path[i].node); + for (i = 0; i < path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, path[i], &loc))) + { + vkd3d_free(path); + hlsl_free_instr_list(&block->instrs); + hlsl_free_deref(&load->src); + vkd3d_free(load); + return NULL; + } + list_add_tail(&block->instrs, &c->node.entry); + + hlsl_src_from_node(&load->src.path[deref->path_len + i], &c->node); + } + vkd3d_free(path); + + list_add_tail(&block->instrs, &load->node.entry); + + return load; } struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struct hlsl_type *data_type, - enum hlsl_resource_load_type type, struct hlsl_ir_var *resource, struct hlsl_ir_node *resource_offset, - struct hlsl_ir_var *sampler, struct hlsl_ir_node *sampler_offset, struct hlsl_ir_node *coords, - struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc) + enum hlsl_resource_load_type type, struct hlsl_deref *resource, struct hlsl_deref *sampler, + struct hlsl_ir_node *coords, struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc) { struct hlsl_ir_resource_load *load; @@ -870,10 +1136,8 @@ struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struc return NULL; init_node(&load->node, HLSL_IR_RESOURCE_LOAD, data_type, *loc); load->load_type = type; - load->resource.var = resource; - hlsl_src_from_node(&load->resource.offset, resource_offset); - load->sampler.var = sampler; - hlsl_src_from_node(&load->sampler.offset, sampler_offset); + deref_copy(ctx, &load->resource, resource); + deref_copy(ctx, &load->sampler, sampler); hlsl_src_from_node(&load->coords, coords); hlsl_src_from_node(&load->texel_offset, texel_offset); return load; @@ -1664,6 +1928,15 @@ void hlsl_free_instr_list(struct list *list) void hlsl_free_deref(struct hlsl_deref *deref) { + unsigned int i; + + for (i = 0; i < deref->path_len; ++i) + hlsl_src_remove(&deref->path[i]); + vkd3d_free(deref->path); + + deref->path = NULL; + deref->path_len = 0; + hlsl_src_remove(&deref->offset); } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index fbadd9c6..d3885540 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -374,6 +374,10 @@ struct hlsl_ir_swizzle struct hlsl_deref { struct hlsl_ir_var *var; + + unsigned int path_len; + struct hlsl_src *path; + struct hlsl_src offset; }; @@ -753,14 +757,29 @@ struct hlsl_ir_if *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condit struct hlsl_ir_constant *hlsl_new_int_constant(struct hlsl_ctx *ctx, int n, const struct vkd3d_shader_location *loc); struct hlsl_ir_jump *hlsl_new_jump(struct hlsl_ctx *ctx, enum hlsl_ir_jump_type type, struct vkd3d_shader_location loc); + +struct hlsl_deref hlsl_get_direct_var_deref(struct hlsl_ir_var *var); + +struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, + struct vkd3d_shader_location loc); +struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, + struct hlsl_ir_node *idx, struct vkd3d_shader_location loc); +struct hlsl_ir_load *hlsl_new_load_component(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct hlsl_deref *deref, unsigned int comp, struct vkd3d_shader_location loc); + +struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs); +struct hlsl_ir_store *hlsl_new_store_index(struct hlsl_ctx *ctx, const struct hlsl_deref *lhs, + struct hlsl_ir_node *idx, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc); +struct hlsl_ir_store *hlsl_new_store_component(struct hlsl_ctx *ctx, struct hlsl_block *block, + const struct hlsl_deref *lhs, unsigned int comp, struct hlsl_ir_node *rhs); + +struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struct hlsl_type *data_type, + enum hlsl_resource_load_type type, struct hlsl_deref *resource, struct hlsl_deref *sampler, + struct hlsl_ir_node *coords, struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc); + struct hlsl_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_ir_node *offset, struct hlsl_type *type, struct vkd3d_shader_location loc); struct hlsl_ir_loop *hlsl_new_loop(struct hlsl_ctx *ctx, struct vkd3d_shader_location loc); -struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struct hlsl_type *data_type, - enum hlsl_resource_load_type type, struct hlsl_ir_var *resource, struct hlsl_ir_node *resource_offset, - struct hlsl_ir_var *sampler, struct hlsl_ir_node *sampler_offset, struct hlsl_ir_node *coords, - struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc); -struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs); struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_ir_node *offset, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc); struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, @@ -777,8 +796,6 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, const struct vkd3d_shader_location loc, const struct hlsl_semantic *semantic, unsigned int modifiers, const struct hlsl_reg_reservation *reg_reservation); -struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, - const struct vkd3d_shader_location loc); void hlsl_error(struct hlsl_ctx *ctx, const struct vkd3d_shader_location *loc, enum vkd3d_shader_error error, const char *fmt, ...) VKD3D_PRINTF_FUNC(4, 5); @@ -798,8 +815,8 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, unsigned int default_majority, unsigned int modifiers); unsigned int hlsl_type_component_count(struct hlsl_type *type); unsigned int hlsl_type_get_array_element_reg_size(const struct hlsl_type *type); -unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, struct hlsl_type *type, - unsigned int idx, struct hlsl_type **comp_type); +unsigned int *hlsl_compute_component_path(struct hlsl_ctx *ctx, struct hlsl_type *type, + unsigned int idx, struct hlsl_type **comp_type, unsigned int *path_len); bool hlsl_type_is_row_major(const struct hlsl_type *type); unsigned int hlsl_type_minor_size(const struct hlsl_type *type); unsigned int hlsl_type_major_size(const struct hlsl_type *type); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 63904580..ed45d54f 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -289,6 +289,7 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, { struct vkd3d_string_buffer *name; static unsigned int counter = 0; + struct hlsl_deref var_deref; struct hlsl_ir_load *load; struct hlsl_ir_var *var; unsigned int dst_idx; @@ -308,13 +309,14 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, vkd3d_string_buffer_release(&ctx->string_buffers, name); if (!var) return NULL; + var_deref = hlsl_get_direct_var_deref(var); for (dst_idx = 0; dst_idx < dst_type->dimx * dst_type->dimy; ++dst_idx) { + unsigned int src_idx, *dst_path, dst_path_len; struct hlsl_type *dst_scalar_type; - unsigned int src_idx, dst_offset; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; + struct hlsl_block block; if (broadcast) { @@ -334,7 +336,10 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, } } - dst_offset = hlsl_compute_component_offset(ctx, dst_type, dst_idx, &dst_scalar_type); + dst_path = hlsl_compute_component_path(ctx, dst_type, dst_idx, &dst_scalar_type, &dst_path_len); + if (dst_path_len && !dst_path) + return NULL; + vkd3d_free(dst_path); if (!(load = add_load_component(ctx, instrs, node, src_idx, *loc))) return NULL; @@ -343,16 +348,12 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, return NULL; list_add_tail(instrs, &cast->node.entry); - if (!(c = hlsl_new_uint_constant(ctx, dst_offset, loc))) + if (!(store = hlsl_new_store_component(ctx, &block, &var_deref, dst_idx, &cast->node))) return NULL; - list_add_tail(instrs, &c->node.entry); - - if (!(store = hlsl_new_store(ctx, var, &c->node, &cast->node, 0, *loc))) - return NULL; - list_add_tail(instrs, &store->node.entry); + list_move_tail(instrs, &block.instrs); } - if (!(load = hlsl_new_load(ctx, var, NULL, dst_type, *loc))) + if (!(load = hlsl_new_var_load(ctx, var, *loc))) return NULL; list_add_tail(instrs, &load->node.entry); @@ -625,22 +626,13 @@ static struct hlsl_ir_jump *add_return(struct hlsl_ctx *ctx, struct list *instrs static struct hlsl_ir_load *add_load_index(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_node, struct hlsl_ir_node *idx, const struct vkd3d_shader_location loc) { - struct hlsl_type *elem_type; - struct hlsl_ir_node *offset; struct hlsl_ir_load *load; - struct hlsl_block block; - - elem_type = hlsl_get_type_from_path_index(ctx, var_node->data_type, idx); if (var_node->type == HLSL_IR_LOAD) { const struct hlsl_deref *src = &hlsl_ir_load(var_node)->src; - if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, var_node->data_type, src->offset.node, idx, &loc))) - return NULL; - list_move_tail(instrs, &block.instrs); - - if (!(load = hlsl_new_load(ctx, src->var, offset, elem_type, loc))) + if (!(load = hlsl_new_load_index(ctx, src, idx, loc))) return NULL; list_add_tail(instrs, &load->node.entry); } @@ -650,10 +642,6 @@ static struct hlsl_ir_load *add_load_index(struct hlsl_ctx *ctx, struct list *in struct hlsl_ir_var *var; char name[27]; - if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, var_node->data_type, NULL, idx, &loc))) - return NULL; - list_move_tail(instrs, &block.instrs); - sprintf(name, "", var_node); if (!(var = hlsl_new_synthetic_var(ctx, name, var_node->data_type, var_node->loc))) return NULL; @@ -662,7 +650,7 @@ static struct hlsl_ir_load *add_load_index(struct hlsl_ctx *ctx, struct list *in return NULL; list_add_tail(instrs, &store->node.entry); - if (!(load = hlsl_new_load(ctx, var, offset, elem_type, loc))) + if (!(load = hlsl_new_load_index(ctx, &store->lhs, idx, loc))) return NULL; list_add_tail(instrs, &load->node.entry); } @@ -673,38 +661,16 @@ static struct hlsl_ir_load *add_load_index(struct hlsl_ctx *ctx, struct list *in static struct hlsl_ir_load *add_load_component(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_node, unsigned int comp, const struct vkd3d_shader_location loc) { - struct hlsl_type *comp_type; - struct hlsl_ir_node *offset; - struct hlsl_ir_constant *c; struct hlsl_ir_load *load; - unsigned int comp_offset; - struct hlsl_ir_var *var; - - comp_offset = hlsl_compute_component_offset(ctx, var_node->data_type, comp, &comp_type); - - if (!(c = hlsl_new_uint_constant(ctx, comp_offset, &loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); - - offset = &c->node; + struct hlsl_block block; if (var_node->type == HLSL_IR_LOAD) { const struct hlsl_deref *src = &hlsl_ir_load(var_node)->src; - struct hlsl_ir_node *add; - - var = src->var; - if (src->offset.node) - { - if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, src->offset.node, &c->node))) - return NULL; - list_add_tail(instrs, &add->entry); - offset = add; - } - if (!(load = hlsl_new_load(ctx, var, offset, comp_type, loc))) + if (!(load = hlsl_new_load_component(ctx, &block, src, comp, loc))) return NULL; - list_add_tail(instrs, &load->node.entry); + list_move_tail(instrs, &block.instrs); } else { @@ -720,9 +686,9 @@ static struct hlsl_ir_load *add_load_component(struct hlsl_ctx *ctx, struct list return NULL; list_add_tail(instrs, &store->node.entry); - if (!(load = hlsl_new_load(ctx, var, offset, comp_type, loc))) + if (!(load = hlsl_new_load_component(ctx, &block, &store->lhs, comp, loc))) return NULL; - list_add_tail(instrs, &load->node.entry); + list_move_tail(instrs, &block.instrs); } return load; @@ -752,6 +718,7 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_type *mat_type = matrix->data_type, *ret_type; struct vkd3d_string_buffer *name; static unsigned int counter = 0; + struct hlsl_deref var_deref; struct hlsl_ir_load *load; struct hlsl_ir_var *var; unsigned int i; @@ -767,12 +734,14 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, vkd3d_string_buffer_release(&ctx->string_buffers, name); if (!var) return false; + var_deref = hlsl_get_direct_var_deref(var); for (i = 0; i < mat_type->dimx; ++i) { struct hlsl_ir_load *column, *value; struct hlsl_ir_store *store; struct hlsl_ir_constant *c; + struct hlsl_block block; if (!(c = hlsl_new_uint_constant(ctx, i, loc))) return false; @@ -784,9 +753,9 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, if (!(value = add_load_index(ctx, instrs, &column->node, index, *loc))) return false; - if (!(store = hlsl_new_store(ctx, var, &c->node, &value->node, 0, *loc))) + if (!(store = hlsl_new_store_component(ctx, &block, &var_deref, i, &value->node))) return false; - list_add_tail(instrs, &store->node.entry); + list_move_tail(instrs, &block.instrs); } if (!(load = hlsl_new_var_load(ctx, var, *loc))) @@ -1234,6 +1203,7 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, struct vkd3d_string_buffer *name; static unsigned int counter = 0; struct hlsl_type *vector_type; + struct hlsl_deref var_deref; struct hlsl_ir_load *load; struct hlsl_ir_var *var; @@ -1245,6 +1215,7 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, vkd3d_string_buffer_release(&ctx->string_buffers, name); if (!var) return NULL; + var_deref = hlsl_get_direct_var_deref(var); for (i = 0; i < hlsl_type_major_size(type); i++) { @@ -1272,16 +1243,12 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, if (!(value = add_expr(ctx, instrs, op, vector_operands, vector_type, loc))) return NULL; - if (!(c = hlsl_new_uint_constant(ctx, 4 * i, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); - - if (!(store = hlsl_new_store(ctx, var, &c->node, value, 0, *loc))) + if (!(store = hlsl_new_store_index(ctx, &var_deref, &c->node, value, 0, *loc))) return NULL; list_add_tail(instrs, &store->node.entry); } - if (!(load = hlsl_new_load(ctx, var, NULL, type, *loc))) + if (!(load = hlsl_new_var_load(ctx, var, *loc))) return NULL; list_add_tail(instrs, &load->node.entry); @@ -1664,15 +1631,11 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in return NULL; } - if (!(store = hlsl_alloc(ctx, sizeof(*store)))) - return NULL; - while (lhs->type != HLSL_IR_LOAD) { if (lhs->type == HLSL_IR_EXPR && hlsl_ir_expr(lhs)->op == HLSL_OP1_CAST) { hlsl_fixme(ctx, &lhs->loc, "Cast on the LHS."); - vkd3d_free(store); return NULL; } else if (lhs->type == HLSL_IR_SWIZZLE) @@ -1686,13 +1649,11 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in if (!invert_swizzle(&s, &writemask, &width)) { hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, "Invalid writemask."); - vkd3d_free(store); return NULL; } if (!(new_swizzle = hlsl_new_swizzle(ctx, s, width, rhs, &swizzle->node.loc))) { - vkd3d_free(store); return NULL; } list_add_tail(instrs, &new_swizzle->node.entry); @@ -1703,16 +1664,12 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in else { hlsl_error(ctx, &lhs->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, "Invalid lvalue."); - vkd3d_free(store); return NULL; } } - init_node(&store->node, HLSL_IR_STORE, NULL, lhs->loc); - store->writemask = writemask; - store->lhs.var = hlsl_ir_load(lhs)->src.var; - hlsl_src_from_node(&store->lhs.offset, hlsl_ir_load(lhs)->src.offset.node); - hlsl_src_from_node(&store->rhs, rhs); + if (!(store = hlsl_new_store_index(ctx, &hlsl_ir_load(lhs)->src, NULL, rhs, writemask, rhs->loc))) + return NULL; list_add_tail(instrs, &store->node.entry); /* Don't use the instruction itself as a source, as this makes structure @@ -1761,32 +1718,32 @@ static void initialize_var_components(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *dst, unsigned int *store_index, struct hlsl_ir_node *src) { unsigned int src_comp_count = hlsl_type_component_count(src->data_type); + struct hlsl_deref dst_deref = hlsl_get_direct_var_deref(dst); unsigned int k; for (k = 0; k < src_comp_count; ++k) { + unsigned int dst_path_len, *dst_path; struct hlsl_type *dst_comp_type; - unsigned int dst_reg_offset; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; struct hlsl_ir_load *load; struct hlsl_ir_node *conv; + struct hlsl_block block; if (!(load = add_load_component(ctx, instrs, src, k, src->loc))) return; - dst_reg_offset = hlsl_compute_component_offset(ctx, dst->data_type, *store_index, &dst_comp_type); - - if (!(conv = add_implicit_conversion(ctx, instrs, &load->node, dst_comp_type, &src->loc))) + dst_path = hlsl_compute_component_path(ctx, dst->data_type, *store_index, &dst_comp_type, &dst_path_len); + if (dst_path_len && !dst_path) return; + vkd3d_free(dst_path); - if (!(c = hlsl_new_uint_constant(ctx, dst_reg_offset, &src->loc))) + if (!(conv = add_implicit_conversion(ctx, instrs, &load->node, dst_comp_type, &src->loc))) return; - list_add_tail(instrs, &c->node.entry); - if (!(store = hlsl_new_store(ctx, dst, &c->node, conv, 0, src->loc))) + if (!(store = hlsl_new_store_component(ctx, &block, &dst_deref, *store_index, conv))) return; - list_add_tail(instrs, &store->node.entry); + list_move_tail(instrs, &block.instrs); ++*store_index; } @@ -2151,6 +2108,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, unsigned int i, j, k, vect_count = 0; struct vkd3d_string_buffer *name; static unsigned int counter = 0; + struct hlsl_deref var_deref; struct hlsl_ir_load *load; struct hlsl_ir_var *var; @@ -2197,15 +2155,15 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, vkd3d_string_buffer_release(&ctx->string_buffers, name); if (!var) return false; + var_deref = hlsl_get_direct_var_deref(var); for (i = 0; i < matrix_type->dimx; ++i) + { for (j = 0; j < matrix_type->dimy; ++j) { struct hlsl_ir_node *node = NULL; - struct hlsl_type *scalar_type; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; - unsigned int offset; + struct hlsl_block block; for (k = 0; k < cast_type1->dimx && k < cast_type2->dimy; ++k) { @@ -2232,17 +2190,13 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, } } - offset = hlsl_compute_component_offset(ctx, matrix_type, j * matrix_type->dimx + i, &scalar_type); - if (!(c = hlsl_new_uint_constant(ctx, offset, loc))) - return false; - list_add_tail(params->instrs, &c->node.entry); - - if (!(store = hlsl_new_store(ctx, var, &c->node, node, 0, *loc))) + if (!(store = hlsl_new_store_component(ctx, &block, &var_deref, j * matrix_type->dimx + i, node))) return false; - list_add_tail(params->instrs, &store->node.entry); + list_move_tail(params->instrs, &block.instrs); } + } - if (!(load = hlsl_new_load(ctx, var, NULL, matrix_type, *loc))) + if (!(load = hlsl_new_var_load(ctx, var, *loc))) return false; list_add_tail(params->instrs, &load->node.entry); @@ -2478,7 +2432,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl return false; if (!(load = hlsl_new_resource_load(ctx, object_type->e.resource_format, HLSL_RESOURCE_LOAD, - object_load->src.var, object_load->src.offset.node, NULL, NULL, coords, NULL, loc))) + &object_load->src, NULL, coords, NULL, loc))) return false; list_add_tail(instrs, &load->node.entry); return true; @@ -2529,10 +2483,10 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl } if (!(load = hlsl_new_resource_load(ctx, object_type->e.resource_format, - HLSL_RESOURCE_SAMPLE, object_load->src.var, object_load->src.offset.node, - sampler_load->src.var, sampler_load->src.offset.node, coords, offset, loc))) + HLSL_RESOURCE_SAMPLE, &object_load->src, &sampler_load->src, coords, offset, loc))) return false; list_add_tail(instrs, &load->node.entry); + return true; } else if ((!strcmp(name, "Gather") || !strcmp(name, "GatherRed") || !strcmp(name, "GatherBlue") @@ -2633,8 +2587,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl return false; if (!(load = hlsl_new_resource_load(ctx, result_type, - load_type, object_load->src.var, object_load->src.offset.node, - sampler_load->src.var, sampler_load->src.offset.node, coords, offset, loc))) + load_type, &object_load->src, &sampler_load->src, coords, offset, loc))) return false; list_add_tail(instrs, &load->node.entry); return true; diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 373439af..513e599e 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -21,6 +21,75 @@ #include "hlsl.h" #include +/* TODO: remove when no longer needed, only used for transform_deref_paths_into_offsets() */ +static void replace_deref_path_with_offset(struct hlsl_ctx *ctx, struct hlsl_deref *deref, + struct hlsl_ir_node *instr) +{ + struct hlsl_ir_node *offset; + struct hlsl_type *type; + unsigned int i; + + if (!deref->var) + return; + + type = deref->var->data_type; + + /* register offsets shouldn't be used before this point is reached. */ + assert(!deref->offset.node); + + offset = NULL; + + for (i = 0; i < deref->path_len; ++i) + { + struct hlsl_ir_node *block_instr, *block_next; + struct hlsl_block block; + + if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, type, offset, deref->path[i].node, &instr->loc))) + return; + + LIST_FOR_EACH_ENTRY_SAFE(block_instr, block_next, &block.instrs, struct hlsl_ir_node, entry) + { + list_remove(&block_instr->entry); + list_add_before(&instr->entry, &block_instr->entry); + } + + type = hlsl_get_type_from_path_index(ctx, type, deref->path[i].node); + } + + hlsl_free_deref(deref); + hlsl_src_from_node(&deref->offset, offset); +} + +/* TODO: remove when no longer needed. */ +static bool transform_deref_paths_into_offsets(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) +{ + switch(instr->type) + { + case HLSL_IR_LOAD: + { + replace_deref_path_with_offset(ctx, &hlsl_ir_load(instr)->src, instr); + return true; + } + + case HLSL_IR_STORE: + { + replace_deref_path_with_offset(ctx, &hlsl_ir_store(instr)->lhs, instr); + return true; + } + + case HLSL_IR_RESOURCE_LOAD: + { + replace_deref_path_with_offset(ctx, &hlsl_ir_resource_load(instr)->resource, instr); + replace_deref_path_with_offset(ctx, &hlsl_ir_resource_load(instr)->sampler, instr); + return true; + } + + default: + return false; + } + return false; +} + /* Split uniforms into two variables representing the constant and temp * registers, and copy the former to the latter, so that writes to uniforms * work. */ @@ -1890,6 +1959,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry list_move_head(&body->instrs, &ctx->static_initializers); + transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); /* TODO: move forward, remove when no longer needed */ + LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct hlsl_ir_var, scope_entry) { if (var->modifiers & HLSL_STORAGE_UNIFORM) -- 2.34.1