On Fri, Nov 3, 2017 at 5:32 PM, Richard Sandiford
<[email protected]> wrote:
> A general TARGET_MEM_REF is:
>
> BASE + STEP * INDEX + INDEX2 + OFFSET
>
> After classifying the address in this way, the code that builds
> TARGET_MEM_REFs tries to simplify the address until it's valid
> for the current target and for the mode of memory being addressed.
> It does this in a fixed order:
>
> (1) add SYMBOL to BASE
> (2) add INDEX * STEP to the base, if STEP != 1
> (3) add OFFSET to INDEX or BASE (reverted if unsuccessful)
> (4) add INDEX to BASE
> (5) add OFFSET to BASE
>
> So suppose we had an address:
>
> &symbol + offset + index * 8 (e.g. "a[i + 1]" for a global "a")
>
> on a target that only allows an index or an offset, not both. Following
> the steps above, we'd first create:
>
> tmp = symbol
> tmp2 = tmp + index * 8
>
> Then if the given offset value was valid for the mode being addressed,
> we'd create:
>
> MEM[base:tmp2, offset:offset]
>
> while if it was invalid we'd create:
>
> tmp3 = tmp2 + offset
> MEM[base:tmp3, offset:0]
>
> The problem is that this could happen if ivopts had decided to use
> a scaled index for an address that happens to have a constant base.
> The old procedure failed to give an indexed TARGET_MEM_REF in that case,
> and adding the offset last prevented later passes from being able to
> fold the index back in.
>
> The patch avoids this by skipping (2) if BASE + INDEX * STEP
> is a legitimate address and if OFFSET is stopping the address
> being valid.
>
> Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64-linux-gnu.
> OK to install?
>
> Richard
>
>
> 2017-10-31 Richard Sandiford <[email protected]>
> Alan Hayward <[email protected]>
> David Sherwood <[email protected]>
>
> gcc/
> * tree-ssa-address.c (keep_index_p): New function.
> (create_mem_ref): Use it. Only split out the INDEX * STEP
> component if that is invalid even with the symbol and offset
> removed.
>
> Index: gcc/tree-ssa-address.c
> ===================================================================
> --- gcc/tree-ssa-address.c 2017-11-03 12:15:44.097060121 +0000
> +++ gcc/tree-ssa-address.c 2017-11-03 12:21:18.060359821 +0000
> @@ -746,6 +746,20 @@ gimplify_mem_ref_parts (gimple_stmt_iter
> true, GSI_SAME_STMT);
> }
>
> +/* Return true if the STEP in PARTS gives a valid BASE + INDEX * STEP
> + address for type TYPE and if the offset is making it appear invalid. */
> +
> +static bool
> +keep_index_p (tree type, mem_address parts)
mem_ref_valid_without_offset_p (...)
?
> +{
> + if (!parts.base)
> + return false;
> +
> + gcc_assert (!parts.symbol);
> + parts.offset = NULL_TREE;
> + return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
> +}
> +
> /* Creates and returns a TARGET_MEM_REF for address ADDR. If necessary
> computations are emitted in front of GSI. TYPE is the mode
> of created memory reference. IV_CAND is the selected iv candidate in ADDR,
> @@ -809,7 +823,8 @@ create_mem_ref (gimple_stmt_iterator *gs
Which means all of the following would be more naturally written as
> into:
> index' = index << step;
> [... + index' + ,,,]. */
> - if (parts.step && !integer_onep (parts.step))
> + bool scaled_p = (parts.step && !integer_onep (parts.step));
> + if (scaled_p && !keep_index_p (type, parts))
> {
if (mem_ref_valid_without_offset_p (...))
{
...
return create_mem_ref_raw (...);
}
that said, the function should ideally be re-written to try a few more
options non-destructively. Doesn't IVOPTs itself already verify
the TARGET_MEM_REFs it generates (and costs!) are valid?
Thanks,
Richard.
> gcc_assert (parts.index);
> parts.index = force_gimple_operand_gsi (gsi,
> @@ -821,6 +836,7 @@ create_mem_ref (gimple_stmt_iterator *gs
> mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
> if (mem_ref)
> return mem_ref;
> + scaled_p = false;
> }
>
> /* Add offset to invariant part by transforming address expression:
> @@ -832,7 +848,9 @@ create_mem_ref (gimple_stmt_iterator *gs
> index' = index + offset;
> [base + index']
> depending on which one is invariant. */
> - if (parts.offset && !integer_zerop (parts.offset))
> + if (parts.offset
> + && !integer_zerop (parts.offset)
> + && (!var_in_base || !scaled_p))
> {
> tree old_base = unshare_expr (parts.base);
> tree old_index = unshare_expr (parts.index);
> @@ -882,7 +900,7 @@ create_mem_ref (gimple_stmt_iterator *gs
> /* Transform [base + index + ...] into:
> base' = base + index;
> [base' + ...]. */
> - if (parts.index)
> + if (parts.index && !scaled_p)
> {
> tmp = parts.index;
> parts.index = NULL_TREE;