re PR middle-end/78416 (wrong code for division by (u128)~INT64_MAX at -O0)

PR middle-end/78416
	* expmed.c (expand_divmod): Use wide_int for computation of
	op1_is_pow2.  Don't set it if op1 is 0.  Formatting fixes.
	Use size <= HOST_BITS_PER_WIDE_INT instead of
	HOST_BITS_PER_WIDE_INT >= size.

	* gcc.dg/torture/pr78416.c: New test.

From-SVN: r242690
This commit is contained in:
Jakub Jelinek 2016-11-22 11:14:21 +01:00 committed by Jakub Jelinek
parent 9b28cb6f0a
commit 76a7314dc9
4 changed files with 57 additions and 23 deletions

View File

@ -1,5 +1,11 @@
2016-11-22 Jakub Jelinek <jakub@redhat.com> 2016-11-22 Jakub Jelinek <jakub@redhat.com>
PR middle-end/78416
* expmed.c (expand_divmod): Use wide_int for computation of
op1_is_pow2. Don't set it if op1 is 0. Formatting fixes.
Use size <= HOST_BITS_PER_WIDE_INT instead of
HOST_BITS_PER_WIDE_INT >= size.
PR tree-optimization/78445 PR tree-optimization/78445
* tree-if-conv.c (tree_if_conversion): If any_pred_load_store or * tree-if-conv.c (tree_if_conversion): If any_pred_load_store or
any_complicated_phi, version loop even if flag_tree_loop_if_convert is any_complicated_phi, version loop even if flag_tree_loop_if_convert is

View File

