From eef2da674ab7e8a9551e656e649359c2b27b026d Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Wed, 2 Jan 2019 06:17:54 +0000 Subject: [PATCH] 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 From-SVN: r267505 --- gcc/ChangeLog | 4 + gcc/gimple-fold.c | 69 ++++++-- gcc/testsuite/ChangeLog | 4 + gcc/testsuite/gcc.dg/strlenopt-40.c | 205 ++++++++++++++---------- gcc/testsuite/gcc.dg/strlenopt-51.c | 56 ++----- gcc/testsuite/gcc.dg/tree-ssa/pr79376.c | 21 ++- 6 files changed, 215 insertions(+), 144 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a57567cd8c9..8d243aa03c5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,6 +1,10 @@ 2019-01-01 Martin Sebor Jeff Law + * 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 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/ChangeLog b/gcc/testsuite/ChangeLog index 60eaac7d2cd..6f603209cc7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,6 +1,10 @@ 2019-01-01 Martin Sebor Jeff Law + * 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. 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); -- 2.30.2