nir: Allow derefs to be used as phi sources
authorCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Tue, 7 May 2019 09:03:59 +0000 (02:03 -0700)
committerCaio Marcelo de Oliveira Filho <caio.oliveira@intel.com>
Wed, 29 May 2019 15:19:15 +0000 (08:19 -0700)
It is possible and valid for a pointer to be selected based on a
conditional before used, and depending on the mode, those cases will
result in a phi with derefs as sources.

To achieve this, we don't rematerialize derefs that are used by phis.
As a consequence, when converting from SSA to regs, we may have phis
that come from different blocks and are used by phis.  We now convert
those to regs too.

Validation was added to ensure only derefs of certain modes can be
used as phi sources.  No extra validation is needed for the presence
of cast, any instruction that uses derefs will validate the
deref-chain is complete (ending in a cast or a var).

Reviewed-by: Jason Ekstrand <jason@jlekstrand.net>
src/compiler/nir/nir_deref.c
src/compiler/nir/nir_from_ssa.c
src/compiler/nir/nir_validate.c

index f1e6eee7745a7a5e69958732a7691250418bcd6c..90bb9a0dc3c7112f38d71a486b1d6b805aa4756b 100644 (file)
@@ -601,6 +601,8 @@ rematerialize_deref_src(nir_src *src, void *_state)
  * used.  After this pass has been run, every use of a deref will be of a
  * deref in the same block as the use.  Also, all unused derefs will be
  * deleted as a side-effect.
+ *
+ * Derefs used as sources of phi instructions are not rematerialized.
  */
 bool
 nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl)
@@ -620,6 +622,12 @@ nir_rematerialize_derefs_in_use_blocks_impl(nir_function_impl *impl)
              nir_deref_instr_remove_if_unused(nir_instr_as_deref(instr)))
             continue;
 
+         /* If a deref is used in a phi, we can't rematerialize it, as the new
+          * derefs would appear before the phi, which is not valid.
+          */
+         if (instr->type == nir_instr_type_phi)
+            continue;
+
          state.builder.cursor = nir_before_instr(instr);
          nir_foreach_src(instr, rematerialize_deref_src, &state);
       }
index b406e7401d6380a316aad94ccecb66249e5530f0..2ac67b2b9977d3622bab9e4bd8ea89edd0861e09 100644 (file)
@@ -902,8 +902,6 @@ nir_lower_phis_to_regs_block(nir_block *block)
 
       nir_foreach_phi_src(src, phi) {
          assert(src->src.is_ssa);
-         /* We don't want derefs ending up in phi sources */
-         assert(!nir_src_as_deref(src->src));
          place_phi_read(shader, reg, src->src.ssa, src->pred);
       }
 
index bf3f23f254735768a16f3c3bd52b66cd2a8720f6..682ed762f57d41ff694fe52beb26de1ffccb3029 100644 (file)
@@ -499,6 +499,15 @@ validate_deref_instr(nir_deref_instr *instr, validate_state *state)
     * NULL, an explicit comparison operation should be used.
     */
    validate_assert(state, list_empty(&instr->dest.ssa.if_uses));
+
+   /* Only certain modes can be used as sources for phi instructions. */
+   nir_foreach_use(use, &instr->dest.ssa) {
+      if (use->parent_instr->type == nir_instr_type_phi) {
+         validate_assert(state, instr->mode == nir_var_mem_ubo ||
+                                instr->mode == nir_var_mem_ssbo ||
+                                instr->mode == nir_var_mem_shared);
+      }
+   }
 }
 
 static void