From: Jakub Jelinek Date: Tue, 22 Nov 2016 10:14:21 +0000 (+0100) Subject: re PR middle-end/78416 (wrong code for division by (u128)~INT64_MAX at -O0) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=76a7314dc936394490f2207c45ed76ab248b3da0;p=gcc.git 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 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c97934882eb..0402b3949f3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,11 @@ 2016-11-22 Jakub Jelinek + 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 * 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 diff --git a/gcc/expmed.c b/gcc/expmed.c index a21a632ab18..fa710565f30 100644 --- a/gcc/expmed.c +++ b/gcc/expmed.c @@ -3994,11 +3994,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode, op1_is_constant = CONST_INT_P (op1); if (op1_is_constant) { - unsigned HOST_WIDE_INT ext_op1 = UINTVAL (op1); - if (unsignedp) - ext_op1 &= GET_MODE_MASK (mode); - op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1) - || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1)))); + wide_int ext_op1 = rtx_mode_t (op1, mode); + op1_is_pow2 = (wi::popcount (ext_op1) == 1 + || (! unsignedp + && wi::popcount (wi::neg (ext_op1)) == 1)); } /* @@ -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 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 ? udiv_optab : sdiv_optab)); - optab2 = ((op1_is_pow2 && op1 != const0_rtx) - ? optab1 + optab2 = (op1_is_pow2 ? optab1 : (unsignedp ? udivmod_optab : sdivmod_optab)); 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 must recompute the following. */ op1_is_constant = CONST_INT_P (op1); - op1_is_pow2 = (op1_is_constant - && ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)) - || (! unsignedp - && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1)))))); + if (op1_is_constant) + { + wide_int ext_op1 = rtx_mode_t (op1, compute_mode); + 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. */ @@ -4182,10 +4185,10 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode, unsigned HOST_WIDE_INT mh, ml; int pre_shift, post_shift; int dummy; - unsigned HOST_WIDE_INT d = (INTVAL (op1) - & GET_MODE_MASK (compute_mode)); + wide_int wd = rtx_mode_t (op1, 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); if (rem_flag) @@ -4325,7 +4328,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode, else if (d == -1) quotient = expand_unop (compute_mode, neg_optab, op0, 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)) { /* 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; } else if (EXACT_POWER_OF_2_OR_ZERO_P (d) + && (size <= HOST_BITS_PER_WIDE_INT || d >= 0) && (rem_flag ? smod_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) != 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) { @@ -4483,7 +4489,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode, case FLOOR_DIV_EXPR: case FLOOR_MOD_EXPR: /* 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; 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); t2 = expand_binop (compute_mode, ior_optab, op0, t1, NULL_RTX, 0, OPTAB_WIDEN); - nsign = expand_shift - (RSHIFT_EXPR, compute_mode, t2, - size - 1, NULL_RTX, 0); + nsign = expand_shift (RSHIFT_EXPR, compute_mode, t2, + size - 1, NULL_RTX, 0); t3 = force_operand (gen_rtx_MINUS (compute_mode, t1, nsign), NULL_RTX); 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: 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; unsigned HOST_WIDE_INT d = INTVAL (op1); @@ -4876,7 +4884,7 @@ expand_divmod (int rem_flag, enum tree_code code, machine_mode mode, break; 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); unsigned HOST_WIDE_INT ml; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 125b01f2817..c24012dee07 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,8 @@ 2016-11-22 Jakub Jelinek + PR middle-end/78416 + * gcc.dg/torture/pr78416.c: New test. + PR tree-optimization/78445 * gcc.dg/pr78445.c: New test. diff --git a/gcc/testsuite/gcc.dg/torture/pr78416.c b/gcc/testsuite/gcc.dg/torture/pr78416.c new file mode 100644 index 00000000000..5028156f4fa --- /dev/null +++ b/gcc/testsuite/gcc.dg/torture/pr78416.c @@ -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; +}