diff options
author | Jason Ekstrand <[email protected]> | 2016-07-15 15:44:32 -0700 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2016-07-20 15:29:55 -0700 |
commit | 9d503aea069e08cffd57a4d590a6a0ca3b8ae4a2 (patch) | |
tree | c7e1f13f17188ba526c8fad218da3354bebb86c3 /src | |
parent | dc9f2436c39d6539b56c9aedceefdc79566e5db8 (diff) |
nir/inline: Constant-initialize local variables in the callee if needed
Signed-off-by: Jason Ekstrand <[email protected]>
Reviewed-by: Kenneth Graunke <[email protected]>
Cc: "12.0" <[email protected]>
Diffstat (limited to 'src')
-rw-r--r-- | src/compiler/nir/nir_inline_functions.c | 42 |
1 files changed, 40 insertions, 2 deletions
diff --git a/src/compiler/nir/nir_inline_functions.c b/src/compiler/nir/nir_inline_functions.c index c36748d6cf5..cf31e144608 100644 --- a/src/compiler/nir/nir_inline_functions.c +++ b/src/compiler/nir/nir_inline_functions.c @@ -25,6 +25,20 @@ #include "nir_builder.h" #include "nir_control_flow.h" +static bool +deref_apply_constant_initializer(nir_deref_var *deref, void *state) +{ + struct nir_builder *b = state; + + nir_load_const_instr *initializer = + nir_deref_get_const_initializer_load(b->shader, deref); + nir_builder_instr_insert(b, &initializer->instr); + + nir_store_deref_var(b, deref, &initializer->def, 0xf); + + return true; +} + static bool inline_function_impl(nir_function_impl *impl, struct set *inlined); static void @@ -174,11 +188,35 @@ inline_functions_block(nir_block *block, nir_builder *b, /* Add copies of all in parameters */ assert(call->num_params == callee_copy->num_params); + b->cursor = nir_before_instr(&call->instr); + + /* Before we insert the copy of the function, we need to lower away + * constant initializers on local variables. This is because constant + * initializers happen (effectively) at the top of the function and, + * since these are about to become locals of the calling function, + * initialization will happen at the top of the caller rather than at + * the top of the callee. This isn't usually a problem, but if we are + * being inlined inside of a loop, it can result in the variable not + * getting re-initialized properly for all loop iterations. + */ + nir_foreach_variable(local, &callee_copy->locals) { + if (!local->constant_initializer) + continue; + + nir_deref_var deref; + deref.deref.deref_type = nir_deref_type_var, + deref.deref.child = NULL; + deref.deref.type = local->type, + deref.var = local; + + nir_deref_foreach_leaf(&deref, deref_apply_constant_initializer, b); + + local->constant_initializer = NULL; + } + exec_list_append(&b->impl->locals, &callee_copy->locals); exec_list_append(&b->impl->registers, &callee_copy->registers); - b->cursor = nir_before_instr(&call->instr); - /* We now need to tie the two functions together using the * parameters. There are two ways we do this: One is to turn the * parameter into a local variable and do a shadow-copy. The other |