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.
This commit is contained in:
Jakub Jelinek 2020-06-27 12:38:23 +02:00
parent daaed0199e
commit 3799596098
2 changed files with 20 additions and 1 deletions

View File

@ -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)))))
{

View File

@ -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];
}