diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
index 45b391a565e..72006251f29 100644
--- a/gcc/ipa-modref.c
+++ b/gcc/ipa-modref.c
@@ -2603,11 +2603,13 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
 }
 
 /* Analyze function F.  IPA indicates whether we're running in local mode
-   (false) or the IPA mode (true).  */
+   (false) or the IPA mode (true).
+   Return true if fixup cfg is needed after the pass.  */
 
-static void
+static bool
 analyze_function (function *f, bool ipa)
 {
+  bool fixup_cfg = false;
   if (dump_file)
     fprintf (dump_file, "modref analyzing '%s' (ipa=%i)%s%s\n",
 	     function_name (f), ipa,
@@ -2617,7 +2619,7 @@ analyze_function (function *f, bool ipa)
   /* Don't analyze this function if it's compiled with -fno-strict-aliasing.  */
   if (!flag_ipa_modref
       || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
-    return;
+    return false;
 
   /* Compute no-LTO summaries when local optimization is going to happen.  */
   bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
@@ -2774,12 +2776,32 @@ analyze_function (function *f, bool ipa)
 	      if (!summary->useful_p (ecf_flags, false))
 		{
 		  remove_summary (lto, nolto, ipa);
-		  return;
+		  return false;
 		}
 	    }
 	  first = false;
 	}
     }
+  if (summary && !summary->global_memory_written_p () && !summary->side_effects
+      && !finite_function_p ())
+    summary->side_effects = true;
+  if (summary_lto && !summary_lto->side_effects && !finite_function_p ())
+    summary_lto->side_effects = true;
+
+  if (!ipa && flag_ipa_pure_const)
+    {
+      if (!summary->stores->every_base && !summary->stores->bases)
+	{
+	  if (!summary->loads->every_base && !summary->loads->bases)
+	    fixup_cfg = ipa_make_function_const
+		   (cgraph_node::get (current_function_decl),
+		    summary->side_effects, true);
+	  else
+	    fixup_cfg = ipa_make_function_pure
+		   (cgraph_node::get (current_function_decl),
+		    summary->side_effects, true);
+	}
+    }
   if (summary && !summary->useful_p (ecf_flags))
     {
       if (!ipa)
@@ -2793,11 +2815,6 @@ analyze_function (function *f, bool ipa)
       summaries_lto->remove (fnode);
       summary_lto = NULL;
     }
-  if (summary && !summary->global_memory_written_p () && !summary->side_effects
-      && !finite_function_p ())
-    summary->side_effects = true;
-  if (summary_lto && !summary_lto->side_effects && !finite_function_p ())
-    summary_lto->side_effects = true;
 
   if (ipa && !summary && !summary_lto)
     remove_modref_edge_summaries (fnode);
@@ -2907,6 +2924,7 @@ analyze_function (function *f, bool ipa)
 	    }
 	}
     }
+  return fixup_cfg;
 }
 
 /* Callback for generate_summary.  */
@@ -3714,7 +3732,8 @@ public:
 
 unsigned int pass_modref::execute (function *f)
 {
-  analyze_function (f, false);
+  if (analyze_function (f, false))
+    return execute_fixup_cfg ();
   return 0;
 }
 
@@ -3749,9 +3768,7 @@ ignore_edge (struct cgraph_edge *e)
 
   return (avail <= AVAIL_INTERPOSABLE
 	  || ((!optimization_summaries || !optimization_summaries->get (callee))
-	      && (!summaries_lto || !summaries_lto->get (callee)))
-	  || flags_from_decl_or_type (e->callee->decl)
-	     & (ECF_CONST | ECF_NOVOPS));
+	      && (!summaries_lto || !summaries_lto->get (callee))));
 }
 
 /* Compute parm_map for CALLEE_EDGE.  */
