예제 #1
0
static bool
fold_const_builtin_load_exponent (real_value *result, const real_value *arg0,
				  const wide_int_ref &arg1,
				  const real_format *format)
{
  /* Bound the maximum adjustment to twice the range of the
     mode's valid exponents.  Use abs to ensure the range is
     positive as a sanity check.  */
  int max_exp_adj = 2 * labs (format->emax - format->emin);

  /* The requested adjustment must be inside this range.  This
     is a preliminary cap to avoid things like overflow, we
     may still fail to compute the result for other reasons.  */
  if (wi::les_p (arg1, -max_exp_adj) || wi::ges_p (arg1, max_exp_adj))
    return false;

  REAL_VALUE_TYPE initial_result;
  real_ldexp (&initial_result, arg0, arg1.to_shwi ());

  /* Ensure we didn't overflow.  */
  if (real_isinf (&initial_result))
    return false;

  /* Only proceed if the target mode can hold the
     resulting value.  */
  *result = real_value_truncate (format, initial_result);
  return real_equal (&initial_result, result);
}
예제 #2
0
static bool
fold_const_call_cc (real_value *result_real, real_value *result_imag,
		    built_in_function fn, const real_value *arg_real,
		    const real_value *arg_imag, const real_format *format)
{
  switch (fn)
    {
    CASE_FLT_FN (BUILT_IN_CCOS):
      return do_mpc_arg1 (result_real, result_imag, mpc_cos,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CCOSH):
      return do_mpc_arg1 (result_real, result_imag, mpc_cosh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CPROJ):
      if (real_isinf (arg_real) || real_isinf (arg_imag))
	{
	  real_inf (result_real);
	  *result_imag = dconst0;
	  result_imag->sign = arg_imag->sign;
	}
      else
	{
	  *result_real = *arg_real;
	  *result_imag = *arg_imag;
	}
      return true;

    CASE_FLT_FN (BUILT_IN_CSIN):
      return do_mpc_arg1 (result_real, result_imag, mpc_sin,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CSINH):
      return do_mpc_arg1 (result_real, result_imag, mpc_sinh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CTAN):
      return do_mpc_arg1 (result_real, result_imag, mpc_tan,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CTANH):
      return do_mpc_arg1 (result_real, result_imag, mpc_tanh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CLOG):
      return do_mpc_arg1 (result_real, result_imag, mpc_log,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CSQRT):
      return do_mpc_arg1 (result_real, result_imag, mpc_sqrt,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CASIN):
      return do_mpc_arg1 (result_real, result_imag, mpc_asin,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CACOS):
      return do_mpc_arg1 (result_real, result_imag, mpc_acos,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CATAN):
      return do_mpc_arg1 (result_real, result_imag, mpc_atan,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CASINH):
      return do_mpc_arg1 (result_real, result_imag, mpc_asinh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CACOSH):
      return do_mpc_arg1 (result_real, result_imag, mpc_acosh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CATANH):
      return do_mpc_arg1 (result_real, result_imag, mpc_atanh,
			  arg_real, arg_imag, format);

    CASE_FLT_FN (BUILT_IN_CEXP):
      return do_mpc_arg1 (result_real, result_imag, mpc_exp,
			  arg_real, arg_imag, format);

    default:
      return false;
    }
}
예제 #3
0
static bool
fold_const_call_ss (wide_int *result, built_in_function fn,
		    const real_value *arg, unsigned int precision,
		    const real_format *format)
{
  switch (fn)
    {
    CASE_FLT_FN (BUILT_IN_SIGNBIT):
      if (real_isneg (arg))
	*result = wi::one (precision);
      else
	*result = wi::zero (precision);
      return true;

    CASE_FLT_FN (BUILT_IN_ILOGB):
      /* For ilogb we don't know FP_ILOGB0, so only handle normal values.
	 Proceed iff radix == 2.  In GCC, normalized significands are in
	 the range [0.5, 1.0).  We want the exponent as if they were
	 [1.0, 2.0) so get the exponent and subtract 1.  */
      if (arg->cl == rvc_normal && format->b == 2)
	{
	  *result = wi::shwi (REAL_EXP (arg) - 1, precision);
	  return true;
	}
      return false;

    CASE_FLT_FN (BUILT_IN_ICEIL):
    CASE_FLT_FN (BUILT_IN_LCEIL):
    CASE_FLT_FN (BUILT_IN_LLCEIL):
      return fold_const_conversion (result, real_ceil, arg,
				    precision, format);

    CASE_FLT_FN (BUILT_IN_LFLOOR):
    CASE_FLT_FN (BUILT_IN_IFLOOR):
    CASE_FLT_FN (BUILT_IN_LLFLOOR):
      return fold_const_conversion (result, real_floor, arg,
				    precision, format);

    CASE_FLT_FN (BUILT_IN_IROUND):
    CASE_FLT_FN (BUILT_IN_LROUND):
    CASE_FLT_FN (BUILT_IN_LLROUND):
      return fold_const_conversion (result, real_round, arg,
				    precision, format);

    CASE_FLT_FN (BUILT_IN_IRINT):
    CASE_FLT_FN (BUILT_IN_LRINT):
    CASE_FLT_FN (BUILT_IN_LLRINT):
      /* Not yet folded to a constant.  */
      return false;

    CASE_FLT_FN (BUILT_IN_FINITE):
    case BUILT_IN_FINITED32:
    case BUILT_IN_FINITED64:
    case BUILT_IN_FINITED128:
    case BUILT_IN_ISFINITE:
      *result = wi::shwi (real_isfinite (arg) ? 1 : 0, precision);
      return true;

    CASE_FLT_FN (BUILT_IN_ISINF):
    case BUILT_IN_ISINFD32:
    case BUILT_IN_ISINFD64:
    case BUILT_IN_ISINFD128:
      if (real_isinf (arg))
	*result = wi::shwi (arg->sign ? -1 : 1, precision);
      else
	*result = wi::shwi (0, precision);
      return true;

    CASE_FLT_FN (BUILT_IN_ISNAN):
    case BUILT_IN_ISNAND32:
    case BUILT_IN_ISNAND64:
    case BUILT_IN_ISNAND128:
      *result = wi::shwi (real_isnan (arg) ? 1 : 0, precision);
      return true;

    default:
      return false;
    }
}
예제 #4
0
파일: ubsan.c 프로젝트: acoxepochlabs/gcc
tree
ubsan_instrument_float_cast (location_t loc, tree type, tree expr)
{
  tree expr_type = TREE_TYPE (expr);
  tree t, tt, fn, min, max;
  enum machine_mode mode = TYPE_MODE (expr_type);
  int prec = TYPE_PRECISION (type);
  bool uns_p = TYPE_UNSIGNED (type);

  /* Float to integer conversion first truncates toward zero, so
     even signed char c = 127.875f; is not problematic.
     Therefore, we should complain only if EXPR is unordered or smaller
     or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than
     TYPE_MAX_VALUE + 1.0.  */
  if (REAL_MODE_FORMAT (mode)->b == 2)
    {
      /* For maximum, TYPE_MAX_VALUE might not be representable
	 in EXPR_TYPE, e.g. if TYPE is 64-bit long long and
	 EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is
	 either representable or infinity.  */
      REAL_VALUE_TYPE maxval = dconst1;
      SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p);
      real_convert (&maxval, mode, &maxval);
      max = build_real (expr_type, maxval);

      /* For unsigned, assume -1.0 is always representable.  */
      if (uns_p)
	min = build_minus_one_cst (expr_type);
      else
	{
	  /* TYPE_MIN_VALUE is generally representable (or -inf),
	     but TYPE_MIN_VALUE - 1.0 might not be.  */
	  REAL_VALUE_TYPE minval = dconstm1, minval2;
	  SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1);
	  real_convert (&minval, mode, &minval);
	  real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1);
	  real_convert (&minval2, mode, &minval2);
	  if (real_compare (EQ_EXPR, &minval, &minval2)
	      && !real_isinf (&minval))
	    {
	      /* If TYPE_MIN_VALUE - 1.0 is not representable and
		 rounds to TYPE_MIN_VALUE, we need to subtract
		 more.  As REAL_MODE_FORMAT (mode)->p is the number
		 of base digits, we want to subtract a number that
		 will be 1 << (REAL_MODE_FORMAT (mode)->p - 1)
		 times smaller than minval.  */
	      minval2 = dconst1;
	      gcc_assert (prec > REAL_MODE_FORMAT (mode)->p);
	      SET_REAL_EXP (&minval2,
			    REAL_EXP (&minval2) + prec - 1
			    - REAL_MODE_FORMAT (mode)->p + 1);
	      real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2);
	      real_convert (&minval2, mode, &minval2);
	    }
	  min = build_real (expr_type, minval2);
	}
    }
  else if (REAL_MODE_FORMAT (mode)->b == 10)
    {
      /* For _Decimal128 up to 34 decimal digits, - sign,
	 dot, e, exponent.  */
      char buf[64];
      mpfr_t m;
      int p = REAL_MODE_FORMAT (mode)->p;
      REAL_VALUE_TYPE maxval, minval;

      /* Use mpfr_snprintf rounding to compute the smallest
	 representable decimal number greater or equal than
	 1 << (prec - !uns_p).  */
      mpfr_init2 (m, prec + 2);
      mpfr_set_ui_2exp (m, 1, prec - !uns_p, GMP_RNDN);
      mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m);
      decimal_real_from_string (&maxval, buf);
      max = build_real (expr_type, maxval);

      /* For unsigned, assume -1.0 is always representable.  */
      if (uns_p)
	min = build_minus_one_cst (expr_type);
      else
	{
	  /* Use mpfr_snprintf rounding to compute the largest
	     representable decimal number less or equal than
	     (-1 << (prec - 1)) - 1.  */
	  mpfr_set_si_2exp (m, -1, prec - 1, GMP_RNDN);
	  mpfr_sub_ui (m, m, 1, GMP_RNDN);
	  mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m);
	  decimal_real_from_string (&minval, buf);
	  min = build_real (expr_type, minval);
	}
      mpfr_clear (m);
    }
  else
    return NULL_TREE;

  if (flag_sanitize_undefined_trap_on_error)
    fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
  else
    {
      /* Create the __ubsan_handle_float_cast_overflow fn call.  */
      tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data", NULL,
				     NULL, ubsan_type_descriptor (expr_type),
				     ubsan_type_descriptor (type), NULL_TREE);
      enum built_in_function bcode
	= flag_sanitize_recover
	  ? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW
	  : BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT;
      fn = builtin_decl_explicit (bcode);
      fn = build_call_expr_loc (loc, fn, 2,
				build_fold_addr_expr_loc (loc, data),
				ubsan_encode_value (expr, false));
    }

  t = fold_build2 (UNLE_EXPR, boolean_type_node, expr, min);
  tt = fold_build2 (UNGE_EXPR, boolean_type_node, expr, max);
  return fold_build3 (COND_EXPR, void_type_node,
		      fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt),
		      fn, integer_zero_node);
}
예제 #5
0
static bool
fold_const_call_cc (real_value *result_real, real_value *result_imag,
		    combined_fn fn, const real_value *arg_real,
		    const real_value *arg_imag, const real_format *format)
{
  switch (fn)
    {
    CASE_CFN_CCOS:
      return do_mpc_arg1 (result_real, result_imag, mpc_cos,
			  arg_real, arg_imag, format);

    CASE_CFN_CCOSH:
      return do_mpc_arg1 (result_real, result_imag, mpc_cosh,
			  arg_real, arg_imag, format);

    CASE_CFN_CPROJ:
      if (real_isinf (arg_real) || real_isinf (arg_imag))
	{
	  real_inf (result_real);
	  *result_imag = dconst0;
	  result_imag->sign = arg_imag->sign;
	}
      else
	{
	  *result_real = *arg_real;
	  *result_imag = *arg_imag;
	}
      return true;

    CASE_CFN_CSIN:
      return do_mpc_arg1 (result_real, result_imag, mpc_sin,
			  arg_real, arg_imag, format);

    CASE_CFN_CSINH:
      return do_mpc_arg1 (result_real, result_imag, mpc_sinh,
			  arg_real, arg_imag, format);

    CASE_CFN_CTAN:
      return do_mpc_arg1 (result_real, result_imag, mpc_tan,
			  arg_real, arg_imag, format);

    CASE_CFN_CTANH:
      return do_mpc_arg1 (result_real, result_imag, mpc_tanh,
			  arg_real, arg_imag, format);

    CASE_CFN_CLOG:
      return do_mpc_arg1 (result_real, result_imag, mpc_log,
			  arg_real, arg_imag, format);

    CASE_CFN_CSQRT:
      return do_mpc_arg1 (result_real, result_imag, mpc_sqrt,
			  arg_real, arg_imag, format);

    CASE_CFN_CASIN:
      return do_mpc_arg1 (result_real, result_imag, mpc_asin,
			  arg_real, arg_imag, format);

    CASE_CFN_CACOS:
      return do_mpc_arg1 (result_real, result_imag, mpc_acos,
			  arg_real, arg_imag, format);

    CASE_CFN_CATAN:
      return do_mpc_arg1 (result_real, result_imag, mpc_atan,
			  arg_real, arg_imag, format);

    CASE_CFN_CASINH:
      return do_mpc_arg1 (result_real, result_imag, mpc_asinh,
			  arg_real, arg_imag, format);

    CASE_CFN_CACOSH:
      return do_mpc_arg1 (result_real, result_imag, mpc_acosh,
			  arg_real, arg_imag, format);

    CASE_CFN_CATANH:
      return do_mpc_arg1 (result_real, result_imag, mpc_atanh,
			  arg_real, arg_imag, format);

    CASE_CFN_CEXP:
      return do_mpc_arg1 (result_real, result_imag, mpc_exp,
			  arg_real, arg_imag, format);

    default:
      return false;
    }
}