You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
108 lines
3.6 KiB
108 lines
3.6 KiB
2016-11-18 Jakub Jelinek <jakub@redhat.com> |
|
|
|
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; |
|
+}
|
|
|