@@ -4130,7 +4147,7 @@ remove_useless_summaries (cgraph_node *node,
 /* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
    and propagate loads/stores.  */
 
-static void
+static bool
 modref_propagate_in_scc (cgraph_node *component_node)
 {
   bool changed = true;
@@ -4352,6 +4369,38 @@ modref_propagate_in_scc (cgraph_node *component_node)
   if (dump_file)
     fprintf (dump_file,
 	     "Propagation finished in %i iterations\n", iteration);
+  bool pureconst = false;
+  for (struct cgraph_node *cur = component_node; cur;
+       cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
+    if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
+      {
+	modref_summary *summary = optimization_summaries
+				  ? optimization_summaries->get (cur)
+				  : NULL;
+	modref_summary_lto *summary_lto = summaries_lto
+					  ? summaries_lto->get (cur)
+					  : NULL;
+	if (summary && !summary->stores->every_base && !summary->stores->bases)
+	  {
+	    if (!summary->loads->every_base && !summary->loads->bases)
+	      pureconst |= ipa_make_function_const
+		     (cur, summary->side_effects, false);
+	    else
+	      pureconst |= ipa_make_function_pure
+		     (cur, summary->side_effects, false);
+	  }
+	if (summary_lto && !summary_lto->stores->every_base
+	    && !summary_lto->stores->bases)
+	  {
+	    if (!summary_lto->loads->every_base && !summary_lto->loads->bases)
+	      pureconst |= ipa_make_function_const
+		     (cur, summary_lto->side_effects, false);
+	    else
+	      pureconst |= ipa_make_function_pure
+		     (cur, summary_lto->side_effects, false);
+	  }
+     }
+  return pureconst;
 }
 
 /* Dump results of propagation in SCC rooted in COMPONENT_NODE.  */
@@ -4831,6 +4880,7 @@ pass_ipa_modref::execute (function *)
 {
   if (!summaries && !summaries_lto)
     return 0;
+  bool pureconst = false;
 
   if (optimization_summaries)
     ggc_delete (optimization_summaries);
@@ -4853,7 +4903,7 @@ pass_ipa_modref::execute (function *)
       if (dump_file)
 	fprintf (dump_file, "\n\nStart of SCC component\n");
 
-      modref_propagate_in_scc (component_node);
+      pureconst |= modref_propagate_in_scc (component_node);
       modref_propagate_flags_in_scc (component_node);
       if (dump_file)
 	modref_propagate_dump_scc (component_node);
@@ -4869,7 +4919,10 @@ pass_ipa_modref::execute (function *)
   fnspec_summaries = NULL;
   delete escape_summaries;
   escape_summaries = NULL;
-  return 0;
+
+  /* If we posibly made constructors const/pure we may need to remove
+     them.  */
+  return pureconst ? TODO_remove_functions : 0;
 }
 
 /* Summaries must stay alive until end of compilation.  */
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index 422b52fba4b..550bdeded16 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -275,7 +275,7 @@ warn_function_noreturn (tree decl)
   static hash_set<tree> *warned_about;
   if (!lang_hooks.missing_noreturn_ok_p (decl)
       && targetm.warn_func_return (decl))
-    warned_about 
+    warned_about
       = suggest_attribute (OPT_Wsuggest_attribute_noreturn, original_decl,
 			   true, warned_about, "noreturn");
 }
@@ -286,7 +286,7 @@ warn_function_cold (tree decl)
   tree original_decl = decl;
 
   static hash_set<tree> *warned_about;
-  warned_about 
+  warned_about
     = suggest_attribute (OPT_Wsuggest_attribute_cold, original_decl,
 			 true, warned_about, "cold");
 }
@@ -1428,6 +1428,105 @@ ignore_edge_for_pure_const (struct cgraph_edge *e)
 			  flag_ipa_pure_const));
 }
 
