aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorTamar Christina <tnfchris@gcc.gnu.org>2017-06-09 08:10:51 +0000
committerTamar Christina <tnfchris@gcc.gnu.org>2017-06-09 08:10:51 +0000
commit903c723b9d931abb6de044135c3bd4f44559fca7 (patch)
tree501cfa4a6ed13c934e7150ad55732b9b2c606305 /gcc/builtins.c
parent48e692477f5e3e1e99755b1e964ddd8a51fb5775 (diff)
downloadgcc-903c723b9d931abb6de044135c3bd4f44559fca7.zip
gcc-903c723b9d931abb6de044135c3bd4f44559fca7.tar.gz
gcc-903c723b9d931abb6de044135c3bd4f44559fca7.tar.bz2
Reverted r249005 until PowerPC and AIX issues sorted.
From-SVN: r249050
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c374
1 files changed, 349 insertions, 25 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 254dab6..30462ad 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -165,6 +165,7 @@ static tree fold_builtin_0 (location_t, tree);
static tree fold_builtin_1 (location_t, tree, tree);
static tree fold_builtin_2 (location_t, tree, tree, tree);
static tree fold_builtin_3 (location_t, tree, tree, tree, tree);
+static tree fold_builtin_varargs (location_t, tree, tree*, int);
static tree fold_builtin_strpbrk (location_t, tree, tree, tree);
static tree fold_builtin_strspn (location_t, tree, tree);
@@ -2226,8 +2227,19 @@ interclass_mathfn_icode (tree arg, tree fndecl)
switch (DECL_FUNCTION_CODE (fndecl))
{
CASE_FLT_FN (BUILT_IN_ILOGB):
- errno_set = true;
- builtin_optab = ilogb_optab;
+ errno_set = true; builtin_optab = ilogb_optab; break;
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ builtin_optab = isinf_optab; break;
+ case BUILT_IN_ISNORMAL:
+ case BUILT_IN_ISFINITE:
+ CASE_FLT_FN (BUILT_IN_FINITE):
+ case BUILT_IN_FINITED32:
+ case BUILT_IN_FINITED64:
+ case BUILT_IN_FINITED128:
+ case BUILT_IN_ISINFD32:
+ case BUILT_IN_ISINFD64:
+ case BUILT_IN_ISINFD128:
+ /* These builtins have no optabs (yet). */
break;
default:
gcc_unreachable ();
@@ -2246,7 +2258,8 @@ interclass_mathfn_icode (tree arg, tree fndecl)
}
/* Expand a call to one of the builtin math functions that operate on
- floating point argument and output an integer result (ilogb, etc).
+ floating point argument and output an integer result (ilogb, isinf,
+ isnan, etc).
Return 0 if a normal call should be emitted rather than expanding the
function in-line. EXP is the expression that is a call to the builtin
function; if convenient, the result should be placed in TARGET. */
@@ -6592,7 +6605,11 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
CASE_FLT_FN (BUILT_IN_ILOGB):
if (! flag_unsafe_math_optimizations)
break;
-
+ gcc_fallthrough ();
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ CASE_FLT_FN (BUILT_IN_FINITE):
+ case BUILT_IN_ISFINITE:
+ case BUILT_IN_ISNORMAL:
target = expand_builtin_interclass_mathfn (exp, target);
if (target)
return target;
@@ -6900,25 +6917,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
}
break;
- CASE_FLT_FN (BUILT_IN_ISINF):
- case BUILT_IN_ISNAND32:
- case BUILT_IN_ISNAND64:
- case BUILT_IN_ISNAND128:
- case BUILT_IN_ISNAN:
- case BUILT_IN_ISINFD32:
- case BUILT_IN_ISINFD64:
- case BUILT_IN_ISINFD128:
- case BUILT_IN_ISNORMAL:
- case BUILT_IN_ISZERO:
- case BUILT_IN_ISSUBNORMAL:
- case BUILT_IN_FPCLASSIFY:
case BUILT_IN_SETJMP:
- CASE_FLT_FN (BUILT_IN_FINITE):
- case BUILT_IN_FINITED32:
- case BUILT_IN_FINITED64:
- case BUILT_IN_FINITED128:
- case BUILT_IN_ISFINITE:
- /* These should have been lowered to the builtins in gimple-low.c. */
+ /* This should have been lowered to the builtins below. */
gcc_unreachable ();
case BUILT_IN_SETJMP_SETUP:
@@ -8258,19 +8258,184 @@ fold_builtin_modf (location_t loc, tree arg0, tree arg1, tree rettype)
return NULL_TREE;
}
+/* Given a location LOC, an interclass builtin function decl FNDECL
+ and its single argument ARG, return an folded expression computing
+ the same, or NULL_TREE if we either couldn't or didn't want to fold
+ (the latter happen if there's an RTL instruction available). */
+
+static tree
+fold_builtin_interclass_mathfn (location_t loc, tree fndecl, tree arg)
+{
+ machine_mode mode;
+
+ if (!validate_arg (arg, REAL_TYPE))
+ return NULL_TREE;
+
+ if (interclass_mathfn_icode (arg, fndecl) != CODE_FOR_nothing)
+ return NULL_TREE;
+
+ mode = TYPE_MODE (TREE_TYPE (arg));
+
+ bool is_ibm_extended = MODE_COMPOSITE_P (mode);
+ /* If there is no optab, try generic code. */
+ switch (DECL_FUNCTION_CODE (fndecl))
+ {
+ tree result;
-/* Fold a call to __builtin_isinf_sign.
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ {
+ /* isinf(x) -> isgreater(fabs(x),DBL_MAX). */
+ tree const isgr_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
+ tree type = TREE_TYPE (arg);
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
+ get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+ real_from_string (&r, buf);
+ result = build_call_expr (isgr_fn, 2,
+ fold_build1_loc (loc, ABS_EXPR, type, arg),
+ build_real (type, r));
+ return result;
+ }
+ CASE_FLT_FN (BUILT_IN_FINITE):
+ case BUILT_IN_ISFINITE:
+ {
+ /* isfinite(x) -> islessequal(fabs(x),DBL_MAX). */
+ tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
+ tree type = TREE_TYPE (arg);
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
+ get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+ real_from_string (&r, buf);
+ result = build_call_expr (isle_fn, 2,
+ fold_build1_loc (loc, ABS_EXPR, type, arg),
+ build_real (type, r));
+ /*result = fold_build2_loc (loc, UNGT_EXPR,
+ TREE_TYPE (TREE_TYPE (fndecl)),
+ fold_build1_loc (loc, ABS_EXPR, type, arg),
+ build_real (type, r));
+ result = fold_build1_loc (loc, TRUTH_NOT_EXPR,
+ TREE_TYPE (TREE_TYPE (fndecl)),
+ result);*/
+ return result;
+ }
+ case BUILT_IN_ISNORMAL:
+ {
+ /* isnormal(x) -> isgreaterequal(fabs(x),DBL_MIN) &
+ islessequal(fabs(x),DBL_MAX). */
+ tree const isle_fn = builtin_decl_explicit (BUILT_IN_ISLESSEQUAL);
+ tree type = TREE_TYPE (arg);
+ tree orig_arg, max_exp, min_exp;
+ machine_mode orig_mode = mode;
+ REAL_VALUE_TYPE rmax, rmin;
+ char buf[128];
+
+ orig_arg = arg = builtin_save_expr (arg);
+ if (is_ibm_extended)
+ {
+ /* Use double to test the normal range of IBM extended
+ precision. Emin for IBM extended precision is
+ different to emin for IEEE double, being 53 higher
+ since the low double exponent is at least 53 lower
+ than the high double exponent. */
+ type = double_type_node;
+ mode = DFmode;
+ arg = fold_build1_loc (loc, NOP_EXPR, type, arg);
+ }
+ arg = fold_build1_loc (loc, ABS_EXPR, type, arg);
+
+ get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf));
+ real_from_string (&rmax, buf);
+ sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (orig_mode)->emin - 1);
+ real_from_string (&rmin, buf);
+ max_exp = build_real (type, rmax);
+ min_exp = build_real (type, rmin);
+
+ max_exp = build_call_expr (isle_fn, 2, arg, max_exp);
+ if (is_ibm_extended)
+ {
+ /* Testing the high end of the range is done just using
+ the high double, using the same test as isfinite().
+ For the subnormal end of the range we first test the
+ high double, then if its magnitude is equal to the
+ limit of 0x1p-969, we test whether the low double is
+ non-zero and opposite sign to the high double. */
+ tree const islt_fn = builtin_decl_explicit (BUILT_IN_ISLESS);
+ tree const isgt_fn = builtin_decl_explicit (BUILT_IN_ISGREATER);
+ tree gt_min = build_call_expr (isgt_fn, 2, arg, min_exp);
+ tree eq_min = fold_build2 (EQ_EXPR, integer_type_node,
+ arg, min_exp);
+ tree as_complex = build1 (VIEW_CONVERT_EXPR,
+ complex_double_type_node, orig_arg);
+ tree hi_dbl = build1 (REALPART_EXPR, type, as_complex);
+ tree lo_dbl = build1 (IMAGPART_EXPR, type, as_complex);
+ tree zero = build_real (type, dconst0);
+ tree hilt = build_call_expr (islt_fn, 2, hi_dbl, zero);
+ tree lolt = build_call_expr (islt_fn, 2, lo_dbl, zero);
+ tree logt = build_call_expr (isgt_fn, 2, lo_dbl, zero);
+ tree ok_lo = fold_build1 (TRUTH_NOT_EXPR, integer_type_node,
+ fold_build3 (COND_EXPR,
+ integer_type_node,
+ hilt, logt, lolt));
+ eq_min = fold_build2 (TRUTH_ANDIF_EXPR, integer_type_node,
+ eq_min, ok_lo);
+ min_exp = fold_build2 (TRUTH_ORIF_EXPR, integer_type_node,
+ gt_min, eq_min);
+ }
+ else
+ {
+ tree const isge_fn
+ = builtin_decl_explicit (BUILT_IN_ISGREATEREQUAL);
+ min_exp = build_call_expr (isge_fn, 2, arg, min_exp);
+ }
+ result = fold_build2 (BIT_AND_EXPR, integer_type_node,
+ max_exp, min_exp);
+ return result;
+ }
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+/* Fold a call to __builtin_isnan(), __builtin_isinf, __builtin_finite.
ARG is the argument for the call. */
static tree
-fold_builtin_classify (location_t loc, tree arg, int builtin_index)
+fold_builtin_classify (location_t loc, tree fndecl, tree arg, int builtin_index)
{
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+
if (!validate_arg (arg, REAL_TYPE))
return NULL_TREE;
switch (builtin_index)
{
+ case BUILT_IN_ISINF:
+ if (!HONOR_INFINITIES (arg))
+ return omit_one_operand_loc (loc, type, integer_zero_node, arg);
+
+ return NULL_TREE;
+
case BUILT_IN_ISINF_SIGN:
{
/* isinf_sign(x) -> isinf(x) ? (signbit(x) ? -1 : 1) : 0 */
@@ -8303,11 +8468,106 @@ fold_builtin_classify (location_t loc, tree arg, int builtin_index)
return tmp;
}
+ case BUILT_IN_ISFINITE:
+ if (!HONOR_NANS (arg)
+ && !HONOR_INFINITIES (arg))
+ return omit_one_operand_loc (loc, type, integer_one_node, arg);
+
+ return NULL_TREE;
+
+ case BUILT_IN_ISNAN:
+ if (!HONOR_NANS (arg))
+ return omit_one_operand_loc (loc, type, integer_zero_node, arg);
+
+ {
+ bool is_ibm_extended = MODE_COMPOSITE_P (TYPE_MODE (TREE_TYPE (arg)));
+ if (is_ibm_extended)
+ {
+ /* NaN and Inf are encoded in the high-order double value
+ only. The low-order value is not significant. */
+ arg = fold_build1_loc (loc, NOP_EXPR, double_type_node, arg);
+ }
+ }
+ arg = builtin_save_expr (arg);
+ return fold_build2_loc (loc, UNORDERED_EXPR, type, arg, arg);
+
default:
gcc_unreachable ();
}
}
+/* Fold a call to __builtin_fpclassify(int, int, int, int, int, ...).
+ This builtin will generate code to return the appropriate floating
+ point classification depending on the value of the floating point
+ number passed in. The possible return values must be supplied as
+ int arguments to the call in the following order: FP_NAN, FP_INFINITE,
+ FP_NORMAL, FP_SUBNORMAL and FP_ZERO. The ellipses is for exactly
+ one floating point argument which is "type generic". */
+
+static tree
+fold_builtin_fpclassify (location_t loc, tree *args, int nargs)
+{
+ tree fp_nan, fp_infinite, fp_normal, fp_subnormal, fp_zero,
+ arg, type, res, tmp;
+ machine_mode mode;
+ REAL_VALUE_TYPE r;
+ char buf[128];
+
+ /* Verify the required arguments in the original call. */
+ if (nargs != 6
+ || !validate_arg (args[0], INTEGER_TYPE)
+ || !validate_arg (args[1], INTEGER_TYPE)
+ || !validate_arg (args[2], INTEGER_TYPE)
+ || !validate_arg (args[3], INTEGER_TYPE)
+ || !validate_arg (args[4], INTEGER_TYPE)
+ || !validate_arg (args[5], REAL_TYPE))
+ return NULL_TREE;
+
+ fp_nan = args[0];
+ fp_infinite = args[1];
+ fp_normal = args[2];
+ fp_subnormal = args[3];
+ fp_zero = args[4];
+ arg = args[5];
+ type = TREE_TYPE (arg);
+ mode = TYPE_MODE (type);
+ arg = builtin_save_expr (fold_build1_loc (loc, ABS_EXPR, type, arg));
+
+ /* fpclassify(x) ->
+ isnan(x) ? FP_NAN :
+ (fabs(x) == Inf ? FP_INFINITE :
+ (fabs(x) >= DBL_MIN ? FP_NORMAL :
+ (x == 0 ? FP_ZERO : FP_SUBNORMAL))). */
+
+ tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
+ build_real (type, dconst0));
+ res = fold_build3_loc (loc, COND_EXPR, integer_type_node,
+ tmp, fp_zero, fp_subnormal);
+
+ sprintf (buf, "0x1p%d", REAL_MODE_FORMAT (mode)->emin - 1);
+ real_from_string (&r, buf);
+ tmp = fold_build2_loc (loc, GE_EXPR, integer_type_node,
+ arg, build_real (type, r));
+ res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, fp_normal, res);
+
+ if (HONOR_INFINITIES (mode))
+ {
+ real_inf (&r);
+ tmp = fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg,
+ build_real (type, r));
+ res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp,
+ fp_infinite, res);
+ }
+
+ if (HONOR_NANS (mode))
+ {
+ tmp = fold_build2_loc (loc, ORDERED_EXPR, integer_type_node, arg, arg);
+ res = fold_build3_loc (loc, COND_EXPR, integer_type_node, tmp, res, fp_nan);
+ }
+
+ return res;
+}
+
/* Fold a call to an unordered comparison function such as
__builtin_isgreater(). FNDECL is the FUNCTION_DECL for the function
being called and ARG0 and ARG1 are the arguments for the call.
@@ -8608,8 +8868,40 @@ fold_builtin_1 (location_t loc, tree fndecl, tree arg0)
case BUILT_IN_ISDIGIT:
return fold_builtin_isdigit (loc, arg0);
+ CASE_FLT_FN (BUILT_IN_FINITE):
+ case BUILT_IN_FINITED32:
+ case BUILT_IN_FINITED64:
+ case BUILT_IN_FINITED128:
+ case BUILT_IN_ISFINITE:
+ {
+ tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISFINITE);
+ if (ret)
+ return ret;
+ return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
+ }
+
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ case BUILT_IN_ISINFD32:
+ case BUILT_IN_ISINFD64:
+ case BUILT_IN_ISINFD128:
+ {
+ tree ret = fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF);
+ if (ret)
+ return ret;
+ return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
+ }
+
+ case BUILT_IN_ISNORMAL:
+ return fold_builtin_interclass_mathfn (loc, fndecl, arg0);
+
case BUILT_IN_ISINF_SIGN:
- return fold_builtin_classify (loc, arg0, BUILT_IN_ISINF_SIGN);
+ return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISINF_SIGN);
+
+ CASE_FLT_FN (BUILT_IN_ISNAN):
+ case BUILT_IN_ISNAND32:
+ case BUILT_IN_ISNAND64:
+ case BUILT_IN_ISNAND128:
+ return fold_builtin_classify (loc, fndecl, arg0, BUILT_IN_ISNAN);
case BUILT_IN_FREE:
if (integer_zerop (arg0))
@@ -8806,6 +9098,7 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
ret = fold_builtin_3 (loc, fndecl, args[0], args[1], args[2]);
break;
default:
+ ret = fold_builtin_varargs (loc, fndecl, args, nargs);
break;
}
if (ret)
@@ -9696,6 +9989,37 @@ fold_builtin_object_size (tree ptr, tree ost)
return NULL_TREE;
}
+/* Builtins with folding operations that operate on "..." arguments
+ need special handling; we need to store the arguments in a convenient
+ data structure before attempting any folding. Fortunately there are
+ only a few builtins that fall into this category. FNDECL is the
+ function, EXP is the CALL_EXPR for the call. */
+
+static tree
+fold_builtin_varargs (location_t loc, tree fndecl, tree *args, int nargs)
+{
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
+ tree ret = NULL_TREE;
+
+ switch (fcode)
+ {
+ case BUILT_IN_FPCLASSIFY:
+ ret = fold_builtin_fpclassify (loc, args, nargs);
+ break;
+
+ default:
+ break;
+ }
+ if (ret)
+ {
+ ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
+ SET_EXPR_LOCATION (ret, loc);
+ TREE_NO_WARNING (ret) = 1;
+ return ret;
+ }
+ return NULL_TREE;
+}
+
/* Initialize format string characters in the target charset. */
bool