static tree fold_const_call_1 (built_in_function fn, tree type, tree arg0, tree arg1, tree arg2) { machine_mode mode = TYPE_MODE (type); machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0)); machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1)); machine_mode arg2_mode = TYPE_MODE (TREE_TYPE (arg2)); if (arg0_mode == arg1_mode && arg0_mode == arg2_mode && real_cst_p (arg0) && real_cst_p (arg1) && real_cst_p (arg2)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode)); if (mode == arg0_mode) { /* real, real, real -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_ssss (&result, fn, TREE_REAL_CST_PTR (arg0), TREE_REAL_CST_PTR (arg1), TREE_REAL_CST_PTR (arg2), REAL_MODE_FORMAT (mode))) return build_real (type, result); } return NULL_TREE; } return NULL_TREE; }
tree gfc_build_nan (tree type, const char *str) { REAL_VALUE_TYPE real; real_nan (&real, str, 1, TYPE_MODE (type)); return build_real (type, real); }
static inline tree chrec_fold_multiply_poly_poly (tree type, tree poly0, tree poly1) { tree t0, t1, t2; int var; struct loop *loop0 = get_chrec_loop (poly0); struct loop *loop1 = get_chrec_loop (poly1); gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_checking_assert (useless_type_conversion_p (type, chrec_type (poly0)) && useless_type_conversion_p (type, chrec_type (poly1))); /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2, {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ if (flow_loop_nested_p (loop0, loop1)) /* poly0 is a constant wrt. poly1. */ return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0), CHREC_RIGHT (poly1)); if (flow_loop_nested_p (loop1, loop0)) /* poly1 is a constant wrt. poly0. */ return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); gcc_assert (loop0 == loop1); /* poly0 and poly1 are two polynomials in the same variable, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ /* "a*c". */ t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); /* "a*d + b*c". */ t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)); t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1))); /* "b*d". */ t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); /* "a*d + b*c + b*d". */ t1 = chrec_fold_plus (type, t1, t2); /* "2*b*d". */ t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconst2) : build_int_cst (type, 2), t2); var = CHREC_VARIABLE (poly0); return build_polynomial_chrec (var, t0, build_polynomial_chrec (var, t1, t2)); }
static tree rewrite_reciprocal (block_stmt_iterator *bsi) { tree stmt, lhs, rhs, stmt1, stmt2, var, name, tmp; tree real_one; stmt = bsi_stmt (*bsi); lhs = GENERIC_TREE_OPERAND (stmt, 0); rhs = GENERIC_TREE_OPERAND (stmt, 1); /* stmt must be GIMPLE_MODIFY_STMT. */ var = create_tmp_var (TREE_TYPE (rhs), "reciptmp"); add_referenced_var (var); DECL_GIMPLE_REG_P (var) = 1; if (TREE_CODE (TREE_TYPE (rhs)) == VECTOR_TYPE) { int i, len; tree list = NULL_TREE; real_one = build_real (TREE_TYPE (TREE_TYPE (rhs)), dconst1); len = TYPE_VECTOR_SUBPARTS (TREE_TYPE (rhs)); for (i = 0; i < len; i++) list = tree_cons (NULL, real_one, list); real_one = build_vector (TREE_TYPE (rhs), list); } else real_one = build_real (TREE_TYPE (rhs), dconst1); tmp = build2 (RDIV_EXPR, TREE_TYPE (rhs), real_one, TREE_OPERAND (rhs, 1)); stmt1 = build_gimple_modify_stmt (var, tmp); name = make_ssa_name (var, stmt1); GIMPLE_STMT_OPERAND (stmt1, 0) = name; tmp = build2 (MULT_EXPR, TREE_TYPE (rhs), name, TREE_OPERAND (rhs, 0)); stmt2 = build_gimple_modify_stmt (lhs, tmp); /* Replace division stmt with reciprocal and multiply stmts. The multiply stmt is not invariant, so update iterator and avoid rescanning. */ bsi_replace (bsi, stmt1, true); bsi_insert_after (bsi, stmt2, BSI_NEW_STMT); SSA_NAME_DEF_STMT (lhs) = stmt2; /* Continue processing with invariant reciprocal statement. */ return stmt1; }
static tree fold_const_builtin_nan (tree type, tree arg, bool quiet) { REAL_VALUE_TYPE real; const char *str = c_getstr (arg); if (str && real_nan (&real, str, quiet, TYPE_MODE (type))) return build_real (type, real); return NULL_TREE; }
static inline tree chrec_fold_multiply_poly_poly (tree type, tree poly0, tree poly1) { tree t0, t1, t2; int var; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_assert (chrec_type (poly0) == chrec_type (poly1)); gcc_assert (type == chrec_type (poly0)); /* {a, +, b}_1 * {c, +, d}_2 -> {c*{a, +, b}_1, +, d}_2, {a, +, b}_2 * {c, +, d}_1 -> {a*{c, +, d}_1, +, b}_2, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1)) /* poly0 is a constant wrt. poly1. */ return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_multiply (type, CHREC_LEFT (poly1), poly0), CHREC_RIGHT (poly1)); if (CHREC_VARIABLE (poly1) < CHREC_VARIABLE (poly0)) /* poly1 is a constant wrt. poly0. */ return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_multiply (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); /* poly0 and poly1 are two polynomials in the same variable, {a, +, b}_x * {c, +, d}_x -> {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x. */ /* "a*c". */ t0 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); /* "a*d + b*c + b*d". */ t1 = chrec_fold_multiply (type, CHREC_LEFT (poly0), CHREC_RIGHT (poly1)); t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_LEFT (poly1))); t1 = chrec_fold_plus (type, t1, chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1))); /* "2*b*d". */ t2 = chrec_fold_multiply (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); t2 = chrec_fold_multiply (type, SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconst2) : build_int_cst (type, 2), t2); var = CHREC_VARIABLE (poly0); return build_polynomial_chrec (var, t0, build_polynomial_chrec (var, t1, t2)); }
tree fold_fma (location_t, tree type, tree arg0, tree arg1, tree arg2) { REAL_VALUE_TYPE result; if (real_cst_p (arg0) && real_cst_p (arg1) && real_cst_p (arg2) && do_mpfr_arg3 (&result, mpfr_fma, TREE_REAL_CST_PTR (arg0), TREE_REAL_CST_PTR (arg1), TREE_REAL_CST_PTR (arg2), REAL_MODE_FORMAT (TYPE_MODE (type)))) return build_real (type, result); return NULL_TREE; }
tree gfc_build_inf_or_huge (tree type, int kind) { if (HONOR_INFINITIES (TYPE_MODE (type))) { REAL_VALUE_TYPE real; real_inf (&real); return build_real (type, real); } else { int k = gfc_validate_kind (BT_REAL, kind, false); return gfc_conv_mpfr_to_tree (gfc_real_kinds[k].huge, kind, 0); } }
tree gfc_conv_mpfr_to_tree (mpfr_t f, int kind, int is_snan) { tree type; int n; REAL_VALUE_TYPE real; n = gfc_validate_kind (BT_REAL, kind, false); gcc_assert (gfc_real_kinds[n].radix == 2); type = gfc_get_real_type (kind); if (mpfr_nan_p (f) && is_snan) real_from_string (&real, "SNaN"); else real_from_mpfr (&real, f, type, GFC_RND_MODE); return build_real (type, real); }
static void java_perform_atof (YYSTYPE *java_lval, char *literal_token, int fflag, int number_beginning) { REAL_VALUE_TYPE value; tree type = (fflag ? FLOAT_TYPE_NODE : DOUBLE_TYPE_NODE); SET_REAL_VALUE_ATOF (value, REAL_VALUE_ATOF (literal_token, TYPE_MODE (type))); if (REAL_VALUE_ISINF (value) || REAL_VALUE_ISNAN (value)) { JAVA_FLOAT_RANGE_ERROR (fflag ? "float" : "double"); value = DCONST0; } else if (IS_ZERO (value)) { /* We check to see if the value is really 0 or if we've found an underflow. We do this in the most primitive imaginable way. */ int really_zero = 1; char *p = literal_token; if (*p == '-') ++p; while (*p && *p != 'e' && *p != 'E') { if (*p != '0' && *p != '.') { really_zero = 0; break; } ++p; } if (! really_zero) { int save_col = ctxp->lexer->position.col; ctxp->lexer->position.col = number_beginning; java_lex_error ("Floating point literal underflow", 0); ctxp->lexer->position.col = save_col; } } SET_LVAL_NODE (build_real (type, value)); }
/* Interpret TOKEN, a floating point number with FLAGS as classified by cpplib. */ static tree interpret_float (const cpp_token *token, unsigned int flags) { tree type; tree value; REAL_VALUE_TYPE real; char *copy; size_t copylen; const char *type_name; /* FIXME: make %T work in error/warning, then we don't need type_name. */ if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) { type = long_double_type_node; type_name = "long double"; } else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL || flag_single_precision_constant) { type = float_type_node; type_name = "float"; } else { type = double_type_node; type_name = "double"; } /* Copy the constant to a nul-terminated buffer. If the constant has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF can't handle them. */ copylen = token->val.str.len; if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) /* Must be an F or L suffix. */ copylen--; if (flags & CPP_N_IMAGINARY) /* I or J suffix. */ copylen--; copy = (char *) alloca (copylen + 1); memcpy (copy, token->val.str.text, copylen); copy[copylen] = '\0'; real_from_string (&real, copy); real_convert (&real, TYPE_MODE (type), &real); /* Both C and C++ require a diagnostic for a floating constant outside the range of representable values of its type. Since we have __builtin_inf* to produce an infinity, it might now be appropriate for this to be a mandatory pedwarn rather than conditioned on -pedantic. */ if (REAL_VALUE_ISINF (real) && pedantic) pedwarn ("floating constant exceeds range of %<%s%>", type_name); /* Create a node with determined type and value. */ value = build_real (type, real); if (flags & CPP_N_IMAGINARY) value = build_complex (NULL_TREE, convert (type, integer_zero_node), value); return value; }
/* Interpret TOKEN, a floating point number with FLAGS as classified by cpplib. */ static tree interpret_float (const cpp_token *token, unsigned int flags) { tree type; tree value; REAL_VALUE_TYPE real; char *copy; size_t copylen; /* Default (no suffix) is double. */ if (flags & CPP_N_DEFAULT) { flags ^= CPP_N_DEFAULT; flags |= CPP_N_MEDIUM; } /* Decode type based on width and properties. */ if (flags & CPP_N_DFLOAT) if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) type = dfloat128_type_node; else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL) type = dfloat32_type_node; else type = dfloat64_type_node; else if ((flags & CPP_N_WIDTH) == CPP_N_LARGE) type = long_double_type_node; else if ((flags & CPP_N_WIDTH) == CPP_N_SMALL || flag_single_precision_constant) type = float_type_node; else type = double_type_node; /* Copy the constant to a nul-terminated buffer. If the constant has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF can't handle them. */ copylen = token->val.str.len; if (flags & CPP_N_DFLOAT) copylen -= 2; else { if ((flags & CPP_N_WIDTH) != CPP_N_MEDIUM) /* Must be an F or L suffix. */ copylen--; if (flags & CPP_N_IMAGINARY) /* I or J suffix. */ copylen--; } copy = (char *) alloca (copylen + 1); memcpy (copy, token->val.str.text, copylen); copy[copylen] = '\0'; real_from_string3 (&real, copy, TYPE_MODE (type)); /* Both C and C++ require a diagnostic for a floating constant outside the range of representable values of its type. Since we have __builtin_inf* to produce an infinity, it might now be appropriate for this to be a mandatory pedwarn rather than conditioned on -pedantic. */ if (REAL_VALUE_ISINF (real) && pedantic) pedwarn ("floating constant exceeds range of %qT", type); /* Create a node with determined type and value. */ value = build_real (type, real); if (flags & CPP_N_IMAGINARY) value = build_complex (NULL_TREE, convert (type, integer_zero_node), value); return value; }
tree gfc_conv_mpfr_to_tree (mpfr_t f, int kind) { tree res; tree type; mp_exp_t exp; char *p; char *q; int n; int edigits; for (n = 0; gfc_real_kinds[n].kind != 0; n++) { if (gfc_real_kinds[n].kind == kind) break; } gcc_assert (gfc_real_kinds[n].kind); n = MAX (abs (gfc_real_kinds[n].min_exponent), abs (gfc_real_kinds[n].max_exponent)); edigits = 1; while (n > 0) { n = n / 10; edigits += 3; } if (kind == gfc_default_double_kind) p = mpfr_get_str (NULL, &exp, 10, 17, f, GFC_RND_MODE); else p = mpfr_get_str (NULL, &exp, 10, 8, f, GFC_RND_MODE); /* We also have one minus sign, "e", "." and a null terminator. */ q = (char *) gfc_getmem (strlen (p) + edigits + 4); if (p[0]) { if (p[0] == '-') { strcpy (&q[2], &p[1]); q[0] = '-'; q[1] = '.'; } else { strcpy (&q[1], p); q[0] = '.'; } strcat (q, "e"); sprintf (&q[strlen (q)], "%d", (int) exp); } else { strcpy (q, "0"); } type = gfc_get_real_type (kind); res = build_real (type, REAL_VALUE_ATOF (q, TYPE_MODE (type))); gfc_free (q); gfc_free (p); return res; }
tree ubsan_instrument_division (location_t loc, tree op0, tree op1) { tree t, tt; tree type = TREE_TYPE (op0); /* At this point both operands should have the same type, because they are already converted to RESULT_TYPE. Use TYPE_MAIN_VARIANT since typedefs can confuse us. */ gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0)) == TYPE_MAIN_VARIANT (TREE_TYPE (op1))); op0 = unshare_expr (op0); op1 = unshare_expr (op1); if (TREE_CODE (type) == INTEGER_TYPE && (flag_sanitize & SANITIZE_DIVIDE)) t = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_int_cst (type, 0)); else if (TREE_CODE (type) == REAL_TYPE && (flag_sanitize & SANITIZE_FLOAT_DIVIDE)) t = fold_build2 (EQ_EXPR, boolean_type_node, op1, build_real (type, dconst0)); else return NULL_TREE; /* We check INT_MIN / -1 only for signed types. */ if (TREE_CODE (type) == INTEGER_TYPE && (flag_sanitize & SANITIZE_DIVIDE) && !TYPE_UNSIGNED (type)) { tree x; tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1), build_int_cst (type, -1)); x = fold_build2 (EQ_EXPR, boolean_type_node, op0, TYPE_MIN_VALUE (type)); x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt); t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x); } /* If the condition was folded to 0, no need to instrument this expression. */ if (integer_zerop (t)) return NULL_TREE; /* In case we have a SAVE_EXPR in a conditional context, we need to make sure it gets evaluated before the condition. */ t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t); t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t); if (flag_sanitize_undefined_trap_on_error) tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc, ubsan_type_descriptor (type), NULL_TREE, NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = (flag_sanitize_recover & SANITIZE_DIVIDE) ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT; tt = builtin_decl_explicit (bcode); op0 = unshare_expr (op0); op1 = unshare_expr (op1); tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0), ubsan_encode_value (op1)); } t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node); return t; }
static tree chrec_fold_plus_1 (enum tree_code code, tree type, tree op0, tree op1) { if (automatically_generated_chrec_p (op0) || automatically_generated_chrec_p (op1)) return chrec_fold_automatically_generated_operands (op0, op1); switch (TREE_CODE (op0)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op0, CHREC_VARIABLE (op0))); switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); return chrec_fold_plus_poly_poly (code, type, op0, op1); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_plus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); else return build_polynomial_chrec (CHREC_VARIABLE (op0), chrec_fold_minus (type, CHREC_LEFT (op0), op1), CHREC_RIGHT (op0)); } CASE_CONVERT: if (tree_contains_chrecs (op0, NULL)) return chrec_dont_know; default: switch (TREE_CODE (op1)) { case POLYNOMIAL_CHREC: gcc_checking_assert (!chrec_contains_symbols_defined_in_loop (op1, CHREC_VARIABLE (op1))); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_plus (type, op0, CHREC_LEFT (op1)), CHREC_RIGHT (op1)); else return build_polynomial_chrec (CHREC_VARIABLE (op1), chrec_fold_minus (type, op0, CHREC_LEFT (op1)), chrec_fold_multiply (type, CHREC_RIGHT (op1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); CASE_CONVERT: if (tree_contains_chrecs (op1, NULL)) return chrec_dont_know; default: { int size = 0; if ((tree_contains_chrecs (op0, &size) || tree_contains_chrecs (op1, &size)) && size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) return build2 (code, type, op0, op1); else if (size < PARAM_VALUE (PARAM_SCEV_MAX_EXPR_SIZE)) { if (code == POINTER_PLUS_EXPR) return fold_build_pointer_plus (fold_convert (type, op0), op1); else return fold_build2 (code, type, fold_convert (type, op0), fold_convert (type, op1)); } else return chrec_dont_know; } } } }
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 tree fold_const_call_1 (built_in_function fn, tree type, tree arg0, tree arg1) { machine_mode mode = TYPE_MODE (type); machine_mode arg0_mode = TYPE_MODE (TREE_TYPE (arg0)); machine_mode arg1_mode = TYPE_MODE (TREE_TYPE (arg1)); if (arg0_mode == arg1_mode && real_cst_p (arg0) && real_cst_p (arg1)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode)); if (mode == arg0_mode) { /* real, real -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0), TREE_REAL_CST_PTR (arg1), REAL_MODE_FORMAT (mode))) return build_real (type, result); } return NULL_TREE; } if (real_cst_p (arg0) && integer_cst_p (arg1)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg0_mode)); if (mode == arg0_mode) { /* real, int -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0), arg1, REAL_MODE_FORMAT (mode))) return build_real (type, result); } return NULL_TREE; } if (integer_cst_p (arg0) && real_cst_p (arg1)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg1_mode)); if (mode == arg1_mode) { /* int, real -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_sss (&result, fn, arg0, TREE_REAL_CST_PTR (arg1), REAL_MODE_FORMAT (mode))) return build_real (type, result); } return NULL_TREE; } if (arg0_mode == arg1_mode && complex_cst_p (arg0) && complex_cst_p (arg1)) { gcc_checking_assert (COMPLEX_MODE_P (arg0_mode)); machine_mode inner_mode = GET_MODE_INNER (arg0_mode); tree arg0r = TREE_REALPART (arg0); tree arg0i = TREE_IMAGPART (arg0); tree arg1r = TREE_REALPART (arg1); tree arg1i = TREE_IMAGPART (arg1); if (mode == arg0_mode && real_cst_p (arg0r) && real_cst_p (arg0i) && real_cst_p (arg1r) && real_cst_p (arg1i)) { /* complex real, complex real -> complex real. */ REAL_VALUE_TYPE result_real, result_imag; if (fold_const_call_ccc (&result_real, &result_imag, fn, TREE_REAL_CST_PTR (arg0r), TREE_REAL_CST_PTR (arg0i), TREE_REAL_CST_PTR (arg1r), TREE_REAL_CST_PTR (arg1i), REAL_MODE_FORMAT (inner_mode))) return build_complex (type, build_real (TREE_TYPE (type), result_real), build_real (TREE_TYPE (type), result_imag)); } return NULL_TREE; } return NULL_TREE; }
static tree fold_const_call_1 (built_in_function fn, tree type, tree arg) { machine_mode mode = TYPE_MODE (type); machine_mode arg_mode = TYPE_MODE (TREE_TYPE (arg)); if (integer_cst_p (arg)) { if (SCALAR_INT_MODE_P (mode)) { wide_int result; if (fold_const_call_ss (&result, fn, arg, TYPE_PRECISION (type), TREE_TYPE (arg))) return wide_int_to_tree (type, result); } return NULL_TREE; } if (real_cst_p (arg)) { gcc_checking_assert (SCALAR_FLOAT_MODE_P (arg_mode)); if (mode == arg_mode) { /* real -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_ss (&result, fn, TREE_REAL_CST_PTR (arg), REAL_MODE_FORMAT (mode))) return build_real (type, result); } else if (COMPLEX_MODE_P (mode) && GET_MODE_INNER (mode) == arg_mode) { /* real -> complex real. */ REAL_VALUE_TYPE result_real, result_imag; if (fold_const_call_cs (&result_real, &result_imag, fn, TREE_REAL_CST_PTR (arg), REAL_MODE_FORMAT (arg_mode))) return build_complex (type, build_real (TREE_TYPE (type), result_real), build_real (TREE_TYPE (type), result_imag)); } else if (INTEGRAL_TYPE_P (type)) { /* real -> int. */ wide_int result; if (fold_const_call_ss (&result, fn, TREE_REAL_CST_PTR (arg), TYPE_PRECISION (type), REAL_MODE_FORMAT (arg_mode))) return wide_int_to_tree (type, result); } return NULL_TREE; } if (complex_cst_p (arg)) { gcc_checking_assert (COMPLEX_MODE_P (arg_mode)); machine_mode inner_mode = GET_MODE_INNER (arg_mode); tree argr = TREE_REALPART (arg); tree argi = TREE_IMAGPART (arg); if (mode == arg_mode && real_cst_p (argr) && real_cst_p (argi)) { /* complex real -> complex real. */ REAL_VALUE_TYPE result_real, result_imag; if (fold_const_call_cc (&result_real, &result_imag, fn, TREE_REAL_CST_PTR (argr), TREE_REAL_CST_PTR (argi), REAL_MODE_FORMAT (inner_mode))) return build_complex (type, build_real (TREE_TYPE (type), result_real), build_real (TREE_TYPE (type), result_imag)); } if (mode == inner_mode && real_cst_p (argr) && real_cst_p (argi)) { /* complex real -> real. */ REAL_VALUE_TYPE result; if (fold_const_call_sc (&result, fn, TREE_REAL_CST_PTR (argr), TREE_REAL_CST_PTR (argi), REAL_MODE_FORMAT (inner_mode))) return build_real (type, result); } return NULL_TREE; } return NULL_TREE; }
static inline tree chrec_fold_plus_poly_poly (enum tree_code code, tree type, tree poly0, tree poly1) { tree left, right; struct loop *loop0 = get_chrec_loop (poly0); struct loop *loop1 = get_chrec_loop (poly1); tree rtype = code == POINTER_PLUS_EXPR ? chrec_type (poly1) : type; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); if (POINTER_TYPE_P (chrec_type (poly0))) gcc_checking_assert (ptrofftype_p (chrec_type (poly1)) && useless_type_conversion_p (type, chrec_type (poly0))); else gcc_checking_assert (useless_type_conversion_p (type, chrec_type (poly0)) && useless_type_conversion_p (type, chrec_type (poly1))); /* {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2, {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2, {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */ if (flow_loop_nested_p (loop0, loop1)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)), CHREC_RIGHT (poly1)); else return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)), chrec_fold_multiply (type, CHREC_RIGHT (poly1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); } if (flow_loop_nested_p (loop1, loop0)) { if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_plus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); else return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_minus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); } /* This function should never be called for chrecs of loops that do not belong to the same loop nest. */ gcc_assert (loop0 == loop1); if (code == PLUS_EXPR || code == POINTER_PLUS_EXPR) { left = chrec_fold_plus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_plus (rtype, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } else { left = chrec_fold_minus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_minus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } if (chrec_zerop (right)) return left; else return build_polynomial_chrec (CHREC_VARIABLE (poly0), left, right); }
static inline tree chrec_fold_plus_poly_poly (enum tree_code code, tree type, tree poly0, tree poly1) { tree left, right; gcc_assert (poly0); gcc_assert (poly1); gcc_assert (TREE_CODE (poly0) == POLYNOMIAL_CHREC); gcc_assert (TREE_CODE (poly1) == POLYNOMIAL_CHREC); gcc_assert (chrec_type (poly0) == chrec_type (poly1)); gcc_assert (type == chrec_type (poly0)); /* {a, +, b}_1 + {c, +, d}_2 -> {{a, +, b}_1 + c, +, d}_2, {a, +, b}_2 + {c, +, d}_1 -> {{c, +, d}_1 + a, +, b}_2, {a, +, b}_x + {c, +, d}_x -> {a+c, +, b+d}_x. */ if (CHREC_VARIABLE (poly0) < CHREC_VARIABLE (poly1)) { if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_plus (type, poly0, CHREC_LEFT (poly1)), CHREC_RIGHT (poly1)); else return build_polynomial_chrec (CHREC_VARIABLE (poly1), chrec_fold_minus (type, poly0, CHREC_LEFT (poly1)), chrec_fold_multiply (type, CHREC_RIGHT (poly1), SCALAR_FLOAT_TYPE_P (type) ? build_real (type, dconstm1) : build_int_cst_type (type, -1))); } if (CHREC_VARIABLE (poly0) > CHREC_VARIABLE (poly1)) { if (code == PLUS_EXPR) return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_plus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); else return build_polynomial_chrec (CHREC_VARIABLE (poly0), chrec_fold_minus (type, CHREC_LEFT (poly0), poly1), CHREC_RIGHT (poly0)); } if (code == PLUS_EXPR) { left = chrec_fold_plus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_plus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } else { left = chrec_fold_minus (type, CHREC_LEFT (poly0), CHREC_LEFT (poly1)); right = chrec_fold_minus (type, CHREC_RIGHT (poly0), CHREC_RIGHT (poly1)); } if (chrec_zerop (right)) return left; else return build_polynomial_chrec (CHREC_VARIABLE (poly0), left, right); }