aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2020-06-27 12:38:23 +0200
committerGiuliano Belinassi <giuliano.belinassi@usp.br>2020-08-17 13:15:08 -0300
commit21eba61de879b1e01804a3567bbb1e64750bdcee (patch)
tree1986ba0e20908ee9714922b2d88ace3be9434552
parentbadd0f254d890ce04a8aa3b8d055e48c71ef2216 (diff)
downloadgcc-21eba61de879b1e01804a3567bbb1e64750bdcee.zip
gcc-21eba61de879b1e01804a3567bbb1e64750bdcee.tar.gz
gcc-21eba61de879b1e01804a3567bbb1e64750bdcee.tar.bz2
c-family: Use TYPE_OVERFLOW_UNDEFINED instead of !TYPE_UNSIGNED in pointer_sum [PR95903]
For lp64 targets and int off ... ptr[off + 1] is lowered in pointer_sum to *(ptr + ((sizetype) off + (sizetype) 1)). That is fine when signed integer wrapping is undefined (and is not done already if off has unsigned type), but changes behavior for -fwrapv, where overflow is well defined. Runtime test could be: int main () { char *p = __builtin_malloc (0x100000000UL); if (!p) return 0; char *q = p + 0x80000000UL; int o = __INT_MAX__; q[o + 1] = 1; if (q[-__INT_MAX__ - 1] != 1) __builtin_abort (); return 0; } with -fwrapv or so, not included in the testsuite because it requires 4GB allocation (with some other test it would be enough to have something slightly above 2GB, but still...). 2020-06-27 Jakub Jelinek <jakub@redhat.com> PR middle-end/95903 gcc/c-family/ * c-common.c (pointer_int_sum): Use TYPE_OVERFLOW_UNDEFINED instead of !TYPE_UNSIGNED check to see if we can apply distributive law and handle smaller precision intop operands separately. gcc/testsuite/ * c-c++-common/pr95903.c: New test.
-rw-r--r--gcc/c-family/c-common.c2
-rw-r--r--gcc/testsuite/c-c++-common/pr95903.c19
2 files changed, 20 insertions, 1 deletions
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index b73ad2e..a9fa0d1 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -3141,7 +3141,7 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
/* If the constant is unsigned, and smaller than the pointer size,
then we must skip this optimization. This is because it could cause
an overflow error if the constant is negative but INTOP is not. */
- && (!TYPE_UNSIGNED (TREE_TYPE (intop))
+ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (intop))
|| (TYPE_PRECISION (TREE_TYPE (intop))
== TYPE_PRECISION (TREE_TYPE (ptrop)))))
{
diff --git a/gcc/testsuite/c-c++-common/pr95903.c b/gcc/testsuite/c-c++-common/pr95903.c
new file mode 100644
index 0000000..6e9f68e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/pr95903.c
@@ -0,0 +1,19 @@
+/* PR middle-end/95903 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -fwrapv -fdump-tree-optimized" } */
+/* Verify that for -fwrapv the + 1 addition is performed in the parameter's
+ type before sign extending it. */
+/* { dg-final { scan-tree-dump-times "off_\[0-9]+\\\(D\\\) \\+ 1" 2 "optimized" } } */
+
+char
+foo (const char *ptr, int off)
+{
+ off += 1;
+ return ptr[off];
+}
+
+char
+bar (const char *ptr, int off)
+{
+ return ptr[off + 1];
+}