<div dir="ltr"><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, May 14, 2016 at 12:20 PM, Rob Clark <span dir="ltr"><<a href="mailto:robdclark@gmail.com" target="_blank">robdclark@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On Thu, May 12, 2016 at 10:55 PM, Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>> wrote:<br>
><br>
><br>
> On Tue, May 10, 2016 at 11:57 AM, Rob Clark <<a href="mailto:robdclark@gmail.com">robdclark@gmail.com</a>> wrote:<br>
>><br>
>> From: Rob Clark <<a href="mailto:robclark@freedesktop.org">robclark@freedesktop.org</a>><br>
>><br>
>> Some optimizations, like converting integer multiply/divide into left/<br>
>> right shifts, have additional constraints on the search expression.<br>
>> Like requiring that a variable is a constant power of two.  Support<br>
>> these cases by allowing a fxn name to be appended to the search var<br>
>> expression (ie. "a#32(is_power_of_two)").<br>
>><br>
>> TODO update doc/comment explaining search var syntax<br>
>> TODO the eagle-eyed viewer might have noticed that this could also<br>
>> replace the existing const syntax (ie. "#a").  Not sure if we should<br>
>> keep that.. we could make it syntactic sugar (ie '#' automatically sets<br>
>> the cond fxn ptr to 'is_const') or just get rid of it entirely?  Maybe<br>
>> that is a follow-on clean-up patch?<br>
>><br>
>> Signed-off-by: Rob Clark <<a href="mailto:robclark@freedesktop.org">robclark@freedesktop.org</a>><br>
>> ---<br>
>>  src/compiler/nir/nir_algebraic.py     |  8 +++--<br>
>>  src/compiler/nir/nir_opt_algebraic.py |  5 +++<br>
>>  src/compiler/nir/nir_search.c         |  3 ++<br>
>>  src/compiler/nir/nir_search.h         | 10 ++++++<br>
>>  src/compiler/nir/nir_search_helpers.h | 66<br>
>> +++++++++++++++++++++++++++++++++++<br>
>>  5 files changed, 90 insertions(+), 2 deletions(-)<br>
>>  create mode 100644 src/compiler/nir/nir_search_helpers.h<br>
>><br>
>> diff --git a/src/compiler/nir/nir_algebraic.py<br>
>> b/src/compiler/nir/nir_algebraic.py<br>
>> index 285f853..19ac6ee 100644<br>
>> --- a/src/compiler/nir/nir_algebraic.py<br>
>> +++ b/src/compiler/nir/nir_algebraic.py<br>
>> @@ -76,6 +76,7 @@ class Value(object):<br>
>>           return Constant(val, name_base)<br>
>><br>
>>     __template = mako.template.Template("""<br>
>> +#include "compiler/nir/nir_search_helpers.h"<br>
>>  static const ${val.c_type} ${<a href="http://val.name" rel="noreferrer" target="_blank">val.name</a>} = {<br>
>>     { ${val.type_enum}, ${val.bit_size} },<br>
>>  % if isinstance(val, Constant):<br>
>> @@ -84,6 +85,7 @@ static const ${val.c_type} ${<a href="http://val.name" rel="noreferrer" target="_blank">val.name</a>} = {<br>
>>     ${val.index}, /* ${val.var_name} */<br>
>>     ${'true' if val.is_constant else 'false'},<br>
>>     ${val.type() or 'nir_type_invalid' },<br>
>> +   ${val.cond if val.cond else 'NULL'},<br>
>>  % elif isinstance(val, Expression):<br>
>>     ${'true' if val.inexact else 'false'},<br>
>>     nir_op_${val.opcode},<br>
>> @@ -113,7 +115,7 @@ static const ${val.c_type} ${<a href="http://val.name" rel="noreferrer" target="_blank">val.name</a>} = {<br>
>>                                      Variable=Variable,<br>
>>                                      Expression=Expression)<br>
>><br>
>> -_constant_re = re.compile(r"(?P<value>[^@]+)(?:@(?P<bits>\d+))?")<br>
>> +_constant_re = re.compile(r"(?P<value>[^@\(]+)(?:@(?P<bits>\d+))?")<br>
><br>
><br>
> Spurious change?<br>
><br>
<br>
</div></div>I thought it needed to avoid matching something like<br>
a(is_power_of_two).. but it seems to work with that hunk reverted so I<br>
guess I can drop it..<br>
<div><div class="h5"><br>
>><br>
>><br>
>>  class Constant(Value):<br>
>>     def __init__(self, val, name):<br>
>> @@ -150,7 +152,8 @@ class Constant(Value):<br>
>>           return "nir_type_float"<br>
>><br>
>>  _var_name_re = re.compile(r"(?P<const>#)?(?P<name>\w+)"<br>
>> -<br>
>> r"(?:@(?P<type>int|uint|bool|float)?(?P<bits>\d+)?)?")<br>
>> +<br>
>> r"(?:@(?P<type>int|uint|bool|float)?(?P<bits>\d+)?)?"<br>
>> +                          r"(?P<cond>\([^\)]+\))?")<br>
>><br>
>>  class Variable(Value):<br>
>>     def __init__(self, val, name, varset):<br>
>> @@ -161,6 +164,7 @@ class Variable(Value):<br>
>><br>
>>        self.var_name = m.group('name')<br>
>>        self.is_constant = m.group('const') is not None<br>
>> +      self.cond = m.group('cond')<br>
>>        self.required_type = m.group('type')<br>
>>        self.bit_size = int(m.group('bits')) if m.group('bits') else 0<br>
>><br>
>> diff --git a/src/compiler/nir/nir_opt_algebraic.py<br>
>> b/src/compiler/nir/nir_opt_algebraic.py<br>
>> index 0a95725..952a91a 100644<br>
>> --- a/src/compiler/nir/nir_opt_algebraic.py<br>
>> +++ b/src/compiler/nir/nir_opt_algebraic.py<br>
>> @@ -62,6 +62,11 @@ d = 'd'<br>
>>  # constructed value should have that bit-size.<br>
>><br>
>>  optimizations = [<br>
>> +<br>
>> +   (('imul', a, '#b@32(is_power_of_two)'), ('ishl', a, ('find_lsb', b))),<br>
>> +   (('udiv', a, '#b@32(is_power_of_two)'), ('ushr', a, ('find_lsb', b))),<br>
>> +   (('umod', a, '#b(is_power_of_two)'),    ('iand', a, ('isub', b, 1))),<br>
>> +<br>
>>     (('fneg', ('fneg', a)), a),<br>
>>     (('ineg', ('ineg', a)), a),<br>
>>     (('fabs', ('fabs', a)), ('fabs', a)),<br>
>> diff --git a/src/compiler/nir/nir_search.c b/src/compiler/nir/nir_search.c<br>
>> index 2c2fd92..b21fb2c 100644<br>
>> --- a/src/compiler/nir/nir_search.c<br>
>> +++ b/src/compiler/nir/nir_search.c<br>
>> @@ -127,6 +127,9 @@ match_value(const nir_search_value *value,<br>
>> nir_alu_instr *instr, unsigned src,<br>
>>               instr->src[src].src.ssa->parent_instr->type !=<br>
>> nir_instr_type_load_const)<br>
>>              return false;<br>
>><br>
>> +         if (var->cond && !var->cond(instr, src, num_components,<br>
>> new_swizzle))<br>
>> +            return false;<br>
>> +<br>
>>           if (var->type != nir_type_invalid) {<br>
>>              if (instr->src[src].src.ssa->parent_instr->type !=<br>
>> nir_instr_type_alu)<br>
>>                 return false;<br>
>> diff --git a/src/compiler/nir/nir_search.h b/src/compiler/nir/nir_search.h<br>
>> index a500feb..f55d797 100644<br>
>> --- a/src/compiler/nir/nir_search.h<br>
>> +++ b/src/compiler/nir/nir_search.h<br>
>> @@ -68,6 +68,16 @@ typedef struct {<br>
>>      * never match anything.<br>
>>      */<br>
>>     nir_alu_type type;<br>
>> +<br>
>> +   /** Optional condition fxn ptr<br>
>> +    *<br>
>> +    * This is only allowed in search expressions, and allows additional<br>
>> +    * constraints to be placed on the match.  Typically used for<br>
>> 'is_constant'<br>
>> +    * variables to require, for example, power-of-two in order for the<br>
>> search<br>
>> +    * to match.<br>
>> +    */<br>
>> +   bool (*cond)(nir_alu_instr *instr, unsigned src,<br>
>> +                unsigned num_components, const uint8_t *swizzle);<br>
>>  } nir_search_variable;<br>
>><br>
>>  typedef struct {<br>
>> diff --git a/src/compiler/nir/nir_search_helpers.h<br>
>> b/src/compiler/nir/nir_search_helpers.h<br>
>> new file mode 100644<br>
>> index 0000000..8ed2ca0<br>
>> --- /dev/null<br>
>> +++ b/src/compiler/nir/nir_search_helpers.h<br>
>> @@ -0,0 +1,66 @@<br>
>> +/*<br>
>> + * Copyright © 2016 Red Hat<br>
>> + *<br>
>> + * Permission is hereby granted, free of charge, to any person obtaining<br>
>> a<br>
>> + * copy of this software and associated documentation files (the<br>
>> "Software"),<br>
>> + * to deal in the Software without restriction, including without<br>
>> limitation<br>
>> + * the rights to use, copy, modify, merge, publish, distribute,<br>
>> sublicense,<br>
>> + * and/or sell copies of the Software, and to permit persons to whom the<br>
>> + * Software is furnished to do so, subject to the following conditions:<br>
>> + *<br>
>> + * The above copyright notice and this permission notice (including the<br>
>> next<br>
>> + * paragraph) shall be included in all copies or substantial portions of<br>
>> the<br>
>> + * Software.<br>
>> + *<br>
>> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,<br>
>> EXPRESS OR<br>
>> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF<br>
>> MERCHANTABILITY,<br>
>> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT<br>
>> SHALL<br>
>> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR<br>
>> OTHER<br>
>> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,<br>
>> ARISING<br>
>> + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER<br>
>> DEALINGS<br>
>> + * IN THE SOFTWARE.<br>
>> + *<br>
>> + * Authors:<br>
>> + *    Rob Clark <<a href="mailto:robclark@freedesktop.org">robclark@freedesktop.org</a>><br>
>> + */<br>
>> +<br>
>> +#ifndef _NIR_SEARCH_HELPERS_<br>
>> +#define _NIR_SEARCH_HELPERS_<br>
>> +<br>
>> +#include "nir.h"<br>
>> +<br>
>> +static inline bool<br>
>> +__is_power_of_two(unsigned int x)<br>
>> +{<br>
>> +   return ((x != 0) && !(x & (x - 1)));<br>
>> +}<br>
>> +<br>
>> +static inline bool<br>
>> +is_power_of_two(nir_alu_instr *instr, unsigned src, unsigned<br>
>> num_components,<br>
>> +                const uint8_t *swizzle)<br>
>> +{<br>
>> +   nir_const_value *val = nir_src_as_const_value(instr->src[src].src);<br>
>> +<br>
>> +   /* only constant src's: */<br>
>> +   if (!val)<br>
>> +      return false;<br>
>> +<br>
>> +   for (unsigned i = 0; i < num_components; i++) {<br>
>> +      switch (nir_op_infos[instr->op].input_types[src]) {<br>
>> +      case nir_type_int:<br>
>> +         if (!__is_power_of_two(val->i32[swizzle[i]]))<br>
>> +            return false;<br>
>> +         break;<br>
>> +      case nir_type_uint:<br>
>> +         if (!__is_power_of_two(val->u32[swizzle[i]]))<br>
>> +            return false;<br>
><br>
><br>
> Your implementation of __is_power_of_two takes an unsigned.  There's no<br>
> benefit to splitting it into two cases and it just creates a false<br>
> distinction.  If you do, you can probably inline the helper (I don't care<br>
> much one way or the other on that).<br>
<br>
</div></div>hmm, are you sure about negative PoT?  Although possibly that should<br>
be '__is_power_of_two(ABS(val->i32[..])'?<br></blockquote><div><br></div><div>I don't know off-hand whether or not it's correct for negative power-of-two.  However, I do know that it does exactly the same thing in both cases regardless of whether or not the first one is correct :-)<br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
BR,<br>
-R<br>
<div class="HOEnZb"><div class="h5"><br>
> All in all, this seems ok.  The "(some_function)" syntax seems clunky but I<br>
> can't come up with anything better off-hand.  Let's just go with it for now<br>
> and we can always change it later.<br>
><br>
> Reviewed-by: Jason Ekstrand <<a href="mailto:jason@jlekstrand.net">jason@jlekstrand.net</a>><br>
><br>
>><br>
>> +         break;<br>
>> +      default:<br>
>> +         return false;<br>
>> +      }<br>
>> +   }<br>
>> +<br>
>> +   return true;<br>
>> +}<br>
>> +<br>
>> +#endif /* _NIR_SEARCH_ */<br>
>> --<br>
>> 2.5.5<br>
>><br>
><br>
</div></div></blockquote></div><br></div></div>