[Mesa-dev] [PATCH 01/17] nir: introduce new convergent and cross-thread attributes

Connor Abbott connora at valvesoftware.com
Fri Jun 9 23:44:00 UTC 2017


From: Connor Abbott <cwabbott0 at gmail.com>

These are properties of the instruction that must be respected when
moving it around, in addition to the usual SSA dominance guarantee.
Previously, we only had special handling for fddx and fddy, in a very
ad-hoc way. But with arb_shader_ballot and arb_shader_group_vote, we'll
have to start handling a lot more instructions with similar constraints,
so we want to add a more formal model of what the optimizer can and
cannot do.

v2: don't add attribute for ALU instructions
v3: special-case derivative ALU instructions
Signed-off-by: Connor Abbott <cwabbott0 at gmail.com>
---
 src/compiler/nir/nir.h | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h
index 3b827bf..64caccb 100644
--- a/src/compiler/nir/nir.h
+++ b/src/compiler/nir/nir.h
@@ -985,6 +985,25 @@ typedef enum {
     * intrinsic are due to the register reads/writes.
     */
    NIR_INTRINSIC_CAN_REORDER = (1 << 1),
+
+   /**
+    * Indicates whether this intrinsic is "cross-thread". An operation is
+    * cross-thread if results in one thread depend on inputs in another thread,
+    * and therefore optimizations cannot change the execution mask when the
+    * operation is called. Examples of cross-thread operations include
+    * screen-space derivatives, the "any" reduction which returns "true" in
+    * all threads if any thread inputs "true", etc.
+    */
+   NIR_INTRINSIC_CROSS_THREAD,
+
+   /**
+    * Indicates that this intrinsic is "convergent". An operation is
+    * convergent when it must always be called in convergent control flow,
+    * that is, control flow with the same execution mask as when the program
+    * started. If an operation is convergent, it must be cross-thread as well,
+    * since the optimizer must maintain the guarantee.
+    */
+   NIR_INTRINSIC_CONVERGENT,
 } nir_intrinsic_semantic_flag;
 
 /**
@@ -1459,6 +1478,67 @@ NIR_DEFINE_CAST(nir_instr_as_parallel_copy, nir_instr,
                 type, nir_instr_type_parallel_copy)
 
 /*
+ * Helpers to determine if an instruction is cross-thread or convergent. See
+ * NIR_INTRINSIC_{CONVERGENT|CROSS_THREAD} for the definitions.
+ */
+static inline bool
+nir_instr_is_convergent(const nir_instr *instr)
+{
+   switch (instr->type) {
+   case nir_instr_type_alu:
+      switch (nir_instr_as_alu(instr)->op) {
+      case nir_op_fddx:
+      case nir_op_fddy:
+      case nir_op_fddx_fine:
+      case nir_op_fddy_fine:
+      case nir_op_fddx_coarse:
+      case nir_op_fddy_coarse:
+         /* Partial derivatives are convergent */
+         return true;
+
+      default:
+         return false;
+      }
+
+   case nir_instr_type_intrinsic: {
+      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+      return nir_intrinsic_infos[intrin->intrinsic].flags &
+         NIR_INTRINSIC_CONVERGENT;
+   }
+
+   case nir_instr_type_tex:
+         switch (nir_instr_as_tex(instr)->op) {
+         case nir_texop_tex:
+         case nir_texop_txb:
+         case nir_texop_lod:
+            /* These three take implicit derivatives, so they are convergent */
+            return true;
+
+         default:
+            return false;
+         }
+
+   default:
+      return false;
+   }
+}
+
+static inline bool
+nir_instr_is_cross_thread(const nir_instr *instr)
+{
+   switch (instr->type) {
+   case nir_instr_type_intrinsic: {
+      nir_intrinsic_instr *intrin = nir_instr_as_intrinsic(instr);
+      return nir_intrinsic_infos[intrin->intrinsic].flags &
+         NIR_INTRINSIC_CROSS_THREAD;
+   }
+
+   default:
+      return nir_instr_is_convergent(instr);
+   }
+}
+
+/*
  * Control flow
  *
  * Control flow consists of a tree of control flow nodes, which include
-- 
2.9.4



More information about the mesa-dev mailing list