Commit 488c6247 by Martin Liska Committed by Martin Liska

Fold __builtin_memchr function

	* builtins.h(target_char_cst_p): Declare the function.
	* builtins.c (fold_builtin_memchr): Remove.
	(target_char_cst_p): Move the function from gimple-fold.c.
	(fold_builtin_3): Do not call the function.
	* gimple-fold.c (gimple_fold_builtin_memchr): New function.
	(gimple_fold_builtin): Call the function.
	* fold-const-call.c (fold_const_call_1): Handle CFN_BUILT_IN_MEMCHR.

From-SVN: r241160
parent a918bfbf
2016-10-14 Martin Liska <mliska@suse.cz> 2016-10-14 Martin Liska <mliska@suse.cz>
* builtins.h(target_char_cst_p): Declare the function.
* builtins.c (fold_builtin_memchr): Remove.
(target_char_cst_p): Move the function from gimple-fold.c.
(fold_builtin_3): Do not call the function.
* gimple-fold.c (gimple_fold_builtin_memchr): New function.
(gimple_fold_builtin): Call the function.
* fold-const-call.c (fold_const_call_1): Handle CFN_BUILT_IN_MEMCHR.
2016-10-14 Martin Liska <mliska@suse.cz>
* builtins.c (fold_builtin_strcmp): Remove function. * builtins.c (fold_builtin_strcmp): Remove function.
(fold_builtin_strncmp): Likewise. (fold_builtin_strncmp): Likewise.
(fold_builtin_2): Remove call of the function. (fold_builtin_2): Remove call of the function.
......
...@@ -148,7 +148,6 @@ static tree rewrite_call_expr (location_t, tree, int, tree, int, ...); ...@@ -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 bool validate_arg (const_tree, enum tree_code code);
static rtx expand_builtin_fabs (tree, rtx, rtx); static rtx expand_builtin_fabs (tree, rtx, rtx);
static rtx expand_builtin_signbit (tree, rtx); static rtx expand_builtin_signbit (tree, rtx);
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_memcmp (location_t, tree, tree, tree);
static tree fold_builtin_isascii (location_t, tree); static tree fold_builtin_isascii (location_t, tree);
static tree fold_builtin_toascii (location_t, tree); static tree fold_builtin_toascii (location_t, tree);
...@@ -7242,47 +7241,6 @@ fold_builtin_sincos (location_t loc, ...@@ -7242,47 +7241,6 @@ fold_builtin_sincos (location_t loc,
fold_build1_loc (loc, REALPART_EXPR, type, call))); fold_build1_loc (loc, REALPART_EXPR, type, call)));
} }
/* 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. */
static tree
fold_builtin_memchr (location_t loc, tree arg1, tree arg2, tree len, tree type)
{
if (!validate_arg (arg1, POINTER_TYPE)
|| !validate_arg (arg2, INTEGER_TYPE)
|| !validate_arg (len, INTEGER_TYPE))
return NULL_TREE;
else
{
const char *p1;
if (TREE_CODE (arg2) != INTEGER_CST
|| !tree_fits_uhwi_p (len))
return NULL_TREE;
p1 = c_getstr (arg1);
if (p1 && compare_tree_int (len, strlen (p1) + 1) <= 0)
{
char c;
const char *r;
tree tem;
if (target_char_cast (arg2, &c))
return NULL_TREE;
r = (const char *) memchr (p1, c, tree_to_uhwi (len));
if (r == NULL)
return build_int_cst (TREE_TYPE (arg1), 0);
tem = fold_build_pointer_plus_hwi_loc (loc, arg1, r - p1);
return fold_convert_loc (loc, type, tem);
}
return NULL_TREE;
}
}
/* Fold function call to builtin memcmp with arguments ARG1 and ARG2. /* Fold function call to builtin memcmp with arguments ARG1 and ARG2.
Return NULL_TREE if no simplification can be made. */ Return NULL_TREE if no simplification can be made. */
...@@ -8338,9 +8296,6 @@ fold_builtin_3 (location_t loc, tree fndecl, ...@@ -8338,9 +8296,6 @@ fold_builtin_3 (location_t loc, tree fndecl,
return do_mpfr_remquo (arg0, arg1, arg2); return do_mpfr_remquo (arg0, arg1, arg2);
break; break;
case BUILT_IN_MEMCHR:
return fold_builtin_memchr (loc, arg0, arg1, arg2, type);
case BUILT_IN_BCMP: case BUILT_IN_BCMP:
case BUILT_IN_MEMCMP: case BUILT_IN_MEMCMP:
return fold_builtin_memcmp (loc, arg0, arg1, arg2);; return fold_builtin_memcmp (loc, arg0, arg1, arg2);;
...@@ -9906,3 +9861,17 @@ is_inexpensive_builtin (tree decl) ...@@ -9906,3 +9861,17 @@ is_inexpensive_builtin (tree decl)
return false; return false;
} }
/* 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. */
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;
}
...@@ -97,6 +97,7 @@ extern unsigned HOST_WIDE_INT target_percent; ...@@ -97,6 +97,7 @@ extern unsigned HOST_WIDE_INT target_percent;
extern char target_percent_s[3]; extern char target_percent_s[3];
extern char target_percent_c[3]; extern char target_percent_c[3];
extern char target_percent_s_newline[4]; extern char target_percent_s_newline[4];
extern bool target_char_cst_p (tree t, char *p);
extern internal_fn associated_internal_fn (tree); extern internal_fn associated_internal_fn (tree);
extern internal_fn replacement_internal_fn (gcall *); extern internal_fn replacement_internal_fn (gcall *);
......
...@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "fold-const-call.h" #include "fold-const-call.h"
#include "case-cfn-macros.h" #include "case-cfn-macros.h"
#include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */ #include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */
#include "builtins.h"
/* Functions that test for certain constant types, abstracting away the /* Functions that test for certain constant types, abstracting away the
decision about whether to check for overflow. */ decision about whether to check for overflow. */
...@@ -1463,6 +1464,36 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1, tree arg2) ...@@ -1463,6 +1464,36 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1, tree arg2)
return NULL_TREE; return NULL_TREE;
} }
switch (fn)
{
case CFN_BUILT_IN_MEMCHR:
{
char c;
if (integer_zerop (arg2)
&& !TREE_SIDE_EFFECTS (arg0)
&& !TREE_SIDE_EFFECTS (arg1))
return build_int_cst (type, 0);
if (!tree_fits_uhwi_p (arg2) || !target_char_cst_p (arg1, &c))
return NULL_TREE;
unsigned HOST_WIDE_INT length = tree_to_uhwi (arg2);
unsigned HOST_WIDE_INT string_length;
const char *p1 = c_getstr (arg0, &string_length);
if (p1)
{
const char *r
= (const char *)memchr (p1, c, MIN (length, string_length));
if (r == NULL && length <= string_length)
return build_int_cst (type, 0);
}
break;
}
default:
break;
}
return NULL_TREE; return NULL_TREE;
} }
......
...@@ -57,20 +57,6 @@ along with GCC; see the file COPYING3. If not see ...@@ -57,20 +57,6 @@ along with GCC; see the file COPYING3. If not see
#include "tree-cfg.h" #include "tree-cfg.h"
#include "fold-const-call.h" #include "fold-const-call.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. /* Return true when DECL can be referenced from current unit.
FROM_DECL (if non-null) specify constructor of variable DECL was taken from. 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 We can get declarations that are not possible to reference for various
...@@ -1967,6 +1953,67 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi) ...@@ -1967,6 +1953,67 @@ gimple_fold_builtin_string_compare (gimple_stmt_iterator *gsi)
return false; return false;
} }
/* Fold a call to the memchr pointed by GSI iterator. */
static bool
gimple_fold_builtin_memchr (gimple_stmt_iterator *gsi)
{
gimple *stmt = gsi_stmt (*gsi);
tree lhs = gimple_call_lhs (stmt);
tree arg1 = gimple_call_arg (stmt, 0);
tree arg2 = gimple_call_arg (stmt, 1);
tree len = gimple_call_arg (stmt, 2);
/* If the LEN parameter is zero, return zero. */
if (integer_zerop (len))
{
replace_call_with_value (gsi, build_int_cst (ptr_type_node, 0));
return true;
}
char c;
if (TREE_CODE (arg2) != INTEGER_CST
|| !tree_fits_uhwi_p (len)
|| !target_char_cst_p (arg2, &c))
return false;
unsigned HOST_WIDE_INT length = tree_to_uhwi (len);
unsigned HOST_WIDE_INT string_length;
const char *p1 = c_getstr (arg1, &string_length);
if (p1)
{
const char *r = (const char *)memchr (p1, c, MIN (length, string_length));
if (r == NULL)
{
if (length <= string_length)
{
replace_call_with_value (gsi, build_int_cst (ptr_type_node, 0));
return true;
}
}
else
{
unsigned HOST_WIDE_INT offset = r - p1;
gimple_seq stmts = NULL;
if (lhs != NULL_TREE)
{
tree offset_cst = build_int_cst (TREE_TYPE (len), offset);
gassign *stmt = gimple_build_assign (lhs, POINTER_PLUS_EXPR,
arg1, offset_cst);
gimple_seq_add_stmt_without_update (&stmts, stmt);
}
else
gimple_seq_add_stmt_without_update (&stmts,
gimple_build_nop ());
gsi_replace_with_seq_vops (gsi, stmts);
return true;
}
}
return false;
}
/* Fold a call to the fputs builtin. ARG0 and ARG1 are the arguments /* Fold a call to the fputs builtin. ARG0 and ARG1 are the arguments
to the call. IGNORE is true if the value returned to the call. IGNORE is true if the value returned
...@@ -3194,6 +3241,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi) ...@@ -3194,6 +3241,8 @@ gimple_fold_builtin (gimple_stmt_iterator *gsi)
case BUILT_IN_STRNCMP: case BUILT_IN_STRNCMP:
case BUILT_IN_STRNCASECMP: case BUILT_IN_STRNCASECMP:
return gimple_fold_builtin_string_compare (gsi); return gimple_fold_builtin_string_compare (gsi);
case BUILT_IN_MEMCHR:
return gimple_fold_builtin_memchr (gsi);
case BUILT_IN_FPUTS: case BUILT_IN_FPUTS:
return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0), return gimple_fold_builtin_fputs (gsi, gimple_call_arg (stmt, 0),
gimple_call_arg (stmt, 1), false); gimple_call_arg (stmt, 1), false);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment