int default_unspec_may_trap_p (const_rtx x, unsigned flags) { int i; /* Any floating arithmetic may trap. */ if ((SCALAR_FLOAT_MODE_P (GET_MODE (x)) && flag_trapping_math)) return 1; for (i = 0; i < XVECLEN (x, 0); ++i) { if (may_trap_p_1 (XVECEXP (x, 0, i), flags)) return 1; } return 0; }
void do_compare_rtx_and_jump (rtx op0, rtx op1, enum rtx_code code, int unsignedp, enum machine_mode mode, rtx size, rtx if_false_label, rtx if_true_label, int prob) { rtx tem; rtx dummy_label = NULL_RTX; /* Reverse the comparison if that is safe and we want to jump if it is false. Also convert to the reverse comparison if the target can implement it. */ if ((! if_true_label || ! can_compare_p (code, mode, ccp_jump)) && (! FLOAT_MODE_P (mode) || code == ORDERED || code == UNORDERED || (! HONOR_NANS (mode) && (code == LTGT || code == UNEQ)) || (! HONOR_SNANS (mode) && (code == EQ || code == NE)))) { enum rtx_code rcode; if (FLOAT_MODE_P (mode)) rcode = reverse_condition_maybe_unordered (code); else rcode = reverse_condition (code); /* Canonicalize to UNORDERED for the libcall. */ if (can_compare_p (rcode, mode, ccp_jump) || (code == ORDERED && ! can_compare_p (ORDERED, mode, ccp_jump))) { tem = if_true_label; if_true_label = if_false_label; if_false_label = tem; code = rcode; prob = inv (prob); } } /* If one operand is constant, make it the second one. Only do this if the other operand is not constant as well. */ if (swap_commutative_operands_p (op0, op1)) { tem = op0; op0 = op1; op1 = tem; code = swap_condition (code); } do_pending_stack_adjust (); code = unsignedp ? unsigned_condition (code) : code; if (0 != (tem = simplify_relational_operation (code, mode, VOIDmode, op0, op1))) { if (CONSTANT_P (tem)) { rtx label = (tem == const0_rtx || tem == CONST0_RTX (mode)) ? if_false_label : if_true_label; if (label) emit_jump (label); return; } code = GET_CODE (tem); mode = GET_MODE (tem); op0 = XEXP (tem, 0); op1 = XEXP (tem, 1); unsignedp = (code == GTU || code == LTU || code == GEU || code == LEU); } if (! if_true_label) dummy_label = if_true_label = gen_label_rtx (); if (GET_MODE_CLASS (mode) == MODE_INT && ! can_compare_p (code, mode, ccp_jump)) { switch (code) { case LTU: do_jump_by_parts_greater_rtx (mode, 1, op1, op0, if_false_label, if_true_label, prob); break; case LEU: do_jump_by_parts_greater_rtx (mode, 1, op0, op1, if_true_label, if_false_label, inv (prob)); break; case GTU: do_jump_by_parts_greater_rtx (mode, 1, op0, op1, if_false_label, if_true_label, prob); break; case GEU: do_jump_by_parts_greater_rtx (mode, 1, op1, op0, if_true_label, if_false_label, inv (prob)); break; case LT: do_jump_by_parts_greater_rtx (mode, 0, op1, op0, if_false_label, if_true_label, prob); break; case LE: do_jump_by_parts_greater_rtx (mode, 0, op0, op1, if_true_label, if_false_label, inv (prob)); break; case GT: do_jump_by_parts_greater_rtx (mode, 0, op0, op1, if_false_label, if_true_label, prob); break; case GE: do_jump_by_parts_greater_rtx (mode, 0, op1, op0, if_true_label, if_false_label, inv (prob)); break; case EQ: do_jump_by_parts_equality_rtx (mode, op0, op1, if_false_label, if_true_label, prob); break; case NE: do_jump_by_parts_equality_rtx (mode, op0, op1, if_true_label, if_false_label, inv (prob)); break; default: gcc_unreachable (); } } else { if (SCALAR_FLOAT_MODE_P (mode) && ! can_compare_p (code, mode, ccp_jump) && can_compare_p (swap_condition (code), mode, ccp_jump)) { rtx tmp; code = swap_condition (code); tmp = op0; op0 = op1; op1 = tmp; } else if (SCALAR_FLOAT_MODE_P (mode) && ! can_compare_p (code, mode, ccp_jump) /* Never split ORDERED and UNORDERED. These must be implemented. */ && (code != ORDERED && code != UNORDERED) /* Split a floating-point comparison if we can jump on other conditions... */ && (have_insn_for (COMPARE, mode) /* ... or if there is no libcall for it. */ || code_to_optab (code) == unknown_optab)) { enum rtx_code first_code; bool and_them = split_comparison (code, mode, &first_code, &code); /* If there are no NaNs, the first comparison should always fall through. */ if (!HONOR_NANS (mode)) gcc_assert (first_code == (and_them ? ORDERED : UNORDERED)); else { if (and_them) { rtx dest_label; /* If we only jump if true, just bypass the second jump. */ if (! if_false_label) { if (! dummy_label) dummy_label = gen_label_rtx (); dest_label = dummy_label; } else dest_label = if_false_label; do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode, size, dest_label, NULL_RTX, prob); } else do_compare_rtx_and_jump (op0, op1, first_code, unsignedp, mode, size, NULL_RTX, if_true_label, prob); } } emit_cmp_and_jump_insns (op0, op1, code, size, mode, unsignedp, if_true_label, prob); } if (if_false_label) emit_jump (if_false_label); if (dummy_label) emit_label (dummy_label); }
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; }