diff mbox series

[committed] Further distinguish between length for warnings vs length for codegen/optimization

Message ID 1c1f6837-28c0-9d90-1767-d6632e8df04c@redhat.com
State New
Headers show
Series [committed] Further distinguish between length for warnings vs length for codegen/optimization | expand

Commit Message

Jeff Law Jan. 2, 2019, 6:16 a.m. UTC
This is the second behavior changing hunk of Martin's work.

In this patch we improve the distinction between maxbound/maxlen in
get_range_strlen.  This throttles several of the boundry crossing issues
with string length range computations by allowing us to distinguish
better between a length for warnings (maxbound) and a length of
codegen/optimization purposes (maxlen).

The updated tests reflect cases where we incorrectly optimizing based on
the assumption that we wouldn't cross field boundaries and the like.

This patch also fixes some of the failures in strlen-{5,6,7} which will
be introduced in the next patch.  I didn't include those in this patch
because they'd fail without the next patch.

This has been bootstrapped and regression tested on x86_64.  It'll go
through testing on the other targets overnight.

Installing on the trunk momentarily.

I'm going to stop here for the night.  There's one more behavior
changing patch, then some very light cleanup (STK_LENRANGE_2, comments,
more tests etc) that I'll wrap up tomorrow.

jeff
* gimple-fold.c (get_range_strlen_tree): Record if the computed
	length is optimistic.  If it is, then arrange to compute the
	conservative length as well.

	* gcc.dg/strlenopt-40.c: Update 
	* gcc.dg/strlenopt-51.c: Likewise. 
	* gcc.dg/tree-ssa/pr79376.c: Likewise.
diff mbox series

Patch

diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 6185f98e6bd..cf19db268ad 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1291,6 +1291,12 @@  get_range_strlen_tree (tree arg, bitmap *visited,
   /* The length computed by this invocation of the function.  */
   tree val = NULL_TREE;
 
+  /* True if VAL is an optimistic (tight) bound determined from
+     the size of the character array in which the string may be
+     stored.  In that case, the computed VAL is used to set
+     PDATA->MAXBOUND.  */
+  bool tight_bound = false;
+
   /* We can end up with &(*iftmp_1)[0] here as well, so handle it.  */
   if (TREE_CODE (arg) == ADDR_EXPR
       && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
@@ -1384,6 +1390,7 @@  get_range_strlen_tree (tree arg, bitmap *visited,
 	      && optype == TREE_TYPE (TREE_OPERAND (arg, 0))
 	      && array_at_struct_end_p (TREE_OPERAND (arg, 0)))
 	    *flexp = true;
+	  tight_bound = true;
 	}
       else if (TREE_CODE (arg) == COMPONENT_REF
 	       && (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1)))
@@ -1419,17 +1426,24 @@  get_range_strlen_tree (tree arg, bitmap *visited,
 	  /* Set the minimum size to zero since the string in
 	     the array could have zero length.  */
 	  pdata->minlen = ssize_int (0);
-	}
 
