[gcc(refs/users/marxin/heads/marxin-gcc-benchmark-branch)] PR tree-optimization/92765 - wrong code for strcmp of a union member

Martin Liska marxin@gcc.gnu.org
Mon Mar 30 10:48:55 GMT 2020


https://gcc.gnu.org/g:e7868dc6a79daec4f46552fa5c99f88e4eb8de4c

commit e7868dc6a79daec4f46552fa5c99f88e4eb8de4c
Author: Martin Sebor <msebor@redhat.com>
Date:   Wed Feb 5 16:55:26 2020 -0700

    PR tree-optimization/92765 - wrong code for strcmp of a union member
    
    gcc/ChangeLog:
    
            PR tree-optimization/92765
            * gimple-fold.c (get_range_strlen_tree): Handle MEM_REF and PARM_DECL.
            * tree-ssa-strlen.c (compute_string_length): Remove.
            (determine_min_objsize): Remove.
            (get_len_or_size): Add an argument.  Call get_range_strlen_dynamic.
            Avoid using type size as the upper bound on string length.
            (handle_builtin_string_cmp): Add an argument.  Adjust.
            (strlen_check_and_optimize_call): Pass additional argument to
            handle_builtin_string_cmp.
    
    gcc/testsuite/ChangeLog:
    
            PR tree-optimization/92765
            * g++.dg/tree-ssa/strlenopt-1.C: New test.
            * g++.dg/tree-ssa/strlenopt-2.C: New test.
            * gcc.dg/Warray-bounds-58.c: New test.
            * gcc.dg/Wrestrict-20.c: Avoid a valid -Wformat-overflow.
            * gcc.dg/Wstring-compare.c: Xfail a test.
            * gcc.dg/strcmpopt_2.c: Disable tests.
            * gcc.dg/strcmpopt_4.c: Adjust tests.
            * gcc.dg/strcmpopt_10.c: New test.
            * gcc.dg/strcmpopt_11.c: New test.
            * gcc.dg/strlenopt-69.c: Disable tests.
            * gcc.dg/strlenopt-92.c: New test.
            * gcc.dg/strlenopt-93.c: New test.
            * gcc.dg/strlenopt.h: Declare calloc.
            * gcc.dg/tree-ssa/pr92056.c: Xfail tests until pr93518 is resolved.
            * gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Correct test (pr93517).

Diff:
---
 gcc/ChangeLog                                      |  12 +
 gcc/gimple-fold.c                                  |  45 +++-
 gcc/testsuite/ChangeLog                            |  19 ++
 gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C        |  42 ++++
 gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C        |  56 +++++
 gcc/testsuite/gcc.dg/Warray-bounds-58.c            |  81 +++++++
 gcc/testsuite/gcc.dg/Wrestrict-20.c                |   4 +-
 gcc/testsuite/gcc.dg/Wstring-compare.c             |   3 +-
 gcc/testsuite/gcc.dg/strcmpopt_10.c                | 130 +++++++++++
 gcc/testsuite/gcc.dg/strcmpopt_11.c                |  16 ++
 gcc/testsuite/gcc.dg/strcmpopt_2.c                 |  67 +++---
 gcc/testsuite/gcc.dg/strcmpopt_4.c                 |  25 ++-
 gcc/testsuite/gcc.dg/strlenopt-69.c                |   3 +
 gcc/testsuite/gcc.dg/strlenopt-92.c                |  58 +++++
 gcc/testsuite/gcc.dg/strlenopt-93.c                |  71 ++++++
 gcc/testsuite/gcc.dg/strlenopt.h                   |   1 +
 .../gcc.dg/tree-ssa/builtin-sprintf-warn-23.c      |  16 +-
 gcc/testsuite/gcc.dg/tree-ssa/pr92056.c            |  11 +-
 gcc/tree-ssa-strlen.c                              | 242 ++++++++-------------
 19 files changed, 701 insertions(+), 201 deletions(-)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8fb1da0313c..b8fa14e00b6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,15 @@
+2020-02-05  Martin Sebor  <msebor@redhat.com>
+
+	PR tree-optimization/92765
+	* gimple-fold.c (get_range_strlen_tree): Handle MEM_REF and PARM_DECL.
+	* tree-ssa-strlen.c (compute_string_length): Remove.
+	(determine_min_objsize): Remove.
+	(get_len_or_size): Add an argument.  Call get_range_strlen_dynamic.
+	Avoid using type size as the upper bound on string length.
+	(handle_builtin_string_cmp): Add an argument.  Adjust.
+	(strlen_check_and_optimize_call): Pass additional argument to
+	handle_builtin_string_cmp.
+
 2020-02-05  Uroš Bizjak  <ubizjak@gmail.com>
 
 	* config/i386/i386.md (*pushdi2_rex64 peephole2): Remove.
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index ed225922269..fa7a396a361 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "calls.h"
 #include "tree-vector-builder.h"
 #include "tree-ssa-strlen.h"
+#include "varasm.h"
 
 enum strlen_range_kind {
   /* Compute the exact constant string length.  */
@@ -1280,7 +1281,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
 		       c_strlen_data *pdata, unsigned eltsize)
 {
   gcc_assert (TREE_CODE (arg) != SSA_NAME);
- 
+
   /* The length computed by this invocation of the function.  */
   tree val = NULL_TREE;
 
@@ -1422,7 +1423,44 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
 	     type about the length here.  */
 	  tight_bound = true;
 	}
