From: Francisco Casas Subject: Re: HLSL offsetting Message-Id: <58124ceb-c80e-14f8-094d-65edf961e6ae@codeweavers.com> Date: Fri, 17 Jun 2022 17:51:13 -0400 In-Reply-To: <9a60c866-77fb-73cd-0e5d-26fbcff862a6@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> Hello, I attach a second version of the previous patch, now rebased into the master branch. I will start working on including the suggestions that Zebediah's made in the other e-mails. Besides those, I will also check if we can remove the "type" argument from hlsl_new_load(), I think it can be deducted from the path and the variable. Best regards, Francisco. On 14-06-22 23:05, Francisco Casas wrote: > Hello, > > On 13-06-22 11:59, Francisco Casas wrote: >> Okay, I stopped working on multiple register offsets and now I am >> working on this approach. >> >> I still think that adding a pass to translate these "route"s to the >> original register "offset"s, so that we can implement this change >> gradually, is good. We can move the pass forward as we change more >> passes to work with component offsets. And we can debug more easily >> the things that we don't translate correctly. >> >> I am aiming to implement the new approach until right after >> split_matrix_copies, and put the translation afterwards. So far it >> seems to be going nicely. >> > > I attach a patch that achieves this, in case there are any opinions. > > The "paths"[1] of component indexes seem like the best way to solve the > problem after all. I think that keeping them as an arrays of nodes in > the hlsl_deref allows to write more uniform code than using a more > complex data structure, as Giovanni mentioned. > > IMO, I think this patch manages matrices nicely too, but there is the > problem that it is based on top of > --- > bb49bdba gmascellani vkd3d-shader/hlsl: Allow majority modifiers on > function declarations. > --- > which is a little behind of master. > > So I still have to rebase it on top of current master, and in particular > on top of the recent patches pertaining matrices. So I will probably > have to make some design decisions while solving the conflicts. > > I guess that the main objective is that we don't want to deal with > matrices at all after splitting matrix copies. > > > Best regards, > Francisco. > > > --- > > [1] I hope that this is a better name than "route". From a3a94aa8019fd5b8cb2ffc43578b5ea4cbcc31a4 Mon Sep 17 00:00:00 2001 From: Francisco Casas Date: Tue, 14 Jun 2022 22:13:16 -0400 Subject: [PATCH vkd3d v2] vkd3d-shader/hlsl: Replace register offsets with index paths until after split copies. The transform_deref_paths_into_offsets pass goes back to 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 component index paths. This, until register offsets can be totally removed, when 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 struct load should be an hlsl_ir_constant, since the field that's being addressed is always known at parse-time. - When adding nodes to a path_arg we have to make sure that new nodes are added to the corresponding instruction list before the load/store in which the path_arg is used. - 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. Signed-off-by: Francisco Casas --- include/private/list.h | 13 + libs/vkd3d-shader/hlsl.c | 224 ++++++++++--- libs/vkd3d-shader/hlsl.h | 33 +- libs/vkd3d-shader/hlsl.y | 424 ++++++++++++++----------- libs/vkd3d-shader/hlsl_codegen.c | 521 +++++++++++++++++++++++-------- 5 files changed, 848 insertions(+), 367 deletions(-) diff --git a/include/private/list.h b/include/private/list.h index b4d681fe..07ab8c1f 100644 --- a/include/private/list.h +++ b/include/private/list.h @@ -135,6 +135,19 @@ static inline int list_empty( const struct list *list ) return list->next == list; } +/* get element by index */ +static inline struct list *list_get( const struct list *list, unsigned int i ) +{ + struct list *elem = list_head(list); + + while (i-- > 0) + { + if (!elem) return NULL; + elem = list_next(list, elem); + } + return elem; +} + /* initialize a list */ static inline void list_init( struct list *list ) { diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c index 7239b183..af4ecefb 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. */ @@ -232,39 +232,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: @@ -272,43 +283,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 k = 0; LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { - unsigned int elem_comp_count = hlsl_type_component_count(field->type); + unsigned int 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] = k; + return path; } - idx -= elem_comp_count; + idx -= field_comp_count; + ++k; } - 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) @@ -618,7 +640,80 @@ 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 path_arg *path_arg_init(struct hlsl_ctx *ctx) +{ + struct path_arg *parg = hlsl_alloc(ctx, sizeof(struct path_arg)); + + parg->path_len = 0; + parg->path = hlsl_alloc(ctx, 0); + return parg; +} + +struct path_arg *path_arg_copy(struct hlsl_ctx *ctx, const struct path_arg *original) +{ + struct path_arg *parg = hlsl_alloc(ctx, sizeof(struct path_arg)); + + assert(original); + parg->path_len = original->path_len; + parg->path = hlsl_alloc(ctx, sizeof(*parg->path) * parg->path_len); + memcpy(parg->path, original->path, sizeof(*parg->path) * parg->path_len); + return parg; +} + +struct path_arg *path_arg_copy_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref) +{ + struct path_arg *parg = hlsl_alloc(ctx, sizeof(struct path_arg)); + unsigned int i; + + assert(deref); + if (!(parg->path = hlsl_alloc(ctx, sizeof(*parg->path) * parg->path_len))) + return parg; + parg->path_len = deref->path_len; + for (i = 0; i < parg->path_len; ++i) + parg->path[i] = deref->path[i].node; + return parg; +} + +void path_arg_add_node(struct hlsl_ctx *ctx, struct path_arg *parg, struct hlsl_ir_node *node) +{ + assert(node); + ++parg->path_len; + parg->path = hlsl_realloc(ctx, parg->path, sizeof(*parg->path) * parg->path_len); + parg->path[parg->path_len - 1] = node; +} + +void path_arg_concat(struct hlsl_ctx *ctx, struct path_arg *parg, const struct path_arg *other) +{ + unsigned int i; + + assert(other); + for (i = 0; i < other->path_len; ++i) + path_arg_add_node(ctx, parg, other->path[i]); +} + +void path_arg_free(struct path_arg *parg) +{ + assert(parg); + vkd3d_free(parg->path); + vkd3d_free(parg); +} + +static void deref_init_from_path_arg(struct hlsl_ctx *ctx, struct hlsl_deref *deref, const struct path_arg *path) +{ + unsigned int path_len = path? path->path_len : 0; + unsigned int i; + + assert(!deref->path); + assert(!deref->path_len); + + if (!(deref->path = hlsl_alloc(ctx, sizeof(*deref->path) * path_len))) + return; + deref->path_len = path_len; + for (i = 0; i < path_len; ++i) + hlsl_src_from_node(&deref->path[i], path->path[i]); +} + +struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, const struct path_arg *path, struct hlsl_ir_node *rhs, unsigned int writemask, struct vkd3d_shader_location loc) { struct hlsl_ir_store *store; @@ -631,7 +726,7 @@ struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *v init_node(&store->node, HLSL_IR_STORE, NULL, loc); store->lhs.var = var; - hlsl_src_from_node(&store->lhs.offset, offset); + deref_init_from_path_arg(ctx, &store->lhs, path); hlsl_src_from_node(&store->rhs, rhs); store->writemask = writemask; return store; @@ -725,7 +820,7 @@ 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_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, const struct path_arg *path, struct hlsl_type *type, const struct vkd3d_shader_location loc) { struct hlsl_ir_load *load; @@ -734,7 +829,7 @@ struct hlsl_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var return NULL; init_node(&load->node, HLSL_IR_LOAD, type, loc); load->src.var = var; - hlsl_src_from_node(&load->src.offset, offset); + deref_init_from_path_arg(ctx, &load->src, path); return load; } @@ -745,8 +840,8 @@ struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct hlsl_ir_var } 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, + enum hlsl_resource_load_type type, struct hlsl_ir_var *resource, const struct path_arg *resource_path, + struct hlsl_ir_var *sampler, const struct path_arg *sampler_path, struct hlsl_ir_node *coords, struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc) { struct hlsl_ir_resource_load *load; @@ -756,9 +851,9 @@ struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx *ctx, struc 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); + deref_init_from_path_arg(ctx, &load->resource, resource_path); load->sampler.var = sampler; - hlsl_src_from_node(&load->sampler.offset, sampler_offset); + deref_init_from_path_arg(ctx, &load->sampler, sampler_path); hlsl_src_from_node(&load->coords, coords); hlsl_src_from_node(&load->texel_offset, texel_offset); return load; @@ -1185,10 +1280,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) + { + dump_src(buffer, &deref->path[i]); + if (i < deref->path_len - 1) + 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); @@ -1546,6 +1654,20 @@ void hlsl_free_instr_list(struct list *list) hlsl_free_instr(node); } +void free_hlsl_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); @@ -1575,7 +1697,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); + free_hlsl_deref(&load->src); vkd3d_free(load); } @@ -1588,8 +1710,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); + free_hlsl_deref(&load->sampler); + free_hlsl_deref(&load->resource); hlsl_src_remove(&load->texel_offset); vkd3d_free(load); } @@ -1597,7 +1719,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); + free_hlsl_deref(&store->lhs); vkd3d_free(store); } diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h index 28b2ff1b..daffa62b 100644 --- a/libs/vkd3d-shader/hlsl.h +++ b/libs/vkd3d-shader/hlsl.h @@ -371,7 +371,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 @@ -716,6 +720,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 free_hlsl_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); @@ -726,6 +732,18 @@ struct hlsl_ir_function_decl *hlsl_get_func_decl(struct hlsl_ctx *ctx, const cha struct hlsl_type *hlsl_get_type(struct hlsl_scope *scope, const char *name, bool recursive); struct hlsl_ir_var *hlsl_get_var(struct hlsl_scope *scope, const char *name); +struct path_arg { + unsigned int path_len; + struct hlsl_ir_node **path; +}; + +struct path_arg *path_arg_init(struct hlsl_ctx *ctx); +struct path_arg *path_arg_copy(struct hlsl_ctx *ctx, const struct path_arg *original); +struct path_arg *path_arg_copy_from_deref(struct hlsl_ctx *ctx, const struct hlsl_deref *deref); +void path_arg_add_node(struct hlsl_ctx *ctx, struct path_arg *parg, struct hlsl_ir_node *node); +void path_arg_concat(struct hlsl_ctx *ctx, struct path_arg *parg, const struct path_arg *other); +void path_arg_free(struct path_arg *parg); + struct hlsl_type *hlsl_new_array_type(struct hlsl_ctx *ctx, struct hlsl_type *basic_type, unsigned int array_size); struct hlsl_ir_node *hlsl_new_binary_expr(struct hlsl_ctx *ctx, enum hlsl_ir_expr_op op, struct hlsl_ir_node *arg1, struct hlsl_ir_node *arg2); @@ -742,15 +760,15 @@ 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_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, const struct path_arg *path, 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, + enum hlsl_resource_load_type type, struct hlsl_ir_var *resource, const struct path_arg *resource_path, + struct hlsl_ir_var *sampler, const struct path_arg *sampler_offset, struct hlsl_ir_node *coords, struct hlsl_ir_node *texel_offset, const struct vkd3d_shader_location *loc); struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs); -struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, struct hlsl_ir_node *offset, +struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct hlsl_ir_var *var, const struct path_arg *path, 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_ir_swizzle *hlsl_new_swizzle(struct hlsl_ctx *ctx, DWORD s, unsigned int components, @@ -786,8 +804,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 df5fda47..5a6eca66 100644 --- a/libs/vkd3d-shader/hlsl.y +++ b/libs/vkd3d-shader/hlsl.y @@ -267,12 +267,14 @@ 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); + const struct path_arg *path, struct hlsl_type *data_type, 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 *src_scalar_type = hlsl_get_scalar_type(ctx, src_type->base_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)) @@ -281,13 +283,24 @@ static struct hlsl_ir_node *add_cast(struct hlsl_ctx *ctx, struct list *instrs, if ((src_type->type == HLSL_CLASS_MATRIX || dst_type->type == HLSL_CLASS_MATRIX) && src_type->type <= HLSL_CLASS_LAST_NUMERIC && dst_type->type <= HLSL_CLASS_LAST_NUMERIC) { + struct hlsl_ir_constant *cs[4] = { NULL }; struct vkd3d_string_buffer *name; static unsigned int counter = 0; struct hlsl_ir_load *load; struct hlsl_ir_var *var; - unsigned int dst_idx; + unsigned int i, y, x; bool broadcast; + for (i = 0; i < 4; ++i) + { + if (i >= dst_type->dimx && i >= dst_type->dimy && i >= src_type->dimx && i >= src_type->dimy) + break; + + if (!(cs[i] = hlsl_new_uint_constant(ctx, i, loc))) + return NULL; + list_add_tail(instrs, &cs[i]->node.entry); + } + broadcast = src_type->dimx == 1 && src_type->dimy == 1; assert(dst_type->dimx * dst_type->dimy <= src_type->dimx * src_type->dimy || broadcast); if (src_type->type == HLSL_CLASS_MATRIX && dst_type->type == HLSL_CLASS_MATRIX && !broadcast) @@ -303,52 +316,58 @@ 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) - { - unsigned int x = dst_idx % dst_type->dimx, y = dst_idx / dst_type->dimx; + struct path_arg *src_path, *dst_path; + struct hlsl_ir_store *store; - src_idx = y * src_type->dimx + x; + src_path = path_arg_init(ctx); + if (broadcast) + { + if (src_type->type == HLSL_CLASS_MATRIX) + path_arg_add_node(ctx, src_path, &cs[0]->node); + if (src_type->type == HLSL_CLASS_MATRIX || src_type->type == HLSL_CLASS_VECTOR) + path_arg_add_node(ctx, src_path, &cs[0]->node); + } + else if (src_type->type == HLSL_CLASS_MATRIX && dst_type->type == HLSL_CLASS_MATRIX) + { + path_arg_add_node(ctx, src_path, &cs[y]->node); + path_arg_add_node(ctx, src_path, &cs[x]->node); } else { - src_idx = dst_idx; + unsigned int src_idx = dst_type->dimx * y + x; + + if (src_type->type == HLSL_CLASS_MATRIX) + path_arg_add_node(ctx, src_path, &cs[src_idx / src_type->dimx]->node); + if (src_type->type == HLSL_CLASS_MATRIX || src_type->type == HLSL_CLASS_VECTOR) + path_arg_add_node(ctx, src_path, &cs[src_idx % src_type->dimx]->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); + dst_path = path_arg_init(ctx); + if (dst_type->type == HLSL_CLASS_MATRIX) + path_arg_add_node(ctx, dst_path, &cs[y]->node); + if (dst_type->type == HLSL_CLASS_MATRIX || dst_type->type == HLSL_CLASS_VECTOR) + path_arg_add_node(ctx, dst_path, &cs[x]->node); - 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, src_path, src_scalar_type, *loc))) + return NULL; - 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 (!(cast = hlsl_new_cast(ctx, &load->node, dst_scalar_type, loc))) - return NULL; - list_add_tail(instrs, &cast->node.entry); + assert(dst_path->path_len == dst_type->type); - if (!(c = hlsl_new_uint_constant(ctx, dst_offset, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); + if (!(store = hlsl_new_store(ctx, var, dst_path, &cast->node, 0, *loc))) + return NULL; + list_add_tail(instrs, &store->node.entry); - if (!(store = hlsl_new_store(ctx, var, &c->node, &cast->node, 0, *loc))) - return NULL; - list_add_tail(instrs, &store->node.entry); + path_arg_free(src_path); + path_arg_free(dst_path); + } } if (!(load = hlsl_new_load(ctx, var, NULL, dst_type, *loc))) @@ -622,28 +641,26 @@ 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) + const struct path_arg *path, struct hlsl_type *data_type, 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; + struct path_arg *load_path = path_arg_copy_from_deref(ctx, 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; - } + path_arg_concat(ctx, load_path, path); + if (!(load = hlsl_new_load(ctx, src->var, load_path, data_type, loc))) + return NULL; + list_add_tail(instrs, &load->node.entry); + + path_arg_free(load_path); } else { struct hlsl_ir_store *store; + struct hlsl_ir_var *var; char name[27]; sprintf(name, "", var_node); @@ -652,26 +669,32 @@ 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(ctx, var, path, data_type, 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; + struct path_arg *path; - 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); + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &c->node); + if (!add_load(ctx, instrs, record, path, field->type, loc)) + return false; + path_arg_free(path); + return true; } static struct hlsl_ir_node *add_binary_arithmetic_expr(struct hlsl_ctx *ctx, struct list *instrs, @@ -682,36 +705,17 @@ 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; + struct path_arg *path = path_arg_init(ctx); + struct hlsl_ir_load *load; 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))) + path_arg_add_node(ctx, path, y); + path_arg_add_node(ctx, path, x); + if (!(load = add_load(ctx, instrs, matrix, path, scalar_type, *loc))) return NULL; + path_arg_free(path); return &load->node; } @@ -740,6 +744,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 path_arg *path; if (!(c = hlsl_new_uint_constant(ctx, i, loc))) return false; @@ -748,9 +753,12 @@ 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))) + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &c->node); + if (!(store = hlsl_new_store(ctx, var, path, value, 0, *loc))) return false; list_add_tail(instrs, &store->node.entry); + path_arg_free(path); } if (!(load = hlsl_new_var_load(ctx, var, *loc))) @@ -765,19 +773,11 @@ static bool add_array_load(struct hlsl_ctx *ctx, struct list *instrs, struct hls { const struct hlsl_type *expr_type = array->data_type; struct hlsl_type *data_type; - struct hlsl_ir_constant *c; + struct path_arg *path; 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) { @@ -796,17 +796,32 @@ 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); + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, index); + + if (!add_load(ctx, instrs, array, path, data_type, loc)) + return false; + + path_arg_free(path); + + return true; } -static struct hlsl_struct_field *get_struct_field(struct list *fields, const char *name) +static struct hlsl_struct_field *get_struct_field(struct list *fields, const char *name, + unsigned int *field_indx) { struct hlsl_struct_field *f; + unsigned int k = 0; LIST_FOR_EACH_ENTRY(f, fields, struct hlsl_struct_field, entry) { if (!strcmp(f->name, name)) + { + if (field_indx) + *field_indx = k; return f; + } + ++k; } return NULL; } @@ -1201,38 +1216,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++); @@ -1241,38 +1251,45 @@ 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; + for (x = 0; x < type->dimx; ++x) + { + struct hlsl_ir_node *value, *scalar_operands[HLSL_MAX_OPERANDS] = { NULL }; + struct path_arg *path = path_arg_init(ctx); + struct hlsl_ir_store *store; - if (!(c = hlsl_new_uint_constant(ctx, 4 * i, loc))) - return NULL; - list_add_tail(instrs, &c->node.entry); + path_arg_add_node(ctx, path, &cs[y]->node); + path_arg_add_node(ctx, path, &cs[x]->node); - for (j = 0; j < HLSL_MAX_OPERANDS; j++) - { - if (operands[j]) + for (j = 0; j < HLSL_MAX_OPERANDS; j++) { - struct hlsl_type *vector_arg_type; - struct hlsl_ir_load *load; + if (operands[j]) + { + struct hlsl_type *scalar_arg_type; + struct hlsl_ir_load *load; + + 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); + scalar_arg_type = hlsl_get_scalar_type(ctx, operands[j]->data_type->base_type); - vector_arg_type = hlsl_get_vector_type(ctx, operands[j]->data_type->base_type, minor_size(type)); + if (!(load = add_load(ctx, instrs, operands[j], path, scalar_arg_type, *loc))) + return NULL; - if (!(load = add_load(ctx, instrs, operands[j], &c->node, vector_arg_type, *loc))) - return NULL; - vector_operands[j] = &load->node; + 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_store(ctx, var, path, value, 0, *loc))) + return NULL; + list_add_tail(instrs, &store->node.entry); + + path_arg_free(path); + } } if (!(load = hlsl_new_load(ctx, var, NULL, type, *loc))) @@ -1577,6 +1594,7 @@ static struct hlsl_ir_node *add_assignment(struct hlsl_ctx *ctx, struct list *in { struct hlsl_type *lhs_type = lhs->data_type; struct hlsl_ir_store *store; + struct path_arg *load_path; struct hlsl_ir_expr *copy; unsigned int writemask = 0; @@ -1603,15 +1621,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) @@ -1625,13 +1639,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); @@ -1642,17 +1654,15 @@ 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); + load_path = path_arg_copy_from_deref(ctx, &hlsl_ir_load(lhs)->src); + if (!(store = hlsl_new_store(ctx, hlsl_ir_load(lhs)->src.var, load_path, rhs, writemask, rhs->loc))) + return NULL; list_add_tail(instrs, &store->node.entry); + path_arg_free(load_path); /* Don't use the instruction itself as a source, as this makes structure * splitting easier. Instead copy it here. Since we retrieve sources from @@ -1700,37 +1710,53 @@ 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); - unsigned int k; + unsigned int k, i; 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, src_path_len; + unsigned int *dst_path, *src_path; struct hlsl_ir_store *store; struct hlsl_ir_constant *c; struct hlsl_ir_load *load; struct hlsl_ir_node *conv; + struct path_arg *path; - 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); + src_path = hlsl_compute_component_path(ctx, src->data_type, k, &src_comp_type, &src_path_len); + dst_path = hlsl_compute_component_path(ctx, dst->data_type, *store_index, &dst_comp_type, &dst_path_len); - if (!(c = hlsl_new_uint_constant(ctx, src_reg_offset, &src->loc))) - return; - list_add_tail(instrs, &c->node.entry); + path = path_arg_init(ctx); + for (i = 0; i < src_path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, src_path[i], &src->loc))) + return; + list_add_tail(instrs, &c->node.entry); - if (!(load = add_load(ctx, instrs, src, &c->node, src_comp_type, src->loc))) + path_arg_add_node(ctx, path, &c->node); + } + vkd3d_free(src_path); + if (!(load = add_load(ctx, instrs, src, path, src_comp_type, src->loc))) return; + path_arg_free(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))) - return; - list_add_tail(instrs, &c->node.entry); + path = path_arg_init(ctx); + for (i = 0; i < dst_path_len; ++i) + { + if (!(c = hlsl_new_uint_constant(ctx, dst_path[i], &src->loc))) + return; + list_add_tail(instrs, &c->node.entry); - if (!(store = hlsl_new_store(ctx, dst, &c->node, conv, 0, src->loc))) + path_arg_add_node(ctx, path, &c->node); + } + vkd3d_free(dst_path); + if (!(store = hlsl_new_store(ctx, dst, path, conv, 0, src->loc))) return; list_add_tail(instrs, &store->node.entry); + path_arg_free(path); ++*store_index; } @@ -2051,7 +2077,8 @@ 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_type *cast_type1 = arg1->data_type, *cast_type2 = arg2->data_type, *matrix_type, *ret_type, *scalar_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; @@ -2102,35 +2129,44 @@ 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); + } + + scalar_type = hlsl_get_scalar_type(ctx, base); + 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 path_arg *path; 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))) - return false; - list_add_tail(params->instrs, &c->node.entry); - - if (!(value1 = add_load(ctx, params->instrs, cast1, &c->node, scalar_type, *loc))) + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &cs[j]->node); + path_arg_add_node(ctx, path, &cs[k]->node); + if (!(value1 = add_load(ctx, params->instrs, cast1, path, scalar_type, *loc))) return false; + path_arg_free(path); - 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))) + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &cs[k]->node); + path_arg_add_node(ctx, path, &cs[i]->node); + if (!(value2 = add_load(ctx, params->instrs, cast2, path, scalar_type, *loc))) return false; + path_arg_free(path); if (!(mul = add_binary_arithmetic_expr(ctx, params->instrs, HLSL_OP2_MUL, &value1->node, &value2->node, loc))) return false; @@ -2146,15 +2182,14 @@ 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))) + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &cs[j]->node); + path_arg_add_node(ctx, path, &cs[i]->node); + if (!(store = hlsl_new_store(ctx, var, path, node, 0, *loc))) return false; list_add_tail(params->instrs, &store->node.entry); } + } if (!(load = hlsl_new_load(ctx, var, NULL, matrix_type, *loc))) return false; @@ -2364,6 +2399,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); struct hlsl_ir_resource_load *load; struct hlsl_ir_node *coords; + struct path_arg *resource_path; if (object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMS || object_type->sampler_dim == HLSL_SAMPLER_DIM_2DMSARRAY) @@ -2388,10 +2424,12 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl hlsl_get_vector_type(ctx, HLSL_TYPE_INT, sampler_dim + 1), loc))) return false; + resource_path = path_arg_copy_from_deref(ctx, &object_load->src); 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.var, resource_path, NULL, NULL, coords, NULL, loc))) return false; list_add_tail(instrs, &load->node.entry); + path_arg_free(resource_path); return true; } else if (!strcmp(name, "Sample") @@ -2399,6 +2437,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl && object_type->sampler_dim != HLSL_SAMPLER_DIM_2DMSARRAY) { const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + struct path_arg *resource_path, *sampler_path; const struct hlsl_type *sampler_type; struct hlsl_ir_resource_load *load; struct hlsl_ir_node *offset = NULL; @@ -2439,11 +2478,17 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl return false; } + resource_path = path_arg_copy_from_deref(ctx, &object_load->src); + sampler_path = path_arg_copy_from_deref(ctx, &sampler_load->src); + 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.var, resource_path, + sampler_load->src.var, sampler_path, coords, offset, loc))) return false; list_add_tail(instrs, &load->node.entry); + path_arg_free(resource_path); + path_arg_free(sampler_path); + return true; } else if ((!strcmp(name, "Gather") || !strcmp(name, "GatherRed") || !strcmp(name, "GatherBlue") @@ -2454,6 +2499,7 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl || object_type->sampler_dim == HLSL_SAMPLER_DIM_CUBEARRAY)) { const unsigned int sampler_dim = hlsl_sampler_dim_count(object_type->sampler_dim); + struct path_arg *resource_path, *sampler_path; enum hlsl_resource_load_type load_type; const struct hlsl_type *sampler_type; struct hlsl_ir_resource_load *load; @@ -2543,11 +2589,16 @@ static bool add_method_call(struct hlsl_ctx *ctx, struct list *instrs, struct hl hlsl_get_vector_type(ctx, HLSL_TYPE_FLOAT, sampler_dim), loc))) return false; + resource_path = path_arg_copy_from_deref(ctx, &object_load->src); + sampler_path = path_arg_copy_from_deref(ctx, &sampler_load->src); + 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.var, resource_path, sampler_load->src.var, sampler_path, + coords, offset, loc))) return false; list_add_tail(instrs, &load->node.entry); + path_arg_free(resource_path); + path_arg_free(sampler_path); return true; } else @@ -2944,7 +2995,7 @@ fields_list: $$ = $1; LIST_FOR_EACH_ENTRY_SAFE(field, next, $2, struct hlsl_struct_field, entry) { - if ((existing = get_struct_field($$, field->name))) + if ((existing = get_struct_field($$, field->name, NULL))) { hlsl_error(ctx, &@2, VKD3D_SHADER_ERROR_HLSL_REDEFINED, "Field \"%s\" is already defined.", field->name); @@ -3839,14 +3890,15 @@ postfix_expr: { struct hlsl_type *type = node->data_type; struct hlsl_struct_field *field; + unsigned int field_indx; - if (!(field = get_struct_field(type->e.elements, $3))) + if (!(field = get_struct_field(type->e.elements, $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 1a5e9055..e17b339b 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; + struct hlsl_struct_field *field; + + field = LIST_ENTRY(list_get(type->e.elements, field_i), struct hlsl_struct_field, entry); + + 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; + } + } + + free_hlsl_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,81 +226,149 @@ 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 ext_var; +} + +static void prepend_input_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, const struct path_arg *field_path, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + struct hlsl_ir_store *store; + struct hlsl_ir_load *load; + struct hlsl_ir_var *input; + + if (!(input = add_extern_var(ctx, var, type, modifiers, semantic, false))) return; - list_add_head(instrs, &load->node.entry); - if (!(offset = hlsl_new_uint_constant(ctx, field_offset, &var->loc))) + if (!(load = hlsl_new_var_load(ctx, input, var->loc))) return; - list_add_after(&load->node.entry, &offset->node.entry); + if (field_path->path_len == 0) + list_add_head(instrs, &load->node.entry); + else + list_add_after(&field_path->path[field_path->path_len - 1]->entry, &load->node.entry); - if (!(store = hlsl_new_store(ctx, var, &offset->node, &load->node, 0, var->loc))) + if (!(store = hlsl_new_store(ctx, var, field_path, &load->node, 0, var->loc))) return; - list_add_after(&offset->node.entry, &store->node.entry); + list_add_after(&load->node.entry, &store->node.entry); +} + +static void prepend_input_matrix_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, const struct path_arg *field_path, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + struct hlsl_type *scalar_type = hlsl_get_scalar_type(ctx, type->base_type); + struct hlsl_ir_constant *cs[4] = { NULL }; + bool row_major = hlsl_type_is_row_major(type); + struct hlsl_ir_store *store; + struct hlsl_ir_var *input; + struct hlsl_ir_load *load; + unsigned int i, j; + + assert(type->type == HLSL_CLASS_MATRIX); + + for (i = 0; i < 4; ++i) + { + if (i >= type->dimx && i >= type->dimy) + break; + if (!(cs[i] = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_head(instrs, &cs[i]->node.entry); + } + assert(cs[0]); + + for (i = 0; i < major_size(type); ++i) + { + struct hlsl_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + struct hlsl_semantic semantic_copy = *semantic; + struct path_arg *path; + + 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) + { + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &cs[j]->node); + if (!(load = hlsl_new_load(ctx, input, path, scalar_type, var->loc))) + return; + list_add_after(&cs[0]->node.entry, &load->node.entry); + path_arg_free(path); + + path = path_arg_copy(ctx, field_path); + path_arg_add_node(ctx, path, row_major? &cs[i]->node : &cs[j]->node); + path_arg_add_node(ctx, path, row_major? &cs[j]->node : &cs[i]->node); + if (!(store = hlsl_new_store(ctx, var, path, &load->node, 0, var->loc))) + return; + list_add_after(&load->node.entry, &store->node.entry); + path_arg_free(path); + } + } } 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, const struct path_arg *path) { struct hlsl_struct_field *field; + unsigned int k = 0; LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { + struct path_arg *field_path = path_arg_copy(ctx, path); + struct hlsl_ir_constant *c; + + if (!(c = hlsl_new_uint_constant(ctx, k, &var->loc))) + return; + list_add_head(instrs, &c->node.entry); + + path_arg_add_node(ctx, field_path, &c->node); + 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, field_path); + else if (field->type->type == HLSL_CLASS_MATRIX) + prepend_input_matrix_copy(ctx, instrs, var, field->type, field_path, 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, field_path, field->modifiers, &field->semantic); else hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, "Field '%s' is missing a semantic.", field->name); + + path_arg_free(field_path); + + ++k; } } @@ -156,87 +376,121 @@ static void prepend_input_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, * and copy the former to the latter, so that writes to input variables work. */ static void prepend_input_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct path_arg *path = path_arg_init(ctx); + if (var->data_type->type == HLSL_CLASS_STRUCT) - prepend_input_struct_copy(ctx, instrs, var, var->data_type, 0); + prepend_input_struct_copy(ctx, instrs, var, var->data_type, path); + else if (var->data_type->type == HLSL_CLASS_MATRIX) + prepend_input_matrix_copy(ctx, instrs, var, var->data_type, path, var->modifiers, &var->semantic); else if (var->semantic.name) - prepend_input_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); + prepend_input_copy(ctx, instrs, var, var->data_type, path, var->modifiers, &var->semantic); + + path_arg_free(path); } 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, const struct path_arg *field_path, 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; struct hlsl_ir_var *output; struct hlsl_ir_load *load; - 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) - { - append_output_copy(ctx, instrs, var, vector_type, 4 * i, modifiers, &vector_semantic); - ++vector_semantic.index; - } + output = add_extern_var(ctx, var, type, modifiers, semantic, true); + if (!(load = hlsl_new_load(ctx, var, field_path, type, var->loc))) return; - } + list_add_tail(instrs, &load->node.entry); - if (!(name = hlsl_get_string_buffer(ctx))) + if (!(store = hlsl_new_store(ctx, output, NULL, &load->node, 0, var->loc))) return; - vkd3d_string_buffer_printf(name, "", semantic->name, semantic->index); - if (!(new_semantic.name = hlsl_strdup(ctx, semantic->name))) + list_add_after(&load->node.entry, &store->node.entry); +} + +static void append_output_matrix_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var, + struct hlsl_type *type, const struct path_arg *field_path, unsigned int modifiers, + const struct hlsl_semantic *semantic) +{ + struct hlsl_type *scalar_type = hlsl_get_scalar_type(ctx, type->base_type); + struct hlsl_ir_constant *cs[4] = { NULL }; + bool row_major = hlsl_type_is_row_major(type); + struct hlsl_ir_store *store; + struct hlsl_ir_var *output; + struct hlsl_ir_load *load; + unsigned int i, j; + + assert(type->type == HLSL_CLASS_MATRIX); + + for (i = 0; i < 4; ++i) { - hlsl_release_string_buffer(ctx, name); - return; + if (i >= type->dimx && i >= type->dimy) + break; + if (!(cs[i] = hlsl_new_uint_constant(ctx, i, &var->loc))) + return; + list_add_tail(instrs, &cs[i]->node.entry); } - new_semantic.index = semantic->index; - if (!(output = hlsl_new_var(ctx, hlsl_strdup(ctx, name->buffer), - type, var->loc, &new_semantic, modifiers, NULL))) + + 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_type *vector_type = hlsl_get_vector_type(ctx, type->base_type, minor_size(type)); + struct hlsl_semantic semantic_copy = *semantic; + struct path_arg *path; - 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) + { + path = path_arg_copy(ctx, field_path); + path_arg_add_node(ctx, path, row_major? &cs[i]->node : &cs[j]->node); + path_arg_add_node(ctx, path, row_major? &cs[j]->node : &cs[i]->node); + if (!(load = hlsl_new_load(ctx, var, path, scalar_type, var->loc))) + return; + list_add_tail(instrs, &load->node.entry); + path_arg_free(path); + + path = path_arg_init(ctx); + path_arg_add_node(ctx, path, &cs[j]->node); + if (!(store = hlsl_new_store(ctx, output, path, &load->node, 0, var->loc))) + return; + list_add_tail(instrs, &store->node.entry); + path_arg_free(path); + } + } } 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, const struct path_arg *path) { struct hlsl_struct_field *field; + unsigned int k = 0; LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { + struct path_arg *field_path = path_arg_copy(ctx, path); + struct hlsl_ir_constant *c; + + if (!(c = hlsl_new_uint_constant(ctx, k, &var->loc))) + return; + list_add_tail(instrs, &c->node.entry); + + path_arg_add_node(ctx, field_path, &c->node); + 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, field_path); + else if (field->type->type == HLSL_CLASS_MATRIX) + append_output_matrix_copy(ctx, instrs, var, field->type, field_path, 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, field_path, field->modifiers, &field->semantic); else hlsl_error(ctx, &field->loc, VKD3D_SHADER_ERROR_HLSL_MISSING_SEMANTIC, "Field '%s' is missing a semantic.", field->name); + + path_arg_free(field_path); + + ++k; } } @@ -245,10 +499,16 @@ static void append_output_struct_copy(struct hlsl_ctx *ctx, struct list *instrs, * variables work. */ static void append_output_var_copy(struct hlsl_ctx *ctx, struct list *instrs, struct hlsl_ir_var *var) { + struct path_arg *path = path_arg_init(ctx); + if (var->data_type->type == HLSL_CLASS_STRUCT) - append_output_struct_copy(ctx, instrs, var, var->data_type, 0); + append_output_struct_copy(ctx, instrs, var, var->data_type, path); + else if (var->data_type->type == HLSL_CLASS_MATRIX) + append_output_matrix_copy(ctx, instrs, var, var->data_type, path, var->modifiers, &var->semantic); else if (var->semantic.name) - append_output_copy(ctx, instrs, var, var->data_type, 0, var->modifiers, &var->semantic); + append_output_copy(ctx, instrs, var, var->data_type, path, var->modifiers, &var->semantic); + + path_arg_free(path); } static bool transform_ir(struct hlsl_ctx *ctx, bool (*func)(struct hlsl_ctx *ctx, struct hlsl_ir_node *, void *), @@ -779,42 +1039,53 @@ 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_store *split_store; + struct path_arg *split_load_path = path_arg_copy_from_deref(ctx, &load->src); + struct path_arg *split_store_path = path_arg_copy_from_deref(ctx, &store->lhs); 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); + struct hlsl_ir_store *split_store; - 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); + path_arg_add_node(ctx, split_load_path, &y->node); + path_arg_add_node(ctx, split_store_path, &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); + path_arg_add_node(ctx, split_load_path, &x->node); + path_arg_add_node(ctx, split_store_path, &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); + path_arg_add_node(ctx, split_load_path, &c->node); + path_arg_add_node(ctx, split_store_path, &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(ctx, load->src.var, split_load_path, type, store->node.loc))) + return false; + list_add_before(&store->node.entry, &split_load->node.entry); + + if (!(split_store = hlsl_new_store(ctx, store->lhs.var, split_store_path, &split_load->node, 0, store->node.loc))) return false; list_add_before(&store->node.entry, &split_store->node.entry); + path_arg_free(split_load_path); + path_arg_free(split_store_path); + return true; } @@ -823,8 +1094,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; @@ -835,7 +1106,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) { @@ -845,7 +1115,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; } @@ -863,6 +1133,7 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr const struct hlsl_ir_node *rhs; const struct hlsl_type *type; struct hlsl_ir_store *store; + unsigned int k = 0; if (instr->type != HLSL_IR_STORE) return false; @@ -881,8 +1152,9 @@ static bool split_struct_copies(struct hlsl_ctx *ctx, struct hlsl_ir_node *instr LIST_FOR_EACH_ENTRY(field, type->e.elements, struct hlsl_struct_field, entry) { - if (!split_copy(ctx, store, hlsl_ir_load(rhs), field->reg_offset, field->type)) + if (!split_copy(ctx, store, hlsl_ir_load(rhs), k, field->type)) return false; + ++k; } /* Remove the store instruction, so that we can split structs which contain @@ -909,7 +1181,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) { @@ -917,9 +1189,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; } @@ -1942,6 +2214,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