The following tries to address the inconsistency with folding two addresses based on two decls vs. one pointer vs a decl address caused by the latter not honoring interposition.
Honza, is + /* If obj1 is interposable give up. */ + if (VAR_P (obj1) + && (TREE_STATIC (obj1) || DECL_EXTERNAL (obj1))) + { + varpool_node *node = varpool_node::get (obj1); + if (! node + || ! node->analyzed + || ! decl_binds_to_current_def_p (obj1)) + return false; + } conservatively correct? I tried to learn from symtab_node::equal_address_to but I'm not 100% sure. Esp. in what cases can I expect a NULL node from varpool_node::get? Basically I am using the above to decide whether I can use the ultimate alias target of two decls to decide whether they are not equal (points-to uses the DECL_UID of the ultimate alias target in the bitmaps). Maybe you can factor out a symtab helper for me? I think I want to catch all cases where symtab_node::equal_address_to would return -1 (thus with respect to aliases the above doesn't look conservative?) Thanks, Richard. 2016-10-19 Richard Biener <rguent...@suse.de> PR tree-optimization/78035 * tree-ssa-alias.h (struct pt_solution): Add vars_contains_interposable flag. * tree-ssa-structalias.c: Include varasm.h. (set_uids_in_ptset): Set vars_contains_interposable for interposable variables. (ipa_escaped_pt): Adjust. * tree-ssa-alias.c: Include varasm.h. (ptrs_compare_unequal): If pt->vars_contains_interposable or a decl is interposable then do not conclude anything about address equality. (dump_points_to_solution): Handle vars_contains_interposable. * gimple-pretty-print.c (pp_points_to_solution): Likewise. * gcc.target/i386/pr78035.c: New testcase. Index: gcc/testsuite/gcc.target/i386/pr78035.c =================================================================== --- gcc/testsuite/gcc.target/i386/pr78035.c (revision 0) +++ gcc/testsuite/gcc.target/i386/pr78035.c (revision 0) @@ -0,0 +1,24 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +extern int a; +extern int b; +extern int c; + +int foo(int choose_a) +{ + int *p; + if (choose_a) + p = &a; + else + p = &b; + return p != &c; +} + +int bar () +{ + return &a != &c; +} + +/* We should not optimize away either comparison. */ +/* { dg-final { scan-assembler-times "cmp" 2 } } */ Index: gcc/tree-ssa-alias.c =================================================================== --- gcc/tree-ssa-alias.c (revision 241362) +++ gcc/tree-ssa-alias.c (working copy) @@ -32,12 +32,12 @@ along with GCC; see the file COPYING3. #include "tree-pretty-print.h" #include "alias.h" #include "fold-const.h" - #include "langhooks.h" #include "dumpfile.h" #include "tree-eh.h" #include "tree-dfa.h" #include "ipa-reference.h" +#include "varasm.h" /* Broad overview of how alias analysis on gimple works: @@ -366,15 +366,39 @@ ptrs_compare_unequal (tree ptr1, tree pt /* We may not use restrict to optimize pointer comparisons. See PR71062. So we have to assume that restrict-pointed-to may be in fact obj1. */ - if (!pi || pi->pt.vars_contains_restrict) + if (! pi + || pi->pt.vars_contains_restrict + || pi->pt.vars_contains_interposable) return false; + /* If obj1 is interposable give up. */ + if (VAR_P (obj1) + && (TREE_STATIC (obj1) || DECL_EXTERNAL (obj1))) + { + varpool_node *node = varpool_node::get (obj1); + if (! node + || ! node->analyzed + || ! decl_binds_to_current_def_p (obj1)) + return false; + } return !pt_solution_includes (&pi->pt, obj1); } else if (TREE_CODE (ptr1) == SSA_NAME && obj2) { struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr1); - if (!pi || pi->pt.vars_contains_restrict) + if (! pi + || pi->pt.vars_contains_restrict + || pi->pt.vars_contains_interposable) return false; + /* If obj2 is interposable give up. */ + if (VAR_P (obj2) + && (TREE_STATIC (obj2) || DECL_EXTERNAL (obj2))) + { + varpool_node *node = varpool_node::get (obj2); + if (! node + || ! node->analyzed + || ! decl_binds_to_current_def_p (obj2)) + return false; + } return !pt_solution_includes (&pi->pt, obj2); } @@ -545,7 +569,12 @@ dump_points_to_solution (FILE *file, str comma = ", "; } if (pt->vars_contains_restrict) - fprintf (file, "%srestrict", comma); + { + fprintf (file, "%srestrict", comma); + comma = ", "; + } + if (pt->vars_contains_interposable) + fprintf (file, "%sinterposable", comma); fprintf (file, ")"); } } Index: gcc/tree-ssa-alias.h =================================================================== --- gcc/tree-ssa-alias.h (revision 241362) +++ gcc/tree-ssa-alias.h (working copy) @@ -57,6 +57,8 @@ struct GTY(()) pt_solution /* Nonzero if the vars bitmap includes a anonymous variable used to represent storage pointed to by a restrict qualified pointer. */ unsigned int vars_contains_restrict : 1; + /* Nonzero if the vars bitmap includes an interposable variable. */ + unsigned int vars_contains_interposable : 1; /* Set of variables that this pointer may point to. */ bitmap vars; Index: gcc/gimple-pretty-print.c =================================================================== --- gcc/gimple-pretty-print.c (revision 241362) +++ gcc/gimple-pretty-print.c (working copy) @@ -728,6 +728,12 @@ pp_points_to_solution (pretty_printer *b { pp_string (buffer, comma); pp_string (buffer, "restrict"); + comma = ", "; + } + if (pt->vars_contains_interposable) + { + pp_string (buffer, comma); + pp_string (buffer, "interposable"); } pp_string (buffer, ")"); } Index: gcc/tree-ssa-structalias.c =================================================================== --- gcc/tree-ssa-structalias.c (revision 241362) +++ gcc/tree-ssa-structalias.c (working copy) @@ -39,6 +39,8 @@ #include "tree-dfa.h" #include "params.h" #include "gimple-walk.h" +#include "varasm.h" + /* The idea behind this analyzer is to generate set constraints from the program, then solve the resulting constraints in order to generate the @@ -6344,6 +6346,18 @@ set_uids_in_ptset (bitmap into, bitmap f && fndecl && ! auto_var_in_fn_p (vi->decl, fndecl))) pt->vars_contains_nonlocal = true; + + /* If we have a variable that is interposable record that fact + for pointer comparison simplification. */ + if (VAR_P (vi->decl) + && (DECL_EXTERNAL (vi->decl) || TREE_PUBLIC (vi->decl))) + { + varpool_node *node = varpool_node::get (vi->decl); + if (! node + || ! node->analyzed + || ! decl_binds_to_current_def_p (node->decl)) + pt->vars_contains_interposable = true; + } } else if (TREE_CODE (vi->decl) == FUNCTION_DECL @@ -7576,7 +7590,8 @@ make_pass_build_ealias (gcc::context *ct /* IPA PTA solutions for ESCAPED. */ struct pt_solution ipa_escaped_pt - = { true, false, false, false, false, false, false, false, false, NULL }; + = { true, false, false, false, false, + false, false, false, false, false, NULL }; /* Associate node with varinfo DATA. Worker for cgraph_for_symbol_thunks_and_aliases. */