nir/regs_to_ssa: Handle regs in phi sources properly
authorJason Ekstrand <jason@jlekstrand.net>
Fri, 12 Jul 2019 16:01:40 +0000 (11:01 -0500)
committerJason Ekstrand <jason@jlekstrand.net>
Tue, 16 Jul 2019 23:28:03 +0000 (23:28 +0000)
Sources of phi instructions act as if they occur at the very end of the
predecessor block not the block in which the phi lives.  In order to
handle them correctly, we have to skip phi sources on the normal
instruction walk and handle them as a separate walk over the successor
phis.  While registers in phi instructions is a bit of an oddity it can
happen when we temporarily go out-of-SSA for control-flow manipulations.

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=111075
Cc: mesa-stable@lists.freedesktop.org
Reviewed-by: Caio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
src/compiler/nir/nir_lower_regs_to_ssa.c

index 0db11ff1d1cd26ad8f50dced3b8a68c81cacca0f..76ed1287379d1256e46b46d8bacc4ce19f4f723b 100644 (file)
@@ -251,9 +251,17 @@ nir_lower_regs_to_ssa_impl(nir_function_impl *impl)
 
    nir_foreach_block(block, impl) {
       nir_foreach_instr(instr, block) {
-         if (instr->type == nir_instr_type_alu) {
+         switch (instr->type) {
+         case nir_instr_type_alu:
             rewrite_alu_instr(nir_instr_as_alu(instr), &state);
-         } else {
+            break;
+
+         case nir_instr_type_phi:
+            /* We rewrite sources as a separate pass */
+            nir_foreach_dest(instr, rewrite_dest, &state);
+            break;
+
+         default:
             nir_foreach_src(instr, rewrite_src, &state);
             nir_foreach_dest(instr, rewrite_dest, &state);
          }
@@ -262,6 +270,28 @@ nir_lower_regs_to_ssa_impl(nir_function_impl *impl)
       nir_if *following_if = nir_block_get_following_if(block);
       if (following_if)
          rewrite_if_condition(following_if, &state);
+
+      /* Handle phi sources that source from this block.  We have to do this
+       * as a separate pass because the phi builder assumes that uses and
+       * defs are processed in an order that respects dominance.  When we have
+       * loops, a phi source may be a back-edge so we have to handle it as if
+       * it were one of the last instructions in the predecessor block.
+       */
+      for (unsigned i = 0; i < ARRAY_SIZE(block->successors); i++) {
+         if (block->successors[i] == NULL)
+            continue;
+
+         nir_foreach_instr(instr, block->successors[i]) {
+            if (instr->type != nir_instr_type_phi)
+               break;
+
+            nir_phi_instr *phi = nir_instr_as_phi(instr);
+            nir_foreach_phi_src(phi_src, phi) {
+               if (phi_src->pred == block)
+                  rewrite_src(&phi_src->src, &state);
+            }
+         }
+      }
    }
 
    nir_phi_builder_finish(phi_build);