|
|
85359c |
2016-11-18 Jakub Jelinek <jakub@redhat.com>
|
|
|
85359c |
|
|
|
85359c |
PR middle-end/78416
|
|
|
85359c |
* expmed.c (expand_divmod): For modes wider than HWI, take into
|
|
|
85359c |
account implicit 1 bits above msb for EXACT_POWER_OF_2_OR_ZERO_P.
|
|
|
85359c |
|
|
|
85359c |
* gcc.dg/torture/pr78416.c: New test.
|
|
|
85359c |
|
|
|
85359c |
--- gcc/expmed.c
|
|
|
85359c |
+++ gcc/expmed.c
|
|
|
85359c |
@@ -3844,7 +3844,15 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
if (unsignedp)
|
|
|
85359c |
ext_op1 &= GET_MODE_MASK (mode);
|
|
|
85359c |
op1_is_pow2 = ((EXACT_POWER_OF_2_OR_ZERO_P (ext_op1)
|
|
|
85359c |
- || (! unsignedp && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1))));
|
|
|
85359c |
+ /* If mode is wider than HWI and op1 has msb set,
|
|
|
85359c |
+ then it has there extra implicit 1 bits above it. */
|
|
|
85359c |
+ && (GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || INTVAL (op1) >= 0))
|
|
|
85359c |
+ || (! unsignedp
|
|
|
85359c |
+ && EXACT_POWER_OF_2_OR_ZERO_P (-ext_op1)
|
|
|
85359c |
+ && (GET_MODE_PRECISION (mode)
|
|
|
85359c |
+ <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || INTVAL (op1) < 0)));
|
|
|
85359c |
}
|
|
|
85359c |
|
|
|
85359c |
/*
|
|
|
85359c |
@@ -3987,8 +3995,17 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
op1_is_constant = CONST_INT_P (op1);
|
|
|
85359c |
op1_is_pow2 = (op1_is_constant
|
|
|
85359c |
&& ((EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
|
|
|
85359c |
- || (! unsignedp
|
|
|
85359c |
- && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1))))));
|
|
|
85359c |
+ /* If mode is wider than HWI and op1 has msb set,
|
|
|
85359c |
+ then it has there extra implicit 1 bits above
|
|
|
85359c |
+ it. */
|
|
|
85359c |
+ && (GET_MODE_PRECISION (compute_mode)
|
|
|
85359c |
+ <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || INTVAL (op1) >= 0))
|
|
|
85359c |
+ || (! unsignedp
|
|
|
85359c |
+ && EXACT_POWER_OF_2_OR_ZERO_P (-UINTVAL (op1))
|
|
|
85359c |
+ && (GET_MODE_PRECISION (compute_mode)
|
|
|
85359c |
+ <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || INTVAL (op1) < 0))));
|
|
|
85359c |
}
|
|
|
85359c |
|
|
|
85359c |
/* If one of the operands is a volatile MEM, copy it into a register. */
|
|
|
85359c |
@@ -4031,7 +4048,8 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
unsigned HOST_WIDE_INT d = (INTVAL (op1)
|
|
|
85359c |
& GET_MODE_MASK (compute_mode));
|
|
|
85359c |
|
|
|
85359c |
- if (EXACT_POWER_OF_2_OR_ZERO_P (d))
|
|
|
85359c |
+ if (EXACT_POWER_OF_2_OR_ZERO_P (d)
|
|
|
85359c |
+ && (INTVAL (op1) >= 0 || size <= HOST_BITS_PER_WIDE_INT))
|
|
|
85359c |
{
|
|
|
85359c |
pre_shift = floor_log2 (d);
|
|
|
85359c |
if (rem_flag)
|
|
|
85359c |
@@ -4179,6 +4197,7 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
goto fail1;
|
|
|
85359c |
}
|
|
|
85359c |
else if (EXACT_POWER_OF_2_OR_ZERO_P (d)
|
|
|
85359c |
+ && (size <= HOST_BITS_PER_WIDE_INT || d >= 0)
|
|
|
85359c |
&& (rem_flag
|
|
|
85359c |
? smod_pow2_cheap (speed, compute_mode)
|
|
|
85359c |
: sdiv_pow2_cheap (speed, compute_mode))
|
|
|
85359c |
@@ -4192,7 +4211,9 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
compute_mode)
|
|
|
85359c |
!= CODE_FOR_nothing)))
|
|
|
85359c |
;
|
|
|
85359c |
- else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d))
|
|
|
85359c |
+ else if (EXACT_POWER_OF_2_OR_ZERO_P (abs_d)
|
|
|
85359c |
+ && (size <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || abs_d != (unsigned HOST_WIDE_INT) d))
|
|
|
85359c |
{
|
|
|
85359c |
if (rem_flag)
|
|
|
85359c |
{
|
|
|
85359c |
@@ -4504,7 +4525,10 @@ expand_divmod (int rem_flag, enum tree_code code, enum machine_mode mode,
|
|
|
85359c |
case CEIL_MOD_EXPR:
|
|
|
85359c |
if (unsignedp)
|
|
|
85359c |
{
|
|
|
85359c |
- if (op1_is_constant && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1)))
|
|
|
85359c |
+ if (op1_is_constant
|
|
|
85359c |
+ && EXACT_POWER_OF_2_OR_ZERO_P (INTVAL (op1))
|
|
|
85359c |
+ && (size <= HOST_BITS_PER_WIDE_INT
|
|
|
85359c |
+ || INTVAL (op1) >= 0))
|
|
|
85359c |
{
|
|
|
85359c |
rtx t1, t2, t3;
|
|
|
85359c |
unsigned HOST_WIDE_INT d = INTVAL (op1);
|
|
|
85359c |
--- gcc/testsuite/gcc.dg/torture/pr78416.c
|
|
|
85359c |
+++ gcc/testsuite/gcc.dg/torture/pr78416.c
|
|
|
85359c |
@@ -0,0 +1,17 @@
|
|
|
85359c |
+/* PR middle-end/78416 */
|
|
|
85359c |
+/* { dg-do run { target int128 } } */
|
|
|
85359c |
+
|
|
|
85359c |
+int
|
|
|
85359c |
+main ()
|
|
|
85359c |
+{
|
|
|
85359c |
+ unsigned __int128 x;
|
|
|
85359c |
+ x = 0xFFFFFFFFFFFFFFFFULL;
|
|
|
85359c |
+ x /= ~0x7FFFFFFFFFFFFFFFLL;
|
|
|
85359c |
+ if (x != 0)
|
|
|
85359c |
+ __builtin_abort ();
|
|
|
85359c |
+ x = ~0x7FFFFFFFFFFFFFFELL;
|
|
|
85359c |
+ x /= ~0x7FFFFFFFFFFFFFFFLL;
|
|
|
85359c |
+ if (x != 1)
|
|
|
85359c |
+ __builtin_abort ();
|
|
|
85359c |
+ return 0;
|
|
|
85359c |
+}
|