nir/inline: Constant-initialize local variables in the callee if needed
authorJason Ekstrand <jason.ekstrand@intel.com>
Fri, 15 Jul 2016 22:44:32 +0000 (15:44 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 20 Jul 2016 22:29:55 +0000 (15:29 -0700)
Signed-off-by: Jason Ekstrand <jason@jlekstrand.net>
Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
Cc: "12.0" <mesa-stable@lists.freedesktop.org>
src/compiler/nir/nir_inline_functions.c

index c36748d6cf5863e815af775cd023d5e216bb1670..cf31e144608d707e15e95bdfe7908596e068f38f 100644 (file)
 #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