https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92656

--- Comment #3 from Jim Wilson <wilson at gcc dot gnu.org> ---
Looking at this, I see that the problem occurs in record_value_for_reg where it
does
      if (!insn
          || (value && rsp->last_set_table_tick >= label_tick_ebb_start))
        rsp->last_set_invalid = 1;
last_set_table_tick is 2 and label_tick_ebb_start is 1 because this is the
first block of the function.  This actually causes a lot of variables set in
the first block to be marked invalid if used in a successful combination two or
more times, which then prevents the nonzero bits info from being used for any
of them.

There seems to be a problem with how label_tick is used.  In the very first
block in the body of the function, label_tick is 2 and label_tick_ebb_start is
1.  This is because it is considered to be the second block in the ebb after
the entry block.  In the second block in the body of the function, label_tick
is 3 and label_tick_ebb_start is 3.  This means that every variable set in the
first block gets treated differently than in every block after the first.

If I add a little bit of code before the loop to force it to be the second
block, then I get correct output from combine.  I just added this before the
loop
  static int j = 0;
  if (val)
    j++;

This also explains why the problem only occurs with -mtune=sifive-7-series
because this enables the conditional move support that turns the loop into a
single block, and then the -funroll-loops option fully unrolls the loop,
turning the entire function into one block, which prevents combine from
handling many of the register sets correctly because everything is in the first
block now.

This also explains why the problem started when the 2->2 combination support
was added, as that causes more successful combinations, and hence more
registers getting invalidated in the first block.

So the question is why we need label_tick > label_tick_ebb_start for the first
block of the function.  There is nothing set in the entry block other than hard
registers, and those could always be handled specially by just marking them as
invalid somehow before processing instructions.

Or alternatively, in record_value_for_reg, maybe we can add a check for a
pseudo reg only set once and not live in the prologue, and avoid marking it as
invalid when we process it a second time.  There are already a lot of checks
like this scattered around the code.

Reply via email to