diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h
index 8e9b89b3e2c..52f225b1aae 100644
--- a/gcc/ipa-modref-tree.h
+++ b/gcc/ipa-modref-tree.h
@@ -1012,6 +1017,31 @@ struct GTY((user)) modref_tree
     return NULL;
   }
 
+  /* Return true if tree contains access to global memory.  */
+  bool global_access_p ()
+  {
+    size_t i, j, k;
+    modref_base_node <T> *base_node;
+    modref_ref_node <T> *ref_node;
+    modref_access_node *access_node;
+    if (every_base)
+      return true;
+    FOR_EACH_VEC_SAFE_ELT (bases, i, base_node)
+      {
+	if (base_node->every_ref)
+	  return true;
+	FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
+	  {
+	    if (ref_node->every_access)
+	      return true;
+	    FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
+	      if (access_node->parm_index < 0)
+		return true;
+	  }
+      }
+    return false;
+  }
+
   /* Return ggc allocated instance.  We explicitly call destructors via
      ggc_delete and do not want finalizers to be registered and
      called at the garbage collection time.  */
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 6d49cc1410e..0bbec8df0a2 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -280,17 +281,6 @@ modref_summary::~modref_summary ()
     ggc_delete (stores);
 }
 
-/* All flags that are implied by the ECF_CONST functions.  */
-const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
-				     | EAF_NODIRECTESCAPE | EAF_NOREAD;
-/* All flags that are implied by the ECF_PURE function.  */
-const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
-				    | EAF_NODIRECTESCAPE;
-/* All flags implied when we know we can ignore stores (i.e. when handling
-   call to noreturn).  */
-const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
-				    | EAF_NODIRECTESCAPE;
-
 /* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
    useful to track.  If returns_void is true moreover clear
    EAF_NOT_RETURNED.  */
@@ -305,10 +295,6 @@ remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
     eaf_flags &= ~implicit_pure_eaf_flags;
   else if ((ecf_flags & ECF_NORETURN) || returns_void)
     eaf_flags &= ~EAF_NOT_RETURNED;
-  /* Only NOCLOBBER or DIRECT flags alone are not useful (see comments
-     in tree-ssa-alias.c).  Give up earlier.  */
-  if ((eaf_flags & ~(EAF_DIRECT | EAF_NOCLOBBER)) == 0)
-    return 0;
   return eaf_flags;
 }
 
@@ -345,6 +331,26 @@ modref_summary::useful_p (int ecf_flags, bool check_flags)
   return stores && !stores->every_base;
 }
 
+/* Return true if global memory is read
+   (that is loads summary contains global memory access).  */
+bool
+modref_summary::global_memory_read_p ()
+{
+  if (!loads)
+    return true;
+  return loads->global_access_p ();
+}
+
+/* Return true if global memory is written.  */
+bool
+modref_summary::global_memory_written_p ()
+{
+  if (!stores)
+    return true;
+  return stores->global_access_p ();
+}
+
+
 /* Single function summary used for LTO.  */
 
 typedef modref_tree <tree> modref_records_lto;
diff --git a/gcc/ipa-modref.h b/gcc/ipa-modref.h
index 540fdea8efa..5afa3aa439f 100644
--- a/gcc/ipa-modref.h
+++ b/gcc/ipa-modref.h
@@ -37,10 +37,23 @@ struct GTY(()) modref_summary
   ~modref_summary ();
   void dump (FILE *);
   bool useful_p (int ecf_flags, bool check_flags = true);
+  bool global_memory_read_p ();
+  bool global_memory_written_p ();
 };
 
 modref_summary *get_modref_function_summary (cgraph_node *func);
 void ipa_modref_c_finalize ();
 void ipa_merge_modref_summary_after_inlining (cgraph_edge *e);
 
