RFC: Disentangle builtin folding from expanding

Michael Matz matz@suse.de
Wed Sep 23 18:18:00 GMT 2009


Hi,

so this is my current WIP stuff for separating builtin folding from 
builtin expansion.  I've started by adding a gcc_assert at most expanders 
that called folding routines directly, asserting that nothing was folded, 
and from there started to fix the resulting ICEs.  In addition to that I 
changed some build_call_expr calls (that implicitely call folders) in 
expanders to a new routine build_call_expr_nofold, that really just builds 
a call statement.

Fixing the resulting ICEs needed moving some folding from expand time to, 
well, folding time, e.g. the strcat expander sometimes folded into 
strlen+strcpy, but no, not at folding time :-/  The stpcpy folder (that 
didn't really exist then) needed similar surgery.

Further I made fold_stmt_1 (when inplace is false) possibly emit multiple 
statements, effectively doing what pass_fold_builtin always did.  By 
doing this we can often fold much earlier that waiting until that pass 
(which I moved up to the end of the pipeline).  This in turn required 
changes in some places that uses fold_stmt, in particular the inliner 
needs to go over all emitted insns to see if any of them are calls, and 
substitute_and_fold needs some changes as it walks backwards over the 
instructions and otherwise would hit decls not in SSA form.

(I tried to use an into_ssa gimplify context in 
gimplify_and_update_call_from_tree, but that's theoretically a bit 
dangerous as the folders not necessarily write into temp decls they create 
only once)

Unfortunately I still need the full pass_fold_builtins, as quite some 
passes that propagate stuff around (possibly making a builtin call 
foldable) use fold_stmt_inplace and aren't trivial to change to use 
fold_stmt.  Eventually that should be done, but not in this patch set, it 
requires some surgery on the fold_stmt interface first.

I didn't want to introduce a second pass_fold_builtins, so I moved it very 
late.  That works except for calls to __builtin_constant_p.  Those are a 
bit special: we can't fold them to false too early (we want to wait until 
some cprop was run), so it's nothing we can do right in fold_gimple_stmt.
But we can't fold them too late either, as otherwise dead code isn't 
removed and leads to warnings/errors.  So we can't wait for the (now very 
late) pass_fold_builtins.  I've decided to add this into the first dom 
pass, that's late enough so that usual propagations already occured, but 
early enough that dead code will be eliminated.

This patch as is regstraps on x86_64-linux with all langs+Ada.  As it 
contains all the "gcc_assert (!result)" this means that the expansion now 
doesn't fold anything anymore, a preliminary step for expanding call 
statements from tuples directly.

In a final patch I'll obviously remove all the code that is proved dead 
with the asserts, but wanted to see what others think about all this (and 
the removal makes the patch probably noisy).  No ChangeLog for that 
reason.

Other cleanups that Paolo already listed are still on my list.


