[PATCH vkd3d 07/12] vkd3d-shader/hlsl: Replace register offsets with index paths in parse code.

Francisco Casas fcasas at codeweavers.com
Fri Jul 8 16:04:18 CDT 2022



On 08-07-22 11:43, Giovanni Mascellani wrote:
> Hi,
> 
> a first round on this one. Given that it's pretty large, I think I'll 
> need some more thinking next week.
> 
> Il 01/07/22 23:24, Francisco Casas ha scritto:
>> The transform_deref_paths_into_offsets pass turns these index paths back
>> into register offsets, they should not be used anywhere before that.
>>
>> Signed-off-by: Francisco Casas <fcasas at codeweavers.com>
>>
>> ---
>>
>> The idea is that we can move this pass forward as we translate more
>> passes to work with index paths. This, until register offsets can be
>> totally removed, after we implement the SMxIRs and their translations.
>>
>> The aim is to have 3 ways of initializing load/store nodes when using 
>> index
>> paths:
>>
>> * One that initializes the node from a another's node deref and and
>>    optional index to be appended to that deref's path.
>> * One that initializes the node from a deref and the index
>>    of a single basic component within it. This one also generates 
>> constant
>>    nodes for the required path, so it also initializes an instruction 
>> block
>>    whose instructions must be inserted in the instruction list.
>> * One that initializes the node directly for a whole variable. These 
>> functions
>>    are already present: hlsl_new_var_load() and hlsl_new_simple_store().
>>
>> The signatures of these functions were placed nearby in hlsl.h
>>
>> hlsl_new_resource_load() was modified to receive deref arguments instead
>> of var+offset pairs.
>>
>> It is worth noting that the use of index paths allows to remove the 
>> data type
>> argument when initializing store/loads because it can now be deducted 
>> from the
>> variable and the hlsl_deref.
>>
>> Applying an index over a matrix derefence retrieves a vector. If the 
>> matrix
>> is row_major, this corresponds to a row, otherwise, it corresponds to a
>> column. So, the code should take matrix majority into account, at 
>> least until
>> the split_matrix_copies pass.
>>
>> The first index in a path after a loading a struct should be an
>> hlsl_ir_constant, since the field that's being addressed is always
>> known at parse-time.
>>
>> hlsl_get_direct_var_deref() can be used to create a deref value that can
>> be passed by reference in the first 2 cases. This value shall not be
>> modified after being created.
>>
>> Signed-off-by: Francisco Casas <fcasas at codeweavers.com>
>> ---
>>   libs/vkd3d-shader/hlsl.c         | 371 +++++++++++++++++++++++++++----
>>   libs/vkd3d-shader/hlsl.h         |  35 ++-
>>   libs/vkd3d-shader/hlsl.y         | 147 +++++-------
>>   libs/vkd3d-shader/hlsl_codegen.c |  71 ++++++
>>   4 files changed, 469 insertions(+), 155 deletions(-)
>>
>> diff --git a/libs/vkd3d-shader/hlsl.c b/libs/vkd3d-shader/hlsl.c
>> index 17ccd305..c7416054 100644
>> --- a/libs/vkd3d-shader/hlsl.c
>> +++ b/libs/vkd3d-shader/hlsl.c
>> @@ -249,39 +249,51 @@ static struct hlsl_type *hlsl_new_type(struct 
>> hlsl_ctx *ctx, const char *name, e
>>       return type;
>>   }
>> -/* Returns the register offset of a given component within a type, 
>> given its index.
>> - * *comp_type will be set to the type of the component. */
>> -unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, 
>> struct hlsl_type *type,
>> -        unsigned int idx, struct hlsl_type **comp_type)
>> +/* Returns the path of a given component within a type, given its index.
>> + * *comp_type will be set to the type of the component.
>> + * *path_len will be set to the lenght of the path.
>> + * Memory should be free afterwards.
>> + */
>> +unsigned int *hlsl_compute_component_path(struct hlsl_ctx *ctx, 
>> struct hlsl_type *type,
>> +        unsigned int idx, struct hlsl_type **comp_type, unsigned int 
>> *path_len)
>>   {
>> +    unsigned int *path;
>> +
>>       switch (type->type)
>>       {
> 
> Notice that here and elsewhere you don't need to put braces around a 
> case block, unless you want to declare variables in it. I am not sure of 
> what is suggested when some case blocks declare variables and others don't.
> 
> On the other hand, I think we tend to leave a blank line between case 
> blocks.
> 

I see. I will modify the switch blocks in the next version then.
(And try to remember these rules!).

>>           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;
> 
> Hmm, this means that this function can return NULL even if it succeeds. 
> You're clearly aware of that because when checking for failure you look 
> at both the returned pointer and the path length, but it seems to me an 
> unidiomatic form. Maybe it's better to allocate one byte here and 
> stipulate that the function returns NULL if and only if it fails?
> 

That's a good idea; I will change it for the next version too.

>> +        }
>>           case HLSL_CLASS_VECTOR:
>>           {
>>               assert(idx < type->dimx * type->dimy);
> 
> Isn't dimy always 1 for vectors?
> 

Yes. Well, this may also cover if we ever assing type->dimy = 0 by 
mistake. I am not sure what's better; seems superfluous.

>>               *comp_type = hlsl_get_scalar_type(ctx, type->base_type);
>> -            return idx;
>> +            *path_len = 1;
>> +            if (!(path = hlsl_alloc(ctx, 1 * sizeof(unsigned int))))
>> +                return NULL;
>> +            path[0] = idx;
>> +            return path;
>>           }
>>           case HLSL_CLASS_MATRIX:
>>           {
>> -            unsigned int minor, major, x = idx % type->dimx, y = idx 
>> / type->dimx;
>> +            unsigned int y = idx / type->dimx, x = idx % type->dimx;
>> +            bool row_major = hlsl_type_is_row_major(type);
>>               assert(idx < type->dimx * type->dimy);
>> -            if (hlsl_type_is_row_major(type))
>> -            {
>> -                minor = x;
>> -                major = y;
>> -            }
>> -            else
>> -            {
>> -                minor = y;
>> -                major = x;
>> -            }
>> -
>>               *comp_type = hlsl_get_scalar_type(ctx, type->base_type);
>> -            return 4 * major + minor;
>> +            *path_len = 2;
>> +            if (!(path = hlsl_alloc(ctx, 2 * sizeof(unsigned int))))
>> +                return NULL;
>> +            path[0] = row_major? y : x;
>> +            path[1] = row_major? x : y;
>> +            return path;
>>           }
>>           case HLSL_CLASS_ARRAY:
>> @@ -289,45 +301,64 @@ unsigned int 
>> hlsl_compute_component_offset(struct hlsl_ctx *ctx, struct hlsl_typ
>>               unsigned int elem_comp_count = 
>> hlsl_type_component_count(type->e.array.type);
>>               unsigned int array_idx = idx / elem_comp_count;
>>               unsigned int idx_in_elem = idx % elem_comp_count;
>> +            unsigned int elem_path_len;
>> +            unsigned int *elem_path;
>> -            assert(array_idx < type->e.array.elements_count);
> 
> Didn't this assertion make sense? Given that equivalent ones are present 
> in the other branches, I'd leave it.
> 

Okay, I don't know why I deleted it.

>> +            elem_path = hlsl_compute_component_path(ctx, 
>> type->e.array.type, idx_in_elem, comp_type, &elem_path_len);
>> +            if (elem_path_len && !elem_path)
>> +                return NULL;
>> -            return array_idx * 
>> hlsl_type_get_array_element_reg_size(type->e.array.type) +
>> -                    hlsl_compute_component_offset(ctx, 
>> type->e.array.type, idx_in_elem, comp_type);
>> +            *path_len = elem_path_len + 1;
>> +            if (!(path = hlsl_alloc(ctx, (*path_len) * 
>> sizeof(unsigned int))))
>> +            {
>> +                vkd3d_free(elem_path);
>> +                return NULL;
>> +            }
>> +            memcpy(path + 1, elem_path, elem_path_len * 
>> sizeof(unsigned int));
>> +            vkd3d_free(elem_path);
>> +            path[0] = array_idx;
>> +            return path;
>>           }
>>           case HLSL_CLASS_STRUCT:
>>           {
>>               struct hlsl_struct_field *field;
>> -            unsigned int elem_comp_count, i;
>> +            unsigned int field_comp_count, i;
>>               for (i = 0; i < type->e.record.field_count; ++i)
>>               {
>>                   field = &type->e.record.fields[i];
>> -                elem_comp_count = 
>> hlsl_type_component_count(field->type);
>> +                field_comp_count = 
>> hlsl_type_component_count(field->type);
>> -                if (idx < elem_comp_count)
>> +                if (idx < field_comp_count)
>>                   {
>> -                    return field->reg_offset +
>> -                            hlsl_compute_component_offset(ctx, 
>> field->type, idx, comp_type);
>> +                    unsigned int field_path_len;
>> +                    unsigned int *field_path;
>> +
>> +                    field_path = hlsl_compute_component_path(ctx, 
>> field->type, idx, comp_type, &field_path_len);
>> +                    if (field_path_len && !field_path)
>> +                        return NULL;
>> +
>> +                    *path_len = field_path_len + 1;
>> +                    if (!(path = hlsl_alloc(ctx, (*path_len) * 
>> sizeof(unsigned int))))
>> +                    {
>> +                        vkd3d_free(field_path);
>> +                        return NULL;
>> +                    }
>> +                    memcpy(path + 1, field_path, field_path_len * 
>> sizeof(unsigned int));
>> +                    vkd3d_free(field_path);
>> +                    path[0] = i;
>> +                    return path;
>>                   }
>> -                idx -= elem_comp_count;
>> +                idx -= field_comp_count;
>>               }
>> -
>>               assert(0);
>> -            return 0;
>> -        }
>> -
>> -        case HLSL_CLASS_OBJECT:
>> -        {
>> -            assert(idx == 0);
>> -            *comp_type = type;
>> -            return 0;
>> +            return NULL;
>>           }
>>       }
>>       assert(0);
>> -    return 0;
>> +    return NULL;
>>   }
>>   struct hlsl_type *hlsl_get_type_from_path_index(struct hlsl_ctx 
>> *ctx, const struct hlsl_type *type,
>> @@ -733,6 +764,62 @@ static bool type_is_single_reg(const struct 
>> hlsl_type *type)
>>       return type->type == HLSL_CLASS_SCALAR || type->type == 
>> HLSL_CLASS_VECTOR;
>>   }
>> +static bool init_deref(struct hlsl_ctx *ctx, struct hlsl_deref 
>> *deref, struct hlsl_ir_var *var,
>> +        unsigned int path_len)
>> +{
>> +    deref->var = var;
>> +    deref->path_len = path_len;
>> +    deref->offset.node = NULL;
>> +
>> +    if (path_len == 0)
>> +    {
>> +        deref->path = NULL;
>> +        return true;
>> +    }
>> +
>> +    if (!(deref->path = hlsl_alloc(ctx, sizeof(*deref->path) * 
>> deref->path_len)))
>> +    {
>> +        deref->var = NULL;
>> +        deref->path_len = 0;
>> +        return false;
>> +    }
>> +
>> +    return true;
>> +}
>> +
>> +static bool deref_copy(struct hlsl_ctx *ctx, struct hlsl_deref 
>> *deref, struct hlsl_deref *other)
>> +{
>> +    unsigned int i;
>> +
>> +    if (!other)
>> +    {
>> +        deref->var = NULL;
>> +        deref->path = NULL;
>> +        deref->path_len = 0;
> 
> I guess you're forgetting "offset" here? BTW, with a memset you can 
> initialize everything in one line.
> 

Well, deref_copy() isn't intended to copy dereferences that use offsets 
instead of index paths. Maybe I should add an

assert(!other->offset);

>> +        return true;
>> +    }
>> +
>> +    if (!init_deref(ctx, deref, other->var, other->path_len))
>> +        return false;
>> +
>> +    for (i = 0; i < deref->path_len; ++i)
>> +        hlsl_src_from_node(&deref->path[i], other->path[i].node);
>> +
>> +    hlsl_src_from_node(&deref->offset, other->offset.node);
>> +
>> +    return true;
>> +}
>> +
>> +static struct hlsl_type *get_type_from_deref(struct hlsl_ctx *ctx, 
>> const struct hlsl_deref *deref)
>> +{
>> +    struct hlsl_type *type = deref->var->data_type;
>> +    unsigned int i;
>> +
>> +    for (i = 0; i < deref->path_len; ++i)
>> +        type = hlsl_get_type_from_path_index(ctx, type, 
>> deref->path[i].node);
>> +    return type;
>> +}
>> +
>>   struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var, struct hlsl_ir_node *offset,
>>           struct hlsl_ir_node *rhs, unsigned int writemask, struct 
>> vkd3d_shader_location loc)
>>   {
>> @@ -745,16 +832,113 @@ struct hlsl_ir_store *hlsl_new_store(struct 
>> hlsl_ctx *ctx, struct hlsl_ir_var *v
>>           return NULL;
>>       init_node(&store->node, HLSL_IR_STORE, NULL, loc);
>> -    store->lhs.var = var;
>> +    init_deref(ctx, &store->lhs, var, 0);
>>       hlsl_src_from_node(&store->lhs.offset, offset);
>>       hlsl_src_from_node(&store->rhs, rhs);
>>       store->writemask = writemask;
>>       return store;
>>   }
>> +/* Returns a simple variable derefence, so that the value can be 
>> stored and then passed by reference
>> + * to load/store functions. It shall not be modified afterwards. */
>> +struct hlsl_deref hlsl_get_direct_var_deref(struct hlsl_ir_var *var)
>> +{
>> +    struct hlsl_deref deref = {};
>> +
>> +    deref.var = var;
>> +    return deref;
>> +}
>> +
>>   struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, 
>> struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs)
>>   {
>> -    return hlsl_new_store(ctx, lhs, NULL, rhs, 0, rhs->loc);
>> +    struct hlsl_deref lhs_deref = hlsl_get_direct_var_deref(lhs);
>> +
>> +    return hlsl_new_store_index(ctx, &lhs_deref, NULL, rhs, 0, 
>> rhs->loc);
>> +}
>> +
>> +struct hlsl_ir_store *hlsl_new_store_index(struct hlsl_ctx *ctx, 
>> const struct hlsl_deref *lhs,
>> +        struct hlsl_ir_node *idx, struct hlsl_ir_node *rhs, unsigned 
>> int writemask, struct vkd3d_shader_location loc)
>> +{
>> +    struct hlsl_ir_store *store;
>> +    unsigned int i;
>> +
>> +    assert(lhs);
>> +
>> +    if (!(store = hlsl_alloc(ctx, sizeof(*store))))
>> +        return NULL;
>> +    init_node(&store->node, HLSL_IR_STORE, NULL, loc);
>> +
>> +    if (!init_deref(ctx, &store->lhs, lhs->var, lhs->path_len + !!idx))
>> +        return NULL;
>> +    for (i = 0; i < lhs->path_len; ++i)
>> +        hlsl_src_from_node(&store->lhs.path[i], lhs->path[i].node);
>> +    if (idx)
>> +        hlsl_src_from_node(&store->lhs.path[i], idx);
> 
> Using "i" here makes the code more obscure than it should be. Could you 
> please use "lhs->path_len" instead?
> 

Roger.

>> +    hlsl_src_from_node(&store->rhs, rhs);
>> +
>> +    if (!writemask && type_is_single_reg(rhs->data_type))
>> +        writemask = (1 << rhs->data_type->dimx) - 1;
>> +    store->writemask = writemask;
>> +
>> +    return store;
>> +}
>> +
>> +struct hlsl_ir_store *hlsl_new_store_component(struct hlsl_ctx *ctx, 
>> struct hlsl_block *block,
>> +        const struct hlsl_deref *lhs, unsigned int comp, struct 
>> hlsl_ir_node *rhs)
>> +{
>> +    struct hlsl_type *type, *comp_type;
>> +    unsigned int *path, path_len, i;
>> +    struct hlsl_ir_store *store;
>> +    struct hlsl_ir_constant *c;
>> +
>> +    list_init(&block->instrs);
>> +
>> +    if (!(store = hlsl_alloc(ctx, sizeof(*store))))
>> +        return NULL;
>> +    init_node(&store->node, HLSL_IR_STORE, NULL, rhs->loc);
>> +
>> +    type = get_type_from_deref(ctx, lhs);
>> +    path = hlsl_compute_component_path(ctx, type, comp, &comp_type, 
>> &path_len);
>> +    if (path_len && !path)
>> +    {
>> +        vkd3d_free(store);
>> +        return NULL;
>> +    }
>> +
>> +    if (!init_deref(ctx, &store->lhs, lhs->var, lhs->path_len + 
>> path_len))
>> +    {
>> +        vkd3d_free(path);
>> +        vkd3d_free(store);
>> +        return NULL;
>> +    }
>> +
>> +    for (i = 0; i < lhs->path_len; ++i)
>> +        hlsl_src_from_node(&store->lhs.path[i], lhs->path[i].node);
>> +    for (i = 0; i < path_len; ++i)
>> +    {
>> +        if (!(c = hlsl_new_uint_constant(ctx, path[i], &rhs->loc)))
>> +        {
>> +            vkd3d_free(path);
>> +            hlsl_free_instr_list(&block->instrs);
>> +            hlsl_free_deref(&store->lhs);
>> +            vkd3d_free(store);
>> +            return NULL;
>> +        }
>> +        list_add_tail(&block->instrs, &c->node.entry);
>> +
>> +        hlsl_src_from_node(&store->lhs.path[lhs->path_len + i], 
>> &c->node);
>> +    }
>> +    vkd3d_free(path);
>> +
>> +    hlsl_src_from_node(&store->rhs, rhs);
>> +
>> +    if (type_is_single_reg(rhs->data_type))
>> +        store->writemask = (1 << rhs->data_type->dimx) - 1;
>> +
>> +    list_add_tail(&block->instrs, &store->node.entry);
>> +
>> +    return store;
>>   }
>>   struct hlsl_ir_constant *hlsl_new_constant(struct hlsl_ctx *ctx, 
>> struct hlsl_type *type,
>> @@ -848,21 +1032,103 @@ struct hlsl_ir_load *hlsl_new_load(struct 
>> hlsl_ctx *ctx, struct hlsl_ir_var *var
>>       if (!(load = hlsl_alloc(ctx, sizeof(*load))))
>>           return NULL;
>>       init_node(&load->node, HLSL_IR_LOAD, type, loc);
>> -    load->src.var = var;
>> +    init_deref(ctx, &load->src, var, 0);
>>       hlsl_src_from_node(&load->src.offset, offset);
>>       return load;
>>   }
>> +struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const 
>> struct hlsl_deref *deref,
>> +        struct hlsl_ir_node *idx, struct vkd3d_shader_location loc)
>> +{
>> +    struct hlsl_ir_load *load;
>> +    struct hlsl_type *type;
>> +    unsigned int i;
>> +
>> +    type = get_type_from_deref(ctx, deref);
>> +    if (idx)
>> +        type = hlsl_get_type_from_path_index(ctx, type, idx);
>> +
>> +    if (!(load = hlsl_alloc(ctx, sizeof(*load))))
>> +        return NULL;
>> +    init_node(&load->node, HLSL_IR_LOAD, type, loc);
>> +
>> +    if (!init_deref(ctx, &load->src, deref->var, deref->path_len + 
>> !!idx))
>> +    {
>> +        vkd3d_free(load);
>> +        return NULL;
>> +    }
>> +    for (i = 0; i < deref->path_len; ++i)
>> +        hlsl_src_from_node(&load->src.path[i], deref->path[i].node);
>> +    if (idx)
>> +        hlsl_src_from_node(&load->src.path[i], idx);
> 
> Same as above.
> 

Roger, roger.

>> +
>> +    return load;
>> +}
>> +
>>   struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var,
>> -        const struct vkd3d_shader_location loc)
>> +        struct vkd3d_shader_location loc)
>>   {
>> -    return hlsl_new_load(ctx, var, NULL, var->data_type, loc);
>> +    struct hlsl_deref var_deref = hlsl_get_direct_var_deref(var);
>> +
>> +    return hlsl_new_load_index(ctx, &var_deref, NULL, loc);
>> +}
>> +
>> +struct hlsl_ir_load *hlsl_new_load_component(struct hlsl_ctx *ctx, 
>> struct hlsl_block *block,
>> +        const struct hlsl_deref *deref, unsigned int comp, struct 
>> vkd3d_shader_location loc)
>> +{
>> +    struct hlsl_type *type, *comp_type;
>> +    unsigned int *path, path_len, i;
>> +    struct hlsl_ir_constant *c;
>> +    struct hlsl_ir_load *load;
>> +
>> +    list_init(&block->instrs);
>> +
>> +    type = get_type_from_deref(ctx, deref);
>> +    path = hlsl_compute_component_path(ctx, type, comp, &comp_type, 
>> &path_len);
>> +    if (path_len && !path)
>> +        return NULL;
>> +
>> +    if (!(load = hlsl_alloc(ctx, sizeof(*load))))
>> +    {
>> +        vkd3d_free(path);
>> +        return NULL;
>> +    }
>> +    init_node(&load->node, HLSL_IR_LOAD, comp_type, loc);
>> +
>> +
> 
> There are two blank lines here, I belive that's a mistake?
> 

Ah, yes!

>> +    if (!init_deref(ctx, &load->src, deref->var, deref->path_len + 
>> path_len))
>> +    {
>> +        vkd3d_free(path);
>> +        vkd3d_free(load);
>> +        return NULL;
>> +    }
>> +
>> +    for (i = 0; i < deref->path_len; ++i)
>> +        hlsl_src_from_node(&load->src.path[i], deref->path[i].node);
>> +    for (i = 0; i < path_len; ++i)
>> +    {
>> +        if (!(c = hlsl_new_uint_constant(ctx, path[i], &loc)))
>> +        {
>> +            vkd3d_free(path);
>> +            hlsl_free_instr_list(&block->instrs);
>> +            hlsl_free_deref(&load->src);
>> +            vkd3d_free(load);
>> +            return NULL;
>> +        }
>> +        list_add_tail(&block->instrs, &c->node.entry);
>> +
>> +        hlsl_src_from_node(&load->src.path[deref->path_len + i], 
>> &c->node);
>> +    }
>> +    vkd3d_free(path);
>> +
>> +    list_add_tail(&block->instrs, &load->node.entry);
>> +
>> +    return load;
>>   }
>>   struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx 
>> *ctx, struct hlsl_type *data_type,
>> -        enum hlsl_resource_load_type type, struct hlsl_ir_var 
>> *resource, struct hlsl_ir_node *resource_offset,
>> -        struct hlsl_ir_var *sampler, struct hlsl_ir_node 
>> *sampler_offset, struct hlsl_ir_node *coords,
>> -        struct hlsl_ir_node *texel_offset, const struct 
>> vkd3d_shader_location *loc)
>> +        enum hlsl_resource_load_type type, struct hlsl_deref 
>> *resource, struct hlsl_deref *sampler,
>> +        struct hlsl_ir_node *coords, struct hlsl_ir_node 
>> *texel_offset, const struct vkd3d_shader_location *loc)
>>   {
>>       struct hlsl_ir_resource_load *load;
>> @@ -870,10 +1136,8 @@ struct hlsl_ir_resource_load 
>> *hlsl_new_resource_load(struct hlsl_ctx *ctx, struc
>>           return NULL;
>>       init_node(&load->node, HLSL_IR_RESOURCE_LOAD, data_type, *loc);
>>       load->load_type = type;
>> -    load->resource.var = resource;
>> -    hlsl_src_from_node(&load->resource.offset, resource_offset);
>> -    load->sampler.var = sampler;
>> -    hlsl_src_from_node(&load->sampler.offset, sampler_offset);
>> +    deref_copy(ctx, &load->resource, resource);
>> +    deref_copy(ctx, &load->sampler, sampler);
>>       hlsl_src_from_node(&load->coords, coords);
>>       hlsl_src_from_node(&load->texel_offset, texel_offset);
>>       return load;
>> @@ -1664,6 +1928,15 @@ void hlsl_free_instr_list(struct list *list)
>>   void hlsl_free_deref(struct hlsl_deref *deref)
>>   {
>> +    unsigned int i;
>> +
>> +    for (i = 0; i < deref->path_len; ++i)
>> +        hlsl_src_remove(&deref->path[i]);
>> +    vkd3d_free(deref->path);
>> +
>> +    deref->path = NULL;
>> +    deref->path_len = 0;
>> +
>>       hlsl_src_remove(&deref->offset);
>>   }
>> diff --git a/libs/vkd3d-shader/hlsl.h b/libs/vkd3d-shader/hlsl.h
>> index fbadd9c6..d3885540 100644
>> --- a/libs/vkd3d-shader/hlsl.h
>> +++ b/libs/vkd3d-shader/hlsl.h
>> @@ -374,6 +374,10 @@ struct hlsl_ir_swizzle
>>   struct hlsl_deref
>>   {
>>       struct hlsl_ir_var *var;
>> +
>> +    unsigned int path_len;
>> +    struct hlsl_src *path;
>> +
>>       struct hlsl_src offset;
>>   };
>> @@ -753,14 +757,29 @@ struct hlsl_ir_if *hlsl_new_if(struct hlsl_ctx 
>> *ctx, struct hlsl_ir_node *condit
>>   struct hlsl_ir_constant *hlsl_new_int_constant(struct hlsl_ctx *ctx, 
>> int n,
>>           const struct vkd3d_shader_location *loc);
>>   struct hlsl_ir_jump *hlsl_new_jump(struct hlsl_ctx *ctx, enum 
>> hlsl_ir_jump_type type, struct vkd3d_shader_location loc);
>> +
>> +struct hlsl_deref hlsl_get_direct_var_deref(struct hlsl_ir_var *var);
>> +
>> +struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var,
>> +        struct vkd3d_shader_location loc);
>> +struct hlsl_ir_load *hlsl_new_load_index(struct hlsl_ctx *ctx, const 
>> struct hlsl_deref *deref,
>> +        struct hlsl_ir_node *idx, struct vkd3d_shader_location loc);
>> +struct hlsl_ir_load *hlsl_new_load_component(struct hlsl_ctx *ctx, 
>> struct hlsl_block *block,
>> +        const struct hlsl_deref *deref, unsigned int comp, struct 
>> vkd3d_shader_location loc);
>> +
>> +struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, 
>> struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs);
>> +struct hlsl_ir_store *hlsl_new_store_index(struct hlsl_ctx *ctx, 
>> const struct hlsl_deref *lhs,
>> +        struct hlsl_ir_node *idx, struct hlsl_ir_node *rhs, unsigned 
>> int writemask, struct vkd3d_shader_location loc);
>> +struct hlsl_ir_store *hlsl_new_store_component(struct hlsl_ctx *ctx, 
>> struct hlsl_block *block,
>> +        const struct hlsl_deref *lhs, unsigned int comp, struct 
>> hlsl_ir_node *rhs);
>> +
>> +struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx 
>> *ctx, struct hlsl_type *data_type,
>> +        enum hlsl_resource_load_type type, struct hlsl_deref 
>> *resource, struct hlsl_deref *sampler,
>> +        struct hlsl_ir_node *coords, struct hlsl_ir_node 
>> *texel_offset, const struct vkd3d_shader_location *loc);
>> +
>>   struct hlsl_ir_load *hlsl_new_load(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var, struct hlsl_ir_node *offset,
>>           struct hlsl_type *type, struct vkd3d_shader_location loc);
>>   struct hlsl_ir_loop *hlsl_new_loop(struct hlsl_ctx *ctx, struct 
>> vkd3d_shader_location loc);
>> -struct hlsl_ir_resource_load *hlsl_new_resource_load(struct hlsl_ctx 
>> *ctx, struct hlsl_type *data_type,
>> -        enum hlsl_resource_load_type type, struct hlsl_ir_var 
>> *resource, struct hlsl_ir_node *resource_offset,
>> -        struct hlsl_ir_var *sampler, struct hlsl_ir_node 
>> *sampler_offset, struct hlsl_ir_node *coords,
>> -        struct hlsl_ir_node *texel_offset, const struct 
>> vkd3d_shader_location *loc);
>> -struct hlsl_ir_store *hlsl_new_simple_store(struct hlsl_ctx *ctx, 
>> struct hlsl_ir_var *lhs, struct hlsl_ir_node *rhs);
>>   struct hlsl_ir_store *hlsl_new_store(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var, struct hlsl_ir_node *offset,
>>           struct hlsl_ir_node *rhs, unsigned int writemask, struct 
>> vkd3d_shader_location loc);
>>   struct hlsl_type *hlsl_new_struct_type(struct hlsl_ctx *ctx, const 
>> char *name,
>> @@ -777,8 +796,6 @@ struct hlsl_ir_node *hlsl_new_unary_expr(struct 
>> hlsl_ctx *ctx, enum hlsl_ir_expr
>>   struct hlsl_ir_var *hlsl_new_var(struct hlsl_ctx *ctx, const char 
>> *name, struct hlsl_type *type,
>>           const struct vkd3d_shader_location loc, const struct 
>> hlsl_semantic *semantic, unsigned int modifiers,
>>           const struct hlsl_reg_reservation *reg_reservation);
>> -struct hlsl_ir_load *hlsl_new_var_load(struct hlsl_ctx *ctx, struct 
>> hlsl_ir_var *var,
>> -        const struct vkd3d_shader_location loc);
>>   void hlsl_error(struct hlsl_ctx *ctx, const struct 
>> vkd3d_shader_location *loc,
>>           enum vkd3d_shader_error error, const char *fmt, ...) 
>> VKD3D_PRINTF_FUNC(4, 5);
>> @@ -798,8 +815,8 @@ struct hlsl_type *hlsl_type_clone(struct hlsl_ctx 
>> *ctx, struct hlsl_type *old,
>>           unsigned int default_majority, unsigned int modifiers);
>>   unsigned int hlsl_type_component_count(struct hlsl_type *type);
>>   unsigned int hlsl_type_get_array_element_reg_size(const struct 
>> hlsl_type *type);
>> -unsigned int hlsl_compute_component_offset(struct hlsl_ctx *ctx, 
>> struct hlsl_type *type,
>> -        unsigned int idx, struct hlsl_type **comp_type);
>> +unsigned int *hlsl_compute_component_path(struct hlsl_ctx *ctx, 
>> struct hlsl_type *type,
>> +        unsigned int idx, struct hlsl_type **comp_type, unsigned int 
>> *path_len);
>>   bool hlsl_type_is_row_major(const struct hlsl_type *type);
>>   unsigned int hlsl_type_minor_size(const struct hlsl_type *type);
>>   unsigned int hlsl_type_major_size(const struct hlsl_type *type);
>> diff --git a/libs/vkd3d-shader/hlsl.y b/libs/vkd3d-shader/hlsl.y
>> index 63904580..ed45d54f 100644
>> --- a/libs/vkd3d-shader/hlsl.y
>> +++ b/libs/vkd3d-shader/hlsl.y
>> @@ -289,6 +289,7 @@ static struct hlsl_ir_node *add_cast(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>       {
>>           struct vkd3d_string_buffer *name;
>>           static unsigned int counter = 0;
>> +        struct hlsl_deref var_deref;
>>           struct hlsl_ir_load *load;
>>           struct hlsl_ir_var *var;
>>           unsigned int dst_idx;
>> @@ -308,13 +309,14 @@ static struct hlsl_ir_node *add_cast(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>           vkd3d_string_buffer_release(&ctx->string_buffers, name);
>>           if (!var)
>>               return NULL;
>> +        var_deref = hlsl_get_direct_var_deref(var);
>>           for (dst_idx = 0; dst_idx < dst_type->dimx * dst_type->dimy; 
>> ++dst_idx)
>>           {
>> +            unsigned int src_idx, *dst_path, dst_path_len;
>>               struct hlsl_type *dst_scalar_type;
>> -            unsigned int src_idx, dst_offset;
>>               struct hlsl_ir_store *store;
>> -            struct hlsl_ir_constant *c;
>> +            struct hlsl_block block;
>>               if (broadcast)
>>               {
>> @@ -334,7 +336,10 @@ static struct hlsl_ir_node *add_cast(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>                   }
>>               }
>> -            dst_offset = hlsl_compute_component_offset(ctx, dst_type, 
>> dst_idx, &dst_scalar_type);
>> +            dst_path = hlsl_compute_component_path(ctx, dst_type, 
>> dst_idx, &dst_scalar_type, &dst_path_len);
>> +            if (dst_path_len && !dst_path)
>> +                return NULL;
>> +            vkd3d_free(dst_path);
>>               if (!(load = add_load_component(ctx, instrs, node, 
>> src_idx, *loc)))
>>                   return NULL;
>> @@ -343,16 +348,12 @@ static struct hlsl_ir_node *add_cast(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>                   return NULL;
>>               list_add_tail(instrs, &cast->node.entry);
>> -            if (!(c = hlsl_new_uint_constant(ctx, dst_offset, loc)))
>> +            if (!(store = hlsl_new_store_component(ctx, &block, 
>> &var_deref, dst_idx, &cast->node)))
>>                   return NULL;
>> -            list_add_tail(instrs, &c->node.entry);
>> -
>> -            if (!(store = hlsl_new_store(ctx, var, &c->node, 
>> &cast->node, 0, *loc)))
>> -                return NULL;
>> -            list_add_tail(instrs, &store->node.entry);
>> +            list_move_tail(instrs, &block.instrs);
> 
> It's not wrong, and maybe it could even be accepted as it is, but here 
> you're basically computing the path, then dropping it, then computing it 
> again.
> 

Well, I needed to do

dst_path = hlsl_compute_component_path(ctx, dst_type, dst_idx, 
&dst_scalar_type, &dst_path_len);

just to obtain the dst_scalar_type, to create the cast node which is 
passed to the store.

I could add a function just to get the type from the component but it 
would have a somewhat redudant implementation. Another idea may be 
having functions to initialize a store/load from a path, but I don't 
think that adding different ways of doing the same thing is good.

Also, I don't think that the overhead of this approach is significative, 
so I would keep this implementation. For now at least.

>>           }
>> -        if (!(load = hlsl_new_load(ctx, var, NULL, dst_type, *loc)))
>> +        if (!(load = hlsl_new_var_load(ctx, var, *loc)))
>>               return NULL;
>>           list_add_tail(instrs, &load->node.entry);
>> @@ -625,22 +626,13 @@ static struct hlsl_ir_jump *add_return(struct 
>> hlsl_ctx *ctx, struct list *instrs
>>   static struct hlsl_ir_load *add_load_index(struct hlsl_ctx *ctx, 
>> struct list *instrs, struct hlsl_ir_node *var_node,
>>           struct hlsl_ir_node *idx, const struct vkd3d_shader_location 
>> loc)
>>   {
>> -    struct hlsl_type *elem_type;
>> -    struct hlsl_ir_node *offset;
>>       struct hlsl_ir_load *load;
>> -    struct hlsl_block block;
>> -
>> -    elem_type = hlsl_get_type_from_path_index(ctx, 
>> var_node->data_type, idx);
>>       if (var_node->type == HLSL_IR_LOAD)
>>       {
>>           const struct hlsl_deref *src = &hlsl_ir_load(var_node)->src;
>> -        if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, 
>> var_node->data_type, src->offset.node, idx, &loc)))
>> -            return NULL;
>> -        list_move_tail(instrs, &block.instrs);
>> -
>> -        if (!(load = hlsl_new_load(ctx, src->var, offset, elem_type, 
>> loc)))
>> +        if (!(load = hlsl_new_load_index(ctx, src, idx, loc)))
>>               return NULL;
>>           list_add_tail(instrs, &load->node.entry);
>>       }
>> @@ -650,10 +642,6 @@ static struct hlsl_ir_load *add_load_index(struct 
>> hlsl_ctx *ctx, struct list *in
>>           struct hlsl_ir_var *var;
>>           char name[27];
>> -        if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, 
>> var_node->data_type, NULL, idx, &loc)))
>> -            return NULL;
>> -        list_move_tail(instrs, &block.instrs);
>> -
>>           sprintf(name, "<deref-%p>", var_node);
>>           if (!(var = hlsl_new_synthetic_var(ctx, name, 
>> var_node->data_type, var_node->loc)))
>>               return NULL;
>> @@ -662,7 +650,7 @@ static struct hlsl_ir_load *add_load_index(struct 
>> hlsl_ctx *ctx, struct list *in
>>               return NULL;
>>           list_add_tail(instrs, &store->node.entry);
>> -        if (!(load = hlsl_new_load(ctx, var, offset, elem_type, loc)))
>> +        if (!(load = hlsl_new_load_index(ctx, &store->lhs, idx, loc)))
>>               return NULL;
>>           list_add_tail(instrs, &load->node.entry);
>>       }
>> @@ -673,38 +661,16 @@ static struct hlsl_ir_load 
>> *add_load_index(struct hlsl_ctx *ctx, struct list *in
>>   static struct hlsl_ir_load *add_load_component(struct hlsl_ctx *ctx, 
>> struct list *instrs, struct hlsl_ir_node *var_node,
>>           unsigned int comp, const struct vkd3d_shader_location loc)
>>   {
>> -    struct hlsl_type *comp_type;
>> -    struct hlsl_ir_node *offset;
>> -    struct hlsl_ir_constant *c;
>>       struct hlsl_ir_load *load;
>> -    unsigned int comp_offset;
>> -    struct hlsl_ir_var *var;
>> -
>> -    comp_offset = hlsl_compute_component_offset(ctx, 
>> var_node->data_type, comp, &comp_type);
>> -
>> -    if (!(c = hlsl_new_uint_constant(ctx, comp_offset, &loc)))
>> -        return NULL;
>> -    list_add_tail(instrs, &c->node.entry);
>> -
>> -    offset = &c->node;
>> +    struct hlsl_block block;
>>       if (var_node->type == HLSL_IR_LOAD)
>>       {
>>           const struct hlsl_deref *src = &hlsl_ir_load(var_node)->src;
>> -        struct hlsl_ir_node *add;
>> -
>> -        var = src->var;
>> -        if (src->offset.node)
>> -        {
>> -            if (!(add = hlsl_new_binary_expr(ctx, HLSL_OP2_ADD, 
>> src->offset.node, &c->node)))
>> -                return NULL;
>> -            list_add_tail(instrs, &add->entry);
>> -            offset = add;
>> -        }
>> -        if (!(load = hlsl_new_load(ctx, var, offset, comp_type, loc)))
>> +        if (!(load = hlsl_new_load_component(ctx, &block, src, comp, 
>> loc)))
>>               return NULL;
>> -        list_add_tail(instrs, &load->node.entry);
>> +        list_move_tail(instrs, &block.instrs);
>>       }
>>       else
>>       {
>> @@ -720,9 +686,9 @@ static struct hlsl_ir_load 
>> *add_load_component(struct hlsl_ctx *ctx, struct list
>>               return NULL;
>>           list_add_tail(instrs, &store->node.entry);
>> -        if (!(load = hlsl_new_load(ctx, var, offset, comp_type, loc)))
>> +        if (!(load = hlsl_new_load_component(ctx, &block, 
>> &store->lhs, comp, loc)))
>>               return NULL;
>> -        list_add_tail(instrs, &load->node.entry);
>> +        list_move_tail(instrs, &block.instrs);
>>       }
>>       return load;
>> @@ -752,6 +718,7 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, 
>> struct list *instrs,
>>       struct hlsl_type *mat_type = matrix->data_type, *ret_type;
>>       struct vkd3d_string_buffer *name;
>>       static unsigned int counter = 0;
>> +    struct hlsl_deref var_deref;
>>       struct hlsl_ir_load *load;
>>       struct hlsl_ir_var *var;
>>       unsigned int i;
>> @@ -767,12 +734,14 @@ static bool add_matrix_index(struct hlsl_ctx 
>> *ctx, struct list *instrs,
>>       vkd3d_string_buffer_release(&ctx->string_buffers, name);
>>       if (!var)
>>           return false;
>> +    var_deref = hlsl_get_direct_var_deref(var);
>>       for (i = 0; i < mat_type->dimx; ++i)
>>       {
>>           struct hlsl_ir_load *column, *value;
>>           struct hlsl_ir_store *store;
>>           struct hlsl_ir_constant *c;
>> +        struct hlsl_block block;
>>           if (!(c = hlsl_new_uint_constant(ctx, i, loc)))
>>               return false;
>> @@ -784,9 +753,9 @@ static bool add_matrix_index(struct hlsl_ctx *ctx, 
>> struct list *instrs,
>>           if (!(value = add_load_index(ctx, instrs, &column->node, 
>> index, *loc)))
>>               return false;
>> -        if (!(store = hlsl_new_store(ctx, var, &c->node, 
>> &value->node, 0, *loc)))
>> +        if (!(store = hlsl_new_store_component(ctx, &block, 
>> &var_deref, i, &value->node)))
>>               return false;
>> -        list_add_tail(instrs, &store->node.entry);
>> +        list_move_tail(instrs, &block.instrs);
>>       }
>>       if (!(load = hlsl_new_var_load(ctx, var, *loc)))
>> @@ -1234,6 +1203,7 @@ static struct hlsl_ir_node *add_expr(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>           struct vkd3d_string_buffer *name;
>>           static unsigned int counter = 0;
>>           struct hlsl_type *vector_type;
>> +        struct hlsl_deref var_deref;
>>           struct hlsl_ir_load *load;
>>           struct hlsl_ir_var *var;
>> @@ -1245,6 +1215,7 @@ static struct hlsl_ir_node *add_expr(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>           vkd3d_string_buffer_release(&ctx->string_buffers, name);
>>           if (!var)
>>               return NULL;
>> +        var_deref = hlsl_get_direct_var_deref(var);
>>           for (i = 0; i < hlsl_type_major_size(type); i++)
>>           {
>> @@ -1272,16 +1243,12 @@ static struct hlsl_ir_node *add_expr(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>               if (!(value = add_expr(ctx, instrs, op, vector_operands, 
>> vector_type, loc)))
>>                   return NULL;
>> -            if (!(c = hlsl_new_uint_constant(ctx, 4 * i, loc)))
>> -                return NULL;
>> -            list_add_tail(instrs, &c->node.entry);
>> -
>> -            if (!(store = hlsl_new_store(ctx, var, &c->node, value, 
>> 0, *loc)))
>> +            if (!(store = hlsl_new_store_index(ctx, &var_deref, 
>> &c->node, value, 0, *loc)))
>>                   return NULL;
>>               list_add_tail(instrs, &store->node.entry);
>>           }
>> -        if (!(load = hlsl_new_load(ctx, var, NULL, type, *loc)))
>> +        if (!(load = hlsl_new_var_load(ctx, var, *loc)))
>>               return NULL;
>>           list_add_tail(instrs, &load->node.entry);
>> @@ -1664,15 +1631,11 @@ static struct hlsl_ir_node 
>> *add_assignment(struct hlsl_ctx *ctx, struct list *in
>>               return NULL;
>>       }
>> -    if (!(store = hlsl_alloc(ctx, sizeof(*store))))
>> -        return NULL;
>> -
>>       while (lhs->type != HLSL_IR_LOAD)
>>       {
>>           if (lhs->type == HLSL_IR_EXPR && hlsl_ir_expr(lhs)->op == 
>> HLSL_OP1_CAST)
>>           {
>>               hlsl_fixme(ctx, &lhs->loc, "Cast on the LHS.");
>> -            vkd3d_free(store);
>>               return NULL;
>>           }
>>           else if (lhs->type == HLSL_IR_SWIZZLE)
>> @@ -1686,13 +1649,11 @@ static struct hlsl_ir_node 
>> *add_assignment(struct hlsl_ctx *ctx, struct list *in
>>               if (!invert_swizzle(&s, &writemask, &width))
>>               {
>>                   hlsl_error(ctx, &lhs->loc, 
>> VKD3D_SHADER_ERROR_HLSL_INVALID_WRITEMASK, "Invalid writemask.");
>> -                vkd3d_free(store);
>>                   return NULL;
>>               }
>>               if (!(new_swizzle = hlsl_new_swizzle(ctx, s, width, rhs, 
>> &swizzle->node.loc)))
>>               {
>> -                vkd3d_free(store);
>>                   return NULL;
>>               }
>>               list_add_tail(instrs, &new_swizzle->node.entry);
>> @@ -1703,16 +1664,12 @@ static struct hlsl_ir_node 
>> *add_assignment(struct hlsl_ctx *ctx, struct list *in
>>           else
>>           {
>>               hlsl_error(ctx, &lhs->loc, 
>> VKD3D_SHADER_ERROR_HLSL_INVALID_LVALUE, "Invalid lvalue.");
>> -            vkd3d_free(store);
>>               return NULL;
>>           }
>>       }
>> -    init_node(&store->node, HLSL_IR_STORE, NULL, lhs->loc);
>> -    store->writemask = writemask;
>> -    store->lhs.var = hlsl_ir_load(lhs)->src.var;
>> -    hlsl_src_from_node(&store->lhs.offset, 
>> hlsl_ir_load(lhs)->src.offset.node);
>> -    hlsl_src_from_node(&store->rhs, rhs);
>> +    if (!(store = hlsl_new_store_index(ctx, &hlsl_ir_load(lhs)->src, 
>> NULL, rhs, writemask, rhs->loc)))
>> +        return NULL;
>>       list_add_tail(instrs, &store->node.entry);
>>       /* Don't use the instruction itself as a source, as this makes 
>> structure
>> @@ -1761,32 +1718,32 @@ static void initialize_var_components(struct 
>> hlsl_ctx *ctx, struct list *instrs,
>>           struct hlsl_ir_var *dst, unsigned int *store_index, struct 
>> hlsl_ir_node *src)
>>   {
>>       unsigned int src_comp_count = 
>> hlsl_type_component_count(src->data_type);
>> +    struct hlsl_deref dst_deref = hlsl_get_direct_var_deref(dst);
>>       unsigned int k;
>>       for (k = 0; k < src_comp_count; ++k)
>>       {
>> +        unsigned int dst_path_len, *dst_path;
>>           struct hlsl_type *dst_comp_type;
>> -        unsigned int dst_reg_offset;
>>           struct hlsl_ir_store *store;
>> -        struct hlsl_ir_constant *c;
>>           struct hlsl_ir_load *load;
>>           struct hlsl_ir_node *conv;
>> +        struct hlsl_block block;
>>           if (!(load = add_load_component(ctx, instrs, src, k, 
>> src->loc)))
>>               return;
>> -        dst_reg_offset = hlsl_compute_component_offset(ctx, 
>> dst->data_type, *store_index, &dst_comp_type);
>> -
>> -        if (!(conv = add_implicit_conversion(ctx, instrs, 
>> &load->node, dst_comp_type, &src->loc)))
>> +        dst_path = hlsl_compute_component_path(ctx, dst->data_type, 
>> *store_index, &dst_comp_type, &dst_path_len);
>> +        if (dst_path_len && !dst_path)
>>               return;
>> +        vkd3d_free(dst_path);
>> -        if (!(c = hlsl_new_uint_constant(ctx, dst_reg_offset, 
>> &src->loc)))
>> +        if (!(conv = add_implicit_conversion(ctx, instrs, 
>> &load->node, dst_comp_type, &src->loc)))
>>               return;
>> -        list_add_tail(instrs, &c->node.entry);
>> -        if (!(store = hlsl_new_store(ctx, dst, &c->node, conv, 0, 
>> src->loc)))
>> +        if (!(store = hlsl_new_store_component(ctx, &block, 
>> &dst_deref, *store_index, conv)))
>>               return;
>> -        list_add_tail(instrs, &store->node.entry);
>> +        list_move_tail(instrs, &block.instrs);
> 
> Same as above. Though on second thought it might really be the case that 
> it's the best alternative, at least for the moment.
> >>           ++*store_index;
>>       }
>> @@ -2151,6 +2108,7 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx,
>>       unsigned int i, j, k, vect_count = 0;
>>       struct vkd3d_string_buffer *name;
>>       static unsigned int counter = 0;
>> +    struct hlsl_deref var_deref;
>>       struct hlsl_ir_load *load;
>>       struct hlsl_ir_var *var;
>> @@ -2197,15 +2155,15 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx,
>>       vkd3d_string_buffer_release(&ctx->string_buffers, name);
>>       if (!var)
>>           return false;
>> +    var_deref = hlsl_get_direct_var_deref(var);
>>       for (i = 0; i < matrix_type->dimx; ++i)
>> +    {
>>           for (j = 0; j < matrix_type->dimy; ++j)
>>           {
>>               struct hlsl_ir_node *node = NULL;
>> -            struct hlsl_type *scalar_type;
>>               struct hlsl_ir_store *store;
>> -            struct hlsl_ir_constant *c;
>> -            unsigned int offset;
>> +            struct hlsl_block block;
>>               for (k = 0; k < cast_type1->dimx && k < 
>> cast_type2->dimy; ++k)
>>               {
>> @@ -2232,17 +2190,13 @@ static bool intrinsic_mul(struct hlsl_ctx *ctx,
>>                   }
>>               }
>> -            offset = hlsl_compute_component_offset(ctx, matrix_type, 
>> j * matrix_type->dimx + i, &scalar_type);
>> -            if (!(c = hlsl_new_uint_constant(ctx, offset, loc)))
>> -                return false;
>> -            list_add_tail(params->instrs, &c->node.entry);
>> -
>> -            if (!(store = hlsl_new_store(ctx, var, &c->node, node, 0, 
>> *loc)))
>> +            if (!(store = hlsl_new_store_component(ctx, &block, 
>> &var_deref, j * matrix_type->dimx + i, node)))
>>                   return false;
>> -            list_add_tail(params->instrs, &store->node.entry);
>> +            list_move_tail(params->instrs, &block.instrs);
>>           }
>> +    }
>> -    if (!(load = hlsl_new_load(ctx, var, NULL, matrix_type, *loc)))
>> +    if (!(load = hlsl_new_var_load(ctx, var, *loc)))
>>           return false;
>>       list_add_tail(params->instrs, &load->node.entry);
>> @@ -2478,7 +2432,7 @@ static bool add_method_call(struct hlsl_ctx 
>> *ctx, struct list *instrs, struct hl
>>               return false;
>>           if (!(load = hlsl_new_resource_load(ctx, 
>> object_type->e.resource_format, HLSL_RESOURCE_LOAD,
>> -                object_load->src.var, object_load->src.offset.node, 
>> NULL, NULL, coords, NULL, loc)))
>> +                &object_load->src, NULL, coords, NULL, loc)))
>>               return false;
>>           list_add_tail(instrs, &load->node.entry);
>>           return true;
>> @@ -2529,10 +2483,10 @@ static bool add_method_call(struct hlsl_ctx 
>> *ctx, struct list *instrs, struct hl
>>           }
>>           if (!(load = hlsl_new_resource_load(ctx, 
>> object_type->e.resource_format,
>> -                HLSL_RESOURCE_SAMPLE, object_load->src.var, 
>> object_load->src.offset.node,
>> -                sampler_load->src.var, sampler_load->src.offset.node, 
>> coords, offset, loc)))
>> +                HLSL_RESOURCE_SAMPLE, &object_load->src, 
>> &sampler_load->src, coords, offset, loc)))
>>               return false;
>>           list_add_tail(instrs, &load->node.entry);
>> +
>>           return true;
>>       }
>>       else if ((!strcmp(name, "Gather") || !strcmp(name, "GatherRed") 
>> || !strcmp(name, "GatherBlue")
>> @@ -2633,8 +2587,7 @@ static bool add_method_call(struct hlsl_ctx 
>> *ctx, struct list *instrs, struct hl
>>               return false;
>>           if (!(load = hlsl_new_resource_load(ctx, result_type,
>> -                load_type, object_load->src.var, 
>> object_load->src.offset.node,
>> -                sampler_load->src.var, sampler_load->src.offset.node, 
>> coords, offset, loc)))
>> +                load_type, &object_load->src, &sampler_load->src, 
>> coords, offset, loc)))
>>               return false;
>>           list_add_tail(instrs, &load->node.entry);
>>           return true;
>> diff --git a/libs/vkd3d-shader/hlsl_codegen.c 
>> b/libs/vkd3d-shader/hlsl_codegen.c
>> index 373439af..513e599e 100644
>> --- a/libs/vkd3d-shader/hlsl_codegen.c
>> +++ b/libs/vkd3d-shader/hlsl_codegen.c
>> @@ -21,6 +21,75 @@
>>   #include "hlsl.h"
>>   #include <stdio.h>
>> +/* TODO: remove when no longer needed, only used for 
>> transform_deref_paths_into_offsets() */
>> +static void replace_deref_path_with_offset(struct hlsl_ctx *ctx, 
>> struct hlsl_deref *deref,
>> +        struct hlsl_ir_node *instr)
>> +{
>> +    struct hlsl_ir_node *offset;
>> +    struct hlsl_type *type;
>> +    unsigned int i;
>> +
>> +    if (!deref->var)
>> +        return;
>> +
>> +    type = deref->var->data_type;
>> +
>> +    /* register offsets shouldn't be used before this point is 
>> reached. */
>> +    assert(!deref->offset.node);
>> +
>> +    offset = NULL;
>> +
>> +    for (i = 0; i < deref->path_len; ++i)
>> +    {
>> +        struct hlsl_ir_node *block_instr, *block_next;
>> +        struct hlsl_block block;
>> +
>> +        if (!(offset = hlsl_new_offset_from_path_index(ctx, &block, 
>> type, offset, deref->path[i].node, &instr->loc)))
>> +            return;
>> +
>> +        LIST_FOR_EACH_ENTRY_SAFE(block_instr, block_next, 
>> &block.instrs, struct hlsl_ir_node, entry)
>> +        {
>> +            list_remove(&block_instr->entry);
>> +            list_add_before(&instr->entry, &block_instr->entry);
>> +        }
> 
> Unless I am mistaken, list_move_tail() should do the same thing (but 
> faster).
> 

Good point, as we agreed upon, I will add Zeb's

b810928d zfigura include: Add list_move_after() and list_move_before().

before this one so that we use list_add_before() instead.

>> +
>> +        type = hlsl_get_type_from_path_index(ctx, type, 
>> deref->path[i].node);
>> +    }
>> +
>> +    hlsl_free_deref(deref);
>> +    hlsl_src_from_node(&deref->offset, offset);
>> +}
>> +
>> +/* TODO: remove when no longer needed. */
>> +static bool transform_deref_paths_into_offsets(struct hlsl_ctx *ctx, 
>> struct hlsl_ir_node *instr, void *context)
>> +{
>> +    switch(instr->type)
>> +    {
>> +        case HLSL_IR_LOAD:
>> +        {
>> +            replace_deref_path_with_offset(ctx, 
>> &hlsl_ir_load(instr)->src, instr);
>> +            return true;
>> +        }
>> +
>> +        case HLSL_IR_STORE:
>> +        {
>> +            replace_deref_path_with_offset(ctx, 
>> &hlsl_ir_store(instr)->lhs, instr);
>> +            return true;
>> +        }
>> +
>> +        case HLSL_IR_RESOURCE_LOAD:
>> +        {
>> +            replace_deref_path_with_offset(ctx, 
>> &hlsl_ir_resource_load(instr)->resource, instr);
>> +            replace_deref_path_with_offset(ctx, 
>> &hlsl_ir_resource_load(instr)->sampler, instr);
>> +            return true;
>> +        }
>> +
>> +        default:
>> +            return false;
>> +    }
>> +    return false;
>> +}
>> +
>>   /* Split uniforms into two variables representing the constant and temp
>>    * registers, and copy the former to the latter, so that writes to 
>> uniforms
>>    * work. */
>> @@ -1890,6 +1959,8 @@ int hlsl_emit_bytecode(struct hlsl_ctx *ctx, 
>> struct hlsl_ir_function_decl *entry
>>       list_move_head(&body->instrs, &ctx->static_initializers);
>> +    transform_ir(ctx, transform_deref_paths_into_offsets, body, 
>> NULL); /* TODO: move forward, remove when no longer needed */
>> +
>>       LIST_FOR_EACH_ENTRY(var, &ctx->globals->vars, struct 
>> hlsl_ir_var, scope_entry)
>>       {
>>           if (var->modifiers & HLSL_STORAGE_UNIFORM)
> 
> Thanks, Giovanni.
> 



More information about the wine-devel mailing list