From 781ff3d80e88d7d0df019eb3e82ef2a3fb64429c Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Mon, 18 Jun 2018 16:32:59 +0000 Subject: PR tree-optimization/81384 - built-in form of strnlen missing gcc/ChangeLog: PR tree-optimization/81384 * builtin-types.def (BT_FN_SIZE_CONST_STRING_SIZE): New. * builtins.c (expand_builtin_strnlen): New function. (expand_builtin): Call it. (fold_builtin_n): Avoid setting TREE_NO_WARNING. * builtins.def (BUILT_IN_STRNLEN): New. * calls.c (maybe_warn_nonstring_arg): Handle BUILT_IN_STRNLEN. Warn for bounds in excess of maximum object size. * tree-ssa-strlen.c (maybe_set_strlen_range): Return tree representing single-value ranges. Handle strnlen. (handle_builtin_strlen): Handle strnlen. (strlen_check_and_optimize_stmt): Same. * doc/extend.texi (Other Builtins): Document strnlen. gcc/testsuite/ChangeLog: PR tree-optimization/81384 * gcc.c-torture/execute/builtins/lib/strnlen.c: New test. * gcc.c-torture/execute/builtins/strnlen-lib.c: New test. * gcc.c-torture/execute/builtins/strnlen.c: New test. * gcc.dg/attr-nonstring-2.c: New test. * gcc.dg/attr-nonstring-3.c: New test. * gcc.dg/attr-nonstring-4.c: New test. * gcc.dg/strlenopt-45.c: New test. * gcc.dg/strlenopt.h (strnlen): Declare. From-SVN: r261705 --- gcc/testsuite/gcc.dg/strlenopt-45.c | 335 ++++++++++++++++++++++++++++++++++++ 1 file changed, 335 insertions(+) create mode 100644 gcc/testsuite/gcc.dg/strlenopt-45.c (limited to 'gcc/testsuite/gcc.dg/strlenopt-45.c') diff --git a/gcc/testsuite/gcc.dg/strlenopt-45.c b/gcc/testsuite/gcc.dg/strlenopt-45.c new file mode 100644 index 0000000..bd9b197 --- /dev/null +++ b/gcc/testsuite/gcc.dg/strlenopt-45.c @@ -0,0 +1,335 @@ +/* PR tree-optimization/81384 - built-in form of strnlen missing + Test to verify that strnlen built-in expansion works correctly + in the absence of tree strlen optimization. + { dg-do compile } + { dg-options "-O2 -Wall -fdump-tree-optimized" } */ + +#include "strlenopt.h" + +#define PTRDIFF_MAX __PTRDIFF_MAX__ +#define SIZE_MAX __SIZE_MAX__ + +typedef __SIZE_TYPE__ size_t; + +extern void abort (void); +extern size_t strnlen (const char *, size_t); + +#define CAT(x, y) x ## y +#define CONCAT(x, y) CAT (x, y) +#define FAILNAME(name) CONCAT (call_ ## name ##_on_line_, __LINE__) + +#define FAIL(name) do { \ + extern void FAILNAME (name) (void); \ + FAILNAME (name)(); \ + } while (0) + +/* Macro to emit a call to funcation named + call_in_true_branch_not_eliminated_on_line_NNN() + for each call that's expected to be eliminated. The dg-final + 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) + +extern char c; +extern char a1[1]; +extern char a3[3]; +extern char a5[5]; +extern char a3_7[3][7]; +extern char ax[]; + +void elim_strnlen_arr_cst (void) +{ + /* The length of a string stored in a one-element array must be zero. + The result reported by strnlen() for such an array can be non-zero + only when the bound is equal to 1 (in which case the result must + be one). */ + ELIM (strnlen (&c, 0) == 0); + ELIM (strnlen (&c, 1) < 2); + ELIM (strnlen (&c, 2) == 0); + ELIM (strnlen (&c, 9) == 0); + ELIM (strnlen (&c, PTRDIFF_MAX) == 0); + ELIM (strnlen (&c, SIZE_MAX) == 0); + ELIM (strnlen (&c, -1) == 0); + + ELIM (strnlen (a1, 0) == 0); + ELIM (strnlen (a1, 1) < 2); + ELIM (strnlen (a1, 2) == 0); + ELIM (strnlen (a1, 9) == 0); + ELIM (strnlen (a1, PTRDIFF_MAX) == 0); + ELIM (strnlen (a1, SIZE_MAX) == 0); + ELIM (strnlen (a1, -1) == 0); + + ELIM (strnlen (a3, 0) == 0); + ELIM (strnlen (a3, 1) < 2); + ELIM (strnlen (a3, 2) < 3); + ELIM (strnlen (a3, 3) < 4); + ELIM (strnlen (a3, 9) < 4); + ELIM (strnlen (a3, PTRDIFF_MAX) < 4); + ELIM (strnlen (a3, SIZE_MAX) < 4); + ELIM (strnlen (a3, -1) < 4); + + ELIM (strnlen (a3_7[0], 0) == 0); + ELIM (strnlen (a3_7[0], 1) < 2); + ELIM (strnlen (a3_7[0], 2) < 3); + ELIM (strnlen (a3_7[0], 3) < 4); + ELIM (strnlen (a3_7[0], 9) < 8); + ELIM (strnlen (a3_7[0], PTRDIFF_MAX) < 8); + ELIM (strnlen (a3_7[0], SIZE_MAX) < 8); + ELIM (strnlen (a3_7[0], -1) < 8); + + ELIM (strnlen (a3_7[2], 0) == 0); + ELIM (strnlen (a3_7[2], 1) < 2); + ELIM (strnlen (a3_7[2], 2) < 3); + ELIM (strnlen (a3_7[2], 3) < 4); + ELIM (strnlen (a3_7[2], 9) < 8); + ELIM (strnlen (a3_7[2], PTRDIFF_MAX) < 8); + ELIM (strnlen (a3_7[2], SIZE_MAX) < 8); + ELIM (strnlen (a3_7[2], -1) < 8); + + ELIM (strnlen ((char*)a3_7, 0) == 0); + ELIM (strnlen ((char*)a3_7, 1) < 2); + ELIM (strnlen ((char*)a3_7, 2) < 3); + ELIM (strnlen ((char*)a3_7, 3) < 4); + ELIM (strnlen ((char*)a3_7, 9) < 10); + ELIM (strnlen ((char*)a3_7, 19) < 20); + ELIM (strnlen ((char*)a3_7, 21) < 22); + ELIM (strnlen ((char*)a3_7, 23) < 22); + ELIM (strnlen ((char*)a3_7, PTRDIFF_MAX) < 22); + ELIM (strnlen ((char*)a3_7, SIZE_MAX) < 22); + ELIM (strnlen ((char*)a3_7, -1) < 22); + + ELIM (strnlen (ax, 0) == 0); + ELIM (strnlen (ax, 1) < 2); + ELIM (strnlen (ax, 2) < 3); + ELIM (strnlen (ax, 9) < 10); + ELIM (strnlen (a3, PTRDIFF_MAX) <= PTRDIFF_MAX); + ELIM (strnlen (a3, SIZE_MAX) < PTRDIFF_MAX); + ELIM (strnlen (a3, -1) < PTRDIFF_MAX); +} + +struct MemArrays +{ + char c; + char a0[0]; + char a1[1]; + char a3[3]; + char a5[5]; + char a3_7[3][7]; + char ax[1]; +}; + +void elim_strnlen_memarr_cst (struct MemArrays *p, int i) +{ + ELIM (strnlen (&p->c, 0) == 0); + ELIM (strnlen (&p->c, 1) < 2); + ELIM (strnlen (&p->c, 9) == 0); + ELIM (strnlen (&p->c, PTRDIFF_MAX) == 0); + ELIM (strnlen (&p->c, SIZE_MAX) == 0); + ELIM (strnlen (&p->c, -1) == 0); + + /* Other accesses to internal zero-length arrays are undefined. */ + ELIM (strnlen (p->a0, 0) == 0); + + ELIM (strnlen (p->a1, 0) == 0); + ELIM (strnlen (p->a1, 1) < 2); + ELIM (strnlen (p->a1, 9) == 0); + ELIM (strnlen (p->a1, PTRDIFF_MAX) == 0); + ELIM (strnlen (p->a1, SIZE_MAX) == 0); + ELIM (strnlen (p->a1, -1) == 0); + + ELIM (strnlen (p->a3, 0) == 0); + ELIM (strnlen (p->a3, 1) < 2); + ELIM (strnlen (p->a3, 2) < 3); + ELIM (strnlen (p->a3, 3) < 4); + ELIM (strnlen (p->a3, 9) < 4); + ELIM (strnlen (p->a3, PTRDIFF_MAX) < 4); + ELIM (strnlen (p->a3, SIZE_MAX) < 4); + ELIM (strnlen (p->a3, -1) < 4); + + ELIM (strnlen (p[i].a3, 0) == 0); + ELIM (strnlen (p[i].a3, 1) < 2); + ELIM (strnlen (p[i].a3, 2) < 3); + ELIM (strnlen (p[i].a3, 3) < 4); + ELIM (strnlen (p[i].a3, 9) < 4); + ELIM (strnlen (p[i].a3, PTRDIFF_MAX) < 4); + ELIM (strnlen (p[i].a3, SIZE_MAX) < 4); + ELIM (strnlen (p[i].a3, -1) < 4); + + ELIM (strnlen (p->a3_7[0], 0) == 0); + ELIM (strnlen (p->a3_7[0], 1) < 2); + ELIM (strnlen (p->a3_7[0], 2) < 3); + ELIM (strnlen (p->a3_7[0], 3) < 4); + ELIM (strnlen (p->a3_7[0], 9) < 8); + ELIM (strnlen (p->a3_7[0], PTRDIFF_MAX) < 8); + ELIM (strnlen (p->a3_7[0], SIZE_MAX) < 8); + ELIM (strnlen (p->a3_7[0], -1) < 8); + + ELIM (strnlen (p->a3_7[2], 0) == 0); + ELIM (strnlen (p->a3_7[2], 1) < 2); + ELIM (strnlen (p->a3_7[2], 2) < 3); + ELIM (strnlen (p->a3_7[2], 3) < 4); + ELIM (strnlen (p->a3_7[2], 9) < 8); + ELIM (strnlen (p->a3_7[2], PTRDIFF_MAX) < 8); + ELIM (strnlen (p->a3_7[2], SIZE_MAX) < 8); + ELIM (strnlen (p->a3_7[2], -1) < 8); + + ELIM (strnlen (p->a3_7[i], 0) == 0); + ELIM (strnlen (p->a3_7[i], 1) < 2); + ELIM (strnlen (p->a3_7[i], 2) < 3); + ELIM (strnlen (p->a3_7[i], 3) < 4); + +#if 0 + /* This is tranformed into strnlen ((char*)p + offsetof (a3_7[i]), N) + which makes it impssible to determine the size of the array. */ + ELIM (strnlen (p->a3_7[i], 9) < 8); + ELIM (strnlen (p->a3_7[i], PTRDIFF_MAX) < 8); + ELIM (strnlen (p->a3_7[i], SIZE_MAX) < 8); + ELIM (strnlen (p->a3_7[i], -1) < 8); +#else + ELIM (strnlen (p->a3_7[i], 9) < 10); + ELIM (strnlen (p->a3_7[i], 19) < 20); +#endif + + ELIM (strnlen ((char*)p->a3_7, 0) == 0); + ELIM (strnlen ((char*)p->a3_7, 1) < 2); + ELIM (strnlen ((char*)p->a3_7, 2) < 3); + ELIM (strnlen ((char*)p->a3_7, 3) < 4); + ELIM (strnlen ((char*)p->a3_7, 9) < 10); + ELIM (strnlen ((char*)p->a3_7, 19) < 20); + ELIM (strnlen ((char*)p->a3_7, 21) < 22); + ELIM (strnlen ((char*)p->a3_7, 23) < 22); + ELIM (strnlen ((char*)p->a3_7, PTRDIFF_MAX) < 22); + ELIM (strnlen ((char*)p->a3_7, SIZE_MAX) < 22); + ELIM (strnlen ((char*)p->a3_7, -1) < 22); + + ELIM (strnlen (p->ax, 0) == 0); + ELIM (strnlen (p->ax, 1) < 2); + ELIM (strnlen (p->ax, 2) < 3); + ELIM (strnlen (p->ax, 9) < 10); + ELIM (strnlen (p->a3, PTRDIFF_MAX) <= PTRDIFF_MAX); + ELIM (strnlen (p->a3, SIZE_MAX) < PTRDIFF_MAX); + ELIM (strnlen (p->a3, -1) < PTRDIFF_MAX); +} + + +void elim_strnlen_str_cst (void) +{ + const char *s0 = ""; + const char *s1 = "1"; + const char *s3 = "123"; + + ELIM (strnlen (s0, 0) == 0); + ELIM (strnlen (s0, 1) == 0); + ELIM (strnlen (s0, 9) == 0); + ELIM (strnlen (s0, PTRDIFF_MAX) == 0); + ELIM (strnlen (s0, SIZE_MAX) == 0); + ELIM (strnlen (s0, -1) == 0); + + ELIM (strnlen (s1, 0) == 0); + ELIM (strnlen (s1, 1) == 1); + ELIM (strnlen (s1, 9) == 1); + ELIM (strnlen (s1, PTRDIFF_MAX) == 1); + ELIM (strnlen (s1, SIZE_MAX) == 1); + ELIM (strnlen (s1, -2) == 1); + + ELIM (strnlen (s3, 0) == 0); + ELIM (strnlen (s3, 1) == 1); + ELIM (strnlen (s3, 2) == 2); + ELIM (strnlen (s3, 3) == 3); + ELIM (strnlen (s3, 9) == 3); + ELIM (strnlen (s3, PTRDIFF_MAX) == 3); + ELIM (strnlen (s3, SIZE_MAX) == 3); + ELIM (strnlen (s3, -2) == 3); +} + +void elim_strnlen_range (char *s) +{ + const char *s0 = ""; + const char *s1 = "1"; + const char *s3 = "123"; + + size_t n_0_1 = (size_t)s & 1; + size_t n_0_2 = ((size_t)s & 3) < 3 ? ((size_t)s & 3) : 2; + size_t n_0_3 = (size_t)s & 3; + size_t n_1_2 = n_0_1 + 1; + + ELIM (strnlen (s0, n_0_1) == 0); + ELIM (strnlen (s0, n_0_2) == 0); + ELIM (strnlen (s0, n_1_2) == 0); + + ELIM (strnlen (s1, n_0_1) < 2); + ELIM (strnlen (s1, n_0_2) < 2); + ELIM (strnlen (s1, n_0_3) < 2); + + ELIM (strnlen (s1, n_1_2) > 0); + ELIM (strnlen (s1, n_1_2) < 2); + + ELIM (strnlen (s3, n_0_1) < 2); + ELIM (strnlen (s3, n_0_2) < 3); + ELIM (strnlen (s3, n_0_3) < 4); + + ELIM (strnlen (s3, n_1_2) > 0); + ELIM (strnlen (s3, n_1_2) < 4); +} + + +#line 1000 + +void keep_strnlen_arr_cst (void) +{ + KEEP (strnlen (&c, 1) == 0); + KEEP (strnlen (&c, 1) == 1); + + KEEP (strnlen (a1, 1) == 0); + KEEP (strnlen (a1, 1) == 1); + + KEEP (strnlen (ax, 9) < 9); +} + +struct FlexArrays +{ + char c; + char a0[0]; /* Access to internal zero-length arrays are undefined. */ + char a1[1]; +}; + +void keep_strnlen_memarr_cst (struct FlexArrays *p) +{ + KEEP (strnlen (&p->c, 1) == 0); + KEEP (strnlen (&p->c, 1) == 1); + +#if 0 + /* Accesses to internal zero-length arrays are undefined so avoid + exercising them. */ + KEEP (strnlen (p->a0, 1) == 0); + KEEP (strnlen (p->a0, 1) == 1); + KEEP (strnlen (p->a0, 9) < 9); +#endif + + KEEP (strnlen (p->a1, 1) == 0); + KEEP (strnlen (p->a1, 1) == 1); + + KEEP (strnlen (p->a1, 2) == 0); + KEEP (strnlen (p->a1, 2) == 1); + KEEP (strnlen (p->a1, 2) == 2); + + KEEP (strnlen (p->a1, 9) < 9); +} + +/* { dg-final { scan-tree-dump-times "call_in_true_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\]" 13 "optimized" } } + { dg-final { scan-tree-dump-times "call_made_in_false_branch_on_line_1\[0-9\]\[0-9\]\[0-9\]" 13 "optimized" } } */ -- cgit v1.1