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