Move all existing strchr and strrchr folding from builtins.c to gimple-fold.c.

gcc/
        * builtins.c (fold_builtin_strchr): Remove function.
        (fold_builtin_strrchr): Likewise.
        (fold_builtin2): Remove strchr, index, strrchr, rindex cases.
        * gimple-fold.c (target_char_cst_p): New function.
        (gimple_fold_builtin_strchr) Add more foldings.
        (gimple_fold_builtin): Add index, strrchr, rindex cases.

From-SVN: r240782
This commit is contained in:
Wilco Dijkstra 2016-10-05 12:31:05 +00:00 committed by Wilco Dijkstra
parent 92805612f4
commit 71dea1dd60
3 changed files with 71 additions and 137 deletions

View File

@ -1,3 +1,12 @@
2016-10-05 Wilco Dijkstra <wdijkstr@arm.com>
* builtins.c (fold_builtin_strchr): Remove function.
(fold_builtin_strrchr): Likewise.
(fold_builtin2): Remove strchr, index, strrchr, rindex cases.
* gimple-fold.c (target_char_cst_p): New function.
(gimple_fold_builtin_strchr) Add more foldings.
(gimple_fold_builtin): Add index, strrchr, rindex cases.
2016-10-05 Richard Biener <rguenther@suse.de>
PR middle-end/77863

View File

