diff gcc/ipa-pure-const.c @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
line wrap: on
line diff
--- a/gcc/ipa-pure-const.c	Thu Oct 25 07:37:49 2018 +0900
+++ b/gcc/ipa-pure-const.c	Thu Feb 13 11:34:05 2020 +0900
@@ -1,5 +1,5 @@
 /* Callgraph based analysis of static variables.
-   Copyright (C) 2004-2018 Free Software Foundation, Inc.
+   Copyright (C) 2004-2020 Free Software Foundation, Inc.
    Contributed by Kenneth Zadeck <zadeck@naturalbridge.com>
 
 This file is part of GCC.
@@ -122,17 +122,18 @@
   enum malloc_state_e malloc_state;
 };
 
-typedef struct funct_state_d * funct_state;
+typedef class funct_state_d * funct_state;
 
 /* The storage of the funct_state is abstracted because there is the
    possibility that it may be desirable to move this to the cgraph
    local info.  */
 
-class funct_state_summary_t: public function_summary <funct_state_d *>
+class funct_state_summary_t:
+  public fast_function_summary <funct_state_d *, va_heap>
 {
 public:
   funct_state_summary_t (symbol_table *symtab):
-    function_summary <funct_state_d *> (symtab) {}
+    fast_function_summary <funct_state_d *, va_heap> (symtab) {}
 
   virtual void insert (cgraph_node *, funct_state_d *state);
   virtual void duplicate (cgraph_node *src_node, cgraph_node *dst_node,
@@ -198,7 +199,7 @@
 		   hash_set<tree> *warned_about,
 		   const char * attrib_name)
 {
-  if (!option_enabled (option, &global_options))
+  if (!option_enabled (option, lang_hooks.option_lang_mask (), &global_options))
     return warned_about;
   if (TREE_THIS_VOLATILE (decl)
       || (known_finite && function_always_visible_to_compiler_p (decl)))
@@ -339,7 +340,7 @@
   if (DECL_EXTERNAL (t) || TREE_PUBLIC (t))
     {
       /* Readonly reads are safe.  */
-      if (TREE_READONLY (t) && !TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (t)))
+      if (TREE_READONLY (t))
 	return; /* Read of a constant, do not change the function state.  */
       else
 	{
@@ -499,7 +500,7 @@
     {
       if (dump_file && (dump_flags & TDF_DETAILS))
 	fprintf (dump_file, "Dropping state to PURE because call to %s may not "
-		 "bind to current def.\n", to->name ());
+		 "bind to current def.\n", to->dump_name ());
       state2 = IPA_PURE;
     }
   *state = MAX (*state, state2);
@@ -510,35 +511,34 @@
    but function using them is.  */
 static bool
 special_builtin_state (enum pure_const_state_e *state, bool *looping,
-			tree callee)
+		       tree callee)
 {
   if (DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
     switch (DECL_FUNCTION_CODE (callee))
       {
-	case BUILT_IN_RETURN:
-	case BUILT_IN_UNREACHABLE:
-	CASE_BUILT_IN_ALLOCA:
-	case BUILT_IN_STACK_SAVE:
-	case BUILT_IN_STACK_RESTORE:
-	case BUILT_IN_EH_POINTER:
-	case BUILT_IN_EH_FILTER:
-	case BUILT_IN_UNWIND_RESUME:
-	case BUILT_IN_CXA_END_CLEANUP:
-	case BUILT_IN_EH_COPY_VALUES:
-	case BUILT_IN_FRAME_ADDRESS:
-	case BUILT_IN_APPLY:
-	case BUILT_IN_APPLY_ARGS:
-	case BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT:
-	case BUILT_IN_ASAN_AFTER_DYNAMIC_INIT:
-	  *looping = false;
-	  *state = IPA_CONST;
-	  return true;
-	case BUILT_IN_PREFETCH:
-	  *looping = true;
-	  *state = IPA_CONST;
-	  return true;
-	default:
-	  break;
+      case BUILT_IN_RETURN:
+      case BUILT_IN_UNREACHABLE:
+      CASE_BUILT_IN_ALLOCA:
+      case BUILT_IN_STACK_SAVE:
+      case BUILT_IN_STACK_RESTORE:
+      case BUILT_IN_EH_POINTER:
+      case BUILT_IN_EH_FILTER:
+      case BUILT_IN_UNWIND_RESUME:
+      case BUILT_IN_CXA_END_CLEANUP:
+      case BUILT_IN_EH_COPY_VALUES:
+      case BUILT_IN_FRAME_ADDRESS:
+      case BUILT_IN_APPLY_ARGS:
+      case BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT:
+      case BUILT_IN_ASAN_AFTER_DYNAMIC_INIT:
+	*looping = false;
+	*state = IPA_CONST;
+	return true;
+      case BUILT_IN_PREFETCH:
+	*looping = true;
+	*state = IPA_CONST;
+	return true;
+      default:
+	break;
       }
   return false;
 }
@@ -623,9 +623,10 @@
 	  case BUILT_IN_LONGJMP:
 	  case BUILT_IN_NONLOCAL_GOTO:
 	    if (dump_file)
-	      fprintf (dump_file, "    longjmp and nonlocal goto is not const/pure\n");
+	      fprintf (dump_file,
+		       "    longjmp and nonlocal goto is not const/pure\n");
 	    local->pure_const_state = IPA_NEITHER;
-            local->looping = true;
+	    local->looping = true;
 	    break;
 	  default:
 	    break;
@@ -873,14 +874,17 @@
 {  \
   if (dump_file && (dump_flags & TDF_DETAILS))  \
     fprintf (dump_file, "\n%s is not a malloc candidate, reason: %s\n", \
-	     (node->name()), (reason));  \
+	     (node->dump_name ()), (reason));  \
   return false;  \
 }
 
 static bool
-malloc_candidate_p_1 (function *fun, tree retval, gimple *ret_stmt, bool ipa)
+malloc_candidate_p_1 (function *fun, tree retval, gimple *ret_stmt, bool ipa,
+		      bitmap visited)
 {
   cgraph_node *node = cgraph_node::get_create (fun->decl);
+  if (!bitmap_set_bit (visited, SSA_NAME_VERSION (retval)))
+    return true;
 
   if (!check_retval_uses (retval, ret_stmt))
     DUMP_AND_RETURN("Return value has uses outside return stmt"
@@ -925,7 +929,7 @@
 	    gimple *arg_def = SSA_NAME_DEF_STMT (arg);
 	    if (is_a<gphi *> (arg_def))
 	      {
-		if (!malloc_candidate_p_1 (fun, arg, phi, ipa))
+		if (!malloc_candidate_p_1 (fun, arg, phi, ipa, visited))
 		    DUMP_AND_RETURN ("nested phi fail")
 		continue;
 	      }
@@ -971,6 +975,7 @@
       || !flag_delete_null_pointer_checks)
     return false;
 
+  auto_bitmap visited;
   FOR_EACH_EDGE (e, ei, exit_block->preds)
     {
       gimple_stmt_iterator gsi = gsi_last_bb (e->src);
@@ -987,7 +992,7 @@
 	  || TREE_CODE (TREE_TYPE (retval)) != POINTER_TYPE)
 	DUMP_AND_RETURN("Return value is not SSA_NAME or not a pointer type.")
 
-      if (!malloc_candidate_p_1 (fun, retval, ret_stmt, ipa))
+      if (!malloc_candidate_p_1 (fun, retval, ret_stmt, ipa, visited))
 	return false;
     }
 
@@ -1009,7 +1014,7 @@
   funct_state l;
   basic_block this_block;
 
-  l = XCNEW (struct funct_state_d);
+  l = XCNEW (class funct_state_d);
   l->pure_const_state = IPA_CONST;
   l->state_previously_known = IPA_NEITHER;
   l->looping_previously_known = true;
@@ -1032,7 +1037,7 @@
   if (dump_file)
     {
       fprintf (dump_file, "\n\n local analysis of %s\n ",
-	       fn->name ());
+	       fn->dump_name ());
     }
 
   push_cfun (DECL_STRUCT_FUNCTION (decl));
