nir/algebraic: Allow for flagging operations as being inexact
authorJason Ekstrand <jason.ekstrand@intel.com>
Thu, 17 Mar 2016 18:04:49 +0000 (11:04 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Wed, 23 Mar 2016 23:27:55 +0000 (16:27 -0700)
Reviewed-by: Francisco Jerez <currojerez@riseup.net>
src/compiler/nir/nir_algebraic.py
src/compiler/nir/nir_opt_algebraic.py
src/compiler/nir/nir_search.c
src/compiler/nir/nir_search.h

index 1818877a21633c21be490b61420f3c54b222570a..d05564f779c8c6a3991dceea269c707c52c7ed6f 100644 (file)
@@ -69,6 +69,7 @@ static const ${val.c_type} ${val.name} = {
    ${'true' if val.is_constant else 'false'},
    ${val.type() or 'nir_type_invalid' },
 % elif isinstance(val, Expression):
+   ${'true' if val.inexact else 'false'},
    nir_op_${val.opcode},
    { ${', '.join(src.c_ptr for src in val.sources)} },
 % endif
@@ -145,12 +146,18 @@ class Variable(Value):
       elif self.required_type == 'float':
          return "nir_type_float"
 
+_opcode_re = re.compile(r"(?P<inexact>~)?(?P<opcode>\w+)")
+
 class Expression(Value):
    def __init__(self, expr, name_base, varset):
       Value.__init__(self, name_base, "expression")
       assert isinstance(expr, tuple)
 
-      self.opcode = expr[0]
+      m = _opcode_re.match(expr[0])
+      assert m and m.group('opcode') is not None
+
+      self.opcode = m.group('opcode')
+      self.inexact = m.group('inexact') is not None
       self.sources = [ Value.create(src, "{0}_{1}".format(name_base, i), varset)
                        for (i, src) in enumerate(expr[1:]) ]
 
index 0f2bd18dd69f4d3a906d98d6d4ccb1b00c5b24bb..d788b7b1a0ceebbe46a85028e79250127bef9c0b 100644 (file)
@@ -34,10 +34,17 @@ d = 'd'
 
 # Written in the form (<search>, <replace>) where <search> is an expression
 # and <replace> is either an expression or a value.  An expression is
-# defined as a tuple of the form (<op>, <src0>, <src1>, <src2>, <src3>)
+# defined as a tuple of the form ([~]<op>, <src0>, <src1>, <src2>, <src3>)
 # where each source is either an expression or a value.  A value can be
 # either a numeric constant or a string representing a variable name.
 #
+# If the opcode in a search expression is prefixed by a '~' character, this
+# indicates that the operation is inexact.  Such operations will only get
+# applied to SSA values that do not have the exact bit set.  This should be
+# used by by any optimizations that are not bit-for-bit exact.  It should not,
+# however, be used for backend-requested lowering operations as those need to
+# happen regardless of precision.
+#
 # Variable names are specified as "[#]name[@type]" where "#" inicates that
 # the given variable will only match constants and the type indicates that
 # the given variable will only match values from ALU instructions with the
index 6f6a9425c18ab579c3303e62bb80dd3d0ab362c0..110ab5e2362cefc0156a3dce3d92c37786a97767 100644 (file)
@@ -238,6 +238,10 @@ match_expression(const nir_search_expression *expr, nir_alu_instr *instr,
    if (instr->op != expr->opcode)
       return false;
 
+   assert(instr->dest.dest.is_ssa);
+   if (expr->inexact && instr->exact)
+      return false;
+
    assert(!instr->dest.saturate);
    assert(nir_op_infos[instr->op].num_inputs > 0);
 
index 321d6d00355d30d366769734e46050493b0a8877..61742f129b139043c1760c649dabdd584466c616 100644 (file)
@@ -83,6 +83,12 @@ typedef struct {
 typedef struct {
    nir_search_value value;
 
+   /* When set on a search expression, the expression will only match an SSA
+    * value that does *not* have the exact bit set.  If unset, the exact bit
+    * on the SSA value is ignored.
+    */
+   bool inexact;
+
    nir_op opcode;
    const nir_search_value *srcs[4];
 } nir_search_expression;