+/* All flags that are implied by the ECF_CONST functions.  */
+static const int implicit_const_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
+				     | EAF_NODIRECTESCAPE | EAF_NOREAD;
+/* All flags that are implied by the ECF_PURE function.  */
+static const int implicit_pure_eaf_flags = EAF_NOCLOBBER | EAF_NOESCAPE
+				    | EAF_NODIRECTESCAPE;
+/* All flags implied when we know we can ignore stores (i.e. when handling
+   call to noreturn).  */
+static const int ignore_stores_eaf_flags = EAF_DIRECT | EAF_NOCLOBBER | EAF_NOESCAPE
+				    | EAF_NODIRECTESCAPE;
+
 #endif
diff --git a/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c b/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c
index 1f30467b98e..de019a7ecaf 100644
--- a/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c
+++ b/gcc/testsuite/gcc.dg/torture/ssa-pta-fn-1.c
@@ -6,13 +6,13 @@ extern void abort (void);
 int *g;
 int dummy;
 
-int * __attribute__((noinline,const))
+int * __attribute__((noinline,const,noipa))
 foo_const(int *p) { return p; }
 
-int * __attribute__((noinline,pure))
+int * __attribute__((noinline,pure,noipa))
 foo_pure(int *p) { return p + dummy; }
 
-int * __attribute__((noinline))
+int * __attribute__((noinline,noipa))
 foo_normal(int *p) { g = p; return p; }
 
 void test_const(void)
@@ -58,4 +58,4 @@ int main()
 
 /* { dg-final { scan-tree-dump "q_const_. = { NONLOCAL i }" "alias" } } */
 /* { dg-final { scan-tree-dump "q_pure_. = { ESCAPED NONLOCAL i }" "alias" } } */
-/* { dg-final { scan-tree-dump "q_normal_. = { ESCAPED NONLOCAL }" "alias" } } */
+/* { dg-final { scan-tree-dump "q_normal_. = { ESCAPED NONLOCAL i }" "alias" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c b/gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c
index cb85ec18bbc..aa639b45dc2 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pta-callused.c
@@ -22,5 +22,5 @@ int bar (int b)
   return *foo (&q);
 }
 
-/* { dg-final { scan-tree-dump "CALLUSED\\(\[0-9\]+\\) = { f.* i q }" "alias" } } */
+/* { dg-final { scan-tree-dump "CALLUSED\\(\[0-9\]+\\) = { NONLOCAL f.* i q }" "alias" } } */
 
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 0b8a81ff113..c97babeecb9 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -44,6 +44,9 @@
 #include "tree-ssa.h"
 #include "tree-cfg.h"
 #include "gimple-range.h"
+#include "ipa-modref-tree.h"
+#include "ipa-modref.h"
+#include "attr-fnspec.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -4048,98 +4051,190 @@ get_function_part_constraint (varinfo_t fi, unsigned part)
   return c;
 }
 
-/* For non-IPA mode, generate constraints necessary for a call on the
-   RHS.  */
-
 static void
-handle_rhs_call (gcall *stmt, vec<ce_s> *results)
-{
-  struct constraint_expr rhsc;
-  unsigned i;
-  bool returns_uses = false;
+handle_call_arg (gcall *stmt, tree arg, vec<ce_s> *results, int flags,
+		 int callescape_id, bool writes_global_memory)
+{
+  /* If the argument is not used we can ignore it.
+     Similarly argument is invisile for us if it not clobbered, does not
+     escape, is not read and can not be returned.  */
+  if ((flags & EAF_UNUSED)
+      || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
+		    | EAF_NOT_RETURNED))
+	  == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
+	      | EAF_NOT_RETURNED)))
+    return;
+
+  varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
+  tem->is_reg_var = true;
+  make_constraint_to (tem->id, arg);
+  make_any_offset_constraints (tem);
+
+  if (!(flags & EAF_DIRECT))
+    make_transitive_closure_constraints (tem);
 
-  for (i = 0; i < gimple_call_num_args (stmt); ++i)
+  if (!(flags & EAF_NOT_RETURNED))
     {
-      tree arg = gimple_call_arg (stmt, i);
-      int flags = gimple_call_arg_flags (stmt, i);
+      struct constraint_expr cexpr;
+      cexpr.var = tem->id;
+      cexpr.type = SCALAR;
+      cexpr.offset = 0;
+      results->safe_push (cexpr);
+    }
 
