From: Francisco Casas Subject: Re: HLSL offsetting Message-Id: <247ef0a8-7727-ac8e-f04a-e946320dfcb2@codeweavers.com> Date: Sat, 25 Jun 2022 10:05:11 -0400 In-Reply-To: <07dca95c-e258-84bc-be37-dd3236a56ea0@codeweavers.com> References: <6a65d783-32b7-1869-622f-2898f70af302@codeweavers.com> <7cb1f3d1-0d20-1b6a-6328-132d0cd16dcf@codeweavers.com> <62467a7d-3a59-59b8-ef11-ec7b681f7e5d@codeweavers.com> <32508591-b482-cfb2-ef9d-afa0af351552@codeweavers.com> <145424ee-00e6-c6fa-ba80-83a8faadaa1a@codeweavers.com> <0b9be172-5c4a-b846-30b7-7be58d2ec767@codeweavers.com> <54839a65-9285-647f-836d-4eb074c7995f@codeweavers.com> <7bd6d5b0-0114-56d1-ea30-94ebdd830f8a@codeweavers.com> <1baa6160-f472-e80e-1033-b41c00a4fe73@codeweavers.com> <9a60c866-77fb-73cd-0e5d-26fbcff862a6@codeweavers.com> <58124ceb-c80e-14f8-094d-65edf961e6ae@codeweavers.com> <07dca95c-e258-84bc-be37-dd3236a56ea0@codeweavers.com> Aaaand, I forgot to attach 02224576 zfigura vkd3d-shader/hlsl: Store the struct fields as an array. before that one. Sorry. On 25-06-22 00:46, Francisco Casas wrote: > Hello, > > I attach the third version of the previous patch, applying the > suggestions made by Zeb, and some other changes that arose from them. > > The patch is based on the master branch, but I guess I will have to > update it if the recent patches from Giovanni are accepted, before > sending it for review. > > > Best regards, > Francisco. From cee7f65be73ac6f6ac685290c440ff4149b86be0 Mon Sep 17 00:00:00 2001 From: Francisco Casas Date: Tue, 14 Jun 2022 22:13:16 -0400 Subject: [PATCH vkd3d 2/2] vkd3d-shader/hlsl: Replace register offsets with index paths until after split copies. The transform_deref_paths_into_offsets pass turns these index paths back into register offsets, but they are not used anywhere before that. 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. Some remarks: * There should always be 2 indexes in the path for loading a matrix component. One for the row and the other for the column. Using only one would have meant having to add runtime DIV and MOD operations. * The first index in a path after a loading a structshould be an hlsl_ir_constant, since the field that's being addressed is always known at parse-time. * prepend_input_matrix_copy and append_output_matrix_copy need to be aware of whether the matrix are row_major or not, in order to properly copy components to output semantics. * 3 different functions to initialize load/store nodes from different argument types are defined: * One that initializes the node directly for a whole variable. * Another that initializes the node from a another's node deref and up to 2 additional indexes to be appended to that deref. * Finally, one that initializes the node from a variable 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. The signatures of these functions were placed nearby in hlsl.h An alternative that was considered was receiving arrays of nodes as arguments for these functions. However, adding this additional abstraction was discarded to simplify the code. A downside is that synthetic variables are required for each initializer argument and some operations are less vectorized, because they are done component-wise. This expected negative effect in the performance of the resulting programs should be addressed in the future with vectorization and common subexpression elimination passes. * The use of index paths allows to remove the data type when initializing store/loads because it can now be deducted from the variable and the hlsl_deref. * The recursive structure of prepend input copies and append output copies could be preserved using component_offsets, these are in terms of simple basic components within the variable data type. * We may want to consider the removal of writemasks in the HIR at some point. Signed-off-by: Francisco Casas --- libs/vkd3d-shader/hlsl.c | 376 ++++++++++++++++++++----- libs/vkd3d-shader/hlsl.h | 42 ++- libs/vkd3d-shader/hlsl.y | 401 +++++++++++++-------------- libs/vkd3d-shader/hlsl_codegen.c | 461 ++++++++++++++++++++++--------- 4 files changed, 862 insertions(+), 418 deletions(-) diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index b349eb15..3f9b9db9 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -117,7 +117,7 @@ void hlsl_free_var(struct hlsl_ir_var *decl) vkd3d_free(decl); } -static bool hlsl_type_is_row_major(const struct hlsl_type *type) +bool hlsl_type_is_row_major(const struct hlsl_type *type) { /* Default to column-major if the majority isn't explicitly set, which can * happen for anonymous nodes. */ @@ -233,39 +233,50 @@ 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; + path = hlsl_alloc(ctx, 1 * sizeof(unsigned int)); + 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; assert(idx < type->dimx * type->dimy); - if (hlsl_type_is_row_major(type)) - { - minor = x; - major = y; - } - else - { - minor = y; - major = x; - } + /* matrix components must always have paths of lenght 2: row and column */ *comp_type = hlsl_get_scalar_type(ctx, type->base_type); - return 4 * major + minor; + *path_len = 2; + path = hlsl_alloc(ctx, 2 * sizeof(unsigned int)); + path[0] = y; + path[1] = x; + return path; } case HLSL_CLASS_ARRAY: @@ -273,45 +284,54 @@ 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; - - assert(array_idx < type->e.array.elements_count); - - 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); + unsigned int elem_path_len; + unsigned int *elem_path; + + elem_path = hlsl_compute_component_path(ctx, type->e.array.type, idx_in_elem, comp_type, + &elem_path_len); + + *path_len = elem_path_len + 1; + path = hlsl_alloc(ctx, (*path_len) * sizeof(unsigned int)); + 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); + + *path_len = field_path_len + 1; + path = hlsl_alloc(ctx, (*path_len) * sizeof(unsigned int)); + 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_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *basic_type, unsigned int array_size) @@ -610,28 +630,166 @@ static bool type_is_single_reg(const struct hlsl_type *type) return type->type == HLSL_CLASS_SCALAR || type->type == HLSL_CLASS_VECTOR; } -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) +static void deref_copy_append(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other, + struct hlsl_ir_node *node1, struct hlsl_ir_node *node2) { - struct hlsl_ir_store *store; + unsigned int i; - if (!writemask && type_is_single_reg(rhs->data_type)) - writemask = (1 << rhs->data_type->dimx) - 1; + assert(other); + + deref->var = other->var; + deref->path_len = other->path_len + !!node1 + !!node2; + if (!(deref->path = hlsl_alloc(ctx, sizeof(*deref->path) * deref->path_len))) + { + deref->var = NULL; + deref->path_len = 0; + return; + } + for (i = 0; i < other->path_len; ++i) + hlsl_src_from_node(&deref->path[i], other->path[i].node); + if (node1) + hlsl_src_from_node(&deref->path[i++], node1); + if (node2) + hlsl_src_from_node(&deref->path[i++], node2); +} + +static void deref_copy(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct hlsl_deref *other) +{ + if (!other) + { + deref->var = NULL; + deref->path_len = 0; + deref->path = NULL; + return; + } + deref_copy_append(ctx, deref, other, NULL, NULL); +} + +static struct hlsl_type *get_type_from_path_node(struct hlsl_ctx *ctx, const struct hlsl_type *type, + struct hlsl_ir_node *node) +{ + assert(node); + + if (type->type == HLSL_CLASS_VECTOR) + return hlsl_get_scalar_type(ctx, type->base_type); + + /* Matrix components should always be addressed with paths of lenght 2, this is only for convenience. */ + if (type->type == HLSL_CLASS_MATRIX) + return hlsl_get_vector_type(ctx, type->base_type, type->dimx); + + if (type->type == HLSL_CLASS_ARRAY) + return type->e.array.type; + + if (type->type == HLSL_CLASS_STRUCT) + { + struct hlsl_ir_constant *c = hlsl_ir_constant(node); + + assert(c->value[0].u < type->e.record.field_count); + return type->e.record.fields[c->value[0].u].type; + } + + assert(0); + return NULL; +} + +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 = get_type_from_path_node(ctx, type, deref->path[i].node); + return type; +} + +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 *store; if (!(store = hlsl_alloc(ctx, sizeof(*store)))) return NULL; + init_node(&store->node, HLSL_IR_STORE, NULL, rhs->loc); + + store->lhs.var = lhs; + store->lhs.path = NULL; + store->lhs.path_len = 0; + hlsl_src_from_node(&store->rhs, rhs); + + if (type_is_single_reg(rhs->data_type)) + store->writemask = (1 << rhs->data_type->dimx) - 1; + + return store; +} + +struct hlsl_ir_store *hlsl_new_store_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *lhs, + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, struct hlsl_ir_node *rhs, + unsigned int writemask, struct vkd3d_shader_location loc) +{ + struct hlsl_ir_store *store; + + assert(lhs); + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) + return NULL; init_node(&store->node, HLSL_IR_STORE, NULL, loc); - store->lhs.var = var; - hlsl_src_from_node(&store->lhs.offset, offset); + + deref_copy_append(ctx, &store->lhs, lhs, idx1, idx2); 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_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs) +struct hlsl_ir_store *hlsl_new_component_store(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *lhs, + unsigned int comp, struct hlsl_ir_node *rhs) { - return hlsl_new_store(ctx, lhs, NULL, rhs, 0, rhs->loc); + unsigned int *path, path_len, i; + struct hlsl_ir_store *store; + struct hlsl_type *comp_type; + struct hlsl_ir_constant *c; + + list_init(&block->instrs); + + path = hlsl_compute_component_path(ctx, lhs->data_type, comp, &comp_type, &path_len); + + if (!(store = hlsl_alloc(ctx, sizeof(*store)))) + return NULL; + init_node(&store->node, HLSL_IR_STORE, NULL, rhs->loc); + + store->lhs.var = lhs; + store->lhs.path_len = path_len; + if (!(store->lhs.path = hlsl_alloc(ctx, sizeof(*store->lhs.path) * store->lhs.path_len))) + { + vkd3d_free(path); + hlsl_free_instr_list(&block->instrs); + return NULL; + } + + for (i = 0; i < path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, path[i], &rhs->loc))) + { + hlsl_free_instr_list(&block->instrs); + vkd3d_free(path); + return NULL; + } + list_add_tail(&block->instrs, &c->node.entry); + + hlsl_src_from_node(&store->lhs.path[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, @@ -717,29 +875,90 @@ struct hlsl_ir_if *hlsl_new_if(struct hlsl_ctx *ctx, struct hlsl_ir_node *condit return iff; } -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, const struct vkd3d_shader_location loc) +struct hlsl_ir_load *hlsl_new_load_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, struct vkd3d_shader_location loc) { struct hlsl_ir_load *load; + struct hlsl_type *type; + + type = get_type_from_deref(ctx, deref); + assert((type->type == HLSL_CLASS_MATRIX) || !idx2); + if (idx1) + type = get_type_from_path_node(ctx, type, idx1); + if (idx2) + type = get_type_from_path_node(ctx, type, idx2); if (!(load = hlsl_alloc(ctx, sizeof(*load)))) return NULL; init_node(&load->node, HLSL_IR_LOAD, type, loc); - load->src.var = var; - hlsl_src_from_node(&load->src.offset, offset); + deref_copy_append(ctx, &load->src, deref, idx1, idx2); + 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) +{ + struct hlsl_ir_load *load; + + if (!(load = hlsl_alloc(ctx, sizeof(*load)))) + return NULL; + init_node(&load->node, HLSL_IR_LOAD, var->data_type, loc); + + load->src.var = var; + load->src.path = NULL; + load->src.path_len = 0; + + return load; +} + +struct hlsl_ir_load *hlsl_new_component_load(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *var, + unsigned int comp, struct vkd3d_shader_location loc) { - return hlsl_new_load(ctx, var, NULL, var->data_type, loc); + unsigned int *path, path_len, i; + struct hlsl_ir_load *load; + struct hlsl_type *comp_type; + struct hlsl_ir_constant *c; + + list_init(&block->instrs); + + path = hlsl_compute_component_path(ctx, var->data_type, comp, &comp_type, &path_len); + + if (!(load = hlsl_alloc(ctx, sizeof(*load)))) + return NULL; + init_node(&load->node, HLSL_IR_LOAD, comp_type, loc); + + load->src.var = var; + load->src.path_len = path_len; + if (!(load->src.path = hlsl_alloc(ctx, sizeof(*load->src.path) * load->src.path_len))) + { + vkd3d_free(path); + hlsl_free_instr_list(&block->instrs); + return NULL; + } + + for (i = 0; i < path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, path[i], &loc))) + { + hlsl_free_instr_list(&block->instrs); + vkd3d_free(path); + return NULL; + } + list_add_tail(&block->instrs, &c->node.entry); + + hlsl_src_from_node(&load->src.path[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; @@ -747,10 +966,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; @@ -1175,10 +1392,23 @@ static void dump_ir_var(struct hlsl_ctx *ctx, struct vkd3d_string_buffer *buffer static void dump_deref(struct vkd3d_string_buffer *buffer, const struct hlsl_deref *deref) { + unsigned int i; + if (deref->var) { vkd3d_string_buffer_printf(buffer, "%s", deref->var->name); - if (deref->offset.node) + if (deref->path_len) + { + vkd3d_string_buffer_printf(buffer, "["); + 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, "]"); + } + else if (deref->offset.node) /* TODO: remove */ { vkd3d_string_buffer_printf(buffer, "["); dump_src(buffer, &deref->offset); @@ -1539,6 +1769,20 @@ void hlsl_free_instr_list(struct list *list) hlsl_free_instr(node); } +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); /* TODO: remove when no longer needed */ +} + static void free_ir_constant(struct hlsl_ir_constant *constant) { vkd3d_free(constant); @@ -1568,7 +1812,7 @@ static void free_ir_jump(struct hlsl_ir_jump *jump) static void free_ir_load(struct hlsl_ir_load *load) { - hlsl_src_remove(&load->src.offset); + hlsl_free_deref(&load->src); vkd3d_free(load); } @@ -1581,8 +1825,8 @@ static void free_ir_loop(struct hlsl_ir_loop *loop) static void free_ir_resource_load(struct hlsl_ir_resource_load *load) { hlsl_src_remove(&load->coords); - hlsl_src_remove(&load->sampler.offset); - hlsl_src_remove(&load->resource.offset); + hlsl_free_deref(&load->sampler); + hlsl_free_deref(&load->resource); hlsl_src_remove(&load->texel_offset); vkd3d_free(load); } @@ -1590,7 +1834,7 @@ static void free_ir_resource_load(struct hlsl_ir_resource_load *load) static void free_ir_store(struct hlsl_ir_store *store) { hlsl_src_remove(&store->rhs); - hlsl_src_remove(&store->lhs.offset); + hlsl_free_deref(&store->lhs); vkd3d_free(store); } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 661822f7..07ea0280 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -374,7 +374,11 @@ struct hlsl_ir_swizzle struct hlsl_deref { struct hlsl_ir_var *var; - struct hlsl_src offset; + + unsigned int path_len; + struct hlsl_src *path; + + struct hlsl_src offset; /* TODO: remove. */ }; struct hlsl_ir_load @@ -719,6 +723,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new); +void hlsl_free_deref(struct hlsl_deref *deref); + void hlsl_free_instr(struct hlsl_ir_node *node); void hlsl_free_instr_list(struct list *list); void hlsl_free_type(struct hlsl_type *type); @@ -745,16 +751,25 @@ 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_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_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_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref, + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, struct vkd3d_shader_location loc); +struct hlsl_ir_load *hlsl_new_component_load(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *var, + 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(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_ir_store *hlsl_new_store_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *lhs, + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, struct hlsl_ir_node *rhs, + unsigned int writemask, struct vkd3d_shader_location loc); +struct hlsl_ir_store *hlsl_new_component_store(struct hlsl_ctx *ctx, struct hlsl_block *block, struct hlsl_ir_var *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_loop *hlsl_new_loop(struct hlsl_ctx *ctx, struct vkd3d_shader_location loc); struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct hlsl_struct_field *fields, size_t field_count); struct hlsl_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components, @@ -769,8 +784,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); @@ -790,8 +803,9 @@ 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_get_sm4_offset(const struct hlsl_type *type, unsigned int offset); bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2); diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index 81307af0..3061f1b8 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -273,12 +273,13 @@ static bool implicit_compatible_data_types(struct hlsl_type *t1, struct hlsl_typ } static struct hlsl_ir_load *add_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_node, - struct hlsl_ir_node *offset, struct hlsl_type *data_type, const struct vkd3d_shader_location loc); + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, const struct vkd3d_shader_location loc); static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *node, struct hlsl_type *dst_type, const struct vkd3d_shader_location *loc) { struct hlsl_type *src_type = node->data_type; + struct hlsl_type *dst_scalar_type = hlsl_get_scalar_type(ctx, dst_type->base_type); struct hlsl_ir_expr *cast; if (hlsl_types_are_equal(src_type, dst_type)) @@ -289,9 +290,10 @@ 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_ir_constant *c; struct hlsl_ir_load *load; struct hlsl_ir_var *var; - unsigned int dst_idx; + unsigned int y, x; bool broadcast; broadcast = src_type->dimx == 1 && src_type->dimy == 1; @@ -309,58 +311,79 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, if (!var) return NULL; - for (dst_idx = 0; dst_idx < dst_type->dimx * dst_type->dimy; ++dst_idx) + for (y = 0; y < dst_type->dimy; ++y) { - struct hlsl_type *src_scalar_type, *dst_scalar_type; - unsigned int src_idx, src_offset, dst_offset; - struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; - - if (broadcast) + for (x = 0; x < dst_type->dimx; ++x) { - src_idx = 0; - } - else - { - if (src_type->type == HLSL_CLASS_MATRIX && dst_type->type == HLSL_CLASS_MATRIX) + struct hlsl_ir_node *src_idx1 = NULL, *src_idx2 = NULL; + struct hlsl_ir_store *store; + struct hlsl_block block; + + if (broadcast) + { + if (src_type->type == HLSL_CLASS_VECTOR || src_type->type == HLSL_CLASS_MATRIX) + { + if (!(c = hlsl_new_uint_constant(ctx, 0, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx1 = &c->node; + if (src_type->type == HLSL_CLASS_MATRIX) + src_idx2 = &c->node; + } + } + else if (dst_type->type == HLSL_CLASS_MATRIX && src_type->type == HLSL_CLASS_MATRIX) { - unsigned int x = dst_idx % dst_type->dimx, y = dst_idx / dst_type->dimx; + if (!(c = hlsl_new_uint_constant(ctx, y, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx1 = &c->node; - src_idx = y * src_type->dimx + x; + if (!(c = hlsl_new_uint_constant(ctx, x, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx2 = &c->node; } else { - src_idx = dst_idx; + unsigned int src_idx = dst_type->dimx * y + x; + + if (src_type->type == HLSL_CLASS_MATRIX) + { + if (!(c = hlsl_new_uint_constant(ctx, src_idx / src_type->dimx, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx1 = &c->node; + + if (!(c = hlsl_new_uint_constant(ctx, src_idx % src_type->dimx, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx2 = &c->node; + } + else if (src_type->type == HLSL_CLASS_VECTOR) + { + if (!(c = hlsl_new_uint_constant(ctx, src_idx % src_type->dimx, loc))) + return NULL; + list_add_tail(instrs, &c->node.entry); + src_idx1 = &c->node; + } } - } - - dst_offset = hlsl_compute_component_offset(ctx, dst_type, dst_idx, &dst_scalar_type); - src_offset = hlsl_compute_component_offset(ctx, src_type, src_idx, &src_scalar_type); - - if (!(c = hlsl_new_uint_constant(ctx, src_offset, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); - - if (!(load = add_load(ctx, instrs, node, &c->node, src_scalar_type, *loc))) - return NULL; - if (!(cast = hlsl_new_cast(ctx, &load->node, dst_scalar_type, loc))) - return NULL; - list_add_tail(instrs, &cast->node.entry); + if (!(load = add_load(ctx, instrs, node, src_idx1, src_idx2, *loc))) + return NULL; - if (!(c = hlsl_new_uint_constant(ctx, dst_offset, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); + if (!(cast = hlsl_new_cast(ctx, &load->node, dst_scalar_type, loc))) + return NULL; + list_add_tail(instrs, &cast->node.entry); - if (!(store = hlsl_new_store(ctx, var, &c->node, &cast->node, 0, *loc))) - return NULL; - list_add_tail(instrs, &store->node.entry); + if (!(store = hlsl_new_component_store(ctx, &block, var, y * dst_type->dimx + x, &cast->node))) + return NULL; + 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); - return &load->node; } else @@ -628,28 +651,22 @@ static struct hlsl_ir_jump *add_return(struct hlsl_ctx *ctx, struct list *instrs } static struct hlsl_ir_load *add_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *var_node, - struct hlsl_ir_node *offset, struct hlsl_type *data_type, const struct vkd3d_shader_location loc) + struct hlsl_ir_node *idx1, struct hlsl_ir_node *idx2, const struct vkd3d_shader_location loc) { - struct hlsl_ir_node *add = NULL; struct hlsl_ir_load *load; - struct hlsl_ir_var *var; if (var_node->type == HLSL_IR_LOAD) { const struct hlsl_deref *src = &hlsl_ir_load(var_node)->src; - var = src->var; - if (src->offset.node) - { - if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, src->offset.node, offset))) - return NULL; - list_add_tail(instrs, &add->entry); - offset = add; - } + if (!(load = hlsl_new_load_from_deref(ctx, src, idx1, idx2, loc))) + return NULL; + list_add_tail(instrs, &load->node.entry); } else { struct hlsl_ir_store *store; + struct hlsl_ir_var *var; char name[27]; sprintf(name, "", var_node); @@ -658,26 +675,29 @@ static struct hlsl_ir_load *add_load(struct hlsl_ctx *ctx, struct list *instrs, if (!(store = hlsl_new_simple_store(ctx, var, var_node))) return NULL; - list_add_tail(instrs, &store->node.entry); + + if (!(load = hlsl_new_load_from_deref(ctx, &store->lhs, idx1, idx2, loc))) + return NULL; + list_add_tail(instrs, &load->node.entry); } - if (!(load = hlsl_new_load(ctx, var, offset, data_type, loc))) - return NULL; - list_add_tail(instrs, &load->node.entry); return load; } static bool add_record_load(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_node *record, - const struct hlsl_struct_field *field, const struct vkd3d_shader_location loc) + const struct hlsl_struct_field *field, unsigned int field_indx, const struct vkd3d_shader_location loc) { struct hlsl_ir_constant *c; - if (!(c = hlsl_new_uint_constant(ctx, field->reg_offset, &loc))) + if (!(c = hlsl_new_uint_constant(ctx, field_indx, &loc))) return false; list_add_tail(instrs, &c->node.entry); - return !!add_load(ctx, instrs, record, &c->node, field->type, loc); + if (!add_load(ctx, instrs, record, &c->node, NULL, loc)) + return false; + + return true; } static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, struct list *instrs, @@ -688,35 +708,9 @@ static struct hlsl_ir_node *add_matrix_scalar_load(struct hlsl_ctx *ctx, struct struct hlsl_ir_node *matrix, struct hlsl_ir_node *x, struct hlsl_ir_node *y, const struct vkd3d_shader_location *loc) { - struct hlsl_ir_node *major, *minor, *mul, *add; - struct hlsl_ir_constant *four; struct hlsl_ir_load *load; - struct hlsl_type *type = matrix->data_type, *scalar_type; - - scalar_type = hlsl_get_scalar_type(ctx, type->base_type); - - if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR) - { - minor = x; - major = y; - } - else - { - minor = y; - major = x; - } - if (!(four = hlsl_new_uint_constant(ctx, 4, loc))) - return NULL; - list_add_tail(instrs, &four->node.entry); - - if (!(mul = add_binary_arithmetic_expr(ctx, instrs, HLSL_OP2_MUL, &four->node, major, loc))) - return NULL; - - if (!(add = add_binary_arithmetic_expr(ctx, instrs, HLSL_OP2_ADD, mul, minor, loc))) - return NULL; - - if (!(load = add_load(ctx, instrs, matrix, add, scalar_type, *loc))) + if (!(load = add_load(ctx, instrs, matrix, y, x, *loc))) return NULL; return &load->node; @@ -746,6 +740,7 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_store *store; struct hlsl_ir_node *value; struct hlsl_ir_constant *c; + struct hlsl_block block; if (!(c = hlsl_new_uint_constant(ctx, i, loc))) return false; @@ -754,9 +749,9 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, struct list *instrs, if (!(value = add_matrix_scalar_load(ctx, instrs, matrix, &c->node, index, loc))) return false; - if (!(store = hlsl_new_store(ctx, var, &c->node, value, 0, *loc))) + if (!(store = hlsl_new_component_store(ctx, &block, var, i, value))) return false; - list_add_tail(instrs, &store->node.entry); + list_move_tail(instrs, &block.instrs); } if (!(load = hlsl_new_var_load(ctx, var, *loc))) @@ -770,30 +765,11 @@ static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hls struct hlsl_ir_node *index, const struct vkd3d_shader_location loc) { const struct hlsl_type *expr_type = array->data_type; - struct hlsl_type *data_type; - struct hlsl_ir_constant *c; - - if (expr_type->type == HLSL_CLASS_ARRAY) - { - data_type = expr_type->e.array.type; - if (!(c = hlsl_new_uint_constant(ctx, hlsl_type_get_array_element_reg_size(data_type), &loc))) - return false; - list_add_tail(instrs, &c->node.entry); - - if (!(index = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, index, &c->node))) - return false; - list_add_tail(instrs, &index->entry); - } - else if (expr_type->type == HLSL_CLASS_MATRIX) - { + if (expr_type->type == HLSL_CLASS_MATRIX) return add_matrix_index(ctx, instrs, array, index, &loc); - } - else if (expr_type->type == HLSL_CLASS_VECTOR) - { - data_type = hlsl_get_scalar_type(ctx, expr_type->base_type); - } - else + + if (expr_type->type != HLSL_CLASS_ARRAY && expr_type->type != HLSL_CLASS_VECTOR) { if (expr_type->type == HLSL_CLASS_SCALAR) hlsl_error(ctx, &loc, VKD3D_SHADER_ERROR_HLSL_INVALID_INDEX, "Scalar expressions cannot be array-indexed."); @@ -802,18 +778,25 @@ static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hls return false; } - return !!add_load(ctx, instrs, array, index, data_type, loc); + if (!add_load(ctx, instrs, array, index, NULL, loc)) + return false; + + return true; } static const struct hlsl_struct_field *get_struct_field(const struct hlsl_struct_field *fields, - size_t count, const char *name) + size_t count, const char *name, unsigned int *field_indx) { size_t i; for (i = 0; i < count; ++i) { if (!strcmp(fields[i].name, name)) + { + if (field_indx) + *field_indx = i; return &fields[i]; + } } return NULL; } @@ -1204,38 +1187,33 @@ static bool expr_common_shape(struct hlsl_ctx *ctx, struct hlsl_type *t1, struct return true; } -static unsigned int minor_size(const struct hlsl_type *type) -{ - if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR) - return type->dimx; - else - return type->dimy; -} - -static unsigned int major_size(const struct hlsl_type *type) -{ - if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR) - return type->dimy; - else - return type->dimx; -} - static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, enum hlsl_ir_expr_op op, struct hlsl_ir_node *operands[HLSL_MAX_OPERANDS], struct hlsl_type *type, const struct vkd3d_shader_location *loc) { struct hlsl_ir_expr *expr; - unsigned int i; + unsigned int y, x, i, j; if (type->type == HLSL_CLASS_MATRIX) { + struct hlsl_ir_constant *cs[4] = { NULL }; struct vkd3d_string_buffer *name; static unsigned int counter = 0; - struct hlsl_type *vector_type; + struct hlsl_type *scalar_type; struct hlsl_ir_load *load; struct hlsl_ir_var *var; - vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + scalar_type = hlsl_get_scalar_type(ctx, type->base_type); + + for (i = 0; i < 4; i++) + { + if (i >= type->dimx && i >= type->dimy) + break; + + if (!(cs[i] = hlsl_new_uint_constant(ctx, i, loc))) + return NULL; + list_add_tail(instrs, &cs[i]->node.entry); + } name = vkd3d_string_buffer_get(&ctx->string_buffers); vkd3d_string_buffer_printf(name, "", counter++); @@ -1244,41 +1222,41 @@ static struct hlsl_ir_node *add_expr(struct hlsl_ctx *ctx, struct list *instrs, if (!var) return NULL; - for (i = 0; i < major_size(type); i++) + for (y = 0; y < type->dimy; ++y) { - struct hlsl_ir_node *value, *vector_operands[HLSL_MAX_OPERANDS] = { NULL }; - struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; - unsigned int j; - - if (!(c = hlsl_new_uint_constant(ctx, 4 * i, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); - - for (j = 0; j < HLSL_MAX_OPERANDS; j++) + for (x = 0; x < type->dimx; ++x) { - if (operands[j]) + struct hlsl_ir_node *value, *scalar_operands[HLSL_MAX_OPERANDS] = { NULL }; + struct hlsl_ir_store *store; + struct hlsl_block block; + + for (j = 0; j < HLSL_MAX_OPERANDS; j++) { - struct hlsl_type *vector_arg_type; - struct hlsl_ir_load *load; + if (operands[j]) + { + struct hlsl_ir_load *load; - vector_arg_type = hlsl_get_vector_type(ctx, operands[j]->data_type->base_type, minor_size(type)); + assert(operands[j]->data_type->type == HLSL_CLASS_MATRIX); + assert(operands[j]->data_type->dimy == type->dimy); + assert(operands[j]->data_type->dimx == type->dimx); - if (!(load = add_load(ctx, instrs, operands[j], &c->node, vector_arg_type, *loc))) - return NULL; - vector_operands[j] = &load->node; + if (!(load = add_load(ctx, instrs, operands[j], &cs[y]->node, &cs[x]->node, *loc))) + return NULL; + + scalar_operands[j] = &load->node; + } } - } - if (!(value = add_expr(ctx, instrs, op, vector_operands, vector_type, loc))) - return NULL; + if (!(value = add_expr(ctx, instrs, op, scalar_operands, scalar_type, loc))) + return NULL; - if (!(store = hlsl_new_store(ctx, var, &c->node, value, 0, *loc))) - return NULL; - list_add_tail(instrs, &store->node.entry); + if (!(store = hlsl_new_component_store(ctx, &block, var, y * type->dimx + x, value))) + return NULL; + list_move_tail(instrs, &block.instrs); + } } - 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); @@ -1606,15 +1584,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) @@ -1628,13 +1602,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); @@ -1645,16 +1617,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_from_deref(ctx, &hlsl_ir_load(lhs)->src, NULL, 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 @@ -1703,37 +1671,45 @@ 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 vkd3d_string_buffer *name; + static unsigned int counter = 0; + struct hlsl_ir_store *store; + struct hlsl_ir_var *var; unsigned int k; + name = vkd3d_string_buffer_get(&ctx->string_buffers); + vkd3d_string_buffer_printf(name, "", counter++); + var = hlsl_new_synthetic_var(ctx, name->buffer, src->data_type, src->loc); + vkd3d_string_buffer_release(&ctx->string_buffers, name); + if (!var) + return; + + if(!(store = hlsl_new_simple_store(ctx, var, src))) + return; + list_add_tail(instrs, &store->node.entry); + for (k = 0; k < src_comp_count; ++k) { - struct hlsl_type *dst_comp_type, *src_comp_type; - unsigned int dst_reg_offset, src_reg_offset; + unsigned int dst_path_len, *dst_path; + struct hlsl_type *dst_comp_type; struct hlsl_ir_store *store; - struct hlsl_ir_constant *c; struct hlsl_ir_load *load; struct hlsl_ir_node *conv; + struct hlsl_block block; - dst_reg_offset = hlsl_compute_component_offset(ctx, dst->data_type, *store_index, &dst_comp_type); - src_reg_offset = hlsl_compute_component_offset(ctx, src->data_type, k, &src_comp_type); - - if (!(c = hlsl_new_uint_constant(ctx, src_reg_offset, &src->loc))) + if (!(load = hlsl_new_component_load(ctx, &block, var, k, src->loc))) return; - list_add_tail(instrs, &c->node.entry); + list_move_tail(instrs, &block.instrs); - if (!(load = add_load(ctx, instrs, src, &c->node, src_comp_type, src->loc))) - return; + dst_path = hlsl_compute_component_path(ctx, dst->data_type, *store_index, &dst_comp_type, &dst_path_len); + vkd3d_free(dst_path); if (!(conv = add_implicit_conversion(ctx, instrs, &load->node, dst_comp_type, &src->loc))) return; - if (!(c = hlsl_new_uint_constant(ctx, dst_reg_offset, &src->loc))) + if (!(store = hlsl_new_component_store(ctx, &block, dst, *store_index, conv))) return; - list_add_tail(instrs, &c->node.entry); - - if (!(store = hlsl_new_store(ctx, dst, &c->node, conv, 0, src->loc))) - return; - list_add_tail(instrs, &store->node.entry); + list_move_tail(instrs, &block.instrs); ++*store_index; } @@ -2055,6 +2031,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, struct hlsl_ir_node *arg1 = params->args[0], *arg2 = params->args[1], *cast1, *cast2; enum hlsl_base_type base = expr_common_base_type(arg1->data_type->base_type, arg2->data_type->base_type); struct hlsl_type *cast_type1 = arg1->data_type, *cast_type2 = arg2->data_type, *matrix_type, *ret_type; + struct hlsl_ir_constant *cs[4] = { NULL }; unsigned int i, j, k, vect_count = 0; struct vkd3d_string_buffer *name; static unsigned int counter = 0; @@ -2105,34 +2082,33 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx, if (!var) return false; + for (i = 0; i < 4; i++) + { + if (i >= matrix_type->dimx && i >= matrix_type->dimy && (i >= cast_type1->dimx || i >= cast_type2->dimy)) + break; + + if (!(cs[i] = hlsl_new_uint_constant(ctx, i, loc))) + return NULL; + list_add_tail(params->instrs, &cs[i]->node.entry); + } + 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) { struct hlsl_ir_load *value1, *value2; struct hlsl_ir_node *mul; - offset = hlsl_compute_component_offset(ctx, cast_type1, j * cast_type1->dimx + k, &scalar_type); - if (!(c = hlsl_new_uint_constant(ctx, offset, loc))) + if (!(value1 = add_load(ctx, params->instrs, cast1, &cs[j]->node, &cs[k]->node, *loc))) return false; - list_add_tail(params->instrs, &c->node.entry); - if (!(value1 = add_load(ctx, params->instrs, cast1, &c->node, scalar_type, *loc))) - return false; - - offset = hlsl_compute_component_offset(ctx, cast_type2, k * cast_type2->dimx + i, &scalar_type); - if (!(c = hlsl_new_uint_constant(ctx, offset, loc))) - return false; - list_add_tail(params->instrs, &c->node.entry); - - if (!(value2 = add_load(ctx, params->instrs, cast2, &c->node, scalar_type, *loc))) + if (!(value2 = add_load(ctx, params->instrs, cast2, &cs[k]->node, &cs[i]->node, *loc))) return false; if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, &value1->node, &value2->node, loc))) @@ -2149,17 +2125,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_component_store(ctx, &block, var, 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); @@ -2392,7 +2364,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; @@ -2443,10 +2415,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") @@ -2547,8 +2519,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; @@ -2949,10 +2920,9 @@ fields_list: for (i = 0; i < $2.count; ++i) { - const struct hlsl_struct_field *field = &$2.fields[i]; - const struct hlsl_struct_field *existing; + const struct hlsl_struct_field *field = &$2.fields[i], *existing; - if ((existing = get_struct_field($1.fields, $1.count, field->name))) + if ((existing = get_struct_field($1.fields, $1.count, field->name, NULL))) { hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, "Field \"%s\" is already defined.", field->name); @@ -3850,14 +3820,15 @@ postfix_expr: { struct hlsl_type *type = node->data_type; const struct hlsl_struct_field *field; + unsigned int field_indx; - if (!(field = get_struct_field(type->e.record.fields, type->e.record.field_count, $3))) + if (!(field = get_struct_field(type->e.record.fields, type->e.record.field_count, $3, &field_indx))) { hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Field \"%s\" is not defined.", $3); YYABORT; } - if (!add_record_load(ctx, $1, node, field, @2)) + if (!add_record_load(ctx, $1, node, field, field_indx, @2)) YYABORT; $$ = $1; } diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 00743bf6..35ba1186 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -23,7 +23,7 @@ static unsigned int minor_size(const struct hlsl_type *type) { - if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR) + if (hlsl_type_is_row_major(type)) return type->dimx; else return type->dimy; @@ -31,12 +31,164 @@ static unsigned int minor_size(const struct hlsl_type *type) static unsigned int major_size(const struct hlsl_type *type) { - if (type->modifiers & HLSL_MODIFIER_ROW_MAJOR) + if (hlsl_type_is_row_major(type)) return type->dimy; else return type->dimx; } +/* 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_ir_constant *c; + struct hlsl_type *type; + unsigned int i; + + if (!deref->var) + return; + + type = deref->var->data_type; + + /* Only paths should be used until this point is reached. */ + assert(!deref->offset.node); + + if (!(c = hlsl_new_uint_constant(ctx, 0, &instr->loc))) + return; + list_add_before(&instr->entry, &c->node.entry); + offset = &c->node; + + for (i = 0; i < deref->path_len; ++i) + { + if (type->type == HLSL_CLASS_STRUCT) + { + unsigned int field_i = hlsl_ir_constant(deref->path[i].node)->value[0].u; + struct hlsl_ir_constant *field_offset; + const struct hlsl_struct_field *field; + + field = &type->e.record.fields[field_i]; + + if (!(field_offset = hlsl_new_uint_constant(ctx, field->reg_offset, &instr->loc))) + return; + list_add_before(&instr->entry, &field_offset->node.entry); + + if (!(offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, &field_offset->node))) + return; + list_add_before(&instr->entry, &offset->entry); + + type = field->type; + } + else if (type->type == HLSL_CLASS_ARRAY) + { + unsigned int size = hlsl_type_get_array_element_reg_size(type->e.array.type); + struct hlsl_ir_constant *elem_size; + struct hlsl_ir_node *elem_offset; + + if (!(elem_size = hlsl_new_uint_constant(ctx, size, &instr->loc))) + return; + list_add_before(&instr->entry, &elem_size->node.entry); + + if (!(elem_offset = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, deref->path[i].node, &elem_size->node))) + return; + list_add_before(&instr->entry, &elem_offset->entry); + + if (!(offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, elem_offset))) + return; + list_add_before(&instr->entry, &offset->entry); + + type = type->e.array.type; + } + else if (type->type == HLSL_CLASS_MATRIX) + { + struct hlsl_ir_node *major, *minor, *mult, *add; + struct hlsl_ir_constant *c; + + /* matrix components must always have paths of lenght 2: row and column */ + assert(i == deref->path_len - 2); + + if (hlsl_type_is_row_major(type)) + { + major = deref->path[i].node; + minor = deref->path[i + 1].node; + } + else + { + major = deref->path[i + 1].node; + minor = deref->path[i].node; + } + + if (!(c = hlsl_new_uint_constant(ctx, 4, &instr->loc))) + return; + list_add_before(&instr->entry, &c->node.entry); + + if (!(mult = hlsl_new_binary_expr(ctx, HLSL_OP2_MUL, &c->node, major))) + return; + list_add_before(&instr->entry, &mult->entry); + + if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, mult, minor))) + return; + list_add_before(&instr->entry, &add->entry); + + if (!(offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, add))) + return; + list_add_before(&instr->entry, &offset->entry); + + break; + } + else if (type->type == HLSL_CLASS_VECTOR) + { + assert(i == deref->path_len - 1); + if (!(offset = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, offset, deref->path[i].node))) + return; + list_add_before(&instr->entry, &offset->entry); + + break; + } + else + { + hlsl_error(ctx, &instr->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_TYPE, + "deref path for class %u.", type->type); + return; + } + } + + hlsl_free_deref(deref); + hlsl_src_from_node(&deref->offset, offset); +} + +/* Transforms hlsl_deref paths into offsets. + * The idea is to finally delete it once we achieve the SMxIR translations. + */ +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. */ @@ -74,68 +226,110 @@ static void prepend_uniform_copy(struct hlsl_ctx *ctx, struct list *instrs, stru list_add_after(&load->node.entry, &store->node.entry); } -static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, - struct hlsl_type *type, unsigned int field_offset, unsigned int modifiers, const struct hlsl_semantic *semantic) +static struct hlsl_ir_var *add_extern_var(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int modifiers, const struct hlsl_semantic *semantic, bool output) { - struct vkd3d_string_buffer *name; struct hlsl_semantic new_semantic; - struct hlsl_ir_constant *offset; - struct hlsl_ir_store *store; - struct hlsl_ir_load *load; - struct hlsl_ir_var *input; - - if (type->type == HLSL_CLASS_MATRIX) - { - struct hlsl_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); - struct hlsl_semantic vector_semantic = *semantic; - unsigned int i; - - for (i = 0; i < major_size(type); ++i) - { - prepend_input_copy(ctx, instrs, var, vector_type, 4 * i, modifiers, &vector_semantic); - ++vector_semantic.index; - } - - return; - } + struct vkd3d_string_buffer *name; + struct hlsl_ir_var *ext_var; if (!(name = hlsl_get_string_buffer(ctx))) - return; - vkd3d_string_buffer_printf(name, "", semantic->name, semantic->index); + return NULL; + vkd3d_string_buffer_printf(name, "<%s-%s%u>", output? "output" : "input", semantic->name, semantic->index); if (!(new_semantic.name = hlsl_strdup(ctx, semantic->name))) { hlsl_release_string_buffer(ctx, name); - return; + return NULL; } new_semantic.index = semantic->index; - if (!(input = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), + if (!(ext_var = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), type, var->loc, &new_semantic, modifiers, NULL))) { hlsl_release_string_buffer(ctx, name); vkd3d_free((void *)new_semantic.name); - return; + return NULL; } hlsl_release_string_buffer(ctx, name); - input->is_input_semantic = 1; - input->is_param = var->is_param; - list_add_before(&var->scope_entry, &input->scope_entry); - list_add_tail(&ctx->extern_vars, &input->extern_entry); + if (output) + ext_var->is_output_semantic = 1; + else + ext_var->is_input_semantic = 1; + ext_var->is_param = var->is_param; + list_add_before(&var->scope_entry, &ext_var->scope_entry); + list_add_tail(&ctx->extern_vars, &ext_var->extern_entry); - if (!(load = hlsl_new_var_load(ctx, input, var->loc))) - return; - list_add_head(instrs, &load->node.entry); + return ext_var; +} - if (!(offset = hlsl_new_uint_constant(ctx, field_offset, &var->loc))) - return; - list_add_after(&load->node.entry, &offset->node.entry); +static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int component_offset, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + unsigned int component_count = hlsl_type_component_count(type); + struct hlsl_ir_var *input; + unsigned int i; - if (!(store = hlsl_new_store(ctx, var, &offset->node, &load->node, 0, var->loc))) + if (!(input = add_extern_var(ctx, var, type, modifiers, semantic, false))) return; - list_add_after(&offset->node.entry, &store->node.entry); + + for (i = 0; i < component_count; ++i) + { + struct hlsl_block block1, block2; + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + + if (!(load = hlsl_new_component_load(ctx, &block1, input, i, var->loc))) + return; + + if (!(store = hlsl_new_component_store(ctx, &block2, var, component_offset + i, &load->node))) + return; + + list_move_head(instrs, &block2.instrs); + list_move_head(instrs, &block1.instrs); + } +} + +static void prepend_input_matrix_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int component_offset, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + struct hlsl_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + bool row_major = hlsl_type_is_row_major(type); + unsigned int i, j; + + assert(type->type == HLSL_CLASS_MATRIX); + + for (i = 0; i < major_size(type); ++i) + { + struct hlsl_semantic semantic_copy = *semantic; + struct hlsl_ir_var *input; + + semantic_copy.index = semantic->index + i; + + if (!(input = add_extern_var(ctx, var, vector_type, modifiers, &semantic_copy, false))) + return; + + for (j = 0; j < minor_size(type); ++j) + { + unsigned int cell = row_major? (i * type->dimx + j) : (j * type->dimx + i); + struct hlsl_block block1, block2; + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + + if (!(load = hlsl_new_component_load(ctx, &block1, input, j, var->loc))) + return; + + if (!(store = hlsl_new_component_store(ctx, &block2, var, component_offset + cell, &load->node))) + return; + + list_move_head(instrs, &block2.instrs); + list_move_head(instrs, &block1.instrs); + } + } } static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, - struct hlsl_type *type, unsigned int field_offset) + struct hlsl_type *type, unsigned int component_offset) { size_t i; @@ -144,13 +338,16 @@ static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, const struct hlsl_struct_field *field = &type->e.record.fields[i]; if (field->type->type == HLSL_CLASS_STRUCT) - prepend_input_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); + prepend_input_struct_copy(ctx, instrs, var, field->type, component_offset); + else if (field->type->type == HLSL_CLASS_MATRIX) + prepend_input_matrix_copy(ctx, instrs, var, field->type, component_offset, field->modifiers, &field->semantic); else if (field->semantic.name) - prepend_input_copy(ctx, instrs, var, field->type, - field_offset + field->reg_offset, field->modifiers, &field->semantic); + prepend_input_copy(ctx, instrs, var, field->type, component_offset, field->modifiers, &field->semantic); else hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, "Field '%s' is missing a semantic.", field->name); + + component_offset += hlsl_type_component_count(field->type); } } @@ -160,72 +357,79 @@ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st { if (var->data_type->type == HLSL_CLASS_STRUCT) prepend_input_struct_copy(ctx, instrs, var, var->data_type, 0); + else if (var->data_type->type == HLSL_CLASS_MATRIX) + prepend_input_matrix_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); else if (var->semantic.name) prepend_input_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); } static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, - struct hlsl_type *type, unsigned int field_offset, unsigned int modifiers, const struct hlsl_semantic *semantic) + struct hlsl_type *type, unsigned int component_offset, unsigned int modifiers, + const struct hlsl_semantic *semantic) { - struct vkd3d_string_buffer *name; - struct hlsl_semantic new_semantic; - struct hlsl_ir_constant *offset; - struct hlsl_ir_store *store; + unsigned int component_count = hlsl_type_component_count(type); struct hlsl_ir_var *output; - struct hlsl_ir_load *load; + unsigned int i; + + if (!(output = add_extern_var(ctx, var, type, modifiers, semantic, true))) + return; - if (type->type == HLSL_CLASS_MATRIX) + for (i = 0; i < component_count; ++i) { - struct hlsl_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); - struct hlsl_semantic vector_semantic = *semantic; - unsigned int i; + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + struct hlsl_block block; - for (i = 0; i < major_size(type); ++i) - { - append_output_copy(ctx, instrs, var, vector_type, 4 * i, modifiers, &vector_semantic); - ++vector_semantic.index; - } + if (!(load = hlsl_new_component_load(ctx, &block, var, component_offset + i, var->loc))) + return; + list_move_tail(instrs, &block.instrs); - return; + if (!(store = hlsl_new_component_store(ctx, &block, output, i, &load->node))) + return; + list_move_tail(instrs, &block.instrs); } +} - if (!(name = hlsl_get_string_buffer(ctx))) - return; - vkd3d_string_buffer_printf(name, "", semantic->name, semantic->index); - if (!(new_semantic.name = hlsl_strdup(ctx, semantic->name))) - { - hlsl_release_string_buffer(ctx, name); - return; - } - new_semantic.index = semantic->index; - if (!(output = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), - type, var->loc, &new_semantic, modifiers, NULL))) +static void append_output_matrix_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, unsigned int component_offset, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + struct hlsl_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + bool row_major = hlsl_type_is_row_major(type); + unsigned int i, j; + + assert(type->type == HLSL_CLASS_MATRIX); + + for (i = 0; i < major_size(type); ++i) { - vkd3d_free((void *)new_semantic.name); - hlsl_release_string_buffer(ctx, name); - return; - } - hlsl_release_string_buffer(ctx, name); - output->is_output_semantic = 1; - output->is_param = var->is_param; - list_add_before(&var->scope_entry, &output->scope_entry); - list_add_tail(&ctx->extern_vars, &output->extern_entry); + struct hlsl_ir_var *output; + struct hlsl_semantic semantic_copy = *semantic; - if (!(offset = hlsl_new_uint_constant(ctx, field_offset, &var->loc))) - return; - list_add_tail(instrs, &offset->node.entry); + semantic_copy.index = semantic->index + i; - if (!(load = hlsl_new_load(ctx, var, &offset->node, type, var->loc))) - return; - list_add_after(&offset->node.entry, &load->node.entry); + if (!(output = add_extern_var(ctx, var, vector_type, modifiers, &semantic_copy, true))) + return; - if (!(store = hlsl_new_store(ctx, output, NULL, &load->node, 0, var->loc))) - return; - list_add_after(&load->node.entry, &store->node.entry); + for (j = 0; j < minor_size(type); ++j) + { + unsigned int cell = row_major? (i * type->dimx + j) : (j * type->dimx + i); + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + struct hlsl_block block; + + if (!(load = hlsl_new_component_load(ctx, &block, var, component_offset + cell, var->loc))) + return; + list_move_tail(instrs, &block.instrs); + + if (!(store = hlsl_new_component_store(ctx, &block, output, j, &load->node))) + return; + list_move_tail(instrs, &block.instrs); + } + } } static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, - struct hlsl_type *type, unsigned int field_offset) + struct hlsl_type *type, unsigned int component_offset) { size_t i; @@ -234,13 +438,16 @@ static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, const struct hlsl_struct_field *field = &type->e.record.fields[i]; if (field->type->type == HLSL_CLASS_STRUCT) - append_output_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); + append_output_struct_copy(ctx, instrs, var, field->type, component_offset); + else if (field->type->type == HLSL_CLASS_MATRIX) + append_output_matrix_copy(ctx, instrs, var, field->type, component_offset, field->modifiers, &field->semantic); else if (field->semantic.name) - append_output_copy(ctx, instrs, var, field->type, - field_offset + field->reg_offset, field->modifiers, &field->semantic); + append_output_copy(ctx, instrs, var, field->type, component_offset, field->modifiers, &field->semantic); else hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, "Field '%s' is missing a semantic.", field->name); + + component_offset += hlsl_type_component_count(field->type); } } @@ -251,6 +458,8 @@ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, st { if (var->data_type->type == HLSL_CLASS_STRUCT) append_output_struct_copy(ctx, instrs, var, var->data_type, 0); + else if (var->data_type->type == HLSL_CLASS_MATRIX) + append_output_matrix_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); else if (var->semantic.name) append_output_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); } @@ -783,39 +992,43 @@ static bool fold_redundant_casts(struct hlsl_ctx *ctx, struct hlsl_ir_node *inst * split_matrix_copies(). Inserts new instructions right before * "store". */ static bool split_copy(struct hlsl_ctx *ctx, struct hlsl_ir_store *store, - const struct hlsl_ir_load *load, const unsigned int offset, struct hlsl_type *type) + const struct hlsl_ir_load *load, const unsigned int indx, struct hlsl_type *type) { - struct hlsl_ir_node *offset_instr, *add; + struct hlsl_ir_node *idx1 = NULL, *idx2 = NULL; struct hlsl_ir_store *split_store; struct hlsl_ir_load *split_load; - struct hlsl_ir_constant *c; - - if (!(c = hlsl_new_uint_constant(ctx, offset, &store->node.loc))) - return false; - list_add_before(&store->node.entry, &c->node.entry); - offset_instr = &c->node; - if (load->src.offset.node) + if (load->node.data_type->type == HLSL_CLASS_MATRIX) { - if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, load->src.offset.node, &c->node))) + struct hlsl_ir_constant *y, *x; + + /* matrix components must always have paths of lenght 2: row and column */ + + if (!(y = hlsl_new_uint_constant(ctx, indx / load->node.data_type->dimx, &store->node.loc))) return false; - list_add_before(&store->node.entry, &add->entry); - offset_instr = add; - } - if (!(split_load = hlsl_new_load(ctx, load->src.var, offset_instr, type, store->node.loc))) - return false; - list_add_before(&store->node.entry, &split_load->node.entry); + list_add_before(&store->node.entry, &y->node.entry); + idx1 = &y->node; - offset_instr = &c->node; - if (store->lhs.offset.node) + if (!(x = hlsl_new_uint_constant(ctx, indx % load->node.data_type->dimx, &store->node.loc))) + return false; + list_add_before(&store->node.entry, &x->node.entry); + idx2 = &x->node; + } + else { - if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, store->lhs.offset.node, &c->node))) + struct hlsl_ir_constant *c; + + if (!(c = hlsl_new_uint_constant(ctx, indx, &store->node.loc))) return false; - list_add_before(&store->node.entry, &add->entry); - offset_instr = add; + list_add_before(&store->node.entry, &c->node.entry); + idx1 = &c->node; } - if (!(split_store = hlsl_new_store(ctx, store->lhs.var, offset_instr, &split_load->node, 0, store->node.loc))) + if (!(split_load = hlsl_new_load_from_deref(ctx, &load->src, idx1, idx2, store->node.loc))) + return false; + list_add_before(&store->node.entry, &split_load->node.entry); + + if (!(split_store = hlsl_new_store_from_deref(ctx, &store->lhs, idx1, idx2, &split_load->node, 0, store->node.loc))) return false; list_add_before(&store->node.entry, &split_store->node.entry); @@ -827,8 +1040,8 @@ static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, const struct hlsl_ir_node *rhs; struct hlsl_type *element_type; const struct hlsl_type *type; - unsigned int element_size, i; struct hlsl_ir_store *store; + unsigned int i; if (instr->type != HLSL_IR_STORE) return false; @@ -839,7 +1052,6 @@ static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, if (type->type != HLSL_CLASS_ARRAY) return false; element_type = type->e.array.type; - element_size = hlsl_type_get_array_element_reg_size(element_type); if (rhs->type != HLSL_IR_LOAD) { @@ -849,7 +1061,7 @@ static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, for (i = 0; i < type->e.array.elements_count; ++i) { - if (!split_copy(ctx, store, hlsl_ir_load(rhs), i * element_size, element_type)) + if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type)) return false; } @@ -887,7 +1099,7 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr { const struct hlsl_struct_field *field = &type->e.record.fields[i]; - if (!split_copy(ctx, store, hlsl_ir_load(rhs), field->reg_offset, field->type)) + if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, field->type)) return false; } @@ -915,7 +1127,7 @@ static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr type = rhs->data_type; if (type->type != HLSL_CLASS_MATRIX) return false; - element_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + element_type = hlsl_get_scalar_type(ctx, type->base_type); if (rhs->type != HLSL_IR_LOAD) { @@ -923,9 +1135,9 @@ static bool split_matrix_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return false; } - for (i = 0; i < major_size(type); ++i) + for (i = 0; i < type->dimy * type->dimx; ++i) { - if (!split_copy(ctx, store, hlsl_ir_load(rhs), 4 * i, element_type)) + if (!split_copy(ctx, store, hlsl_ir_load(rhs), i, element_type)) return false; } @@ -1948,6 +2160,9 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, struct hlsl_ir_function_decl *entry } while (progress); transform_ir(ctx, split_matrix_copies, body, NULL); + + transform_ir(ctx, transform_deref_paths_into_offsets, body, NULL); /* TODO: move forward, remove when no longer needed */ + transform_ir(ctx, lower_narrowing_casts, body, NULL); transform_ir(ctx, lower_casts_to_bool, body, NULL); do -- 2.34.1 From 022245763fb7d23938811597575fe54e5a559542 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 17 Sep 2021 00:20:42 -0500 Subject: [PATCH vkd3d 1/2] vkd3d-shader/hlsl: Store the struct fields as an array. Signed-off-by: Francisco Casas --- libs/vkd3d-shader/hlsl.c | 123 +++++++++++++++---------------- libs/vkd3d-shader/hlsl.h | 10 ++- libs/vkd3d-shader/hlsl.y | 99 ++++++++++++++----------- libs/vkd3d-shader/hlsl_codegen.c | 18 +++-- libs/vkd3d-shader/hlsl_sm1.c | 13 +++- libs/vkd3d-shader/hlsl_sm4.c | 13 +++- 6 files changed, 150 insertions(+), 126 deletions(-) diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 7239b183..b349eb15 100644 --- a/libs/vkd3d-shader/hlsl.c +++ b/libs/vkd3d-shader/hlsl.c @@ -175,13 +175,14 @@ static void hlsl_type_calculate_reg_size(struct hlsl_ctx *ctx, struct hlsl_type case HLSL_CLASS_STRUCT: { - struct hlsl_struct_field *field; + unsigned int i; type->dimx = 0; type->reg_size = 0; - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { + struct hlsl_struct_field *field = &type->e.record.fields[i]; unsigned int field_size = field->type->reg_size; assert(field_size); @@ -282,10 +283,12 @@ unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, struct hlsl_typ case HLSL_CLASS_STRUCT: { struct hlsl_struct_field *field; + unsigned int elem_comp_count, i; - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { - unsigned int elem_comp_count = hlsl_type_component_count(field->type); + field = &type->e.record.fields[i]; + elem_comp_count = hlsl_type_component_count(field->type); if (idx < elem_comp_count) { @@ -331,7 +334,8 @@ struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *ba return type; } -struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, struct list *fields) +struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, + struct hlsl_struct_field *fields, size_t field_count) { struct hlsl_type *type; @@ -341,7 +345,8 @@ struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, s type->base_type = HLSL_TYPE_VOID; type->name = name; type->dimy = 1; - type->e.elements = fields; + type->e.record.fields = fields; + type->e.record.field_count = field_count; hlsl_type_calculate_reg_size(ctx, type); list_add_tail(&ctx->types, &type->entry); @@ -401,8 +406,7 @@ struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const cha unsigned int hlsl_type_component_count(struct hlsl_type *type) { - struct hlsl_struct_field *field; - unsigned int count = 0; + unsigned int count = 0, i; if (type->type <= HLSL_CLASS_LAST_NUMERIC) { @@ -418,10 +422,8 @@ unsigned int hlsl_type_component_count(struct hlsl_type *type) return 0; } - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) - { - count += hlsl_type_component_count(field->type); - } + for (i = 0; i < type->e.record.field_count; ++i) + count += hlsl_type_component_count(type->e.record.fields[i].type); return count; } @@ -451,24 +453,22 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 return false; if (t1->type == HLSL_CLASS_STRUCT) { - struct list *t1cur, *t2cur; - struct hlsl_struct_field *t1field, *t2field; + size_t i; + + if (t1->e.record.field_count != t2->e.record.field_count) + return false; - t1cur = list_head(t1->e.elements); - t2cur = list_head(t2->e.elements); - while (t1cur && t2cur) + for (i = 0; i < t1->e.record.field_count; ++i) { - t1field = LIST_ENTRY(t1cur, struct hlsl_struct_field, entry); - t2field = LIST_ENTRY(t2cur, struct hlsl_struct_field, entry); - if (!hlsl_types_are_equal(t1field->type, t2field->type)) + const struct hlsl_struct_field *field1 = &t1->e.record.fields[i]; + const struct hlsl_struct_field *field2 = &t2->e.record.fields[i]; + + if (!hlsl_types_are_equal(field1->type, field2->type)) return false; - if (strcmp(t1field->name, t2field->name)) + + if (strcmp(field1->name, field2->name)) return false; - t1cur = list_next(t1->e.elements, t1cur); - t2cur = list_next(t2->e.elements, t2cur); } - if (t1cur != t2cur) - return false; } if (t1->type == HLSL_CLASS_ARRAY) return t1->e.array.elements_count == t2->e.array.elements_count @@ -480,7 +480,6 @@ bool hlsl_types_are_equal(const struct hlsl_type *t1, const struct hlsl_type *t2 struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, unsigned int default_majority, unsigned int modifiers) { - struct hlsl_struct_field *old_field, *field; struct hlsl_type *type; if (!(type = hlsl_alloc(ctx, sizeof(*type)))) @@ -512,37 +511,30 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx *ctx, struct hlsl_type *old, case HLSL_CLASS_STRUCT: { - if (!(type->e.elements = hlsl_alloc(ctx, sizeof(*type->e.elements)))) + size_t field_count = old->e.record.field_count, i; + + type->e.record.field_count = field_count; + + if (!(type->e.record.fields = hlsl_alloc(ctx, field_count * sizeof(*type->e.record.fields)))) { vkd3d_free((void *)type->name); vkd3d_free(type); return NULL; } - list_init(type->e.elements); - LIST_FOR_EACH_ENTRY(old_field, old->e.elements, struct hlsl_struct_field, entry) + + for (i = 0; i < field_count; ++i) { - if (!(field = hlsl_alloc(ctx, sizeof(*field)))) - { - LIST_FOR_EACH_ENTRY_SAFE(field, old_field, type->e.elements, struct hlsl_struct_field, entry) - { - vkd3d_free((void *)field->semantic.name); - vkd3d_free((void *)field->name); - vkd3d_free(field); - } - vkd3d_free(type->e.elements); - vkd3d_free((void *)type->name); - vkd3d_free(type); - return NULL; - } - field->loc = old_field->loc; - field->type = hlsl_type_clone(ctx, old_field->type, default_majority, modifiers); - field->name = hlsl_strdup(ctx, old_field->name); - if (old_field->semantic.name) + const struct hlsl_struct_field *src_field = &old->e.record.fields[i]; + struct hlsl_struct_field *dst_field = &type->e.record.fields[i]; + + dst_field->loc = src_field->loc; + dst_field->type = hlsl_type_clone(ctx, src_field->type, default_majority, modifiers); + dst_field->name = hlsl_strdup(ctx, src_field->name); + if (src_field->semantic.name) { - field->semantic.name = hlsl_strdup(ctx, old_field->semantic.name); - field->semantic.index = old_field->semantic.index; + dst_field->semantic.name = hlsl_strdup(ctx, src_field->semantic.name); + dst_field->semantic.index = src_field->semantic.index; } - list_add_tail(type->e.elements, &field->entry); } break; } @@ -911,24 +903,22 @@ static int compare_param_hlsl_types(const struct hlsl_type *t1, const struct hls return r; if (t1->type == HLSL_CLASS_STRUCT) { - struct list *t1cur, *t2cur; - struct hlsl_struct_field *t1field, *t2field; + size_t i; - t1cur = list_head(t1->e.elements); - t2cur = list_head(t2->e.elements); - while (t1cur && t2cur) + if (t1->e.record.field_count != t2->e.record.field_count) + return t1->e.record.field_count - t2->e.record.field_count; + + for (i = 0; i < t1->e.record.field_count; ++i) { - t1field = LIST_ENTRY(t1cur, struct hlsl_struct_field, entry); - t2field = LIST_ENTRY(t2cur, struct hlsl_struct_field, entry); - if ((r = compare_param_hlsl_types(t1field->type, t2field->type))) + const struct hlsl_struct_field *field1 = &t1->e.record.fields[i]; + const struct hlsl_struct_field *field2 = &t2->e.record.fields[i]; + + if ((r = compare_param_hlsl_types(field1->type, field2->type))) return r; - if ((r = strcmp(t1field->name, t2field->name))) + + if ((r = strcmp(field1->name, field2->name))) return r; - t1cur = list_next(t1->e.elements, t1cur); - t2cur = list_next(t2->e.elements, t2cur); } - if (t1cur != t2cur) - return t1cur ? 1 : -1; return 0; } if (t1->type == HLSL_CLASS_ARRAY) @@ -1519,17 +1509,20 @@ void hlsl_replace_node(struct hlsl_ir_node *old, struct hlsl_ir_node *new) void hlsl_free_type(struct hlsl_type *type) { - struct hlsl_struct_field *field, *next_field; + struct hlsl_struct_field *field; + size_t i; vkd3d_free((void *)type->name); if (type->type == HLSL_CLASS_STRUCT) { - LIST_FOR_EACH_ENTRY_SAFE(field, next_field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { + field = &type->e.record.fields[i]; + vkd3d_free((void *)field->name); vkd3d_free((void *)field->semantic.name); - vkd3d_free(field); } + vkd3d_free((void *)type->e.record.fields); } vkd3d_free(type); } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 28b2ff1b..661822f7 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -126,7 +126,11 @@ struct hlsl_type unsigned int dimy; union { - struct list *elements; + struct + { + struct hlsl_struct_field *fields; + size_t field_count; + } record; struct { struct hlsl_type *type; @@ -147,7 +151,6 @@ struct hlsl_semantic struct hlsl_struct_field { - struct list entry; struct vkd3d_shader_location loc; struct hlsl_type *type; const char *name; @@ -752,7 +755,8 @@ struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struc 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, struct list *fields); +struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const char *name, + struct hlsl_struct_field *fields, size_t field_count); struct hlsl_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components, struct hlsl_ir_node *val, const struct vkd3d_shader_location *loc); struct hlsl_ir_var *hlsl_new_synthetic_var(struct hlsl_ctx *ctx, const char *name, struct hlsl_type *type, diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y index df5fda47..81307af0 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -28,6 +28,12 @@ #define HLSL_YYLTYPE struct vkd3d_shader_location +struct parse_fields +{ + struct hlsl_struct_field *fields; + size_t count, capacity; +}; + struct parse_parameter { struct hlsl_type *type; @@ -799,14 +805,15 @@ static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hls return !!add_load(ctx, instrs, array, index, data_type, loc); } -static struct hlsl_struct_field *get_struct_field(struct list *fields, const char *name) +static const struct hlsl_struct_field *get_struct_field(const struct hlsl_struct_field *fields, + size_t count, const char *name) { - struct hlsl_struct_field *f; + size_t i; - LIST_FOR_EACH_ENTRY(f, fields, struct hlsl_struct_field, entry) + for (i = 0; i < count; ++i) { - if (!strcmp(f->name, name)) - return f; + if (!strcmp(fields[i].name, name)) + return &fields[i]; } return NULL; } @@ -857,31 +864,28 @@ static void free_parse_variable_def(struct parse_variable_def *v) vkd3d_free(v); } -static struct list *gen_struct_fields(struct hlsl_ctx *ctx, - struct hlsl_type *type, unsigned int modifiers, struct list *fields) +static bool gen_struct_fields(struct hlsl_ctx *ctx, struct parse_fields *fields, + struct hlsl_type *type, unsigned int modifiers, struct list *defs) { struct parse_variable_def *v, *v_next; - struct hlsl_struct_field *field; - struct list *list; + size_t i = 0; if (type->type == HLSL_CLASS_MATRIX) assert(type->modifiers & HLSL_MODIFIERS_MAJORITY_MASK); - if (!(list = make_empty_list(ctx))) - return NULL; - LIST_FOR_EACH_ENTRY_SAFE(v, v_next, fields, struct parse_variable_def, entry) - { - unsigned int i; + memset(fields, 0, sizeof(*fields)); + fields->count = list_count(defs); + if (!hlsl_array_reserve(ctx, (void **)&fields->fields, &fields->capacity, fields->count, sizeof(*fields->fields))) + return false; - if (!(field = hlsl_alloc(ctx, sizeof(*field)))) - { - free_parse_variable_def(v); - continue; - } + LIST_FOR_EACH_ENTRY_SAFE(v, v_next, defs, struct parse_variable_def, entry) + { + struct hlsl_struct_field *field = &fields->fields[i++]; + unsigned int j; field->type = type; - for (i = 0; i < v->arrays.count; ++i) - field->type = hlsl_new_array_type(ctx, field->type, v->arrays.sizes[i]); + for (j = 0; j < v->arrays.count; ++j) + field->type = hlsl_new_array_type(ctx, field->type, v->arrays.sizes[j]); vkd3d_free(v->arrays.sizes); field->loc = v->loc; field->name = v->name; @@ -892,11 +896,10 @@ static struct list *gen_struct_fields(struct hlsl_ctx *ctx, hlsl_error(ctx, &v->loc, VKD3D_SHADER_ERROR_HLSL_INVALID_SYNTAX, "Illegal initializer on a struct field."); free_parse_initializer(&v->initializer); } - list_add_tail(list, &field->entry); vkd3d_free(v); } - vkd3d_free(fields); - return list; + vkd3d_free(defs); + return true; } static bool add_typedef(struct hlsl_ctx *ctx, DWORD modifiers, struct hlsl_type *orig_type, struct list *list) @@ -2583,6 +2586,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl DWORD modifiers; struct hlsl_ir_node *instr; struct list *list; + struct parse_fields fields; struct parse_function function; struct parse_parameter parameter; struct parse_initializer initializer; @@ -2711,8 +2715,6 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl %type equality_expr %type expr %type expr_statement -%type field -%type fields_list %type initializer_expr %type jump_statement %type logicand_expr @@ -2749,6 +2751,9 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl %type colon_attribute +%type field +%type fields_list + %type func_declaration %type func_prototype @@ -2904,7 +2909,7 @@ named_struct_spec: { bool ret; - $$ = hlsl_new_struct_type(ctx, $2, $4); + $$ = hlsl_new_struct_type(ctx, $2, $4.fields, $4.count); if (hlsl_get_var(ctx->cur_scope, $2)) { @@ -2923,7 +2928,7 @@ named_struct_spec: unnamed_struct_spec: KW_STRUCT '{' fields_list '}' { - $$ = hlsl_new_struct_type(ctx, NULL, $3); + $$ = hlsl_new_struct_type(ctx, NULL, $3.fields, $3.count); } any_identifier: @@ -2934,30 +2939,35 @@ any_identifier: fields_list: %empty { - if (!($$ = make_empty_list(ctx))) - YYABORT; + $$.fields = NULL; + $$.count = 0; + $$.capacity = 0; } | fields_list field { - struct hlsl_struct_field *field, *next, *existing; + size_t i; - $$ = $1; - LIST_FOR_EACH_ENTRY_SAFE(field, next, $2, struct hlsl_struct_field, entry) + for (i = 0; i < $2.count; ++i) { - if ((existing = get_struct_field($$, field->name))) + const struct hlsl_struct_field *field = &$2.fields[i]; + const struct hlsl_struct_field *existing; + + if ((existing = get_struct_field($1.fields, $1.count, field->name))) { - hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_REDEFINED, + hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_REDEFINED, "Field \"%s\" is already defined.", field->name); hlsl_note(ctx, &existing->loc, VKD3D_SHADER_LOG_ERROR, "'%s' was previously defined here.", field->name); - vkd3d_free(field); - } - else - { - list_add_tail($$, &field->entry); } } - vkd3d_free($2); + + if (!hlsl_array_reserve(ctx, (void **)&$1.fields, &$1.capacity, $1.count + $2.count, sizeof(*$1.fields))) + YYABORT; + memcpy($1.fields + $1.count, $2.fields, $2.count * sizeof(*$2.fields)); + $1.count += $2.count; + vkd3d_free($2.fields); + + $$ = $1; } field_type: @@ -2981,7 +2991,8 @@ field: "Modifiers '%s' are not allowed on struct fields.", string->buffer); hlsl_release_string_buffer(ctx, string); } - $$ = gen_struct_fields(ctx, type, modifiers, $3); + if (!gen_struct_fields(ctx, &$$, type, modifiers, $3)) + YYABORT; } func_declaration: @@ -3838,9 +3849,9 @@ postfix_expr: if (node->data_type->type == HLSL_CLASS_STRUCT) { struct hlsl_type *type = node->data_type; - struct hlsl_struct_field *field; + const struct hlsl_struct_field *field; - if (!(field = get_struct_field(type->e.elements, $3))) + if (!(field = get_struct_field(type->e.record.fields, type->e.record.field_count, $3))) { hlsl_error(ctx, &@3, VKD3D_SHADER_ERROR_HLSL_NOT_DEFINED, "Field \"%s\" is not defined.", $3); YYABORT; diff --git a/libs/vkd3d-shader/hlsl_codegen.c b/libs/vkd3d-shader/hlsl_codegen.c index 1a5e9055..00743bf6 100644 --- a/libs/vkd3d-shader/hlsl_codegen.c +++ b/libs/vkd3d-shader/hlsl_codegen.c @@ -137,10 +137,12 @@ static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int field_offset) { - struct hlsl_struct_field *field; + size_t i; - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + if (field->type->type == HLSL_CLASS_STRUCT) prepend_input_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); else if (field->semantic.name) @@ -225,10 +227,12 @@ static void append_output_copy(struct hlsl_ctx *ctx, struct list *instrs, struct static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, struct hlsl_type *type, unsigned int field_offset) { - struct hlsl_struct_field *field; + size_t i; - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + if (field->type->type == HLSL_CLASS_STRUCT) append_output_struct_copy(ctx, instrs, var, field->type, field_offset + field->reg_offset); else if (field->semantic.name) @@ -859,10 +863,10 @@ static bool split_array_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr, void *context) { - const struct hlsl_struct_field *field; const struct hlsl_ir_node *rhs; const struct hlsl_type *type; struct hlsl_ir_store *store; + size_t i; if (instr->type != HLSL_IR_STORE) return false; @@ -879,8 +883,10 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr return false; } - LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < type->e.record.field_count; ++i) { + const struct hlsl_struct_field *field = &type->e.record.fields[i]; + if (!split_copy(ctx, store, hlsl_ir_load(rhs), field->reg_offset, field->type)) return false; } diff --git a/libs/vkd3d-shader/hlsl_sm1.c b/libs/vkd3d-shader/hlsl_sm1.c index 0cdd3917..06313a42 100644 --- a/libs/vkd3d-shader/hlsl_sm1.c +++ b/libs/vkd3d-shader/hlsl_sm1.c @@ -243,28 +243,33 @@ static void write_sm1_type(struct vkd3d_bytecode_buffer *buffer, struct hlsl_typ { const struct hlsl_type *array_type = get_array_type(type); unsigned int array_size = get_array_size(type); - struct hlsl_struct_field *field; unsigned int field_count = 0; size_t fields_offset = 0; + size_t i; if (type->bytecode_offset) return; if (array_type->type == HLSL_CLASS_STRUCT) { - LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + field_count = array_type->e.record.field_count; + + for (i = 0; i < field_count; ++i) { + struct hlsl_struct_field *field = &array_type->e.record.fields[i]; + field->name_bytecode_offset = put_string(buffer, field->name); write_sm1_type(buffer, field->type, ctab_start); } fields_offset = bytecode_get_size(buffer) - ctab_start; - LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < field_count; ++i) { + struct hlsl_struct_field *field = &array_type->e.record.fields[i]; + put_u32(buffer, field->name_bytecode_offset - ctab_start); put_u32(buffer, field->type->bytecode_offset - ctab_start); - ++field_count; } } diff --git a/libs/vkd3d-shader/hlsl_sm4.c b/libs/vkd3d-shader/hlsl_sm4.c index a6ac2aa3..f90adb1f 100644 --- a/libs/vkd3d-shader/hlsl_sm4.c +++ b/libs/vkd3d-shader/hlsl_sm4.c @@ -355,7 +355,7 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b const struct hlsl_profile_info *profile = ctx->profile; unsigned int field_count = 0, array_size = 0; size_t fields_offset = 0, name_offset = 0; - struct hlsl_struct_field *field; + size_t i; if (type->bytecode_offset) return; @@ -368,20 +368,25 @@ static void write_sm4_type(struct hlsl_ctx *ctx, struct vkd3d_bytecode_buffer *b if (array_type->type == HLSL_CLASS_STRUCT) { - LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + field_count = array_type->e.record.field_count; + + for (i = 0; i < field_count; ++i) { + struct hlsl_struct_field *field = &array_type->e.record.fields[i]; + field->name_bytecode_offset = put_string(buffer, field->name); write_sm4_type(ctx, buffer, field->type); } fields_offset = bytecode_get_size(buffer); - LIST_FOR_EACH_ENTRY(field, array_type->e.elements, struct hlsl_struct_field, entry) + for (i = 0; i < field_count; ++i) { + struct hlsl_struct_field *field = &array_type->e.record.fields[i]; + put_u32(buffer, field->name_bytecode_offset); put_u32(buffer, field->type->bytecode_offset); put_u32(buffer, field->reg_offset); - ++field_count; } } -- 2.34.1