public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* Fix can_inline_edge_p and code marking calls unreachable
@ 2015-03-26 18:32 Jan Hubicka
  2015-03-26 21:12 ` Jan Hubicka
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Hubicka @ 2015-03-26 18:32 UTC (permalink / raw)
  To: gcc-patches

Hi,
this patch fixes several issues in the inliner.  First is the fact that
edge_set_predicate does not mark indirect and speculative edge as unreachable
correctly (found by my updated verification patch).
Other issue is that can_inline_edge_p was wrong in several ways.  It did
use DECL_STRUCT_FUNCTION to check cilk and non-call-exceptions.  THis does
not work with LTO.  I also misupdated Richard's code to avoid inlining across
optimization boundaries so it did not check anoything and finally I noticed
we need to also check flag_exceptions.  Inlining flag_exceptions function that
can throw into !flag_exceptions is leading to a wrong code.  This also made
me notice that we do not correctly maintain DECL_FUNCTION_PERSONALITY.
After we decide to inline function with DECL_FUNCTION_PERSONALITY into a function
without DECL_FUNCTION_PERSONALITY, the caller inherits callee's perosnality.
This is done by tree-inline but it is too late and won't prevent us to mix different
personalities within one caller that has no personality.

Bootstrapped/regtested x86_64-linux, will commit it after testing on firefox.

Honza

	* ipa-inline-analysis.c (redirect_to_unreachable): New function.
	(edge_set_predicate): Use it to mark unreachable edges.
	(inline_summary_t::duplicate): Remove unnecesary code.
	(remap_edge_summaries): Likewise.
	(dump_inline_summary): Report contains_cilk_spawn.
	(compute_inline_parameters): Compute contains_cilk_spawn.
	(inline_read_section, inline_write_summary): Stream
	contains_cilk_spawn.
	* ipa-inline.c (can_inline_edge_p): Do not tuch 
	DECL_STRUCT_FUNCTION that may not be available;
	use CIF_CILK_SPAWN for cilk; fix optimization attribute checks;
	remove check for callee_fun->can_throw_non_call_exceptions and
	replace it by optimization attribute check; check for flag_exceptions.
	* ipa-inline-transform.c (inline_call): Maintain
	DECL_FUNCTION_PERSONALITY
	* ipa-inline.h (inline_summary): Add contains_cilk_spawn.
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c	(revision 221682)
+++ ipa-inline-analysis.c	(working copy)
@@ -760,6 +760,31 @@ account_size_time (struct inline_summary
     }
 }
 
+/* We proved E to be unreachable, redirect it to __bultin_unreachable.  */
+
+static void
+redirect_to_unreachable (struct cgraph_edge *e)
+{
+  struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
+  struct inline_edge_summary *es = inline_edge_summary (e);
+
+  if (e->speculative)
+    e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
+  if (!e->callee)
+    e->make_direct (cgraph_node::get_create
+		      (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
+  else
+    e->redirect_callee (cgraph_node::get_create
+			(builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
+  e->inline_failed = CIF_UNREACHABLE;
+  e->frequency = 0;
+  e->count = 0;
+  es->call_stmt_size = 0;
+  es->call_stmt_time = 0;
+  if (callee)
+    callee->remove_symbol_and_inline_clones ();
+}
+
 /* Set predicate for edge E.  */
 
 static void
@@ -769,18 +794,8 @@ edge_set_predicate (struct cgraph_edge *
 
   /* If the edge is determined to be never executed, redirect it
      to BUILTIN_UNREACHABLE to save inliner from inlining into it.  */
-  if (predicate && false_predicate_p (predicate) && e->callee)
-    {
-      struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
-
-      e->redirect_callee (cgraph_node::get_create
-			    (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
-      e->inline_failed = CIF_UNREACHABLE;
-      es->call_stmt_size = 0;
-      es->call_stmt_time = 0;
-      if (callee)
-	callee->remove_symbol_and_inline_clones ();
-    }
+  if (predicate && false_predicate_p (predicate))
+    redirect_to_unreachable (e);
   if (predicate && !true_predicate_p (predicate))
     {
       if (!es->predicate)
@@ -1228,10 +1243,7 @@ inline_summary_t::duplicate (cgraph_node
 							     info);
 	  if (false_predicate_p (&new_predicate)
 	      && !false_predicate_p (es->predicate))
-	    {
-	      optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
-	      edge->frequency = 0;
-	    }
+	    optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
 	  edge_set_predicate (edge, &new_predicate);
 	}
 
@@ -1250,10 +1262,7 @@ inline_summary_t::duplicate (cgraph_node
 							     info);
 	  if (false_predicate_p (&new_predicate)
 	      && !false_predicate_p (es->predicate))
-	    {
-	      optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
-	      edge->frequency = 0;
-	    }
+	    optimized_out_size += es->call_stmt_size * INLINE_SIZE_SCALE;
 	  edge_set_predicate (edge, &new_predicate);
 	}
       remap_hint_predicate_after_duplication (&info->loop_iterations,
@@ -1441,6 +1450,8 @@ dump_inline_summary (FILE *f, struct cgr
 	fprintf (f, " always_inline");
       if (s->inlinable)
 	fprintf (f, " inlinable");
+      if (s->contains_cilk_spawn)
+	fprintf (f, " contains_cilk_spawn");
       fprintf (f, "\n  self time:       %i\n", s->self_time);
       fprintf (f, "  global time:     %i\n", s->time);
       fprintf (f, "  self size:       %i\n", s->self_size);
@@ -2925,6 +2936,8 @@ compute_inline_parameters (struct cgraph
   else
     info->inlinable = tree_inlinable_function_p (node->decl);
 
+  info->contains_cilk_spawn = fn_contains_cilk_spawn_p (cfun);
+
   /* Type attributes can use parameter indices to describe them.  */
   if (TYPE_ATTRIBUTES (TREE_TYPE (node->decl)))
     node->local.can_change_signature = false;
@@ -3487,14 +3500,6 @@ remap_edge_summaries (struct cgraph_edge
 				   es->predicate, operand_map, offset_map,
 				   possible_truths, toplev_predicate);
 	      edge_set_predicate (e, &p);
-	      /* TODO: We should remove the edge for code that will be
-	         optimized out, but we need to keep verifiers and tree-inline
-	         happy.  Make it cold for now.  */
-	      if (false_predicate_p (&p))
-		{
-		  e->count = 0;
-		  e->frequency = 0;
-		}
 	    }
 	  else
 	    edge_set_predicate (e, toplev_predicate);
@@ -3516,14 +3521,6 @@ remap_edge_summaries (struct cgraph_edge
 			       es->predicate, operand_map, offset_map,
 			       possible_truths, toplev_predicate);
 	  edge_set_predicate (e, &p);
-	  /* TODO: We should remove the edge for code that will be optimized
-	     out, but we need to keep verifiers and tree-inline happy.
-	     Make it cold for now.  */
-	  if (false_predicate_p (&p))
-	    {
-	      e->count = 0;
-	      e->frequency = 0;
-	    }
 	}
       else
 	edge_set_predicate (e, toplev_predicate);
@@ -4228,6 +4225,7 @@ inline_read_section (struct lto_file_dec
 
       bp = streamer_read_bitpack (&ib);
       info->inlinable = bp_unpack_value (&bp, 1);
+      info->contains_cilk_spawn = bp_unpack_value (&bp, 1);
 
       count2 = streamer_read_uhwi (&ib);
       gcc_assert (!info->conds);
@@ -4393,6 +4391,7 @@ inline_write_summary (void)
 	  streamer_write_hwi (ob, info->self_time);
 	  bp = bitpack_create (ob->main_stream);
 	  bp_pack_value (&bp, info->inlinable, 1);
+	  bp_pack_value (&bp, info->contains_cilk_spawn, 1);
 	  streamer_write_bitpack (&bp);
 	  streamer_write_uhwi (ob, vec_safe_length (info->conds));
 	  for (i = 0; vec_safe_iterate (info->conds, i, &c); i++)
Index: ipa-inline-transform.c
===================================================================
--- ipa-inline-transform.c	(revision 221682)
+++ ipa-inline-transform.c	(working copy)
@@ -322,6 +322,10 @@ inline_call (struct cgraph_edge *e, bool
   if (to->global.inlined_to)
     to = to->global.inlined_to;
 
+  if (DECL_FUNCTION_PERSONALITY (callee->decl))
+    DECL_FUNCTION_PERSONALITY (to->decl)
+      = DECL_FUNCTION_PERSONALITY (callee->decl);
+
   /* If aliases are involved, redirect edge to the actual destination and
      possibly remove the aliases.  */
   if (e->callee != callee)
Index: ipa-inline.h
===================================================================
--- ipa-inline.h	(revision 221682)
+++ ipa-inline.h	(working copy)
@@ -126,6 +126,9 @@ struct GTY(()) inline_summary
 
   /* False when there something makes inlining impossible (such as va_arg).  */
   unsigned inlinable : 1;
+  /* True when function contains cilk spawn (and thus we can not inline
+     into it).  */
+  unsigned contains_cilk_spawn : 1;
 
   /* Information about function that will result after applying all the
      inline decisions present in the callgraph.  Generally kept up to
Index: ipa-inline.c
===================================================================
--- ipa-inline.c	(revision 221682)
+++ ipa-inline.c	(working copy)
@@ -329,8 +329,6 @@ can_inline_edge_p (struct cgraph_edge *e
   tree caller_tree = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (caller->decl);
   tree callee_tree
     = callee ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (callee->decl) : NULL;
-  struct function *caller_fun = caller->get_fun ();
-  struct function *callee_fun = callee ? callee->get_fun () : NULL;
 
   if (!callee->definition)
     {
@@ -342,12 +340,6 @@ can_inline_edge_p (struct cgraph_edge *e
       e->inline_failed = CIF_USES_COMDAT_LOCAL;
       inlinable = false;
     }
-  else if (!inline_summaries->get (callee)->inlinable
-	   || (caller_fun && fn_contains_cilk_spawn_p (caller_fun)))
-    {
-      e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
-      inlinable = false;
-    }
   else if (avail <= AVAIL_INTERPOSABLE)
     {
       e->inline_failed = CIF_OVERWRITABLE;
@@ -375,16 +367,6 @@ can_inline_edge_p (struct cgraph_edge *e
       e->inline_failed = CIF_UNSPECIFIED;
       inlinable = false;
     }
-  /* Don't inline if the callee can throw non-call exceptions but the
-     caller cannot.
-     FIXME: this is obviously wrong for LTO where STRUCT_FUNCTION is missing.
-     Move the flag into cgraph node or mirror it in the inline summary.  */
-  else if (callee_fun && callee_fun->can_throw_non_call_exceptions
-	   && !(caller_fun && caller_fun->can_throw_non_call_exceptions))
-    {
-      e->inline_failed = CIF_NON_CALL_EXCEPTIONS;
-      inlinable = false;
-    }
   /* Check compatibility of target optimization options.  */
   else if (!targetm.target_option.can_inline_p (caller->decl,
 						callee->decl))
@@ -392,6 +374,16 @@ can_inline_edge_p (struct cgraph_edge *e
       e->inline_failed = CIF_TARGET_OPTION_MISMATCH;
       inlinable = false;
     }
+  else if (!inline_summaries->get (callee)->inlinable)
+    {
+      e->inline_failed = CIF_FUNCTION_NOT_INLINABLE;
+      inlinable = false;
+    }
+  else if (inline_summaries->get (caller)->contains_cilk_spawn)
+    {
+      e->inline_failed = CIF_CILK_SPAWN;
+      inlinable = false;
+    }
   /* Don't inline a function with mismatched sanitization attributes. */
   else if (!sanitize_attrs_match_for_inline_p (caller->decl, callee->decl))
     {
@@ -416,38 +408,52 @@ can_inline_edge_p (struct cgraph_edge *e
       /* Strictly speaking only when the callee contains signed integer
          math where overflow is undefined.  */
       if ((opt_for_fn (caller->decl, flag_strict_overflow)
-	   != opt_for_fn (caller->decl, flag_strict_overflow))
+	   != opt_for_fn (callee->decl, flag_strict_overflow))
 	  || (opt_for_fn (caller->decl, flag_wrapv)
-	      != opt_for_fn (caller->decl, flag_wrapv))
+	      != opt_for_fn (callee->decl, flag_wrapv))
 	  || (opt_for_fn (caller->decl, flag_trapv)
-	      != opt_for_fn (caller->decl, flag_trapv))
+	      != opt_for_fn (callee->decl, flag_trapv))
 	  /* Strictly speaking only when the callee contains memory
 	     accesses that are not using alias-set zero anyway.  */
 	  || (opt_for_fn (caller->decl, flag_strict_aliasing)
-	      != opt_for_fn (caller->decl, flag_strict_aliasing))
+	      != opt_for_fn (callee->decl, flag_strict_aliasing))
 	  /* Strictly speaking only when the callee uses FP math.  */
 	  || (opt_for_fn (caller->decl, flag_rounding_math)
-	      != opt_for_fn (caller->decl, flag_rounding_math))
+	      != opt_for_fn (callee->decl, flag_rounding_math))
 	  || (opt_for_fn (caller->decl, flag_trapping_math)
-	      != opt_for_fn (caller->decl, flag_trapping_math))
+	      != opt_for_fn (callee->decl, flag_trapping_math))
 	  || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations)
-	      != opt_for_fn (caller->decl, flag_unsafe_math_optimizations))
+	      != opt_for_fn (callee->decl, flag_unsafe_math_optimizations))
 	  || (opt_for_fn (caller->decl, flag_finite_math_only)
-	      != opt_for_fn (caller->decl, flag_finite_math_only))
+	      != opt_for_fn (callee->decl, flag_finite_math_only))
 	  || (opt_for_fn (caller->decl, flag_signaling_nans)
-	      != opt_for_fn (caller->decl, flag_signaling_nans))
+	      != opt_for_fn (callee->decl, flag_signaling_nans))
 	  || (opt_for_fn (caller->decl, flag_cx_limited_range)
-	      != opt_for_fn (caller->decl, flag_cx_limited_range))
+	      != opt_for_fn (callee->decl, flag_cx_limited_range))
 	  || (opt_for_fn (caller->decl, flag_signed_zeros)
-	      != opt_for_fn (caller->decl, flag_signed_zeros))
+	      != opt_for_fn (callee->decl, flag_signed_zeros))
 	  || (opt_for_fn (caller->decl, flag_associative_math)
-	      != opt_for_fn (caller->decl, flag_associative_math))
+	      != opt_for_fn (callee->decl, flag_associative_math))
 	  || (opt_for_fn (caller->decl, flag_reciprocal_math)
-	      != opt_for_fn (caller->decl, flag_reciprocal_math))
+	      != opt_for_fn (callee->decl, flag_reciprocal_math))
+	  /* We do not want to make code compiled with exceptions to be brought
+	     into a non-EH function unless we know that the callee does not
+	     throw.  This is tracked by DECL_FUNCTION_PERSONALITY.  */
+	  || (opt_for_fn (caller->decl, flag_non_call_exceptions)
+	      != opt_for_fn (callee->decl, flag_non_call_exceptions)
+	      /* TODO: We also may allow bringing !flag_non_call_exceptions
+		 to flag_non_call_exceptions function, but that may need
+		 extra work in tree-inline to add the extra EH edges.  */
+	      && (!opt_for_fn (callee->decl, flag_non_call_exceptions)
+		  || DECL_FUNCTION_PERSONALITY (callee->decl)))
+	  || (opt_for_fn (caller->decl, flag_exceptions)
+	      != opt_for_fn (callee->decl, flag_exceptions)
+	      && (!opt_for_fn (callee->decl, flag_exceptions)
+		  || DECL_FUNCTION_PERSONALITY (callee->decl)))
 	  /* Strictly speaking only when the callee contains function
 	     calls that may end up setting errno.  */
 	  || (opt_for_fn (caller->decl, flag_errno_math)
-	      != opt_for_fn (caller->decl, flag_errno_math))
+	      != opt_for_fn (callee->decl, flag_errno_math))
 	  /* When devirtualization is diabled for callee, it is not safe
 	     to inline it as we possibly mangled the type info.
 	     Allow early inlining of always inlines.  */

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-26 18:32 Fix can_inline_edge_p and code marking calls unreachable Jan Hubicka
@ 2015-03-26 21:12 ` Jan Hubicka
  2015-03-26 22:58   ` Christophe Lyon
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Hubicka @ 2015-03-26 21:12 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

Hi,
this patch missed hunk adding CIF code that I commited now
	* cif-code.def (CILK_SPAWN): New code.

--- trunk/gcc/cif-code.def	2015/03/26 20:37:53	221709
+++ trunk/gcc/cif-code.def	2015/03/26 21:10:28	221710
@@ -124,6 +124,10 @@
 DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
 	   N_("function attribute mismatch"))
 
+/* We can't inline because of mismatched caller/callee attributes.  */
+DEFCIFCODE(CILK_SPAWN, CIF_FINAL_ERROR,
+	   N_("caller function contains cilk spawn"))
+
 /* We proved that the call is unreachable.  */
 DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
 	   N_("unreachable"))

I also noticed that this breaks one testcase which is cured by the following patch
I am testing and will commit once it concludes. I apologize for the breakage.

Honza

	* ipa-inline.c (check_maybe_up, check_maybe_down, check_match):
	New macros.
	(can_inline_edge_p): Relax option matching for always inline functions.
Index: ipa-inline.c
===================================================================
--- ipa-inline.c	(revision 221706)
+++ ipa-inline.c	(working copy)
@@ -298,6 +298,27 @@ sanitize_attrs_match_for_inline_p (const
       DECL_ATTRIBUTES (callee));
 }
 
+/* Used for flags where it is safe to inline when caller's value is
+   grater than callee's.  */
+#define check_maybe_up(flag) \
+      (opts_for_fn (caller->decl)->x_##flag		\
+       != opts_for_fn (callee->decl)->x_##flag		\
+       && (!always_inline 				\
+	   || opts_for_fn (caller->decl)->x_##flag	\
+	      < opts_for_fn (callee->decl)->x_##flag))
+/* Used for flags where it is safe to inline when caller's value is
+   smaller than callee's.  */
+#define check_maybe_down(flag) \
+      (opts_for_fn (caller->decl)->x_##flag		\
+       != opts_for_fn (callee->decl)->x_##flag		\
+       && (!always_inline 				\
+	   || opts_for_fn (caller->decl)->x_##flag	\
+	      > opts_for_fn (callee->decl)->x_##flag))
+/* Used for flags where exact match is needed for correctness.  */
+#define check_match(flag) \
+      (opts_for_fn (caller->decl)->x_##flag		\
+       != opts_for_fn (callee->decl)->x_##flag)
+
  /* Decide if we can inline the edge and possibly update
    inline_failed reason.  
    We check whether inlining is possible at all and whether
@@ -401,74 +422,60 @@ can_inline_edge_p (struct cgraph_edge *e
      optimization attribute.  */
   else if (caller_tree != callee_tree)
     {
+      bool always_inline =
+	     (DECL_DISREGARD_INLINE_LIMITS (callee->decl)
+	      && lookup_attribute ("always_inline",
+				   DECL_ATTRIBUTES (callee->decl)));
+
       /* There are some options that change IL semantics which means
          we cannot inline in these cases for correctness reason.
 	 Not even for always_inline declared functions.  */
       /* Strictly speaking only when the callee contains signed integer
          math where overflow is undefined.  */
-      if ((opt_for_fn (caller->decl, flag_strict_overflow)
-	   != opt_for_fn (callee->decl, flag_strict_overflow))
-	  || (opt_for_fn (caller->decl, flag_wrapv)
-	      != opt_for_fn (callee->decl, flag_wrapv))
-	  || (opt_for_fn (caller->decl, flag_trapv)
-	      != opt_for_fn (callee->decl, flag_trapv))
+      if ((check_maybe_up (flag_strict_overflow)
+	   /* this flag is set by optimize.  Allow inlining across
+	      optimize boundary.  */
+	   && (!opt_for_fn (caller->decl, optimize)
+	       == !opt_for_fn (callee->decl, optimize) || !always_inline))
+	  || check_match (flag_wrapv)
+	  || check_match (flag_trapv)
 	  /* Strictly speaking only when the callee contains memory
 	     accesses that are not using alias-set zero anyway.  */
-	  || (opt_for_fn (caller->decl, flag_strict_aliasing)
-	      != opt_for_fn (callee->decl, flag_strict_aliasing))
+	  || check_maybe_down (flag_strict_aliasing)
 	  /* Strictly speaking only when the callee uses FP math.  */
-	  || (opt_for_fn (caller->decl, flag_rounding_math)
-	      != opt_for_fn (callee->decl, flag_rounding_math))
-	  || (opt_for_fn (caller->decl, flag_trapping_math)
-	      != opt_for_fn (callee->decl, flag_trapping_math))
-	  || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations)
-	      != opt_for_fn (callee->decl, flag_unsafe_math_optimizations))
-	  || (opt_for_fn (caller->decl, flag_finite_math_only)
-	      != opt_for_fn (callee->decl, flag_finite_math_only))
-	  || (opt_for_fn (caller->decl, flag_signaling_nans)
-	      != opt_for_fn (callee->decl, flag_signaling_nans))
-	  || (opt_for_fn (caller->decl, flag_cx_limited_range)
-	      != opt_for_fn (callee->decl, flag_cx_limited_range))
-	  || (opt_for_fn (caller->decl, flag_signed_zeros)
-	      != opt_for_fn (callee->decl, flag_signed_zeros))
-	  || (opt_for_fn (caller->decl, flag_associative_math)
-	      != opt_for_fn (callee->decl, flag_associative_math))
-	  || (opt_for_fn (caller->decl, flag_reciprocal_math)
-	      != opt_for_fn (callee->decl, flag_reciprocal_math))
+	  || check_maybe_up (flag_rounding_math)
+	  || check_maybe_up (flag_trapping_math)
+	  || check_maybe_down (flag_unsafe_math_optimizations)
+	  || check_maybe_down (flag_finite_math_only)
+	  || check_maybe_up (flag_signaling_nans)
+	  || check_maybe_down (flag_cx_limited_range)
+	  || check_maybe_up (flag_signed_zeros)
+	  || check_maybe_down (flag_associative_math)
+	  || check_maybe_down (flag_reciprocal_math)
 	  /* We do not want to make code compiled with exceptions to be brought
 	     into a non-EH function unless we know that the callee does not
 	     throw.  This is tracked by DECL_FUNCTION_PERSONALITY.  */
-	  || (opt_for_fn (caller->decl, flag_non_call_exceptions)
-	      != opt_for_fn (callee->decl, flag_non_call_exceptions)
+	  || (check_match (flag_non_call_exceptions)
 	      /* TODO: We also may allow bringing !flag_non_call_exceptions
 		 to flag_non_call_exceptions function, but that may need
 		 extra work in tree-inline to add the extra EH edges.  */
 	      && (!opt_for_fn (callee->decl, flag_non_call_exceptions)
 		  || DECL_FUNCTION_PERSONALITY (callee->decl)))
-	  || (!opt_for_fn (caller->decl, flag_exceptions)
-	      && opt_for_fn (callee->decl, flag_exceptions)
+	  || (check_maybe_up (flag_exceptions)
 	      && DECL_FUNCTION_PERSONALITY (callee->decl))
 	  /* Strictly speaking only when the callee contains function
 	     calls that may end up setting errno.  */
-	  || (opt_for_fn (caller->decl, flag_errno_math)
-	      != opt_for_fn (callee->decl, flag_errno_math))
+	  || check_maybe_up (flag_errno_math)
 	  /* When devirtualization is diabled for callee, it is not safe
 	     to inline it as we possibly mangled the type info.
 	     Allow early inlining of always inlines.  */
-	  || (opt_for_fn (caller->decl, flag_devirtualize)
-	      && !opt_for_fn (callee->decl, flag_devirtualize)
-	      && (!early
-		  || (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
-		      || !lookup_attribute ("always_inline",
-				            DECL_ATTRIBUTES (callee->decl))))))
+	  || (!early && check_maybe_down (flag_devirtualize)))
 	{
 	  e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
 	  inlinable = false;
 	}
       /* gcc.dg/pr43564.c.  Apply user-forced inline even at -O0.  */
-      else if (DECL_DISREGARD_INLINE_LIMITS (callee->decl)
-	       && lookup_attribute ("always_inline",
-				    DECL_ATTRIBUTES (callee->decl)))
+      else if (always_inline)
 	;
       /* When user added an attribute to the callee honor it.  */
       else if (lookup_attribute ("optimize", DECL_ATTRIBUTES (callee->decl))

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-26 21:12 ` Jan Hubicka
@ 2015-03-26 22:58   ` Christophe Lyon
  2015-03-26 23:47     ` Jan Hubicka
  0 siblings, 1 reply; 8+ messages in thread