@ -3994,11 +3994,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
op1_is_constant = CONST_INT_P (op1); op1_is_constant = CONST_INT_P (op1);
if (op1_is_constant) if (op1_is_constant)
{ {
unsigned HOST_WIDE_INT ext_op1 = UINTVAL (op1); wide_int ext_op1 = rtx_mode_t (op1, mode);
if (unsignedp) op1_is_pow2 = (wi::popcount (ext_op1) == 1
ext_op1 &= GET_MODE_MASK (mode); || (! unsignedp
op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1) && wi::popcount (wi::neg (ext_op1)) == 1));
|| (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1))));
} }
/* /*
@ -4079,11 +4078,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
not straightforward to generalize this. Maybe we should make an array not straightforward to generalize this. Maybe we should make an array
of possible modes in init_expmed? Save this for GCC 2.7. */ of possible modes in init_expmed? Save this for GCC 2.7. */
optab1 = ((op1_is_pow2 && op1 != const0_rtx) optab1 = (op1_is_pow2
? (unsignedp ? lshr_optab : ashr_optab) ? (unsignedp ? lshr_optab : ashr_optab)
: (unsignedp ? udiv_optab : sdiv_optab)); : (unsignedp ? udiv_optab : sdiv_optab));
optab2 = ((op1_is_pow2 && op1 != const0_rtx) optab2 = (op1_is_pow2 ? optab1
? optab1
: (unsignedp ? udivmod_optab : sdivmod_optab)); : (unsignedp ? udivmod_optab : sdivmod_optab));
for (compute_mode = mode; compute_mode != VOIDmode; for (compute_mode = mode; compute_mode != VOIDmode;
@ -4139,10 +4137,15 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
/* convert_modes may have placed op1 into a register, so we /* convert_modes may have placed op1 into a register, so we
must recompute the following. */ must recompute the following. */
op1_is_constant = CONST_INT_P (op1); op1_is_constant = CONST_INT_P (op1);
op1_is_pow2 = (op1_is_constant if (op1_is_constant)
&& ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) {
|| (! unsignedp wide_int ext_op1 = rtx_mode_t (op1, compute_mode);
&& EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1)))))); op1_is_pow2 = (wi::popcount (ext_op1) == 1
|| (! unsignedp
&& wi::popcount (wi::neg (ext_op1)) == 1));
}
else
op1_is_pow2 = 0;
} }
/* If one of the operands is a volatile MEM, copy it into a register. */ /* If one of the operands is a volatile MEM, copy it into a register. */
@ -4182,10 +4185,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
unsigned HOST_WIDE_INT mh, ml; unsigned HOST_WIDE_INT mh, ml;
int pre_shift, post_shift; int pre_shift, post_shift;
int dummy; int dummy;
unsigned HOST_WIDE_INT d = (INTVAL (op1) wide_int wd = rtx_mode_t (op1, compute_mode);
& GET_MODE_MASK (compute_mode)); unsigned HOST_WIDE_INT d = wd.to_uhwi ();
if (EXACT_POWER_OF_2_OR_ZERO_P (d)) if (wi::popcount (wd) == 1)
{ {
pre_shift = floor_log2 (d); pre_shift = floor_log2 (d);
if (rem_flag) if (rem_flag)
@ -4325,7 +4328,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
else if (d == -1) else if (d == -1)
quotient = expand_unop (compute_mode, neg_optab, op0, quotient = expand_unop (compute_mode, neg_optab, op0,
tquotient, 0); tquotient, 0);
else if (HOST_BITS_PER_WIDE_INT >= size else if (size <= HOST_BITS_PER_WIDE_INT
&& abs_d == HOST_WIDE_INT_1U << (size - 1)) && abs_d == HOST_WIDE_INT_1U << (size - 1))
{ {
/* This case is not handled correctly below. */ /* This case is not handled correctly below. */
@ -4335,6 +4338,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
goto fail1; goto fail1;
} }
else if (EXACT_POWER_OF_2_OR_ZERO_P (d) else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
&& (size <= HOST_BITS_PER_WIDE_INT || d >= 0)
&& (rem_flag && (rem_flag
? smod_pow2_cheap (speed, compute_mode) ? smod_pow2_cheap (speed, compute_mode)
: sdiv_pow2_cheap (speed, compute_mode)) : sdiv_pow2_cheap (speed, compute_mode))
@ -4348,7 +4352,9 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
compute_mode) compute_mode)
!= CODE_FOR_nothing))) != CODE_FOR_nothing)))
; ;
else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d)) else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d)
&& (size <= HOST_BITS_PER_WIDE_INT
|| abs_d != (unsigned HOST_WIDE_INT) d))
{ {
if (rem_flag) if (rem_flag)
{ {
@ -4483,7 +4489,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
case FLOOR_DIV_EXPR: case FLOOR_DIV_EXPR:
case FLOOR_MOD_EXPR: case FLOOR_MOD_EXPR:
/* We will come here only for signed operations. */ /* We will come here only for signed operations. */
if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size) if (op1_is_constant && size <= HOST_BITS_PER_WIDE_INT)
{ {
unsigned HOST_WIDE_INT mh, ml; unsigned HOST_WIDE_INT mh, ml;
int pre_shift, lgup, post_shift; int pre_shift, lgup, post_shift;
@ -4552,9 +4558,8 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
op0, constm1_rtx), NULL_RTX); op0, constm1_rtx), NULL_RTX);
t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX, t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX,
0, OPTAB_WIDEN); 0, OPTAB_WIDEN);
nsign = expand_shift nsign = expand_shift (RSHIFT_EXPR, compute_mode, t2,
(RSHIFT_EXPR, compute_mode, t2, size - 1, NULL_RTX, 0);
size - 1, NULL_RTX, 0);
t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign), t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign),
NULL_RTX); NULL_RTX);
t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1, t4 = expand_divmod (0, TRUNC_DIV_EXPR, compute_mode, t3, op1,
@ -4663,7 +4668,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
case CEIL_MOD_EXPR: case CEIL_MOD_EXPR:
if (unsignedp) if (unsignedp)
{ {
if (op1_is_constant && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))) if (op1_is_constant
&& EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
&& (size <= HOST_BITS_PER_WIDE_INT
|| INTVAL (op1) >= 0))
{ {
rtx t1, t2, t3; rtx t1, t2, t3;
unsigned HOST_WIDE_INT d = INTVAL (op1); unsigned HOST_WIDE_INT d = INTVAL (op1);
@ -4876,7 +4884,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode,
break; break;
case EXACT_DIV_EXPR: case EXACT_DIV_EXPR:
if (op1_is_constant && HOST_BITS_PER_WIDE_INT >= size) if (op1_is_constant && size <= HOST_BITS_PER_WIDE_INT)
{ {
HOST_WIDE_INT d = INTVAL (op1); HOST_WIDE_INT d = INTVAL (op1);
unsigned HOST_WIDE_INT ml; unsigned HOST_WIDE_INT ml;

View File

@ -1,5 +1,8 @@
2016-11-22 Jakub Jelinek <jakub@redhat.com> 2016-11-22 Jakub Jelinek <jakub@redhat.com>
PR middle-end/78416
* gcc.dg/torture/pr78416.c: New test.
PR tree-optimization/78445 PR tree-optimization/78445
* gcc.dg/pr78445.c: New test. * gcc.dg/pr78445.c: New test.

View File

@ -0,0 +1,17 @@
/* PR middle-end/78416 */
/* { dg-do run { target int128 } } */
int
main ()
{
unsigned __int128 x;
x = 0xFFFFFFFFFFFFFFFFULL;
x /= ~0x7FFFFFFFFFFFFFFFLL;
if (x != 0)
__builtin_abort ();
x = ~0x7FFFFFFFFFFFFFFELL;
x /= ~0x7FFFFFFFFFFFFFFFLL;
if (x != 1)
__builtin_abort ();
return 0;
}