From 47135167124c764f351caf0f0f461e3c865e58fa Mon Sep 17 00:00:00 2001 From: Eric Botcazou Date: Fri, 28 Oct 2016 18:10:14 +0000 Subject: [PATCH] dojump.c (do_jump_by_parts_greater_rtx): Invert probability when swapping the arms of the branch. * dojump.c (do_jump_by_parts_greater_rtx): Invert probability when swapping the arms of the branch. * internal-fn.c (expand_addsub_overflow): Use a straight-line code sequence for the generic signed-signed-signed case. From-SVN: r241656 --- gcc/ChangeLog | 7 ++++ gcc/dojump.c | 1 + gcc/internal-fn.c | 82 +++++++++++++++++++++++++++-------------------- 3 files changed, 55 insertions(+), 35 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3f2ea4dfc71..a3b49ecec75 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2016-10-28 Eric Botcazou + + * dojump.c (do_jump_by_parts_greater_rtx): Invert probability when + swapping the arms of the branch. + * internal-fn.c (expand_addsub_overflow): Use a straight-line code + sequence for the generic signed-signed-signed case. + 2016-10-28 Jeff Law * config/bfin/bfin.c (bfin_legitimate_address_p): Add missing diff --git a/gcc/dojump.c b/gcc/dojump.c index 5a32c34aee6..e6ddf78898d 100644 --- a/gcc/dojump.c +++ b/gcc/dojump.c @@ -703,6 +703,7 @@ do_jump_by_parts_greater_rtx (machine_mode mode, int unsignedp, rtx op0, if_false_label = drop_through_label; drop_through_if_true = false; drop_through_if_false = true; + prob = inv (prob); } /* Compare a word at a time, high order first. */ diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 44776976d2a..156ba31047c 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -847,56 +847,68 @@ expand_addsub_overflow (location_t loc, tree_code code, tree lhs, delete_insns_since (last); } - rtx_code_label *sub_check = gen_label_rtx (); - int pos_neg = 3; - /* Compute the operation. On RTL level, the addition is always unsigned. */ res = expand_binop (mode, code == PLUS_EXPR ? add_optab : sub_optab, op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN); - /* If we can prove one of the arguments (for MINUS_EXPR only + /* If we can prove that one of the arguments (for MINUS_EXPR only the second operand, as subtraction is not commutative) is always non-negative or always negative, we can do just one comparison - and conditional jump instead of 2 at runtime, 3 present in the - emitted code. If one of the arguments is CONST_INT, all we - need is to make sure it is op1, then the first - do_compare_rtx_and_jump will be just folded. Otherwise try - to use range info if available. */ - if (code == PLUS_EXPR && CONST_INT_P (op0)) - std::swap (op0, op1); - else if (CONST_INT_P (op1)) - ; - else if (code == PLUS_EXPR && TREE_CODE (arg0) == SSA_NAME) + and conditional jump. */ + int pos_neg = get_range_pos_neg (arg1); + if (code == PLUS_EXPR) { - pos_neg = get_range_pos_neg (arg0); - if (pos_neg != 3) - std::swap (op0, op1); + int pos_neg0 = get_range_pos_neg (arg0); + if (pos_neg0 != 3 && pos_neg == 3) + { + std::swap (op0, op1); + pos_neg = pos_neg0; + } } - if (pos_neg == 3 && !CONST_INT_P (op1) && TREE_CODE (arg1) == SSA_NAME) - pos_neg = get_range_pos_neg (arg1); - /* If the op1 is negative, we have to use a different check. */ + /* Addition overflows if and only if the two operands have the same sign, + and the result has the opposite sign. Subtraction overflows if and + only if the two operands have opposite sign, and the subtrahend has + the same sign as the result. Here 0 is counted as positive. */ if (pos_neg == 3) - do_compare_rtx_and_jump (op1, const0_rtx, LT, false, mode, NULL_RTX, - NULL, sub_check, PROB_EVEN); + { + /* Compute op0 ^ op1 (operands have opposite sign). */ + rtx op_xor = expand_binop (mode, xor_optab, op0, op1, NULL_RTX, false, + OPTAB_LIB_WIDEN); - /* Compare the result of the operation with one of the operands. */ - if (pos_neg & 1) - do_compare_rtx_and_jump (res, op0, code == PLUS_EXPR ? GE : LE, - false, mode, NULL_RTX, NULL, done_label, - PROB_VERY_LIKELY); + /* Compute res ^ op1 (result and 2nd operand have opposite sign). */ + rtx res_xor = expand_binop (mode, xor_optab, res, op1, NULL_RTX, false, + OPTAB_LIB_WIDEN); - /* If we get here, we have to print the error. */ - if (pos_neg == 3) - { - emit_jump (do_error); - emit_label (sub_check); + rtx tem; + if (code == PLUS_EXPR) + { + /* Compute (res ^ op1) & ~(op0 ^ op1). */ + tem = expand_unop (mode, one_cmpl_optab, op_xor, NULL_RTX, false); + tem = expand_binop (mode, and_optab, res_xor, tem, NULL_RTX, false, + OPTAB_LIB_WIDEN); + } + else + { + /* Compute (op0 ^ op1) & ~(res ^ op1). */ + tem = expand_unop (mode, one_cmpl_optab, res_xor, NULL_RTX, false); + tem = expand_binop (mode, and_optab, op_xor, tem, NULL_RTX, false, + OPTAB_LIB_WIDEN); + } + + /* No overflow if the result has bit sign cleared. */ + do_compare_rtx_and_jump (tem, const0_rtx, GE, false, mode, NULL_RTX, + NULL, done_label, PROB_VERY_LIKELY); } - /* We have k = a + b for b < 0 here. k <= a must hold. */ - if (pos_neg & 2) - do_compare_rtx_and_jump (res, op0, code == PLUS_EXPR ? LE : GE, + /* Compare the result of the operation with the first operand. + No overflow for addition if second operand is positive and result + is larger or second operand is negative and result is smaller. + Likewise for subtraction with sign of second operand flipped. */ + else + do_compare_rtx_and_jump (res, op0, + (pos_neg == 1) ^ (code == MINUS_EXPR) ? GE : LE, false, mode, NULL_RTX, NULL, done_label, PROB_VERY_LIKELY); } -- 2.30.2