<p dir="ltr"><br>
On Apr 13, 2016 7:57 AM, "Connor Abbott" <<a href="mailto:cwabbott0@gmail.com">cwabbott0@gmail.com</a>> wrote:<br>
><br>
> On Wed, Apr 13, 2016 at 3:24 AM, Iago Toral <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br>
> > On Tue, 2016-04-12 at 13:16 -0400, Connor Abbott wrote:<br>
> >> I'm not sure I'm so comfortable with this. For one, this is the sort<br>
> >> of thing the backend can (and should) do. Why should be be adding<br>
> >> stuff at the NIR level to help the backend's copy propagation pass?<br>
> >> And perhaps more importantly, why should we be adding stuff at the NIR<br>
> >> level to workaround the lack of spilling support for doubles? I know<br>
> >> it's more difficult to implement than normal spilling, but it just<br>
> >> feels dirty to workaround it because some tests happen to use too many<br>
> >> registers.<br>
> ><br>
> > My thoughts for this were that NIR is producing suboptimal output for<br>
> > this case: it is unpacking and repacking an entire 64-bit float when it<br>
> > only really needs to operate on the high 32-bit, so fixing that in NIR,<br>
> > where the issue is introduced, instead of having each backend fix it,<br>
> > seemed to make more sense to me.<br>
> ><br>
> > I am not sure that backends can easily fix this either: what they are<br>
> > going to see is a nir_op_pack_double_2x32_split operation, they don't<br>
> > have any context to tell if the low 32-bit argument is actually<br>
> > different from what is already in the register, other than emitting code<br>
> > to check for that which kind of defeats the purpose of the optimization.<br>
> > I suppose they could still see if the instruction that generated the low<br>
> > 32-bit value is actually an unpack of the same register and do the right<br>
> > thing in that case. Would you like that solution better?<br>
> ><br>
> > In any case, I don't think this is something for copy-propagation to<br>
> > handle this is really not about copy-propagating a value, it is about<br>
> > not needing that value to begin with. Register pressure comes from<br>
> > needing to have the low 32-bit value alive until we recombine it in the<br>
> > 64-bit value. This patch makes it so that the low 32-bit is not alive at<br>
> > any moment, we don't need to care about it at any point, and that is why<br>
> > it helps reduce register pressure.</p>
<p dir="ltr">I think we have two fundamental problems here.  One is that spilling is broken.  The second is that NIR is generating code that the backend can't handle without spilling.  I can totally believe that the later is happening given that, thanks to the flag, a the backend can't move two SELs past each other when it schedules and we use SEL very heavily in the double lowering.</p>
<p dir="ltr">In this particular case, I do think we have a coalescing problem more than a need for a new opcode.  Thanks to SSA you could just as easily see a pack where one source is an unpack and do what you're doing with this "replace the top bits" opcode in fs/vec4_nir without adding a special opcode for it.  Therefore, even if this little optimization helps, I think the opcode is unneeded.  I also think it's probably solvable as Connor says with better coalescing.</p>
<p dir="ltr">> Think of what the backend is going to turn this into, though. Say you<br>
> have a sequence like:<br>
><br>
> hi = unpack_double_2x32_split_y foo<br>
><br>
> new_hi = ...<br>
><br>
> lo = unpack_double_2x32_split_x foo<br>
> bar = pack_double_2x32_split lo, new_hi<br>
><br>
> then this gets transformed to, in the backend:<br>
><br>
> hi = foo (stride 2, offset 1)<br>
><br>
> new_hi  = ..<br>
><br>
> lo = foo (stride 2, offset 0)<br>
> bar (stride 2, offset 0) = lo (stride 2, offset 0) # <- notice this<br>
> bar (stride 2, offset 1) hi (stride 2, offset 1)<br>
><br>
> Now the move from lo to bar has the same stride, and the same offset,<br>
> and the same offset, and bar obviously doesn't conflict with lo, so<br>
> register coalescing can combine lo and bar. This will result in:<br>
><br>
> hi = foo (stride 2, offset 1)<br>
><br>
> new_hi  = ..<br>
><br>
> bar (stride 2, offset 0) = foo (stride 2, offset 0)<br>
> bar (stride 2, offset 1) hi (stride 2, offset 1)<br>
><br>
> This is the same code (with the same register pressure) as if you had<br>
> used pack_double_2x32_split_y. In fact, in the bugzilla bug you gave<br>
> me an example of a shader where this happens, and I pointed it out to<br>
> you. I think all you need to do to fix your problem is move down the<br>
> unpack_2x32_split_x to right before the pack, since the backend isn't<br>
> smart enough to reorder it.<br>
><br>
> In any case, I think that we should get spilling to work on doubles regardless.<br>
><br>
> ><br>
> > Jason also mentioned that what we should do is fix the spilling code. I<br>
> > agree that we should do that, but I think the underlying issue here is<br>
> > not that, but that NIR's output is leading to inefficient code, which is<br>
> > then leading to unnecessary spilling in some cases. If we fix the<br>
> > spilling then we can live with the problem, but the problem is still<br>
> > there: we are still having live values that we don't need taking some<br>
> > register space and leading to unnecessary spilling.<br>
> ><br>
> > In any case, I understand why you don't like the patch, so I am fine<br>
> > with holding it back and focus on fixing spilling code first. FWIW, I<br>
> > already had a stab at that, but I run into something that I didn't quite<br>
> > figure out at that time:<br>
> ><br>
> > <a href="https://lists.freedesktop.org/archives/mesa-dev/2016-March/109370.html">https://lists.freedesktop.org/archives/mesa-dev/2016-March/109370.html</a><br>
><br>
> I didn't notice this fly by, but you're not doing the spilling right.<br>
> For things where the stride * type_size is 64, you can't decompose it<br>
> into two scratch reads/writes, since then the exec mask will be wrong.<br>
> You only want to read/write a channel if the exec mask is enabled for<br>
> it. You have to use a different message to spill doubles, since the<br>
> normal one (the scattered read/write) assumes the exec mask channels<br>
> correspond to 32-bit chunks. Jason would know more about this.<br>
><br>
> ><br>
> > I still have plans to get back to that though.<br>
> ><br>
> > Iago<br>
> ><br>
> >> Jason, what do you think?<br>
> >><br>
> >> On Tue, Apr 12, 2016 at 4:05 AM, Samuel Iglesias Gonsálvez<br>
> >> <<a href="mailto:siglesias@igalia.com">siglesias@igalia.com</a>> wrote:<br>
> >> > From: Iago Toral Quiroga <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>><br>
> >> ><br>
> >> > This is useful when we only need to modify the high 32-bit chunk of a double.<br>
> >> > This is a common case, because this is the part that encodes the exponent<br>
> >> > which we manipulate in some double lowering passes. Although we can accomplish<br>
> >> > the same by using pack_double_2x32, this new opcode is better for register<br>
> >> > pressure, since we don't have to unpack both parts of the double and keep<br>
> >> > the low 32-bits around until we can recombine the new exponent.<br>
> >> ><br>
> >> > We will use this opcode in the set_exponent() function of the double lowering<br>
> >> > pass and with that we will fix spilling issues in some dmat4 divide<br>
> >> > piglit tests on Intel.<br>
> >> > ---<br>
> >> >  src/compiler/nir/nir_opcodes.py | 14 ++++++++++++++<br>
> >> >  1 file changed, 14 insertions(+)<br>
> >> ><br>
> >> > diff --git a/src/compiler/nir/nir_opcodes.py b/src/compiler/nir/nir_opcodes.py<br>
> >> > index 9f62e08..f92dd8d 100644<br>
> >> > --- a/src/compiler/nir/nir_opcodes.py<br>
> >> > +++ b/src/compiler/nir/nir_opcodes.py<br>
> >> > @@ -276,6 +276,20 @@ di.i2 = src0.y;<br>
> >> >  dst.x = di.u64;<br>
> >> >  """)<br>
> >> ><br>
> >> > +opcode("pack_double_2x32_split_y", 0, tuint64, [0, 0], [tuint64, tuint32], "", """<br>
> >> > +union {<br>
> >> > +    uint64_t u64;<br>
> >> > +    struct {<br>
> >> > +        uint32_t i1;<br>
> >> > +        uint32_t i2;<br>
> >> > +    };<br>
> >> > +} di;<br>
> >> > +<br>
> >> > +di.u64 = src0;<br>
> >> > +di.i1 = src1;<br>
> >> > +dst = di.u64;<br>
> >> > +""")<br>
> >> > +<br>
> >> >  unop_horiz("unpack_double_2x32", 2, tuint32, 1, tuint64, """<br>
> >> >  union {<br>
> >> >      uint64_t u64;<br>
> >> > --<br>
> >> > 2.5.0<br>
> >> ><br>
> >> > _______________________________________________<br>
> >> > mesa-dev mailing list<br>
> >> > <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> >> > <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
> >> _______________________________________________<br>
> >> mesa-dev mailing list<br>
> >> <a href="mailto:mesa-dev@lists.freedesktop.org">mesa-dev@lists.freedesktop.org</a><br>
> >> <a href="https://lists.freedesktop.org/mailman/listinfo/mesa-dev">https://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
> ><br>
> ><br>
</p>