2 * Copyright © 2015 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_builder.h"
26 #include "nir_control_flow.h"
28 struct inline_functions_state
{
34 static bool inline_function_impl(nir_function_impl
*impl
, struct set
*inlined
);
37 rewrite_param_derefs_block(nir_block
*block
, void *void_state
)
39 nir_call_instr
*call
= void_state
;
41 nir_foreach_instr_safe(block
, instr
) {
42 if (instr
->type
!= nir_instr_type_intrinsic
)
45 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
48 i
< nir_intrinsic_infos
[intrin
->intrinsic
].num_variables
; i
++) {
49 if (intrin
->variables
[i
]->var
->data
.mode
!= nir_var_param
)
52 int param_idx
= intrin
->variables
[i
]->var
->data
.location
;
54 nir_deref_var
*call_deref
;
56 assert(param_idx
< call
->callee
->num_params
);
57 call_deref
= call
->params
[param_idx
];
59 call_deref
= call
->return_deref
;
63 nir_deref_var
*new_deref
= nir_deref_as_var(nir_copy_deref(intrin
, &call_deref
->deref
));
64 nir_deref
*new_tail
= nir_deref_tail(&new_deref
->deref
);
65 new_tail
->child
= intrin
->variables
[i
]->deref
.child
;
66 ralloc_steal(new_tail
, new_tail
->child
);
67 intrin
->variables
[i
] = new_deref
;
75 lower_param_to_local(nir_variable
*param
, nir_function_impl
*impl
, bool write
)
77 if (param
->data
.mode
!= nir_var_param
)
80 nir_parameter_type param_type
;
81 if (param
->data
.location
>= 0) {
82 assert(param
->data
.location
< impl
->num_params
);
83 param_type
= impl
->function
->params
[param
->data
.location
].param_type
;
86 param_type
= nir_parameter_out
;
89 if ((write
&& param_type
== nir_parameter_in
) ||
90 (!write
&& param_type
== nir_parameter_out
)) {
91 /* In this case, we need a shadow copy. Turn it into a local */
92 param
->data
.mode
= nir_var_local
;
93 exec_list_push_tail(&impl
->locals
, ¶m
->node
);
98 lower_params_to_locals_block(nir_block
*block
, void *void_state
)
100 nir_function_impl
*impl
= void_state
;
102 nir_foreach_instr_safe(block
, instr
) {
103 if (instr
->type
!= nir_instr_type_intrinsic
)
106 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
108 switch (intrin
->intrinsic
) {
109 case nir_intrinsic_store_var
:
110 lower_param_to_local(intrin
->variables
[0]->var
, impl
, true);
113 case nir_intrinsic_copy_var
:
114 lower_param_to_local(intrin
->variables
[0]->var
, impl
, true);
115 lower_param_to_local(intrin
->variables
[1]->var
, impl
, false);
118 case nir_intrinsic_load_var
:
119 /* All other intrinsics which access variables (image_load_store)
120 * do so in a read-only fasion.
123 i
< nir_intrinsic_infos
[intrin
->intrinsic
].num_variables
; i
++) {
124 lower_param_to_local(intrin
->variables
[i
]->var
, impl
, false);
137 inline_functions_block(nir_block
*block
, void *void_state
)
139 struct inline_functions_state
*state
= void_state
;
141 nir_builder
*b
= &state
->builder
;
143 /* This is tricky. We're iterating over instructions in a block but, as
144 * we go, the block and its instruction list are being split into
145 * pieces. However, this *should* be safe since foreach_safe always
146 * stashes the next thing in the iteration. That next thing will
147 * properly get moved to the next block when it gets split, and we
148 * continue iterating there.
150 nir_foreach_instr_safe(block
, instr
) {
151 if (instr
->type
!= nir_instr_type_call
)
154 state
->progress
= true;
156 nir_call_instr
*call
= nir_instr_as_call(instr
);
157 assert(call
->callee
->impl
);
159 inline_function_impl(call
->callee
->impl
, state
->inlined
);
161 nir_function_impl
*callee_copy
=
162 nir_function_impl_clone(call
->callee
->impl
);
163 callee_copy
->function
= call
->callee
;
165 /* Add copies of all in parameters */
166 assert(call
->num_params
== callee_copy
->num_params
);
168 exec_list_append(&b
->impl
->locals
, &callee_copy
->locals
);
169 exec_list_append(&b
->impl
->registers
, &callee_copy
->registers
);
171 b
->cursor
= nir_before_instr(&call
->instr
);
173 /* We now need to tie the two functions together using the
174 * parameters. There are two ways we do this: One is to turn the
175 * parameter into a local variable and do a shadow-copy. The other
176 * is to treat the parameter as a "proxy" and rewrite derefs to use
177 * the actual variable that comes from the call instruction. We
178 * implement both schemes. The first is needed in the case where we
179 * have an in parameter that we write or similar. The second case is
180 * needed for handling things such as images and uniforms properly.
183 /* Figure out when we need to lower to a shadow local */
184 nir_foreach_block(callee_copy
, lower_params_to_locals_block
, callee_copy
);
185 for (unsigned i
= 0; i
< callee_copy
->num_params
; i
++) {
186 nir_variable
*param
= callee_copy
->params
[i
];
188 if (param
->data
.mode
== nir_var_local
&&
189 call
->callee
->params
[i
].param_type
!= nir_parameter_out
) {
190 nir_copy_deref_var(b
, nir_deref_var_create(b
->shader
, param
),
195 nir_foreach_block(callee_copy
, rewrite_param_derefs_block
, call
);
197 /* Pluck the body out of the function and place it here */
199 nir_cf_list_extract(&body
, &callee_copy
->body
);
200 nir_cf_reinsert(&body
, b
->cursor
);
202 b
->cursor
= nir_before_instr(&call
->instr
);
204 /* Add copies of all out parameters and the return */
205 assert(call
->num_params
== callee_copy
->num_params
);
206 for (unsigned i
= 0; i
< callee_copy
->num_params
; i
++) {
207 nir_variable
*param
= callee_copy
->params
[i
];
209 if (param
->data
.mode
== nir_var_local
&&
210 call
->callee
->params
[i
].param_type
!= nir_parameter_in
) {
211 nir_copy_deref_var(b
, call
->params
[i
],
212 nir_deref_var_create(b
->shader
, param
));
215 if (!glsl_type_is_void(call
->callee
->return_type
) &&
216 callee_copy
->return_var
->data
.mode
== nir_var_local
) {
217 nir_copy_deref_var(b
, call
->return_deref
,
218 nir_deref_var_create(b
->shader
,
219 callee_copy
->return_var
));
222 nir_instr_remove(&call
->instr
);
229 inline_function_impl(nir_function_impl
*impl
, struct set
*inlined
)
231 if (_mesa_set_search(inlined
, impl
))
232 return false; /* Already inlined */
234 struct inline_functions_state state
;
236 state
.inlined
= inlined
;
237 state
.progress
= false;
238 nir_builder_init(&state
.builder
, impl
);
240 nir_foreach_block(impl
, inline_functions_block
, &state
);
242 if (state
.progress
) {
243 /* SSA and register indices are completely messed up now */
244 nir_index_ssa_defs(impl
);
245 nir_index_local_regs(impl
);
247 nir_metadata_preserve(impl
, nir_metadata_none
);
250 _mesa_set_add(inlined
, impl
);
252 return state
.progress
;
256 nir_inline_functions(nir_shader
*shader
)
258 struct set
*inlined
= _mesa_set_create(NULL
, _mesa_hash_pointer
,
259 _mesa_key_pointer_equal
);
260 bool progress
= false;
262 nir_foreach_function(shader
, function
) {
264 progress
= inline_function_impl(function
->impl
, inlined
) || progress
;
267 _mesa_set_destroy(inlined
, NULL
);