-      if (VAR_P (arg))
-	{
-	  tree type = TREE_TYPE (arg);
-	  if (POINTER_TYPE_P (type))
-	    type = TREE_TYPE (type);
-
-	  if (TREE_CODE (type) == ARRAY_TYPE)
+	  /* The array size determined above is an optimistic bound
+	     on the length.  If the array isn't nul-terminated the
+	     length computed by the library function would be greater.
+	     Even though using strlen to cross the subobject boundary
+	     is undefined, avoid drawing conclusions from the member
+	     type about the length here.  */
+	  tight_bound = true;
+	}
+      else if (VAR_P (arg))
+	{
+	  /* Avoid handling pointers to arrays.  GCC might misuse
+	     a pointer to an array of one bound to point to an array
+	     object of a greater bound.  */
+	  tree argtype = TREE_TYPE (arg);
+	  if (TREE_CODE (argtype) == ARRAY_TYPE)
 	    {
-	      val = TYPE_SIZE_UNIT (type);
+	      val = TYPE_SIZE_UNIT (argtype);
 	      if (!val
 		  || TREE_CODE (val) != INTEGER_CST
 		  || integer_zerop (val))
@@ -1476,6 +1490,43 @@  get_range_strlen_tree (tree arg, bitmap *visited,
   else
     pdata->maxbound = val;
 
+  if (tight_bound)
+    {
+      /* VAL computed above represents an optimistically tight bound
+	 on the length of the string based on the referenced object's
+	 or subobject's type.  Determine the conservative upper bound
+	 based on the enclosing object's size if possible.  */
+      if (rkind == SRK_LENRANGE || rkind == SRK_LENRANGE_2)
+	{
+	  poly_int64 offset;
+	  tree base = get_addr_base_and_unit_offset (arg, &offset);
+	  if (!base)
+	    {
+	      /* When the call above fails due to a non-constant offset
+		 assume the offset is zero and use the size of the whole
+		 enclosing object instead.  */
+	      base = get_base_address (arg);
+	      offset = 0;
+	    }
+	  /* If the base object is a pointer no upper bound on the length
+	     can be determined.  Otherwise the maximum length is equal to
+	     the size of the enclosing object minus the offset of
+	     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)))
+	    val = build_all_ones_cst (size_type_node);
+	  else
+	    {
+	      val = DECL_SIZE_UNIT (base);
+	      val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
+				 size_int (offset + 1));
+	    }
+	}
+      else
+	return false;
+    }
+
   if (pdata->maxlen)
     {
       /* Adjust the more conservative bound if possible/necessary
diff --git a/gcc/testsuite/gcc.dg/strlenopt-40.c b/gcc/testsuite/gcc.dg/strlenopt-40.c
index e24b510deeb..7a97ebb8fe5 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-40.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-40.c
@@ -105,20 +105,23 @@  void elim_global_arrays (int i)
   /* Verify that the expression involving the strlen call as well
      as whatever depends on it is eliminated  from the test output.
      All these expressions must be trivially true.  */
-  ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3[0]);
-  ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3[1]);
-  ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3[6]);
-  ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3[i]);
-
-  ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7[0]);
-  ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7[1]);
-  ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7[4]);
-  ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7[0]);
-
-  ELIM_TRUE (strlen (ax_3[0]) < sizeof ax_3[0]);
-  ELIM_TRUE (strlen (ax_3[1]) < sizeof ax_3[1]);
-  ELIM_TRUE (strlen (ax_3[9]) < sizeof ax_3[9]);
-  ELIM_TRUE (strlen (ax_3[i]) < sizeof ax_3[i]);
+  ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3);
+  ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3 - sizeof *a7_3);
+  ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3 - 5 * sizeof *a7_3);
+  ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3);
+
+  ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7);
+  ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7 - sizeof *a5_7);
+  ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7 - 3 * sizeof *a5_7);
+  ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7);
+
+  /* Even when treating a multi-dimensional array as a single string
+     the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC
+     doesn't do that computation yet so avoid testing it.  */
+  ELIM_TRUE (strlen (ax_3[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[9]) < DIFF_MAX);
+  ELIM_TRUE (strlen (ax_3[i]) < DIFF_MAX);
 
   ELIM_TRUE (strlen (a3) < sizeof a3);
   ELIM_TRUE (strlen (a7) < sizeof a7);
@@ -130,21 +133,25 @@  void elim_global_arrays (int i)
 
 void elim_pointer_to_arrays (void)
 {
-  ELIM_TRUE (strlen (*pa7) < 7);
-  ELIM_TRUE (strlen (*pa5) < 5);
-  ELIM_TRUE (strlen (*pa3) < 3);
-
-  ELIM_TRUE (strlen ((*pa7_3)[0]) < 3);
-  ELIM_TRUE (strlen ((*pa7_3)[1]) < 3);
-  ELIM_TRUE (strlen ((*pa7_3)[6]) < 3);
-
-  ELIM_TRUE (strlen ((*pax_3)[0]) < 3);
-  ELIM_TRUE (strlen ((*pax_3)[1]) < 3);
-  ELIM_TRUE (strlen ((*pax_3)[9]) < 3);
-
-  ELIM_TRUE (strlen ((*pa5_7)[0]) < 7);
-  ELIM_TRUE (strlen ((*pa5_7)[1]) < 7);
-  ELIM_TRUE (strlen ((*pa5_7)[4]) < 7);
+  /* Unfortunately, GCC cannot be trusted not to misuse a pointer
+     to a smaller array to point to an object of a bigger type so
+     the strlen range optimization must assume each array pointer
+     points effectively to an array of an unknown bound.  */
+  ELIM_TRUE (strlen (*pa7) < DIFF_MAX);
+  ELIM_TRUE (strlen (*pa5) < DIFF_MAX);
+  ELIM_TRUE (strlen (*pa3) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pax_3)[9]) < DIFF_MAX);
+
+  ELIM_TRUE (strlen ((*pa5_7)[0]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa5_7)[1]) < DIFF_MAX);
+  ELIM_TRUE (strlen ((*pa5_7)[4]) < DIFF_MAX);
 }
 
 void elim_global_arrays_and_strings (int i)
