+2015-11-07 Richard Sandiford <richard.sandiford@arm.com>
+
+ * builtins.c (fold_builtin_nan): Delete.
+ (fold_builtin_memcmp): Remove case where both arguments are constant.
+ (fold_builtin_strcmp, fold_builtin_strncmp): Likewise.
+ (fold_builtin_strspn, fold_builtin_strcspn): Likewise.
+ (fold_builtin_1): Remove BUILT_IN_NAN* handling.
+ * fold-const-call.c: Include fold-const.h.
+ (host_size_t_cst_p): New function.
+ (build_cmp_result, fold_const_builtin_nan): Likewise.
+ (fold_const_call_1): New function, split out from...
+ (fold_const_call): ...here (for all three interfaces). Handle
+ constant nan, nans, strlen, strcmp, strncmp, strspn and strcspn.
+
2015-11-07 Richard Sandiford <richard.sandiford@arm.com>
* builtins.c (fold_builtin_bitop, fold_builtin_bswap): Delete.
static tree fold_builtin_classify_type (tree);
static tree fold_builtin_strlen (location_t, tree, tree);
static tree fold_builtin_inf (location_t, tree, int);
-static tree fold_builtin_nan (tree, tree, int);
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);
return build_real (type, real);
}
-/* Fold a call to __builtin_nan or __builtin_nans with argument ARG. */
-
-static tree
-fold_builtin_nan (tree arg, tree type, int quiet)
-{
- REAL_VALUE_TYPE real;
- const char *str;
-
- if (!validate_arg (arg, POINTER_TYPE))
- return NULL_TREE;
- str = c_getstr (arg);
- if (!str)
- return NULL_TREE;
-
- if (!real_nan (&real, str, quiet, TYPE_MODE (type)))
- return NULL_TREE;
-
- return build_real (type, real);
-}
-
/* Fold function call to builtin sincos, sincosf, or sincosl. Return
NULL_TREE if no simplification can be made. */
static tree
fold_builtin_memcmp (location_t loc, tree arg1, tree arg2, tree len)
{
- const char *p1, *p2;
-
if (!validate_arg (arg1, POINTER_TYPE)
|| !validate_arg (arg2, POINTER_TYPE)
|| !validate_arg (len, INTEGER_TYPE))
if (operand_equal_p (arg1, arg2, 0))
return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
-
- /* If all arguments are constant, and the value of len is not greater
- than the lengths of arg1 and arg2, evaluate at compile-time. */
- if (tree_fits_uhwi_p (len) && p1 && p2
- && compare_tree_int (len, strlen (p1) + 1) <= 0
- && compare_tree_int (len, strlen (p2) + 1) <= 0)
- {
- const int r = memcmp (p1, p2, tree_to_uhwi (len));
-
- if (r > 0)
- return integer_one_node;
- else if (r < 0)
- return integer_minus_one_node;
- else
- return integer_zero_node;
- }
-
/* If len parameter is one, return an expression corresponding to
(*(const unsigned char*)arg1 - (const unsigned char*)arg2). */
if (tree_fits_uhwi_p (len) && tree_to_uhwi (len) == 1)
static tree
fold_builtin_strcmp (location_t loc, tree arg1, tree arg2)
{
- const char *p1, *p2;
-
if (!validate_arg (arg1, POINTER_TYPE)
|| !validate_arg (arg2, POINTER_TYPE))
return NULL_TREE;
if (operand_equal_p (arg1, arg2, 0))
return integer_zero_node;
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
-
- if (p1 && p2)
- {
- const int i = strcmp (p1, p2);
- if (i < 0)
- return integer_minus_one_node;
- else if (i > 0)
- return integer_one_node;
- else
- return integer_zero_node;
- }
-
/* If the second arg is "", return *(const unsigned char*)arg1. */
+ const char *p2 = c_getstr (arg2);
if (p2 && *p2 == '\0')
{
tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
}
/* If the first arg is "", return -*(const unsigned char*)arg2. */
+ const char *p1 = c_getstr (arg1);
if (p1 && *p1 == '\0')
{
tree cst_uchar_node = build_type_variant (unsigned_char_type_node, 1, 0);
static tree
fold_builtin_strncmp (location_t loc, tree arg1, tree arg2, tree len)
{
- const char *p1, *p2;
-
if (!validate_arg (arg1, POINTER_TYPE)
|| !validate_arg (arg2, POINTER_TYPE)
|| !validate_arg (len, INTEGER_TYPE))
if (operand_equal_p (arg1, arg2, 0))
return omit_one_operand_loc (loc, integer_type_node, integer_zero_node, len);
- p1 = c_getstr (arg1);
- p2 = c_getstr (arg2);
-
- if (tree_fits_uhwi_p (len) && p1 && p2)
- {
- const int i = strncmp (p1, p2, tree_to_uhwi (len));
- if (i > 0)
- return integer_one_node;
- else if (i < 0)
- return integer_minus_one_node;
- else
- return integer_zero_node;
- }
-
/* If the second arg is "", and the length is greater than zero,
return *(const unsigned char*)arg1. */
+ const char *p2 = c_getstr (arg2);
if (p2 && *p2 == '\0'
&& TREE_CODE (len) == INTEGER_CST
&& tree_int_cst_sgn (len) == 1)
/* If the first arg is "", and the length is greater than zero,
return -*(const unsigned char*)arg2. */
+ const char *p1 = c_getstr (arg1);
if (p1 && *p1 == '\0'
&& TREE_CODE (len) == INTEGER_CST
&& tree_int_cst_sgn (len) == 1)
CASE_FLT_FN (BUILT_IN_CARG):
return fold_builtin_carg (loc, arg0, type);
- CASE_FLT_FN (BUILT_IN_NAN):
- case BUILT_IN_NAND32:
- case BUILT_IN_NAND64:
- case BUILT_IN_NAND128:
- return fold_builtin_nan (arg0, type, true);
-
- CASE_FLT_FN (BUILT_IN_NANS):
- return fold_builtin_nan (arg0, type, false);
-
case BUILT_IN_ISASCII:
return fold_builtin_isascii (loc, arg0);
{
const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
- /* If both arguments are constants, evaluate at compile-time. */
- if (p1 && p2)
- {
- const size_t r = strspn (p1, p2);
- return build_int_cst (size_type_node, r);
- }
-
/* If either argument is "", return NULL_TREE. */
if ((p1 && *p1 == '\0') || (p2 && *p2 == '\0'))
/* Evaluate and ignore both arguments in case either one has
return NULL_TREE;
else
{
- const char *p1 = c_getstr (s1), *p2 = c_getstr (s2);
-
- /* If both arguments are constants, evaluate at compile-time. */
- if (p1 && p2)
- {
- const size_t r = strcspn (p1, p2);
- return build_int_cst (size_type_node, r);
- }
-
/* If the first argument is "", return NULL_TREE. */
+ const char *p1 = c_getstr (s1);
if (p1 && *p1 == '\0')
{
/* Evaluate and ignore argument s2 in case it has
}
/* If the second argument is "", return __builtin_strlen(s1). */
+ const char *p2 = c_getstr (s2);
if (p2 && *p2 == '\0')
{
tree fn = builtin_decl_implicit (BUILT_IN_STRLEN);
#include "tree.h"
#include "stor-layout.h"
#include "options.h"
+#include "fold-const.h"
#include "fold-const-call.h"
#include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */
return TREE_CODE (t) == COMPLEX_CST;
}
+/* Return true if ARG is a constant in the range of the host size_t.
+ Store it in *SIZE_OUT if so. */
+
+static inline bool
+host_size_t_cst_p (tree t, size_t *size_out)
+{
+ if (integer_cst_p (t)
+ && wi::min_precision (t, UNSIGNED) <= sizeof (size_t) * CHAR_BIT)
+ {
+ *size_out = tree_to_uhwi (t);
+ return true;
+ }
+ return false;
+}
+
+/* RES is the result of a comparison in which < 0 means "less", 0 means
+ "equal" and > 0 means "more". Canonicalize it to -1, 0 or 1 and
+ return it in type TYPE. */
+
+static inline tree
+build_cmp_result (tree type, int res)
+{
+ return build_int_cst (type, res < 0 ? -1 : res > 0 ? 1 : 0);
+}
+
/* M is the result of trying to constant-fold an expression (starting
with clear MPFR flags) and INEXACT says whether the result in M is
exact or inexact. Return true if M can be used as a constant-folded
return real_equal (&initial_result, result);
}
+/* Fold a call to __builtin_nan or __builtin_nans with argument ARG and
+ return type TYPE. QUIET is true if a quiet rather than signalling
+ NaN is required. */
+
+static tree
+fold_const_builtin_nan (tree type, tree arg, bool quiet)
+{
+ REAL_VALUE_TYPE real;
+ const char *str = c_getstr (arg);
+ if (str && real_nan (&real, str, quiet, TYPE_MODE (type)))
+ return build_real (type, real);
+ return NULL_TREE;
+}
+
/* Try to evaluate:
*RESULT = FN (*ARG)
}
}
-/* Try to fold FN (ARG) to a constant. Return the constant on success,
- otherwise return null. TYPE is the type of the return value. */
+/* Subroutine of fold_const_call, with the same interface. Handle cases
+ where the arguments and result are numerical. */
-tree
-fold_const_call (built_in_function fn, tree type, tree arg)
+static tree
+fold_const_call_1 (built_in_function fn, tree type, tree arg)
{
machine_mode mode = TYPE_MODE (type);
machine_mode arg_mode = TYPE_MODE (TREE_TYPE (arg));
return NULL_TREE;
}
+/* Try to fold FN (ARG) to a constant. Return the constant on success,
+ otherwise return null. TYPE is the type of the return value. */
+
+tree
+fold_const_call (built_in_function fn, tree type, tree arg)
+{
+ switch (fn)
+ {
+ case BUILT_IN_STRLEN:
+ if (const char *str = c_getstr (arg))
+ return build_int_cst (type, strlen (str));
+ return NULL_TREE;
+
+ CASE_FLT_FN (BUILT_IN_NAN):
+ case BUILT_IN_NAND32:
+ case BUILT_IN_NAND64:
+ case BUILT_IN_NAND128:
+ return fold_const_builtin_nan (type, arg, true);
+
+ CASE_FLT_FN (BUILT_IN_NANS):
+ return fold_const_builtin_nan (type, arg, false);
+
+ default:
+ return fold_const_call_1 (fn, type, arg);
+ }
+}
+
/* Try to evaluate:
*RESULT = FN (*ARG0, *ARG1)
}
}
-/* Try to fold FN (ARG0, ARG1) to a constant. Return the constant on success,
- otherwise return null. TYPE is the type of the return value. */
+/* Subroutine of fold_const_call, with the same interface. Handle cases
+ where the arguments and result are numerical. */
-tree
-fold_const_call (built_in_function fn, tree type, tree arg0, tree arg1)
+static tree
+fold_const_call_1 (built_in_function fn, tree type, tree arg0, tree arg1)
{
machine_mode mode = TYPE_MODE (type);
machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
return NULL_TREE;
}
+/* Try to fold FN (ARG0, ARG1) to a constant. Return the constant on success,
+ otherwise return null. TYPE is the type of the return value. */
+
+tree
+fold_const_call (built_in_function fn, tree type, tree arg0, tree arg1)
+{
+ const char *p0, *p1;
+ switch (fn)
+ {
+ case BUILT_IN_STRSPN:
+ if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
+ return build_int_cst (type, strspn (p0, p1));
+ return NULL_TREE;
+
+ case BUILT_IN_STRCSPN:
+ if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
+ return build_int_cst (type, strcspn (p0, p1));
+ return NULL_TREE;
+
+ case BUILT_IN_STRCMP:
+ if ((p0 = c_getstr (arg0)) && (p1 = c_getstr (arg1)))
+ return build_cmp_result (type, strcmp (p0, p1));
+ return NULL_TREE;
+
+ default:
+ return fold_const_call_1 (fn, type, arg0, arg1);
+ }
+}
+
/* Try to evaluate:
*RESULT = FN (*ARG0, *ARG1, *ARG2)
}
}
-/* Try to fold FN (ARG0, ARG1, ARG2) to a constant. Return the constant on
- success, otherwise return null. TYPE is the type of the return value. */
+/* Subroutine of fold_const_call, with the same interface. Handle cases
+ where the arguments and result are numerical. */
-tree
-fold_const_call (built_in_function fn, tree type, tree arg0, tree arg1,
- tree arg2)
+static tree
+fold_const_call_1 (built_in_function fn, tree type, tree arg0, tree arg1,
+ tree arg2)
{
machine_mode mode = TYPE_MODE (type);
machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0));
return NULL_TREE;
}
+/* Try to fold FN (ARG0, ARG1, ARG2) to a constant. Return the constant on
+ success, otherwise return null. TYPE is the type of the return value. */
+
+tree
+fold_const_call (built_in_function fn, tree type, tree arg0, tree arg1,
+ tree arg2)
+{
+ const char *p0, *p1;
+ size_t s2;
+ switch (fn)
+ {
+ case BUILT_IN_STRNCMP:
+ if ((p0 = c_getstr (arg0))
+ && (p1 = c_getstr (arg1))
+ && host_size_t_cst_p (arg2, &s2))
+ return build_int_cst (type, strncmp (p0, p1, s2));
+ return NULL_TREE;
+
+ case BUILT_IN_BCMP:
+ case BUILT_IN_MEMCMP:
+ if ((p0 = c_getstr (arg0))
+ && (p1 = c_getstr (arg1))
+ && host_size_t_cst_p (arg2, &s2)
+ && s2 <= strlen (p0)
+ && s2 <= strlen (p1))
+ return build_cmp_result (type, memcmp (p0, p1, s2));
+ return NULL_TREE;
+
+ default:
+ return fold_const_call_1 (fn, type, arg0, arg1, arg2);
+ }
+}
+
/* Fold a fma operation with arguments ARG[012]. */
tree