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
This commit is contained in:
parent
2667a5d04a
commit
eef2da674a
|
@ -1,6 +1,10 @@
|
|||
2019-01-01 Martin Sebor <msebor@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.
|
||||
* builtins.c (check_access): Update call to get_range_strlen to use
|
||||
c_strlen_data pointer. Change various variable accesses to instead
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if (VAR_P (arg))
|
||||
else if (VAR_P (arg))
|
||||
{
|
||||
tree type = TREE_TYPE (arg);
|
||||
if (POINTER_TYPE_P (type))
|
||||
type = TREE_TYPE (type);
|
||||
|
||||
if (TREE_CODE (type) == ARRAY_TYPE)
|
||||
/* 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
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
2019-01-01 Martin Sebor <msebor@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-48.c: Twiddle test slightly.
|
||||
* gcc.dg/strlenopt-59.c: New test.
|
||||
|
|
|
@ -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 (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[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 (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);
|
||||
|
||||
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]);
|
||||
/* 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);
|
||||
/* 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]) < 3);
|
||||
ELIM_TRUE (strlen ((*pa7_3)[1]) < 3);
|
||||
ELIM_TRUE (strlen ((*pa7_3)[6]) < 3);
|
||||
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]) < 3);
|
||||
ELIM_TRUE (strlen ((*pax_3)[1]) < 3);
|
||||
ELIM_TRUE (strlen ((*pax_3)[9]) < 3);
|
||||
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]) < 7);
|
||||
ELIM_TRUE (strlen ((*pa5_7)[1]) < 7);
|
||||
ELIM_TRUE (strlen ((*pa5_7)[4]) < 7);
|
||||
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" } } */
|
||||
|
|
|
@ -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" } } */
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue