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 assert(glsl_get_explicit_stride(type
) == 0);
54 return glsl_array_type(elem
, glsl_get_length(type
), 0);
56 assert(glsl_type_is_struct_or_ifc(type
));
57 assert(index
< glsl_get_length(type
));
58 return glsl_get_struct_field(type
, index
);
63 split_variable(struct nir_variable
*var
, nir_shader
*shader
,
64 struct hash_table
*var_to_member_map
, void *dead_ctx
)
66 assert(var
->state_slots
== NULL
);
68 /* Constant initializers are currently not handled */
69 assert(var
->constant_initializer
== NULL
&& var
->pointer_initializer
== NULL
);
71 nir_variable
**members
=
72 ralloc_array(dead_ctx
, nir_variable
*, var
->num_members
);
74 for (unsigned i
= 0; i
< var
->num_members
; i
++) {
75 char *member_name
= NULL
;
77 /* Calculate a reasonable variable name */
78 member_name
= ralloc_strdup(dead_ctx
, var
->name
);
79 const struct glsl_type
*t
= var
->type
;
80 while (glsl_type_is_array(t
)) {
81 ralloc_strcat(&member_name
, "[*]");
82 t
= glsl_get_array_element(t
);
84 const char *field_name
= glsl_get_struct_elem_name(t
, i
);
86 member_name
= ralloc_asprintf(dead_ctx
, "%s.%s",
87 member_name
, field_name
);
89 member_name
= ralloc_asprintf(dead_ctx
, "%s.@%d", member_name
, i
);
94 nir_variable_create(shader
, var
->members
[i
].mode
,
95 member_type(var
->type
, i
), member_name
);
96 if (var
->interface_type
) {
97 members
[i
]->interface_type
=
98 glsl_get_struct_field(var
->interface_type
, i
);
100 members
[i
]->data
= var
->members
[i
];
103 _mesa_hash_table_insert(var_to_member_map
, var
, members
);
106 static nir_deref_instr
*
107 build_member_deref(nir_builder
*b
, nir_deref_instr
*deref
, nir_variable
*member
)
109 if (deref
->deref_type
== nir_deref_type_var
) {
110 return nir_build_deref_var(b
, member
);
112 nir_deref_instr
*parent
=
113 build_member_deref(b
, nir_deref_instr_parent(deref
), member
);
114 return nir_build_deref_follower(b
, parent
, deref
);
119 rewrite_deref_instr(nir_builder
*b
, nir_deref_instr
*deref
,
120 struct hash_table
*var_to_member_map
)
122 /* We must be a struct deref */
123 if (deref
->deref_type
!= nir_deref_type_struct
)
126 nir_deref_instr
*base
;
127 for (base
= nir_deref_instr_parent(deref
);
128 base
&& base
->deref_type
!= nir_deref_type_var
;
129 base
= nir_deref_instr_parent(base
)) {
131 /* If this struct is nested inside another, bail */
132 if (base
->deref_type
== nir_deref_type_struct
)
136 /* We must be on a variable with members */
137 if (!base
|| base
->var
->num_members
== 0)
140 nir_variable
*member
= find_var_member(base
->var
, deref
->strct
.index
,
144 b
->cursor
= nir_before_instr(&deref
->instr
);
145 nir_deref_instr
*member_deref
=
146 build_member_deref(b
, nir_deref_instr_parent(deref
), member
);
147 nir_ssa_def_rewrite_uses(&deref
->dest
.ssa
,
148 nir_src_for_ssa(&member_deref
->dest
.ssa
));
150 /* The referenced variable is no longer valid, clean up the deref */
151 nir_deref_instr_remove_if_unused(deref
);
155 nir_split_per_member_structs(nir_shader
*shader
)
157 bool progress
= false;
158 void *dead_ctx
= ralloc_context(NULL
);
159 struct hash_table
*var_to_member_map
=
160 _mesa_pointer_hash_table_create(dead_ctx
);
162 nir_foreach_variable_with_modes_safe(var
, shader
, nir_var_shader_in
|
164 nir_var_system_value
) {
165 if (var
->num_members
== 0)
168 split_variable(var
, shader
, var_to_member_map
, dead_ctx
);
169 exec_node_remove(&var
->node
);
174 ralloc_free(dead_ctx
);
178 nir_foreach_function(function
, shader
) {
183 nir_builder_init(&b
, function
->impl
);
184 nir_foreach_block(block
, function
->impl
) {
185 nir_foreach_instr_safe(instr
, block
) {
186 if (instr
->type
== nir_instr_type_deref
) {
187 rewrite_deref_instr(&b
, nir_instr_as_deref(instr
),
193 nir_metadata_preserve(function
->impl
,
194 nir_metadata_block_index
|
195 nir_metadata_dominance
);
198 ralloc_free(dead_ctx
);