summaryrefslogtreecommitdiffstats
path: root/src/compiler/nir/nir_inline_functions.c
diff options
context:
space:
mode:
authorJason Ekstrand <[email protected]>2016-07-15 15:44:32 -0700
committerJason Ekstrand <[email protected]>2016-07-20 15:29:55 -0700
commit9d503aea069e08cffd57a4d590a6a0ca3b8ae4a2 (patch)
treec7e1f13f17188ba526c8fad218da3354bebb86c3 /src/compiler/nir/nir_inline_functions.c
parentdc9f2436c39d6539b56c9aedceefdc79566e5db8 (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/compiler/nir/nir_inline_functions.c')
-rw-r--r--src/compiler/nir/nir_inline_functions.c42
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