@@ -1081,13 +1086,13 @@
 	    }
 	  else
 	    {
-	      struct loop *loop;
+	      class loop *loop;
 	      scev_initialize ();
 	      FOR_EACH_LOOP (loop, 0)
 		if (!finite_loop_p (loop))
 		  {
 		    if (dump_file)
-		      fprintf (dump_file, "    can not prove finiteness of "
+		      fprintf (dump_file, "    cannot prove finiteness of "
 			       "loop %i\n", loop->num);
 		    l->looping =true;
 		    break;
@@ -1186,7 +1191,7 @@
 
   /* Process all of the functions.
 
-     We process AVAIL_INTERPOSABLE functions.  We can not use the results
+     We process AVAIL_INTERPOSABLE functions.  We cannot use the results
      by default, but the info can be used at LTO with -fwhole-program or
      when function got cloned and the clone is AVAILABLE.  */
 
@@ -1274,7 +1279,7 @@
     {
       const char *data;
       size_t len;
-      struct lto_input_block *ib
+      class lto_input_block *ib
 	= lto_create_simple_input_block (file_data,
 					 LTO_section_ipa_pure_const,
 					 &data, &len);
@@ -1356,12 +1361,14 @@
     return true;
 
   enum availability avail;
-  cgraph_node *n = e->callee->function_or_virtual_thunk_symbol (&avail,
-							        e->caller);
-  if (avail <= AVAIL_INTERPOSABLE || TREE_NOTHROW (n->decl))
+  cgraph_node *ultimate_target
+    = e->callee->function_or_virtual_thunk_symbol (&avail, e->caller);
+  if (avail <= AVAIL_INTERPOSABLE || TREE_NOTHROW (ultimate_target->decl))
     return true;
-  return opt_for_fn (e->callee->decl, flag_non_call_exceptions)
-	 && !e->callee->binds_to_current_def_p (e->caller);
+  return ((opt_for_fn (e->callee->decl, flag_non_call_exceptions)
+	   && !e->callee->binds_to_current_def_p (e->caller))
+	  || !opt_for_fn (e->caller->decl, flag_ipa_pure_const)
+	  || !opt_for_fn (ultimate_target->decl, flag_ipa_pure_const));
 }
 
 /* Return true if NODE is self recursive function.
@@ -1391,17 +1398,22 @@
   return false;
 }
 
-/* We only propagate across edges with non-interposable callee.  */
+/* Skip edges from and to nodes without ipa_pure_const enabled.
+   Ignore not available symbols.  */
 
 static bool
 ignore_edge_for_pure_const (struct cgraph_edge *e)
 {
   enum availability avail;
-  e->callee->function_or_virtual_thunk_symbol (&avail, e->caller);
-  return (avail <= AVAIL_INTERPOSABLE);
+  cgraph_node *ultimate_target
+    = e->callee->function_or_virtual_thunk_symbol (&avail, e->caller);
+
+  return (avail <= AVAIL_INTERPOSABLE
+	  || !opt_for_fn (e->caller->decl, flag_ipa_pure_const)
+	  || !opt_for_fn (ultimate_target->decl,
+			  flag_ipa_pure_const));
 }
 
-
 /* Produce transitive closure over the callgraph and compute pure/const
    attributes.  */
 
@@ -1418,7 +1430,7 @@
   bool remove_p = false;
   bool has_cdtor;
 
-  order_pos = ipa_reduced_postorder (order, true, false,
+  order_pos = ipa_reduced_postorder (order, true,
 				     ignore_edge_for_pure_const);
   if (dump_file)
     {
@@ -1494,7 +1506,8 @@
 		}
 	      if (avail > AVAIL_INTERPOSABLE)
 		{
-		  funct_state y_l = funct_state_summaries->get (y);
+		  funct_state y_l = funct_state_summaries->get_create (y);
+
 		  if (dump_file && (dump_flags & TDF_DETAILS))
 		    {
 		      fprintf (dump_file,
@@ -1519,7 +1532,7 @@
 		    }
 		}
 	      else if (special_builtin_state (&edge_state, &edge_looping,
-					       y->decl))
+					      y->decl))
 		;
 	      else
 		state_from_flags (&edge_state, &edge_looping,
@@ -1644,7 +1657,7 @@
 	  w->nonfreeing_fn = !can_free;
 	  if (!can_free && dump_file)
 	    fprintf (dump_file, "Function found not to call free: %s\n",
-		     w->name ());
+		     w->dump_name ());
 
 	  if (w_l->state_previously_known != IPA_NEITHER
 	      && this_state > w_l->state_previously_known)
@@ -1665,7 +1678,7 @@
 	  /* Inline clones share declaration with their offline copies;
 	     do not modify their declarations since the offline copy may
 	     be different.  */
-	  if (!w->global.inlined_to)
+	  if (!w->inlined_to)
 	    switch (this_state)
 	      {
 	      case IPA_CONST:
@@ -1675,7 +1688,7 @@
 		    if (dump_file)
 		      fprintf (dump_file, "Function found to be %sconst: %s\n",
 			       this_looping ? "looping " : "",
-			       w->name ());
+			       w->dump_name ());
 		  }
 		/* Turning constructor or destructor to non-looping const/pure
 		   enables us to possibly remove the function completely.  */
@@ -1690,7 +1703,7 @@
 		      fprintf (dump_file,
 			       "Declaration updated to be %sconst: %s\n",
 			       this_looping ? "looping " : "",
-			       w->name ());
+			       w->dump_name ());
 		    remove_p |= has_cdtor;
 		  }
 		break;