-      else if (VAR_P (arg))
+      else if (TREE_CODE (arg) == MEM_REF
+	       && TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE
+	       && TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == INTEGER_TYPE
+	       && TREE_CODE (TREE_OPERAND (arg, 0)) == ADDR_EXPR)
+	{
+	  /* Handle a MEM_REF into a DECL accessing an array of integers,
+	     being conservative about references to extern structures with
+	     flexible array members that can be initialized to arbitrary
+	     numbers of elements as an extension (static structs are okay).
+	     FIXME: Make this less conservative -- see
+	     component_ref_size in tree.c.  */
+	  tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
+	  if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
+	      && (decl_binds_to_current_def_p (ref)
+		  || !array_at_struct_end_p (arg)))
+	    {
+	      /* Fail if the offset is out of bounds.  Such accesses
+		 should be diagnosed at some point.  */
+	      val = DECL_SIZE_UNIT (ref);
+	      if (!val || integer_zerop (val))
+		return false;
+
+	      poly_offset_int psiz = wi::to_offset (val);
+	      poly_offset_int poff = mem_ref_offset (arg);
+	      if (known_le (psiz, poff))
+		return false;
+
+	      pdata->minlen = ssize_int (0);
+
+	      /* Subtract the offset and one for the terminating nul.  */
+	      psiz -= poff;
+	      psiz -= 1;
+	      val = wide_int_to_tree (TREE_TYPE (val), psiz);
+	      /* Since VAL reflects the size of a declared object
+		 rather the type of the access it is not a tight bound.  */
+	    }
+	}
+      else if (TREE_CODE (arg) == PARM_DECL || VAR_P (arg))
 	{
 	  /* Avoid handling pointers to arrays.  GCC might misuse
 	     a pointer to an array of one bound to point to an array
@@ -1500,7 +1538,8 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
 	     the referenced subobject minus 1 (for the terminating nul).  */
 	  tree type = TREE_TYPE (base);
 	  if (TREE_CODE (type) == POINTER_TYPE
-	      || !VAR_P (base) || !(val = DECL_SIZE_UNIT (base)))
+	      || (TREE_CODE (base) != PARM_DECL && !VAR_P (base))
+	      || !(val = DECL_SIZE_UNIT (base)))
 	    val = build_all_ones_cst (size_type_node);
 	  else
 	    {
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index ca1d083971c..5802f0d7c60 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,22 @@
+2020-02-05  Martin Sebor  <msebor@redhat.com>
+
+	PR tree-optimization/92765
+	* g++.dg/tree-ssa/strlenopt-1.C: New test.
+	* g++.dg/tree-ssa/strlenopt-2.C: New test.
+	* gcc.dg/Warray-bounds-58.c: New test.
+	* gcc.dg/Wrestrict-20.c: Avoid a valid -Wformat-overflow.
+	* gcc.dg/Wstring-compare.c: Xfail a test.
+	* gcc.dg/strcmpopt_2.c: Disable tests.
+	* gcc.dg/strcmpopt_4.c: Adjust tests.
+	* gcc.dg/strcmpopt_10.c: New test.
+	* gcc.dg/strcmpopt_11.c: New test.
+	* gcc.dg/strlenopt-69.c: Disable tests.
+	* gcc.dg/strlenopt-92.c: New test.
+	* gcc.dg/strlenopt-93.c: New test.
+	* gcc.dg/strlenopt.h: Declare calloc.
+	* gcc.dg/tree-ssa/pr92056.c: Xfail tests until pr93518 is resolved.
+	* gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Correct test (pr93517).
+
 2020-02-05  Marek Polacek  <polacek@redhat.com>
 
 	PR c++/93559 - ICE with CONSTRUCTOR flags verification.
diff --git a/gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C b/gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C
new file mode 100644
index 00000000000..b6adfac7136
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C
@@ -0,0 +1,42 @@
+/* PR tree-optimization/92765 - wrong code for strcmp of a union member
+   { dg-do run }
+   { dg-options "-O2 -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void* operator new (size_t, void *p)
+{
+  return p;
+}
+
+struct A { char a2[2]; };
+struct B { char a4[4]; };
+
+__attribute__((noipa)) void
+sink (void*) { }
+
+__attribute__((noipa)) void
+copy (char *d, const char *s)
+{
+  while ((*d++ = *s++));
+}
+
+__attribute__((noipa)) void
+store_and_compare (void *p)
+{
+  A *a = new (p) A;
+  sink (a->a2);
+
+  B *b = new (p) B;
+  char *q = (char *) b->a4;
+  copy (q, "abc");
+
+  if (__builtin_strcmp (q, "abc"))
+    __builtin_abort ();
+}
+
+int main ()
+{
+  char a [sizeof (A) > sizeof (B) ? sizeof (A) : sizeof (B)];
+  store_and_compare (a);
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C b/gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C
new file mode 100644
index 00000000000..60f8205c2ab
--- /dev/null
+++ b/gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C
@@ -0,0 +1,56 @@
+/* PR tree-optimization/92765 - wrong code for strcmp of a union member
+   { dg-do run }
+   { dg-options "-O2 -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+inline void* operator new (size_t, void *p)
+{
+  return p;
+}
+
+struct A
+{
+  char a[2]; char b[2]; char c[2];
+  A () { a[0] = 0; b[0] = 0; c[0] = 0; };
+  ~A () { }
+};
+
+struct B
+{
+  char d[6];
+  B () { d[0] = 0; d[2] = 0; }
+  ~B () { }
+};
+
+__attribute__((noipa)) void
+sink (void *) { }
+
+__attribute__((noipa)) void
+copy (char *d, const char *s)
+{
+  while ((*d++ = *s++));
+}
+
+__attribute__((noipa)) void
+store_and_compare (void *p)
+{
+  A *a = new (p) A ();
+  sink (&a->b);
+  a->~A ();
+
+  B *b = new (p) B ();
+  char *q = &b->d[2];
+  copy (q, "abc");
+
+  if (__builtin_strcmp (q, "abc"))
+    __builtin_abort ();
+  b->~B ();
+}
+
+int main ()
+{
+  char a [sizeof (A) > sizeof (B) ? sizeof (A) : sizeof (B)];
+  store_and_compare (a);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-58.c b/gcc/testsuite/gcc.dg/Warray-bounds-58.c
new file mode 100644
index 00000000000..7bd6df2bf2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-58.c
@@ -0,0 +1,81 @@
+/* { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern size_t strlen (const char*);
+
+void sink (size_t);
+
+struct A0 { char i, a[0]; };
+
+extern struct A0 ea0;
+
+void fa0_extern (void)
+{
+  sink (strlen (ea0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ea0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ea0.a));        // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ea0.a + 1));    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+static struct A0 sa0 = { 0 };
+
+void fa0_static (void)
+{
+  sink (strlen (sa0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (sa0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (sa0.a));        // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (sa0.a + 1));    // { dg-warning "\\\[-Warray-bounds" }
+}
+
+
+struct Ax { char i, a[]; };
+
+extern struct Ax ax;
+
+void fax_extern (void)
+{
+  sink (strlen (ax.a - 2));     // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax.a - 1));     // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax.a));
+  sink (strlen (ax.a + 123));
+}
+
+static struct Ax ax0 = { 0, { 0 } };
+static struct Ax ax1 = { 1, { 1, 0 } };
+static struct Ax ax2 = { 2, { 2, 1, 0 } };
+static struct Ax ax3 = { 3, { 3, 2, 1, 0 } };
+
+void fax_static (void)
+{
+  sink (strlen (ax0.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax0.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax0.a));
+  sink (strlen (ax0.a + 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax0.a + 2));    // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (strlen (ax1.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax1.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax1.a));
+  sink (strlen (ax1.a + 1));
+  sink (strlen (ax1.a + 2));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax1.a + 3));    // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (strlen (ax2.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax2.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax2.a));
+  sink (strlen (ax2.a + 1));
+  sink (strlen (ax2.a + 2));
+  sink (strlen (ax2.a + 3));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax2.a + 4));    // { dg-warning "\\\[-Warray-bounds" }
+
+  sink (strlen (ax3.a - 2));    // { dg-warning "\\\[-Warray-bounds" }
+  sink (strlen (ax3.a - 1));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax3.a));
+  sink (strlen (ax3.a + 1));
+  sink (strlen (ax3.a + 2));
+  sink (strlen (ax3.a + 3));
+  sink (strlen (ax3.a + 4));    // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
+  sink (strlen (ax3.a + 5));    // { dg-warning "\\\[-Warray-bounds" }
+}
diff --git a/gcc/testsuite/gcc.dg/Wrestrict-20.c b/gcc/testsuite/gcc.dg/Wrestrict-20.c
index 9826e7f4503..a2d29887c37 100644
--- a/gcc/testsuite/gcc.dg/Wrestrict-20.c
+++ b/gcc/testsuite/gcc.dg/Wrestrict-20.c
@@ -15,7 +15,7 @@ void test_warn (char *p)
   sprintf (a, "a=%s", a);     /* { dg-warning "-Wrestrict" } */
 
   p = a;
-  char *q = p + 1;
+  char *q = p + 3;
   sprintf (p, "a=%s", q);     /* { dg-warning "-Wrestrict" } */
 }
 
