aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-01-30 19:04:13 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2016-01-30 19:04:13 +0100
commitdb7a2818002ba7e0c1863d15aca3212911161267 (patch)
tree3a978b34d4a749f949ab5c378dd10d65e6b9c5b1
parente520d5f02a0cfa5d07a48a14f2b67af63884e9ed (diff)
downloadgcc-db7a2818002ba7e0c1863d15aca3212911161267.zip
gcc-db7a2818002ba7e0c1863d15aca3212911161267.tar.gz
gcc-db7a2818002ba7e0c1863d15aca3212911161267.tar.bz2
re PR middle-end/69546 (wrong code with -O and simple int128 arithmetics)
PR tree-optimization/69546 * wide-int.cc (wi::divmod_internal): For unsigned division where both operands fit into uhwi, if o1 is 1 and o0 has msb set, if divident_prec is larger than bits per hwi, clear another quotient word and return 2 instead of 1. Similarly for remainder with msb in HWI set, if dividend_prec is larger than bits per hwi. * gcc.dg/torture/pr69546.c: New test. From-SVN: r233012
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr69546-1.c26
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr69546-2.c18
-rw-r--r--gcc/wide-int.cc23
5 files changed, 79 insertions, 3 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 1d60690..0d405cd 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,13 @@
+2016-01-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/69546
+ * wide-int.cc (wi::divmod_internal): For unsigned division
+ where both operands fit into uhwi, if o1 is 1 and o0 has
+ msb set, if divident_prec is larger than bits per hwi,
+ clear another quotient word and return 2 instead of 1.
+ Similarly for remainder with msb in HWI set, if dividend_prec
+ is larger than bits per hwi.
+
2016-01-29 Martin Jambor <mjambor@suse.cz>
* hsa-gen.c (get_memory_order_name): Mask with MEMMODEL_BASE_MASK.
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index df468e1..63a4bfa 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2016-01-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/69546
+ * gcc.dg/torture/pr69546.c: New test.
+
2016-01-30 Paul Thomas <pault@gcc.gnu.org>
PR fortran/69566
diff --git a/gcc/testsuite/gcc.dg/torture/pr69546-1.c b/gcc/testsuite/gcc.dg/torture/pr69546-1.c
new file mode 100644
index 0000000..39db179
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr69546-1.c
@@ -0,0 +1,26 @@
+/* PR tree-optimization/69546 */
+/* { dg-do run { target int128 } } */
+
+unsigned __int128 __attribute__ ((noinline, noclone))
+foo (unsigned long long x)
+{
+ unsigned __int128 y = ~0ULL;
+ x >>= 63;
+ return y / (x | 1);
+}
+
+unsigned __int128 __attribute__ ((noinline, noclone))
+bar (unsigned long long x)
+{
+ unsigned __int128 y = ~33ULL;
+ x >>= 63;
+ return y / (x | 1);
+}
+
+int
+main ()
+{
+ if (foo (1) != ~0ULL || bar (17) != ~33ULL)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr69546-2.c b/gcc/testsuite/gcc.dg/torture/pr69546-2.c
new file mode 100644
index 0000000..f004310
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr69546-2.c
@@ -0,0 +1,18 @@
+/* PR tree-optimization/69546 */
+/* { dg-do run { target int128 } } */
+
+unsigned __int128
+foo (void)
+{
+ unsigned __int128 a = 0xfffffffffffffffeULL;
+ unsigned __int128 b = 0xffffffffffffffffULL;
+ return a % b;
+}
+
+int
+main ()
+{
+ if (foo () != 0xfffffffffffffffeULL)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index 195ac26..5fcec2e 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -1788,15 +1788,32 @@ wi::divmod_internal (HOST_WIDE_INT *quotient, unsigned int *remainder_len,
{
unsigned HOST_WIDE_INT o0 = dividend.to_uhwi ();
unsigned HOST_WIDE_INT o1 = divisor.to_uhwi ();
+ unsigned int quotient_len = 1;
if (quotient)
- quotient[0] = o0 / o1;
+ {
+ quotient[0] = o0 / o1;
+ if (o1 == 1
+ && (HOST_WIDE_INT) o0 < 0
+ && dividend_prec > HOST_BITS_PER_WIDE_INT)
+ {
+ quotient[1] = 0;
+ quotient_len = 2;
+ }
+ }
if (remainder)
{
remainder[0] = o0 % o1;
- *remainder_len = 1;
+ if ((HOST_WIDE_INT) remainder[0] < 0
+ && dividend_prec > HOST_BITS_PER_WIDE_INT)
+ {
+ remainder[1] = 0;
+ *remainder_len = 2;
+ }
+ else
+ *remainder_len = 1;
}
- return 1;
+ return quotient_len;
}
/* Make the divisor and dividend positive and remember what we