From: Christophe Lyon @ 2015-03-26 22:58 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: gcc-patches

On 26 March 2015 at 22:12, Jan Hubicka <hubicka@ucw.cz> wrote:
> Hi,
> this patch missed hunk adding CIF code that I commited now
>         * cif-code.def (CILK_SPAWN): New code

Hi,
After this fix, I can see build failures in glibc:
key_call.c:574:1: internal compiler error: in inline_call, at
ipa-inline-transform.c:386
 }
 ^
0x10eb475 inline_call(cgraph_edge*, bool, vec<cgraph_edge*, va_heap,
vl_ptr>*, int*, bool, bool*)
        /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline-transform.c:381
0x10e43ed inline_small_functions
        /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline.c:1942
0x10e4ead ipa_inline
        /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline.c:2345

See http://abe.tcwglab.linaro.org/logs/validations/cross-validation/gcc-build/trunk/221710/build.html
for more detailed logs.

Thanks

Christophe

>
> --- trunk/gcc/cif-code.def      2015/03/26 20:37:53     221709
> +++ trunk/gcc/cif-code.def      2015/03/26 21:10:28     221710
> @@ -124,6 +124,10 @@
>  DEFCIFCODE(ATTRIBUTE_MISMATCH, CIF_FINAL_ERROR,
>            N_("function attribute mismatch"))
>
> +/* We can't inline because of mismatched caller/callee attributes.  */
> +DEFCIFCODE(CILK_SPAWN, CIF_FINAL_ERROR,
> +          N_("caller function contains cilk spawn"))
> +
>  /* We proved that the call is unreachable.  */
>  DEFCIFCODE(UNREACHABLE, CIF_FINAL_ERROR,
>            N_("unreachable"))
>
> I also noticed that this breaks one testcase which is cured by the following patch
> I am testing and will commit once it concludes. I apologize for the breakage.
>
> Honza
>
>         * ipa-inline.c (check_maybe_up, check_maybe_down, check_match):
>         New macros.
>         (can_inline_edge_p): Relax option matching for always inline functions.
> Index: ipa-inline.c
> ===================================================================
> --- ipa-inline.c        (revision 221706)
> +++ ipa-inline.c        (working copy)
> @@ -298,6 +298,27 @@ sanitize_attrs_match_for_inline_p (const
>        DECL_ATTRIBUTES (callee));
>  }
>
> +/* Used for flags where it is safe to inline when caller's value is
> +   grater than callee's.  */
> +#define check_maybe_up(flag) \
> +      (opts_for_fn (caller->decl)->x_##flag            \
> +       != opts_for_fn (callee->decl)->x_##flag         \
> +       && (!always_inline                              \
> +          || opts_for_fn (caller->decl)->x_##flag      \
> +             < opts_for_fn (callee->decl)->x_##flag))
> +/* Used for flags where it is safe to inline when caller's value is
> +   smaller than callee's.  */
> +#define check_maybe_down(flag) \
> +      (opts_for_fn (caller->decl)->x_##flag            \
> +       != opts_for_fn (callee->decl)->x_##flag         \
> +       && (!always_inline                              \
> +          || opts_for_fn (caller->decl)->x_##flag      \
> +             > opts_for_fn (callee->decl)->x_##flag))
> +/* Used for flags where exact match is needed for correctness.  */
> +#define check_match(flag) \
> +      (opts_for_fn (caller->decl)->x_##flag            \
> +       != opts_for_fn (callee->decl)->x_##flag)
> +
>   /* Decide if we can inline the edge and possibly update
>     inline_failed reason.
>     We check whether inlining is possible at all and whether
> @@ -401,74 +422,60 @@ can_inline_edge_p (struct cgraph_edge *e
>       optimization attribute.  */
>    else if (caller_tree != callee_tree)
>      {
> +      bool always_inline =
> +            (DECL_DISREGARD_INLINE_LIMITS (callee->decl)
> +             && lookup_attribute ("always_inline",
> +                                  DECL_ATTRIBUTES (callee->decl)));
> +
>        /* There are some options that change IL semantics which means
>           we cannot inline in these cases for correctness reason.
>          Not even for always_inline declared functions.  */
>        /* Strictly speaking only when the callee contains signed integer
>           math where overflow is undefined.  */
> -      if ((opt_for_fn (caller->decl, flag_strict_overflow)
> -          != opt_for_fn (callee->decl, flag_strict_overflow))
> -         || (opt_for_fn (caller->decl, flag_wrapv)
> -             != opt_for_fn (callee->decl, flag_wrapv))
> -         || (opt_for_fn (caller->decl, flag_trapv)
> -             != opt_for_fn (callee->decl, flag_trapv))
> +      if ((check_maybe_up (flag_strict_overflow)
> +          /* this flag is set by optimize.  Allow inlining across
> +             optimize boundary.  */
> +          && (!opt_for_fn (caller->decl, optimize)
> +              == !opt_for_fn (callee->decl, optimize) || !always_inline))
> +         || check_match (flag_wrapv)
> +         || check_match (flag_trapv)
>           /* Strictly speaking only when the callee contains memory
>              accesses that are not using alias-set zero anyway.  */
> -         || (opt_for_fn (caller->decl, flag_strict_aliasing)
> -             != opt_for_fn (callee->decl, flag_strict_aliasing))
> +         || check_maybe_down (flag_strict_aliasing)
>           /* Strictly speaking only when the callee uses FP math.  */
> -         || (opt_for_fn (caller->decl, flag_rounding_math)
> -             != opt_for_fn (callee->decl, flag_rounding_math))
> -         || (opt_for_fn (caller->decl, flag_trapping_math)
> -             != opt_for_fn (callee->decl, flag_trapping_math))
> -         || (opt_for_fn (caller->decl, flag_unsafe_math_optimizations)
> -             != opt_for_fn (callee->decl, flag_unsafe_math_optimizations))
> -         || (opt_for_fn (caller->decl, flag_finite_math_only)
> -             != opt_for_fn (callee->decl, flag_finite_math_only))
> -         || (opt_for_fn (caller->decl, flag_signaling_nans)
> -             != opt_for_fn (callee->decl, flag_signaling_nans))
> -         || (opt_for_fn (caller->decl, flag_cx_limited_range)
> -             != opt_for_fn (callee->decl, flag_cx_limited_range))
> -         || (opt_for_fn (caller->decl, flag_signed_zeros)
> -             != opt_for_fn (callee->decl, flag_signed_zeros))
> -         || (opt_for_fn (caller->decl, flag_associative_math)
> -             != opt_for_fn (callee->decl, flag_associative_math))
> -         || (opt_for_fn (caller->decl, flag_reciprocal_math)
> -             != opt_for_fn (callee->decl, flag_reciprocal_math))
> +         || check_maybe_up (flag_rounding_math)
> +         || check_maybe_up (flag_trapping_math)
> +         || check_maybe_down (flag_unsafe_math_optimizations)
> +         || check_maybe_down (flag_finite_math_only)
> +         || check_maybe_up (flag_signaling_nans)
> +         || check_maybe_down (flag_cx_limited_range)
> +         || check_maybe_up (flag_signed_zeros)
> +         || check_maybe_down (flag_associative_math)
> +         || check_maybe_down (flag_reciprocal_math)
>           /* We do not want to make code compiled with exceptions to be brought
>              into a non-EH function unless we know that the callee does not
>              throw.  This is tracked by DECL_FUNCTION_PERSONALITY.  */
> -         || (opt_for_fn (caller->decl, flag_non_call_exceptions)
> -             != opt_for_fn (callee->decl, flag_non_call_exceptions)
> +         || (check_match (flag_non_call_exceptions)
>               /* TODO: We also may allow bringing !flag_non_call_exceptions
>                  to flag_non_call_exceptions function, but that may need
>                  extra work in tree-inline to add the extra EH edges.  */
>               && (!opt_for_fn (callee->decl, flag_non_call_exceptions)
>                   || DECL_FUNCTION_PERSONALITY (callee->decl)))
> -         || (!opt_for_fn (caller->decl, flag_exceptions)
> -             && opt_for_fn (callee->decl, flag_exceptions)
> +         || (check_maybe_up (flag_exceptions)
>               && DECL_FUNCTION_PERSONALITY (callee->decl))
>           /* Strictly speaking only when the callee contains function
>              calls that may end up setting errno.  */
> -         || (opt_for_fn (caller->decl, flag_errno_math)
> -             != opt_for_fn (callee->decl, flag_errno_math))
> +         || check_maybe_up (flag_errno_math)
>           /* When devirtualization is diabled for callee, it is not safe
>              to inline it as we possibly mangled the type info.
>              Allow early inlining of always inlines.  */
> -         || (opt_for_fn (caller->decl, flag_devirtualize)
> -             && !opt_for_fn (callee->decl, flag_devirtualize)
> -             && (!early
> -                 || (!DECL_DISREGARD_INLINE_LIMITS (callee->decl)
> -                     || !lookup_attribute ("always_inline",
> -                                           DECL_ATTRIBUTES (callee->decl))))))
> +         || (!early && check_maybe_down (flag_devirtualize)))
>         {
>           e->inline_failed = CIF_OPTIMIZATION_MISMATCH;
>           inlinable = false;
>         }
>        /* gcc.dg/pr43564.c.  Apply user-forced inline even at -O0.  */
> -      else if (DECL_DISREGARD_INLINE_LIMITS (callee->decl)
> -              && lookup_attribute ("always_inline",
> -                                   DECL_ATTRIBUTES (callee->decl)))
> +      else if (always_inline)
>         ;
>        /* When user added an attribute to the callee honor it.  */
>        else if (lookup_attribute ("optimize", DECL_ATTRIBUTES (callee->decl))

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-26 22:58   ` Christophe Lyon
@ 2015-03-26 23:47     ` Jan Hubicka
  2015-03-27  2:05       ` Jan Hubicka
  2015-03-27  2:09       ` Markus Trippelsdorf
  0 siblings, 2 replies; 8+ messages in thread
From: Jan Hubicka @ 2015-03-26 23:47 UTC (permalink / raw)
  To: Christophe Lyon; +Cc: Jan Hubicka, gcc-patches

> On 26 March 2015 at 22:12, Jan Hubicka <hubicka@ucw.cz> wrote:
> > Hi,
> > this patch missed hunk adding CIF code that I commited now
> >         * cif-code.def (CILK_SPAWN): New code
> 
> Hi,
> After this fix, I can see build failures in glibc:
> key_call.c:574:1: internal compiler error: in inline_call, at
> ipa-inline-transform.c:386
>  }
>  ^
> 0x10eb475 inline_call(cgraph_edge*, bool, vec<cgraph_edge*, va_heap,
> vl_ptr>*, int*, bool, bool*)
>         /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline-transform.c:381
> 0x10e43ed inline_small_functions
>         /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline.c:1942
> 0x10e4ead ipa_inline
>         /tmp/9065933_3.tmpdir/aci-gcc-fsf/sources/gcc-fsf/gccsrc/gcc/ipa-inline.c:2345
> 
> See http://abe.tcwglab.linaro.org/logs/validations/cross-validation/gcc-build/trunk/221710/build.html
> for more detailed logs.

Can you please send me preprocessed testcase? It is probably another misaccounting
bug in ipa-inline-analysis.  I may just silence this assert for this stage 4.

Honza

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-26 23:47     ` Jan Hubicka
@ 2015-03-27  2:05       ` Jan Hubicka
  2015-03-27  2:09       ` Markus Trippelsdorf
  1 sibling, 0 replies; 8+ messages in thread
From: Jan Hubicka @ 2015-03-27  2:05 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Christophe Lyon, gcc-patches

Hi,
I reproduced the problem of Firefox LTO (though small testcase would be welcome)
The problem is in a way we walk edges that now can be turned from indirect to direct.
I am working on a fix.

Honza

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-26 23:47     ` Jan Hubicka
  2015-03-27  2:05       ` Jan Hubicka
@ 2015-03-27  2:09       ` Markus Trippelsdorf
  2015-03-27  2:14         ` Jan Hubicka
  1 sibling, 1 reply; 8+ messages in thread
From: Markus Trippelsdorf @ 2015-03-27  2:09 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Christophe Lyon, gcc-patches

On 2015.03.27 at 00:46 +0100, Jan Hubicka wrote:
> > On 26 March 2015 at 22:12, Jan Hubicka <hubicka@ucw.cz> wrote:
> > After this fix, I can see build failures in glibc:
> > key_call.c:574:1: internal compiler error: in inline_call, at
> > ipa-inline-transform.c:386
> 
> Can you please send me preprocessed testcase? It is probably another misaccounting
> bug in ipa-inline-analysis.  I may just silence this assert for this stage 4.

Also happens when building the Linux kernel:

trippels@gcc2-power8 linux-3.18.8 % cat nf_sockopt.i
int a;
int (*b)(), (*c)();
int fn1(int p1) {
  if (a)
    return 0;
  if (p1) {
    c();
    b();
  }
}
void fn2() { fn1(0); }

trippels@gcc2-power8 linux-3.18.8 % /home/trippels/gcc_test/usr/local/bin/gcc -O2 -c nf_sockopt.i
nf_sockopt.i:11:1: internal compiler error: in inline_call, at ipa-inline-transform.c:386
 void fn2() { fn1(0); }
 ^
0x10e435cf inline_call(cgraph_edge*, bool, vec<cgraph_edge*, va_heap, vl_ptr>*, int*, bool, bool*)
        ../../gcc/gcc/ipa-inline-transform.c:381
0x10e39a7b inline_small_functions
        ../../gcc/gcc/ipa-inline.c:1949
0x10e39a7b ipa_inline
        ../../gcc/gcc/ipa-inline.c:2352
Please submit a full bug report,
with preprocessed source if appropriate.
Please include the complete backtrace with any bug report.
See <http://gcc.gnu.org/bugs.html> for instructions.

-- 
Markus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-27  2:09       ` Markus Trippelsdorf
@ 2015-03-27  2:14         ` Jan Hubicka
  2015-03-27  9:36           ` Christophe Lyon
  0 siblings, 1 reply; 8+ messages in thread
From: Jan Hubicka @ 2015-03-27  2:14 UTC (permalink / raw)
  To: Markus Trippelsdorf; +Cc: Jan Hubicka, Christophe Lyon, gcc-patches

> On 2015.03.27 at 00:46 +0100, Jan Hubicka wrote:
> > > On 26 March 2015 at 22:12, Jan Hubicka <hubicka@ucw.cz> wrote:
> > > After this fix, I can see build failures in glibc:
> > > key_call.c:574:1: internal compiler error: in inline_call, at
> > > ipa-inline-transform.c:386
> > 
> > Can you please send me preprocessed testcase? It is probably another misaccounting
> > bug in ipa-inline-analysis.  I may just silence this assert for this stage 4.
> 
> Also happens when building the Linux kernel:
> 
> trippels@gcc2-power8 linux-3.18.8 % cat nf_sockopt.i
> int a;
> int (*b)(), (*c)();
> int fn1(int p1) {
>   if (a)
>     return 0;
>   if (p1) {
>     c();
>     b();
>   }
> }
> void fn2() { fn1(0); }

Great, Markus, having a testcase is important for covering this code path.
I am attaching a fix, will test it with your testcase and commit.

	* ipa-inline-analysis.c (redirect_to_unreachable): Be prepared for
	edge to change by speculation resolution or redirection.
	(edge_set_predicate): Likewise.
	(inline_summary_t::duplicate): Likewise.
	(remap_edge_summaries): Likewise.
Index: ipa-inline-analysis.c
===================================================================
--- ipa-inline-analysis.c	(revision 221706)
+++ ipa-inline-analysis.c	(working copy)
@@ -762,20 +762,20 @@ account_size_time (struct inline_summary
 
 /* We proved E to be unreachable, redirect it to __bultin_unreachable.  */
 
-static void
+static struct cgraph_edge *
 redirect_to_unreachable (struct cgraph_edge *e)
 {
   struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
-  struct inline_edge_summary *es = inline_edge_summary (e);
 
   if (e->speculative)
-    e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
-  if (!e->callee)
+    e = e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
+  else if (!e->callee)
     e->make_direct (cgraph_node::get_create
 		      (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
   else
     e->redirect_callee (cgraph_node::get_create
 			(builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
+  struct inline_edge_summary *es = inline_edge_summary (e);
   e->inline_failed = CIF_UNREACHABLE;
   e->frequency = 0;
   e->count = 0;
@@ -783,6 +783,7 @@ redirect_to_unreachable (struct cgraph_e
   es->call_stmt_time = 0;
   if (callee)
     callee->remove_symbol_and_inline_clones ();
+  return e;
 }
 
 /* Set predicate for edge E.  */
@@ -790,12 +791,12 @@ redirect_to_unreachable (struct cgraph_e
 static void
 edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
 {
-  struct inline_edge_summary *es = inline_edge_summary (e);
-
   /* If the edge is determined to be never executed, redirect it
      to BUILTIN_UNREACHABLE to save inliner from inlining into it.  */
   if (predicate && false_predicate_p (predicate))
-    redirect_to_unreachable (e);
+    e = redirect_to_unreachable (e);
+
+  struct inline_edge_summary *es = inline_edge_summary (e);
   if (predicate && !true_predicate_p (predicate))
     {
       if (!es->predicate)
@@ -1184,7 +1185,7 @@ inline_summary_t::duplicate (cgraph_node
       size_time_entry *e;
       int optimized_out_size = 0;
       bool inlined_to_p = false;
-      struct cgraph_edge *edge;
+      struct cgraph_edge *edge, *next;
 
       info->entry = 0;
       known_vals.safe_grow_cleared (count);
@@ -1229,10 +1230,11 @@ inline_summary_t::duplicate (cgraph_node
 
       /* Remap edge predicates with the same simplification as above.
          Also copy constantness arrays.   */
-      for (edge = dst->callees; edge; edge = edge->next_callee)
+      for (edge = dst->callees; edge; edge = next)
 	{
 	  struct predicate new_predicate;
 	  struct inline_edge_summary *es = inline_edge_summary (edge);
+	  next = edge->next_callee;
 
 	  if (!edge->inline_failed)
 	    inlined_to_p = true;
@@ -1249,10 +1251,11 @@ inline_summary_t::duplicate (cgraph_node
 
       /* Remap indirect edge predicates with the same simplificaiton as above. 
          Also copy constantness arrays.   */
-      for (edge = dst->indirect_calls; edge; edge = edge->next_callee)
+      for (edge = dst->indirect_calls; edge; edge = next)
 	{
 	  struct predicate new_predicate;
 	  struct inline_edge_summary *es = inline_edge_summary (edge);
+	  next = edge->next_callee;
 
 	  gcc_checking_assert (edge->inline_failed);
 	  if (!es->predicate)
@@ -3484,11 +3487,12 @@ remap_edge_summaries (struct cgraph_edge
 		      clause_t possible_truths,
 		      struct predicate *toplev_predicate)
 {
-  struct cgraph_edge *e;
-  for (e = node->callees; e; e = e->next_callee)
+  struct cgraph_edge *e, *next;
+  for (e = node->callees; e; e = next)
     {
       struct inline_edge_summary *es = inline_edge_summary (e);
       struct predicate p;
+      next = e->next_callee;
 
       if (e->inline_failed)
 	{
@@ -3509,10 +3513,11 @@ remap_edge_summaries (struct cgraph_edge
 			      operand_map, offset_map, possible_truths,
 			      toplev_predicate);
     }
-  for (e = node->indirect_calls; e; e = e->next_callee)
+  for (e = node->indirect_calls; e; e = next)
     {
       struct inline_edge_summary *es = inline_edge_summary (e);
       struct predicate p;
+      next = e->next_callee;
 
       remap_edge_change_prob (inlined_edge, e);
       if (es->predicate)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Fix can_inline_edge_p and code marking calls unreachable
  2015-03-27  2:14         ` Jan Hubicka
@ 2015-03-27  9:36           ` Christophe Lyon
  0 siblings, 0 replies; 8+ messages in thread
From: Christophe Lyon @ 2015-03-27  9:36 UTC (permalink / raw)
  To: Jan Hubicka; +Cc: Markus Trippelsdorf, gcc-patches

On 27 March 2015 at 03:14, Jan Hubicka <hubicka@ucw.cz> wrote:
>> On 2015.03.27 at 00:46 +0100, Jan Hubicka wrote:
>> > > On 26 March 2015 at 22:12, Jan Hubicka <hubicka@ucw.cz> wrote:
>> > > After this fix, I can see build failures in glibc:
>> > > key_call.c:574:1: internal compiler error: in inline_call, at
>> > > ipa-inline-transform.c:386
>> >
>> > Can you please send me preprocessed testcase? It is probably another misaccounting
>> > bug in ipa-inline-analysis.  I may just silence this assert for this stage 4.
>>
>> Also happens when building the Linux kernel:
>>
>> trippels@gcc2-power8 linux-3.18.8 % cat nf_sockopt.i
>> int a;
>> int (*b)(), (*c)();
>> int fn1(int p1) {
>>   if (a)
>>     return 0;
>>   if (p1) {
>>     c();
>>     b();
>>   }
>> }
>> void fn2() { fn1(0); }
>
> Great, Markus, having a testcase is important for covering this code path.
> I am attaching a fix, will test it with your testcase and commit.
>
>         * ipa-inline-analysis.c (redirect_to_unreachable): Be prepared for
>         edge to change by speculation resolution or redirection.
>         (edge_set_predicate): Likewise.
>         (inline_summary_t::duplicate): Likewise.
>         (remap_edge_summaries): Likewise.

This commit (221718) does fix the problems I saw, thanks.

Christophe.

> Index: ipa-inline-analysis.c
> ===================================================================
> --- ipa-inline-analysis.c       (revision 221706)
> +++ ipa-inline-analysis.c       (working copy)
> @@ -762,20 +762,20 @@ account_size_time (struct inline_summary
>
>  /* We proved E to be unreachable, redirect it to __bultin_unreachable.  */
>
> -static void
> +static struct cgraph_edge *
>  redirect_to_unreachable (struct cgraph_edge *e)
>  {
>    struct cgraph_node *callee = !e->inline_failed ? e->callee : NULL;
> -  struct inline_edge_summary *es = inline_edge_summary (e);
>
>    if (e->speculative)
> -    e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
> -  if (!e->callee)
> +    e = e->resolve_speculation (builtin_decl_implicit (BUILT_IN_UNREACHABLE));
> +  else if (!e->callee)
>      e->make_direct (cgraph_node::get_create
>                       (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
>    else
>      e->redirect_callee (cgraph_node::get_create
>                         (builtin_decl_implicit (BUILT_IN_UNREACHABLE)));
> +  struct inline_edge_summary *es = inline_edge_summary (e);
>    e->inline_failed = CIF_UNREACHABLE;
>    e->frequency = 0;
>    e->count = 0;
> @@ -783,6 +783,7 @@ redirect_to_unreachable (struct cgraph_e
>    es->call_stmt_time = 0;
>    if (callee)
>      callee->remove_symbol_and_inline_clones ();
> +  return e;
>  }
>
>  /* Set predicate for edge E.  */
> @@ -790,12 +791,12 @@ redirect_to_unreachable (struct cgraph_e
>  static void
>  edge_set_predicate (struct cgraph_edge *e, struct predicate *predicate)
>  {
> -  struct inline_edge_summary *es = inline_edge_summary (e);
> -
>    /* If the edge is determined to be never executed, redirect it
>       to BUILTIN_UNREACHABLE to save inliner from inlining into it.  */
>    if (predicate && false_predicate_p (predicate))
> -    redirect_to_unreachable (e);
> +    e = redirect_to_unreachable (e);
> +
> +  struct inline_edge_summary *es = inline_edge_summary (e);
>    if (predicate && !true_predicate_p (predicate))
>      {
>        if (!es->predicate)
> @@ -1184,7 +1185,7 @@ inline_summary_t::duplicate (cgraph_node
>        size_time_entry *e;
>        int optimized_out_size = 0;
>        bool inlined_to_p = false;
> -      struct cgraph_edge *edge;
> +      struct cgraph_edge *edge, *next;
>
>        info->entry = 0;
>        known_vals.safe_grow_cleared (count);
> @@ -1229,10 +1230,11 @@ inline_summary_t::duplicate (cgraph_node
>
>        /* Remap edge predicates with the same simplification as above.
>           Also copy constantness arrays.   */
> -      for (edge = dst->callees; edge; edge = edge->next_callee)
> +      for (edge = dst->callees; edge; edge = next)
>         {
>           struct predicate new_predicate;
>           struct inline_edge_summary *es = inline_edge_summary (edge);
> +         next = edge->next_callee;
>
>           if (!edge->inline_failed)
>             inlined_to_p = true;
> @@ -1249,10 +1251,11 @@ inline_summary_t::duplicate (cgraph_node
>
>        /* Remap indirect edge predicates with the same simplificaiton as above.
>           Also copy constantness arrays.   */
> -      for (edge = dst->indirect_calls; edge; edge = edge->next_callee)
> +      for (edge = dst->indirect_calls; edge; edge = next)
>         {
>           struct predicate new_predicate;
>           struct inline_edge_summary *es = inline_edge_summary (edge);
> +         next = edge->next_callee;
>
>           gcc_checking_assert (edge->inline_failed);
>           if (!es->predicate)
> @@ -3484,11 +3487,12 @@ remap_edge_summaries (struct cgraph_edge
>                       clause_t possible_truths,
>                       struct predicate *toplev_predicate)
>  {
> -  struct cgraph_edge *e;
> -  for (e = node->callees; e; e = e->next_callee)
> +  struct cgraph_edge *e, *next;
> +  for (e = node->callees; e; e = next)
>      {
>        struct inline_edge_summary *es = inline_edge_summary (e);
>        struct predicate p;
> +      next = e->next_callee;
>
>        if (e->inline_failed)
>         {
> @@ -3509,10 +3513,11 @@ remap_edge_summaries (struct cgraph_edge
>                               operand_map, offset_map, possible_truths,
>                               toplev_predicate);
>      }
> -  for (e = node->indirect_calls; e; e = e->next_callee)
> +  for (e = node->indirect_calls; e; e = next)
>      {
>        struct inline_edge_summary *es = inline_edge_summary (e);
>        struct predicate p;
> +      next = e->next_callee;
>
>        remap_edge_change_prob (inlined_edge, e);
>        if (es->predicate)

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2015-03-27  9:36 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-03-26 18:32 Fix can_inline_edge_p and code marking calls unreachable Jan Hubicka
2015-03-26 21:12 ` Jan Hubicka
2015-03-26 22:58   ` Christophe Lyon
2015-03-26 23:47     ` Jan Hubicka
2015-03-27  2:05       ` Jan Hubicka
2015-03-27  2:09       ` Markus Trippelsdorf
2015-03-27  2:14         ` Jan Hubicka
2015-03-27  9:36           ` Christophe Lyon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).