Ciao,
Michael.
--
Index: builtins.c
===================================================================
--- builtins.c	(Revision 151906)
+++ builtins.c	(Arbeitskopie)
@@ -117,7 +117,7 @@ static rtx expand_builtin_memcmp (tree,
 static rtx expand_builtin_strcmp (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strncmp (tree, rtx, enum machine_mode);
 static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, enum machine_mode);
-static rtx expand_builtin_strcat (tree, tree, rtx, enum machine_mode);
+static rtx expand_builtin_strcat (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strncat (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strspn (tree, rtx, enum machine_mode);
 static rtx expand_builtin_strcspn (tree, rtx, enum machine_mode);
@@ -2550,6 +2550,22 @@ expand_builtin_cexpi (tree exp, rtx targ
 		      target, VOIDmode, EXPAND_NORMAL);
 }
 
+static tree
+build_call_nofold_loc (location_t loc, tree fndecl, int n, ...)
+{
+  va_list ap;
+  tree fntype = TREE_TYPE (fndecl);
+  tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
+
+  va_start (ap, n);
+  fn = build_call_valist (TREE_TYPE (fntype), fn, n, ap);
+  va_end (ap);
+  SET_EXPR_LOCATION (fn, loc);
+  return fn;
+}
+#define build_call_nofold(...) \
+  build_call_nofold_loc (UNKNOWN_LOCATION, __VA_ARGS__)
+
 /* Expand a call to one of the builtin rounding functions gcc defines
    as an extension (lfloor and lceil).  As these are gcc extensions we
    do not need to worry about setting errno to EDOM.
@@ -2666,7 +2682,7 @@ expand_builtin_int_roundingfn (tree exp,
       fallback_fndecl = build_fn_decl (name, fntype);
     }
 
-  exp = build_call_expr (fallback_fndecl, 1, arg);
+  exp = build_call_nofold (fallback_fndecl, 1, arg);
 
   tmp = expand_normal (exp);
 
@@ -3016,7 +3032,7 @@ expand_builtin_pow (tree exp, rtx target
 	       && powi_cost (n/2) <= POWI_MAX_MULTS)
 	      || n == 1))
 	{
-	  tree call_expr = build_call_expr (fn, 1, narg0);
+	  tree call_expr = build_call_nofold (fn, 1, narg0);
 	  /* Use expand_expr in case the newly built call expression
 	     was folded to a non-call.  */
 	  op = expand_expr (call_expr, subtarget, mode, EXPAND_NORMAL);
@@ -3061,7 +3077,7 @@ expand_builtin_pow (tree exp, rtx target
 	       && powi_cost (n/3) <= POWI_MAX_MULTS)
 	      || n == 1))
 	{
-	  tree call_expr = build_call_expr (fn, 1,narg0);
+	  tree call_expr = build_call_nofold (fn, 1,narg0);
 	  op = expand_builtin (call_expr, NULL_RTX, subtarget, mode, 0);
 	  if (abs (n) % 3 == 2)
 	    op = expand_simple_binop (mode, MULT, op, op, op,
@@ -3272,6 +3288,7 @@ expand_builtin_strstr (tree exp, rtx tar
       tree result = fold_builtin_strstr (EXPR_LOCATION (exp),
 					 CALL_EXPR_ARG (exp, 0),
 					 CALL_EXPR_ARG (exp, 1), type);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -3291,6 +3308,7 @@ expand_builtin_strchr (tree exp, rtx tar
       tree result = fold_builtin_strchr (EXPR_LOCATION (exp),
 					 CALL_EXPR_ARG (exp, 0),
 					 CALL_EXPR_ARG (exp, 1), type);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
 
@@ -3312,6 +3330,7 @@ expand_builtin_strrchr (tree exp, rtx ta
       tree result = fold_builtin_strrchr (EXPR_LOCATION (exp),
 					  CALL_EXPR_ARG (exp, 0),
 					  CALL_EXPR_ARG (exp, 1), type);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -3331,6 +3350,7 @@ expand_builtin_strpbrk (tree exp, rtx ta
       tree result = fold_builtin_strpbrk (EXPR_LOCATION (exp),
 					  CALL_EXPR_ARG (exp, 0),
 					  CALL_EXPR_ARG (exp, 1), type);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -3385,6 +3405,7 @@ expand_builtin_memcpy (tree exp, rtx tar
       unsigned int expected_align = 0;
       tree_ann_common_t ann;
 
+      gcc_assert (!result);
       if (result)
 	{
 	  while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3492,7 +3513,7 @@ expand_builtin_mempcpy_args (tree dest,
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_MEMCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
-      tree result = build_call_expr (fn, 3, dest, src, len);
+      tree result = build_call_nofold (fn, 3, dest, src, len);
 
       while (TREE_CODE (result) == COMPOUND_EXPR)
 	{
@@ -3512,6 +3533,7 @@ expand_builtin_mempcpy_args (tree dest,
       tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
 					    dest, src, len, type, false, endp);
 
+      gcc_assert (!result);
       if (result)
 	{
 	  while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3608,6 +3630,7 @@ expand_builtin_memmove_args (tree dest,
   tree result = fold_builtin_memory_op (UNKNOWN_LOCATION,
 					dest, src, len, type, ignore, /*endp=*/3);
 
+  gcc_assert (!result);
   if (result)
     {
       STRIP_TYPE_NOPS (result);
@@ -3747,6 +3770,7 @@ expand_builtin_strcpy_args (tree fndecl,
 {
   tree result = fold_builtin_strcpy (UNKNOWN_LOCATION,
 				     fndecl, dest, src, 0);
+  gcc_assert (!result);
   if (result)
     return expand_expr (result, target, mode, EXPAND_NORMAL);
   return expand_movstr (dest, src, target, /*endp=*/0);
@@ -3774,7 +3798,7 @@ expand_builtin_stpcpy (tree exp, rtx tar
   if (target == const0_rtx && implicit_built_in_decls[BUILT_IN_STRCPY])
     {
       tree fn = implicit_built_in_decls[BUILT_IN_STRCPY];
-      tree result = build_call_expr (fn, 2, dst, src);
+      tree result = build_call_nofold (fn, 2, dst, src);
 
       STRIP_NOPS (result);
       while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -3873,6 +3897,7 @@ expand_builtin_strncpy (tree exp, rtx ta
       tree result = fold_builtin_strncpy (EXPR_LOCATION (exp),
 					  fndecl, dest, src, len, slen);
 
+      gcc_assert (!result);
       if (result)
 	{
 	  while (TREE_CODE (result) == COMPOUND_EXPR)
@@ -4101,9 +4126,9 @@ expand_builtin_memset_args (tree dest, t
   fndecl = get_callee_fndecl (orig_exp);
   fcode = DECL_FUNCTION_CODE (fndecl);
   if (fcode == BUILT_IN_MEMSET)
-    fn = build_call_expr (fndecl, 3, dest, val, len);
+    fn = build_call_nofold (fndecl, 3, dest, val, len);
   else if (fcode == BUILT_IN_BZERO)
-    fn = build_call_expr (fndecl, 2, dest, len);
+    fn = build_call_nofold (fndecl, 2, dest, len);
   else
     gcc_unreachable ();
   if (TREE_CODE (fn) == CALL_EXPR)
@@ -4151,6 +4176,7 @@ expand_builtin_memchr (tree exp, rtx tar
 					 CALL_EXPR_ARG (exp, 0),
 					 CALL_EXPR_ARG (exp, 1),
 					 CALL_EXPR_ARG (exp, 2), type);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4176,6 +4202,7 @@ expand_builtin_memcmp (tree exp, rtx tar
 					 CALL_EXPR_ARG (exp, 0),
  					 CALL_EXPR_ARG (exp, 1),
  					 CALL_EXPR_ARG (exp, 2));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4287,6 +4314,7 @@ expand_builtin_strcmp (tree exp, rtx tar
       tree result = fold_builtin_strcmp (loc,
 					 CALL_EXPR_ARG (exp, 0),
  					 CALL_EXPR_ARG (exp, 1));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4414,7 +4442,7 @@ expand_builtin_strcmp (tree exp, rtx tar
     do_libcall:
 #endif
       fndecl = get_callee_fndecl (exp);
-      fn = build_call_expr (fndecl, 2, arg1, arg2);
+      fn = build_call_nofold (fndecl, 2, arg1, arg2);
       if (TREE_CODE (fn) == CALL_EXPR)
 	CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
       return expand_call (fn, target, target == const0_rtx);
@@ -4441,6 +4469,7 @@ expand_builtin_strncmp (tree exp, rtx ta
 					  CALL_EXPR_ARG (exp, 0),
  					  CALL_EXPR_ARG (exp, 1),
  					  CALL_EXPR_ARG (exp, 2));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4544,7 +4573,7 @@ expand_builtin_strncmp (tree exp, rtx ta
     /* Expand the library call ourselves using a stabilized argument
        list to avoid re-evaluating the function's arguments twice.  */
     fndecl = get_callee_fndecl (exp);
-    fn = build_call_expr (fndecl, 3, arg1, arg2, len);
+    fn = build_call_nofold (fndecl, 3, arg1, arg2, len);
     if (TREE_CODE (fn) == CALL_EXPR)
       CALL_EXPR_TAILCALL (fn) = CALL_EXPR_TAILCALL (exp);
     return expand_call (fn, target, target == const0_rtx);
@@ -4558,59 +4587,20 @@ expand_builtin_strncmp (tree exp, rtx ta
    otherwise try to get the result in TARGET, if convenient.  */
 
 static rtx
-expand_builtin_strcat (tree fndecl, tree exp, rtx target, enum machine_mode mode)
+expand_builtin_strcat (tree exp, rtx target, enum machine_mode mode)
 {
-  location_t loc = EXPR_LOCATION (exp);
-
   if (!validate_arglist (exp, POINTER_TYPE, POINTER_TYPE, VOID_TYPE))
     return NULL_RTX;
   else
     {
-      tree dst = CALL_EXPR_ARG (exp, 0);
-      tree src = CALL_EXPR_ARG (exp, 1);
-      const char *p = c_getstr (src);
-
-      /* If the string length is zero, return the dst parameter.  */
-      if (p && *p == '\0')
-	return expand_expr (dst, target, mode, EXPAND_NORMAL);
-
-      if (optimize_insn_for_speed_p ())
-	{
-	  /* See if we can store by pieces into (dst + strlen(dst)).  */
-	  tree newsrc, newdst,
-	    strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
-	  rtx insns;
-
-	  /* Stabilize the argument list.  */
-	  newsrc = builtin_save_expr (src);
-	  dst = builtin_save_expr (dst);
-
-	  start_sequence ();
-
-	  /* Create strlen (dst).  */
-	  newdst = build_call_expr (strlen_fn, 1, dst);
-	  /* Create (dst p+ strlen (dst)).  */
-
-	  newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
-				TREE_TYPE (dst), dst, newdst);
-	  newdst = builtin_save_expr (newdst);
-
-	  if (!expand_builtin_strcpy_args (fndecl, newdst, newsrc, target, mode))
-	    {
-	      end_sequence (); /* Stop sequence.  */
-	      return NULL_RTX;
-	    }
-
-	  /* Output the entire sequence.  */
-	  insns = get_insns ();
-	  end_sequence ();
-	  emit_insn (insns);
-
-	  return expand_expr (dst, target, mode, EXPAND_NORMAL);
-	}
-
-      return NULL_RTX;
+      tree result = fold_builtin_strcat (EXPR_LOCATION (exp),
+					 CALL_EXPR_ARG (exp, 0),
+					 CALL_EXPR_ARG (exp, 1));
+      gcc_assert (!result);
+      if (result)
+	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
+  return NULL_RTX;
 }
 
 /* Expand expression EXP, which is a call to the strncat builtin.
@@ -4627,6 +4617,7 @@ expand_builtin_strncat (tree exp, rtx ta
 					  CALL_EXPR_ARG (exp, 0),
 					  CALL_EXPR_ARG (exp, 1),
 					  CALL_EXPR_ARG (exp, 2));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4645,6 +4636,7 @@ expand_builtin_strspn (tree exp, rtx tar
       tree result = fold_builtin_strspn (EXPR_LOCATION (exp),
 					 CALL_EXPR_ARG (exp, 0),
 					 CALL_EXPR_ARG (exp, 1));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -4663,6 +4655,7 @@ expand_builtin_strcspn (tree exp, rtx ta
       tree result = fold_builtin_strcspn (EXPR_LOCATION (exp),
 					  CALL_EXPR_ARG (exp, 0),
 					  CALL_EXPR_ARG (exp, 1));
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, mode, EXPAND_NORMAL);
     }
@@ -5310,6 +5303,7 @@ expand_builtin_fputs (tree exp, rtx targ
  					CALL_EXPR_ARG (exp, 1),
 					(target == const0_rtx),
 					unlocked, NULL_TREE);
+      gcc_assert (!result);
       if (result)
 	return expand_expr (result, target, VOIDmode, EXPAND_NORMAL);
     }
@@ -5475,7 +5469,7 @@ expand_builtin_printf (tree exp, rtx tar
 	  || ! POINTER_TYPE_P (TREE_TYPE (CALL_EXPR_ARG (exp, 1))))
 	return NULL_RTX;
       if (fn_puts)
-	fn = build_call_expr (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
+	fn = build_call_nofold (fn_puts, 1, CALL_EXPR_ARG (exp, 1));
     }
   /* If the format specifier was "%c", call __builtin_putchar(arg).  */
   else if (strcmp (fmt_str, target_percent_c) == 0)
@@ -5484,7 +5478,7 @@ expand_builtin_printf (tree exp, rtx tar
 	  || TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (exp, 1))) != INTEGER_TYPE)
 	return NULL_RTX;
       if (fn_putchar)
-	fn = build_call_expr (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
+	fn = build_call_nofold (fn_putchar, 1, CALL_EXPR_ARG (exp, 1));
     }
   else
     {
@@ -5506,7 +5500,7 @@ expand_builtin_printf (tree exp, rtx tar
 	     function.  */
 	  arg = build_int_cst (NULL_TREE, fmt_str[0]);
 	  if (fn_putchar)
-	    fn = build_call_expr (fn_putchar, 1, arg);
+	    fn = build_call_nofold (fn_putchar, 1, arg);
 	}
       else
 	{
@@ -5521,7 +5515,7 @@ expand_builtin_printf (tree exp, rtx tar
 	      newstr[len - 1] = 0;
 	      arg = build_string_literal (len, newstr);
 	      if (fn_puts)
-		fn = build_call_expr (fn_puts, 1, arg);
+		fn = build_call_nofold (fn_puts, 1, arg);
 	    }
 	  else
 	    /* We'd like to arrange to call fputs(string,stdout) here,
@@ -5587,7 +5581,7 @@ expand_builtin_fprintf (tree exp, rtx ta
 	return NULL_RTX;
       arg = CALL_EXPR_ARG (exp, 2);
       if (fn_fputs)
-	fn = build_call_expr (fn_fputs, 2, arg, fp);
+	fn = build_call_nofold (fn_fputs, 2, arg, fp);
     }
   /* If the format specifier was "%c", call __builtin_fputc(arg,fp).  */
   else if (strcmp (fmt_str, target_percent_c) == 0)
@@ -5597,7 +5591,7 @@ expand_builtin_fprintf (tree exp, rtx ta
 	return NULL_RTX;
       arg = CALL_EXPR_ARG (exp, 2);
       if (fn_fputc)
-	fn = build_call_expr (fn_fputc, 2, arg, fp);
+	fn = build_call_nofold (fn_fputc, 2, arg, fp);
     }
   else
     {
@@ -5620,7 +5614,7 @@ expand_builtin_fprintf (tree exp, rtx ta
 	 fprintf(stream,string) with fputs(string,stream).  The fputs
 	 builtin will take care of special cases like length == 1.  */
       if (fn_fputs)
-	fn = build_call_expr (fn_fputs, 2, fmt, fp);
+	fn = build_call_nofold (fn_fputs, 2, fmt, fp);
     }
 
   if (!fn)
@@ -5668,7 +5662,7 @@ expand_builtin_sprintf (tree exp, rtx ta
 
       if ((nargs > 2) || ! fn)
 	return NULL_RTX;
-      expand_expr (build_call_expr (fn, 2, dest, fmt),
+      expand_expr (build_call_nofold (fn, 2, dest, fmt),
 		   const0_rtx, VOIDmode, EXPAND_NORMAL);
       if (target == const0_rtx)
 	return const0_rtx;
@@ -5698,7 +5692,7 @@ expand_builtin_sprintf (tree exp, rtx ta
       else
 	len = NULL_TREE;
 
-      expand_expr (build_call_expr (fn, 2, dest, arg),
+      expand_expr (build_call_nofold (fn, 2, dest, arg),
 		   const0_rtx, VOIDmode, EXPAND_NORMAL);
 
       if (target == const0_rtx)
@@ -6655,7 +6649,7 @@ expand_builtin (tree exp, rtx target, rt
       break;
 
     case BUILT_IN_STRCAT:
-      target = expand_builtin_strcat (fndecl, exp, target, mode);
+      target = expand_builtin_strcat (exp, target, mode);
       if (target)
 	return target;
       break;
@@ -9289,6 +9283,46 @@ fold_builtin_strcpy (location_t loc, tre
 			   build_call_expr_loc (loc, fn, 3, dest, src, len));
 }
 
+/* Fold function call to builtin stpcpy with arguments DEST and SRC.
+   Return NULL_TREE if no simplification can be made.  */
+
+static tree
+fold_builtin_stpcpy (location_t loc, tree fndecl, tree dest, tree src)
+{
+  tree fn, len, lenp1, call, type;
+
+  if (!validate_arg (dest, POINTER_TYPE)
+      || !validate_arg (src, POINTER_TYPE))
+    return NULL_TREE;
+
+  len = c_strlen (src, 1);
+  if (!len
+      || TREE_CODE (len) != INTEGER_CST)
+    return NULL_TREE;
+
+  if (optimize_function_for_size_p (cfun)
+      /* If length is zero it's small enough.  */
+      && !integer_zerop (len))
+    return NULL_TREE;
+
+  fn = implicit_built_in_decls[BUILT_IN_MEMCPY];
+  if (!fn)
+    return NULL_TREE;
+
+  lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1));
+  /* We use dest twice in building our expression.  Save it from
+     multiple expansions.  */
+  dest = builtin_save_expr (dest);
+  call = build_call_expr_loc (loc, fn, 3, dest, src, lenp1);
+
+  type = TREE_TYPE (TREE_TYPE (fndecl));
+  len = fold_convert_loc (loc, sizetype, len);
+  dest = fold_build2_loc (loc, POINTER_PLUS_EXPR, TREE_TYPE (dest), dest, len);
+  dest = fold_convert_loc (loc, type, dest);
+  dest = omit_one_operand_loc (loc, type, dest, call);
+  return dest;
+}
+
 /* Fold function call to builtin strncpy with arguments DEST, SRC, and LEN.
    If SLEN is not NULL, it represents the length of the source string.
    Return NULL_TREE if no simplification can be made.  */
@@ -10799,6 +10833,8 @@ fold_builtin_2 (location_t loc, tree fnd
 
 	  return build_call_expr_loc (loc, fn, 2, arg0, arg1);
 	}
+      else
+	return fold_builtin_stpcpy (loc, fndecl, arg0, arg1);
       break;
 
     case BUILT_IN_STRCMP:
@@ -11764,6 +11800,42 @@ fold_builtin_strcat (location_t loc ATTR
       if (p && *p == '\0')
 	return dst;
 
+      if (optimize_insn_for_speed_p ())
+	{
+	  /* See if we can store by pieces into (dst + strlen(dst)).  */
+	  tree newdst, call;
+	  tree strlen_fn = implicit_built_in_decls[BUILT_IN_STRLEN];
+	  tree strcpy_fn = implicit_built_in_decls[BUILT_IN_STRCPY];
+
+	  if (!strlen_fn || !strcpy_fn)
+	    return NULL_TREE;
+
+	  /* If we don't have a movstr we don't want to emit an strcpy
+	     call.  We have to do that if the length of the source string
+	     isn't computable (in that case we can use memcpy probably
+	     later expanding to a sequence of mov instructions).  If we 
+	     have movstr instructions we can emit strcpy calls.  */
+	  if (!HAVE_movstr)
+	    {
+	      tree len = c_strlen (src, 1);
+	      if (! len || TREE_SIDE_EFFECTS (len))
+		return NULL_TREE;
+	    }
+
+	  /* Stabilize the argument list.  */
+	  dst = builtin_save_expr (dst);
+
+	  /* Create strlen (dst).  */
+	  newdst = build_call_expr_loc (loc, strlen_fn, 1, dst);
+	  /* Create (dst p+ strlen (dst)).  */
+
+	  newdst = fold_build2_loc (loc, POINTER_PLUS_EXPR,
+				TREE_TYPE (dst), dst, newdst);
+	  newdst = builtin_save_expr (newdst);
+
+	  call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
+	  return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
+	}
       return NULL_TREE;
     }
 }
@@ -12284,7 +12356,7 @@ expand_builtin_memory_chk (tree exp, rtx
       if (! fn)
 	return NULL_RTX;
 
-      fn = build_call_expr (fn, 3, dest, src, len);
+      fn = build_call_nofold (fn, 3, dest, src, len);
       STRIP_TYPE_NOPS (fn);
       while (TREE_CODE (fn) == COMPOUND_EXPR)
 	{
@@ -12339,7 +12411,7 @@ expand_builtin_memory_chk (tree exp, rtx
 	      tree fn = built_in_decls[BUILT_IN_MEMCPY_CHK];
 	      if (!fn)
 		return NULL_RTX;
-	      fn = build_call_expr (fn, 4, dest, src, len, size);
+	      fn = build_call_nofold (fn, 4, dest, src, len, size);
 	      STRIP_TYPE_NOPS (fn);
 	      while (TREE_CODE (fn) == COMPOUND_EXPR)
 		{
Index: passes.c
===================================================================
--- passes.c	(Revision 151906)
+++ passes.c	(Arbeitskopie)
@@ -641,7 +641,6 @@ init_optimization_passes (void)
       NEXT_PASS (pass_object_sizes);
       NEXT_PASS (pass_ccp);
       NEXT_PASS (pass_copy_prop);
-      NEXT_PASS (pass_fold_builtins);
       NEXT_PASS (pass_cse_sincos);
       NEXT_PASS (pass_optimize_bswap);
       NEXT_PASS (pass_split_crit_edges);
@@ -709,6 +708,7 @@ init_optimization_passes (void)
       NEXT_PASS (pass_dse);
       NEXT_PASS (pass_forwprop);
       NEXT_PASS (pass_phiopt);
+      NEXT_PASS (pass_fold_builtins);
       NEXT_PASS (pass_tail_calls);
       NEXT_PASS (pass_rename_ssa_copies);
       NEXT_PASS (pass_uncprop);
Index: tree-inline.c
===================================================================
--- tree-inline.c	(Revision 151906)
+++ tree-inline.c	(Arbeitskopie)
@@ -3873,7 +3873,36 @@ fold_marked_statements (int first, struc
 	      gimple old_stmt = gsi_stmt (gsi);
 	      tree old_decl = is_gimple_call (old_stmt) ? gimple_call_fndecl (old_stmt) : 0;
 
-	      if (fold_stmt (&gsi))
+	      if (old_decl && DECL_BUILT_IN (old_decl))
+		{
+		  /* Folding builtins can create multiple instructions,
+		     we need to look at all of them.  */
+		  gimple_stmt_iterator i2 = gsi;
+		  gsi_prev (&i2);
+		  if (fold_stmt (&gsi))
+		    {
+		      gimple new_stmt;
+		      if (gsi_end_p (i2))
+			i2 = gsi_start_bb (BASIC_BLOCK (first));
+		      else
+			gsi_next (&i2);
+		      while (1)
+			{
+			  new_stmt = gsi_stmt (i2);
+			  update_stmt (new_stmt);
+			  if (is_gimple_call (old_stmt)
+			      || is_gimple_call (new_stmt))
+			    cgraph_update_edges_for_call_stmt (old_stmt, old_decl, new_stmt);
+
+			  if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt))
+			    gimple_purge_dead_eh_edges (BASIC_BLOCK (first));
+			  if (new_stmt == gsi_stmt (gsi))
+			    break;
+			  gsi_next (&i2);
+			}
+		    }
+		}
+	      else if (fold_stmt (&gsi))
 		{
 		  /* Re-read the statement from GSI as fold_stmt() may
 		     have changed it.  */
Index: tree-ssa-ccp.c
===================================================================
--- tree-ssa-ccp.c	(Revision 151906)
+++ tree-ssa-ccp.c	(Arbeitskopie)
@@ -1423,8 +1423,8 @@ evaluate_stmt (gimple stmt)
       else if (code == GIMPLE_SWITCH)
         simplified = gimple_switch_index (stmt);
       else
-        /* These cannot satisfy is_gimple_min_invariant without folding.  */
-        gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
+	/* These cannot satisfy is_gimple_min_invariant without folding.  */
+	gcc_assert (code == GIMPLE_CALL || code == GIMPLE_COND);
     }
 
   is_constant = simplified && is_gimple_min_invariant (simplified);
@@ -2866,6 +2866,7 @@ fold_gimple_cond (gimple stmt)
   return false;
 }
 
+static void gimplify_and_update_call_from_tree (gimple_stmt_iterator *, tree);
 
 /* Attempt to fold a call statement referenced by the statement iterator GSI.
    The statement may be replaced by another statement, e.g., if the call
@@ -2886,7 +2887,11 @@ fold_gimple_call (gimple_stmt_iterator *
       tree result = ccp_fold_builtin (stmt);
 
       if (result)
-        return update_call_from_tree (gsi, result);
+	{
+          if (!update_call_from_tree (gsi, result))
+	    gimplify_and_update_call_from_tree (gsi, result);
+	  return true;
+	}
     }
   else
     {
Index: tree-ssa-dom.c
===================================================================
--- tree-ssa-dom.c	(Revision 151906)
+++ tree-ssa-dom.c	(Arbeitskopie)
@@ -2184,6 +2184,20 @@ optimize_stmt (basic_block bb, gimple_st
     {
       may_have_exposed_new_symbols |= eliminate_redundant_computations (&si);
       stmt = gsi_stmt (si);
+      if (gimple_code (stmt) == GIMPLE_CALL)
+	{
+	  /* Resolve __builtin_constant_p.  If it hasn't been
+	     folded to integer_one_node by now, it's fairly
+	     certain that the value simply isn't constant.  */
+	  tree callee = gimple_call_fndecl (stmt);
+	  if (callee
+	      && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL
+	      && DECL_FUNCTION_CODE (callee) == BUILT_IN_CONSTANT_P)
+	    {
+	      propagate_tree_value_into_stmt (&si, integer_zero_node);
+	      stmt = gsi_stmt (si);
+	    }
+	}
     }
 
   /* Record any additional equivalences created by this statement.  */
Index: tree-ssa-propagate.c
===================================================================
--- tree-ssa-propagate.c	(Revision 151906)
+++ tree-ssa-propagate.c	(Arbeitskopie)
@@ -1069,6 +1069,10 @@ substitute_and_fold (prop_value_t *prop_
 	  gimple stmt = gsi_stmt (i);
 	  gimple old_stmt;
 	  enum gimple_code code = gimple_code (stmt);
+	  gimple_stmt_iterator oldi;
+
+	  oldi = i;
+	  gsi_prev (&i);
 
 	  /* Ignore ASSERT_EXPRs.  They are used by VRP to generate
 	     range information for names and they are discarded
@@ -1076,10 +1080,7 @@ substitute_and_fold (prop_value_t *prop_
 
 	  if (code == GIMPLE_ASSIGN
 	      && TREE_CODE (gimple_assign_rhs1 (stmt)) == ASSERT_EXPR)
-	    {
-	      gsi_prev (&i);
-	      continue;
-	    }
+	    continue;
 
 	  /* No point propagating into a stmt whose result is not used,
 	     but instead we might be able to remove a trivially dead stmt.  */
@@ -1098,7 +1099,6 @@ substitute_and_fold (prop_value_t *prop_
 		  fprintf (dump_file, "\n");
 		}
 	      prop_stats.num_dce++;
-	      gsi_prev (&i);
 	      i2 = gsi_for_stmt (stmt);
 	      gsi_remove (&i2, true);
 	      release_defs (stmt);
@@ -1118,9 +1118,9 @@ substitute_and_fold (prop_value_t *prop_
 	     predicate expressions.  */
 	  if (use_ranges_p)
 	    {
-	      did_replace = fold_predicate_in (&i);
+	      did_replace = fold_predicate_in (&oldi);
 	      /* fold_predicate_in should not have reallocated STMT.  */
-	      gcc_assert (gsi_stmt (i) == stmt);
+	      gcc_assert (gsi_stmt (oldi) == stmt);
 	    }
 
 	  /* Only replace real uses if we couldn't fold the
@@ -1133,7 +1133,7 @@ substitute_and_fold (prop_value_t *prop_
 
 	  old_stmt = stmt;
 	  if (did_replace)
-	    fold_stmt (&i);
+	    fold_stmt (&oldi);
 
 	  /* Some statements may be simplified using ranges.  For
 	     example, division may be replaced by shifts, modulo
@@ -1142,12 +1142,12 @@ substitute_and_fold (prop_value_t *prop_
 	     presented with a fully propagated, canonicalized
 	     statement.  */
 	  if (use_ranges_p)
-	    did_replace |= simplify_stmt_using_ranges (&i);
+	    did_replace |= simplify_stmt_using_ranges (&oldi);
 
 	  /* Now cleanup.  */
 	  if (did_replace)
 	    {
-	      stmt = gsi_stmt (i);
+	      stmt = gsi_stmt (oldi);
 
               /* If we cleaned up EH information from the statement,
                  remove EH edges.  */
@@ -1181,8 +1181,6 @@ substitute_and_fold (prop_value_t *prop_
 	      else
 		fprintf (dump_file, "Not folded\n");
 	    }
-
-	  gsi_prev (&i);
 	}
     }
 



More information about the Gcc-patches mailing list