aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2021-09-06 10:08:16 +0200
committerJakub Jelinek <jakub@redhat.com>2021-09-06 10:08:16 +0200
commit8a4602c2e0f81895415ba7ee23bf81dc795d1103 (patch)
treed45c41b2fe49e3573b83c74eb9741ac12c7df030 /gcc
parent564efbf40077c25623cdd6ce2f911c56b5b08f6c (diff)
downloadgcc-8a4602c2e0f81895415ba7ee23bf81dc795d1103.zip
gcc-8a4602c2e0f81895415ba7ee23bf81dc795d1103.tar.gz
gcc-8a4602c2e0f81895415ba7ee23bf81dc795d1103.tar.bz2
match.pd: Fix up __builtin_*_overflow arg demotion [PR102207]
My earlier patch to demote arguments of __builtin_*_overflow unfortunately caused a wrong-code regression. The builtins operate on infinite precision arguments, outer_prec > inner_prec signed -> signed, unsigned -> unsigned promotions there are just repeating the sign or 0s and can be demoted, similarly unsigned -> signed which also is repeating 0s, but as the testcase shows, signed -> unsigned promotions need to be preserved (unless we'd know the inner arguments can't be negative), because for negative numbers such promotion sets the outer_prec -> inner_prec bits to 1 bit the bits above that to 0 in the infinite precision. So, the following patch avoids the demotions for the signed -> unsigned promotions. 2021-09-06 Jakub Jelinek <jakub@redhat.com> PR tree-optimization/102207 * match.pd: Don't demote operands of IFN_{ADD,SUB,MUL}_OVERFLOW if they were promoted from signed to wider unsigned type. * gcc.dg/pr102207.c: New test.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/match.pd6
-rw-r--r--gcc/testsuite/gcc.dg/pr102207.c24
2 files changed, 28 insertions, 2 deletions
diff --git a/gcc/match.pd b/gcc/match.pd
index cc7809d..008f775 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -5608,13 +5608,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(ovf (convert@2 @0) @1)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
- && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0)))
+ && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
+ && (!TYPE_UNSIGNED (TREE_TYPE (@2)) || TYPE_UNSIGNED (TREE_TYPE (@0))))
(ovf @0 @1)))
(simplify
(ovf @1 (convert@2 @0))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& INTEGRAL_TYPE_P (TREE_TYPE (@2))
- && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0)))
+ && TYPE_PRECISION (TREE_TYPE (@2)) > TYPE_PRECISION (TREE_TYPE (@0))
+ && (!TYPE_UNSIGNED (TREE_TYPE (@2)) || TYPE_UNSIGNED (TREE_TYPE (@0))))
(ovf @1 @0))))
/* Simplification of math builtins. These rules must all be optimizations
diff --git a/gcc/testsuite/gcc.dg/pr102207.c b/gcc/testsuite/gcc.dg/pr102207.c
new file mode 100644
index 0000000..08540d0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr102207.c
@@ -0,0 +1,24 @@
+/* PR tree-optimization/102207 */
+/* { dg-do run { target int128 } } */
+/* { dg-options "-O2" } */
+
+typedef unsigned __int128 u128;
+
+u128
+foo (unsigned short a)
+{
+ u128 g;
+ __builtin_sub_overflow ((unsigned long long) -a, 1, &g);
+ return g;
+}
+
+int
+main ()
+{
+ if (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ != 64
+ || __SIZEOF_SHORT__ * __CHAR_BIT__ != 16)
+ return 0;
+ if (foo (1) != 0xfffffffffffffffeULL)
+ __builtin_abort ();
+ return 0;
+}