+/* Return true if function should be skipped for local pure const analysis.  */
+
+static bool
+skip_function_for_local_pure_const (struct cgraph_node *node)
+{
+  /* Because we do not schedule pass_fixup_cfg over whole program after early
+     optimizations we must not promote functions that are called by already
+     processed functions.  */
+
+  if (function_called_by_processed_nodes_p ())
+    {
+      if (dump_file)
+	fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
+      return true;
+    }
+  /* Save some work and do not analyze functions which are interposable and
+     do not have any non-interposable aliases.  */
+  if (node->get_availability () <= AVAIL_INTERPOSABLE
+      && !flag_lto
+      && !node->has_aliases_p ())
+    {
+      if (dump_file)
+	fprintf (dump_file,
+		 "Function is interposable; not analyzing.\n");
+      return true;
+    }
+  return false;
+}
+
+/* Make function const and output warning.  If LOCAL is true,
+   return true if anything changed.  Otherwise return true if
+   we may have introduced removale ctors.  */
+
+bool
+ipa_make_function_const (struct cgraph_node *node, bool looping, bool local)
+{
+  bool cdtor = false;
+
+  if (TREE_READONLY (node->decl)
+      && (looping || !DECL_LOOPING_CONST_OR_PURE_P (node->decl)))
+    return false;
+  warn_function_const (node->decl, !looping);
+  if (local && skip_function_for_local_pure_const (node))
+    return false;
+  if (dump_file)
+    fprintf (dump_file, "Function found to be %sconst: %s\n",
+	     looping ? "looping " : "",
+	     node->dump_name ());
+  if (!local)
+    cdtor = node->call_for_symbol_and_aliases (cdtor_p, NULL, true);
+  if (node->set_const_flag (true, looping))
+    {
+      if (dump_file)
+	fprintf (dump_file,
+		 "Declaration updated to be %sconst: %s\n",
+		 looping ? "looping " : "",
+		 node->dump_name ());
+      if (local)
+	return true;
+      return cdtor;
+    }
+  return false;
+}
+
+/* Make function const and output warning.  If LOCAL is true,
+   return true if anything changed.  Otherwise return true if
+   we may have introduced removale ctors.  */
+
+bool
+ipa_make_function_pure (struct cgraph_node *node, bool looping, bool local)
+{
+  bool cdtor = false;
+
+  if (DECL_PURE_P (node->decl)
+      && (looping || DECL_LOOPING_CONST_OR_PURE_P (node->decl)))
+    return false;
+  warn_function_pure (node->decl, !looping);
+  if (local && skip_function_for_local_pure_const (node))
+    return false;
+  if (dump_file)
+    fprintf (dump_file, "Function found to be %spure: %s\n",
+	     looping ? "looping " : "",
+	     node->dump_name ());
+  if (!local)
+    cdtor = node->call_for_symbol_and_aliases (cdtor_p, NULL, true);
+  if (node->set_pure_flag (true, looping))
+    {
+      if (dump_file)
+	fprintf (dump_file,
+		 "Declaration updated to be %spure: %s\n",
+		 looping ? "looping " : "",
+		 node->dump_name ());
+      if (local)
+	return true;
+      return cdtor;
+    }
+  return false;
+}
+
 /* Produce transitive closure over the callgraph and compute pure/const
    attributes.  */
 
@@ -1442,7 +1541,6 @@ propagate_pure_const (void)
   int i;
   struct ipa_dfs_info * w_info;
   bool remove_p = false;
-  bool has_cdtor;
 
   order_pos = ipa_reduced_postorder (order, true,
 				     ignore_edge_for_pure_const);
@@ -1513,6 +1611,9 @@ propagate_pure_const (void)
 	      enum pure_const_state_e edge_state = IPA_CONST;
 	      bool edge_looping = false;
 
+	      if (e->recursive_p ())
+		looping = true;
+
 	      if (e->recursive_p ())
 		looping = true;
 
@@ -1699,55 +1800,11 @@ propagate_pure_const (void)
 	    switch (this_state)
 	      {
 	      case IPA_CONST:
-		if (!TREE_READONLY (w->decl))
-		  {
-		    warn_function_const (w->decl, !this_looping);
-		    if (dump_file)
-		      fprintf (dump_file, "Function found to be %sconst: %s\n",
-			       this_looping ? "looping " : "",
-			       w->dump_name ());
-		  }
-		/* Turning constructor or destructor to non-looping const/pure
-		   enables us to possibly remove the function completely.  */
-		if (this_looping)
-		  has_cdtor = false;
-		else
-		  has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
-							      NULL, true);
-		if (w->set_const_flag (true, this_looping))
-		  {
-		    if (dump_file)
-		      fprintf (dump_file,
-			       "Declaration updated to be %sconst: %s\n",
-			       this_looping ? "looping " : "",
-			       w->dump_name ());
-		    remove_p |= has_cdtor;
-		  }
+		remove_p |= ipa_make_function_const (node, looping, false);
 		break;
 
 	      case IPA_PURE:
