On January 15, 2019 12:17:49 AM GMT+01:00, Jakub Jelinek <ja...@redhat.com> 
wrote:
>Hi!
>
>The following patch (except for the else if (!INTEGRAL_TYPE_P ) part is
>(improved) code to fix up the ptr1 != ptr2 comparison handling. 
>Unfortunately it looks like we don't really want to lower pointer
>equality
>comparisons performed in integral type to normal pointer equality
>comparisons for GCC 9, as it is too risky, so the following patch keeps
>doing what we were doing for pointer comparisons, but for the
>comparisons
>of addresses in integral types
>1) fixes a bug, where for zero sized objects we'd happily optimize
>(uintptr_t) &e[0] != (uintptr_t) &f[0] even for int e[0] = {}, f[0] =
>{}
>2) improves the rest, mainly if the offset is different:
>- if one variable is automatic and the other one is global, we can fold
>  - if one or both pointers are in the middle of objects they point to,
>     it is fine too
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK. 

Thanks, 
Richard. 

>2019-01-14  Jakub Jelinek  <ja...@redhat.com>
>
>       PR tree-optimization/88775
>       * match.pd (cmp (convert1?@2 addr@0) (convert2? addr@1)): Optimize
>       equal == 0 equality pointer comparisons some more if compared in
>       integral types and either one points to an automatic var and the
>       other to a global, or we can prove at least one points to the middle
>       or both point to start or both point to end.
>
>       * gcc.dg/tree-ssa/pr88775-1.c: New test.
>       * gcc.dg/tree-ssa/pr88775-2.c: New test.
>
>--- gcc/match.pd.jj    2019-01-12 12:20:56.190999044 +0100
>+++ gcc/match.pd       2019-01-14 14:26:18.805750285 +0100
>@@ -3896,6 +3896,52 @@ (define_operator_list COND_TERNARY
>                   || TREE_CODE (base1) == SSA_NAME
>                   || TREE_CODE (base1) == STRING_CST))
>          equal = (base0 == base1);
>+       if (equal == 0)
>+       {
>+         if (!DECL_P (base0) || !DECL_P (base1))
>+           equal = 2;
>+         else if (cmp != EQ_EXPR && cmp != NE_EXPR)
>+           equal = 2;
>+         /* If this is a pointer comparison, ignore for now even
>+            valid equalities where one pointer is the offset zero
>+            of one object and the other to one past end of another one.  */
>+         else if (!INTEGRAL_TYPE_P (TREE_TYPE (@2)))
>+           ;
>+         /* Assume that automatic variables can't be adjacent to global
>+            variables.  */
>+         else if (is_global_var (base0) != is_global_var (base1))
>+           ;
>+         else
>+           {
>+             tree sz0 = DECL_SIZE_UNIT (base0);
>+             tree sz1 = DECL_SIZE_UNIT (base1);
>+             /* If sizes are unknown, e.g. VLA or not representable,
>+                punt.  */
>+             if (!tree_fits_poly_int64_p (sz0)
>+                 || !tree_fits_poly_int64_p (sz1))
>+               equal = 2;
>+             else
>+               {
>+                 poly_int64 size0 = tree_to_poly_int64 (sz0);
>+                 poly_int64 size1 = tree_to_poly_int64 (sz1);
>+                 /* If one offset is pointing (or could be) to the beginning
>+                    of one object and the other is pointing to one past the
>+                    last byte of the other object, punt.  */
>+                 if (maybe_eq (off0, 0) && maybe_eq (off1, size1))
>+                   equal = 2;
>+                 else if (maybe_eq (off1, 0) && maybe_eq (off0, size0))
>+                   equal = 2;
>+                 /* If both offsets are the same, there are some cases
>+                    we know that are ok.  Either if we know they aren't
>+                    zero, or if we know both sizes are no zero.  */
>+                 if (equal == 2
>+                     && known_eq (off0, off1)
>+                     && (known_ne (off0, 0)
>+                         || (known_ne (size0, 0) && known_ne (size1, 0))))
>+                   equal = 0;
>+               }
>+           }
>+       }
>      }
>      (if (equal == 1
>         && (cmp == EQ_EXPR || cmp == NE_EXPR
>@@ -3918,16 +3964,12 @@ (define_operator_list COND_TERNARY
>       { constant_boolean_node (known_ge (off0, off1), type); })
>(if (cmp == GT_EXPR && (known_gt (off0, off1) || known_le (off0,
>off1)))
>       { constant_boolean_node (known_gt (off0, off1), type); }))
>-      (if (equal == 0
>-         && DECL_P (base0) && DECL_P (base1)
>-         /* If we compare this as integers require equal offset.  */
>-         && (!INTEGRAL_TYPE_P (TREE_TYPE (@2))
>-             || known_eq (off0, off1)))
>-       (switch
>-      (if (cmp == EQ_EXPR)
>-       { constant_boolean_node (false, type); })
>-      (if (cmp == NE_EXPR)
>-       { constant_boolean_node (true, type); })))))))))
>+      (if (equal == 0)
>+      (switch
>+       (if (cmp == EQ_EXPR)
>+        { constant_boolean_node (false, type); })
>+       (if (cmp == NE_EXPR)
>+        { constant_boolean_node (true, type); })))))))))
> 
> /* Simplify pointer equality compares using PTA.  */
> (for neeq (ne eq)
>--- gcc/testsuite/gcc.dg/tree-ssa/pr88775-1.c.jj       2019-01-14
>13:18:09.332006700 +0100
>+++ gcc/testsuite/gcc.dg/tree-ssa/pr88775-1.c  2019-01-14
>14:23:24.007622756 +0100
>@@ -0,0 +1,73 @@
>+/* PR tree-optimization/88775 */
>+/* { dg-do compile } */
>+/* { dg-options "-O2 -fdump-tree-optimized" } */
>+/* { dg-final { scan-tree-dump-times "return 1;" 10 "optimized" } } */
>+
>+int a[64] = {};
>+int b[64] = {};
>+
>+int
>+f1 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[2] != (__UINTPTR_TYPE__) &b[2];
>+}
>+
>+int
>+f2 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[2] != (__UINTPTR_TYPE__) &b[10];
>+}
>+
>+int
>+f3 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[0] != (__UINTPTR_TYPE__) &b[0];
>+}
>+
>+int
>+f4 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[64] != (__UINTPTR_TYPE__) &b[64];
>+}
>+
>+int
>+f5 (void)
>+{
>+  int c[64] = {};
>+  return (__UINTPTR_TYPE__) &a[0] != (__UINTPTR_TYPE__) &c[64];
>+}
>+
>+int
>+f6 (void)
>+{
>+  int c[64] = {};
>+  return (__UINTPTR_TYPE__) &b[64] != (__UINTPTR_TYPE__) &c[0];
>+}
>+
>+int
>+f7 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[2] != (__UINTPTR_TYPE__) &d[2];
>+}
>+
>+int
>+f8 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[2] != (__UINTPTR_TYPE__) &d[10];
>+}
>+
>+int
>+f9 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[0] != (__UINTPTR_TYPE__) &d[0];
>+}
>+
>+int
>+f10 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[64] != (__UINTPTR_TYPE__) &d[64];
>+}
>--- gcc/testsuite/gcc.dg/tree-ssa/pr88775-2.c.jj       2019-01-14
>13:18:09.332006700 +0100
>+++ gcc/testsuite/gcc.dg/tree-ssa/pr88775-2.c  2019-01-14
>14:24:01.838001078 +0100
>@@ -0,0 +1,43 @@
>+/* PR tree-optimization/88775 */
>+/* { dg-do compile } */
>+/* { dg-options "-O2 -fdump-tree-optimized" } */
>+/* These can't be decided until we know how the variables will
>+   be laid out in memory.  */
>+/* { dg-final { scan-tree-dump-not "return 1;" "optimized" } } */
>+
>+int a[64] = {};
>+int b[64] = {};
>+int e[0] = {};
>+int f[0] = {};
>+
>+int
>+f1 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[0] != (__UINTPTR_TYPE__) &b[64];
>+}
>+
>+int
>+f2 (void)
>+{
>+  return (__UINTPTR_TYPE__) &a[64] != (__UINTPTR_TYPE__) &b[0];
>+}
>+
>+int
>+f3 (void)
>+{
>+  return (__UINTPTR_TYPE__) &e[0] != (__UINTPTR_TYPE__) &f[0];
>+}
>+
>+int
>+f4 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[0] != (__UINTPTR_TYPE__) &d[64];
>+}
>+
>+int
>+f5 (void)
>+{
>+  int c[64] = {}, d[64] = {};
>+  return (__UINTPTR_TYPE__) &c[64] != (__UINTPTR_TYPE__) &d[0];
>+}
>
>       Jakub

Reply via email to