-      /* If the argument is not used we can ignore it.
-	 Similarly argument is invisile for us if it not clobbered, does not
-	 escape, is not read and can not be returned.  */
-      if ((flags & EAF_UNUSED)
-	  || ((flags & (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
-			| EAF_NOT_RETURNED))
-	      == (EAF_NOCLOBBER | EAF_NOESCAPE | EAF_NOREAD
-		  | EAF_NOT_RETURNED)))
-	continue;
+  if (!(flags & EAF_NOREAD))
+    {
+      varinfo_t uses = get_call_use_vi (stmt);
+      make_copy_constraint (uses, tem->id);
+    }
 
-      /* As we compute ESCAPED context-insensitive we do not gain
-         any precision with just EAF_NOCLOBBER but not EAF_NOESCAPE
-	 set.  The argument would still get clobbered through the
-	 escape solution.  */
-      if ((flags & EAF_NOCLOBBER)
-	   && (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
-	{
-	  varinfo_t uses = get_call_use_vi (stmt);
-	  varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
-	  tem->is_reg_var = true;
-	  make_constraint_to (tem->id, arg);
-	  make_any_offset_constraints (tem);
-	  if (!(flags & EAF_DIRECT))
-	    make_transitive_closure_constraints (tem);
-	  make_copy_constraint (uses, tem->id);
-	  /* TODO: This is overly conservative when some parameters are
-	     returned while others are not.  */
-	  if (!(flags & EAF_NOT_RETURNED))
-	    returns_uses = true;
-	  if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
-	    make_indirect_escape_constraint (tem);
-	}
-      else if (flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE))
+  if (!(flags & EAF_NOCLOBBER))
+    {
+      struct constraint_expr lhs, rhs;
+
+      /* *arg = callescape.  */
+      lhs.type = DEREF;
+      lhs.var = tem->id;
+      lhs.offset = 0;
+
+      rhs.type = SCALAR;
+      rhs.var = callescape_id;
+      rhs.offset = 0;
+      process_constraint (new_constraint (lhs, rhs));
+
+      /* callclobbered = arg.  */
+      make_copy_constraint (get_call_clobber_vi (stmt), tem->id);
+    }
+
+  if (!(flags & (EAF_NOESCAPE | EAF_NODIRECTESCAPE)))
+    {
+      struct constraint_expr lhs, rhs;
+
+      /* callescape = arg;  */
+      lhs.var = callescape_id;
+      lhs.offset = 0;
+      lhs.type = SCALAR;
+
+      rhs.var = tem->id;
+      rhs.offset = 0;
+      rhs.type = SCALAR;
+      process_constraint (new_constraint (lhs, rhs));
+
+      if (writes_global_memory)
+	make_escape_constraint (arg);
+    }
+  else if (!(flags & EAF_NOESCAPE))
+    {
+      struct constraint_expr lhs, rhs;
+
+      /* callescape = *(arg + UNKNOWN);  */
+      lhs.var = callescape_id;
+      lhs.offset = 0;
+      lhs.type = SCALAR;
+
+      rhs.var = tem->id;
+      rhs.offset = UNKNOWN_OFFSET;
+      rhs.type = DEREF;
+      process_constraint (new_constraint (lhs, rhs));
+
+      if (writes_global_memory)
+	make_indirect_escape_constraint (tem);
+    }
+}
+
+/* Determine global memory access of call STMT and update
+   WRITES_GLOBAL_MEMORY, READS_GLOBAL_MEMORY and USES_GLOBAL_MEMORY.  */
+
+static void
+determine_global_memory_access (gcall *stmt,
+				bool *writes_global_memory,
+				bool *reads_global_memory,
+				bool *uses_global_memory)
+{
+  tree callee;
+  cgraph_node *node;
+  modref_summary *summary;
+
+  /* We need to detrmine reads to set uses.  */
+  gcc_assert (!uses_global_memory || reads_global_memory);
+
+  if ((callee = gimple_call_fndecl (stmt)) != NULL_TREE
+      && (node = cgraph_node::get (callee)) != NULL
+      && (summary = get_modref_function_summary (node)))
+    {
+      if (writes_global_memory && *writes_global_memory)
+	*writes_global_memory = summary->global_memory_written_p ();
+      if (reads_global_memory && *reads_global_memory)
+	*reads_global_memory = summary->global_memory_read_p ();
+      if (reads_global_memory && uses_global_memory
+	  && !*reads_global_memory && node->binds_to_current_def_p ())
+	*uses_global_memory = false;
+    }
+  if ((writes_global_memory && *writes_global_memory)
+      || (uses_global_memory && *uses_global_memory)
+      || (reads_global_memory && *reads_global_memory))
+    {
+      attr_fnspec fnspec = gimple_call_fnspec (stmt);
+      if (fnspec.known_p ())
 	{
-	  struct constraint_expr lhs, rhs;
-	  varinfo_t uses = get_call_use_vi (stmt);
-	  varinfo_t clobbers = get_call_clobber_vi (stmt);
-	  varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
-	  tem->is_reg_var = true;
-	  make_constraint_to (tem->id, arg);
-	  make_any_offset_constraints (tem);
-	  if (!(flags & EAF_DIRECT))
-	    make_transitive_closure_constraints (tem);
-	  make_copy_constraint (uses, tem->id);
-	  if (!(flags & EAF_NOT_RETURNED))
-	    returns_uses = true;
-	  make_copy_constraint (clobbers, tem->id);
-	  /* Add *tem = nonlocal, do not add *tem = callused as
-	     EAF_NOESCAPE parameters do not escape to other parameters
-	     and all other uses appear in NONLOCAL as well.  */
-	  lhs.type = DEREF;
-	  lhs.var = tem->id;
-	  lhs.offset = 0;
-	  rhs.type = SCALAR;
-	  rhs.var = nonlocal_id;
-	  rhs.offset = 0;
-	  process_constraint (new_constraint (lhs, rhs));
-	  if (!(flags & (EAF_NOESCAPE | EAF_DIRECT)))
-	    make_indirect_escape_constraint (tem);
+	  if (writes_global_memory
+	      && !fnspec.global_memory_written_p ())
+	    *writes_global_memory = false;
+	  if (reads_global_memory && !fnspec.global_memory_read_p ())
+	    {
+	      *reads_global_memory = false;
+	      if (uses_global_memory)
+		*uses_global_memory = false;
+	    }
 	}
-      else
-	make_escape_constraint (arg);
     }
+}
+
+static void
+handle_rhs_call (gcall *stmt, vec<ce_s> *results,
+		 int implicit_eaf_flags,
+		 bool writes_global_memory,
+		 bool reads_global_memory)
+{
+  determine_global_memory_access (stmt, &writes_global_memory,
+				  &reads_global_memory,
+				  NULL);
 
-  /* If we added to the calls uses solution make sure we account for
-     pointers to it to be returned.  */
-  if (returns_uses)
+  varinfo_t callescape = new_var_info (NULL_TREE, "callescape", true);
+
+  /* If function can use global memory, add it to callescape
+     and to possible return values.  If not we can still use/return addresses
+     of global symbols.  */
+  struct constraint_expr lhs, rhs;
+
+  lhs.type = SCALAR;
+  lhs.var = callescape->id;
+  lhs.offset = 0;
+
+  rhs.type = reads_global_memory ? SCALAR : ADDRESSOF;
+  rhs.var = nonlocal_id;
+  rhs.offset = 0;
+
+  process_constraint (new_constraint (lhs, rhs));
+  results->safe_push (rhs);
+
+  varinfo_t uses = get_call_use_vi (stmt);
+  make_copy_constraint (uses, callescape->id);
+
+  for (unsigned i = 0; i < gimple_call_num_args (stmt); ++i)
     {
-      rhsc.var = get_call_use_vi (stmt)->id;
-      rhsc.offset = UNKNOWN_OFFSET;
-      rhsc.type = SCALAR;
-      results->safe_push (rhsc);
+      tree arg = gimple_call_arg (stmt, i);
+      int flags = gimple_call_arg_flags (stmt, i);
+      handle_call_arg (stmt, arg, results,
+		       flags | implicit_eaf_flags,
+		       callescape->id, writes_global_memory);
     }
 
   /* The static chain escapes as well.  */
   if (gimple_call_chain (stmt))
-    make_escape_constraint (gimple_call_chain (stmt));
+    handle_call_arg (stmt, gimple_call_chain (stmt), results,
+		     implicit_eaf_flags,
+		     callescape->id, writes_global_memory);
 
   /* And if we applied NRV the address of the return slot escapes as well.  */
   if (gimple_call_return_slot_opt_p (stmt)
@@ -4147,20 +4242,17 @@ handle_rhs_call (gcall *stmt, vec<ce_s> *results)
       && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
     {
       auto_vec<ce_s> tmpc;
-      struct constraint_expr lhsc, *c;
+      struct constraint_expr *c;
+      unsigned i;
+
       get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
-      lhsc.var = escaped_id;
-      lhsc.offset = 0;
-      lhsc.type = SCALAR;
+
+      make_constraints_to (callescape->id, tmpc);
+      if (writes_global_memory)
+	make_constraints_to (escaped_id, tmpc);
       FOR_EACH_VEC_ELT (tmpc, i, c)
-	process_constraint (new_constraint (lhsc, *c));
+	results->safe_push (*c);
     }
-
-  /* Regular functions return nonlocal memory.  */
-  rhsc.var = nonlocal_id;
-  rhsc.offset = 0;
-  rhsc.type = SCALAR;
-  results->safe_push (rhsc);
 }
 
 /* For non-IPA mode, generate constraints necessary for a call
@@ -4227,160 +4319,6 @@ handle_lhs_call (gcall *stmt, tree lhs, int flags, vec<ce_s> &rhsc,
     process_all_all_constraints (lhsc, rhsc);
 }
 
-/* For non-IPA mode, generate constraints necessary for a call of a
-   const function that returns a pointer in the statement STMT.  */
-
-static void
-handle_const_call (gcall *stmt, vec<ce_s> *results)
-{
-  struct constraint_expr rhsc;
-  unsigned int k;
-  bool need_uses = false;
-
-  /* Treat nested const functions the same as pure functions as far
-     as the static chain is concerned.  */
-  if (gimple_call_chain (stmt))
-    {
-      varinfo_t uses = get_call_use_vi (stmt);
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
-      need_uses = true;
-    }
-
-  /* And if we applied NRV the address of the return slot escapes as well.  */
-  if (gimple_call_return_slot_opt_p (stmt)
-      && gimple_call_lhs (stmt) != NULL_TREE
-      && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
-    {
-      varinfo_t uses = get_call_use_vi (stmt);
-      auto_vec<ce_s> tmpc;
-      get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
-      make_constraints_to (uses->id, tmpc);
-      need_uses = true;
-    }
-
-  if (need_uses)
-    {
-      varinfo_t uses = get_call_use_vi (stmt);
-      make_any_offset_constraints (uses);
-      make_transitive_closure_constraints (uses);
-      rhsc.var = uses->id;
-      rhsc.offset = 0;
-      rhsc.type = SCALAR;
-      results->safe_push (rhsc);
-    }
-
-  /* May return offsetted arguments.  */
-  varinfo_t tem = NULL;
-  for (k = 0; k < gimple_call_num_args (stmt); ++k)
-    {
-      int flags = gimple_call_arg_flags (stmt, k);
-
-      /* If the argument is not used or not returned we can ignore it.  */
-      if (flags & (EAF_UNUSED | EAF_NOT_RETURNED))
-	continue;
-      if (!tem)
-	{
-	  tem = new_var_info (NULL_TREE, "callarg", true);
-	  tem->is_reg_var = true;
-	}
-      tree arg = gimple_call_arg (stmt, k);
-      auto_vec<ce_s> argc;
-      get_constraint_for_rhs (arg, &argc);
-      make_constraints_to (tem->id, argc);
-    }
-  if (tem)
-    {
-      ce_s ce;
-      ce.type = SCALAR;
-      ce.var = tem->id;
-      ce.offset = UNKNOWN_OFFSET;
-      results->safe_push (ce);
-    }
-
-  /* May return addresses of globals.  */
-  rhsc.var = nonlocal_id;
-  rhsc.offset = 0;
-  rhsc.type = ADDRESSOF;
-  results->safe_push (rhsc);
-}
-
-/* For non-IPA mode, generate constraints necessary for a call to a
-   pure function in statement STMT.  */
-
-static void
-handle_pure_call (gcall *stmt, vec<ce_s> *results)
-{
-  struct constraint_expr rhsc;
-  unsigned i;
-  varinfo_t uses = NULL;
-  bool record_uses = false;
-
-  /* Memory reached from pointer arguments is call-used.  */
-  for (i = 0; i < gimple_call_num_args (stmt); ++i)
-    {
-      tree arg = gimple_call_arg (stmt, i);
-      int flags = gimple_call_arg_flags (stmt, i);
-
-      /* If the argument is not used we can ignore it.  */
-      if ((flags & EAF_UNUSED)
-	  || (flags & (EAF_NOT_RETURNED | EAF_NOREAD))
-	     == (EAF_NOT_RETURNED | EAF_NOREAD))
-	continue;
-      if (!uses)
-	{
-	  uses = get_call_use_vi (stmt);
-	  make_any_offset_constraints (uses);
-	  make_transitive_closure_constraints (uses);
-	}
-      make_constraint_to (uses->id, arg);
-      if (!(flags & EAF_NOT_RETURNED))
-	record_uses = true;
-    }
-
-  /* The static chain is used as well.  */
-  if (gimple_call_chain (stmt))
-    {
-      if (!uses)
-	{
-	  uses = get_call_use_vi (stmt);
-	  make_any_offset_constraints (uses);
-	  make_transitive_closure_constraints (uses);
-	}
-      make_constraint_to (uses->id, gimple_call_chain (stmt));
-      record_uses = true;
-    }
-
-  /* And if we applied NRV the address of the return slot.  */
-  if (gimple_call_return_slot_opt_p (stmt)
-      && gimple_call_lhs (stmt) != NULL_TREE
-      && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (stmt))))
-    {
-      if (!uses)
-	{
-	  uses = get_call_use_vi (stmt);
-	  make_any_offset_constraints (uses);
-	  make_transitive_closure_constraints (uses);
-	}
-      auto_vec<ce_s> tmpc;
-      get_constraint_for_address_of (gimple_call_lhs (stmt), &tmpc);
-      make_constraints_to (uses->id, tmpc);
-      record_uses = true;
-    }
-
-  /* Pure functions may return call-used and nonlocal memory.  */
-  if (record_uses)
-    {
-      rhsc.var = uses->id;
-      rhsc.offset = 0;
-      rhsc.type = SCALAR;
-      results->safe_push (rhsc);
-    }
-  rhsc.var = nonlocal_id;
-  rhsc.offset = 0;
-  rhsc.type = SCALAR;
-  results->safe_push (rhsc);
-}
-
 
 /* Return the varinfo for the callee of CALL.  */
 