@ -148,7 +148,6 @@ static tree rewrite_call_expr (location_t, tree, int, tree, int, ...);
static bool validate_arg (const_tree, enum tree_code code);
static rtx expand_builtin_fabs (tree, rtx, rtx);
static rtx expand_builtin_signbit (tree, rtx);
static tree fold_builtin_strchr (location_t, tree, tree, tree);
static tree fold_builtin_memchr (location_t, tree, tree, tree, tree);
static tree fold_builtin_memcmp (location_t, tree, tree, tree);
static tree fold_builtin_strcmp (location_t, tree, tree);
@ -168,7 +167,6 @@ 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);
static tree fold_builtin_strrchr (location_t, tree, tree, tree);
static tree fold_builtin_strspn (location_t, tree, tree);
static tree fold_builtin_strcspn (location_t, tree, tree);
@ -8395,14 +8393,6 @@ fold_builtin_2 (location_t loc, tree fndecl, tree arg0, tree arg1)
case BUILT_IN_STRCSPN:
return fold_builtin_strcspn (loc, arg0, arg1);
case BUILT_IN_STRCHR:
case BUILT_IN_INDEX:
return fold_builtin_strchr (loc, arg0, arg1, type);
case BUILT_IN_STRRCHR:
case BUILT_IN_RINDEX:
return fold_builtin_strrchr (loc, arg0, arg1, type);
case BUILT_IN_STRCMP:
return fold_builtin_strcmp (loc, arg0, arg1);
@ -8895,124 +8885,6 @@ fold_builtin_strstr (location_t loc, tree s1, tree s2, tree type)
}
}
/* Simplify a call to the strchr builtin. S1 and S2 are the arguments to
the call, and TYPE is its return type.
Return NULL_TREE if no simplification was possible, otherwise return the
simplified form of the call as a tree.
The simplified form may be a constant or other expression which
computes the same value, but in a more efficient manner (including
calls to other builtin functions).
The call may contain arguments which need to be evaluated, but
which are not useful to determine the result of the call. In
this case we return a chain of COMPOUND_EXPRs. The LHS of each
COMPOUND_EXPR will be an argument which must be evaluated.
COMPOUND_EXPRs are chained through their RHS. The RHS of the last
COMPOUND_EXPR in the chain will contain the tree for the simplified
form of the builtin function call. */
static tree
fold_builtin_strchr (location_t loc, tree s1, tree s2, tree type)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, INTEGER_TYPE))
return NULL_TREE;
else
{
const char *p1;
if (TREE_CODE (s2) != INTEGER_CST)
return NULL_TREE;
p1 = c_getstr (s1);
if (p1 != NULL)
{
char c;
const char *r;
tree tem;
if (target_char_cast (s2, &c))
return NULL_TREE;
r = strchr (p1, c);
if (r == NULL)
return build_int_cst (TREE_TYPE (s1), 0);
/* Return an offset into the constant string argument. */
tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
return fold_convert_loc (loc, type, tem);
}
return NULL_TREE;
}
}
/* Simplify a call to the strrchr builtin. S1 and S2 are the arguments to
the call, and TYPE is its return type.
Return NULL_TREE if no simplification was possible, otherwise return the
simplified form of the call as a tree.
The simplified form may be a constant or other expression which
computes the same value, but in a more efficient manner (including
calls to other builtin functions).
The call may contain arguments which need to be evaluated, but
which are not useful to determine the result of the call. In
this case we return a chain of COMPOUND_EXPRs. The LHS of each
COMPOUND_EXPR will be an argument which must be evaluated.
COMPOUND_EXPRs are chained through their RHS. The RHS of the last
COMPOUND_EXPR in the chain will contain the tree for the simplified
form of the builtin function call. */
static tree
fold_builtin_strrchr (location_t loc, tree s1, tree s2, tree type)
{
if (!validate_arg (s1, POINTER_TYPE)
|| !validate_arg (s2, INTEGER_TYPE))
return NULL_TREE;
else
{
tree fn;
const char *p1;
if (TREE_CODE (s2) != INTEGER_CST)
return NULL_TREE;
p1 = c_getstr (s1);
if (p1 != NULL)
{
char c;
const char *r;
tree tem;
if (target_char_cast (s2, &c))
return NULL_TREE;
r = strrchr (p1, c);
if (r == NULL)
return build_int_cst (TREE_TYPE (s1), 0);
/* Return an offset into the constant string argument. */
tem = fold_build_pointer_plus_hwi_loc (loc, s1, r - p1);
return fold_convert_loc (loc, type, tem);
}
if (! integer_zerop (s2))
return NULL_TREE;
fn = builtin_decl_implicit (BUILT_IN_STRCHR);
if (!fn)
return NULL_TREE;
/* Transform strrchr(s1, '\0') to strchr(s1, '\0'). */
return build_call_expr_loc (loc, fn, 2, s1, s2);
}
}
/* Simplify a call to the strpbrk builtin. S1 and S2 are the arguments
to the call, and TYPE is its return type.

View File

@ -57,6 +57,20 @@ along with GCC; see the file COPYING3. If not see
#include "tree-cfg.h"
/* Return true if T is a constant and the value cast to a target char
can be represented by a host char.
Store the casted char constant in *P if so. */
static bool
target_char_cst_p (tree t, char *p)
{
if (!tree_fits_uhwi_p (t) || CHAR_TYPE_SIZE != HOST_BITS_PER_CHAR)
return false;
*p = (char)tree_to_uhwi (t);
return true;
}
/* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from.
We can get declarations that are not possible to reference for various
@ -1457,22 +1471,60 @@ gimple_fold_builtin_strncpy (gimple_stmt_iterator *gsi,
return true;
}
/* Simplify strchr (str, 0) into str + strlen (str).
/* Fold function call to builtin strchr or strrchr.
If both arguments are constant, evaluate and fold the result,
otherwise simplify str(r)chr (str, 0) into str + strlen (str).
In general strlen is significantly faster than strchr
due to being a simpler operation. */
static bool
gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi)
gimple_fold_builtin_strchr (gimple_stmt_iterator *gsi, bool is_strrchr)
{
gimple *stmt = gsi_stmt (*gsi);
tree str = gimple_call_arg (stmt, 0);
tree c = gimple_call_arg (stmt, 1);
location_t loc = gimple_location (stmt);
const char *p;
char ch;
if (!gimple_call_lhs (stmt))
return false;
if ((p = c_getstr (str)) && target_char_cst_p (c, &ch))
{
const char *p1 = is_strrchr ? strrchr (p, ch) : strchr (p, ch);
if (p1 == NULL)
{
replace_call_with_value (gsi, integer_zero_node);
return true;
}
tree len = build_int_cst (size_type_node, p1 - p);
gimple_seq stmts = NULL;
gimple *new_stmt = gimple_build_assign (gimple_call_lhs (stmt),
POINTER_PLUS_EXPR, str, len);
gimple_seq_add_stmt_without_update (&stmts, new_stmt);
gsi_replace_with_seq_vops (gsi, stmts);
return true;
}
if (!integer_zerop (c))
return false;
/* Transform strrchr (s, 0) to strchr (s, 0) when optimizing for size. */
if (optimize_function_for_size_p (cfun))
return false;
{
tree strchr_fn = builtin_decl_implicit (BUILT_IN_STRCHR);
if (!integer_zerop (c) || !gimple_call_lhs (stmt))
return false;
if (is_strrchr && strchr_fn)
{
gimple *repl = gimple_build_call (strchr_fn, 2, str, c);
replace_call_with_call_and_fold (gsi, repl);
return true;
}
return false;
}
tree len;
tree strlen_fn = builtin_decl_implicit (BUILT_IN_STRLEN);
@ -2947,11 +2999,12 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
gimple_call_arg (stmt, 1));
case BUILT_IN_STRNCAT:
return gimple_fold_builtin_strncat (gsi);
case BUILT_IN_INDEX:
case BUILT_IN_STRCHR:
if (gimple_fold_builtin_strchr (gsi))
return true;
/* Perform additional folding in builtin.c. */
break;
return gimple_fold_builtin_strchr (gsi, false);
case BUILT_IN_RINDEX:
case BUILT_IN_STRRCHR:
return gimple_fold_builtin_strchr (gsi, true);
case BUILT_IN_FPUTS:
return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 1), false);