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.