diff mbox

[RFC] PR78035

Message ID alpine.LSU.2.11.1610201113320.2258@t29.fhfr.qr
State New
Headers show

Commit Message

Richard Biener Oct. 20, 2016, 9:22 a.m. UTC
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  <rguenther@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.

Comments

Jan Hubicka Oct. 20, 2016, 9:46 a.m. UTC | #1
> 
> 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

I would drop node->analyzed. If decl_binds_to_current_def_p returns
false positives, I would say it is bug of this predicate and also in
late compilation we drop the bodies after compiling but they still
bind to current def.

> 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?

If you do folding from fold-const.c, then you need to be conservative
when symbol table is not built yet.  If you analyze gimple bodies
after cgraph construction we should be able to assume that the symbol
table entries are created (I know we had some side cases with this in
past but I hope they are fixed or I will fix it).

symtab_node::equal_address_to contains the magic mostly becuase of early
folding.

> 
> 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?)

OK, so you need a predicate such that if it returns true on
node1, node2 then node1==node2 if and only if ultimate alias targets are the
same?

I can do that.  Wonder what would be proper name for this beast?

Note that we are generally inconsistent about what aliases are valid. In older
GCCs I think generally you can't safely use two aliases of the same symbol for
non-readonly memory.

I was thining that we may just impose an requirement for the aliases to be explicitely
declared.  I.e.

extern int a;
extern int b __attribute__ ((alias("a")));

would be only valid way to mix a and b pointing to the same memory location.

The fact that difference declarations are actually different objects is quite
burried into nature of C/C++ standards and trying to fully support this may be
quite some work.  What are the consequences on the base+offset alias oracle
accuracy?

Honza
> 
> Thanks,
> Richard.
> 
> 2016-10-19  Richard Biener  <rguenther@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.  */
Richard Biener Oct. 20, 2016, 10:03 a.m. UTC | #2
On Thu, 20 Oct 2016, Jan Hubicka wrote:

> > 
> > 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
> 
> I would drop node->analyzed. If decl_binds_to_current_def_p returns
> false positives, I would say it is bug of this predicate and also in
> late compilation we drop the bodies after compiling but they still
> bind to current def.

Ok.

> > 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?
> 
> If you do folding from fold-const.c, then you need to be conservative
> when symbol table is not built yet.  If you analyze gimple bodies
> after cgraph construction we should be able to assume that the symbol
> table entries are created (I know we had some side cases with this in
> past but I hope they are fixed or I will fix it).
> 
> symtab_node::equal_address_to contains the magic mostly becuase of early
> folding.

I see.  As this is part of the code happens when points-to is available
we should be safe then, but I guess "safe" would be to handle ! node
conservatively then.

> > 
> > 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?)
> 
> OK, so you need a predicate such that if it returns true on
> node1, node2 then node1==node2 if and only if ultimate alias targets are the
> same?

Yes.

> I can do that.  Wonder what would be proper name for this beast?

Is it equal to node1 and node2 being not interposable?  (if we
factor out nonnull-ness)

If so interposable ()?

Not sure if this captures the alias behavior.

> Note that we are generally inconsistent about what aliases are valid. In older
> GCCs I think generally you can't safely use two aliases of the same symbol for
> non-readonly memory.
> 
> I was thining that we may just impose an requirement for the aliases to be explicitely
> declared.  I.e.
> 
> extern int a;
> extern int b __attribute__ ((alias("a")));
> 
> would be only valid way to mix a and b pointing to the same memory location.
> 
> The fact that difference declarations are actually different objects is quite
> burried into nature of C/C++ standards and trying to fully support this may be
> quite some work.  What are the consequences on the base+offset alias oracle
> accuracy?

No idea but part of PR78035 notes that we are conservative when
comparing pointers but quite optimistic for aliasing here.  This
causes issue when we propagate pointer equivalences, like

extern int a;
extern int b;

ptr = &a;

...

if (ptr == &b)
  {
    *ptr = 3;
    .. = a;
  }

where we end up with

   b = 3;
   .. = a;

and thus breaking aliasing when a and b are the same.

But interposition would mean that (without LTO) all globals are
to be treated the same by points-to and we'd be left with
TBAA for the disambiguations?  At least for externs and for
all globals with -fPIC.

I guess the effect would be pretty bad...

(I'm trying to "fix" PR77964)

Richard.

> Honza
> > 
> > Thanks,
> > Richard.
> > 
> > 2016-10-19  Richard Biener  <rguenther@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.  */
> 
>
diff mbox

Patch

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.  */