[PATCH] Fix up __builtin_*_overflow expansion on some targets (PR target/63848)
Hi! Apparently, emit_cmp_and_jump_insns can silently generate wrong code for wider modes on some targets, so this patch changes all those calls in internal-fn.c to do_compare_rtx_and_jump, which is a wrapper around emit_cmp_and_jump_insns that should handle the wider mode comparison expansion. Unfortunately, the order of arguments is different :(. No new testcases provided, the existing testsuite exhibited this on various targets. Bootstrapped/regtested on x86_64-linux and i686-linux, tested on the testcases for ia64 and Uros tested the testcases on Alpha (in both cases they previously failed), ok for trunk? 2014-11-21 Jakub Jelinek ja...@redhat.com PR target/63848 PR target/63975 * internal-fn.c (expand_arith_overflow_result_store, expand_addsub_overflow, expand_neg_overflow, expand_mul_overflow): Use do_compare_rtx_and_jump instead of emit_cmp_and_jump_insns everywhere, adjust arguments to those functions. Use unsignedp = true for EQ, NE, GEU, LEU, LTU and GTU comparisons. --- gcc/internal-fn.c.jj2014-11-19 18:48:02.0 +0100 +++ gcc/internal-fn.c 2014-11-21 17:34:00.634621461 +0100 @@ -386,8 +386,8 @@ expand_arith_overflow_result_store (tree int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))); lres = convert_modes (tgtmode, mode, res, uns); gcc_assert (GET_MODE_PRECISION (tgtmode) GET_MODE_PRECISION (mode)); - emit_cmp_and_jump_insns (res, convert_modes (mode, tgtmode, lres, uns), - EQ, NULL_RTX, mode, false, done_label, + do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns), + EQ, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); write_complex_part (target, const1_rtx, true); emit_label (done_label); @@ -533,8 +533,8 @@ expand_addsub_overflow (location_t loc, ? (CONST_SCALAR_INT_P (op0) REG_P (op1)) : CONST_SCALAR_INT_P (op1))) tem = op1; - emit_cmp_and_jump_insns (res, tem, code == PLUS_EXPR ? GEU : LEU, - NULL_RTX, mode, false, done_label, + do_compare_rtx_and_jump (res, tem, code == PLUS_EXPR ? GEU : LEU, + true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -549,7 +549,7 @@ expand_addsub_overflow (location_t loc, rtx tem = expand_binop (mode, add_optab, code == PLUS_EXPR ? res : op0, sgn, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (tem, op1, GEU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -591,9 +591,9 @@ expand_addsub_overflow (location_t loc, emit_jump (do_error); else if (pos_neg == 3) /* If ARG0 is not known to be always positive, check at runtime. */ - emit_cmp_and_jump_insns (op0, const0_rtx, LT, NULL_RTX, mode, false, -do_error, PROB_VERY_UNLIKELY); - emit_cmp_and_jump_insns (op1, op0, LEU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX, +NULL_RTX, do_error, PROB_VERY_UNLIKELY); + do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -607,7 +607,7 @@ expand_addsub_overflow (location_t loc, OPTAB_LIB_WIDEN); rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (op0, tem, LTU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -619,8 +619,8 @@ expand_addsub_overflow (location_t loc, unsigned. */ res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false, - do_error, PROB_VERY_UNLIKELY); + do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX, + NULL_RTX, do_error, PROB_VERY_UNLIKELY); rtx tem = op1; /* The operation is commutative, so we can pick operand to compare against. For prec = BITS_PER_WORD, I think preferring REG operand @@ -633,7 +633,7 @@ expand_addsub_overflow (location_t loc, ? (CONST_SCALAR_INT_P (op1) REG_P (op0)) : CONST_SCALAR_INT_P (op0)) tem = op0; - emit_cmp_and_jump_insns (res, tem, GEU,
Re: [PATCH] Fix up __builtin_*_overflow expansion on some targets (PR target/63848)
On November 21, 2014 8:08:37 PM CET, Jakub Jelinek ja...@redhat.com wrote: Hi! Apparently, emit_cmp_and_jump_insns can silently generate wrong code for wider modes on some targets, so this patch changes all those calls in internal-fn.c to do_compare_rtx_and_jump, which is a wrapper around emit_cmp_and_jump_insns that should handle the wider mode comparison expansion. Unfortunately, the order of arguments is different :(. No new testcases provided, the existing testsuite exhibited this on various targets. Bootstrapped/regtested on x86_64-linux and i686-linux, tested on the testcases for ia64 and Uros tested the testcases on Alpha (in both cases they previously failed), ok for trunk? Ok. Thanks, Richard. 2014-11-21 Jakub Jelinek ja...@redhat.com PR target/63848 PR target/63975 * internal-fn.c (expand_arith_overflow_result_store, expand_addsub_overflow, expand_neg_overflow, expand_mul_overflow): Use do_compare_rtx_and_jump instead of emit_cmp_and_jump_insns everywhere, adjust arguments to those functions. Use unsignedp = true for EQ, NE, GEU, LEU, LTU and GTU comparisons. --- gcc/internal-fn.c.jj 2014-11-19 18:48:02.0 +0100 +++ gcc/internal-fn.c 2014-11-21 17:34:00.634621461 +0100 @@ -386,8 +386,8 @@ expand_arith_overflow_result_store (tree int uns = TYPE_UNSIGNED (TREE_TYPE (TREE_TYPE (lhs))); lres = convert_modes (tgtmode, mode, res, uns); gcc_assert (GET_MODE_PRECISION (tgtmode) GET_MODE_PRECISION (mode)); - emit_cmp_and_jump_insns (res, convert_modes (mode, tgtmode, lres, uns), - EQ, NULL_RTX, mode, false, done_label, + do_compare_rtx_and_jump (res, convert_modes (mode, tgtmode, lres, uns), + EQ, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); write_complex_part (target, const1_rtx, true); emit_label (done_label); @@ -533,8 +533,8 @@ expand_addsub_overflow (location_t loc, ? (CONST_SCALAR_INT_P (op0) REG_P (op1)) : CONST_SCALAR_INT_P (op1))) tem = op1; - emit_cmp_and_jump_insns (res, tem, code == PLUS_EXPR ? GEU : LEU, - NULL_RTX, mode, false, done_label, + do_compare_rtx_and_jump (res, tem, code == PLUS_EXPR ? GEU : LEU, + true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -549,7 +549,7 @@ expand_addsub_overflow (location_t loc, rtx tem = expand_binop (mode, add_optab, code == PLUS_EXPR ? res : op0, sgn, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (tem, op1, GEU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (tem, op1, GEU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -591,9 +591,9 @@ expand_addsub_overflow (location_t loc, emit_jump (do_error); else if (pos_neg == 3) /* If ARG0 is not known to be always positive, check at runtime. */ - emit_cmp_and_jump_insns (op0, const0_rtx, LT, NULL_RTX, mode, false, - do_error, PROB_VERY_UNLIKELY); - emit_cmp_and_jump_insns (op1, op0, LEU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (op0, const0_rtx, LT, false, mode, NULL_RTX, + NULL_RTX, do_error, PROB_VERY_UNLIKELY); + do_compare_rtx_and_jump (op1, op0, LEU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -607,7 +607,7 @@ expand_addsub_overflow (location_t loc, OPTAB_LIB_WIDEN); rtx tem = expand_binop (mode, add_optab, op1, sgn, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (op0, tem, LTU, NULL_RTX, mode, false, + do_compare_rtx_and_jump (op0, tem, LTU, true, mode, NULL_RTX, NULL_RTX, done_label, PROB_VERY_LIKELY); goto do_error_label; } @@ -619,8 +619,8 @@ expand_addsub_overflow (location_t loc, unsigned. */ res = expand_binop (mode, add_optab, op0, op1, NULL_RTX, false, OPTAB_LIB_WIDEN); - emit_cmp_and_jump_insns (res, const0_rtx, LT, NULL_RTX, mode, false, - do_error, PROB_VERY_UNLIKELY); + do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode, NULL_RTX, + NULL_RTX, do_error, PROB_VERY_UNLIKELY); rtx tem = op1; /* The operation is commutative, so we can pick operand to compare against. For prec = BITS_PER_WORD, I think preferring REG operand @@ -633,7 +633,7 @@ expand_addsub_overflow (location_t loc, ? (CONST_SCALAR_INT_P (op1) REG_P (op0)) : CONST_SCALAR_INT_P (op0)) tem = op0;