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:
parent
92805612f4
commit
71dea1dd60
3 changed files with 71 additions and 137 deletions
|
@ -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
|
||||
|
|
128
gcc/builtins.c
128
gcc/builtins.c
|
@ -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.
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Reference in a new issue