@@ -4931,13 +4869,13 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
       if (flags & (ECF_CONST|ECF_NOVOPS))
 	{
 	  if (gimple_call_lhs (t))
-	    handle_const_call (t, &rhsc);
+	    handle_rhs_call (t, &rhsc, implicit_const_eaf_flags, false, false);
 	}
       /* Pure functions can return addresses in and of memory
 	 reachable from their arguments, but they are not an escape
 	 point for reachable memory of their arguments.  */
       else if (flags & (ECF_PURE|ECF_LOOPING_CONST_OR_PURE))
-	handle_pure_call (t, &rhsc);
+	handle_rhs_call (t, &rhsc, implicit_pure_eaf_flags, true, false);
       /* If the call is to a replaceable operator delete and results
 	 from a delete expression as opposed to a direct call to
 	 such operator, then the effects for PTA (in particular
@@ -4947,7 +4885,7 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
 	       && gimple_call_from_new_or_delete (t))
 	;
       else
-	handle_rhs_call (t, &rhsc);
+	handle_rhs_call (t, &rhsc, 0, true, true);
       if (gimple_call_lhs (t))
 	handle_lhs_call (t, gimple_call_lhs (t),
 			 gimple_call_return_flags (t), rhsc, fndecl);
@@ -7582,43 +7520,64 @@ compute_points_to_sets (void)
 	  pt = gimple_call_use_set (stmt);
 	  if (gimple_call_flags (stmt) & ECF_CONST)
 	    memset (pt, 0, sizeof (struct pt_solution));
-	  else if ((vi = lookup_call_use_vi (stmt)) != NULL)
-	    {
-	      *pt = find_what_var_points_to (cfun->decl, vi);
-	      /* Escaped (and thus nonlocal) variables are always
-	         implicitly used by calls.  */
-	      /* ???  ESCAPED can be empty even though NONLOCAL
-		 always escaped.  */
-	      pt->nonlocal = 1;
-	      pt->escaped = 1;
-	    }
 	  else
 	    {
-	      /* If there is nothing special about this call then
-		 we have made everything that is used also escape.  */
-	      *pt = cfun->gimple_df->escaped;
-	      pt->nonlocal = 1;
+	      bool uses_global_memory = true;
+	      bool reads_global_memory = true;
+
+	      determine_global_memory_access (stmt, NULL,
+					      &reads_global_memory,
+					      &uses_global_memory);
+	      if (!uses_global_memory)
+		;
+	      else if ((vi = lookup_call_use_vi (stmt)) != NULL)
+		{
+		  *pt = find_what_var_points_to (cfun->decl, vi);
+		  /* Escaped (and thus nonlocal) variables are always
+		     implicitly used by calls.  */
+		  /* ???  ESCAPED can be empty even though NONLOCAL
+		     always escaped.  */
+		  pt->nonlocal = uses_global_memory;
+		  pt->escaped = uses_global_memory;
+		}
+	      else if (uses_global_memory)
+		{
+		  /* If there is nothing special about this call then
+		     we have made everything that is used also escape.  */
+		  *pt = cfun->gimple_df->escaped;
+		  pt->nonlocal = 1;
+		}
 	    }
 
 	  pt = gimple_call_clobber_set (stmt);
 	  if (gimple_call_flags (stmt) & (ECF_CONST|ECF_PURE|ECF_NOVOPS))
 	    memset (pt, 0, sizeof (struct pt_solution));
