On Thu, 4 Dec 2014, Richard Biener wrote:

> 
> This is the last patch, moving stpcpy folding.  There are still
> string function foldings left but those are exclusively GENERIC
> now with no chance of advertedly recursing from GIMPLE folding
> via GENERIC folding back to GIMPLE folding.  I'll deal with those
> during next stage1.
> 
> Bootstrapped on x86_64-unknown-linux-gnu, testing in progress.

The following is what I have applied.

Bootstrapped / tested on x86_64-unknown-linux-gnu.

Richard.

2014-12-08  Richard Biener  <rguent...@suse.de>

        * builtins.c (fold_builtin_0): Remove unused ignore parameter.
        (fold_builtin_1): Likewise.
        (fold_builtin_3): Likewise.
        (fold_builtin_varargs): Likewise.
        (fold_builtin_2): Likewise.  Do not fold stpcpy here.
        (fold_builtin_n): Adjust.
        (fold_builtin_stpcpy): Move to gimple-fold.c.
        (gimple_fold_builtin_stpcpy): Moved and gimplified from builtins.c.
        (gimple_fold_builtin): Fold stpcpy here.

Index: trunk/gcc/builtins.c
===================================================================
*** trunk.orig/gcc/builtins.c   2014-12-04 14:24:58.265803955 +0100
--- trunk/gcc/builtins.c        2014-12-04 14:49:45.367752467 +0100
*************** static tree fold_builtin_fabs (location_
*** 191,201 ****
  static tree fold_builtin_abs (location_t, tree, tree);
  static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum 
tree_code,
                                        enum tree_code);
! static tree fold_builtin_0 (location_t, tree, bool);
! static tree fold_builtin_1 (location_t, tree, tree, bool);
! static tree fold_builtin_2 (location_t, tree, tree, tree, bool);
! static tree fold_builtin_3 (location_t, tree, tree, tree, tree, bool);
! static tree fold_builtin_varargs (location_t, tree, tree*, int, bool);
  
  static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
  static tree fold_builtin_strstr (location_t, tree, tree, tree);
--- 191,201 ----
  static tree fold_builtin_abs (location_t, tree, tree);
  static tree fold_builtin_unordered_cmp (location_t, tree, tree, tree, enum 
tree_code,
                                        enum tree_code);
! static tree fold_builtin_0 (location_t, tree);
! static tree fold_builtin_1 (location_t, tree, tree);
! static tree fold_builtin_2 (location_t, tree, tree, tree);
! static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
! static tree fold_builtin_varargs (location_t, tree, tree*, int);
  
  static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
  static tree fold_builtin_strstr (location_t, tree, tree, tree);
*************** fold_builtin_exponent (location_t loc, t
*** 8657,8703 ****
    return NULL_TREE;
  }
  
- /* 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 = builtin_decl_implicit (BUILT_IN_MEMCPY);
-   if (!fn)
-     return NULL_TREE;
- 
-   lenp1 = size_binop_loc (loc, PLUS_EXPR,
-                         fold_convert_loc (loc, size_type_node, len),
-                         build_int_cst (size_type_node, 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));
-   dest = fold_build_pointer_plus_loc (loc, 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 memchr.  ARG1, ARG2 and LEN are the
     arguments to the call, and TYPE is its return type.
     Return NULL_TREE if no simplification can be made.  */
--- 8657,8662 ----
*************** fold_builtin_arith_overflow (location_t
*** 9857,9867 ****
  }
  
  /* Fold a call to built-in function FNDECL with 0 arguments.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_0 (location_t loc, tree fndecl, bool ignore ATTRIBUTE_UNUSED)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
--- 9816,9825 ----
  }
  
  /* Fold a call to built-in function FNDECL with 0 arguments.
!    This function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_0 (location_t loc, tree fndecl)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
*************** fold_builtin_0 (location_t loc, tree fnd
*** 9886,9896 ****
  }
  
  /* Fold a call to built-in function FNDECL with 1 argument, ARG0.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_1 (location_t loc, tree fndecl, tree arg0, bool)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
--- 9844,9853 ----
  }
  
  /* Fold a call to built-in function FNDECL with 1 argument, ARG0.
!    This function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
*************** fold_builtin_1 (location_t loc, tree fnd
*** 10301,10311 ****
  }
  
  /* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
!    IGNORE is true if the result of the function call is ignored.  This
!    function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1, bool 
ignore)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
--- 10258,10267 ----
  }
  
  /* Fold a call to built-in function FNDECL with 2 arguments, ARG0 and ARG1.
!    This function returns NULL_TREE if no simplification was possible.  */
  
  static tree
! fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
*************** fold_builtin_2 (location_t loc, tree fnd
*** 10392,10410 ****
      case BUILT_IN_RINDEX:
        return fold_builtin_strrchr (loc, arg0, arg1, type);
  
-     case BUILT_IN_STPCPY:
-       if (ignore)
-       {
-         tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-         if (!fn)
-           break;
- 
-         return build_call_expr_loc (loc, fn, 2, arg0, arg1);
-       }
-       else
-       return fold_builtin_stpcpy (loc, fndecl, arg0, arg1);
-       break;
- 
      case BUILT_IN_STRCMP:
        return fold_builtin_strcmp (loc, arg0, arg1);
  
--- 10348,10353 ----
*************** fold_builtin_2 (location_t loc, tree fnd
*** 10469,10480 ****
  }
  
  /* Fold a call to built-in function FNDECL with 3 arguments, ARG0, ARG1,
!    and ARG2.  IGNORE is true if the result of the function call is ignored.
     This function returns NULL_TREE if no simplification was possible.  */
  
  static tree
  fold_builtin_3 (location_t loc, tree fndecl,
!               tree arg0, tree arg1, tree arg2, bool)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
--- 10412,10423 ----
  }
  
  /* Fold a call to built-in function FNDECL with 3 arguments, ARG0, ARG1,
!    and ARG2.
     This function returns NULL_TREE if no simplification was possible.  */
  
  static tree
  fold_builtin_3 (location_t loc, tree fndecl,
!               tree arg0, tree arg1, tree arg2)
  {
    tree type = TREE_TYPE (TREE_TYPE (fndecl));
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
*************** fold_builtin_3 (location_t loc, tree fnd
*** 10543,10568 ****
     simplification was possible.  */
  
  tree
! fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool 
ignore)
  {
    tree ret = NULL_TREE;
  
    switch (nargs)
      {
      case 0:
!       ret = fold_builtin_0 (loc, fndecl, ignore);
        break;
      case 1:
!       ret = fold_builtin_1 (loc, fndecl, args[0], ignore);
        break;
      case 2:
!       ret = fold_builtin_2 (loc, fndecl, args[0], args[1], ignore);
        break;
      case 3:
!       ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2], ignore);
        break;
      default:
!       ret = fold_builtin_varargs (loc, fndecl, args, nargs, ignore);
        break;
      }
    if (ret)
--- 10486,10511 ----
     simplification was possible.  */
  
  tree
! fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
  {
    tree ret = NULL_TREE;
  
    switch (nargs)
      {
      case 0:
!       ret = fold_builtin_0 (loc, fndecl);
        break;
      case 1:
!       ret = fold_builtin_1 (loc, fndecl, args[0]);
        break;
      case 2:
!       ret = fold_builtin_2 (loc, fndecl, args[0], args[1]);
        break;
      case 3:
!       ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2]);
        break;
      default:
!       ret = fold_builtin_varargs (loc, fndecl, args, nargs);
        break;
      }
    if (ret)
*************** fold_builtin_object_size (tree ptr, tree
*** 11656,11667 ****
     need special handling; we need to store the arguments in a convenient
     data structure before attempting any folding.  Fortunately there are
     only a few builtins that fall into this category.  FNDECL is the
!    function, EXP is the CALL_EXPR for the call, and IGNORE is true if the
!    result of the function call is ignored.  */
  
  static tree
! fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs,
!                     bool ignore ATTRIBUTE_UNUSED)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
    tree ret = NULL_TREE;