@@ -176,65 +183,33 @@  void elim_global_arrays_and_strings (int i)
 
 void elim_member_arrays_obj (int i)
 {
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a3) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][2].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][6].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][0][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < 5);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < 5);
+  ELIM_TRUE (strlen (ma0_3_5_7[1][1][0].a5) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < 3);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 3);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a7_3[0]) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < sizeof ma0_3_5_7);
 
-  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 7);
-}
-
-void elim_member_arrays_ptr (struct MemArrays0 *ma0,
-			     struct MemArraysX *max,
-			     struct MemArrays7 *ma7,
-			     int i)
-{
-  ELIM_TRUE (strlen (ma0->a7_3[0]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[1]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[6]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
-  ELIM_TRUE (strlen (ma0->a7_3[i]) < 3);
-
-  ELIM_TRUE (strlen (ma0->a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[0].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[1].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[1].a5_7[4]) < 7);
-  ELIM_TRUE (strlen (ma0[9].a5_7[0]) < 7);
-  ELIM_TRUE (strlen (ma0[9].a5_7[4]) < 7);
-
-  ELIM_TRUE (strlen (ma0->a3) < sizeof ma0->a3);
-  ELIM_TRUE (strlen (ma0->a5) < sizeof ma0->a5);
-  ELIM_TRUE (strlen (ma0->a0) < DIFF_MAX - 1);
-
-  ELIM_TRUE (strlen (max->a3) < sizeof max->a3);
-  ELIM_TRUE (strlen (max->a5) < sizeof max->a5);
-  ELIM_TRUE (strlen (max->ax) < DIFF_MAX - 1);
-
-  ELIM_TRUE (strlen (ma7->a3) < sizeof max->a3);
-  ELIM_TRUE (strlen (ma7->a5) < sizeof max->a5);
-  ELIM_TRUE (strlen (ma7->a7) < DIFF_MAX - 1);
+  ELIM_TRUE (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < sizeof ma0_3_5_7);
+  ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < sizeof ma0_3_5_7);
 }
 
 
@@ -255,11 +230,27 @@  void keep_global_arrays (int i)
   KEEP (strlen (a5_7[4]) < 6);
   KEEP (strlen (a5_7[i]) < 6);
 
+  /* Verify also that tests (and strlen calls) are not eliminated
+     for results greater than what would the size of the innermost
+     array suggest might be possible (in case the element array is
+     not nul-terminated), even though such calls are undefined.  */
+  KEEP (strlen (a5_7[0]) > sizeof a5_7 - 2);
+  KEEP (strlen (a5_7[1]) > sizeof a5_7 - sizeof a5_7[1] - 2);
+  KEEP (strlen (a5_7[i]) > sizeof a5_7 - 2);
+
   KEEP (strlen (ax_3[0]) < 2);
   KEEP (strlen (ax_3[1]) < 2);
   KEEP (strlen (ax_3[2]) < 2);
   KEEP (strlen (ax_3[i]) < 2);
 
+  /* Here again, verify that the ax_3 matrix is treated essentially
+     as a flat array of unknown bound for the benefit of all the
+     undefined code out there that might rely on it.  */
+  KEEP (strlen (ax_3[0]) > 3);
+  KEEP (strlen (ax_3[1]) > 9);
+  KEEP (strlen (ax_3[2]) > 99);
+  KEEP (strlen (ax_3[i]) > 999);
+
   KEEP (strlen (a3) < 2);
   KEEP (strlen (a7) < 6);
 
@@ -274,24 +265,48 @@  void keep_global_arrays (int i)
   KEEP (strlen (ax) < 1);
 }
 
