[PATCH][RFC] Fix PR59860

Richard Biener rguenther@suse.de
Mon Jan 20 14:53:00 GMT 2014


On Mon, 20 Jan 2014, Jakub Jelinek wrote:

> On Mon, Jan 20, 2014 at 02:37:21PM +0100, Richard Biener wrote:
> > Well, strcat itself can do that ... but yes, as I said, if you can
> > CSE that strlen call then it's a win.  But you can't know this without
> 
> It can't, strcat doesn't know the length of the src string, we don't have
> any 3 argument strcat alternative API where the compiler tells it the length
> of the string that the compiler knows, but the function doesn't.
> 
> > > Normally, if folding of a builtin folds it into a call to some other
> > > builtin, that other builtin is folded right away, so the common case is
> > > optimized immediately, the only problem is if gimple_fold_builtin tries
> > > harder to optimize using maximum lengths or exact length (as in this case).
> > > And, for this it wouldn't even help if we handled STRCAT/STRCAT_CHK
> > > specially too and passed the src length to the folder routine, because
> > > gimple_fold_builtin first folds normally and only if that fails, attempts
> > > harder.
> > 
> > But we still can re-introduce the folding I removed from builtins.c
> > below the avoid_folding_inline_builtin section as in that case
> > builtins.c didn't do the folding and the gimple folding has
> > strictly more information.  No?  I don't really like a special
> 
> There are two cases.  One is where the length of the second string
> is really variable or not known to the compiler.  Then I agree library
> strcat ought to do the exact same job, it is strlen + movstr instruction.
> The other case is your testcase, where it is just because the compiler did a
> poor job.  I guess we can use something like following untested patch
> for that.  Or supposedly we could only change fold_builtin_strcat and
> leave strcat_chk unmodified, after all strcat_chk folding is only handling
> the case where the size is -1UL (i.e. unknown) and then folds to strcat.

That works for me.

Richard.

