This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[pretty-ipa] pure-const improvements, finite loop removal in CD-DCE and pure/const warning


Hi,
this patch imrpves pure-const discovery so it attempts to prove finiteness of
loop.  I added finite_loop_p prepdicate for this reason and updated empty loop
removal to use it.  It is based on iteration code, just bit simpler than the
code trying to bound number of iterations.  It is now bit smarter and it also
makes assumption that loops in pure/const functions are finite.  Doing this
helps analysis on tramp3d quite a bit.

I also made cd-dce to remove probably finite loops and added the warning on
missing nothrow/const/pure markers.  It seems that we can prove finitarity of
most of loops in libstdc++ with exception of stuff like RB tree walking that is
not obviously finite in any way.

Bootstrapped/regtested x86_64-linux, comitting to pretty-ipa so we can see how
much effect the extra calls to SCEV have on compile time.

	* tree-ssa-loop-niter.c (finite_loop_p): New function.
	* cfgloopanal.c (irred_loop_found): New static var.
	(check_irred): set it.
	(mark_irreducible_loops): Return true if found.
	* toplev.h (warn_function_nothrow): New function.
	* cp/decl.c (finish_function): Use it.
	* ipa-pure.const.c: Include toplev.h, flags.h, pointer-set.h, cfgloop.h
	and tree-scalar-evolution.h
	(struct funct_state_d): Add looping_in_source.
	(function_always_visible_to_compiler_p): New predicate.
	(warn_function_nothrow, warn_function_pure, warn_function_const): New
	functions.
	(check_call): More verbose debug output.
	(analyze_function): Do not bail out for overwrittable functions; try
	to prove finiteness of the loops; handle looping_in_source.
	(propagate): Hande looping in source; output warnings.
	(skip_function_for_local_pure_const): New function.
	(local_pure_const): Analyze overwrittable function body when asked for warnings;
	handle looping_in_source.
	* tree-ssa-loop-ivcanon.c (empty_loop_p): Use finite_loop_p predicate.
	* except.c (set_nothrow_function_flags): Warn.
	* common.opt (Wmissing-const, Wmissing-nothrow, Wmissing-pure): New.
	* tree-ssa-dce.c (find_obviously_necessary_stmts): Try to prove finiteness
	of loop.
	(perform_tree_ssa_dce): Initialize loop optimizer if needed.
	* cfgloop.h (mark_irreducible_loops): Declare.
	(finite_loop_p): Declare.
Index: tree-ssa-loop-niter.c
===================================================================
--- tree-ssa-loop-niter.c	(revision 146576)
+++ tree-ssa-loop-niter.c	(working copy)
@@ -1953,6 +1953,50 @@ find_loop_niter (struct loop *loop, edge
   return niter ? niter : chrec_dont_know;
 }
 
+/* Return true if loop is known to be finite.  */
+bool
+finite_loop_p (struct loop *loop)
+{
+  unsigned i;
+  VEC (edge, heap) *exits = get_loop_exit_edges (loop);
+  edge ex;
+  struct tree_niter_desc desc;
+  bool finite = false;
+
+  if (flag_unsafe_loop_optimizations)
+    return true;
+  if ((TREE_READONLY (current_function_decl)
+       || DECL_PURE_P (current_function_decl))
+      && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl))
+    {
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	fprintf (dump_file, "Found loop %i to be finite: it is within pure or const function.\n",
+		 loop->num);
+      return true;
+    }
+   
+  exits = get_loop_exit_edges (loop);
+  for (i = 0; VEC_iterate (edge, exits, i, ex); i++)
+    {
+      if (!just_once_each_iteration_p (loop, ex->src))
+	continue;
+
+      if (number_of_iterations_exit (loop, ex, &desc, false))
+        {
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    {
+	      fprintf (dump_file, "Found loop %i to be finite: iterating ", loop->num);
+	      print_generic_expr (dump_file, desc.niter, TDF_SLIM);
+	      fprintf (dump_file, " times\n");
+	    }
+	  finite = true;
+	  break;
+	}
+    }
+  VEC_free (edge, heap, exits);
+  return finite;
+}
+
 /*
 
    Analysis of a number of iterations of a loop by a brute-force evaluation.
Index: cfgloopanal.c
===================================================================
--- cfgloopanal.c	(revision 146576)
+++ cfgloopanal.c	(working copy)
@@ -52,6 +52,8 @@ just_once_each_iteration_p (const struct
   return true;
 }
 
+static bool irred_loop_found;
+
 /* Marks the edge E in graph G irreducible if it connects two vertices in the
    same scc.  */
 
