I have a bug I'm trying to investigate where, starting in gcc-4.2.x,
the loop invariant pass considers a computation involving a global
register variable as invariant across a call.  The basic structure
of the code is:

register unsigned long regvar asm ("foo");

func(arg)
{
        for (...) {
                call();
                *arg = expression(regvar);
        }
}

The code is built with "-ffixed-foo".  Actually the specific
case is 64-bit sparc, and the register being used is "%g5"
so global_regs[%g5], call_used_regs[%g5] and fixed_regs[%g5]
will all be true.

loop-invariant.c decides that expression(regvar) is invariant
and can be moved outside of the loop, which is an illegal
transformation because calls clobber global register variables.

When I noticed this I said to myself, "Hmmm, that's peculiar..."

I then checked to see what changed in the loop invariant pass between
gcc-4.1.x and gcc-4.2.x, and mainly it was changed to use the dataflow
layer.

So I started looking at how the dataflow layer handles global register
variables wrt. calls.

When a CALL is encountered, df_insn_refs_record() only marks them as
used by going:

        for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
          if (global_regs[i])
            df_uses_record (...

I thought initially that this coude should be using "df_defs_record
(...", but the next few lines take care of that issue by iterating
over df_invalidated_by_call, which is initialized with the contents
of regs_invalidated_by_call and I validated that the global register
in use is included in the invalidation list by making some df_dump()
calls in a debugging session.

So the dataflow problem should show the loop-invariant pass that the
call inside the loop potentially changes 'regvar' and thus expressions
involving 'regvar' are not invariant.  But for some reason that isn't
happening.

I'm wondering if there is a bad interaction between how df-scan.c
cooks up these fake insn "locations" for things like
df_invalidated_by_call.

In such cases, DF_REF_LOC will be &regno_reg_rtx[], and in
loop-invariant.c it will:

1) Records the DF_REF_LOCs, via record_uses(), in the ->pos
   member of it's "struct use" data-structure.

2) Later writes directly to *u->pos in move_invariant_reg().

But perhaps we shouldn't even get that far with such fake
location expressions.

I'm trying to debug this further, but if anyone sees anything obvious
or has some suggestions for debugging this, let me know.

Thanks.

Reply via email to