--- 11599,11608 ----
     need special handling; we need to store the arguments in a convenient
     data structure before attempting any folding.  Fortunately there are
     only a few builtins that fall into this category.  FNDECL is the
!    function, EXP is the CALL_EXPR for the call.  */
  
  static tree
! fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs)
  {
    enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
    tree ret = NULL_TREE;
Index: trunk/gcc/gimple-fold.c
===================================================================
*** trunk.orig/gcc/gimple-fold.c        2014-12-04 14:24:58.265803955 +0100
--- trunk/gcc/gimple-fold.c     2014-12-04 14:50:19.438751288 +0100
*************** gimple_fold_builtin_stxncpy_chk (gimple_
*** 2052,2057 ****
--- 2052,2121 ----
    return true;
  }
  
+ /* Fold function call to builtin stpcpy with arguments DEST and SRC.
+    Return NULL_TREE if no simplification can be made.  */
+ 
+ static bool
+ gimple_fold_builtin_stpcpy (gimple_stmt_iterator *gsi)
+ {
+   gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
+   location_t loc = gimple_location (stmt);
+   tree dest = gimple_call_arg (stmt, 0);
+   tree src = gimple_call_arg (stmt, 1);
+   tree fn, len, lenp1;
+ 
+   /* If the result is unused, replace stpcpy with strcpy.  */
+   if (gimple_call_lhs (stmt) == NULL_TREE)
+     {
+       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+       if (!fn)
+       return false;
+       gimple_call_set_fndecl (stmt, fn);
+       fold_stmt (gsi);
+       return true;
+     }
+ 
+   len = c_strlen (src, 1);
+   if (!len
+       || TREE_CODE (len) != INTEGER_CST)
+     return false;
+ 
+   if (optimize_function_for_size_p (cfun)
+       /* If length is zero it's small enough.  */
+       && !integer_zerop (len))
+     return false;
+ 
+   /* If the source has a known length replace stpcpy with memcpy.  */
+   fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
+   if (!fn)
+     return false;
+ 
+   gimple_seq stmts = NULL;
+   tree tem = gimple_convert (&stmts, loc, size_type_node, len);
+   lenp1 = gimple_build (&stmts, loc, PLUS_EXPR, size_type_node,
+                       tem, build_int_cst (size_type_node, 1));
+   gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+   gcall *repl = gimple_build_call (fn, 3, dest, src, lenp1);
+   gimple_set_vuse (repl, gimple_vuse (stmt));
+   gimple_set_vdef (repl, gimple_vdef (stmt));
+   if (gimple_vdef (repl)
+       && TREE_CODE (gimple_vdef (repl)) == SSA_NAME)
+     SSA_NAME_DEF_STMT (gimple_vdef (repl)) = repl;
+   gsi_insert_before (gsi, repl, GSI_SAME_STMT);
+   /* Replace the result with dest + len.  */
+   stmts = NULL;
+   tem = gimple_convert (&stmts, loc, sizetype, len);
+   gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+   gassign *ret = gimple_build_assign (gimple_call_lhs (stmt),
+                                     POINTER_PLUS_EXPR, dest, tem);
+   gsi_replace (gsi, ret, true);
+   /* Finally fold the memcpy call.  */
+   gimple_stmt_iterator gsi2 = *gsi;
+   gsi_prev (&gsi2);
+   fold_stmt (&gsi2);
+   return true;
+ }
+ 
  /* Fold a call EXP to {,v}snprintf having NARGS passed as ARGS.  Return
     NULL_TREE if a normal call should be emitted rather than expanding
     the function inline.  FCODE is either BUILT_IN_SNPRINTF_CHK or
*************** gimple_fold_builtin (gimple_stmt_iterato
*** 2849,2854 ****
--- 2913,2920 ----
                                             gimple_call_arg (stmt, 2),
                                             gimple_call_arg (stmt, 3),
                                             fcode);
+     case BUILT_IN_STPCPY:
+       return gimple_fold_builtin_stpcpy (gsi);
      case BUILT_IN_STRCPY_CHK:
      case BUILT_IN_STPCPY_CHK:
        return gimple_fold_builtin_stxcpy_chk (gsi,

Reply via email to