-void keep_pointer_to_arrays (void)
+void keep_pointer_to_arrays (int i)
 {
   KEEP (strlen (*pa7) < 6);
   KEEP (strlen (*pa5) < 4);
   KEEP (strlen (*pa3) < 2);
 
+  /* Since GCC cannot be trusted not to misuse a pointer to a smaller
+     array to point to an object of a larger type verify that the bound
+     in a pointer to an array of a known bound isn't relied on for
+     the strlen range optimization.  If GCC is fixed to avoid these
+     misuses these tests can be removed.  */
+  KEEP (strlen (*pa7) > sizeof *pa7);
+  KEEP (strlen (*pa5) > sizeof *pa5);
+  KEEP (strlen (*pa3) > sizeof *pa3);
+
   KEEP (strlen ((*pa7_3)[0]) < 2);
   KEEP (strlen ((*pa7_3)[1]) < 2);
   KEEP (strlen ((*pa7_3)[6]) < 2);
+  KEEP (strlen ((*pa7_3)[i]) < 2);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pa7_3)[0]) > sizeof *pa7_3);
+  KEEP (strlen ((*pa7_3)[i]) > sizeof *pa7_3);
 
   KEEP (strlen ((*pax_3)[0]) < 2);
   KEEP (strlen ((*pax_3)[1]) < 2);
   KEEP (strlen ((*pax_3)[9]) < 2);
+  KEEP (strlen ((*pax_3)[i]) < 2);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pax_3)[0]) > 3);
+  KEEP (strlen ((*pax_3)[i]) > 333);
 
   KEEP (strlen ((*pa5_7)[0]) < 6);
   KEEP (strlen ((*pa5_7)[1]) < 6);
   KEEP (strlen ((*pa5_7)[4]) < 6);
-}
+  KEEP (strlen ((*pa5_7)[i]) < 6);
+
+  /* Same as above.  */
+  KEEP (strlen ((*pa5_7)[0]) > sizeof *pa5_7);
+  KEEP (strlen ((*pa5_7)[i]) > sizeof *pa5_7);
+ }
 
 void keep_global_arrays_and_strings (int i)
 {
@@ -306,6 +321,12 @@  void keep_global_arrays_and_strings (int i)
   KEEP (strlen (i < 0 ? a7 : "123") < 5);
   KEEP (strlen (i < 0 ? a7 : "123456") < 6);
   KEEP (strlen (i < 0 ? a7 : "1234567") < 6);
+
+  /* Verify that a matrix is treated as a flat array even in a conditional
+     expression (i.e., don't assume that a7_3[0] is nul-terminated, even
+     though calling strlen() on such an array is undefined).  */
+  KEEP (strlen (i < 0 ? a7_3[0] : "") > 7);
+  KEEP (strlen (i < 0 ? a7_3[i] : "") > 7);
 }
 
 void keep_member_arrays_obj (int i)
