[Mesa-dev] [PATCH 09/16] i965/fs: Calculate interference better in register_coalesce.
Pohjolainen, Topi
topi.pohjolainen at intel.com
Fri Jan 17 06:27:09 PST 2014
On Fri, Jan 10, 2014 at 02:29:04PM -0800, Matt Turner wrote:
> On Wed, Dec 25, 2013 at 2:11 AM, Pohjolainen, Topi
> <topi.pohjolainen at intel.com> wrote:
> > On Thu, Dec 19, 2013 at 01:40:23PM -0800, Matt Turner wrote:
> >> Previously we simply considered two registers whose live ranges
> >> overlapped to interfere. Cases such as
> >>
> >> set A ------
> >> ... |
> >> mov B, A -- |
> >> ... | B | A
> >> use B -- |
> >> ... |
> >> use A ------
> >>
> >> would be considered to interfere, even though B is an unmodified copy of
> >> A whose live range fit wholly inside that of A.
> >>
> >> If no writes to A or B occur between the mov B, A and the use of B then
> >> we can safely coalesce them.
> >>
> >> Instead of removing MOV instructions, we make them NOPs and remove them
> >> at once after the main pass is finished in order to avoid recomputing
> >> live intervals (which are needed to perform the previous step).
> >>
> >> total instructions in shared programs: 1543768 -> 1513077 (-1.99%)
> >> instructions in affected programs: 951563 -> 920872 (-3.23%)
> >> GAINED: 46
> >> LOST: 22
> >> ---
> >> src/mesa/drivers/dri/i965/brw_fs.cpp | 69 ++++++++++++++++++++++++++++++++----
> >> 1 file changed, 62 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/src/mesa/drivers/dri/i965/brw_fs.cpp b/src/mesa/drivers/dri/i965/brw_fs.cpp
> >> index e4ac0a5..ad56b87 100644
> >> --- a/src/mesa/drivers/dri/i965/brw_fs.cpp
> >> +++ b/src/mesa/drivers/dri/i965/brw_fs.cpp
> >> @@ -2273,7 +2273,7 @@ fs_visitor::register_coalesce()
> >> int last_use[MAX_SAMPLER_MESSAGE_SIZE];
> >> int next_ip = 0;
> >>
> >> - foreach_list_safe(node, &this->instructions) {
> >> + foreach_list(node, &this->instructions) {
> >> fs_inst *inst = (fs_inst *)node;
> >>
> >> int ip = next_ip;
> >> @@ -2299,8 +2299,39 @@ fs_visitor::register_coalesce()
> >> int var_to = live_intervals->var_from_reg(&inst->dst);
> >>
> >> if (live_intervals->vars_interfere(var_from, var_to) &&
> >> - !inst->dst.equals(inst->src[0]))
> >> - continue;
> >> + !inst->dst.equals(inst->src[0])) {
> >> +
> >> + if (live_intervals->end[var_to] > live_intervals->end[var_from])
> >> + continue;
> >
> > Just checking if I understood things correctly and trying to fill in the caps
> > that I cannot figure out myself: Is the check for the start implicit from
> > somewhere else? This has to apply as well, right?
> >
> > if (live_intervals->start[var_to] < live_intervals->start[var_from])
> > continue;
>
> We know that the live ranges of (A) var_from and (B) var_to interfere
> because of the ->vars_interfere() call above. If the end of B's live
> range is after the end of A's range, then we know two things:
> - the start of B's live range must be in A's live range (since we
> already know the two ranges interfere, this is the only remaining
> possibility)
> - the interference isn't of the form we're looking for (where B is
> entirely inside A)
>
> That's pretty tricky and it took me a while to recreate what I was
> thinking when I wrote the code, so let me know if this makes sense to
> you. :)
That makes sense, thanks!
>
> I think I'll put an explanatory comment there for good measure.
>
> >> +
> >> + bool overwritten = false;
> >> + int scan_ip = -1;
> >> +
> >> + foreach_list(n, &this->instructions) {
> >> + fs_inst *scan_inst = (fs_inst *)n;
> >> + scan_ip++;
> >> +
> >> + if (scan_inst->is_control_flow()) {
> >> + overwritten = true;
> >> + break;
> >> + }
> >
> > Instructions are scanned from the very beginning of the program, and hence we
> > are also scanning for instructions that correspond to control flow changes
> > (i.e., jumps) before either of the start of live intervals of 'var_to' and
> > 'var_from' (in fact if I'm not mistakan above, this should read "before live
> > interval of 'var_from'").
> >
> > And if any such instruction is found the consideration for any coalescing is
> > dropped. Isn't it enough to scan for control flow changes only after the start
> > of the live interval of 'var_from'? (It has been a while since I've been
> > thinking any of this sort of things and I'm easily missing things. But had to
> > ask.)
>
> I'm not sure because of DO instructions that mark the beginning of a
> loop -- if our live ranges are in a loop we probably need to think
> some more about how we can coalesce registers.. I think we can improve
> this later though, because I've seen a lot of shaders with loops that
> contain MOVs that could be removed if register coalescing were a bit
> smarter.
The more I also think about it the less clear it becomes, better to play safe
and think it through properly.
More information about the mesa-dev
mailing list