[Mesa-dev] [PATCH 2/9] nir: Conditionalize the POW reconstruction on shader compiler options.

Eric Anholt eric at anholt.net
Sun Feb 1 13:17:21 PST 2015


Mesa has a shader compiler struct flagging whether GLSL IR's opt_algebraic
and other passes should try and generate certain types of opcodes or
patterns.  Extend that to NIR by defining our own struct, which is
automatically generated from the Mesa struct in glsl_to_nir and provided
directly by the driver in TGSI-to-NIR.
---
 src/gallium/auxiliary/nir/tgsi_to_nir.c |  5 ++--
 src/gallium/auxiliary/nir/tgsi_to_nir.h |  3 ++-
 src/gallium/drivers/vc4/vc4_program.c   |  6 ++++-
 src/glsl/nir/glsl_to_nir.cpp            | 25 ++++++++++++++++++-
 src/glsl/nir/nir.c                      |  4 ++-
 src/glsl/nir/nir.h                      | 16 ++++++++++--
 src/glsl/nir/nir_algebraic.py           | 44 +++++++++++++++++++++++++++------
 src/glsl/nir/nir_opt_algebraic.py       |  4 +--
 src/mesa/main/mtypes.h                  |  2 ++
 9 files changed, 92 insertions(+), 17 deletions(-)

diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.c b/src/gallium/auxiliary/nir/tgsi_to_nir.c
index 1c96b05..c5660e5 100644
--- a/src/gallium/auxiliary/nir/tgsi_to_nir.c
+++ b/src/gallium/auxiliary/nir/tgsi_to_nir.c
@@ -1230,7 +1230,8 @@ ttn_add_output_stores(struct ttn_compile *c)
 }
 
 struct nir_shader *
-tgsi_to_nir(struct pipe_context *pctx, const void *tgsi_tokens)
+tgsi_to_nir(struct pipe_context *pctx, const void *tgsi_tokens,
+            const nir_shader_compiler_options *options)
 {
    struct tgsi_parse_context parser;
    struct tgsi_shader_info scan;
@@ -1241,7 +1242,7 @@ tgsi_to_nir(struct pipe_context *pctx, const void *tgsi_tokens)
    c = rzalloc(NULL, struct ttn_compile);
    if (!c)
       return NULL;
-   s = nir_shader_create(NULL);
+   s = nir_shader_create(NULL, options);
    if (!s)
       goto fail;
    c->s = s;
diff --git a/src/gallium/auxiliary/nir/tgsi_to_nir.h b/src/gallium/auxiliary/nir/tgsi_to_nir.h
index b9a4ed1..4d5eefa 100644
--- a/src/gallium/auxiliary/nir/tgsi_to_nir.h
+++ b/src/gallium/auxiliary/nir/tgsi_to_nir.h
@@ -24,4 +24,5 @@
 struct pipe_context;
 
 struct nir_shader *
-tgsi_to_nir(struct pipe_context *pctx, const void *tgsi_tokens);
+tgsi_to_nir(struct pipe_context *pctx, const void *tgsi_tokens,
+            const nir_shader_compiler_options *options);
diff --git a/src/gallium/drivers/vc4/vc4_program.c b/src/gallium/drivers/vc4/vc4_program.c
index f6ce03b..806ac6f 100644
--- a/src/gallium/drivers/vc4/vc4_program.c
+++ b/src/gallium/drivers/vc4/vc4_program.c
@@ -2097,6 +2097,10 @@ nir_to_qir(struct vc4_compile *c)
         }
 }
 
+static const nir_shader_compiler_options nir_options = {
+        .lower_fpow = true,
+};
+
 static struct vc4_compile *
 vc4_shader_ntq(struct vc4_context *vc4, enum qstage stage,
                        struct vc4_key *key)
@@ -2157,7 +2161,7 @@ vc4_shader_ntq(struct vc4_context *vc4, enum qstage stage,
                 tgsi_dump(tokens, 0);
         }
 
-        c->s = tgsi_to_nir(&vc4->base, tokens);
+        c->s = tgsi_to_nir(&vc4->base, tokens, &nir_options);
         nir_opt_global_to_local(c->s);
         nir_convert_to_ssa(c->s);
 
diff --git a/src/glsl/nir/glsl_to_nir.cpp b/src/glsl/nir/glsl_to_nir.cpp
index 46cfac3..9cfeedf 100644
--- a/src/glsl/nir/glsl_to_nir.cpp
+++ b/src/glsl/nir/glsl_to_nir.cpp
@@ -124,11 +124,34 @@ private:
 
 }; /* end of anonymous namespace */
 