-		if (!DECL_PURE_P (w->decl))
-		  {
-		    warn_function_pure (w->decl, !this_looping);
-		    if (dump_file)
-		      fprintf (dump_file, "Function found to be %spure: %s\n",
-			       this_looping ? "looping " : "",
-			       w->dump_name ());
-		  }
-		if (this_looping)
-		  has_cdtor = false;
-		else
-		  has_cdtor = w->call_for_symbol_and_aliases (cdtor_p,
-							      NULL, true);
-		if (w->set_pure_flag (true, this_looping))
-		  {
-		    if (dump_file)
-		      fprintf (dump_file,
-			       "Declaration updated to be %spure: %s\n",
-			       this_looping ? "looping " : "",
-			       w->dump_name ());
-		    remove_p |= has_cdtor;
-		  }
+		remove_p |= ipa_make_function_pure (node, looping, false);
 		break;
 
 	      default:
@@ -2046,34 +2103,6 @@ make_pass_ipa_pure_const (gcc::context *ctxt)
   return new pass_ipa_pure_const (ctxt);
 }
 
-/* Return true if function should be skipped for local pure const analysis.  */
-
-static bool
-skip_function_for_local_pure_const (struct cgraph_node *node)
-{
-  /* Because we do not schedule pass_fixup_cfg over whole program after early
-     optimizations we must not promote functions that are called by already
-     processed functions.  */
-
-  if (function_called_by_processed_nodes_p ())
-    {
-      if (dump_file)
-        fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
-      return true;
-    }
-  /* Save some work and do not analyze functions which are interposable and
-     do not have any non-interposable aliases.  */
-  if (node->get_availability () <= AVAIL_INTERPOSABLE
-      && !node->has_aliases_p ())
-    {
-      if (dump_file)
-        fprintf (dump_file,
-		 "Function is interposable; not analyzing.\n");
-      return true;
-    }
-  return false;
-}
-
 /* Simple local pass for pure const discovery reusing the analysis from
    ipa_pure_const.   This pass is effective when executed together with
    other optimization passes in early optimization pass queue.  */
@@ -2144,55 +2173,13 @@ pass_local_pure_const::execute (function *fun)
   switch (l->pure_const_state)
     {
     case IPA_CONST:
-      if (!TREE_READONLY (current_function_decl))
-	{
-	  warn_function_const (current_function_decl, !l->looping);
-	  if (dump_file)
-	    fprintf (dump_file, "Function found to be %sconst: %s\n",
-		     l->looping ? "looping " : "",
-		     current_function_name ());
-	}
-      else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
-	       && !l->looping)
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Function found to be non-looping: %s\n",
-		     current_function_name ());
-	}
-      if (!skip && node->set_const_flag (true, l->looping))
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Declaration updated to be %sconst: %s\n",
-		     l->looping ? "looping " : "",
-		     current_function_name ());
-	  changed = true;
-	}
+      changed |= ipa_make_function_const
+		   (cgraph_node::get (current_function_decl), l->looping, true);
       break;
 
     case IPA_PURE:
-      if (!DECL_PURE_P (current_function_decl))
-	{
-	  warn_function_pure (current_function_decl, !l->looping);
-	  if (dump_file)
-	    fprintf (dump_file, "Function found to be %spure: %s\n",
-		     l->looping ? "looping " : "",
-		     current_function_name ());
-	}
-      else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
-	       && !l->looping)
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Function found to be non-looping: %s\n",
-		     current_function_name ());
-	}
-      if (!skip && node->set_pure_flag (true, l->looping))
-	{
-	  if (dump_file)
-	    fprintf (dump_file, "Declaration updated to be %spure: %s\n",
-		     l->looping ? "looping " : "",
-		     current_function_name ());
-	  changed = true;
-	}
+      changed |= ipa_make_function_pure
+		   (cgraph_node::get (current_function_decl), l->looping, true);
       break;
 
     default:
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index 824780f562a..e2440a1f893 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -50,6 +50,8 @@ bool recursive_call_p (tree, tree);
 /* In ipa-pure-const.c  */
 bool finite_function_p ();
 bool builtin_safe_for_const_function_p (bool *, tree);
+bool ipa_make_function_const (cgraph_node *, bool, bool);
+bool ipa_make_function_pure (cgraph_node *, bool, bool);
 
 /* In ipa-profile.c  */
 bool ipa_propagate_frequency (struct cgraph_node *node);
