On Tue, Jan 9, 2018 at 3:39 PM, Richard Sandiford
<richard.sandif...@linaro.org> wrote:
> Richard Biener <richard.guent...@gmail.com> writes:
>> On Tue, Nov 7, 2017 at 7:04 PM, Richard Sandiford
>> <richard.sandif...@linaro.org> wrote:
>>> Richard Biener <richard.guent...@gmail.com> writes:
>>>> On Fri, Nov 3, 2017 at 5:32 PM, Richard Sandiford
>>>> <richard.sandif...@linaro.org> 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  <richard.sandif...@linaro.org>
>>>>>             Alan Hayward  <alan.hayw...@arm.com>
>>>>>             David Sherwood  <david.sherw...@arm.com>
>>>>>
>>>>> 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 (...)
>>>>
>>>> ?
>>>
>>> OK.
>>>
>>>>> +{
>>>>> +  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 (...);
>>>>    }
>>>
>>> Is this inside the test for a scale:
>>>
>>>   if (parts.step && !integer_onep (parts.step))
>>>     {
>>>       if (mem_ref_valid_without_offset_p (...))
>>>         {
>>>           tree tmp = parts.offset;
>>>           if (parts.base)
>>>             {
>>>               tmp = fold_build_pointer_plus (parts.base, tmp);
>>>               tmp = force_gimple_operand_gsi_1 (gsi, tmp,
>>>                                                 is_gimple_mem_ref_addr,
>>>                                                 NULL_TREE, true,
>>>                                                 GSI_SAME_STMT);
>>>             }
>>>           parts.base = tmp;
>>>           parts.offset = NULL_TREE;
>>>           mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
>>>           gcc_assert (mem_ref);
>>>           return mem_ref;
>>>         }
>>>       ...current code...
>>>     }
>>>
>>> ?  I can do that if you don't mind the cut-&-paste.  Or I could
>>> split the code that adds the offset out into a subroutine.
>>
>> Sorry for the late response.  Yes, sth like that.
>
> Sorry for the dropping the ball on this.  Is the version below OK?

Ok.

Richard.

> Tested on aarch64-linux-gnu, x86_64-linux-gnu and powerpc64-linux-gnu.
>
> Thanks,
> Richard
>
>
> 2018-01-09  Richard Sandiford  <richard.sandif...@linaro.org>
>             Alan Hayward  <alan.hayw...@arm.com>
>             David Sherwood  <david.sherw...@arm.com>
>
> gcc/
>         * tree-ssa-address.c (mem_ref_valid_without_offset_p): New function.
>         (add_offset_to_base): New function, split out from...
>         (create_mem_ref): ...here.  When handling a scale other than 1,
>         check first whether the address is valid without the offset.
>         Add it into the base if so, leaving the index and scale as-is.
>
> Index: gcc/tree-ssa-address.c
> ===================================================================
> --- gcc/tree-ssa-address.c      2018-01-05 13:38:01.651810414 +0000
> +++ gcc/tree-ssa-address.c      2018-01-09 14:36:36.533460131 +0000
> @@ -746,6 +746,35 @@ gimplify_mem_ref_parts (gimple_stmt_iter
>                                              true, GSI_SAME_STMT);
>  }
>
> +/* Return true if the OFFSET in PARTS is the only thing that is making
> +   it an invalid address for type TYPE.  */
> +
> +static bool
> +mem_ref_valid_without_offset_p (tree type, mem_address parts)
> +{
> +  if (!parts.base)
> +    parts.base = parts.offset;
> +  parts.offset = NULL_TREE;
> +  return valid_mem_ref_p (TYPE_MODE (type), TYPE_ADDR_SPACE (type), &parts);
> +}
> +
> +/* Fold PARTS->offset into PARTS->base, so that there is no longer
> +   a separate offset.  Emit any new instructions before GSI.  */
> +
> +static void
> +add_offset_to_base (gimple_stmt_iterator *gsi, mem_address *parts)
> +{
> +  tree tmp = parts->offset;
> +  if (parts->base)
> +    {
> +      tmp = fold_build_pointer_plus (parts->base, tmp);
> +      tmp = force_gimple_operand_gsi_1 (gsi, tmp, is_gimple_mem_ref_addr,
> +                                       NULL_TREE, true, GSI_SAME_STMT);
> +    }
> +  parts->base = tmp;
> +  parts->offset = NULL_TREE;
> +}
> +
>  /* 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,
> @@ -812,6 +841,14 @@ create_mem_ref (gimple_stmt_iterator *gs
>    if (parts.step && !integer_onep (parts.step))
>      {
>        gcc_assert (parts.index);
> +      if (parts.offset && mem_ref_valid_without_offset_p (type, parts))
> +       {
> +         add_offset_to_base (gsi, &parts);
> +         mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
> +         gcc_assert (mem_ref);
> +         return mem_ref;
> +       }
> +
>        parts.index = force_gimple_operand_gsi (gsi,
>                                 fold_build2 (MULT_EXPR, sizetype,
>                                              parts.index, parts.step),
> @@ -906,18 +943,7 @@ create_mem_ref (gimple_stmt_iterator *gs
>         [base'].  */
>    if (parts.offset && !integer_zerop (parts.offset))
>      {
> -      tmp = parts.offset;
> -      parts.offset = NULL_TREE;
> -      /* Add offset to base.  */
> -      if (parts.base)
> -       {
> -         tmp = fold_build_pointer_plus (parts.base, tmp);
> -         tmp = force_gimple_operand_gsi_1 (gsi, tmp,
> -                                           is_gimple_mem_ref_addr,
> -                                           NULL_TREE, true, GSI_SAME_STMT);
> -       }
> -      parts.base = tmp;
> -
> +      add_offset_to_base (gsi, &parts);
>        mem_ref = create_mem_ref_raw (type, alias_ptr_type, &parts, true);
>        if (mem_ref)
>         return mem_ref;

Reply via email to