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 static bool inline_function_impl(nir_function_impl
*impl
, struct set
*inlined
);
31 rewrite_param_derefs(nir_instr
*instr
, nir_call_instr
*call
)
33 if (instr
->type
!= nir_instr_type_intrinsic
)
36 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
39 i
< nir_intrinsic_infos
[intrin
->intrinsic
].num_variables
; i
++) {
40 if (intrin
->variables
[i
]->var
->data
.mode
!= nir_var_param
)
43 int param_idx
= intrin
->variables
[i
]->var
->data
.location
;
45 nir_deref_var
*call_deref
;
47 assert(param_idx
< call
->callee
->num_params
);
48 call_deref
= call
->params
[param_idx
];
50 call_deref
= call
->return_deref
;
54 nir_deref_var
*new_deref
= nir_deref_as_var(nir_copy_deref(intrin
, &call_deref
->deref
));
55 nir_deref
*new_tail
= nir_deref_tail(&new_deref
->deref
);
56 new_tail
->child
= intrin
->variables
[i
]->deref
.child
;
57 ralloc_steal(new_tail
, new_tail
->child
);
58 intrin
->variables
[i
] = new_deref
;
63 lower_param_to_local(nir_variable
*param
, nir_function_impl
*impl
, bool write
)
65 if (param
->data
.mode
!= nir_var_param
)
68 nir_parameter_type param_type
;
69 if (param
->data
.location
>= 0) {
70 assert(param
->data
.location
< impl
->num_params
);
71 param_type
= impl
->function
->params
[param
->data
.location
].param_type
;
74 param_type
= nir_parameter_out
;
77 if ((write
&& param_type
== nir_parameter_in
) ||
78 (!write
&& param_type
== nir_parameter_out
)) {
79 /* In this case, we need a shadow copy. Turn it into a local */
80 param
->data
.mode
= nir_var_local
;
81 exec_list_push_tail(&impl
->locals
, ¶m
->node
);
86 lower_params_to_locals_block(nir_block
*block
, nir_function_impl
*impl
)
88 nir_foreach_instr(instr
, block
) {
89 if (instr
->type
!= nir_instr_type_intrinsic
)
92 nir_intrinsic_instr
*intrin
= nir_instr_as_intrinsic(instr
);
94 switch (intrin
->intrinsic
) {
95 case nir_intrinsic_store_var
:
96 lower_param_to_local(intrin
->variables
[0]->var
, impl
, true);
99 case nir_intrinsic_copy_var
:
100 lower_param_to_local(intrin
->variables
[0]->var
, impl
, true);
101 lower_param_to_local(intrin
->variables
[1]->var
, impl
, false);
104 case nir_intrinsic_load_var
:
105 /* All other intrinsics which access variables (image_load_store)
106 * do so in a read-only fasion.
109 i
< nir_intrinsic_infos
[intrin
->intrinsic
].num_variables
; i
++) {
110 lower_param_to_local(intrin
->variables
[i
]->var
, impl
, false);
123 inline_functions_block(nir_block
*block
, nir_builder
*b
,
126 bool progress
= false;
127 /* This is tricky. We're iterating over instructions in a block but, as
128 * we go, the block and its instruction list are being split into
129 * pieces. However, this *should* be safe since foreach_safe always
130 * stashes the next thing in the iteration. That next thing will
131 * properly get moved to the next block when it gets split, and we
132 * continue iterating there.
134 nir_foreach_instr_safe(instr
, block
) {
135 if (instr
->type
!= nir_instr_type_call
)
140 nir_call_instr
*call
= nir_instr_as_call(instr
);
141 assert(call
->callee
->impl
);
143 inline_function_impl(call
->callee
->impl
, inlined
);
145 nir_function_impl
*callee_copy
=
146 nir_function_impl_clone(call
->callee
->impl
);
147 callee_copy
->function
= call
->callee
;
149 /* Add copies of all in parameters */
150 assert(call
->num_params
== callee_copy
->num_params
);
152 exec_list_append(&b
->impl
->locals
, &callee_copy
->locals
);
153 exec_list_append(&b
->impl
->registers
, &callee_copy
->registers
);
155 b
->cursor
= nir_before_instr(&call
->instr
);
157 /* We now need to tie the two functions together using the
158 * parameters. There are two ways we do this: One is to turn the
159 * parameter into a local variable and do a shadow-copy. The other
160 * is to treat the parameter as a "proxy" and rewrite derefs to use
161 * the actual variable that comes from the call instruction. We
162 * implement both schemes. The first is needed in the case where we
163 * have an in parameter that we write or similar. The second case is
164 * needed for handling things such as images and uniforms properly.
167 /* Figure out when we need to lower to a shadow local */
168 nir_foreach_block(block
, callee_copy
) {
169 lower_params_to_locals_block(block
, callee_copy
);
172 for (unsigned i
= 0; i
< callee_copy
->num_params
; i
++) {
173 nir_variable
*param
= callee_copy
->params
[i
];
175 if (param
->data
.mode
== nir_var_local
&&
176 call
->callee
->params
[i
].param_type
!= nir_parameter_out
) {
177 nir_copy_deref_var(b
, nir_deref_var_create(b
->shader
, param
),
182 nir_foreach_block(block
, callee_copy
) {
183 nir_foreach_instr(instr
, block
)
184 rewrite_param_derefs(instr
, call
);
187 /* Pluck the body out of the function and place it here */
189 nir_cf_list_extract(&body
, &callee_copy
->body
);
190 nir_cf_reinsert(&body
, b
->cursor
);
192 b
->cursor
= nir_before_instr(&call
->instr
);
194 /* Add copies of all out parameters and the return */
195 assert(call
->num_params
== callee_copy
->num_params
);
196 for (unsigned i
= 0; i
< callee_copy
->num_params
; i
++) {
197 nir_variable
*param
= callee_copy
->params
[i
];
199 if (param
->data
.mode
== nir_var_local
&&
200 call
->callee
->params
[i
].param_type
!= nir_parameter_in
) {
201 nir_copy_deref_var(b
, call
->params
[i
],
202 nir_deref_var_create(b
->shader
, param
));
205 if (!glsl_type_is_void(call
->callee
->return_type
) &&
206 callee_copy
->return_var
->data
.mode
== nir_var_local
) {
207 nir_copy_deref_var(b
, call
->return_deref
,
208 nir_deref_var_create(b
->shader
,
209 callee_copy
->return_var
));
212 nir_instr_remove(&call
->instr
);
219 inline_function_impl(nir_function_impl
*impl
, struct set
*inlined
)
221 if (_mesa_set_search(inlined
, impl
))
222 return false; /* Already inlined */
225 nir_builder_init(&b
, impl
);
227 bool progress
= false;
228 nir_foreach_block_safe(block
, impl
) {
229 progress
|= inline_functions_block(block
, &b
, inlined
);
233 /* SSA and register indices are completely messed up now */
234 nir_index_ssa_defs(impl
);
235 nir_index_local_regs(impl
);
237 nir_metadata_preserve(impl
, nir_metadata_none
);
240 _mesa_set_add(inlined
, impl
);
246 nir_inline_functions(nir_shader
*shader
)
248 struct set
*inlined
= _mesa_set_create(NULL
, _mesa_hash_pointer
,
249 _mesa_key_pointer_equal
);
250 bool progress
= false;
252 nir_foreach_function(function
, shader
) {
254 progress
= inline_function_impl(function
->impl
, inlined
) || progress
;
257 _mesa_set_destroy(inlined
, NULL
);