> 2014-01-20  Jakub Jelinek  <jakub@redhat.com>
> 
> 	* tree.h (fold_builtin_strcat, fold_builtin_strcat_chk): New
> 	prototypes.
> 	* builtins.c (fold_builtin_strcat): No longer static.  Add len
> 	argument, if non-NULL, don't call c_strlen.  Optimize
> 	directly into __builtin_memcpy instead of __builtin_strcpy.
> 	(fold_builtin_strcat_chk): No longer static.  Add len argument,
> 	if non-NULL, call fold_builtin_strcat.
> 	(fold_builtin_2): Adjust fold_builtin_strcat{,_chk} callers.
> 	* gimple-fold.c (gimple_fold_builtin): Handle BUILT_IN_STRCAT
> 	and BUILT_IN_STRCAT_CHK.
> 
> --- gcc/tree.h.jj	2014-01-07 17:49:40.000000000 +0100
> +++ gcc/tree.h	2014-01-20 15:04:48.273418236 +0100
> @@ -5854,12 +5854,14 @@ extern tree fold_call_expr (location_t,
>  extern tree fold_builtin_fputs (location_t, tree, tree, bool, bool, tree);
>  extern tree fold_builtin_strcpy (location_t, tree, tree, tree, tree);
>  extern tree fold_builtin_strncpy (location_t, tree, tree, tree, tree, tree);
> +extern tree fold_builtin_strcat (location_t, tree, tree, tree);
>  extern tree fold_builtin_memory_chk (location_t, tree, tree, tree, tree, tree, tree, bool,
>  				     enum built_in_function);
>  extern tree fold_builtin_stxcpy_chk (location_t, tree, tree, tree, tree, tree, bool,
>  				     enum built_in_function);
>  extern tree fold_builtin_stxncpy_chk (location_t, tree, tree, tree, tree, tree, bool,
>  				      enum built_in_function);
> +extern tree fold_builtin_strcat_chk (location_t, tree, tree, tree, tree, tree);
>  extern tree fold_builtin_snprintf_chk (location_t, tree, tree, enum built_in_function);
>  extern bool fold_builtin_next_arg (tree, bool);
>  extern enum built_in_function builtin_mathfn_code (const_tree);
> --- gcc/builtins.c.jj	2014-01-20 12:41:48.000000000 +0100
> +++ gcc/builtins.c	2014-01-20 15:19:23.585947825 +0100
> @@ -180,7 +180,6 @@ static tree fold_builtin_varargs (locati
>  static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
>  static tree fold_builtin_strstr (location_t, tree, tree, tree);
>  static tree fold_builtin_strrchr (location_t, tree, tree, tree);
> -static tree fold_builtin_strcat (location_t, tree, tree);
>  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);
> @@ -194,7 +193,6 @@ static void maybe_emit_chk_warning (tree
>  static void maybe_emit_sprintf_chk_warning (tree, enum built_in_function);
>  static void maybe_emit_free_warning (tree);
>  static tree fold_builtin_object_size (tree, tree);
> -static tree fold_builtin_strcat_chk (location_t, tree, tree, tree, tree);
>  static tree fold_builtin_strncat_chk (location_t, tree, tree, tree, tree, tree);
>  static tree fold_builtin_sprintf_chk (location_t, tree, enum built_in_function);
>  static tree fold_builtin_printf (location_t, tree, tree, tree, bool, enum built_in_function);
> @@ -10770,7 +10768,7 @@ fold_builtin_2 (location_t loc, tree fnd
>        return fold_builtin_strstr (loc, arg0, arg1, type);
>  
>      case BUILT_IN_STRCAT:
> -      return fold_builtin_strcat (loc, arg0, arg1);
> +      return fold_builtin_strcat (loc, arg0, arg1, NULL_TREE);
>  
>      case BUILT_IN_STRSPN:
>        return fold_builtin_strspn (loc, arg0, arg1);
> @@ -10963,7 +10961,8 @@ fold_builtin_3 (location_t loc, tree fnd
>  				      ignore, fcode);
>  
>      case BUILT_IN_STRCAT_CHK:
> -      return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1, arg2);
> +      return fold_builtin_strcat_chk (loc, fndecl, arg0, arg1,
> +				      NULL_TREE, arg2);
>  
>      case BUILT_IN_PRINTF_CHK:
>      case BUILT_IN_VPRINTF_CHK:
> @@ -11813,8 +11812,9 @@ fold_builtin_strpbrk (location_t loc, tr
>     COMPOUND_EXPR in the chain will contain the tree for the simplified
>     form of the builtin function call.  */
>  
> -static tree
> -fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src)
> +tree
> +fold_builtin_strcat (location_t loc ATTRIBUTE_UNUSED, tree dst, tree src,
> +		     tree len)
>  {
>    if (!validate_arg (dst, POINTER_TYPE)
>        || !validate_arg (src, POINTER_TYPE))
> @@ -11832,14 +11832,15 @@ fold_builtin_strcat (location_t loc ATTR
>  	  /* See if we can store by pieces into (dst + strlen(dst)).  */
>  	  tree newdst, call;
>  	  tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
> -	  tree strcpy_fn = builtin_decl_implicit (BUILT_IN_STRCPY);
> +	  tree memcpy_fn = builtin_decl_implicit (BUILT_IN_MEMCPY);
>  
> -	  if (!strlen_fn || !strcpy_fn)
> +	  if (!strlen_fn || !memcpy_fn)
>  	    return NULL_TREE;
>  
>  	  /* If the length of the source string isn't computable don't
> -	     split strcat into strlen and strcpy.  */
> -	  tree len = c_strlen (src, 1);
> +	     split strcat into strlen and memcpy.  */
> +	  if (! len)
> +	    len = c_strlen (src, 1);
>  	  if (! len || TREE_SIDE_EFFECTS (len))
>  	    return NULL_TREE;
>  
> @@ -11853,7 +11854,11 @@ fold_builtin_strcat (location_t loc ATTR
>  	  newdst = fold_build_pointer_plus_loc (loc, dst, newdst);
>  	  newdst = builtin_save_expr (newdst);
>  
> -	  call = build_call_expr_loc (loc, strcpy_fn, 2, newdst, src);
> +	  len = fold_convert_loc (loc, size_type_node, len);
> +	  len = size_binop_loc (loc, PLUS_EXPR, len,
> +				build_int_cst (size_type_node, 1));
> +
> +	  call = build_call_expr_loc (loc, memcpy_fn, 3, newdst, src, len);
>  	  return build2 (COMPOUND_EXPR, TREE_TYPE (dst), call, dst);
>  	}
>        return NULL_TREE;
> @@ -13005,9 +13010,9 @@ fold_builtin_stxncpy_chk (location_t loc
>  /* Fold a call to the __strcat_chk builtin FNDECL.  DEST, SRC, and SIZE
>     are the arguments to the call.  */
>  
> -static tree
> +tree
>  fold_builtin_strcat_chk (location_t loc, tree fndecl, tree dest,
> -			 tree src, tree size)
> +			 tree src, tree len, tree size)
>  {
>    tree fn;
>    const char *p;
> @@ -13030,6 +13035,12 @@ fold_builtin_strcat_chk (location_t loc,
>    if (!fn)
>      return NULL_TREE;
>  
> +  if (len)
> +    {
> +      tree ret = fold_builtin_strcat (loc, dest, src, len);
> +      if (ret)
> +	return ret;
> +    }
>    return build_call_expr_loc (loc, fn, 2, dest, src);
>  }
>  
> --- gcc/gimple-fold.c.jj	2013-11-05 13:06:02.000000000 +0100
> +++ gcc/gimple-fold.c	2014-01-20 15:12:42.297991142 +0100
> @@ -866,6 +866,8 @@ gimple_fold_builtin (gimple stmt)
>        break;
>      case BUILT_IN_STRCPY:
>      case BUILT_IN_STRNCPY:
> +    case BUILT_IN_STRCAT:
> +    case BUILT_IN_STRCAT_CHK:
>        arg_idx = 1;
>        type = 0;
>        break;
> @@ -941,6 +943,22 @@ gimple_fold_builtin (gimple stmt)
>  				       val[1]);
>        break;
>  
> +    case BUILT_IN_STRCAT:
> +      if (val[1] && is_gimple_val (val[1]) && nargs == 2)
> +	result = fold_builtin_strcat (loc, gimple_call_arg (stmt, 0),
> +                                      gimple_call_arg (stmt, 1),
> +				      val[1]);
> +      break;
> +
> +    case BUILT_IN_STRCAT_CHK:
> +      if (val[1] && is_gimple_val (val[1]) && nargs == 3)
> +	result = fold_builtin_strcat_chk (loc, callee,
> +					  gimple_call_arg (stmt, 0),
> +					  gimple_call_arg (stmt, 1),
> +					  val[1],
> +					  gimple_call_arg (stmt, 2));
> +      break;
> +
>      case BUILT_IN_FPUTS:
>        if (nargs == 2)
>  	result = fold_builtin_fputs (loc, gimple_call_arg (stmt, 0),
> 
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer



More information about the Gcc-patches mailing list