On Mon, 4 Feb 2008, Richard Guenther wrote:

> Following the old discussions at
> 
>   http://gcc.gnu.org/ml/gcc/2007-04/msg00096.html


With starting to prototype the proposed MEM_REF scheme I noticed
a few things that I'd like to add.  First let me summarize the
idea again.  The idea is to unify all memory reference trees into
two, MEM_REF and INDIRECT_MEM_REF with the following main goals:

 - get rid of the recursiveness of the current scheme (a.b[i].c.d.e[j].f)
   to simplify and speed up the operand scanner and the to be implemented
   tree level alias oracle

 - make TBAA easier and less fragile by annotating memory accesses with
   the alias set involved.  This allows for example the vectorizer to
   use the original alias sets, even when now vector types are used.
   (The idea is that the alias sets are encoded in the source program;
    we would extract them early and annotate the memory references as
    part of the lowering process)

So we will have

  MEM_REF < base, byte offset, alias set nr. >
  INDIRECT_MEM_REF < base_ptr, byte offset, alias set nr. >

where those two differ only in that the base object of MEM_REF need not
be addressable (the *base_ptr object in INDIRECT_MEM_REF obviously is,
as we have an address pointing to it).

Note also the symmetry to

  POINTER_PLUS < base, offset >

which allows (modulo type system issues) to directly combine address
computations with MEM_REFs and to simply transform

  ADDR_EXPR < INDIRECT_MEM_REF < base, offset, ... > >
    -> POINTER_PLUS < base, offset >

  ADDR_EXPR < MEM_REF < base, offset, ... > >
    -> POINTER_PLUS < ADDR_EXPR < base >, offset >

Given that at the moment we allow invariant addresses to pass the
is_gimple_min_invariant test and that we allow &a.b as
is_gimple_formal_tmp_rhs, IMHO invariant POINTER_PLUS exprs like
&a + CST should be allowed as is_gimple_min_invariant as well, as
should non-invariant &a + o be allowed as is_gimple_formal_tmp_rhs.
So,

  foo (&a.c)

could become

  foo (&a + 4)

without an extra temporary, as well as

  tmp = &a[i];

which would become

  tmp = &a + i;


During prototyping I noticed a few things.  One is that we use
several reference trees on registers, like IMAGPART_EXPR, REALPART_EXPR
and BIT_FIELD_REF -- we need to avoid lowering references to such
registers to MEM_REF.

Another thing is bit-field accesses, like for example in

  struct { int pad : 3; int bit : 1; } x;
  x.bit = 1;
  tmp = x.bit;

which cannot be encoded with MEM_REF directly as that doesn't allow
specifying the offset in bit granularity (and IMHO it doesn't make
sense to do so).  I am playing with lowering the above to

  wtmp = MEM_REF(int) < x, 0, ... >;
  BIT_FIELD_REF < wtmp, 3, 1 > = 1;
  MEM_REF(int) < x, 0, ... > = wtmp;
  wtmp = MEM_REF(int) < x, 0, ... >;
  tmp = BIT_FIELD_REF < wtmp, 3, 1 >;

using the bitfield mode to access the whole bitfield and extract/set
the parts using BIT_FIELD_REF.  IMHO this is better than lowering to
shift and mask operations.  Note that one goal is to do complete lowering,
not keeping some operations unlowered (which would of course be also
possible here).  I'm not sure what to do about bit-aligned TImode fields
for example, or other things that appearantly can be done with Ada
(which allows bit-packing).

Another thing is (late) diagnostics, which will now print MEM_REF
expressions if they previously printed COMPONTENT_REFs or ARRAY_REFs,
but if necessary those can be re-generated.

One more thing is that with the TBAA alias set involved encoded in the
memory reference we in principle no longer need to be careful about type
correctness of pointers, but should be able to propagate them at will,
reducing the number of conversions required (all those conversions of
pointers are value preserving anyway, the current limitations are somewhat
artificial).  All what matters is the access type and the alias set
involved, which for example lets us encode VIEW_CONVERT_EXPR < type, base >
as

  MEM_REF(type) < base, 0, 0 >

simply using alias set zero for the read (the type of the MEM_REF also
specifies the access size).  A related thing is alignment of an access,
which is in principle encoded in the information we have about the
base object.  Not so in the case of INDIRECT_MEM_REF, if we start being
ignorant about its base_ptr type.  So I reserved the option to encode
alignment information alongside the alias set number in the MEM_REF
itself (like we do on RTL).  This also eases extraction of alignment
information in case the offset is non-constant, but the alignment is
nevertheless known (you can of course _not_ simply use the access type
to extract alignment information).


All of the above ignored all the fancy IDX idea with retaining
(multi-dimensional) array access information - I have not yet come
to the point prototyping that.

To shortly summarize this idea:  introduce a multiply-add expression
that we will not commutate, thus can keep extra semantics of the
positional arguments:  IDX < offset + index * step >.  For each
ARRAY_REF in a reference tree we create such an IDX operation
chaining them via offset and remembering its index and its increment.

  int A[l][m][n];
  tmp = A[i][j][k];

should become

 idxk = IDX < 0 + k * 4 >
 sizen = 4 * n;
 idxj = IDX < idxk + j * sizen >
 sizemn = sizen * m;
 idxi = IDX < idxj + i * sizemn >
 tmp = MEM_REF < A, idxi, ... >

which allows extracting array indices by walking the use-def chain of
idxi and collect from the IDX operations.


Comments still welcome ;)

Richard.

Reply via email to