Commit 27c14dbc by Martin Sebor Committed by Martin Sebor

PR tree-optimization/91996 - fold non-constant strlen relational expressions

gcc/testsuite/ChangeLog:

	PR tree-optimization/91996
	* gcc.dg/strlenopt-80.c: New test.
	* gcc.dg/strlenopt-81.c: New test.

gcc/ChangeLog:

	PR tree-optimization/91996
	* tree-ssa-strlen.c (maybe_warn_pointless_strcmp): Improve location
	information.
	(compare_nonzero_chars): Add an overload.
	(count_nonzero_bytes): Add an argument.  Call overload above.
	Handle non-constant lengths in some range.
	(handle_store): Add an argument.
	(check_and_optimize_stmt): Pass an argument to handle_store.

From-SVN: r277076
parent b7bfd3c5
2019-10-16 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91996
* tree-ssa-strlen.c (maybe_warn_pointless_strcmp): Improve location
information.
(compare_nonzero_chars): Add an overload.
(count_nonzero_bytes): Add an argument. Call overload above.
Handle non-constant lengths in some range.
(handle_store): Add an argument.
(check_and_optimize_stmt): Pass an argument to handle_store.
2019-10-16 Richard Earnshaw <rearnsha@arm.com> 2019-10-16 Richard Earnshaw <rearnsha@arm.com>
* config/arm/arm.c (neon_valid_immediate): Clear bytes before use. * config/arm/arm.c (neon_valid_immediate): Clear bytes before use.
......
2019-10-16 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91996
* gcc.dg/strlenopt-80.c: New test.
* gcc.dg/strlenopt-81.c: New test.
2019-10-16 Mihailo Stojanovic <mistojanovic@wavecomp.com> 2019-10-16 Mihailo Stojanovic <mistojanovic@wavecomp.com>
* gcc.target/mips/msa-dpadd-dpsub.c: New test. * gcc.target/mips/msa-dpadd-dpsub.c: New test.
......
/* PR tree-optimization/91996 - fold strlen relational expressions
The optimization is only implemented for MEM_REF stores and other
targets than those below may not transform the memcpy call into
such a store.
{ dg-do compile { target aarch64*-*-* i?86-*-* powerpc*-*-* x86_64-*-* } }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
#define CHAR_BIT __CHAR_BIT__
#define SIZE_MAX __SIZE_MAX__
#define LEN_MAX (__PTRDIFF_MAX__ - 2)
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
extern void* memcpy (void*, const void*, size_t);
extern size_t strlen (const char*);
#define CONCAT(a, b) a ## b
#define CAT(a, b) CONCAT (a, b)
extern void sink (void*, ...);
extern void failure_on_line (int);
extern char src[];
extern char dst[];
/* Copy (1 << NCPYLOG) bytes from an unknown string SRC with strlen (SRC)
in the range [MINSRCLEN, MAXSRCLEN] into DST + DSTOFF and verify that
strlen (DST + DSTOFF) is in the range [MINDSTLEN, MAXDSTLEN]. */
#define MIN_MAX(dst, dstoff, src, \
minsrclen, maxsrclen, mindstlen, maxdstlen, ncpylog) \
void CAT (test_on_line_, __LINE__) (void) \
{ \
size_t srclen = strlen (src); \
if ((minsrclen) <= srclen && srclen <= (maxsrclen)) { \
char *d = (dst) + (dstoff); \
memcpy (d, src, (size_t)1 << (ncpylog)); \
size_t dstlen = strlen (d); \
if (dstlen < (mindstlen) || (maxdstlen) < dstlen) \
{ \
failure_on_line (__LINE__); \
} \
sink (dst, src); \
} \
} typedef void dummy_type
// Verify the lower bound of the resulting strlen range.
#define MIN(dst, dstoff, src, minsrclen, mindstlen, ncpylog) \
MIN_MAX (dst, dstoff, src, minsrclen, LEN_MAX, mindstlen, LEN_MAX, ncpylog)
MIN (dst, 0, src, 2, 1, 0);
MIN (dst, 0, src, 3, 1, 0);
MIN (dst, 0, src, 3, 2, 1);
MIN (dst, 0, src, 3, 2, 2);
MIN (dst, 0, src, 3, 2, 3);
MIN (dst, 1, src, 2, 1, 0);
MIN (dst, 1, src, 3, 1, 0);
MIN (dst, 1, src, 3, 2, 1);
MIN (dst, 1, src, 3, 2, 2);
MIN (dst, 1, src, 3, 2, 3);
MIN (dst, 2, src, 2, 1, 0);
MIN (dst, 3, src, 3, 1, 0);
MIN (dst, 4, src, 3, 2, 1);
MIN (dst, 5, src, 3, 2, 2);
MIN (dst, 6, src, 3, 2, 3);
MIN (dst, 0, src, 5, 1, 0);
MIN (dst, 0, src, 5, 2, 1);
MIN (dst, 0, src, 5, 4, 2);
MIN (dst, 0, src, 5, 5, 3);
#if __aarch64__ || __x86_64__
/* Of the targets above only aarch64 and x86_64 transform memcpy calls
of (2 << 4) bytes into MEM_REF. */
MIN (dst, 0, src, 5, 5, 4);
#endif
MIN (dst, 11, src, 5, 1, 0);
MIN (dst, 22, src, 5, 2, 1);
MIN (dst, 33, src, 5, 4, 2);
MIN (dst, 44, src, 5, 5, 3);
#if __aarch64__ || __x86_64__
MIN (dst, 55, src, 5, 5, 4);
#endif
MIN (dst, 11, src, LEN_MAX, 1, 0);
MIN (dst, 22, src, LEN_MAX, 2, 1);
MIN (dst, 33, src, LEN_MAX, 4, 2);
MIN (dst, 44, src, LEN_MAX, 5, 3);
MIN (dst, 55, src, LEN_MAX, 5, 4);
MIN (dst, 66, src, LEN_MAX, 9, 8);
MIN (dst, 66, src, LEN_MAX, LEN_MAX, sizeof (ptrdiff_t) * CHAR_BIT - 1);
MIN_MAX (dst, 0, src, 3, 5, 1, LEN_MAX, 0);
MIN_MAX (dst, 0, src, 3, 5, 2, LEN_MAX, 1);
MIN_MAX (dst, 0, src, 3, 5, 3, LEN_MAX, 2);
/* Upper bound not implemented yet.
MIN_MAX (dst, 0, src, 3, 5, 3, 5, 3); */
/* { dg-final { scan-tree-dump-times "failure_on_line \\(" 0 "optimized" } } */
/* PR tree-optimization/ - fold strlen relational expressions
{ dg-do run }
{ dg-options "-O2 -Wall -Wno-unused-local-typedefs -fdump-tree-optimized" } */
typedef __SIZE_TYPE__ size_t;
#define NOIPA __attribute__ ((noipa))
#define CONCAT(a, b) a ## b
#define CAT(a, b) CONCAT (a, b)
/* Used in tests where EXPR is expected to be folded to false. */
#define ELIM(expr) \
if (expr) { \
extern void \
CAT (CAT (test_on_line_, __LINE__), _not_eliminated)(void); \
CAT (CAT (test_on_line_, __LINE__), _not_eliminated)(); \
} typedef void dummy_type
char a[32], b[32];
void init (void)
{
__builtin_strncpy (a, "abcdefgh", sizeof a);
__builtin_strncpy (b, "0123456789", sizeof b);
}
NOIPA void fail (const char *func)
{
__builtin_printf ("failure in %s\n", func);
__builtin_abort ();
}
NOIPA void test_global_cpy_4 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char *d = a;
__builtin_memcpy (d, b, 4);
size_t dlen = __builtin_strlen (d);
if (dlen != 8) // cannot be eliminated
fail ("test_global");
}
NOIPA void test_global_cpy_10 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char *d = a;
__builtin_memcpy (d, b, 10);
size_t dlen = __builtin_strlen (d);
if (dlen != 10) // cannot be eliminated
fail ("test_global_cpy_10");
}
NOIPA void test_global_cpy_11 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char *d = a;
__builtin_memcpy (d, b, 11);
size_t dlen = __builtin_strlen (d);
if (dlen != 10) // cannot be eliminated
fail ("test_global_cpy_11");
}
NOIPA void test_global_cpy_20 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char *d = a;
__builtin_memcpy (d, b, 20);
size_t dlen = __builtin_strlen (d);
if (dlen != 10) // cannot be eliminated
fail ("test_global_cpy_20");
}
NOIPA void test_local_cpy_4 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char a[10] = "abcdefgh";
char *d = a;
__builtin_memcpy (d, b, 4);
size_t dlen = __builtin_strlen (d);
ELIM (dlen != 8);
}
NOIPA void test_local_cpy_10 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char a[32] = "abcdefgh";
char *d = a;
__builtin_memcpy (d, b, 10);
/* B can be longer than 9 and A can initially be longer than 10
so the test below cannot be eliminated. */
size_t dlen = __builtin_strlen (d);
if (dlen != 10)
fail ("test_local_cpy_10");
}
NOIPA void test_local_cpy_11 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char a[32] = "abcdefgh";
char *d = a;
__builtin_memcpy (d, b, 11);
size_t dlen = __builtin_strlen (d);
if (dlen != 10)
fail ("test_global_cpy_20");
}
NOIPA void test_local_cpy_20 (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
char a[32] = "abcdefgh";
char *d = a;
__builtin_memcpy (d, b, 20);
size_t dlen = __builtin_strlen (d);
if (dlen != 10)
fail ("test_global_cpy_20");
}
NOIPA void test_global_length_eq (void)
{
size_t blen = __builtin_strlen (b);
if (blen != 10) return;
size_t alen = __builtin_strlen (a);
if (alen != 8) return;
char *d = a;
__builtin_memcpy (d, b, 4);
size_t dlen = __builtin_strlen (d);
ELIM (dlen != 8);
}
NOIPA void test_global_length_gt (void)
{
size_t blen = __builtin_strlen (b);
if (blen < 9) return;
size_t alen = __builtin_strlen (a);
if (alen < 8) return;
char *d = a;
__builtin_memcpy (d, b, 4);
size_t dlen = __builtin_strlen (d);
ELIM (dlen < 8);
}
#define TEST(name) do { init (); test_ ## name (); } while (0)
int main (void)
{
TEST (local_cpy_4);
TEST (local_cpy_10);
TEST (local_cpy_11);
TEST (local_cpy_20);
TEST (global_cpy_4);
TEST (global_cpy_10);
TEST (global_cpy_11);
TEST (global_cpy_20);
TEST (global_length_eq);
TEST (global_length_gt);
}
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