@@ -337,6 +358,12 @@  void keep_member_arrays_obj (int i)
 
   KEEP (strlen (ma0_3_5_7[0][0][0].a5_7[0]) < 6);
   KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 6);
+
+  /* Again, verify that the .a3 array isn't assumed to necessarily
+     be nul-terminated.  */
+  KEEP (strlen (ma0_3_5_7[0][0][0].a3) > 2);
+  KEEP (strlen (ma0_3_5_7[0][0][6].a3) > 2);
+  KEEP (strlen (ma0_3_5_7[0][0][i].a3) > 2);
 }
 
 void keep_member_arrays_ptr (struct MemArrays0 *ma0,
@@ -353,6 +380,11 @@  void keep_member_arrays_ptr (struct MemArrays0 *ma0,
   KEEP (strlen (ma0->a7_3[i]) < 2);
   KEEP (strlen (ma0->a7_3[i]) < 2);
 
+  /* Again, verify that the member array isn't assumed to necessarily
+     be nul-terminated.  */
+  KEEP (strlen (ma0->a7_3[0]) > sizeof ma0->a7_3);
+  KEEP (strlen (ma0->a7_3[i]) > sizeof ma0->a7_3);
+
   KEEP (strlen (ma0->a5_7[0]) < 5);
   KEEP (strlen (ma0[0].a5_7[0]) < 5);
   KEEP (strlen (ma0[1].a5_7[0]) < 5);
@@ -361,6 +393,9 @@  void keep_member_arrays_ptr (struct MemArrays0 *ma0,
   KEEP (strlen (ma0[i].a5_7[4]) < 5);
   KEEP (strlen (ma0[i].a5_7[i]) < 5);
 
+  /* Same as above.  */
+  KEEP (strlen (ma0[i].a5_7[i]) > sizeof ma0[i].a5_7);
+
   KEEP (strlen (ma0->a0) < DIFF_MAX - 2);
   KEEP (strlen (ma0->a0) < 999);
   KEEP (strlen (ma0->a0) < 1);
@@ -389,5 +424,5 @@  void keep_pointers (const char *s)
 /* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
    { dg-final { scan-tree-dump-times "call_in_false_branch_not_eliminated_" 0 "optimized" } }
 
-   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } }
-   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 92 "optimized" } } */
+   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } }
+   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/strlenopt-51.c b/gcc/testsuite/gcc.dg/strlenopt-51.c
index cbed11bbf58..3d879f1329a 100644
--- a/gcc/testsuite/gcc.dg/strlenopt-51.c
+++ b/gcc/testsuite/gcc.dg/strlenopt-51.c
@@ -1,16 +1,17 @@ 
 /* PR tree-optimization/77357 - strlen of constant strings not folded
    { dg-do compile }
-   { dg-options "-O2 -Wall -fdump-tree-gimple -fdump-tree-optimized" } */
+   { dg-options "-O0 -Wall -fdump-tree-gimple" } */
 
 #include "strlenopt.h"
 
 #define CONCAT(x, y) x ## y
 #define CAT(x, y) CONCAT (x, y)
-#define FAILNAME(name) CAT (call_ ## name ##_on_line_, __LINE__)
+#define FAILNAME(name, counter) \
+  CAT (CAT (CAT (call_ ## name ##_on_line_, __LINE__), _), counter)
 
-#define FAIL(name) do {				\
-    extern void FAILNAME (name) (void);		\
-    FAILNAME (name)();				\
+#define FAIL(name, counter) do {			\
+    extern void FAILNAME (name, counter) (void);	\
+    FAILNAME (name, counter)();				\
   } while (0)
 
 /* Macro to emit a call to funcation named
@@ -19,19 +20,7 @@ 
    scan-tree-dump-time directive at the bottom of the test verifies
    that no such call appears in output.  */
 #define ELIM(expr) \
-  if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
-
-/* Macro to emit a call to a function named
-     call_made_in_{true,false}_branch_on_line_NNN()
-   for each call that's expected to be retained.  The dg-final
-   scan-tree-dump-time directive at the bottom of the test verifies
-   that the expected number of both kinds of calls appears in output
-   (a pair for each line with the invocation of the KEEP() macro.  */
-#define KEEP(expr)				\
-  if (expr)					\
-    FAIL (made_in_true_branch);			\
-  else						\
-    FAIL (made_in_false_branch)
+  if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); else (void)0
 
 #define T(s, n) ELIM (strlen (s) == n)
 
@@ -53,7 +42,7 @@  struct S
 
 const char a9[][9] = { S0, S1, S2, S3, S4, S5, S6, S7, S8 };
 
-void test_elim_a9 (int i)
+void test_elim_a9 (unsigned i)
 {
   ELIM (strlen (&a9[0][i]) > 0);
   ELIM (strlen (&a9[1][i]) > 1);
@@ -75,10 +64,10 @@  const char a9_9[][9][9] = {
   { S5, S6, S7, S8, S0, S1, S2, S3, S4 },
   { S6, S7, S8, S0, S1, S2, S3, S4, S5 },
   { S7, S8, S0, S1, S2, S3, S4, S5, S6 },
-  { S8, S0, S2, S2, S3, S4, S5, S6, S7 }
+  { S8, S0, S1, S2, S3, S4, S5, S6, S7 }
 };
 
-void test_elim_a9_9 (int i)
+void test_elim_a9_9 (unsigned i)
 {
 #undef T
 #define T(I)					\
@@ -95,27 +84,4 @@  void test_elim_a9_9 (int i)
   T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
 }
 
-#line 1000
-
-void test_keep_a9_9 (int i)
-{
-#undef T
-#define T(I)					\
-  KEEP (strlen (&a9_9[i][I][0]) > (1 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][1]) > (1 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][2]) > (2 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][3]) > (3 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][4]) > (4 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][5]) > (5 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][6]) > (6 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][7]) > (7 + I) % 9);	\
-  KEEP (strlen (&a9_9[i][I][8]) > (8 + I) % 9)
-
-  T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
-}
-
-/* { dg-final { scan-tree-dump-times "strlen" 72 "gimple" } }
-   { dg-final { scan-tree-dump-times "strlen" 63 "optimized" } }
-
-   { dg-final { scan-tree-dump-times "call_made_in_true_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 72 "optimized" } }
-   { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 81 "optimized" } } */
+/* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c b/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
index 01ecd178211..466dcde998a 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr79376.c
@@ -40,7 +40,18 @@  void test_arrays (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 3);
+    /* Since it's undefined to pass an unterminated array to a %s
+       directive it would be valid to assume that S above is not
+       longer than sizeof (A->A3) but the optimization isn't done
+       because the GIMPLE representation of the %s argument isn't
+       suffficiently reliable not to confuse it for some other
+       array.  The argument length is therefore assumed to be in
+       the range [0, PTRDIFF_MAX - 2] and the sprintf result to be
+       as big as INT_MAX and possibly even negative if the function
+       were to fail due to a single directive resulting in more than
+       the 4,095 byte maximum required to be supported.
+       ASSERT (0 <= n && n < 3);
+    */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -52,7 +63,7 @@  void test_arrays (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -69,7 +80,7 @@  void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 3);
+    /* ASSERT (0 <= n && n < 3); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -81,7 +92,7 @@  void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);
@@ -95,7 +106,7 @@  void test_string_and_array (int i, struct Arrays *a)
 
     int n = __builtin_snprintf (0, 0, "%-s", s);
 
-    ASSERT (0 <= n && n < 5);
+    /* ASSERT (0 <= n && n < 5); */
 
     ASSERT_MAYBE (0 == n);
     ASSERT_MAYBE (1 == n);