2 * Copyright © 2018 Intel Corporation
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 #include "nir_deref.h"
27 struct split_struct_state
{
30 struct hash_table
*var_to_member_map
;
34 find_var_member(struct nir_variable
*var
, unsigned member
,
35 struct hash_table
*var_to_member_map
)
37 struct hash_entry
*map_entry
=
38 _mesa_hash_table_search(var_to_member_map
, var
);
39 if (map_entry
== NULL
)
42 nir_variable
**members
= map_entry
->data
;
43 assert(member
< var
->num_members
);
44 return members
[member
];
47 static const struct glsl_type
*
48 member_type(const struct glsl_type
*type
, unsigned index
)
50 if (glsl_type_is_array(type
)) {
51 const struct glsl_type
*elem
=
52 member_type(glsl_get_array_element(type
), index
);
53 return glsl_get_array_instance(elem
, glsl_get_length(type
));
55 assert(glsl_type_is_struct(type
));
56 assert(index
< glsl_get_length(type
));
57 return glsl_get_struct_field(type
, index
);
62 split_variable(struct nir_variable
*var
, nir_shader
*shader
,
63 struct hash_table
*var_to_member_map
, void *dead_ctx
)
65 assert(var
->state_slots
== NULL
);
67 /* Constant initializers are currently not handled */
68 assert(var
->constant_initializer
== NULL
);
70 nir_variable
**members
=
71 ralloc_array(dead_ctx
, nir_variable
*, var
->num_members
);
73 for (unsigned i
= 0; i
< var
->num_members
; i
++) {
74 char *member_name
= NULL
;
76 /* Calculate a reasonable variable name */
77 member_name
= ralloc_strdup(dead_ctx
, var
->name
);
78 const struct glsl_type
*t
= var
->type
;
79 while (glsl_type_is_array(t
)) {
80 ralloc_strcat(&member_name
, "[*]");
81 t
= glsl_get_array_element(t
);
83 const char *field_name
= glsl_get_struct_elem_name(t
, i
);
85 member_name
= ralloc_asprintf(dead_ctx
, "%s.%s",
86 member_name
, field_name
);
88 member_name
= ralloc_asprintf(dead_ctx
, "%s.@%d", member_name
, i
);
93 nir_variable_create(shader
, var
->members
[i
].mode
,
94 member_type(var
->type
, i
), member_name
);
95 if (var
->interface_type
) {
96 members
[i
]->interface_type
=
97 glsl_get_struct_field(var
->interface_type
, i
);
99 members
[i
]->data
= var
->members
[i
];
102 _mesa_hash_table_insert(var_to_member_map
, var
, members
);
106 split_variables_in_list(struct exec_list
*var_list
, nir_shader
*shader
,
107 struct hash_table
*var_to_member_map
, void *dead_ctx
)
109 bool progress
= false;
111 nir_foreach_variable_safe(var
, var_list
) {
112 if (var
->num_members
== 0)
115 split_variable(var
, shader
, var_to_member_map
, dead_ctx
);
116 exec_node_remove(&var
->node
);
123 static nir_deref_instr
*
124 build_member_deref(nir_builder
*b
, nir_deref_instr
*deref
, nir_variable
*member
)
126 if (deref
->deref_type
== nir_deref_type_var
) {
127 return nir_build_deref_var(b
, member
);
129 nir_deref_instr
*parent
=
130 build_member_deref(b
, nir_deref_instr_parent(deref
), member
);
131 return nir_build_deref_follower(b
, parent
, deref
);
136 rewrite_deref_instr(nir_builder
*b
, nir_deref_instr
*deref
,
137 struct hash_table
*var_to_member_map
)
139 /* We must be a struct deref */
140 if (deref
->deref_type
!= nir_deref_type_struct
)
143 nir_deref_instr
*base
;
144 for (base
= nir_deref_instr_parent(deref
);
145 base
&& base
->deref_type
!= nir_deref_type_var
;
146 base
= nir_deref_instr_parent(base
)) {
148 /* If this struct is nested inside another, bail */
149 if (base
->deref_type
== nir_deref_type_struct
)
153 /* We must be on a variable with members */
154 if (!base
|| base
->var
->num_members
== 0)
157 nir_variable
*member
= find_var_member(base
->var
, deref
->strct
.index
,
161 b
->cursor
= nir_before_instr(&deref
->instr
);
162 nir_deref_instr
*member_deref
=
163 build_member_deref(b
, nir_deref_instr_parent(deref
), member
);
164 nir_ssa_def_rewrite_uses(&deref
->dest
.ssa
,
165 nir_src_for_ssa(&member_deref
->dest
.ssa
));
167 /* The referenced variable is no longer valid, clean up the deref */
168 nir_deref_instr_remove_if_unused(deref
);
172 nir_split_per_member_structs(nir_shader
*shader
)
174 bool progress
= false;
175 void *dead_ctx
= ralloc_context(NULL
);
176 struct hash_table
*var_to_member_map
=
177 _mesa_hash_table_create(dead_ctx
, _mesa_hash_pointer
,
178 _mesa_key_pointer_equal
);
180 progress
|= split_variables_in_list(&shader
->inputs
, shader
,
181 var_to_member_map
, dead_ctx
);
182 progress
|= split_variables_in_list(&shader
->outputs
, shader
,
183 var_to_member_map
, dead_ctx
);
184 progress
|= split_variables_in_list(&shader
->system_values
, shader
,
185 var_to_member_map
, dead_ctx
);
189 nir_foreach_function(function
, shader
) {
194 nir_builder_init(&b
, function
->impl
);
195 nir_foreach_block(block
, function
->impl
) {
196 nir_foreach_instr_safe(instr
, block
) {
197 if (instr
->type
== nir_instr_type_deref
) {
198 rewrite_deref_instr(&b
, nir_instr_as_deref(instr
),
205 ralloc_free(dead_ctx
);