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:
Martin Sebor 2019-01-02 06:17:54 +00:00 committed by Jeff Law
parent 2667a5d04a
commit eef2da674a
6 changed files with 209 additions and 138 deletions

View File

@ -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

View File

@ -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

View File

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

View File

@ -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" } } */

View File

@ -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" } } */

View File

@ -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);