@@ -1702,7 +1715,7 @@
 		    if (dump_file)
 		      fprintf (dump_file, "Function found to be %spure: %s\n",
 			       this_looping ? "looping " : "",
-			       w->name ());
+			       w->dump_name ());
 		  }
 		if (this_looping)
 		  has_cdtor = false;
@@ -1715,7 +1728,7 @@
 		      fprintf (dump_file,
 			       "Declaration updated to be %spure: %s\n",
 			       this_looping ? "looping " : "",
-			       w->name ());
+			       w->dump_name ());
 		    remove_p |= has_cdtor;
 		  }
 		break;
@@ -1747,7 +1760,7 @@
   int i;
   struct ipa_dfs_info * w_info;
 
-  order_pos = ipa_reduced_postorder (order, true, false,
+  order_pos = ipa_reduced_postorder (order, true,
 				     ignore_edge_for_nothrow);
   if (dump_file)
     {
@@ -1792,8 +1805,8 @@
 				   function_or_virtual_thunk_symbol (&avail,
 								     e->caller);
 
-		  /* We can use info about the callee only if we know it can
-		     not be interposed.
+		  /* We can use info about the callee only if we know it
+		     cannot be interposed.
 		     When callee is compiled with non-call exceptions we also
 		     must check that the declaration is bound to current
 		     body as other semantically equivalent body may still
@@ -1826,12 +1839,12 @@
 	      /* Inline clones share declaration with their offline copies;
 		 do not modify their declarations since the offline copy may
 		 be different.  */
-	      if (!w->global.inlined_to)
+	      if (!w->inlined_to)
 		{
 		  w->set_nothrow_flag (true);
 		  if (dump_file)
 		    fprintf (dump_file, "Function found to be nothrow: %s\n",
-			     w->name ());
+			     w->dump_name ());
 		}
 	    }
 	  else if (can_throw && !TREE_NOTHROW (w->decl))
