[RFA] Transparent alias suport part 10: Fix base+offset alias analysis oracle WRT aliases
Richard Biener
rguenther@suse.de
Wed Dec 9 08:47:00 GMT 2015
On Wed, 9 Dec 2015, Jan Hubicka wrote:
> Hi,
> this patch fixes base+offset alias oracles to consider variable aliases.
> With this patch and one extra hack I can LTO bootstrap with variale symbol
> merging disabled in lto-symtab.c
>
> The basic idea is simple - there is new comparer compare_base_decls which knows
> how to handle aliases via symbol table's address_equal_to predicate.
> I went through the sources and tried to find all places where we compare bases
> for equality and replace the copmarsion by this new predicate.
>
> Bootstrapped/regtested x86_64-linux, looks sane?
>
> Honza
>
> * tree-ssa-alias.c (ptr_deref_may_alias_decl_p): Use compare_base_decls
> (nonoverlapping_component_refs_of_decl_p): Update sanity check.
> (decl_refs_may_alias_p): Use compare_base_decls.
> * alias.c: Include cgraph.h
> (rtx_equal_for_memref_p): Use rtx_equal_for_memref_p.
> (compare_base_decls): New function.
> (base_alias_check): Likewise.
> (memrefs_conflict_p): Likewise.
> (nonoverlapping_memrefs_p): Likewise.
> * alias.h (compare_base_decls): Declare.
>
> * gcc.c-torture/execute/alias-2.c: New testcase.
> Index: tree-ssa-alias.c
> ===================================================================
> --- tree-ssa-alias.c (revision 231438)
> +++ tree-ssa-alias.c (working copy)
> @@ -194,7 +194,7 @@ ptr_deref_may_alias_decl_p (tree ptr, tr
> ptr = TREE_OPERAND (base, 0);
> else if (base
> && DECL_P (base))
> - return base == decl;
> + return compare_base_decls (base, decl) != 0;
> else if (base
> && CONSTANT_CLASS_P (base))
> return false;
> @@ -805,8 +805,10 @@ nonoverlapping_component_refs_of_decl_p
> ref2 = TREE_OPERAND (TREE_OPERAND (ref2, 0), 0);
> }
>
> - /* We must have the same base DECL. */
> - gcc_assert (ref1 == ref2);
> + /* Bases must be either same or uncomparable. */
> + gcc_checking_assert (ref1 == ref2
> + || (DECL_P (ref1) && DECL_P (ref2)
> + && compare_base_decls (ref1, ref2)));
I prefer explicit != 0 here.
>
> /* Pop the stacks in parallel and examine the COMPONENT_REFs of the same
> rank. This is sufficient because we start from the same DECL and you
> @@ -989,7 +991,7 @@ decl_refs_may_alias_p (tree ref1, tree b
> gcc_checking_assert (DECL_P (base1) && DECL_P (base2));
>
> /* If both references are based on different variables, they cannot alias. */
> - if (base1 != base2)
> + if (compare_base_decls (base1, base2) == 0)
> return false;
>
> /* If both references are based on the same variable, they cannot alias if
> Index: testsuite/gcc.c-torture/execute/alias-2.c
> ===================================================================
> --- testsuite/gcc.c-torture/execute/alias-2.c (revision 0)
> +++ testsuite/gcc.c-torture/execute/alias-2.c (revision 0)
> @@ -0,0 +1,12 @@
> +/* { dg-require-alias "" } */
> +int a[10]={};
> +extern int b[10] __attribute__ ((alias("a")));
> +int off;
> +main()
> +{
> + b[off]=1;
> + a[off]=2;
> + if (b[off]!=2)
> + __builtin_abort ();
> + return 0;
> +}
> Index: alias.c
> ===================================================================
> --- alias.c (revision 231438)
> +++ alias.c (working copy)
> @@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.
> #include "langhooks.h"
> #include "cfganal.h"
> #include "rtl-iter.h"
> +#include "cgraph.h"
>
> /* The aliasing API provided here solves related but different problems:
>
> @@ -1747,7 +1748,15 @@ rtx_equal_for_memref_p (const_rtx x, con
> return LABEL_REF_LABEL (x) == LABEL_REF_LABEL (y);
>
> case SYMBOL_REF:
> - return XSTR (x, 0) == XSTR (y, 0);
> + {
> + tree x_decl = SYMBOL_REF_DECL (x);
> + tree y_decl = SYMBOL_REF_DECL (y);
> +
> + if (!x_decl || !y_decl)
> + return XSTR (x, 0) == XSTR (y, 0);
> + else
> + return compare_base_decls (x_decl, y_decl) == 1;
> + }
>
> case ENTRY_VALUE:
> /* This is magic, don't go through canonicalization et al. */
> @@ -2010,6 +2019,31 @@ may_be_sp_based_p (rtx x)
> return !base || base == static_reg_base_value[STACK_POINTER_REGNUM];
> }
>
> +/* BASE1 and BASE2 are decls. Return 1 if they refer to same object, 0
> + if they refer to different objects and -1 if we can not decide. */
> +
> +int
> +compare_base_decls (tree base1, tree base2)
> +{
> + int ret;
> + gcc_checking_assert (DECL_P (base1) && DECL_P (base2));
> + if (base1 == base2)
> + return 1;
> +
> + bool in_symtab1 = decl_in_symtab_p (base1);
> + bool in_symtab2 = decl_in_symtab_p (base2);
> +
> + /* Declarations of non-automatic variables may have aliases. All other
> + decls are unique. */
> + if (in_symtab1 != in_symtab2 || !in_symtab1)
> + return 0;
> + ret = symtab_node::get_create (base1)->equal_address_to
> + (symtab_node::get_create (base2), true);
And I don't like ::get_create too much, why's ::get not enough here?
Predicates really shouldn't end up changing global state.
> + if (ret == 2)
> + return -1;
> + return ret;
> +}
> +
> /* Return 0 if the addresses X and Y are known to point to different
> objects, 1 if they might be pointers to the same object. */
>
> @@ -2047,6 +2081,17 @@ base_alias_check (rtx x, rtx x_base, rtx
> if (rtx_equal_p (x_base, y_base))
> return 1;
>
> + if (GET_CODE (x_base) == SYMBOL_REF && GET_CODE (y_base) == SYMBOL_REF)
> + {
> + tree x_decl = SYMBOL_REF_DECL (x_base);
> + tree y_decl = SYMBOL_REF_DECL (y_base);
> +
> + /* We can assume that no stores are made to labels. */
> + if (!x_decl || !y_decl)
> + return 0;
> + return compare_base_decls (x_decl, y_decl) != 0;
> + }
> +
> /* The base addresses are different expressions. If they are not accessed
> via AND, there is no conflict. We can bring knowledge of object
> alignment into play here. For example, on alpha, "char a, b;" can
> @@ -2268,11 +2313,32 @@ memrefs_conflict_p (int xsize, rtx x, in
> else
> y = addr_side_effect_eval (y, abs (ysize), 0);
>
> - if (rtx_equal_for_memref_p (x, y))
> + if (GET_CODE (x) == SYMBOL_REF && GET_CODE (y) == SYMBOL_REF)
> + {
> + tree x_decl = SYMBOL_REF_DECL (x);
> + tree y_decl = SYMBOL_REF_DECL (y);
> + int cmp;
> +
> + if (!x_decl || !y_decl)
> + cmp = offset_overlap_p (c, xsize, ysize);
> + else
> + cmp = compare_base_decls (x_decl, y_decl);
> +
> + /* If both decls are the same, decide by offsets. */
> + if (cmp == 1)
> + return offset_overlap_p (c, xsize, ysize);
please refactor to avoid doing this twice WRT !x_decl / !y_decl
Ok with these changes.
Thanks,
Richard.
> + /* If decls are different or we know by offsets that there is no overlap,
> + we win. */
> + if (!cmp || !offset_overlap_p (c, xsize, ysize))
> + return 0;
> + /* Decls may or may not be different and offsets overlap....*/
> + return -1;
> + }
> + else if (rtx_equal_for_memref_p (x, y))
> {
> return offset_overlap_p (c, xsize, ysize);
> }
>
> /* This code used to check for conflicts involving stack references and
> globals but the base address alias code now handles these cases. */
>
> @@ -2636,7 +2703,7 @@ nonoverlapping_memrefs_p (const_rtx x, c
> are constants or if one is a constant and the other a pointer into the
> stack frame. Otherwise a different base means we can't tell if they
> overlap or not. */
> - if (! rtx_equal_p (basex, basey))
> + if (! compare_base_decls (exprx, expry))
> return ((CONSTANT_P (basex) && CONSTANT_P (basey))
> || (CONSTANT_P (basex) && REG_P (basey)
> && REGNO_PTR_FRAME_P (REGNO (basey)))
> @@ -2647,6 +2714,10 @@ nonoverlapping_memrefs_p (const_rtx x, c
> if (loop_invariant)
> return 0;
>
> + /* Offset based disambiguation is OK even if we do not know that the
> + declarations are necessarily different
> + (i.e. compare_base_decls (exprx, expry) == 2) */
> +
> sizex = (!MEM_P (rtlx) ? (int) GET_MODE_SIZE (GET_MODE (rtlx))
> : MEM_SIZE_KNOWN_P (rtlx) ? MEM_SIZE (rtlx)
> : -1);
> Index: alias.h
> ===================================================================
> --- alias.h (revision 231438)
> +++ alias.h (working copy)
> @@ -36,6 +36,7 @@ extern int nonoverlapping_memrefs_p (con
> extern void dump_alias_stats_in_alias_c (FILE *s);
> tree reference_alias_ptr_type (tree);
> bool alias_ptr_types_compatible_p (tree, tree);
> +int compare_base_decls (tree, tree);
>
> /* This alias set can be used to force a memory to conflict with all
> other memories, creating a barrier across which no memory reference
>
>
--
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)
More information about the Gcc-patches
mailing list