This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: USE patch vs the PA


  In message <199710251330.JAA02308@jfc.>you write:
  > 
  > >   > (1)	R1 = constant
  > >   > (2)	R2 = R1
  > >   > (3)	R1 = variable
  > > Note that if REG_N_SETS (R1) == 1, then find_base_value should return
  > > reg_base_value [REGNO (R1)] if it is nonzero.
  > 
  > Can you send me an example where this helps?
Not easily since the examples I'm working from sources with the
simplify_giv_expr patch, a rerun-loop patch, and other random
stuff I'm playing with.

It's worth noting that paying attention to REG_N_SETS and the
PLUS handling are closely related.  It's not all that useful to
discuss one outside the context of the other.

Right now PLUS handling looks something like this:

    case PLUS:
    case MINUS:
      {
        rtx src_0 = XEXP (src, 0), src_1 = XEXP (src, 1);

        /* Guess which operand is the base address.

           If the first operand is a symbol or the second operand is
           an integer, the first operand is the base address.  Else if
           either operand is a register marked as a pointer, it is the
           base address.  */

        if (GET_CODE (src_1) == CONST_INT
            || GET_CODE (src_0) == SYMBOL_REF
            || GET_CODE (src_0) == LABEL_REF
            || GET_CODE (src_0) == CONST)
          return find_base_value (src_0);

        if (GET_CODE (src_0) == REG && REGNO_POINTER_FLAG (REGNO (src_0)))
          return find_base_value (src_0);

        if (GET_CODE (src_1) == REG && REGNO_POINTER_FLAG (REGNO (src_1)))
          return find_base_value (src_1);

        return 0;
      }


So, if you have (plus (reg) (reg)) and neither has REGNO_POINTER_FLAG
set we do nothing.  Even if one of the regs has a known base value.


One might think that one of the regs should have REGNO_POINTER_FLAG set.

  * Conceptually REGNO_POINTER_FLAG should only be set for a "pure
  pointer".  By pure pointer I mean the value in the reg must be
  within the object being pointed to.

  That sounds odd, but gcc will internally often create a pseudoreg
  outside the bounds of an object, then "correct" it with a later
  addition.  The pseudo which is out of the bounds of the object
  must not have REGNO_POINTER_FLAG set.

  Thus, if you have (set (regC) (plus (regA) (regB))) and regA has
  REGNO_POINTER_FLAG set, you can _not_ set REGNO_POINTER_FLAG for
  regC unless you can prove that the sum of (regA) (regB) still
  points within the same object as (regA).

  It is important to realize that for alias gathering you only
  care about relating values to some base value (ie a symbol_ref,
  frame_pointer_rtx, etc).


  * On a technical level consider a call to emit_iv_add_mult.
  
  It basically computes b * m + a.

  In one case I care about it computes:

  (plus (mult (reg 101) (const_int 8))
	(plus (plus (reg 975) (const_int -8))
	      (reg 1024))

  [ That's not canonicalized, but you get the idea... ]

  Which (of course) creates multiple insns, with temporary
  pseudos holding some values -- we can't get at those pseudos
  easily to propagate REGNO_POINTER_FLAG the way we might want to.

  Furthermore, even though (reg 1024) is the pointer, it is
  difficult to prove that any subexpression involving reg 1024
  is a pointer.



So, how does the PLUS handling tie into peeking at REG_N_SETS?

Basically at the top of the PLUS/MINUS code in find_base_value my
code does something like this:

        if (GET_CODE (src_0) == REG)
          {
            temp = find_base_value (src_0);
            if (temp)
              src_0 = temp;
          }

        if (GET_CODE (src_1) == REG)
          {
            temp = find_base_value (src_1);
            if (temp)
              src_1 = temp;
          }


Which will allow us to pick up any underlying information about
the two regs, regardless of whether or not one is a strict pointer.

Using the example above we might emit code like:

(set (temp1) (plus (reg 975) (const_int -8)))

(set (temp2) (plus (reg 1024) (temp1)))

(set (temp3) (plus (mult (reg 101) (const_int 8)) (temp2)))


Remember (reg 1024) is related to a SYMBOL_REF.

So consider what happens when we find the set for temp2.

find_base_value is called with (plus (reg 1024) (temp1))

(reg 1024) is a pointer, so we call find_base_value (reg 1024), but
since find_base_value just returns the original reg we get nothing
useful back.

If we change find_base_value to return reg_base_values[X] if
the register is only set once, then we can relate temp2 back to
the SYMBOL_REF (via reg 1024).

That's the first improvement, we've now propagated the base value
to one more register.

Then consider what happens for temp3.  We call into find_base_value
with (plus (mult (reg 101) (const_int 8)) (temp2)))

temp2 does not have REGNO_POINTER_FLAG set, so we basically do
nothing and are unable to relate temp3 back to the SYMBOL_REF
(via temp2 & (reg 1024)).

With my change we call find_base_value on temp2, which will give
us back the SYMBOL_REF.  This allows us to relate temp3 back to the
original SYMBOL_REF (via temp2 & (reg 1024).



jeff




Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]