@@ -68,6 +70,7 @@ check_irred (struct graph *g, struct gra
     return;
 
   real->flags |= EDGE_IRREDUCIBLE_LOOP;
+  irred_loop_found = true;
   if (flow_bb_inside_loop_p (real->src->loop_father, real->dest))
     real->src->flags |= BB_IRREDUCIBLE_LOOP;
 }
@@ -84,7 +87,7 @@ check_irred (struct graph *g, struct gra
 #define LOOP_REPR(LOOP) ((LOOP)->num + last_basic_block)
 #define BB_REPR(BB) ((BB)->index + 1)
 
-void
+bool
 mark_irreducible_loops (void)
 {
   basic_block act;
@@ -153,12 +156,14 @@ mark_irreducible_loops (void)
   /* Find the strongly connected components.  */
   graphds_scc (g, NULL);
 
+  irred_loop_found = false;
   /* Mark the irreducible loops.  */
   for_each_edge (g, check_irred);
 
   free_graph (g);
 
   loops_state_set (LOOPS_HAVE_MARKED_IRREDUCIBLE_REGIONS);
+  return irred_loop_found;
 }
 
 /* Counts number of insns inside LOOP.  */
Index: toplev.h
===================================================================
--- toplev.h	(revision 146576)
+++ toplev.h	(working copy)
@@ -210,4 +210,6 @@ extern bool set_src_pwd		       (const c
 extern const char *get_random_seed (bool);
 extern const char *set_random_seed (const char *);
 
+extern void warn_function_nothrow (tree);
+
 #endif /* ! GCC_TOPLEV_H */
Index: cp/decl.c
===================================================================
--- cp/decl.c	(revision 146576)
+++ cp/decl.c	(working copy)
@@ -12254,7 +12254,10 @@ finish_function (int flags)
       && !cp_function_chain->can_throw
       && !flag_non_call_exceptions
       && !DECL_REPLACEABLE_P (fndecl))
-    TREE_NOTHROW (fndecl) = 1;
+    {
+      TREE_NOTHROW (fndecl) = 1;
+      warn_function_nothrow (fndecl);
+    }
 
   /* This must come after expand_function_end because cleanups might
      have declarations (from inline functions) that need to go into
Index: ipa-pure-const.c
===================================================================
--- ipa-pure-const.c	(revision 146576)
+++ ipa-pure-const.c	(working copy)
@@ -52,6 +52,11 @@ along with GCC; see the file COPYING3.  
 #include "diagnostic.h"
 #include "langhooks.h"
 #include "target.h"
+#include "toplev.h"
+#include "flags.h"
+#include "pointer-set.h"
+#include "cfgloop.h"
+#include "tree-scalar-evolution.h"
 
 static struct pointer_set_t *visited_nodes;
 
@@ -73,6 +78,7 @@ struct funct_state_d 
   enum pure_const_state_e pure_const_state;
   /* What user set here; we can be always sure about this.  */
   enum pure_const_state_e state_set_in_source; 
+  bool looping_in_source; 
 
   /* True if the function could possibly infinite loop.  There are a
      lot of ways that this could be determined.  We are pretty
@@ -102,6 +108,76 @@ static struct cgraph_node_hook_list *fun
 static struct cgraph_2node_hook_list *node_duplication_hook_holder;
 static struct cgraph_node_hook_list *node_removal_hook_holder;
 
+/* Try to guess if function body will always be visible to compiler
+   when compiling the call and whether compiler will be able
+   to propagate the information by itself.  */
+
+static bool
+function_always_visible_to_compiler_p (tree decl)
+{
+  if (!TREE_PUBLIC (decl)
+      || DECL_DECLARED_INLINE_P (decl))
+    return true;
+  return false;
+}
+
+void
+warn_function_nothrow (tree decl)
+{
+  static struct pointer_set_t *warned_about;
+
+  if (!warn_missing_nothrow || TREE_THIS_VOLATILE (decl))
+    return;
+  if (function_always_visible_to_compiler_p (decl))
+    return;
+  
+  if (!warned_about)
+    warned_about = pointer_set_create ();
+  if (pointer_set_contains (warned_about, decl))
+    return;
+  pointer_set_insert (warned_about, decl);
+  warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+           "for attribute %<nothrow%> or %<throw ()%> marker in C++ code.",
+	   decl);
+}
+
+static void
+warn_function_pure (tree decl, bool known_finite)
+{
+  if (!warn_missing_pure || TREE_THIS_VOLATILE (decl))
+    return;
+  if (!known_finite)
+    {
+      warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+               "for attribute %<pure%> if it is known to be finite.",
+	       decl);
+      return;
+    }
+  if (function_always_visible_to_compiler_p (decl))
+    return;
+  warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+           "for attribute %<pure%>.",
+	   decl);
+}
+
+static void
+warn_function_const (tree decl, bool known_finite)
+{
+  if (!warn_missing_const || TREE_THIS_VOLATILE (decl))
+    return;
+  if (!known_finite)
+    {
+      warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+               "for attribute %<const%> if it is known to be finite.",
+	       decl);
+      return;
+    }
+  if (function_always_visible_to_compiler_p (decl))
+    return;
+  warning (OPT_Wmissing_noreturn, "%Jfunction might be possible candidate "
+           "for attribute %<const%>.",
+	   decl);
+}
 /* Init the function state.  */
 
 static void