-	  else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
-	    {
-	      *pt = find_what_var_points_to (cfun->decl, vi);
-	      /* Escaped (and thus nonlocal) variables are always
-	         implicitly clobbered by calls.  */
-	      /* ???  ESCAPED can be empty even though NONLOCAL
-		 always escaped.  */
-	      pt->nonlocal = 1;
-	      pt->escaped = 1;
-	    }
 	  else
 	    {
-	      /* If there is nothing special about this call then
-		 we have made everything that is used also escape.  */
-	      *pt = cfun->gimple_df->escaped;
-	      pt->nonlocal = 1;
+	      bool writes_global_memory = true;
+
+	      determine_global_memory_access (stmt, &writes_global_memory,
+					      NULL, NULL);
+
+	      if (!writes_global_memory)
+		;
+	      else if ((vi = lookup_call_clobber_vi (stmt)) != NULL)
+		{
+		  *pt = find_what_var_points_to (cfun->decl, vi);
+		  /* Escaped (and thus nonlocal) variables are always
+		     implicitly clobbered by calls.  */
+		  /* ???  ESCAPED can be empty even though NONLOCAL
+		     always escaped.  */
+		  pt->nonlocal = writes_global_memory;
+		  pt->escaped = writes_global_memory;
+		}
+	      else if (writes_global_memory)
+		{
+		  /* If there is nothing special about this call then
+		     we have made everything that is used also escape.  */
+		  *pt = cfun->gimple_df->escaped;
+		  pt->nonlocal = 1;
+		}
 	    }
 	}
     }
