Mercurial > hg > CbC > CbC_gcc
diff gcc/fold-const-call.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/fold-const-call.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/fold-const-call.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* Constant folding for calls to built-in and internal functions. - Copyright (C) 1988-2018 Free Software Foundation, Inc. + Copyright (C) 1988-2020 Free Software Foundation, Inc. This file is part of GCC. @@ -30,6 +30,7 @@ #include "tm.h" /* For C[LT]Z_DEFINED_AT_ZERO. */ #include "builtins.h" #include "gimple-expr.h" +#include "tree-vector-builder.h" /* Functions that test for certain constant types, abstracting away the decision about whether to check for overflow. */ @@ -98,7 +99,7 @@ return false; REAL_VALUE_TYPE tmp; - real_from_mpfr (&tmp, m, format, GMP_RNDN); + real_from_mpfr (&tmp, m, format, MPFR_RNDN); /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values. If the REAL_VALUE_TYPE is zero but the mpft_t is not, then we @@ -129,11 +130,11 @@ return false; int prec = format->p; - mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN; mpfr_t m; mpfr_init2 (m, prec); - mpfr_from_real (m, arg, GMP_RNDN); + mpfr_from_real (m, arg, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m, m, rnd); bool ok = do_mpfr_ckconv (result, m, inexact, format); @@ -159,11 +160,11 @@ return false; int prec = format->p; - mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN; mpfr_t m, ms, mc; mpfr_inits2 (prec, m, ms, mc, NULL); - mpfr_from_real (m, arg, GMP_RNDN); + mpfr_from_real (m, arg, MPFR_RNDN); mpfr_clear_flags (); bool inexact = mpfr_sin_cos (ms, mc, m, rnd); bool ok = (do_mpfr_ckconv (result_sin, ms, inexact, format) @@ -192,12 +193,12 @@ return false; int prec = format->p; - mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN; mpfr_t m0, m1; mpfr_inits2 (prec, m0, m1, NULL); - mpfr_from_real (m0, arg0, GMP_RNDN); - mpfr_from_real (m1, arg1, GMP_RNDN); + mpfr_from_real (m0, arg0, MPFR_RNDN); + mpfr_from_real (m1, arg1, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m0, m0, m1, rnd); bool ok = do_mpfr_ckconv (result, m0, inexact, format); @@ -215,7 +216,7 @@ static bool do_mpfr_arg2 (real_value *result, - int (*func) (mpfr_ptr, long, mpfr_srcptr, mp_rnd_t), + int (*func) (mpfr_ptr, long, mpfr_srcptr, mpfr_rnd_t), const wide_int_ref &arg0, const real_value *arg1, const real_format *format) { @@ -223,11 +224,11 @@ return false; int prec = format->p; - mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN; mpfr_t m; mpfr_init2 (m, prec); - mpfr_from_real (m, arg1, GMP_RNDN); + mpfr_from_real (m, arg1, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m, arg0.to_shwi (), m, rnd); bool ok = do_mpfr_ckconv (result, m, inexact, format); @@ -259,13 +260,13 @@ return false; int prec = format->p; - mp_rnd_t rnd = format->round_towards_zero ? GMP_RNDZ : GMP_RNDN; + mpfr_rnd_t rnd = format->round_towards_zero ? MPFR_RNDZ : MPFR_RNDN; mpfr_t m0, m1, m2; mpfr_inits2 (prec, m0, m1, m2, NULL); - mpfr_from_real (m0, arg0, GMP_RNDN); - mpfr_from_real (m1, arg1, GMP_RNDN); - mpfr_from_real (m2, arg2, GMP_RNDN); + mpfr_from_real (m0, arg0, MPFR_RNDN); + mpfr_from_real (m1, arg1, MPFR_RNDN); + mpfr_from_real (m2, arg2, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m0, m0, m1, m2, rnd); bool ok = do_mpfr_ckconv (result, m0, inexact, format); @@ -295,8 +296,8 @@ return false; REAL_VALUE_TYPE tmp_real, tmp_imag; - real_from_mpfr (&tmp_real, mpc_realref (m), format, GMP_RNDN); - real_from_mpfr (&tmp_imag, mpc_imagref (m), format, GMP_RNDN); + real_from_mpfr (&tmp_real, mpc_realref (m), format, MPFR_RNDN); + real_from_mpfr (&tmp_imag, mpc_imagref (m), format, MPFR_RNDN); /* Proceed iff GCC's REAL_VALUE_TYPE can hold the MPFR values. If the REAL_VALUE_TYPE is zero but the mpft_t is not, then we @@ -340,8 +341,8 @@ mpc_t m; mpc_init2 (m, prec); - mpfr_from_real (mpc_realref (m), arg_real, GMP_RNDN); - mpfr_from_real (mpc_imagref (m), arg_imag, GMP_RNDN); + mpfr_from_real (mpc_realref (m), arg_real, MPFR_RNDN); + mpfr_from_real (mpc_imagref (m), arg_imag, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m, m, crnd); bool ok = do_mpc_ckconv (result_real, result_imag, m, inexact, format); @@ -377,10 +378,10 @@ mpc_init2 (m0, prec); mpc_init2 (m1, prec); - mpfr_from_real (mpc_realref (m0), arg0_real, GMP_RNDN); - mpfr_from_real (mpc_imagref (m0), arg0_imag, GMP_RNDN); - mpfr_from_real (mpc_realref (m1), arg1_real, GMP_RNDN); - mpfr_from_real (mpc_imagref (m1), arg1_imag, GMP_RNDN); + mpfr_from_real (mpc_realref (m0), arg0_real, MPFR_RNDN); + mpfr_from_real (mpc_imagref (m0), arg0_imag, MPFR_RNDN); + mpfr_from_real (mpc_realref (m1), arg1_real, MPFR_RNDN); + mpfr_from_real (mpc_imagref (m1), arg1_imag, MPFR_RNDN); mpfr_clear_flags (); bool inexact = func (m0, m0, m1, crnd); bool ok = do_mpc_ckconv (result_real, result_imag, m0, inexact, format); @@ -645,6 +646,79 @@ return res; } +/* Fold a call to IFN_VEC_CONVERT (ARG) returning TYPE. */ + +static tree +fold_const_vec_convert (tree ret_type, tree arg) +{ + enum tree_code code = NOP_EXPR; + tree arg_type = TREE_TYPE (arg); + if (TREE_CODE (arg) != VECTOR_CST) + return NULL_TREE; + + gcc_checking_assert (VECTOR_TYPE_P (ret_type) && VECTOR_TYPE_P (arg_type)); + + if (INTEGRAL_TYPE_P (TREE_TYPE (ret_type)) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (arg_type))) + code = FIX_TRUNC_EXPR; + else if (INTEGRAL_TYPE_P (TREE_TYPE (arg_type)) + && SCALAR_FLOAT_TYPE_P (TREE_TYPE (ret_type))) + code = FLOAT_EXPR; + + /* We can't handle steps directly when extending, since the + values need to wrap at the original precision first. */ + bool step_ok_p + = (INTEGRAL_TYPE_P (TREE_TYPE (ret_type)) + && INTEGRAL_TYPE_P (TREE_TYPE (arg_type)) + && (TYPE_PRECISION (TREE_TYPE (ret_type)) + <= TYPE_PRECISION (TREE_TYPE (arg_type)))); + tree_vector_builder elts; + if (!elts.new_unary_operation (ret_type, arg, step_ok_p)) + return NULL_TREE; + + unsigned int count = elts.encoded_nelts (); + for (unsigned int i = 0; i < count; ++i) + { + tree elt = fold_unary (code, TREE_TYPE (ret_type), + VECTOR_CST_ELT (arg, i)); + if (elt == NULL_TREE || !CONSTANT_CLASS_P (elt)) + return NULL_TREE; + elts.quick_push (elt); + } + + return elts.build (); +} + +/* Try to evaluate: + + IFN_WHILE_ULT (ARG0, ARG1, (TYPE) { ... }) + + Return the value on success and null on failure. */ + +static tree +fold_while_ult (tree type, poly_uint64 arg0, poly_uint64 arg1) +{ + if (known_ge (arg0, arg1)) + return build_zero_cst (type); + + if (maybe_ge (arg0, arg1)) + return NULL_TREE; + + poly_uint64 diff = arg1 - arg0; + poly_uint64 nelts = TYPE_VECTOR_SUBPARTS (type); + if (known_ge (diff, nelts)) + return build_all_ones_cst (type); + + unsigned HOST_WIDE_INT const_diff; + if (known_le (diff, nelts) && diff.is_constant (&const_diff)) + { + tree minus_one = build_minus_one_cst (TREE_TYPE (type)); + tree zero = build_zero_cst (TREE_TYPE (type)); + return build_vector_a_then_b (type, const_diff, minus_one, zero); + } + return NULL_TREE; +} + /* Try to evaluate: *RESULT = FN (*ARG) @@ -762,7 +836,7 @@ CASE_CFN_FLOOR: CASE_CFN_FLOOR_FN: - if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math) + if (!REAL_VALUE_ISSIGNALING_NAN (*arg)) { real_floor (result, format, arg); return true; @@ -771,7 +845,7 @@ CASE_CFN_CEIL: CASE_CFN_CEIL_FN: - if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math) + if (!REAL_VALUE_ISSIGNALING_NAN (*arg)) { real_ceil (result, format, arg); return true; @@ -780,18 +854,31 @@ CASE_CFN_TRUNC: CASE_CFN_TRUNC_FN: - real_trunc (result, format, arg); - return true; + if (!REAL_VALUE_ISSIGNALING_NAN (*arg)) + { + real_trunc (result, format, arg); + return true; + } + return false; CASE_CFN_ROUND: CASE_CFN_ROUND_FN: - if (!REAL_VALUE_ISNAN (*arg) || !flag_errno_math) + if (!REAL_VALUE_ISSIGNALING_NAN (*arg)) { real_round (result, format, arg); return true; } return false; + CASE_CFN_ROUNDEVEN: + CASE_CFN_ROUNDEVEN_FN: + if (!REAL_VALUE_ISSIGNALING_NAN (*arg)) + { + real_roundeven (result, format, arg); + return true; + } + return false; + CASE_CFN_LOGB: return fold_const_logb (result, arg, format); @@ -1232,6 +1319,9 @@ case CFN_REDUC_XOR: return fold_const_reduction (type, arg, BIT_XOR_EXPR); + case CFN_VEC_CONVERT: + return fold_const_vec_convert (type, arg); + default: return fold_const_call_1 (fn, type, arg); } @@ -1735,6 +1825,14 @@ } return NULL_TREE; + case CFN_WHILE_ULT: + { + poly_uint64 parg0, parg1; + if (poly_int_tree_p (arg0, &parg0) && poly_int_tree_p (arg1, &parg1)) + return fold_while_ult (type, parg0, parg1); + return NULL_TREE; + } + default: return fold_const_call_1 (fn, type, arg0, arg1, arg2); }