<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Tue, Oct 16, 2018 at 7:51 PM Matt Turner <<a href="mailto:mattst88@gmail.com">mattst88@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Sun, Oct 14, 2018 at 3:58 PM Jason Ekstrand <<a href="mailto:jason@jlekstrand.net" target="_blank">jason@jlekstrand.net</a>> wrote:<br>
><br>
> On October 14, 2018 17:12:34 Matt Turner <<a href="mailto:mattst88@gmail.com" target="_blank">mattst88@gmail.com</a>> wrote:<br>
><br>
> > From: Jason Ekstrand <<a href="mailto:jason.ekstrand@intel.com" target="_blank">jason.ekstrand@intel.com</a>><br>
> ><br>
> > [mattst88]: Found in an old branch of Jason's.<br>
> ><br>
> > Jason implemented: inot, iand, ior, iadd, isub, ineg, iabs, compare,<br>
> >                   imin, imax, umin, umax<br>
> > Matt implemented:  ixor, imov, bcsel<br>
> > ---<br>
> > src/compiler/nir/nir_lower_int64.c | 186 +++++++++++++++++++++++++++++++++++++<br>
> > 1 file changed, 186 insertions(+)<br>
> ><br>
> > diff --git a/src/compiler/nir/nir_lower_int64.c<br>
> > b/src/compiler/nir/nir_lower_int64.c<br>
> > index 0d7f165b406..6b269830801 100644<br>
> > --- a/src/compiler/nir/nir_lower_int64.c<br>
> > +++ b/src/compiler/nir/nir_lower_int64.c<br>
> > @@ -24,6 +24,192 @@<br>
> > #include "nir.h"<br>
> > #include "nir_builder.h"<br>
> ><br>
> > +static nir_ssa_def *<br>
> > +lower_imov64(nir_builder *b, nir_ssa_def *x)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_imov(b, x_lo), nir_imov(b, x_hi));<br>
><br>
> You don't really need the movs...<br>
<br>
Thanks. I think that was really a copy-and-paste-and-replace mistake.<br>
<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_bcsel64(nir_builder *b, nir_ssa_def *cond, nir_ssa_def *x,<br>
> > nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_bcsel(b, cond, x_lo, y_lo),<br>
> > +                                    nir_bcsel(b, cond, x_hi, y_hi));<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_inot64(nir_builder *b, nir_ssa_def *x)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_inot(b, x_lo), nir_inot(b, x_hi));<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_iand64(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_iand(b, x_lo, y_lo),<br>
> > +                                    nir_iand(b, x_hi, y_hi));<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_ior64(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_ior(b, x_lo, y_lo),<br>
> > +                                    nir_ior(b, x_hi, y_hi));<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_ixor64(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, nir_ixor(b, x_lo, y_lo),<br>
> > +                                    nir_ixor(b, x_hi, y_hi));<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_iadd64(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   nir_ssa_def *res_lo = nir_iadd(b, x_lo, y_lo);<br>
> > +   nir_ssa_def *carry = nir_b2i(b, nir_ult(b, res_lo, x_lo));<br>
> > +   nir_ssa_def *res_hi = nir_iadd(b, carry, nir_iadd(b, x_hi, y_hi));<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, res_lo, res_hi);<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_isub64(nir_builder *b, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   nir_ssa_def *res_lo = nir_isub(b, x_lo, y_lo);<br>
> > +   /* In NIR, true is represented by ~0 which is -1 */<br>
><br>
> We've had discussions (had some at XDC this year) about changing booleans<br>
> to one-bit which would break this.  Doing b2i would be safer but this does<br>
> work for now.<br>
><br>
> > +   nir_ssa_def *borrow = nir_ult(b, x_lo, y_lo);<br>
> > +   nir_ssa_def *res_hi = nir_iadd(b, nir_isub(b, x_hi, y_hi), borrow);<br>
> > +<br>
> > +   return nir_pack_64_2x32_split(b, res_lo, res_hi);<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_ineg64(nir_builder *b, nir_ssa_def *x)<br>
> > +{<br>
> > +   /* Since isub is the same number of instructions (with better dependencies)<br>
> > +    * as iadd, subtraction is actually more efficient for ineg than the usual<br>
> > +    * 2's complement "flip the bits and add one".<br>
> > +    */<br>
> > +   return lower_isub64(b, nir_imm_int64(b, 0), x);<br>
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_iabs64(nir_builder *b, nir_ssa_def *x)<br>
> > +{<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *x_is_neg = nir_ilt(b, x_hi, nir_imm_int(b, 0));<br>
> > +   return nir_bcsel(b, x_is_neg, lower_ineg64(b, x), x);<br>
><br>
> lower_bcsel?  Or, since we're depending on this running multiple times,<br>
> just nir_ineg?  I go back and forth on whether a pass like this should run<br>
> in a loop or be smart enough to lower intermediate bits on the fly.  We<br>
> should probably pick one.<br>
<br>
Agreed, I don't love it. A later patch in the series calls<br>
nir_lower_int64() in a loop so I suppose for now I'll rely on that and<br>
use nir_ineg directly.<br></blockquote><div><br></div><div>Connor had a really good suggestion about that....<br></div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> > +}<br>
> > +<br>
> > +static nir_ssa_def *<br>
> > +lower_int64_compare(nir_builder *b, nir_op op, nir_ssa_def *x, nir_ssa_def *y)<br>
> > +{<br>
> > +   nir_ssa_def *x_lo = nir_unpack_64_2x32_split_x(b, x);<br>
> > +   nir_ssa_def *x_hi = nir_unpack_64_2x32_split_y(b, x);<br>
> > +   nir_ssa_def *y_lo = nir_unpack_64_2x32_split_x(b, y);<br>
> > +   nir_ssa_def *y_hi = nir_unpack_64_2x32_split_y(b, y);<br>
> > +<br>
> > +   switch (op) {<br>
> > +   case nir_op_ieq:<br>
> > +      return nir_iand(b, nir_ieq(b, x_hi, y_hi), nir_ieq(b, x_lo, y_lo));<br>
> > +   case nir_op_ine:<br>
> > +      return nir_ior(b, nir_ine(b, x_hi, y_hi), nir_ine(b, x_lo, y_lo));<br>
> > +   case nir_op_ult:<br>
> > +      return nir_ior(b, nir_ult(b, x_hi, y_hi),<br>
> > +                        nir_iand(b, nir_ieq(b, x_hi, y_hi),<br>
> > +                                    nir_ult(b, x_lo, y_lo)));<br>
> > +   case nir_op_ilt:<br>
> > +      /* This one is tricky.  Handled below */<br>
> > +      break;<br>
> > +   case nir_op_uge:<br>
> > +      /* Lower as !(x < y) in the hopes of better CSE */<br>
> > +      return nir_inot(b, lower_int64_compare(b, nir_op_ult, x, y));<br>
> > +   case nir_op_ige:<br>
> > +      /* Lower as !(x < y) in the hopes of better CSE */<br>
> > +      return nir_inot(b, lower_int64_compare(b, nir_op_ilt, x, y));<br>
> > +   default:<br>
> > +      unreachable("Invalid comparison");<br>
> > +   }<br>
> > +<br>
> > +   assert(op == nir_op_ilt);<br>
> > +<br>
> > +   nir_ssa_def *neg_x = lower_ineg64(b, x);<br>
> > +   nir_ssa_def *neg_y = lower_ineg64(b, y);<br>
> > +   nir_ssa_def *x_is_neg = nir_ilt(b, x_hi, nir_imm_int(b, 0));<br>
> > +   nir_ssa_def *y_is_neg = nir_ilt(b, y_hi, nir_imm_int(b, 0));<br>
> > +<br>
> > +   nir_ssa_def *imm_true = nir_imm_int(b, NIR_TRUE);<br>
> > +   nir_ssa_def *imm_false = nir_imm_int(b, NIR_FALSE);<br>
> > +   nir_ssa_def *ult = lower_int64_compare(b, nir_op_ult, x, y);<br>
> > +   nir_ssa_def *not_ult_neg =<br>
> > +      nir_inot(b, lower_int64_compare(b, nir_op_ult, neg_x, neg_y));<br>
><br>
> If you know both are negative, can't you just do an unsigned comparison in<br>
> the opposite direction?  That would save you all the expensive negation.<br>
> You may even be able to re-use the result above though I haven't thought<br>
> through it all the way.<br>
<br>
You wrote this code. You tell me :)<br></blockquote><div><br></div><div>I did?  Well, year-ago me didn't know what he was doing.  That guy was an idiot.<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
In fact, I recently noticed that some piglit comparison tests are<br>
failing, so I suspect there's a bug in here somewhere...<br></blockquote><div><br></div><div>Quite possibly.... Very little of this code got good testing.</div><div><br></div><div>--Jason<br></div></div></div>