Add a mem_alias_size helper class
Jeff Law
law@redhat.com
Tue Nov 29 22:11:00 GMT 2016
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.sandiford@arm.com>
> Alan Hayward <alan.hayward@arm.com>
> David Sherwood <david.sherwood@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 ;-)
Jeff
More information about the Gcc-patches
mailing list