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