+static const nir_shader_compiler_options default_options = {0};
+
 nir_shader *
 glsl_to_nir(exec_list *ir, _mesa_glsl_parse_state *state,
             bool native_integers)
 {
-   nir_shader *shader = nir_shader_create(NULL);
+   const nir_shader_compiler_options *options;
+
+   if (state) {
+      struct gl_context *ctx = state->ctx;
+      struct gl_shader_compiler_options *gl_options =
+         &ctx->Const.ShaderCompilerOptions[state->stage];
+
+      if (!gl_options->NirOptions) {
+         nir_shader_compiler_options *new_options =
+            rzalloc(ctx, nir_shader_compiler_options);
+         options = gl_options->NirOptions = new_options;
+
+         if (gl_options->EmitNoPow)
+            new_options->lower_fpow = true;
+      } else {
+         options = gl_options->NirOptions;
+      }
+   } else {
+      options = &default_options;
+   }
+
+   nir_shader *shader = nir_shader_create(NULL, options);
 
    if (state) {
       shader->num_user_structures = state->num_user_structures;
diff --git a/src/glsl/nir/nir.c b/src/glsl/nir/nir.c
index 10e6ed3..2c5c8db 100644
--- a/src/glsl/nir/nir.c
+++ b/src/glsl/nir/nir.c
@@ -29,7 +29,7 @@
 #include <assert.h>
 
 nir_shader *
-nir_shader_create(void *mem_ctx)
+nir_shader_create(void *mem_ctx, const nir_shader_compiler_options *options)
 {
    nir_shader *shader = ralloc(mem_ctx, nir_shader);
 
@@ -40,6 +40,8 @@ nir_shader_create(void *mem_ctx)
    shader->outputs = _mesa_hash_table_create(shader, _mesa_key_hash_string,
                                              _mesa_key_string_equal);
 
+   shader->options = options;
+
    shader->num_user_structures = 0;
    shader->user_structures = NULL;
 
diff --git a/src/glsl/nir/nir.h b/src/glsl/nir/nir.h
index 98d2689..a2163ed 100644
--- a/src/glsl/nir/nir.h
+++ b/src/glsl/nir/nir.h
@@ -1326,6 +1326,10 @@ typedef struct nir_function {
    exec_node_data(nir_function_overload, \
                   exec_list_get_head(&(func)->overload_list), node)
 
+typedef struct nir_shader_compiler_options {
+   bool lower_fpow;
+} nir_shader_compiler_options;
+
 typedef struct nir_shader {
    /** hash table of name -> uniform nir_variable */
    struct hash_table *uniforms;
@@ -1336,6 +1340,13 @@ typedef struct nir_shader {
    /** hash table of name -> output nir_variable */
    struct hash_table *outputs;
 
+   /** Set of driver-specific options for the shader.
+    *
+    * The memory for the options is expected to be kept in a single static
+    * copy by the driver.
+    */
+   const struct nir_shader_compiler_options *options;
+
    /** list of global variables in the shader */
    struct exec_list globals;
 
@@ -1361,12 +1372,13 @@ typedef struct nir_shader {
    unsigned num_inputs, num_uniforms, num_outputs;
 } nir_shader;
 
-#define nir_foreach_overload(shader, overload) \
+#define nir_foreach_overload(shader, overload)                        \
    foreach_list_typed(nir_function, func, node, &(shader)->functions) \
       foreach_list_typed(nir_function_overload, overload, node, \
                          &(func)->overload_list)
 
-nir_shader *nir_shader_create(void *mem_ctx);
+nir_shader *nir_shader_create(void *mem_ctx,
+                              const nir_shader_compiler_options *options);
 
 /** creates a register, including assigning it an index and adding it to the list */
 nir_register *nir_global_reg_create(nir_shader *shader);
diff --git a/src/glsl/nir/nir_algebraic.py b/src/glsl/nir/nir_algebraic.py
index 4929745..ac6438e 100644
--- a/src/glsl/nir/nir_algebraic.py
+++ b/src/glsl/nir/nir_algebraic.py
@@ -147,10 +147,27 @@ class Expression(Value):
 
 _optimization_ids = itertools.count()
 
+condition_index_map = {'true' : 0}
+condition_list = ['true']
+
 class SearchAndReplace(object):
-   def __init__(self, search, replace):
+   def __init__(self, transform):
       self.id = _optimization_ids.next()
 
+      search = transform[0]
+      replace = transform[1]
+      if len(transform) > 2:
+         self.condition = transform[2]
+      else:
+         self.condition = 'true'
+
+      if self.condition in condition_index_map:
+         self.condition_index = condition_index_map[self.condition]
+      else:
+         self.condition_index = len(condition_list)
+         condition_list.append(self.condition)
+         condition_index_map[self.condition] = self.condition_index
+
       varset = VarSet()
       if isinstance(search, Expression):
          self.search = search
@@ -171,6 +188,7 @@ _algebraic_pass_template = mako.template.Template("""
 struct transform {
    const nir_search_expression *search;
    const nir_search_value *replace;
+   unsigned condition_offset;
 };
 
 % for (opcode, xform_list) in xform_dict.iteritems():
@@ -181,7 +199,7 @@ struct transform {
 
 static const struct transform ${pass_name}_${opcode}_xforms[] = {
 % for xform in xform_list:
-   { &${xform.search.name}, ${xform.replace.c_ptr} },
+   { &${xform.search.name}, ${xform.replace.c_ptr}, ${xform.condition_index} },
 % endfor
 };
 % endfor
@@ -189,6 +207,7 @@ static const struct transform ${pass_name}_${opcode}_xforms[] = {
 struct opt_state {
    void *mem_ctx;
    bool progress;
+   const bool *condition_flags;
 };
 
 static bool
@@ -209,7 +228,8 @@ ${pass_name}_block(nir_block *block, void *void_state)
       case nir_op_${opcode}:
          for (unsigned i = 0; i < ARRAY_SIZE(${pass_name}_${opcode}_xforms); i++) {
             const struct transform *xform = &${pass_name}_${opcode}_xforms[i];
-            if (nir_replace_instr(alu, xform->search, xform->replace,
+            if (state->condition_flags[xform->condition_offset] &&
+                nir_replace_instr(alu, xform->search, xform->replace,
                                   state->mem_ctx)) {
                state->progress = true;
                break;
@@ -226,12 +246,13 @@ ${pass_name}_block(nir_block *block, void *void_state)
 }
 
 static bool
-${pass_name}_impl(nir_function_impl *impl)
+${pass_name}_impl(nir_function_impl *impl, const bool *condition_flags)
 {
    struct opt_state state;
 
    state.mem_ctx = ralloc_parent(impl);
    state.progress = false;
+   state.condition_flags = condition_flags;
 
    nir_foreach_block(impl, ${pass_name}_block, &state);
 
@@ -242,14 +263,21 @@ ${pass_name}_impl(nir_function_impl *impl)
    return state.progress;
 }
 
+
 bool
 ${pass_name}(nir_shader *shader)
 {
    bool progress = false;
+   bool condition_flags[${len(condition_list)}];
+   const nir_shader_compiler_options *options = shader->options;
+
+   % for condition in condition_list:
+   condition_flags[${condition_index_map[condition]}] = ${condition};
+   % endfor
 
    nir_foreach_overload(shader, overload) {
       if (overload->impl)
-         progress |= ${pass_name}_impl(overload->impl);
+         progress |= ${pass_name}_impl(overload->impl, condition_flags);
    }
 
    return progress;
@@ -263,7 +291,7 @@ class AlgebraicPass(object):
 
       for xform in transforms:
          if not isinstance(xform, SearchAndReplace):
-            xform = SearchAndReplace(*xform)
+            xform = SearchAndReplace(xform)
 
          if xform.search.opcode not in self.xform_dict:
             self.xform_dict[xform.search.opcode] = []
@@ -272,4 +300,6 @@ class AlgebraicPass(object):
 
    def render(self):
       return _algebraic_pass_template.render(pass_name=self.pass_name,
-                                             xform_dict=self.xform_dict)
+                                             xform_dict=self.xform_dict,
+                                             condition_list=condition_list,
+                                             condition_index_map=condition_index_map)
diff --git a/src/glsl/nir/nir_opt_algebraic.py b/src/glsl/nir/nir_opt_algebraic.py
index c635ab3..2414f71 100644
--- a/src/glsl/nir/nir_opt_algebraic.py
+++ b/src/glsl/nir/nir_opt_algebraic.py
@@ -107,8 +107,8 @@ optimizations = [
    (('fexp',  ('flog',  a)), a), # e^ln(a)  = a
    (('flog2', ('fexp2', a)), a), # lg2(2^a) = a
    (('flog',  ('fexp',  a)), a), # ln(e^a)  = a
-   (('fexp2', ('fmul', ('flog2', a), b)), ('fpow', a, b)), # 2^(lg2(a)*b) = a^b
-   (('fexp',  ('fmul', ('flog', a), b)),  ('fpow', a, b)), # e^(ln(a)*b) = a^b
+   (('fexp2', ('fmul', ('flog2', a), b)), ('fpow', a, b), '!options->lower_fpow'), # 2^(lg2(a)*b) = a^b
+   (('fexp',  ('fmul', ('flog', a), b)),  ('fpow', a, b), '!options->lower_fpow'), # e^(ln(a)*b) = a^b
    (('fpow', a, 1.0), a),
    (('fpow', a, 2.0), ('fmul', a, a)),
    (('fpow', 2.0, a), ('fexp2', a)),
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index 81a7c0e..d440e58 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -3033,6 +3033,8 @@ struct gl_shader_compiler_options
    GLboolean OptimizeForAOS;
 
    struct gl_sl_pragmas DefaultPragmas; /**< Default #pragma settings */
+
+   struct nir_shader_compiler_options *NirOptions;
 };
 
 
-- 
2.1.4



More information about the mesa-dev mailing list