<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>