2016-11-18 Jakub Jelinek PR middle-end/78416 * expmed.c (expand_divmod): For modes wider than HWI, take into account implicit 1 bits above msb for EXACT_POWER_OF_2_OR_ZERO_P. * gcc.dg/torture/pr78416.c: New test. --- gcc/expmed.c +++ gcc/expmed.c @@ -3844,7 +3844,15 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, 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)))); + /* If mode is wider than HWI and op1 has msb set, + then it has there extra implicit 1 bits above it. */ + && (GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT + || INTVAL (op1) >= 0)) + || (! unsignedp + && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1) + && (GET_MODE_PRECISION (mode) + <= HOST_BITS_PER_WIDE_INT + || INTVAL (op1) < 0))); } /* @@ -3987,8 +3995,17 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, 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 mode is wider than HWI and op1 has msb set, + then it has there extra implicit 1 bits above + it. */ + && (GET_MODE_PRECISION (compute_mode) + <= HOST_BITS_PER_WIDE_INT + || INTVAL (op1) >= 0)) + || (! unsignedp + && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1)) + && (GET_MODE_PRECISION (compute_mode) + <= HOST_BITS_PER_WIDE_INT + || INTVAL (op1) < 0)))); } /* If one of the operands is a volatile MEM, copy it into a register. */ @@ -4031,7 +4048,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode, unsigned HOST_WIDE_INT d = (INTVAL (op1) & GET_MODE_MASK (compute_mode)); - if (EXACT_POWER_OF_2_OR_ZERO_P (d)) + if (EXACT_POWER_OF_2_OR_ZERO_P (d) + && (INTVAL (op1) >= 0 || size <= HOST_BITS_PER_WIDE_INT)) { pre_shift = floor_log2 (d); if (rem_flag) @@ -4179,6 +4197,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum 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)) @@ -4192,7 +4211,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum 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) { @@ -4504,7 +4525,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum 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); --- gcc/testsuite/gcc.dg/torture/pr78416.c +++ 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; +}