Commit eef2da67 by Martin Sebor Committed by Jeff Law

gimple-fold.c (get_range_strlen_tree): Record if the computed length is optimistic.

	* 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.

Co-Authored-By: Jeff Law <law@redhat.com>

From-SVN: r267505
parent 2667a5d0
2019-01-01 Martin Sebor <msebor@redhat.com> 2019-01-01 Martin Sebor <msebor@redhat.com>
Jeff Law <law@redhat.com> Jeff Law <law@redhat.com>
* 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.
* gimple-fold.h (get_range_strlen): Update prototype. * gimple-fold.h (get_range_strlen): Update prototype.
* builtins.c (check_access): Update call to get_range_strlen to use * builtins.c (check_access): Update call to get_range_strlen to use
c_strlen_data pointer. Change various variable accesses to instead c_strlen_data pointer. Change various variable accesses to instead
......
...@@ -1291,6 +1291,12 @@ get_range_strlen_tree (tree arg, bitmap *visited, ...@@ -1291,6 +1291,12 @@ get_range_strlen_tree (tree arg, bitmap *visited,
/* The length computed by this invocation of the function. */ /* The length computed by this invocation of the function. */
tree val = NULL_TREE; 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. */ /* We can end up with &(*iftmp_1)[0] here as well, so handle it. */
if (TREE_CODE (arg) == ADDR_EXPR if (TREE_CODE (arg) == ADDR_EXPR
&& TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF) && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
...@@ -1384,6 +1390,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, ...@@ -1384,6 +1390,7 @@ get_range_strlen_tree (tree arg, bitmap *visited,
&& optype == TREE_TYPE (TREE_OPERAND (arg, 0)) && optype == TREE_TYPE (TREE_OPERAND (arg, 0))
&& array_at_struct_end_p (TREE_OPERAND (arg, 0))) && array_at_struct_end_p (TREE_OPERAND (arg, 0)))
*flexp = true; *flexp = true;
tight_bound = true;
} }
else if (TREE_CODE (arg) == COMPONENT_REF else if (TREE_CODE (arg) == COMPONENT_REF
&& (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) && (TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1)))
...@@ -1419,17 +1426,24 @@ get_range_strlen_tree (tree arg, bitmap *visited, ...@@ -1419,17 +1426,24 @@ get_range_strlen_tree (tree arg, bitmap *visited,
/* Set the minimum size to zero since the string in /* Set the minimum size to zero since the string in
the array could have zero length. */ the array could have zero length. */
pdata->minlen = ssize_int (0); pdata->minlen = ssize_int (0);
}
if (VAR_P (arg)) /* The array size determined above is an optimistic bound
{ on the length. If the array isn't nul-terminated the
tree type = TREE_TYPE (arg); length computed by the library function would be greater.
if (POINTER_TYPE_P (type)) Even though using strlen to cross the subobject boundary
type = TREE_TYPE (type); is undefined, avoid drawing conclusions from the member
type about the length here. */
if (TREE_CODE (type) == ARRAY_TYPE) 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 if (!val
|| TREE_CODE (val) != INTEGER_CST || TREE_CODE (val) != INTEGER_CST
|| integer_zerop (val)) || integer_zerop (val))
...@@ -1476,6 +1490,43 @@ get_range_strlen_tree (tree arg, bitmap *visited, ...@@ -1476,6 +1490,43 @@ get_range_strlen_tree (tree arg, bitmap *visited,
else else
pdata->maxbound = val; 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) if (pdata->maxlen)
{ {
/* Adjust the more conservative bound if possible/necessary /* Adjust the more conservative bound if possible/necessary
......
2019-01-01 Martin Sebor <msebor@redhat.com> 2019-01-01 Martin Sebor <msebor@redhat.com>
Jeff Law <law@redhat.com> Jeff Law <law@redhat.com>
* gcc.dg/strlenopt-40.c: Update
* gcc.dg/strlenopt-51.c: Likewise.
* gcc.dg/tree-ssa/pr79376.c: Likewise.
* gcc.dg/strlenopt-40.c: Disable a couple tests. * gcc.dg/strlenopt-40.c: Disable a couple tests.
* gcc.dg/strlenopt-48.c: Twiddle test slightly. * gcc.dg/strlenopt-48.c: Twiddle test slightly.
* gcc.dg/strlenopt-59.c: New test. * gcc.dg/strlenopt-59.c: New test.
......
...@@ -105,20 +105,23 @@ void elim_global_arrays (int i) ...@@ -105,20 +105,23 @@ void elim_global_arrays (int i)
/* Verify that the expression involving the strlen call as well /* Verify that the expression involving the strlen call as well
as whatever depends on it is eliminated from the test output. as whatever depends on it is eliminated from the test output.
All these expressions must be trivially true. */ All these expressions must be trivially true. */
ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3[0]); ELIM_TRUE (strlen (a7_3[0]) < sizeof a7_3);
ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3[1]); ELIM_TRUE (strlen (a7_3[1]) < sizeof a7_3 - sizeof *a7_3);
ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3[6]); ELIM_TRUE (strlen (a7_3[6]) < sizeof a7_3 - 5 * sizeof *a7_3);
ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3[i]); ELIM_TRUE (strlen (a7_3[i]) < sizeof a7_3);
ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7[0]); ELIM_TRUE (strlen (a5_7[0]) < sizeof a5_7);
ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7[1]); ELIM_TRUE (strlen (a5_7[1]) < sizeof a5_7 - sizeof *a5_7);
ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7[4]); ELIM_TRUE (strlen (a5_7[4]) < sizeof a5_7 - 3 * sizeof *a5_7);
ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7[0]); ELIM_TRUE (strlen (a5_7[i]) < sizeof a5_7);
ELIM_TRUE (strlen (ax_3[0]) < sizeof ax_3[0]); /* Even when treating a multi-dimensional array as a single string
ELIM_TRUE (strlen (ax_3[1]) < sizeof ax_3[1]); the length must be less DIFF_MAX - (ax_3[i] - ax_3[0]) but GCC
ELIM_TRUE (strlen (ax_3[9]) < sizeof ax_3[9]); doesn't do that computation yet so avoid testing it. */
ELIM_TRUE (strlen (ax_3[i]) < sizeof ax_3[i]); 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 (a3) < sizeof a3);
ELIM_TRUE (strlen (a7) < sizeof a7); ELIM_TRUE (strlen (a7) < sizeof a7);
...@@ -130,21 +133,25 @@ void elim_global_arrays (int i) ...@@ -130,21 +133,25 @@ void elim_global_arrays (int i)
void elim_pointer_to_arrays (void) void elim_pointer_to_arrays (void)
{ {
ELIM_TRUE (strlen (*pa7) < 7); /* Unfortunately, GCC cannot be trusted not to misuse a pointer
ELIM_TRUE (strlen (*pa5) < 5); to a smaller array to point to an object of a bigger type so
ELIM_TRUE (strlen (*pa3) < 3); the strlen range optimization must assume each array pointer
points effectively to an array of an unknown bound. */
ELIM_TRUE (strlen ((*pa7_3)[0]) < 3); ELIM_TRUE (strlen (*pa7) < DIFF_MAX);
ELIM_TRUE (strlen ((*pa7_3)[1]) < 3); ELIM_TRUE (strlen (*pa5) < DIFF_MAX);
ELIM_TRUE (strlen ((*pa7_3)[6]) < 3); ELIM_TRUE (strlen (*pa3) < DIFF_MAX);
ELIM_TRUE (strlen ((*pax_3)[0]) < 3); ELIM_TRUE (strlen ((*pa7_3)[0]) < DIFF_MAX);
ELIM_TRUE (strlen ((*pax_3)[1]) < 3); ELIM_TRUE (strlen ((*pa7_3)[1]) < DIFF_MAX);
ELIM_TRUE (strlen ((*pax_3)[9]) < 3); ELIM_TRUE (strlen ((*pa7_3)[6]) < DIFF_MAX);
ELIM_TRUE (strlen ((*pa5_7)[0]) < 7); ELIM_TRUE (strlen ((*pax_3)[0]) < DIFF_MAX);
ELIM_TRUE (strlen ((*pa5_7)[1]) < 7); ELIM_TRUE (strlen ((*pax_3)[1]) < DIFF_MAX);
ELIM_TRUE (strlen ((*pa5_7)[4]) < 7); 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) void elim_global_arrays_and_strings (int i)
...@@ -176,65 +183,33 @@ 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) 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][0].a3) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a3) < 3); 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) < 3); 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) < 3); 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[1][0][0].a3) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a3) < 3); 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[1][1][0].a3) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a3) < 3); 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][0].a5) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[0][0][1].a5) < 5); 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) < 5); 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) < 5); 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[1][0][0].a5) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][0][1].a5) < 5); 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[1][1][0].a5) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5) < 5); 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[0][0][0].a7_3[0]) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a7_3[2]) < 3); 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[0][0][0].a5_7[0]) < sizeof ma0_3_5_7);
ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 7); ELIM_TRUE (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < sizeof ma0_3_5_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);
} }
...@@ -255,11 +230,27 @@ void keep_global_arrays (int i) ...@@ -255,11 +230,27 @@ void keep_global_arrays (int i)
KEEP (strlen (a5_7[4]) < 6); KEEP (strlen (a5_7[4]) < 6);
KEEP (strlen (a5_7[i]) < 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[0]) < 2);
KEEP (strlen (ax_3[1]) < 2); KEEP (strlen (ax_3[1]) < 2);
KEEP (strlen (ax_3[2]) < 2); KEEP (strlen (ax_3[2]) < 2);
KEEP (strlen (ax_3[i]) < 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 (a3) < 2);
KEEP (strlen (a7) < 6); KEEP (strlen (a7) < 6);
...@@ -274,24 +265,48 @@ void keep_global_arrays (int i) ...@@ -274,24 +265,48 @@ void keep_global_arrays (int i)
KEEP (strlen (ax) < 1); KEEP (strlen (ax) < 1);
} }
void keep_pointer_to_arrays (void) void keep_pointer_to_arrays (int i)
{ {
KEEP (strlen (*pa7) < 6); KEEP (strlen (*pa7) < 6);
KEEP (strlen (*pa5) < 4); KEEP (strlen (*pa5) < 4);
KEEP (strlen (*pa3) < 2); 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)[0]) < 2);
KEEP (strlen ((*pa7_3)[1]) < 2); KEEP (strlen ((*pa7_3)[1]) < 2);
KEEP (strlen ((*pa7_3)[6]) < 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)[0]) < 2);
KEEP (strlen ((*pax_3)[1]) < 2); KEEP (strlen ((*pax_3)[1]) < 2);
KEEP (strlen ((*pax_3)[9]) < 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)[0]) < 6);
KEEP (strlen ((*pa5_7)[1]) < 6); KEEP (strlen ((*pa5_7)[1]) < 6);
KEEP (strlen ((*pa5_7)[4]) < 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) void keep_global_arrays_and_strings (int i)
{ {
...@@ -306,6 +321,12 @@ 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 : "123") < 5);
KEEP (strlen (i < 0 ? a7 : "123456") < 6); KEEP (strlen (i < 0 ? a7 : "123456") < 6);
KEEP (strlen (i < 0 ? a7 : "1234567") < 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) void keep_member_arrays_obj (int i)
...@@ -337,6 +358,12 @@ 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[0][0][0].a5_7[0]) < 6);
KEEP (strlen (ma0_3_5_7[2][4][6].a5_7[4]) < 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, void keep_member_arrays_ptr (struct MemArrays0 *ma0,
...@@ -353,6 +380,11 @@ 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);
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->a5_7[0]) < 5);
KEEP (strlen (ma0[0].a5_7[0]) < 5); KEEP (strlen (ma0[0].a5_7[0]) < 5);
KEEP (strlen (ma0[1].a5_7[0]) < 5); KEEP (strlen (ma0[1].a5_7[0]) < 5);
...@@ -361,6 +393,9 @@ void keep_member_arrays_ptr (struct MemArrays0 *ma0, ...@@ -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[4]) < 5);
KEEP (strlen (ma0[i].a5_7[i]) < 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) < DIFF_MAX - 2);
KEEP (strlen (ma0->a0) < 999); KEEP (strlen (ma0->a0) < 999);
KEEP (strlen (ma0->a0) < 1); KEEP (strlen (ma0->a0) < 1);
...@@ -389,5 +424,5 @@ void keep_pointers (const char *s) ...@@ -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_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_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_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\]" 92 "optimized" } } */ { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 119 "optimized" } } */
/* PR tree-optimization/77357 - strlen of constant strings not folded /* PR tree-optimization/77357 - strlen of constant strings not folded
{ dg-do compile } { dg-do compile }
{ dg-options "-O2 -Wall -fdump-tree-gimple -fdump-tree-optimized" } */ { dg-options "-O0 -Wall -fdump-tree-gimple" } */
#include "strlenopt.h" #include "strlenopt.h"
#define CONCAT(x, y) x ## y #define CONCAT(x, y) x ## y
#define CAT(x, y) CONCAT (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 { \ #define FAIL(name, counter) do { \
extern void FAILNAME (name) (void); \ extern void FAILNAME (name, counter) (void); \
FAILNAME (name)(); \ FAILNAME (name, counter)(); \
} while (0) } while (0)
/* Macro to emit a call to funcation named /* Macro to emit a call to funcation named
...@@ -19,19 +20,7 @@ ...@@ -19,19 +20,7 @@
scan-tree-dump-time directive at the bottom of the test verifies scan-tree-dump-time directive at the bottom of the test verifies
that no such call appears in output. */ that no such call appears in output. */
#define ELIM(expr) \ #define ELIM(expr) \
if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0 if (!(expr)) FAIL (in_true_branch_not_eliminated, __COUNTER__); 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)
#define T(s, n) ELIM (strlen (s) == n) #define T(s, n) ELIM (strlen (s) == n)
...@@ -53,7 +42,7 @@ struct S ...@@ -53,7 +42,7 @@ struct S
const char a9[][9] = { S0, S1, S2, S3, S4, S5, S6, S7, S8 }; 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[0][i]) > 0);
ELIM (strlen (&a9[1][i]) > 1); ELIM (strlen (&a9[1][i]) > 1);
...@@ -75,10 +64,10 @@ const char a9_9[][9][9] = { ...@@ -75,10 +64,10 @@ const char a9_9[][9][9] = {
{ S5, S6, S7, S8, S0, S1, S2, S3, S4 }, { S5, S6, S7, S8, S0, S1, S2, S3, S4 },
{ S6, S7, S8, S0, S1, S2, S3, S4, S5 }, { S6, S7, S8, S0, S1, S2, S3, S4, S5 },
{ S7, S8, S0, S1, S2, S3, S4, S5, S6 }, { 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 #undef T
#define T(I) \ #define T(I) \
...@@ -95,27 +84,4 @@ void test_elim_a9_9 (int 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); T (0); T (1); T (2); T (3); T (4); T (5); T (6); T (7); T (8);
} }
#line 1000 /* { dg-final { scan-tree-dump-times "strlen" 0 "gimple" } } */
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" } } */
...@@ -40,7 +40,18 @@ void test_arrays (int i, struct Arrays *a) ...@@ -40,7 +40,18 @@ void test_arrays (int i, struct Arrays *a)
int n = __builtin_snprintf (0, 0, "%-s", s); 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 (0 == n);
ASSERT_MAYBE (1 == n); ASSERT_MAYBE (1 == n);
...@@ -52,7 +63,7 @@ void test_arrays (int i, struct Arrays *a) ...@@ -52,7 +63,7 @@ void test_arrays (int i, struct Arrays *a)
int n = __builtin_snprintf (0, 0, "%-s", s); int n = __builtin_snprintf (0, 0, "%-s", s);
ASSERT (0 <= n && n < 5); /* ASSERT (0 <= n && n < 5); */
ASSERT_MAYBE (0 == n); ASSERT_MAYBE (0 == n);
ASSERT_MAYBE (1 == n); ASSERT_MAYBE (1 == n);
...@@ -69,7 +80,7 @@ void test_string_and_array (int i, struct Arrays *a) ...@@ -69,7 +80,7 @@ void test_string_and_array (int i, struct Arrays *a)
int n = __builtin_snprintf (0, 0, "%-s", s); int n = __builtin_snprintf (0, 0, "%-s", s);
ASSERT (0 <= n && n < 3); /* ASSERT (0 <= n && n < 3); */
ASSERT_MAYBE (0 == n); ASSERT_MAYBE (0 == n);
ASSERT_MAYBE (1 == n); ASSERT_MAYBE (1 == n);
...@@ -81,7 +92,7 @@ void test_string_and_array (int i, struct Arrays *a) ...@@ -81,7 +92,7 @@ void test_string_and_array (int i, struct Arrays *a)
int n = __builtin_snprintf (0, 0, "%-s", s); int n = __builtin_snprintf (0, 0, "%-s", s);
ASSERT (0 <= n && n < 5); /* ASSERT (0 <= n && n < 5); */
ASSERT_MAYBE (0 == n); ASSERT_MAYBE (0 == n);
ASSERT_MAYBE (1 == n); ASSERT_MAYBE (1 == n);
...@@ -95,7 +106,7 @@ void test_string_and_array (int i, struct Arrays *a) ...@@ -95,7 +106,7 @@ void test_string_and_array (int i, struct Arrays *a)
int n = __builtin_snprintf (0, 0, "%-s", s); int n = __builtin_snprintf (0, 0, "%-s", s);
ASSERT (0 <= n && n < 5); /* ASSERT (0 <= n && n < 5); */
ASSERT_MAYBE (0 == n); ASSERT_MAYBE (0 == n);
ASSERT_MAYBE (1 == n); ASSERT_MAYBE (1 == n);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment