[PATCH] Fix up __builtin_*_overflow expansion on some targets (PR target/63848)

2014-11-21 Thread Jakub Jelinek
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)

2014-11-21 Thread Richard Biener
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;