diff --git a/gcc/passes.def b/gcc/passes.def
index 56dab80a029..b583d17c86f 100644
--- a/gcc/passes.def
+++ b/gcc/passes.def
@@ -92,13 +92,13 @@ along with GCC; see the file COPYING3.  If not see
           NEXT_PASS (pass_dse);
 	  NEXT_PASS (pass_cd_dce, false /* update_address_taken_p */);
 	  NEXT_PASS (pass_phiopt, true /* early_p */);
-	  NEXT_PASS (pass_modref);
 	  NEXT_PASS (pass_tail_recursion);
 	  NEXT_PASS (pass_if_to_switch);
 	  NEXT_PASS (pass_convert_switch);
 	  NEXT_PASS (pass_cleanup_eh);
 	  NEXT_PASS (pass_profile);
 	  NEXT_PASS (pass_local_pure_const);
+	  NEXT_PASS (pass_modref);
 	  /* Split functions creates parts that are not run through
 	     early optimizations again.  It is thus good idea to do this
 	      late.  */
diff --git a/gcc/testsuite/c-c++-common/tm/inline-asm.c b/gcc/testsuite/c-c++-common/tm/inline-asm.c
index 73892601897..176266893e9 100644
--- a/gcc/testsuite/c-c++-common/tm/inline-asm.c
+++ b/gcc/testsuite/c-c++-common/tm/inline-asm.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fgnu-tm -O1" } */
+/* { dg-options "-fgnu-tm -O1 -fno-ipa-modref -fno-ipa-pure-const" } */
 
 static inline void
 inline_death ()
diff --git a/gcc/testsuite/g++.dg/ipa/modref-1.C b/gcc/testsuite/g++.dg/ipa/modref-1.C
index c57aaca0230..b49238162fe 100644
--- a/gcc/testsuite/g++.dg/ipa/modref-1.C
+++ b/gcc/testsuite/g++.dg/ipa/modref-1.C
@@ -30,6 +30,6 @@ int main()
 		linker_error ();
 	return 0;
 }
-/* { dg-final { scan-tree-dump "Function found to be const: {anonymous}::B::genB" "local-pure-const1"  } } */
-/* { dg-final { scan-tree-dump "Retslot flags: no_indirect_clobber no_direct_escape no_indirect_escape not_returned_directly not_returned_indirectly no_direct_read no_indirect_read" "modref1" } } */
+/* { dg-final { scan-tree-dump "Function found to be const: static {anonymous}::B {anonymous}::B::genB" "local-pure-const1"  } } */
+/* { dg-final { scan-tree-dump "Retslot flags: not_returned_directly" "modref1" } } */
   
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
index cafb4f34894..10ebe1ff474 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-11.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-modref1"  } */
+/* { dg-options "-O2 -fdump-tree-modref1 -fno-ipa-pure-const"  } */
 struct linkedlist {
   struct linkedlist *next;
 };
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-14.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-14.c
new file mode 100644
index 00000000000..230fafba839
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-14.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+struct a {int a,b,c;};
+__attribute__ ((noinline))
+int init (struct a *a)
+{
+  a->a=1;
+  a->b=2;
+  a->c=3;
+}
+int const_fn () /* { dg-warning "function might be a candidate for attribute .const" } */
+{
+  struct a a;
+  init (&a);
+  return a.a + a.b + a.c;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-8.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-8.c
index 15ae4acc03f..4a18e34cd16 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/modref-8.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-8.c
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 --param modref-max-adjustments=8 -fdump-tree-modref1"  } */
+/* { dg-options "-O2 --param modref-max-adjustments=8 -fdump-tree-modref1 -fno-optimize-sibling-calls"  } */
 /* { dg-do compile } */
 void
 set (char *p)
diff --git a/gcc/testsuite/gfortran.dg/do_subscript_3.f90 b/gcc/testsuite/gfortran.dg/do_subscript_3.f90
index 2f62f58142b..8f7183eb9b6 100644
--- a/gcc/testsuite/gfortran.dg/do_subscript_3.f90
+++ b/gcc/testsuite/gfortran.dg/do_subscript_3.f90
@@ -1,4 +1,5 @@
 ! { dg-do compile }
+! { dg-options "-O0" }
 ! PR fortran/91424
 ! Check that only one warning is issued inside blocks, and that
 ! warnings are also issued for contained subroutines.
