Jeff Law <l...@redhat.com> writes:
> On 11/15/2016 09:04 AM, Richard Sandiford wrote:
>> alias.c encodes memory sizes as follows:
>>
>> size > 0: the exact size is known
>> size == 0: the size isn't known
>> size < 0: the exact size of the reference itself is known,
>>   but the address has been aligned via AND.  In this case
>>   "-size" includes the size of the reference and the worst-case
>>   number of bytes traversed by the AND.
>>
>> This patch wraps this up in a helper class and associated
>> functions.  The new routines fix what seems to be a hole
>> in the old logic: if the size of a reference A was unknown,
>> offset_overlap_p would assume that it could conflict with any
>> other reference B, even if we could prove that B comes before A.
>>
>> The fallback CONSTANT_P (x) && CONSTANT_P (y) case looked incorrect.
>> Either "c" is trustworthy as a distance between the two constants,
>> in which case the alignment handling should work as well there as
>> elsewhere, or "c" isn't trustworthy, in which case offset_overlap_p
>> is unsafe.  I think the latter's true; AFAICT we have no evidence
>> that "c" really is the distance between the two references, so using
>> it in the check doesn't make sense.
>>
>> At this point we've excluded cases for which:
>>
>> (a) the base addresses are the same
>> (b) x and y are SYMBOL_REFs, or SYMBOL_REF-based constants
>>     wrapped in a CONST
>> (c) x and y are both constant integers
>>
>> No useful cases should be left.  As things stood, we would
>> assume that:
>>
>>   (mem:SI (const_int X))
>>
>> could overlap:
>>
>>   (mem:SI (symbol_ref Y))
>>
>> but not:
>>
>>   (mem:SI (const (plus (symbol_ref Y) (const_int 4))))
>>
>> Tested on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?
>>
>> Thanks,
>> Richard
>>
>>
>> [ This patch is part of the SVE series posted here:
>>   https://gcc.gnu.org/ml/gcc/2016-11/msg00030.html ]
>>
>> gcc/
>> 2016-11-15  Richard Sandiford  <richard.sandif...@arm.com>
>>          Alan Hayward  <alan.hayw...@arm.com>
>>          David Sherwood  <david.sherw...@arm.com>
>>
>>      * alias.c (mem_alias_size): New class.
>>      (mem_alias_size::mode): New function.
>>      (mem_alias_size::exact_p): Likewise.
>>      (mem_alias_size::max_size_known_p): Likewise.
>>      (align_to): Likewise.
>>      (alias_may_gt): Likewise.
>>      (addr_side_effect_eval): Change type of size argument to
>>      mem_alias_size.  Use plus_constant.
>>      (offset_overlap_p): Change type of xsize and ysize to
>>      mem_alias_size.  Use alias_may_gt.  Don't assume an overlap
>>      between an access of unknown size and an access that's known
>>      to be earlier than it.
>>      (memrefs_conflict_p): Change type of xsize and ysize to
>>      mem_alias_size.  Remove fallback CONSTANT_P (x) && CONSTANT_P (y)
>>      handling.
> OK.  One possible nit below you might want to consider changing.
>
>> +/* Represents the size of a memory reference during alias analysis.
>> +   There are three possibilities:
>>
>> -/* Set up all info needed to perform alias analysis on memory references.  
>> */
>> +   (1) the size needs to be treated as completely unknown
>> +   (2) the size is known exactly and no alignment is applied to the address
>> +   (3) the size is known exactly but an alignment is applied to the address
>> +
>> +   (3) is used for aligned addresses of the form (and X (const_int -N)),
>> +   which can subtract something in the range [0, N) from the original
>> +   address X.  We handle this by subtracting N - 1 from X and adding N - 1
>> +   to the size, so that the range spans all possible bytes.  */
>> +class mem_alias_size {
>> +public:
>> +  /* Return an unknown size (case (1) above).  */
>> +  static mem_alias_size unknown () { return (HOST_WIDE_INT) 0; }
>> +
>> +  /* Return an exact size (case (2) above).  */
>> +  static mem_alias_size exact (HOST_WIDE_INT size) { return size; }
>> +
>> +  /* Return a worst-case size after alignment (case (3) above).
>> +     SIZE includes the maximum adjustment applied by the alignment.  */
>> +  static mem_alias_size aligned (HOST_WIDE_INT size) { return -size; }
>> +
>> +  /* Return the size of memory reference X.  */
>> +  static mem_alias_size mem (const_rtx x) { return MEM_SIZE (x); }
>> +
>> +  static mem_alias_size mode (machine_mode m);
>> +
>> +  /* Return true if the exact size of the memory is known.  */
>> +  bool exact_p () const { return m_value > 0; }
>> +  bool exact_p (HOST_WIDE_INT *) const;
>> +
>> +  /* Return true if an upper bound on the memory size is known;
>> +     i.e. not case (1) above.  */
>> +  bool max_size_known_p () const { return m_value != 0; }
>> +  bool max_size_known_p (HOST_WIDE_INT *) const;
>> +
>> +  /* Return true if the size is subject to alignment.  */
>> +  bool aligned_p () const { return m_value < 0; }
>> +
>> +private:
>> +  mem_alias_size (HOST_WIDE_INT value) : m_value (value) {}
>> +
>> +  HOST_WIDE_INT m_value;
>> +};
> If I were to see a call to the aligned_p method, my first thought is 
> testing if an object is properly aligned.  This method actually tells us 
> something different -- was the size adjusted to account for alignment 
> issues.
>
> In fact, when I was reading the memrefs_conflict_p changes that's the 
> mistake I nearly called the code out as wrong.  Then I went back to the 
> class definition and realized my mistake.
>
> ISTM that a better name would avoid someone else making a similar 
> mistake.  So consider changing aligned_p to something else 
> (size_was_adjusted_for_alignment seems overly verbose ;-)

Ah, yeah, hadn't thought about that, but I agree it's confusing
in hindsight.  Your name doesn't seem too long if we drop the
"size_was", e.g.

- adjusted_for_alignment_p
- padded_for_alignment_p
- padded_for_mask_p
- padded_for_and_p

Thanks,
Richard

Reply via email to