This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR62090, part 2


The following moves snprintf folding from builtins.c to gimple-fold.c.

Bootstrapped and tested on x86_64-unknown-linux-gnu, applied.

Richard.

2014-08-18  Richard Biener  <rguenther@suse.de>

	PR tree-optimization/62090
	* builtins.c (fold_builtin_snprintf): Move to gimple-fold.c.
	(fold_builtin_3): Do not fold snprintf.
	(fold_builtin_4): Likewise.
	* gimple-fold.c (gimple_fold_builtin_snprintf): New function
	moved from builtins.c.
	(gimple_fold_builtin_with_strlen): Fold snprintf and sprintf.
	(gimple_fold_builtin): Do not fold sprintf here.

	* gcc.dg/pr62090-2.c: New testcase.

Index: gcc/builtins.c
===================================================================
*** gcc/builtins.c.orig	2014-08-18 14:33:16.783737621 +0200
--- gcc/builtins.c	2014-08-18 14:33:28.678736802 +0200
*************** static tree fold_builtin_strrchr (locati
*** 190,196 ****
  static tree fold_builtin_strncat (location_t, tree, tree, tree);
  static tree fold_builtin_strspn (location_t, tree, tree);
  static tree fold_builtin_strcspn (location_t, tree, tree);
- static tree fold_builtin_snprintf (location_t, tree, tree, tree, tree, int);
  
  static rtx expand_builtin_object_size (tree);
  static rtx expand_builtin_memory_chk (tree, rtx, enum machine_mode,
--- 190,195 ----
*************** fold_builtin_3 (location_t loc, tree fnd
*** 10309,10317 ****
      case BUILT_IN_MEMCMP:
        return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
  
-     case BUILT_IN_SNPRINTF:
-       return fold_builtin_snprintf (loc, arg0, arg1, arg2, NULL_TREE, ignore);
- 
      case BUILT_IN_STRCAT_CHK:
        return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2);
  
--- 10308,10313 ----
*************** fold_builtin_4 (location_t loc, tree fnd
*** 10364,10372 ****
      case BUILT_IN_STRNCAT_CHK:
        return fold_builtin_strncat_chk (loc, fndecl, arg0, arg1, arg2, arg3);
  
-     case BUILT_IN_SNPRINTF:
-       return fold_builtin_snprintf (loc, arg0, arg1, arg2, arg3, ignore);
- 
      case BUILT_IN_FPRINTF_CHK:
      case BUILT_IN_VFPRINTF_CHK:
        if (!validate_arg (arg1, INTEGER_TYPE)
--- 10360,10365 ----
*************** fold_builtin_next_arg (tree exp, bool va
*** 11230,11355 ****
  }
  
  
- /* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
-    FMT, and ORIG.  ORIG may be null if this is a 3-argument call.  We don't
-    attempt to simplify calls with more than 4 arguments.
- 
-    Return NULL_TREE if no simplification was possible, otherwise return the
-    simplified form of the call as a tree.  If IGNORED is true, it means that
-    the caller does not use the returned value of the function.  */
- 
- static tree
- fold_builtin_snprintf (location_t loc, tree dest, tree destsize, tree fmt,
- 		       tree orig, int ignored)
- {
-   tree call, retval;
-   const char *fmt_str = NULL;
-   unsigned HOST_WIDE_INT destlen;
- 
-   /* Verify the required arguments in the original call.  We deal with two
-      types of snprintf() calls: 'snprintf (str, cst, fmt)' and
-      'snprintf (dest, cst, "%s", orig)'.  */
-   if (!validate_arg (dest, POINTER_TYPE)
-       || !validate_arg (destsize, INTEGER_TYPE)
-       || !validate_arg (fmt, POINTER_TYPE))
-     return NULL_TREE;
-   if (orig && !validate_arg (orig, POINTER_TYPE))
-     return NULL_TREE;
- 
-   if (!tree_fits_uhwi_p (destsize))
-     return NULL_TREE;
- 
-   /* Check whether the format is a literal string constant.  */
-   fmt_str = c_getstr (fmt);
-   if (fmt_str == NULL)
-     return NULL_TREE;
- 
-   call = NULL_TREE;
-   retval = NULL_TREE;
- 
-   if (!init_target_chars ())
-     return NULL_TREE;
- 
-   destlen = tree_to_uhwi (destsize);
- 
-   /* If the format doesn't contain % args or %%, use strcpy.  */
-   if (strchr (fmt_str, target_percent) == NULL)
-     {
-       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-       size_t len = strlen (fmt_str);
- 
-       /* Don't optimize snprintf (buf, 4, "abc", ptr++).  */
-       if (orig)
- 	return NULL_TREE;
- 
-       /* We could expand this as
- 	 memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
- 	 or to
- 	 memcpy (str, fmt_with_nul_at_cstm1, cst);
- 	 but in the former case that might increase code size
- 	 and in the latter case grow .rodata section too much.
- 	 So punt for now.  */
-       if (len >= destlen)
- 	return NULL_TREE;
- 
-       if (!fn)
- 	return NULL_TREE;
- 
-       /* Convert snprintf (str, cst, fmt) into strcpy (str, fmt) when
- 	 'format' is known to contain no % formats and
- 	 strlen (fmt) < cst.  */
-       call = build_call_expr_loc (loc, fn, 2, dest, fmt);
- 
-       if (!ignored)
- 	retval = build_int_cst (integer_type_node, strlen (fmt_str));
-     }
- 
-   /* If the format is "%s", use strcpy if the result isn't used.  */
-   else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
-     {
-       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
-       unsigned HOST_WIDE_INT origlen;
- 
-       /* Don't crash on snprintf (str1, cst, "%s").  */
-       if (!orig)
- 	return NULL_TREE;
- 
-       retval = c_strlen (orig, 1);
-       if (!retval || !tree_fits_uhwi_p (retval))
- 	return NULL_TREE;
- 
-       origlen = tree_to_uhwi (retval);
-       /* We could expand this as
- 	 memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
- 	 or to
- 	 memcpy (str1, str2_with_nul_at_cstm1, cst);
- 	 but in the former case that might increase code size
- 	 and in the latter case grow .rodata section too much.
- 	 So punt for now.  */
-       if (origlen >= destlen)
- 	return NULL_TREE;
- 
-       /* Convert snprintf (str1, cst, "%s", str2) into
- 	 strcpy (str1, str2) if strlen (str2) < cst.  */
-       if (!fn)
- 	return NULL_TREE;
- 
-       call = build_call_expr_loc (loc, fn, 2, dest, orig);
- 
-       if (ignored)
- 	retval = NULL_TREE;
-     }
- 
-   if (call && retval)
-     {
-       tree fn = builtin_decl_explicit (BUILT_IN_SNPRINTF);
-       retval = fold_convert_loc (loc, TREE_TYPE (TREE_TYPE (fn)), retval);
-       return build2 (COMPOUND_EXPR, TREE_TYPE (retval), call, retval);
-     }
-   else
-     return call;
- }
- 
  /* Expand a call EXP to __builtin_object_size.  */
  
  static rtx
--- 11223,11228 ----
Index: gcc/gimple-fold.c
===================================================================
*** gcc/gimple-fold.c.orig	2014-08-18 14:33:16.802737620 +0200
--- gcc/gimple-fold.c	2014-08-18 14:43:12.832696584 +0200
*************** gimple_fold_builtin_sprintf_chk (gimple_
*** 2091,2097 ****
     the caller does not use the returned value of the function.  */
  
  static bool
! gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi)
  {
    gimple stmt = gsi_stmt (*gsi);
    tree dest = gimple_call_arg (stmt, 0);
--- 2091,2097 ----
     the caller does not use the returned value of the function.  */
  
  static bool
! gimple_fold_builtin_sprintf (gimple_stmt_iterator *gsi, tree orig_len)
  {
    gimple stmt = gsi_stmt (*gsi);
    tree dest = gimple_call_arg (stmt, 0);
*************** gimple_fold_builtin_sprintf (gimple_stmt
*** 2169,2179 ****
        if (!orig)
  	return false;
  
!       tree len = NULL_TREE;
!       if (gimple_call_lhs (stmt))
  	{
! 	  len = c_strlen (orig, 1);
! 	  if (!len)
  	    return false;
  	}
  
--- 2169,2179 ----
        if (!orig)
  	return false;
  
!       if (gimple_call_lhs (stmt)
! 	  && !orig_len)
  	{
! 	  orig_len = c_strlen (orig, 1);
! 	  if (!orig_len)
  	    return false;
  	}
  
*************** gimple_fold_builtin_sprintf (gimple_stmt
*** 2183,2191 ****
        gimple_seq_add_stmt_without_update (&stmts, repl);
        if (gimple_call_lhs (stmt))
  	{
! 	  if (!useless_type_conversion_p (integer_type_node, TREE_TYPE (len)))
! 	    len = fold_convert (integer_type_node, len);
! 	  repl = gimple_build_assign (gimple_call_lhs (stmt), len);
  	  gimple_seq_add_stmt_without_update (&stmts, repl);
  	  gsi_replace_with_seq_vops (gsi, stmts);
  	  /* gsi now points at the assignment to the lhs, get a
--- 2183,2192 ----
        gimple_seq_add_stmt_without_update (&stmts, repl);
        if (gimple_call_lhs (stmt))
  	{
! 	  if (!useless_type_conversion_p (integer_type_node,
! 					  TREE_TYPE (orig_len)))
! 	    orig_len = fold_convert (integer_type_node, orig_len);
! 	  repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len);
  	  gimple_seq_add_stmt_without_update (&stmts, repl);
  	  gsi_replace_with_seq_vops (gsi, stmts);
  	  /* gsi now points at the assignment to the lhs, get a
*************** gimple_fold_builtin_sprintf (gimple_stmt
*** 2206,2212 ****
--- 2207,2353 ----
    return false;
  }
  
+ /* Simplify a call to the snprintf builtin with arguments DEST, DESTSIZE,
+    FMT, and ORIG.  ORIG may be null if this is a 3-argument call.  We don't
+    attempt to simplify calls with more than 4 arguments.
+ 
+    Return NULL_TREE if no simplification was possible, otherwise return the
+    simplified form of the call as a tree.  If IGNORED is true, it means that
+    the caller does not use the returned value of the function.  */
+ 
+ static bool
+ gimple_fold_builtin_snprintf (gimple_stmt_iterator *gsi, tree orig_len)
+ {
+   gimple stmt = gsi_stmt (*gsi);
+   tree dest = gimple_call_arg (stmt, 0);
+   tree destsize = gimple_call_arg (stmt, 1);
+   tree fmt = gimple_call_arg (stmt, 2);
+   tree orig = NULL_TREE;
+   const char *fmt_str = NULL;
+ 
+   if (gimple_call_num_args (stmt) > 4)
+     return false;
+ 
+   if (gimple_call_num_args (stmt) == 4)
+     orig = gimple_call_arg (stmt, 3);
+ 
+   if (!tree_fits_uhwi_p (destsize))
+     return false;
+   unsigned HOST_WIDE_INT destlen = tree_to_uhwi (destsize);
+ 
+   /* Check whether the format is a literal string constant.  */
+   fmt_str = c_getstr (fmt);
+   if (fmt_str == NULL)
+     return false;
+ 
+   if (!init_target_chars ())
+     return false;
+ 
+   /* If the format doesn't contain % args or %%, use strcpy.  */
+   if (strchr (fmt_str, target_percent) == NULL)
+     {
+       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+       if (!fn)
+ 	return false;
  
+       /* Don't optimize snprintf (buf, 4, "abc", ptr++).  */
+       if (orig)
+ 	return false;
+ 
+       /* We could expand this as
+ 	 memcpy (str, fmt, cst - 1); str[cst - 1] = '\0';
+ 	 or to
+ 	 memcpy (str, fmt_with_nul_at_cstm1, cst);
+ 	 but in the former case that might increase code size
+ 	 and in the latter case grow .rodata section too much.
+ 	 So punt for now.  */
+       size_t len = strlen (fmt_str);
+       if (len >= destlen)
+ 	return false;
+ 
+       gimple_seq stmts = NULL;
+       gimple repl = gimple_build_call (fn, 2, dest, fmt);
+       gimple_seq_add_stmt_without_update (&stmts, repl);
+       if (gimple_call_lhs (stmt))
+ 	{
+ 	  repl = gimple_build_assign (gimple_call_lhs (stmt),
+ 				      build_int_cst (integer_type_node, len));
+ 	  gimple_seq_add_stmt_without_update (&stmts, repl);
+ 	  gsi_replace_with_seq_vops (gsi, stmts);
+ 	  /* gsi now points at the assignment to the lhs, get a
+ 	     stmt iterator to the memcpy call.
+ 	     ???  We can't use gsi_for_stmt as that doesn't work when the
+ 	     CFG isn't built yet.  */
+ 	  gimple_stmt_iterator gsi2 = *gsi;
+ 	  gsi_prev (&gsi2);
+ 	  fold_stmt (&gsi2);
+ 	}
+       else
+ 	{
+ 	  gsi_replace_with_seq_vops (gsi, stmts);
+ 	  fold_stmt (gsi);
+ 	}
+       return true;
+     }
+ 
+   /* If the format is "%s", use strcpy if the result isn't used.  */
+   else if (fmt_str && strcmp (fmt_str, target_percent_s) == 0)
+     {
+       tree fn = builtin_decl_implicit (BUILT_IN_STRCPY);
+       if (!fn)
+ 	return false;
+ 
+       /* Don't crash on snprintf (str1, cst, "%s").  */
+       if (!orig)
+ 	return false;
+ 
+       if (!orig_len)
+ 	{
+ 	  orig_len = c_strlen (orig, 1);
+ 	  if (!orig_len)
+ 	    return false;
+ 	}
+ 
+       /* We could expand this as
+ 	 memcpy (str1, str2, cst - 1); str1[cst - 1] = '\0';
+ 	 or to
+ 	 memcpy (str1, str2_with_nul_at_cstm1, cst);
+ 	 but in the former case that might increase code size
+ 	 and in the latter case grow .rodata section too much.
+ 	 So punt for now.  */
+       if (compare_tree_int (orig_len, destlen) >= 0)
+ 	return false;
+ 
+       /* Convert snprintf (str1, cst, "%s", str2) into
+ 	 strcpy (str1, str2) if strlen (str2) < cst.  */
+       gimple_seq stmts = NULL;
+       gimple repl = gimple_build_call (fn, 2, dest, orig);
+       gimple_seq_add_stmt_without_update (&stmts, repl);
+       if (gimple_call_lhs (stmt))
+ 	{
+ 	  if (!useless_type_conversion_p (integer_type_node,
+ 					  TREE_TYPE (orig_len)))
+ 	    orig_len = fold_convert (integer_type_node, orig_len);
+ 	  repl = gimple_build_assign (gimple_call_lhs (stmt), orig_len);
+ 	  gimple_seq_add_stmt_without_update (&stmts, repl);
+ 	  gsi_replace_with_seq_vops (gsi, stmts);
+ 	  /* gsi now points at the assignment to the lhs, get a
+ 	     stmt iterator to the memcpy call.
+ 	     ???  We can't use gsi_for_stmt as that doesn't work when the
+ 	     CFG isn't built yet.  */
+ 	  gimple_stmt_iterator gsi2 = *gsi;
+ 	  gsi_prev (&gsi2);
+ 	  fold_stmt (&gsi2);
+ 	}
+       else
+ 	{
+ 	  gsi_replace_with_seq_vops (gsi, stmts);
+ 	  fold_stmt (gsi);
+ 	}
+       return true;
+     }
+   return false;
+ }
  
  
  /* Fold a call to __builtin_strlen with known length LEN.  */
*************** static bool
*** 2232,2238 ****
  gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi)
  {
    gimple stmt = gsi_stmt (*gsi);
!   tree val[3];
    tree a;
    int arg_idx, type;
    bitmap visited;
--- 2373,2379 ----
  gimple_fold_builtin_with_strlen (gimple_stmt_iterator *gsi)
  {
    gimple stmt = gsi_stmt (*gsi);
!   tree val[4];
    tree a;
    int arg_idx, type;
    bitmap visited;
*************** gimple_fold_builtin_with_strlen (gimple_
*** 2276,2298 ****
        arg_idx = 1;
        type = 2;
        break;
      default:
        return false;
      }
  
    int nargs = gimple_call_num_args (stmt);
-   if (arg_idx >= nargs)
-     return false;
  
    /* Try to use the dataflow information gathered by the CCP process.  */
    visited = BITMAP_ALLOC (NULL);
    bitmap_clear (visited);
  
    memset (val, 0, sizeof (val));
!   a = gimple_call_arg (stmt, arg_idx);
!   if (!get_maxval_strlen (a, &val[arg_idx], visited, type)
!       || !is_gimple_val (val[arg_idx]))
!     val[arg_idx] = NULL_TREE;
  
    BITMAP_FREE (visited);
  
--- 2417,2448 ----
        arg_idx = 1;
        type = 2;
        break;
+     case BUILT_IN_SPRINTF:
+       arg_idx = 2;
+       type = 0;
+       break;
+     case BUILT_IN_SNPRINTF:
+       arg_idx = 3;
+       type = 0;
+       break;
      default:
        return false;
      }
  
    int nargs = gimple_call_num_args (stmt);
  
    /* Try to use the dataflow information gathered by the CCP process.  */
    visited = BITMAP_ALLOC (NULL);
    bitmap_clear (visited);
  
    memset (val, 0, sizeof (val));
!   if (arg_idx < nargs)
!     {
!       a = gimple_call_arg (stmt, arg_idx);
!       if (!get_maxval_strlen (a, &val[arg_idx], visited, type)
! 	  || !is_gimple_val (val[arg_idx]))
! 	val[arg_idx] = NULL_TREE;
!     }
  
    BITMAP_FREE (visited);
  
*************** gimple_fold_builtin_with_strlen (gimple_
*** 2364,2370 ****
      case BUILT_IN_VSNPRINTF_CHK:
        return gimple_fold_builtin_snprintf_chk (gsi, val[1],
  					       DECL_FUNCTION_CODE (callee));
! 
      default:
        gcc_unreachable ();
      }
--- 2514,2523 ----
      case BUILT_IN_VSNPRINTF_CHK:
        return gimple_fold_builtin_snprintf_chk (gsi, val[1],
  					       DECL_FUNCTION_CODE (callee));
!     case BUILT_IN_SNPRINTF:
!       return gimple_fold_builtin_snprintf (gsi, val[3]);
!     case BUILT_IN_SPRINTF:
!       return gimple_fold_builtin_sprintf (gsi, val[2]);
      default:
        gcc_unreachable ();
      }
*************** gimple_fold_builtin (gimple_stmt_iterato
*** 2414,2421 ****
      case BUILT_IN_SPRINTF_CHK:
      case BUILT_IN_VSPRINTF_CHK:
        return gimple_fold_builtin_sprintf_chk (gsi, DECL_FUNCTION_CODE (callee));
-     case BUILT_IN_SPRINTF:
-       return gimple_fold_builtin_sprintf (gsi);
      default:;
      }
  
--- 2567,2572 ----
Index: gcc/testsuite/gcc.dg/pr62090-2.c
===================================================================
*** /dev/null	1970-01-01 00:00:00.000000000 +0000
--- gcc/testsuite/gcc.dg/pr62090-2.c	2014-08-18 14:33:28.689736801 +0200
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do compile } */
+ /* { dg-options "-O2" } */
+ 
+ typedef long unsigned int size_t;
+ extern __inline __attribute__ ((__always_inline__))
+ __attribute__ ((__gnu_inline__)) int
+ snprintf (char *__restrict __s, size_t __n, const char *__restrict __fmt, ...)
+ {
+   return __builtin___snprintf_chk (__s, __n, 2 - 1,
+ 				   __builtin_object_size (__s, 2 > 1),
+ 				   __fmt, __builtin_va_arg_pack ());
+ }
+ typedef struct apacket apacket;
+ struct apacket {
+     unsigned char data[4096];
+ };
+ static size_t fill_connect_data(char *buf, size_t bufsize)
+ {
+   return snprintf(buf, bufsize, "host::") + 1;
+ }
+ unsigned send_connect(apacket *cp)
+ {
+   return fill_connect_data((char *)cp->data, sizeof(cp->data));
+ }


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]