@@ -316,7 +392,11 @@ check_call (funct_state local, gimple ca
 
   /* When not in IPA mode, we can still handle self recursion.  */
   if (!ipa && callee_t == current_function_decl)
-    local->looping = true;
+    {
+      if (dump_file)
+        fprintf (dump_file, "    Recursive call can loop.\n");
+      local->looping = true;
+    }
   /* The callee is either unknown (indirect call) or there is just no
      scannable code for it (external call) .  We look to see if there
      are any bits available for the callee (such as by declaration or
@@ -345,12 +425,20 @@ check_call (funct_state local, gimple ca
       if (flags & ECF_CONST) 
 	{
           if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
-            local->looping = true;
+	    {
+	      if (dump_file)
+		fprintf (dump_file, "    calls looping pure.\n");
+              local->looping = true;
+	    }
 	 }
       else if (flags & ECF_PURE) 
 	{
           if (callee_t && DECL_LOOPING_CONST_OR_PURE_P (callee_t))
-            local->looping = true;
+	    {
+	      if (dump_file)
+		fprintf (dump_file, "    calls looping const.\n");
+              local->looping = true;
+	    }
 	  if (dump_file)
 	    fprintf (dump_file, "    pure function call in not const\n");
 	  if (local->pure_const_state == IPA_CONST)
@@ -476,16 +564,10 @@ analyze_function (struct cgraph_node *fn
   funct_state l;
   basic_block this_block;
 
-  if (cgraph_function_body_availability (fn) <= AVAIL_OVERWRITABLE)
-    {
-      if (dump_file)
-        fprintf (dump_file, "Function is not available or overwrittable; not analyzing.\n");
-      return NULL;
-    }
-
   l = XCNEW (struct funct_state_d);
   l->pure_const_state = IPA_CONST;
   l->state_set_in_source = IPA_NEITHER;
+  l->looping_in_source = true;
   l->looping = false;
   l->can_throw = false;
 
@@ -521,8 +603,33 @@ end:
 	 indication of possible infinite loop side
 	 effect.  */
       if (mark_dfs_back_edges ())
-	l->looping = true;
-      
+        {
+	  loop_optimizer_init (LOOPS_HAVE_PREHEADERS);
+	  if (dump_file && (dump_flags & TDF_DETAILS))
+	    flow_loops_dump (dump_file, NULL, 0);
+	  if (mark_irreducible_loops ())
+	    {
+	      if (dump_file)
+	        fprintf (dump_file, "    has irreducible loops\n");
+	      l->looping = true;
+	    }
+	  else 
+	    {
+	      loop_iterator li;
+	      struct loop *loop;
+	      scev_initialize ();
+	      FOR_EACH_LOOP (li, loop, 0)
+		if (!finite_loop_p (loop))
+		  {
+		    if (dump_file)
+		      fprintf (dump_file, "    can not prove finiteness of loop %i\n", loop->num);
+		    l->looping =true;
+		    break;
+		  }
+	      scev_finalize ();
+	    }
+          loop_optimizer_finalize ();
+	}
     }
 
   if (TREE_READONLY (decl))
@@ -530,7 +637,7 @@ end:
       l->pure_const_state = IPA_CONST;
       l->state_set_in_source = IPA_CONST;
       if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
