<p dir="ltr"><br>
On Jul 15, 2015 11:20 PM, "Iago Toral" <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br>
><br>
> On Wed, 2015-07-15 at 11:02 -0700, Connor Abbott wrote:<br>
> > On Wed, Jul 15, 2015 at 7:49 AM, Iago Toral <<a href="mailto:itoral@igalia.com">itoral@igalia.com</a>> wrote:<br>
> > > Hi,<br>
> > ><br>
> > > when we sent the patches for the new nir->vec4 backend we mentioned that<br>
> > > we had a few dEQP tests that would fail to link because of register<br>
> > > spilling. Now that we have added GS support we see a few instances of<br>
> > > this problem popping up in a few GS piglit tests too, for example this<br>
> > > one:<br>
> > ><br>
> > > tests/spec/glsl-1.50/execution/variable-indexing/gs-input-array-vec4-index-rd.shader_test<br>
> > ><br>
> > > I have been looking into what is going on with these tests and I came to<br>
> > > the conclusion that the problem is a consequence of various factors, but<br>
> > > probably the main thing contributing to it is the way our SSA pass<br>
> > > works. That said, I am not that experienced with NIR, so it could also<br>
> > > be that my analysis is missing something and I am just arriving to wrong<br>
> > > conclusions, so I'll explain my thoughts below and hopefully someone<br>
> > > else with more NIR experience can jump in and confirm or reject my<br>
> > > analysis.<br>
> > ><br>
> > > The GS code in that test looks like this:<br>
> > ><br>
> > > for (int p = 0; p < 3; p++) {<br>
> > >    color = ((index >= ins[p].m1.length() ?<br>
> > >             ins[p].m2[index-ins[p].m1.length()] :<br>
> > >             ins[p].m1[index]) == expect) ?<br>
> > >                vec4(0.0, 1.0, 0.0, 1.0) : vec4(1.0, 0.0, 0.0, 1.0);<br>
> > >    gl_Position = gl_in[p].gl_Position;<br>
> > >    EmitVertex();<br>
> > > }<br>
> > ><br>
> > > One thing that is immediately contributing to the register pressure is<br>
> > > some really awful code generated because of the indirect array indexing<br>
> > > on the inputs inside the loop. This is because of the<br>
> > > lower_variable_index_to_cond_assign lowering pass called from<br>
> > > brw_shader.cpp. This pass will convert that color assignment into a<br>
> > > bunch of nested if/else statements which makes the generated GLSL IR<br>
> > > code rather large, involving plenty of temporaries too. This is only<br>
> > > made worse by the fact that loop unrolling will replicate that 3 times.<br>
> > > The result is a huge pile of GLSL IR with a few dozens of nested if/else<br>
> > > statements and temporaries that looks like [1] (that is only a fragment<br>
> > > of the GLSL IR).<br>
> > ><br>
> > > One thing that is particularly relevant in that code is that it has<br>
> > > multiple conditional assignments to the same variable<br>
> > > (dereference_array_value) as a consequence of this lowering pass.<br>
> > ><br>
> > > That much, however, is common to the NIR and non-NIR paths. The problem<br>
> > > in the NIR case is that all these assignments generate new SSA values,<br>
> > > which then become new registers in the final NIR form. This leads to NIR<br>
> > > code like [2].  In contrast, the old vec4 visitor path, is able to have<br>
> > > writes to the same variable write to the same register.<br>
> > ><br>
> > > As a result, if I print the code right before register allocation in the<br>
> > > NIR path [3] and I compare that to what we get with the old vec4 visitor<br>
> > > path at that same point [4], it is clearly visible that this difference<br>
> > > is allowing the vec4 visitor path to reduce register pressure (see how<br>
> > > in [4] we have multiple writes to vgrf5, while in [3] we always write to<br>
> > > a new vgrf every time).<br>
> > ><br>
> > > So, am I missing something or is this kind of result expected with NIR<br>
> > > programs? Is there anything in the nir->vec4 pass that we can do to fix<br>
> > > this or does this need to be fixed when going out of SSA moe inside NIR?<br>
> > ><br>
> > > Iago<br>
> > ><br>
> > > [1] <a href="http://pastebin.com/5uA8ex2S">http://pastebin.com/5uA8ex2S</a><br>
> > > [2] <a href="http://pastebin.com/pqLfvAVN">http://pastebin.com/pqLfvAVN</a><br>
> > > [3] <a href="http://pastebin.com/64nSuUH8">http://pastebin.com/64nSuUH8</a><br>
> > > [4] <a href="http://pastebin.com/WCrdYxzt">http://pastebin.com/WCrdYxzt</a><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="http://lists.freedesktop.org/mailman/listinfo/mesa-dev">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
> ><br>
> > Hi Iago,<br>
> ><br>
> > Indeed, NIR does convert conditional writes to conditional selectss --<br>
> > it's a required part of the conversion to SSA, and since our HW has a<br>
> > conditional select instruction that's just as fast as doing a<br>
> > conditional move, we haven't bothered much to try and change it back<br>
> > during out-of-SSA. However, doing this shouldn't make things worse. In<br>
> > your example, vgrf9, vgrf15, and vgrf17 all have very short live<br>
> > intervals and don't interfere with vgrf11 (unless there's another use<br>
> > of them somewhere after the snippet you pasted), which means that the<br>
> > register allocator is free to allocate the destinations of all the<br>
> > selects to the same register.<br>
> ><br>
> > What's happening, though, is that you're running into our terrible<br>
> > liveness analysis. After doing the proper liveness analysis, we figure<br>
> > out the place each register first becomes live and last becomes dead,<br>
> > and then we consider registers that have overlapping ranges to<br>
> > interfere. So we consider vgrf11 to interfere with vgrf15 and vgrf17,<br>
> > even though it really doesn't. The trouble with making it do the right<br>
> > thing is that we may actually need to extend the live ranges of<br>
> > registers when the exec masks don't match up, either because one uses<br>
> > writemask_all or because they have incompatible exec masks due to<br>
> > containing different datatypes (half-float vs. float, etc.). For<br>
> > example, in your snippet, if vgrf15 were to be written with<br>
> > force_writemask_all, then it actually would interfere with vgrf11. But<br>
> > right now we're simply being conservative and assuming everything is<br>
> > incompatible, which produces extra register pressure in situations<br>
> > like the one you have. We have the same problem with FS, and I have<br>
> > some idea how to make it better there, but I'm not sure if we would<br>
> > care enough to port it to vec4.<br>
> ><br>
> > So the long answer is that there are some unfortunate features of the<br>
> > backend that are making things much worse than they should be wrt<br>
> > register allocation, and separating things out like SSA does seems to<br>
> > make it worse in certain situations. The short answer is: go fix<br>
> > register spilling!<br>
> ><br>
> > Connor<br>
><br>
> I see, thanks for the detailed reply Connor. I'll have a look at the<br>
> vec4 register spilling code and Ben's work in that area and see what I<br>
> can do.</p>
<p dir="ltr">Thanks for working on that, it is the core problem here.  In the FS, we have an INTEL_DEBUG=spill option that triggers tells it to spill *everything*. That helps a lot when debugging spilling.<br>
--Jason</p>
<p dir="ltr">> Iago<br>
><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="http://lists.freedesktop.org/mailman/listinfo/mesa-dev">http://lists.freedesktop.org/mailman/listinfo/mesa-dev</a><br>
</p>