@@ -1860,7 +1873,7 @@
     {
       funct_state fs = funct_state_summaries->get (node);
       if (fs)
-	fprintf (dump_file, "%s: %s\n", node->name (),
+	fprintf (dump_file, "%s: %s\n", node->dump_name (),
 		 malloc_state_names[fs->malloc_state]);
     }
 }
@@ -1953,11 +1966,11 @@
 	funct_state l = funct_state_summaries->get (node);
 	if (!node->alias
 	    && l->malloc_state == STATE_MALLOC
-	    && !node->global.inlined_to)
+	    && !node->inlined_to)
 	  {
 	    if (dump_file && (dump_flags & TDF_DETAILS))
 	      fprintf (dump_file, "Function %s found to be malloc\n",
-		       node->name ());
+		       node->dump_name ());
 
 	    bool malloc_decl_p = DECL_IS_MALLOC (node->decl);
 	    node->set_malloc_flag (true);
@@ -2186,7 +2199,7 @@
       changed = true;
       if (dump_file)
 	fprintf (dump_file, "Function found to be malloc: %s\n",
-		 node->name ());
+		 node->dump_name ());
     }
 
   free (l);
@@ -2292,7 +2305,7 @@
 
   node = cgraph_node::get (current_function_decl);
 
-  /* We run during lowering, we can not really use availability yet.  */
+  /* We run during lowering, we cannot really use availability yet.  */
   if (cgraph_node::get (current_function_decl)->get_availability ()
       <= AVAIL_INTERPOSABLE)
     {