<p dir="ltr"><br>
On May 26, 2016 7:14 PM, "Ian Romanick" <<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>> wrote:<br>
><br>
> On 05/26/2016 06:30 PM, Jason Ekstrand wrote:<br>
> > The deduplication helps a lot for variables and constants where we have a<br>
> > *lot* of duplicates.  The compact expressions are also a *lot* smaller.<br>
> > This cuts about 56K from nir_search_algebraic.o (mostly from .data):<br>
> ><br>
> >    text     data      bss      dec      hex  filename<br>
> >   17951    64584        0    82535    14267  nir_opt_algebraic.o<br>
> >   10780    15536        0    26316     66cc  nir_opt_algebraic.o<br>
> > ---<br>
> >  src/compiler/nir/nir_algebraic.py | 135 +++++++++++++++++++++++++-------------<br>
> >  src/compiler/nir/nir_search.h     |   2 +-<br>
> >  2 files changed, 92 insertions(+), 45 deletions(-)<br>
> ><br>
> > diff --git a/src/compiler/nir/nir_algebraic.py b/src/compiler/nir/nir_algebraic.py<br>
> > index 0d1ed3a..cccc34d 100644<br>
> > --- a/src/compiler/nir/nir_algebraic.py<br>
> > +++ b/src/compiler/nir/nir_algebraic.py<br>
> > @@ -63,6 +63,28 @@ class VarSet(object):<br>
> >     def lock(self):<br>
> >        self.immutable = True<br>
> ><br>
> > +class ValueCache(object):<br>
> > +   def __init__(self):<br>
> > +      self.cache = {}<br>
> > +      self.list = []<br>
> > +<br>
> > +   def __iter__(self):<br>
> > +      return self.list.__iter__()<br>
> > +<br>
> > +   def add_value(self, val):<br>
> > +      if val in self.cache:<br>
> > +         return;<br>
> > +<br>
> > +      if isinstance(val, Expression):<br>
> > +         for src in val.sources:<br>
> > +            self.add_value(src)<br>
> > +<br>
> > +      self.cache[val] = len(self.list)<br>
> > +      self.list.append(val)<br>
> > +<br>
> > +   def get_index(self, value):<br>
> > +      return self.cache[value]<br>
> > +<br>
> >  class Value(object):<br>
> >     @staticmethod<br>
> >     def create(val, name_base, varset):<br>
> > @@ -75,44 +97,14 @@ class Value(object):<br>
> >        elif isinstance(val, (bool, int, long, float)):<br>
> >           return Constant(val, name_base)<br>
> ><br>
> > -   __template = mako.template.Template("""<br>
> > -static const ${val.c_type} ${<a href="http://val.name">val.name</a>} = {<br>
> > -   { ${val.type_enum}, ${val.bit_size} },<br>
> > -% if isinstance(val, Constant):<br>
> > -   ${val.type()}, { ${hex(val)} /* ${val.value} */ },<br>
> > -% elif isinstance(val, Variable):<br>
> > -   ${val.index}, /* ${val.var_name} */<br>
> > -   ${'true' if val.is_constant else 'false'},<br>
> > -   ${val.type() or 'nir_type_invalid' },<br>
> > -% elif isinstance(val, Expression):<br>
> > -   ${'true' if val.inexact else 'false'},<br>
> > -   nir_op_${val.opcode},<br>
> > -   { ${', '.join(src.c_ptr for src in val.sources)} },<br>
> > -% endif<br>
> > -};""")<br>
> > -<br>
> >     def __init__(self, name, type_str):<br>
> >        <a href="http://self.name">self.name</a> = name<br>
> >        self.type_str = type_str<br>
> ><br>
> >     @property<br>
> > -   def type_enum(self):<br>
> > -      return "nir_search_value_" + self.type_str<br>
> > -<br>
> > -   @property<br>
> >     def c_type(self):<br>
> >        return "nir_search_" + self.type_str<br>
> ><br>
> > -   @property<br>
> > -   def c_ptr(self):<br>
> > -      return "&{0}.value".format(<a href="http://self.name">self.name</a>)<br>
> > -<br>
> > -   def render(self):<br>
> > -      return self.__template.render(val=self,<br>
> > -                                    Constant=Constant,<br>
> > -                                    Variable=Variable,<br>
> > -                                    Expression=Expression)<br>
> > -<br>
> >  _constant_re = re.compile(r"(?P<value>[^@]+)(?:@(?P<bits>\d+))?")<br>
> ><br>
> >  class Constant(Value):<br>
> > @@ -151,6 +143,10 @@ class Constant(Value):<br>
> >        else:<br>
> >           assert False<br>
> ><br>
> > +   @property<br>
> > +   def comment_str(self):<br>
> > +      return "{0}({1})".format(type(self.value).__name__, self.value)<br>
> > +<br>
> >     def type(self):<br>
> >        if isinstance(self.value, (bool)):<br>
> >           return "nir_type_bool32"<br>
> > @@ -159,6 +155,16 @@ class Constant(Value):<br>
> >        elif isinstance(self.value, float):<br>
> >           return "nir_type_float"<br>
> ><br>
> > +   __union_template = mako.template.Template("""<br>
> > +   { .constant = {<br>
> > +      { nir_search_value_constant, ${val.bit_size} },<br>
> > +      ${val.type()},<br>
> > +      { .u = ${hex(val)} /* ${val.value} */ },<br>
> > +   } },""")<br>
> > +<br>
> > +   def render_union(self, cache):<br>
> > +      return self.__union_template.render(val=self)<br>
> > +<br>
> >  _var_name_re = re.compile(r"(?P<const>#)?(?P<name>\w+)"<br>
> >                            r"(?:@(?P<type>int|uint|bool|float)?(?P<bits>\d+)?)?")<br>
> ><br>
> > @@ -199,6 +205,10 @@ class Variable(Value):<br>
> >           and self.required_type == other.required_type \<br>
> >           and self.bit_size == other.bit_size<br>
> ><br>
> > +   @property<br>
> > +   def comment_str(self):<br>
> > +      return "variable"<br>
> > +<br>
> >     def type(self):<br>
> >        if self.required_type == 'bool':<br>
> >           return "nir_type_bool32"<br>
> > @@ -207,6 +217,17 @@ class Variable(Value):<br>
> >        elif self.required_type == 'float':<br>
> >           return "nir_type_float"<br>
> ><br>
> > +   __union_template = mako.template.Template("""<br>
> > +   { .variable = {<br>
> > +      { nir_search_value_variable, ${val.bit_size} },<br>
> > +      ${val.index}, /* ${val.var_name} */<br>
> > +      ${'true' if val.is_constant else 'false'},<br>
> > +      ${val.type() or 'nir_type_invalid' },<br>
> > +   } },""")<br>
> > +<br>
> > +   def render_union(self, cache):<br>
> > +      return self.__union_template.render(val=self)<br>
> > +<br>
> >  _opcode_re = re.compile(r"(?P<inexact>~)?(?P<opcode>\w+)(?:@(?P<bits>\d+))?")<br>
> ><br>
> >  class Expression(Value):<br>
> > @@ -217,6 +238,7 @@ class Expression(Value):<br>
> >        m = _opcode_re.match(expr[0])<br>
> >        assert m and m.group('opcode') is not None<br>
> ><br>
> > +      self.expr = expr<br>
> >        self.opcode = m.group('opcode')<br>
> >        self.bit_size = int(m.group('bits')) if m.group('bits') else 0<br>
> >        self.inexact = m.group('inexact') is not None<br>
> > @@ -247,9 +269,20 @@ class Expression(Value):<br>
> >        return self.inexact == other.inexact \<br>
> >           and self.bit_size == other.bit_size<br>
> ><br>
> > -   def render(self):<br>
> > -      srcs = "\n".join(src.render() for src in self.sources)<br>
> > -      return srcs + super(Expression, self).render()<br>
> > +   @property<br>
> > +   def comment_str(self):<br>
> > +      return str(self.expr)<br>
> > +<br>
> > +   __union_template = mako.template.Template("""<br>
> > +   { .expression = {<br>
> > +      { nir_search_value_compact_expression, ${val.bit_size} },<br>
> > +      ${'true' if val.inexact else 'false'},<br>
> > +      nir_op_${val.opcode},<br>
> > +      { ${', '.join(str(cache.get_index(src)) for src in val.sources)} },<br>
> > +   } },""")<br>
> > +<br>
> > +   def render_union(self, cache):<br>
> > +      return self.__union_template.render(val=self, cache=cache)<br>
> ><br>
> >  class IntEquivalenceRelation(object):<br>
> >     """A class representing an equivalence relation on integers.<br>
> > @@ -548,22 +581,29 @@ _algebraic_pass_template = mako.template.Template("""<br>
> >  #define NIR_OPT_ALGEBRAIC_STRUCT_DEFS<br>
> ><br>
> >  struct transform {<br>
> > -   const nir_search_value *search;<br>
> > -   const nir_search_value *replace;<br>
> > -   unsigned condition_offset;<br>
> > +   uint16_t search;<br>
> > +   uint16_t replace;<br>
> > +   uint16_t condition_offset;<br>
> >  };<br>
> ><br>
> >  #endif<br>
> ><br>
> > -% for (opcode, xform_list) in xform_dict.iteritems():<br>
> > -% for xform in xform_list:<br>
> > -   ${xform.search.render()}<br>
> > -   ${xform.replace.render()}<br>
> > +nir_search_value_union ${pass_name}_values[] = {<br>
> > +% for index, value in enumerate(cache):<br>
> > +<br>
> > +   /* ${index}: ${value.comment_str} */<br>
> > +   ${value.render_union(cache)}<br>
> >  % endfor<br>
> > +};<br>
> ><br>
> > +% for (opcode, xform_list) in xform_dict.iteritems():<br>
> >  static const struct transform ${pass_name}_${opcode}_xforms[] = {<br>
> >  % for xform in xform_list:<br>
> > -   { ${xform.search.c_ptr}, ${xform.replace.c_ptr}, ${xform.condition_index} },<br>
> > +   {<br>
> > +      ${cache.get_index(xform.search)},<br>
> > +      ${cache.get_index(xform.replace)},<br>
> > +      ${xform.condition_index}<br>
> > +   },<br>
> >  % endfor<br>
> >  };<br>
> >  % endfor<br>
> > @@ -588,8 +628,10 @@ ${pass_name}_block(nir_block *block, const bool *condition_flags,<br>
> >           for (unsigned i = 0; i < ARRAY_SIZE(${pass_name}_${opcode}_xforms); i++) {<br>
> >              const struct transform *xform = &${pass_name}_${opcode}_xforms[i];<br>
> >              if (condition_flags[xform->condition_offset] &&<br>
> > -                nir_replace_instr(alu, xform->search, xform->replace,<br>
> > -                                  NULL, mem_ctx)) {<br>
> > +                nir_replace_instr(alu,<br>
> > +                                  &${pass_name}_values[xform->search].value,<br>
> > +                                  &${pass_name}_values[xform->replace].value,<br>
> > +                                  ${pass_name}_values, mem_ctx)) {<br>
> >                 progress = true;<br>
> >                 break;<br>
> >              }<br>
> > @@ -647,6 +689,7 @@ class AlgebraicPass(object):<br>
> >     def __init__(self, pass_name, transforms):<br>
> >        self.xform_dict = {}<br>
> >        self.pass_name = pass_name<br>
> > +      self.cache = ValueCache()<br>
> ><br>
> >        error = False<br>
> ><br>
> > @@ -662,6 +705,9 @@ class AlgebraicPass(object):<br>
> >                 error = True<br>
> >                 continue<br>
> ><br>
> > +         self.cache.add_value(xform.search)<br>
> > +         self.cache.add_value(xform.replace)<br>
> > +<br>
> >           if xform.search.opcode not in self.xform_dict:<br>
> >              self.xform_dict[xform.search.opcode] = []<br>
> ><br>
> > @@ -673,4 +719,5 @@ class AlgebraicPass(object):<br>
> >     def render(self):<br>
> >        return _algebraic_pass_template.render(pass_name=self.pass_name,<br>
> >                                               xform_dict=self.xform_dict,<br>
> > -                                             condition_list=condition_list)<br>
> > +                                             condition_list=condition_list,<br>
> > +                                             cache=self.cache)<br>
> > diff --git a/src/compiler/nir/nir_search.h b/src/compiler/nir/nir_search.h<br>
> > index 1588628..7ce73fb 100644<br>
> > --- a/src/compiler/nir/nir_search.h<br>
> > +++ b/src/compiler/nir/nir_search.h<br>
> > @@ -105,7 +105,7 @@ typedef struct {<br>
> >      */<br>
> >     bool inexact:1;<br>
> ><br>
> > -   nir_op opcode:15;<br>
> > +   unsigned opcode:15; /* enum nir_op */<br>
><br>
> Why this type change?</p>
<p dir="ltr">Oops. I meant to put this in patch 4.</p>
<p dir="ltr">> >     uint16_t srcs[4];<br>
> >  } nir_search_compact_expression;<br>
> ><br>
> ><br>
><br>
</p>