-        l->looping = false;
+        l->looping = false, l->looping_in_source = false;
     }
   if (DECL_PURE_P (decl))
     {
@@ -538,7 +645,7 @@ end:
         l->pure_const_state = IPA_PURE;
       l->state_set_in_source = IPA_PURE;
       if (!DECL_LOOPING_CONST_OR_PURE_P (decl))
-        l->looping = false;
+        l->looping = false, l->looping_in_source = false;
     }
   if (TREE_NOTHROW (decl))
     l->can_throw = false;
@@ -570,7 +677,8 @@ add_new_function (struct cgraph_node *no
      since all we would be interested in are the addressof
      operations.  */
   visited_nodes = pointer_set_create ();
-  set_function_state (node, analyze_function (node, true));
+  if (cgraph_function_body_availability (node) > AVAIL_OVERWRITABLE)
+    set_function_state (node, analyze_function (node, true));
   pointer_set_destroy (visited_nodes);
   visited_nodes = NULL;
 }
@@ -728,12 +836,11 @@ propagate (void)
 	  enum pure_const_state_e this_state = pure_const_state;
 	  bool this_looping = looping;
 
-	  if (w_l->state_set_in_source != IPA_NEITHER)
-	    {
-	      if (this_state > w_l->state_set_in_source)
-	        this_state = w_l->state_set_in_source;
-	      this_looping = false;
-	    }
+	  if (w_l->state_set_in_source != IPA_NEITHER
+	      && this_state > w_l->state_set_in_source)
+            this_state = w_l->state_set_in_source;
+	  if (!w_l->looping_in_source)
+	    this_looping = false;
 
 	  /* All nodes within a cycle share the same info.  */
 	  w_l->pure_const_state = this_state;
@@ -742,19 +849,27 @@ propagate (void)
 	  switch (this_state)
 	    {
 	    case IPA_CONST:
-	      if (!TREE_READONLY (w->decl) && dump_file)
-		fprintf (dump_file, "Function found to be %sconst: %s\n",  
-			 this_looping ? "looping " : "",
-			 cgraph_node_name (w)); 
+	      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 " : "",
+			     cgraph_node_name (w)); 
+		}
 	      TREE_READONLY (w->decl) = 1;
 	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
 	      break;
 	      
 	    case IPA_PURE:
-	      if (!DECL_PURE_P (w->decl) && dump_file)
-		fprintf (dump_file, "Function found to be %spure: %s\n",  
-			 this_looping ? "looping " : "",
-			 cgraph_node_name (w)); 
+	      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 " : "",
+			     cgraph_node_name (w)); 
+		}
 	      DECL_PURE_P (w->decl) = 1;
 	      DECL_LOOPING_CONST_OR_PURE_P (w->decl) = this_looping;
 	      break;
@@ -835,6 +950,7 @@ propagate (void)
 	    {
 	      struct cgraph_edge *e;
 	      TREE_NOTHROW (w->decl) = true;
+	      warn_function_nothrow (w->decl);
 	      for (e = w->callers; e; e = e->next_caller)
 	        e->can_throw_external = false;
 	      if (dump_file)
@@ -902,16 +1018,11 @@ struct ipa_opt_pass pass_ipa_pure_const 
  NULL					/* variable_transform */
 };
 
-/* 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.  */
+/* Return true if function should be skipped for local pure const analysis.  */
 
