diff mbox series

Handle builtin_expect better in ipa-fnsummary

Message ID 20190106235637.dh4gqfhzgfsakxsi@kam.mff.cuni.cz
State New
Headers show
Series Handle builtin_expect better in ipa-fnsummary | expand

Commit Message

Jan Hubicka Jan. 6, 2019, 11:56 p.m. UTC
Hi,
while analyzing Firefox I noticed that it uses builtin_expect quite
extensively and this sometimes causes ipa-predicates to be computed very
conservatively.  There are more possible improvements, but I will leave
it for stage1. This handles the common case where builtin_expect is
applied to parameter.

Bootstrapped/regtested x86_64-linux, will commit it later for tester to
catch up.

Honza

	* ipa-fnsummary.c (builtin_expect_call_p, strip_copies): New function.
	(unmodified_parm, unmodified_parm_or_parm_agg_item,
	will_be_nonconstant_expr_predicate): Use it.
diff mbox series

Patch

Index: ipa-fnsummary.c
===================================================================
--- ipa-fnsummary.c	(revision 267610)
+++ ipa-fnsummary.c	(working copy)
@@ -936,6 +936,57 @@  mark_modified (ao_ref *ao ATTRIBUTE_UNUS
   return true;
 }
 
+/* Return ture if STMT is builtin_expect on one of its variants.  */
+
+static bool
+builtin_expect_call_p (gimple *stmt)
+{
+  return ((gimple_call_builtin_p (stmt, BUILT_IN_EXPECT)
+	   || gimple_call_builtin_p (stmt, BUILT_IN_EXPECT_WITH_PROBABILITY)
+	   || gimple_call_internal_p (stmt, IFN_BUILTIN_EXPECT))
+	  && gimple_call_num_args (stmt));
+}
+
+/* Walk to the original assignment to OP skipping wrapping noop casts,
+   builtin expectes etc.  */
+
+static tree
+strip_copies (tree op, gimple **stmt = NULL)
+{
+  STRIP_NOPS (op);
+  /* TODO: We should have some common way to tell if function returns its
+     argument.  */
+  if (TREE_CODE (op) == CALL_EXPR)
+    {
+      tree fndecl = get_callee_fndecl (op);
+      if (!fndecl)
+	return op;
+      if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+	  && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_EXPECT
+	      || DECL_FUNCTION_CODE (fndecl)
+			 == BUILT_IN_EXPECT_WITH_PROBABILITY))
+	return strip_copies (CALL_EXPR_ARG (op, 0), stmt);
+      return op;
+    }
+  if (TREE_CODE (op) == SSA_NAME
+      && builtin_expect_call_p (SSA_NAME_DEF_STMT (op)))
+    {
+      if (stmt)
+	*stmt = SSA_NAME_DEF_STMT (op);
+      return strip_copies (gimple_call_arg (SSA_NAME_DEF_STMT (op), 0), stmt);
+    }
+  if (TREE_CODE (op) == SSA_NAME
+      && !SSA_NAME_IS_DEFAULT_DEF (op)
+      && gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
+    {
+      if (stmt)
+	*stmt = SSA_NAME_DEF_STMT (op);
+      return strip_copies (gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)),
+			  stmt);
+    }
+  return op;
+}
+
 /* If OP refers to value of function parameter, return the corresponding
    parameter.  If non-NULL, the size of the memory load (or the SSA_NAME of the
    PARM_DECL) will be stored to *SIZE_P in that case too.  */
@@ -979,16 +1030,10 @@  unmodified_parm_1 (gimple *stmt, tree op
 static tree
 unmodified_parm (gimple *stmt, tree op, HOST_WIDE_INT *size_p)
 {
+  op = strip_copies (op, &stmt);
   tree res = unmodified_parm_1 (stmt, op, size_p);
   if (res)
     return res;
-
-  if (TREE_CODE (op) == SSA_NAME
-      && !SSA_NAME_IS_DEFAULT_DEF (op)
-      && gimple_assign_single_p (SSA_NAME_DEF_STMT (op)))
-    return unmodified_parm (SSA_NAME_DEF_STMT (op),
-			    gimple_assign_rhs1 (SSA_NAME_DEF_STMT (op)),
-			    size_p);
   return NULL_TREE;
 }
 
@@ -1005,6 +1050,7 @@  unmodified_parm_or_parm_agg_item (struct
 				  HOST_WIDE_INT *size_p,
 				  struct agg_position_info *aggpos)
 {
+  op = strip_copies (op, &stmt);
   tree res = unmodified_parm_1 (stmt, op, size_p);
 
   gcc_checking_assert (aggpos);
@@ -1450,12 +1496,13 @@  will_be_nonconstant_expr_predicate (stru
 					       nonconstant_names);
       return p2.or_with (summary->conds, p1);
     }
-  else if (TREE_CODE (expr) == CALL_EXPR)
-    return true;
-  else
+  else 
     {
-      debug_tree (expr);
-      gcc_unreachable ();
+      tree expr2 = strip_copies (expr);
+      if (expr2 != expr)
+	return will_be_nonconstant_expr_predicate (info, summary, expr2,
+						   nonconstant_names);
+      return true;
     }
   return false;
 }