@@ -31,7 +31,7 @@ void test_nowarn_front_end (char *d)
 void test_nowarn_sprintf_pass (char *d)
 {
   char *q = d;
-  
+
   sprintf (d, "p=%p", q);
   snprintf (d, 32, "p=%p", q);
 
diff --git a/gcc/testsuite/gcc.dg/Wstring-compare.c b/gcc/testsuite/gcc.dg/Wstring-compare.c
index 0ca492db0ab..d1534bf7555 100644
--- a/gcc/testsuite/gcc.dg/Wstring-compare.c
+++ b/gcc/testsuite/gcc.dg/Wstring-compare.c
@@ -120,7 +120,8 @@ void strcmp_array_copy (void)
 
 void strcmp_member_array_lit (const struct S *p)
 {
-  T (p->a4, "1234");        // { dg-warning "length 4 and an array of size 4 " }
+  // Not handled due to the fix for PR 92756.
+  T (p->a4, "1234");        // { dg-warning "length 4 and an array of size 4 " "pr92765" { xfail *-*-* } }
 }
 
 
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_10.c b/gcc/testsuite/gcc.dg/strcmpopt_10.c
new file mode 100644
index 00000000000..94fda596901
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strcmpopt_10.c
@@ -0,0 +1,130 @@
+/* Verify that strncmp equalities aren't eliminated when the trailing array
+   type referenced by a member pointer is smaller than the string in cases
+   when the pointer pointed to by the enclosing object references an object
+   sufficiently large to store a string of equal length.
+  { dg-do compile }
+  { dg-options "-O2 -Wall -Wextra -fdump-tree-optimized" } */
+
+void init (void*);
+
+struct A1 { char i, a[1]; };
+
+void f1_arr (void)
+{
+  char a[9];
+  init (a);
+
+  struct A1 *p = (struct A1*)a;
+
+  if (__builtin_strncmp (p->a, "01234567", 8) == 0)
+    {
+      extern void array_test (void);
+      array_test ();
+    }
+}
+
+void f1_ptr (void)
+{
+  void *p;
+  init (&p);
+
+  struct A1 *q = (struct A1*)p;
+
+  if (__builtin_strncmp (q->a, "0123456789", 10) == 0)
+    {
+      extern void pointer_test (void);
+      pointer_test ();
+    }
+}
+
+void f1_struct (void)
+{
+  struct { char a[9]; } b;
+  init (&b);
+
+  struct A1 *p = (struct A1*)&b;
+
+  if (__builtin_strncmp (p->a, "01234567", 8) == 0)
+    {
+      extern void struct_test (void);
+      struct_test ();
+    }
+}
+
+void f1_memptr (void)
+{
+  struct { void *p; } b;
+  init (&b);
+
+  struct A1 *p = (struct A1*)b.p;
+
+  if (__builtin_strncmp (p->a, "0123456789", 10) == 0)
+    {
+      extern void memptr_test (void);
+      memptr_test ();
+    }
+}
+
+
+struct A2 { char i, a[2]; };
+
+void f2_arr (void)
+{
+  char a[8];
+  init (a);
+
+  struct A2 *p = (struct A2*)a;
+
+  if (__builtin_strncmp (p->a, "0123456", 7) == 0)
+    {
+      extern void array_test (void);
+      array_test ();
+    }
+}
+
+void f2_ptr (void)
+{
+  void *p;
+  init (&p);
+
+  struct A2 *q = (struct A2*)p;
+
+  if (__builtin_strncmp (q->a, "0123456789", 10) == 0)
+    {
+      extern void pointer_test (void);
+      pointer_test ();
+    }
+}
+
+void f2_struct (void)
+{
+  struct { char a[8]; } b;
+  init (&b);
+
+  struct A2 *p = (struct A2*)&b;
+
+  if (__builtin_strncmp (p->a, "0123456", 7) == 0)
+    {
+      extern void struct_test (void);
+      struct_test ();
+    }
+}
+
+void f2_memptr (void)
+{
+  struct { void *p; } b;
+  init (&b);
+
+  struct A2 *p = (struct A2*)b.p;
+
+  if (__builtin_strncmp (p->a, "0123456789", 10) == 0)
+    {
+      extern void memptr_test (void);
+      memptr_test ();
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "array_test" 2 "optimized" } }
+   { dg-final { scan-tree-dump-times "pointer_test" 2 "optimized" } }
+   { dg-final { scan-tree-dump-times "struct_test" 2 "optimized" } }
+   { dg-final { scan-tree-dump-times "memptr_test" 2 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_11.c b/gcc/testsuite/gcc.dg/strcmpopt_11.c
new file mode 100644
index 00000000000..945e0831996
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strcmpopt_11.c
@@ -0,0 +1,16 @@
+/* Verify that strcmp doesn't make assumptions about the size of a weak
+   symbol.
+   { dg-do compile }
+   { dg-options "-O2 -Wall" } */
+
+/* An ordinary definition of A with more elements might be provided
+   in another translation unit.  Even though that would be undefined
+   (the type of the actual definition must be the same as the type
+   of the weak declaration) this test verifies that GCC doesn't rely
+   on the size of this A for optimization (as a matter of QoI).  */
+__attribute__ ((weak)) char a[3];
+
+int cmp_a3_x (void)
+{
+  return __builtin_strcmp (a, "1234567") == 0;
+}
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_2.c b/gcc/testsuite/gcc.dg/strcmpopt_2.c
index 57d8f651c28..f31761be173 100644
--- a/gcc/testsuite/gcc.dg/strcmpopt_2.c
+++ b/gcc/testsuite/gcc.dg/strcmpopt_2.c
@@ -4,52 +4,53 @@
 char s[100] = {'a','b','c','d'};
 typedef struct { char s[8]; int x; } S;
 
-__attribute__ ((noinline)) int 
-f1 (S *s) 
-{ 
-  return __builtin_strcmp (s->s, "abc") != 0; 
+__attribute__ ((noinline)) int
+f1 (S *s)
+{
+  /* Member arrays not handled due to the fix for PR 92765.  */
+  return 0; // __builtin_strcmp (s->s, "abc") != 0;
 }
 
-__attribute__ ((noinline)) int 
-f2 (void) 
-{ 
-  return __builtin_strcmp (s, "abc") != 0; 
+__attribute__ ((noinline)) int
+f2 (void)
+{
+  return __builtin_strcmp (s, "abc") != 0;
 }
 
-__attribute__ ((noinline)) int 
-f3 (S *s) 
-{ 
-  return __builtin_strcmp ("abc", s->s) != 0; 
+__attribute__ ((noinline)) int
+f3 (S *s)
+{
+  return 0; // __builtin_strcmp ("abc", s->s) != 0;
 }
 
-__attribute__ ((noinline)) int 
-f4 (void) 
-{ 
-  return __builtin_strcmp ("abc", s) != 0; 
+__attribute__ ((noinline)) int
+f4 (void)
+{
+  return __builtin_strcmp ("abc", s) != 0;
 }
 
-__attribute__ ((noinline)) int 
-f5 (S *s) 
-{ 
-  return __builtin_strncmp (s->s, "abc", 3) != 0; 
+__attribute__ ((noinline)) int
+f5 (S *s)
+{
+  return 0; // __builtin_strncmp (s->s, "abc", 3) != 0;
 }
 
-__attribute__ ((noinline)) int 
-f6 (void) 
-{ 
-  return __builtin_strncmp (s, "abc", 2) != 0; 
+__attribute__ ((noinline)) int
+f6 (void)
+{
+  return __builtin_strncmp (s, "abc", 2) != 0;
 }
 
-__attribute__ ((noinline)) int 
-f7 (S *s) 
-{ 
-  return __builtin_strncmp ("abc", s->s, 3) != 0; 
+__attribute__ ((noinline)) int
+f7 (S *s)
+{
+  return 0; // __builtin_strncmp ("abc", s->s, 3) != 0;
 }
 
-__attribute__ ((noinline)) int 
-f8 (void) 
-{ 
-  return __builtin_strncmp ("abc", s, 2) != 0; 
+__attribute__ ((noinline)) int
+f8 (void)
+{
+  return __builtin_strncmp ("abc", s, 2) != 0;
 }
 
 int main (void)
@@ -64,4 +65,4 @@ int main (void)
   return 0;
 }
 
-/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 4 "strlen1" } } */
diff --git a/gcc/testsuite/gcc.dg/strcmpopt_4.c b/gcc/testsuite/gcc.dg/strcmpopt_4.c
index 4e26522eed1..b07fbb6b7b0 100644
--- a/gcc/testsuite/gcc.dg/strcmpopt_4.c
+++ b/gcc/testsuite/gcc.dg/strcmpopt_4.c
@@ -2,15 +2,26 @@
 /* { dg-options "-O2 -fdump-tree-strlen" } */
 
 typedef struct { char s[8]; int x; } S;
+
 extern int max_i;
 
-int
-f1 (S * s)
-{ 
-  int result, i;
-  for (i = 0; i < max_i; i++)
-    result += __builtin_strcmp (s->s, "abc") != 0 ? 2 : 1;
+int f_param (S s)
+{
+  int result = 0;
+  for (int i = 0; i < max_i; i++)
+    result += __builtin_strcmp (s.s, "abc") != 0 ? 2 : 1;
+  return result;
+}
+
+
+S s;
+
+int f_object (void)
+{
+  int result = 0;
+  for (int i = 0; i < max_i; i++)
+    result += __builtin_strcmp (s.s, "abc") != 0 ? 2 : 1;
   return result;
 }
 
-/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen1" } } */
+/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 2 "strlen1" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-69.c b/gcc/testsuite/gcc.dg/strlenopt-69.c
index 9ad8e2e8aac..9df6eeccb97 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-69.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-69.c
@@ -35,6 +35,8 @@ void test_array_lit (void)
 
 void test_memarray_lit (struct S *p)
 {
+#if 0
+  /* Member arrays not handled due to the fix for PR 92765.  */
   A (strcmp (p->a4, "1234"));
   A (strcmp (p->a4, "12345"));
   A (strcmp (p->a4, "123456"));
@@ -42,6 +44,7 @@ void test_memarray_lit (struct S *p)
   A (strcmp ("1234", p->a4));
   A (strcmp ("12345", p->a4));
   A (strcmp ("123456", p->a4));
+#endif
 }
 
 /* Verify that the equality of empty strings is folded.  */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-92.c b/gcc/testsuite/gcc.dg/strlenopt-92.c
new file mode 100644
index 00000000000..a9383e65588
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-92.c
@@ -0,0 +1,58 @@
+/* PR tree-optimization/92765 - wrong code for strcmp of a union member
+   { dg-do run }
+   { dg-options "-O2 -Wall" } */
+
+#include "strlenopt.h"
+
+__attribute__((noipa)) int
+copy (char *x, int y)
+{
+  if (y == 0)
+    strcpy (x, "abcd");
+  return y;
+}
+
+__attribute__((noipa)) char *
+alloc_2_copy_compare (int x)
+{
+  char *p;
+  if (x)
+    p = malloc (4);
+  else
+    p = calloc (16, 1);
+
+  char *q = p + 2;
+  if (copy (q, x))
+    return p;
+
+  if (strcmp (q, "abcd") != 0)
+    abort ();
+
+  return p;
+}
+
+char a5[5], a6[6], a7[7];
+
+__attribute__((noipa)) char *
+decl_3_copy_compare (int x)
+{
+  char *p = x < 0 ? a5 : 0 < x ? a6 : a7;
+  char *q = p + 1;
+  if (copy (q, x))
+    return p;
+
+  if (strcmp (q, "abcd") != 0)
+    abort ();
+
+  return p;
+}
+
+int main ()
+{
+  free (alloc_2_copy_compare (0));
+  free (alloc_2_copy_compare (1));
+
+  decl_3_copy_compare (-1);
+  decl_3_copy_compare (0);
+  decl_3_copy_compare (1);
+}
diff --git a/gcc/testsuite/gcc.dg/strlenopt-93.c b/gcc/testsuite/gcc.dg/strlenopt-93.c
new file mode 100644
index 00000000000..dc5f12d2ce3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/strlenopt-93.c
@@ -0,0 +1,71 @@
+/* Verify that strlen doesn't (inadvertently) use the size of an array
+   of char pointers to put an upper bound on the length of the strings
+   they point to.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -fdump-tree-optimized" } */
+
+void eaa_test (void)
+{
+  extern char eaa[4][4];
+
+  char (*p)[4] = eaa;
+
+  if (!*p)
+    return;
+
+  /* The longest string stored in EAA is 15 characters.  */
+  if (__builtin_strlen (*p) > 14)
+    {
+      extern void eaa_ok (void);
+      eaa_ok ();
+    }
+
+  if (__builtin_strlen (*p) > 15)
+    {
+      extern void eaa_fail (void);
+      eaa_fail ();
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "eaa_ok" 1 "optimized" } }
+   { dg-final { scan-tree-dump-not "eaa_fail" "optimized" } } */
+
+
+void epa_test (void)
+{
+  extern char* epa[4];
+  char **p = epa;
+
+  if (*p && __builtin_strlen (*p) > 123)
+    {
+      extern void epa_ok (void);
+      epa_ok ();
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "epa_ok" 1 "optimized" } } */
+
+
+static char* spa[4];
+
+void spa_test (void)
+{
+  char **p = spa;
+
+  if (*p && __builtin_strlen (*p) > 123)
+    {
+      extern void spa_ok ();
+      spa_ok ();
+    }
+}
+
+/* { dg-final { scan-tree-dump-times "spa_ok" 1 "optimized" } } */
+
+
+void sink (void*, ...);
+
+void init (void)
+{
+  /* Make believe even the static array SA may be non-zero.  */
+  sink (spa);
+}
diff --git a/gcc/testsuite/gcc.dg/strlenopt.h b/gcc/testsuite/gcc.dg/strlenopt.h
index 518d0cf08b2..a3ca951ddc5 100644
--- a/gcc/testsuite/gcc.dg/strlenopt.h
+++ b/gcc/testsuite/gcc.dg/strlenopt.h
@@ -5,6 +5,7 @@
 #define NULL ((void *) 0)
 typedef __SIZE_TYPE__ size_t;
 extern void abort (void);
+void *calloc (size_t, size_t);
 void *malloc (size_t);
 void free (void *);
 char *strdup (const char *);
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-23.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-23.c
index 98dfa1d3966..7fb96514f1d 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-23.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-23.c
@@ -642,10 +642,22 @@ void test_multiple_overlap (int i)
   }
 
   {
-    char a[4];                /* { dg-message "declared here" } */
+    char a[4];
+
+    /* There is no overlap here because the length of a3 is at most 1
+       and a4 is necessarily the empty string.  */
+    char *d = a;
+    char *a3 = a + 2;
+    char *a4 = a + 3;
+
+    T (d, "%s%s", a3, a4);
+  }
+
+  {
+    char a[5];                /* { dg-message "declared here" } */
 
     /* a3 and a4 may overlap the output.  They will only not overlap
-       it when a3 is empty, and a4 is at most chaeracter byte long.  */
+       it when a3 is empty, and a4 is at most 1 character long.  */
     char *d = a;
     char *a3 = a + 2;
     char *a4 = a + 3;
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr92056.c b/gcc/testsuite/gcc.dg/tree-ssa/pr92056.c
index e43d0c06e2f..73b1f2ae52f 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr92056.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr92056.c
@@ -1,8 +1,9 @@
-/* PR tree-optimization/92056 */
-/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-optimized" } */
-/* { dg-final { scan-tree-dump-times "return 1;" 2 "optimized" } } */
-/* { dg-final { scan-tree-dump-not "strcmp \\(" "optimized" } } */
+/* PR tree-optimization/92056
+   { dg-do compile }
+   { dg-options "-O2 -fdump-tree-optimized" }
+   Xfailed until pr93518 is resolved.
+   { dg-final { scan-tree-dump-times "return 1;" 2 "optimized" { xfail *-*-* } } }
+   { dg-final { scan-tree-dump-not "strcmp \\(" "optimized" { xfail *-*-* } } } */
 
 void bar (int, char *);
 
diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c
index ad9e98973b1..1cd64302d8b 100644
--- a/gcc/tree-ssa-strlen.c
+++ b/gcc/tree-ssa-strlen.c
@@ -327,7 +327,8 @@ get_next_strinfo (strinfo *si)
 /* Helper function for get_stridx.  Return the strinfo index of the address
    of EXP, which is available in PTR if nonnull.  If OFFSET_OUT, it is
    OK to return the index for some X <= &EXP and store &EXP - X in
-   *OFFSET_OUT.  When nonnull uses RVALS to determine range information.  */
+   *OFFSET_OUT.  When RVALS is nonnull uses it to determine range
+   information.  */
 
 static int
 get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
@@ -4061,105 +4062,20 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
   return true;
 }
 
-/* Given an index to the strinfo vector, compute the string length
-   for the corresponding string. Return -1 when unknown.  */
-
-static HOST_WIDE_INT
-compute_string_length (int idx)
-{
-  HOST_WIDE_INT string_leni = -1;
-  gcc_assert (idx != 0);
-
-  if (idx < 0)
-   return ~idx;
-
-  strinfo *si = get_strinfo (idx);
-  if (si)
-    {
-      tree const_string_len = get_string_length (si);
-      if (const_string_len && tree_fits_shwi_p (const_string_len))
-	string_leni = tree_to_shwi (const_string_len);
-    }
-
-  if (string_leni < 0)
-    return -1;
-
-  return string_leni;
-}
-
-/* Determine the minimum size of the object referenced by DEST expression
-   which must have a pointer type.
-   Return the minimum size of the object if successful or HWI_M1U when
-   the size cannot be determined.  */
-
-static unsigned HOST_WIDE_INT
-determine_min_objsize (tree dest)
-{
-  unsigned HOST_WIDE_INT size = 0;
-
-  init_object_sizes ();
-
-  if (compute_builtin_object_size (dest, 2, &size))
-    return size;
-
-  /* Try to determine the size of the object through the RHS
-     of the assign statement.  */
-  if (TREE_CODE (dest) == SSA_NAME)
-    {
-      gimple *stmt = SSA_NAME_DEF_STMT (dest);
-      if (!is_gimple_assign (stmt))
-	return HOST_WIDE_INT_M1U;
-
-      if (!gimple_assign_single_p (stmt)
-	  && !gimple_assign_unary_nop_p (stmt))
-	return HOST_WIDE_INT_M1U;
-
-      dest = gimple_assign_rhs1 (stmt);
-      return determine_min_objsize (dest);
-    }
-
-  /* Try to determine the size of the object from its type.  */
-  if (TREE_CODE (dest) != ADDR_EXPR)
-    return HOST_WIDE_INT_M1U;
-
-  tree type = TREE_TYPE (dest);
-  if (TREE_CODE (type) == POINTER_TYPE)
-    type = TREE_TYPE (type);
-
-  type = TYPE_MAIN_VARIANT (type);
-
-  /* The size of a flexible array cannot be determined.  Otherwise,
-     for arrays with more than one element, return the size of its
-     type.  GCC itself misuses arrays of both zero and one elements
-     as flexible array members so they are excluded as well.  */
-  if (TREE_CODE (type) != ARRAY_TYPE
-      || !array_at_struct_end_p (dest))
-    {
-      tree type_size = TYPE_SIZE_UNIT (type);
-      if (type_size && TREE_CODE (type_size) == INTEGER_CST
-	  && !integer_onep (type_size)
-	  && !integer_zerop (type_size))
-        return tree_to_uhwi (type_size);
-    }
-
-  return HOST_WIDE_INT_M1U;
-}
-
-/* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths
-   of  the string(s) referenced by ARG if it can be determined.
-   If the length cannot be determined, set *SIZE to the size of
+/* Given strinfo IDX for ARG, sets LENRNG[] to the range of lengths
+   of the string(s) referenced by ARG if it can be determined.
+   If the length cannot be determined, sets *SIZE to the size of
    the array the string is stored in, if any.  If no such array is
-   known, set *SIZE to -1.  When the strings are nul-terminated set
-   *NULTERM to true, otherwise to false.  Return true on success.  */
+   known, sets *SIZE to -1.  When the strings are nul-terminated sets
+   *NULTERM to true, otherwise to false.  When nonnull uses RVALS to
+   determine range information. Returns true on success.  */
 
 static bool
 get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
-		 unsigned HOST_WIDE_INT *size, bool *nulterm)
+		 unsigned HOST_WIDE_INT *size, bool *nulterm,
+		 const vr_values *rvals)
 {
-  /* Set so that both LEN and ~LEN are invalid lengths, i.e.,
-     maximum possible length + 1.  */
-  lenrng[0] = lenrng[1] = HOST_WIDE_INT_MAX;
-
+  /* Invalidate.  */
   *size = HOST_WIDE_INT_M1U;
 
   if (idx < 0)
@@ -4168,13 +4084,18 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
       lenrng[0] = ~idx;
       lenrng[1] = lenrng[0];
       *nulterm = true;
+      return true;
     }
-  else if (idx == 0)
-    ; /* Handled below.  */
-  else if (strinfo *si = get_strinfo (idx))
+
+  /* Set so that both LEN and ~LEN are invalid lengths, i.e., maximum
+     possible length + 1.  */
+  lenrng[0] = lenrng[1] = HOST_WIDE_INT_MAX;
+
+  if (strinfo *si = idx ? get_strinfo (idx) : NULL)
     {
+      /* FIXME: Handle all this in_range_strlen_dynamic.  */
       if (!si->nonzero_chars)
-	arg = si->ptr;
+	;
       else if (tree_fits_uhwi_p (si->nonzero_chars))
 	{
 	  lenrng[0] = tree_to_uhwi (si->nonzero_chars);
@@ -4195,42 +4116,62 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
 	      *nulterm = si->full_string_p;
 	    }
 	}
-      else if (si->ptr)
-	arg = si->ptr;
     }
 
-  if (lenrng[0] == HOST_WIDE_INT_MAX)
+  if (lenrng[0] != HOST_WIDE_INT_MAX)
+    return true;
+
+  /* Compute the minimum and maximum real or possible lengths.  */
+  c_strlen_data lendata = { };
+  /* Set MAXBOUND to an arbitrary non-null non-integer node as a request
+     to have it set to the length of the longest string in a PHI.  */
+  lendata.maxbound = arg;
+  get_range_strlen_dynamic (arg, &lendata, rvals);
+
+  unsigned HOST_WIDE_INT maxbound = HOST_WIDE_INT_M1U;
+  if (tree_fits_uhwi_p (lendata.maxbound)
+      && !integer_all_onesp (lendata.maxbound))
+    maxbound = tree_to_uhwi (lendata.maxbound);
+
+  if (tree_fits_uhwi_p (lendata.minlen) && tree_fits_uhwi_p (lendata.maxlen))
     {
-      /* Compute the minimum and maximum real or possible lengths.  */
-      c_strlen_data lendata = { };
-      if (get_range_strlen (arg, &lendata, /* eltsize = */1))
+      unsigned HOST_WIDE_INT minlen = tree_to_uhwi (lendata.minlen);
+      unsigned HOST_WIDE_INT maxlen = tree_to_uhwi (lendata.maxlen);
+
+      /* The longest string in this data model.  */
+      const unsigned HOST_WIDE_INT lenmax
+	= tree_to_uhwi (max_object_size ()) - 2;
+
+      if (maxbound == HOST_WIDE_INT_M1U)
 	{
-	  if (tree_fits_shwi_p (lendata.maxlen) && !lendata.maxbound)
-	    {
-	      lenrng[0] = tree_to_shwi (lendata.minlen);
-	      lenrng[1] = tree_to_shwi (lendata.maxlen);
-	      *nulterm = true;
-	    }
-	  else if (lendata.maxbound && tree_fits_shwi_p (lendata.maxbound))
-	    {
-	      /* Set *SIZE to the conservative LENDATA.MAXBOUND which
-		 is a conservative estimate of the longest string based
-		 on the sizes of the arrays referenced by ARG.  */
-	      *size = tree_to_uhwi (lendata.maxbound) + 1;
-	      *nulterm = false;
-	    }
+	  lenrng[0] = minlen;
+	  lenrng[1] = maxlen;
+	  *nulterm = minlen == maxlen;
 	}
-      else
+      else if (maxlen < lenmax)
 	{
-	  /* Set *SIZE to the size of the smallest object referenced
-	     by ARG if ARG denotes a single object, or to HWI_M1U
-	     otherwise.  */
-	  *size = determine_min_objsize (arg);
+	  *size = maxbound + 1;
 	  *nulterm = false;
 	}
+      else
+	return false;
+
+      return true;
     }
 
-  return lenrng[0] != HOST_WIDE_INT_MAX || *size != HOST_WIDE_INT_M1U;
+  if (maxbound != HOST_WIDE_INT_M1U
+      && lendata.maxlen
+      && !integer_all_onesp (lendata.maxlen))
+    {
+      /* Set *SIZE to LENDATA.MAXBOUND which is a conservative estimate
+	 of the longest string based on the sizes of the arrays referenced
+	 by ARG.  */
+      *size = maxbound + 1;
+      *nulterm = false;
+      return true;
+    }
+
+  return false;
 }
 
 /* If IDX1 and IDX2 refer to strings A and B of unequal lengths, return
@@ -4245,15 +4186,15 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
 static tree
 strxcmp_eqz_result (tree arg1, int idx1, tree arg2, int idx2,
 		    unsigned HOST_WIDE_INT bound, unsigned HOST_WIDE_INT len[2],
-		    unsigned HOST_WIDE_INT *psize)
+		    unsigned HOST_WIDE_INT *psize, const vr_values *rvals)
 {
   /* Determine the range the length of each string is in and whether it's
      known to be nul-terminated, or the size of the array it's stored in.  */
   bool nul1, nul2;
   unsigned HOST_WIDE_INT siz1, siz2;
   unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
-  if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1)
-      || !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2))
+  if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1, rvals)
+      || !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2, rvals))
     return NULL_TREE;
 
   /* BOUND is set to HWI_M1U for strcmp and less to strncmp, and LENiRNG
@@ -4405,7 +4346,7 @@ maybe_warn_pointless_strcmp (gimple *stmt, HOST_WIDE_INT bound,
    another and false otherwise.  */
 
 static bool
-handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
+handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
 {
   gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
   tree lhs = gimple_call_lhs (stmt);
@@ -4451,7 +4392,7 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
        or definitely unequal and if so, either fold the result to zero
        (when equal) or set the range of the result to ~[0, 0] otherwise.  */
     if (tree eqz = strxcmp_eqz_result (arg1, idx1, arg2, idx2, bound,
-				       len, &siz))
+				       len, &siz, rvals))
       {
 	if (integer_zerop (eqz))
 	  {
@@ -4482,26 +4423,31 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
   HOST_WIDE_INT cstlen1 = -1, cstlen2 = -1;
   HOST_WIDE_INT arysiz1 = -1, arysiz2 = -1;
 
-  if (idx1)
-    cstlen1 = compute_string_length (idx1);
-  else
-    arysiz1 = determine_min_objsize (arg1);
+  {
+    unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
+    unsigned HOST_WIDE_INT arsz1, arsz2;
+    bool nulterm[2];
+
+    if (!get_len_or_size (arg1, idx1, len1rng, &arsz1, nulterm, rvals)
+	|| !get_len_or_size (arg2, idx2, len2rng, &arsz2, nulterm + 1, rvals))
+      return false;
+
+    if (len1rng[0] == len1rng[1] && len1rng[0] < HOST_WIDE_INT_MAX)
+      cstlen1 = len1rng[0];
+    else if (arsz1 < HOST_WIDE_INT_M1U)
+      arysiz1 = arsz1;
+
+    if (len2rng[0] == len2rng[1] && len2rng[0] < HOST_WIDE_INT_MAX)
+      cstlen2 = len2rng[0];
+    else if (arsz2 < HOST_WIDE_INT_M1U)
+      arysiz2 = arsz2;
+  }
 
   /* Bail if neither the string length nor the size of the array
      it is stored in can be determined.  */
-  if (cstlen1 < 0 && arysiz1 < 0)
-    return false;
-
-  /* Repeat for the second argument.  */
-  if (idx2)
-    cstlen2 = compute_string_length (idx2);
-  else
-    arysiz2 = determine_min_objsize (arg2);
-
-  if (cstlen2 < 0 && arysiz2 < 0)
-    return false;
-
-  if (cstlen1 < 0 && cstlen2 < 0)
+  if ((cstlen1 < 0 && arysiz1 < 0)
+      || (cstlen2 < 0 && arysiz2 < 0)
+      || (cstlen1 < 0 && cstlen2 < 0))
     return false;
 
   if (cstlen1 >= 0)
@@ -5435,7 +5381,7 @@ strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, bool *zero_write,
       break;
     case BUILT_IN_STRCMP:
     case BUILT_IN_STRNCMP:
-      if (handle_builtin_string_cmp (gsi))
+      if (handle_builtin_string_cmp (gsi, rvals))
 	return false;
       break;
     default:


More information about the Gcc-cvs mailing list