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);
     }