-static unsigned int
-local_pure_const (void)
+static bool
+skip_function_for_local_pure_const (void)
 {
-  bool changed = false;
-  funct_state l;
-
   /* 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.  */
 
@@ -919,25 +1030,47 @@ local_pure_const (void)
     {
       if (dump_file)
         fprintf (dump_file, "Function called in recursive cycle; ignoring\n");
-      return 0;
+      return true;
     }
-
-  l = analyze_function (cgraph_node (current_function_decl), false);
-  if (!l)
+  if (cgraph_function_body_availability (cgraph_node (current_function_decl))
+      <= AVAIL_OVERWRITABLE)
     {
       if (dump_file)
-        fprintf (dump_file, "Function has wrong visibility; ignoring\n");
-      return 0;
+        fprintf (dump_file, "Function is not available or overwrittable; 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.  */
+
+static unsigned int
+local_pure_const (void)
+{
+  bool changed = false;
+  funct_state l;
+  bool skip;
+
+  skip = skip_function_for_local_pure_const ();
+  if (!warn_missing_const && !warn_missing_nothrow && !warn_missing_pure
+      && skip)
+    return 0;
+  l = analyze_function (cgraph_node (current_function_decl), false);
 
   switch (l->pure_const_state)
     {
     case IPA_CONST:
       if (!TREE_READONLY (current_function_decl))
 	{
-	  TREE_READONLY (current_function_decl) = 1;
-	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
-	  changed = true;
+	  warn_function_const (current_function_decl, !l->looping);
+	  if (!skip)
+	    {
+	      TREE_READONLY (current_function_decl) = 1;
+	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
+	      changed = true;
+	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be %sconst: %s\n",
 		     l->looping ? "looping " : "",
@@ -947,8 +1080,11 @@ local_pure_const (void)
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
 	       && !l->looping)
 	{
-	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
-	  changed = true;
+	  if (!skip)
+	    {
+	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
+	      changed = true;
+	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be non-looping: %s\n",
 		     lang_hooks.decl_printable_name (current_function_decl,
@@ -959,9 +1095,13 @@ local_pure_const (void)
     case IPA_PURE:
       if (!TREE_READONLY (current_function_decl))
 	{
-	  DECL_PURE_P (current_function_decl) = 1;
-	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
-	  changed = true;
+	  if (!skip)
+	    {
+	      DECL_PURE_P (current_function_decl) = 1;
+	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = l->looping;
+	      changed = true;
+	    }
+	  warn_function_pure (current_function_decl, !l->looping);
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be %spure: %s\n",
 		     l->looping ? "looping " : "",
@@ -971,8 +1111,11 @@ local_pure_const (void)
       else if (DECL_LOOPING_CONST_OR_PURE_P (current_function_decl)
 	       && !l->looping)
 	{
-	  DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
-	  changed = true;
+	  if (!skip)
+	    {
+	      DECL_LOOPING_CONST_OR_PURE_P (current_function_decl) = false;
+	      changed = true;
+	    }
 	  if (dump_file)
 	    fprintf (dump_file, "Function found to be non-looping: %s\n",
 		     lang_hooks.decl_printable_name (current_function_decl,
@@ -985,13 +1128,16 @@ local_pure_const (void)
     }
   if (!l->can_throw && !TREE_NOTHROW (current_function_decl))
     {
-      struct cgraph_edge *e;
-
-      TREE_NOTHROW (current_function_decl) = true;
-      for (e = cgraph_node (current_function_decl)->callers;
-           e; e = e->next_caller)
-	e->can_throw_external = false;
-      changed = true;
+      warn_function_nothrow (current_function_decl);
+      if (!skip)
+	{
+	  struct cgraph_edge *e;
+	  TREE_NOTHROW (current_function_decl) = true;
+	  for (e = cgraph_node (current_function_decl)->callers;
+	       e; e = e->next_caller)
+	    e->can_throw_external = false;
+	  changed = true;
+	}
       if (dump_file)
 	fprintf (dump_file, "Function found to be nothrow: %s\n",
 		 lang_hooks.decl_printable_name (current_function_decl,
Index: tree-ssa-loop-ivcanon.c
===================================================================
--- tree-ssa-loop-ivcanon.c	(revision 146576)
+++ tree-ssa-loop-ivcanon.c	(working copy)
@@ -395,7 +395,6 @@ static bool
 empty_loop_p (struct loop *loop)
 {
   edge exit;
-  struct tree_niter_desc niter;
   basic_block *body;
   gimple_stmt_iterator gsi;
   unsigned i;
@@ -408,7 +407,7 @@ empty_loop_p (struct loop *loop)
     return false;
 
   /* The loop must be finite.  */
-  if (!number_of_iterations_exit (loop, exit, &niter, false))
+  if (!finite_loop_p (loop))
     return false;
 
   /* Values of all loop exit phi nodes must be invariants.  */
Index: except.c
===================================================================
--- except.c	(revision 146576)
+++ except.c	(working copy)
@@ -2823,6 +2823,8 @@ set_nothrow_function_flags (void)
 	    return 0;
 	  }
       }
+  if (crtl->nothrow)
+    warn_function_nothrow (current_function_decl);
   if (crtl->nothrow
       && (cgraph_function_body_availability (cgraph_node
 					     (current_function_decl))
Index: common.opt
===================================================================
--- common.opt	(revision 146576)
+++ common.opt	(working copy)
@@ -132,10 +132,22 @@ Wunsafe-loop-optimizations
 Common Var(warn_unsafe_loop_optimizations) Warning
 Warn if the loop cannot be optimized due to nontrivial assumptions.
 
+Wmissing-const
+Common Var(warn_missing_const) Warning
+Warn about functions which might be candidates for __attribute__((const))
+
+Wmissing-nothrow
+Common Var(warn_missing_nothrow) Warning
+Warn about functions which might be candidates for __attribute__((nothrow))
+
 Wmissing-noreturn
 Common Var(warn_missing_noreturn) Warning
 Warn about functions which might be candidates for __attribute__((noreturn))
 
+Wmissing-pure
+Common Var(warn_missing_pure) Warning
+Warn about functions which might be candidates for __attribute__((pure))
+
 Wmudflap
 Common Var(warn_mudflap) Init(1) Warning
 Warn about constructs not instrumented by -fmudflap
Index: tree-ssa-dce.c
===================================================================
--- tree-ssa-dce.c	(revision 146576)
+++ tree-ssa-dce.c	(working copy)
@@ -427,17 +427,42 @@ find_obviously_necessary_stmts (struct e
 	}
     }
 
+  /* Pure and const functions are finite and thus have no infinite loops in
+     them.  */
+  if ((TREE_READONLY (current_function_decl)
+       || DECL_PURE_P (current_function_decl))
+      && !DECL_LOOPING_CONST_OR_PURE_P (current_function_decl))
+    return;
+
+  /* Prevent the empty possibly infinite loops from being removed.  */
   if (el)
     {
-      /* Prevent the loops from being removed.  We must keep the infinite loops,
-	 and we currently do not have a means to recognize the finite ones.  */
-      FOR_EACH_BB (bb)
-	{
-	  edge_iterator ei;
-	  FOR_EACH_EDGE (e, ei, bb->succs)
-	    if (e->flags & EDGE_DFS_BACK)
-	      mark_control_dependent_edges_necessary (e->dest, el);
-	}
+      loop_iterator li;
+      struct loop *loop;
+      scev_initialize ();
+      if (mark_irreducible_loops ())
+	FOR_EACH_BB (bb)
+	  {
+	    edge_iterator ei;
+	    FOR_EACH_EDGE (e, ei, bb->succs)
+	      if ((e->flags & EDGE_DFS_BACK)
+		  && (e->flags & EDGE_IRREDUCIBLE_LOOP))
+		{
+	          if (dump_file)
+	            fprintf (dump_file, "Marking back edge of irreducible loop %i->%i\n",
+		    	     e->src->index, e->dest->index);
+		  mark_control_dependent_edges_necessary (e->dest, el);
+		}
+	  }
+
+      FOR_EACH_LOOP (li, loop, 0)
+	if (!finite_loop_p (loop))
+	  {
+	    if (dump_file)
+	      fprintf (dump_file, "can not prove finiteness of loop %i\n", loop->num);
+	    mark_control_dependent_edges_necessary (loop->latch, el);
+	  }
+      scev_finalize ();
     }
 }
 
@@ -1099,6 +1124,9 @@ perform_tree_ssa_dce (bool aggressive)
   struct edge_list *el = NULL;
   bool something_changed = 0;
 
+  if (aggressive)
+    loop_optimizer_init (LOOPS_HAVE_PREHEADERS);
+
   tree_dce_init (aggressive);
 
   if (aggressive)
@@ -1118,6 +1146,9 @@ perform_tree_ssa_dce (bool aggressive)
 
   find_obviously_necessary_stmts (el);
 
+  if (aggressive)
+    loop_optimizer_finalize ();
+
   longest_chain = 0;
   total_chain = 0;
   chain_ovfl = false;
Index: cfgloop.h
===================================================================
--- cfgloop.h	(revision 146576)
+++ cfgloop.h	(working copy)
@@ -210,7 +210,7 @@ struct loop *alloc_loop (void);
 extern void flow_loop_free (struct loop *);
 int flow_loop_nodes_find (basic_block, struct loop *);
 void fix_loop_structure (bitmap changed_bbs);
-void mark_irreducible_loops (void);
+bool mark_irreducible_loops (void);
 void release_recorded_exits (void);
 void record_loop_exits (void);
 void rescan_loop_exit (edge, bool, bool);
@@ -645,5 +645,6 @@ enum
 extern void unroll_and_peel_loops (int);
 extern void doloop_optimize_loops (void);
 extern void move_loop_invariants (void);
+extern bool finite_loop_p (struct loop *);
 
 #endif /* GCC_CFGLOOP_H */


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]