Commit 34fcf41e by Martin Sebor Committed by Martin Sebor

PR tree-optimization/91294 - [10 Regression] wrong strlen result of a conditional with an offset

gcc/testsuite/ChangeLog:

	PR tree-optimization/91294
	* gcc.dg/strlenopt-44.c: Adjust tested result.
	* gcc.dg/strlenopt-70.c: Avoid exercising unimplemnted optimization.
	* gcc.dg/strlenopt-73.c: New test.
	* gcc.dg/strlenopt-74.c: New test.
	* gcc.dg/strlenopt-75.c: New test.
	* gcc.dg/strlenopt-76.c: New test.
	* gcc.dg/strlenopt-77.c: New test.

gcc/ChangeLog:

	PR tree-optimization/91294
	* tree-ssa-strlen.c (handle_store): Avoid treating lower bound of
	source length as exact.

From-SVN: r274486
parent b1c0d185
2019-08-14 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91294
* tree-ssa-strlen.c (handle_store): Avoid treating lower bound of
source length as exact.
2019-08-14 Christophe Lyon <christophe.lyon@linaro.org>
* doc/extend.texi: Add "noinit" attribute documentation.
......
......@@ -3726,7 +3726,7 @@ gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
/* Set the strlen() range to [0, MAXLEN]. */
if (tree lhs = gimple_call_lhs (stmt))
set_strlen_range (lhs, maxlen);
set_strlen_range (lhs, minlen, maxlen);
return false;
}
......
2019-08-14 Martin Sebor <msebor@redhat.com>
PR tree-optimization/91294
* gcc.dg/strlenopt-44.c: Adjust tested result.
* gcc.dg/strlenopt-70.c: Avoid exercising unimplemnted optimization.
* gcc.dg/strlenopt-73.c: New test.
* gcc.dg/strlenopt-74.c: New test.
* gcc.dg/strlenopt-75.c: New test.
* gcc.dg/strlenopt-76.c: New test.
* gcc.dg/strlenopt-77.c: New test.
2019-08-14 Jakub Jelinek <jakub@redhat.com>
Marek Polacek <polacek@redhat.com>
......
......@@ -83,7 +83,7 @@ void test_keep (void)
size_t uchar_max = (unsigned char)-1;
KEEP ("1", 0, UR (1, uchar_max + 1), 1);
KEEP ("1\0\3", 1, UR (1, 2), 1);
KEEP ("1\0\3", 1, UR (1, 2), 2);
}
/* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } }
......
......@@ -201,14 +201,17 @@ void store_32bit (volatile int i)
T ("xxx", uint32_t, 0, I32 ("\1\2\3\0"), == 3);
T ("xxx", uint32_t, 0, I32 ("\0\1\2\3"), == 0);
uint32_t x00332211 = I32 ("123\0");
uint32_t x00002211 = I32 ("12\0\0");
uint32_t x00000011 = I32 ("1\0\0\0");
T ("xxxx", uint32_t, 0, i ? x00332211 : x00002211, <= 3);
T ("xxxx", uint32_t, 0, i ? x00332211 : x00002211, >= 2);
T ("xxxx", uint32_t, 0, i ? x00332211 : x00000011, <= 3);
T ("xxxx", uint32_t, 0, i ? x00332211 : x00000011, >= 1);
uint32_t x123_ = I32 ("123\0");
uint32_t x12__ = I32 ("12\0\0");
uint32_t x1___ = I32 ("1\0\0\0");
// FIXME: Upper bound not implemented yet.
/* T ("xxxx", uint32_t, 0, i ? x123_ : x12__, <= 3); */
T ("xxxx", uint32_t, 0, i ? x123_ : x12__, >= 2);
T ("xxxx", uint32_t, 0, i ? x12__ : x123_, >= 2);
/* T ("xxxx", uint32_t, 0, i ? x123_ : x1___, <= 3); */
T ("xxxx", uint32_t, 0, i ? x123_ : x1___, >= 1);
T ("xxxx", uint32_t, 0, i ? x1___ : x123_, >= 1);
TX ("abcde", uint32_t, 0, i ? I32 ("1234") : I32 ("1235"), == 5);
TX ("abcde", uint32_t, 1, i ? I32 ("1234") : I32 ("1235"), == 5);
......@@ -220,7 +223,8 @@ void store_32bit (volatile int i)
TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("13\0\0"), == 5);
TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("123\0"), >= 5);
TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("123\0"), < 7);
/* FIXME: Upper bound not implemented yet. */
/* TX ("abcdef", uint32_t, 3, i ? I32 ("12\0\0") : I32 ("123\0"), < 7); */
}
void store_64bit (int i)
......@@ -246,17 +250,19 @@ void store_64bit (int i)
T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\5\6\0\0\0"), == 6);
T ("xxxxxxx", uint64_t, 0, I64 ("\1\2\3\4\5\6\7\0\0"), == 7);
uint64_t x7777777 = I64 ("\7\7\7\7\7\7\7");
uint64_t x666666 = I64 ("\6\6\6\6\6\6\0");
uint64_t x4444 = I64 ("\4\4\4\4\0\0\0");
uint64_t x3333 = I64 ("\3\3\3\3\0\0\0");
uint64_t x1 = I64 ("\1\0\0\0\0\0\0");
T ("x\0xxxxxx", uint64_t, 0, i ? x7777777 : x666666, <= 7);
T ("xx\0xxxxx", uint64_t, 0, i ? x7777777 : x666666, >= 6);
T ("xxx\0xxxx", uint64_t, 0, i ? x666666 : x1, <= 6);
T ("xxxx\0xxx", uint64_t, 0, i ? x666666 : x1, >= 1);
T ("xxxxxx\0x", uint64_t, 0, i ? x4444 : x3333, == 4);
uint64_t x7777777_ = I64 ("\7\7\7\7\7\7\7");
uint64_t x666666__ = I64 ("\6\6\6\6\6\6\0");
uint64_t x4444____ = I64 ("\4\4\4\4\0\0\0");
uint64_t x4343____ = I64 ("\4\3\4\3\0\0\0");
uint64_t x1_______ = I64 ("\1\0\0\0\0\0\0");
/* FIXME: Upper bound not implemented yet. */
/* T ("x\0xxxxxx", uint64_t, 0, i ? x7777777_ : x666666__, <= 7); */
T ("xx\0xxxxx", uint64_t, 0, i ? x7777777_ : x666666__, >= 6);
T ("xxx\0xxxx", uint64_t, 1, i ? x7777777_ : x666666__, >= 7);
/* T ("xxx\0xxxx", uint64_t, 0, i ? x666666__ : x1, <= 6); */
T ("xxxx\0xxx", uint64_t, 0, i ? x666666__ : x1_______, >= 1);
T ("xxxxxx\0x", uint64_t, 0, i ? x4444____ : x4343____, == 4);
}
#if __SIZEOF_INT128__
......
/* PR tree-optimization/91183 - strlen of a strcpy result with a conditional
source not folded
Test to verify that strlen can determine string lengths from stores
involving PHI nodes with distinct strings of the same length of at
least 16 bytes.
{ dg-do compile }
{ dg-options "-O2 -fdump-tree-optimized" }
On strictly aligned targets the consecutive char assignments used
by the test aren't merged. When they involve multiple trailing nuls
these assignments then defeat the strlen optimization as a result of
pr83821. When the bug is resolved the directive below can be removed.
{ dg-require-effective-target non_strict_align } */
#include "strlenopt.h"
#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)
/* Macros to emit a call to function named
call_failed_to_be_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 (not_eliminated); else (void)0
#define T(expect, N, ncpy, cond) do { \
char CONCAT (arr_, __LINE__)[N]; \
char *pa = CONCAT (arr_, __LINE__); \
memcpy (pa, cond, ncpy); \
ELIM (!(expect strlen (pa))); \
sink (pa); \
} while (0)
void sink (void*);
const char a32[33] = "0123456789abcdef0123456789abcdef";
const char b32[33] = "fedcba9876543210fedcba9876543210";
const char a16[33] = "0123456789abcdef";
const char b16[33] = "fedcba9876543210";
int i0, i1, i2;
void test_copy_cond_equal_length (void)
{
// The test below is represented as this:
// # iftmp.0_3 = PHI <&b16(2), &a16(3)>
// MEM <unsigned char[17]> [(char * {ref-all})&a]
// = MEM <unsigned char[17]> [(char * {ref-all})iftmp.0_3];
// _2 = strlen (&a);
T (16 ==, 17, 17, i0 ? a16 : b16);
T (16 ==, 17, 17, i0 ? a16 : b16);
T (15 ==, 17, 16, (i0 ? a16 : b16) + 1);
T (14 ==, 17, 15, (i0 ? a16 : b16) + 2);
T ( 0 ==, 17, 1, (i0 ? a16 : b16) + 16);
T (31 ==, 33, 32, (i0 ? a32 : b32) + 1);
T (30 ==, 33, 31, (i0 ? a32 : b32) + 2);
T (29 ==, 33, 30, (i0 ? a32 : b32) + 3);
T ( 1 ==, 33, 2, (i0 ? a32 : b32) + 31);
T ( 0 ==, 33, 1, (i0 ? a32 : b32) + 32);
}
const char a4[16] = "0123";
const char b4[16] = "3210";
void test_copy_cond_unequal_length_i64 (void)
{
T (2 <, 16, 8, i0 ? a4 + 1 : b4 + 0);
T (1 <, 16, 8, i0 ? a4 + 1 : b4 + 2);
T (0 <, 16, 8, i0 ? a4 + 1 : b4 + 3);
T (1 <, 16, 8, i0 ? a4 + 2 : b4 + 0);
T (1 <, 16, 8, i0 ? a4 + 2 : b4 + 1);
T (0 <, 16, 8, i0 ? a4 + 2 : b4 + 3);
}
#if __SIZEOF_INT128__ == 16
/* The following tests assume GCC transforms the memcpy calls into
int128_t assignments which it does only when int128_t is supported. */
const char a8[32] = "01234567";
const char b8[32] = "76543210";
void test_copy_cond_unequal_length_i128 (void)
{
T (6 <, 32, 16, i0 ? a8 + 1 : b8 + 0);
T (5 <, 32, 16, i0 ? a8 + 1 : b8 + 2);
T (4 <, 32, 16, i0 ? a8 + 1 : b8 + 3);
T (3 <, 32, 16, i0 ? a8 + 1 : b8 + 4);
T (2 <, 32, 16, i0 ? a8 + 1 : b8 + 5);
T (1 <, 32, 16, i0 ? a8 + 1 : b8 + 6);
T (0 <, 32, 16, i0 ? a8 + 1 : b8 + 7);
T (5 <, 32, 16, i0 ? a8 + 2 : b8 + 0);
T (5 <, 32, 16, i0 ? a8 + 2 : b8 + 1);
T (3 <, 32, 16, i0 ? a8 + 2 : b8 + 3);
T (2 <, 32, 16, i0 ? a8 + 2 : b8 + 4);
T (1 <, 32, 16, i0 ? a8 + 2 : b8 + 5);
T (0 <, 32, 16, i0 ? a8 + 2 : b8 + 6);
T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 0);
T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 1);
T (4 <, 32, 16, i0 ? a8 + 3 : b8 + 2);
T (3 <, 32, 16, i0 ? a8 + 3 : b8 + 4);
T (2 <, 32, 16, i0 ? a8 + 3 : b8 + 5);
T (1 <, 32, 16, i0 ? a8 + 3 : b8 + 6);
T (0 <, 32, 16, i0 ? a8 + 3 : b8 + 7);
T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 0);
T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 1);
T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 2);
T (3 <, 32, 16, i0 ? a8 + 4 : b8 + 3);
T (2 <, 32, 16, i0 ? a8 + 4 : b8 + 5);
T (1 <, 32, 16, i0 ? a8 + 4 : b8 + 6);
T (0 <, 32, 16, i0 ? a8 + 4 : b8 + 7);
}
#endif /* int128_t exists */
/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "_not_eliminated_" 0 "optimized" } } */
/* PR tree-optimization/91294 - wrong strlen result of a conditional with
an offset
{ dg-do run }
{ dg-options "-O2 -Wall" } */
#include "strlenopt.h"
#define NOIPA __attribute__ ((noclone, noinline, noipa))
#define CAT(a, b) a ## b
#define CONCAT(a, b) CAT (a, b)
#define UNIQ_NAME(name) CONCAT (name, __LINE__)
extern int last_line;
int nfails;
char buf[32];
#define VERIFY(expr, nbytes, expect) \
NOIPA void UNIQ_NAME (test_)(void) \
{ \
memcpy (buf, (expr), (nbytes)); \
const size_t len = strlen (buf); \
if (len != expect) \
{ \
++nfails; \
__builtin_printf ("line %i: strlen(%s) == %zu failed: " \
"got %zu\n", \
__LINE__ - 1000 + last_line + 2, \
#expr, (size_t)expect, \
len); \
} \
} typedef void DummyType
const char a8[12] = "01234567";
const char b8[12] = "76543210";
const char c4[12] = "0123";
int i0, i1 = 1, i2 = 2;
int last_line = __LINE__;
#line 1000
VERIFY (i0 ? (a8 + 0) : (b8 + 0), 9, 8);
VERIFY (i0 ? (a8 + 0) : (b8 + 1), 8, 7);
VERIFY (i0 ? (a8 + 0) : (b8 + 2), 8, 6);
VERIFY (i0 ? (a8 + 0) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 0) : (b8 + 3), 8, 5);
VERIFY (i0 ? (a8 + 0) : (b8 + 3), 7, 5);
VERIFY (i0 ? (a8 + 0) : (b8 + 3), 6, 5);
VERIFY (i0 ? (a8 + 0) : (b8 + 4), 8, 4);
VERIFY (i0 ? (a8 + 0) : (b8 + 4), 7, 4);
VERIFY (i0 ? (a8 + 0) : (b8 + 4), 6, 4);
VERIFY (i0 ? (a8 + 0) : (b8 + 4), 5, 4);
VERIFY (i0 ? (a8 + 0) : (b8 + 5), 7, 3);
VERIFY (i0 ? (a8 + 0) : (b8 + 5), 6, 3);
VERIFY (i0 ? (a8 + 0) : (b8 + 5), 5, 3);
VERIFY (i0 ? (a8 + 0) : (b8 + 5), 4, 3);
VERIFY (i0 ? (a8 + 0) : (b8 + 6), 3, 2);
VERIFY (i0 ? (a8 + 0) : (b8 + 7), 2, 1);
VERIFY (i0 ? (a8 + 1) : (b8 + 0), 8, 8);
VERIFY (i0 ? (a8 + 2) : (b8 + 0), 7, 7);
VERIFY (i0 ? (a8 + 1) : (b8 + 1), 8, 7);
VERIFY (i0 ? (a8 + 1) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 2) : (b8 + 1), 8, 7); // FAIL
VERIFY (i0 ? (a8 + 2) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 0) : (b8 + 0), 9, 8);
VERIFY (i0 ? (a8 + 0) : (b8 + 1), 8, 7);
VERIFY (i0 ? (a8 + 0) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 1) : (b8 + 0), 9, 8);
VERIFY (i0 ? (a8 + 2) : (b8 + 0), 9, 8);
VERIFY (i0 ? (a8 + 1) : (b8 + 1), 8, 7);
VERIFY (i0 ? (a8 + 1) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 2) : (b8 + 1), 8, 7); // FAIL
VERIFY (i0 ? (a8 + 2) : (b8 + 2), 7, 6);
VERIFY (i0 ? (a8 + 0) : (c4 + 0), 9, 4);
VERIFY (i0 ? (a8 + 0) : (c4 + 1), 9, 3);
VERIFY (i0 ? (a8 + 0) : (c4 + 3), 9, 1);
VERIFY (i0 ? (a8 + 0) : (c4 + 4), 9, 0);
VERIFY (i0 ? (a8 + 1) : (c4 + 0), 8, 4);
VERIFY (i0 ? (a8 + 1) : (c4 + 1), 8, 3);
VERIFY (i0 ? (a8 + 1) : (c4 + 2), 8, 2);
VERIFY (i0 ? (a8 + 1) : (c4 + 3), 8, 1);
VERIFY (i0 ? (a8 + 1) : (c4 + 4), 8, 0);
VERIFY (i0 ? (a8 + 2) : (c4 + 0), 8, 4);
VERIFY (i0 ? (a8 + 2) : (c4 + 1), 8, 3);
VERIFY (i0 ? (a8 + 2) : (c4 + 2), 8, 2);
VERIFY (i0 ? (a8 + 2) : (c4 + 3), 8, 1);
VERIFY (i0 ? (a8 + 2) : (c4 + 4), 8, 0);
VERIFY ((i0 ? a8 : b8) + 1, 8, 7);
VERIFY ((i0 ? a8 : b8) + 2, 8, 6);
VERIFY ((i0 ? a8 : b8) + 2, 7, 6);
VERIFY ((i0 ? a8 : b8) + 3, 3, 3);
VERIFY ((i0 ? a8 : b8) + 3, 1, 1);
VERIFY ((i0 ? a8 : c4) + 1, 8, 3);
VERIFY ((i0 ? a8 : c4) + 3, 8, 1);
VERIFY ((i0 ? a8 : c4) + 4, 8, 0);
VERIFY ((i0 ? a8 + 1: b8 + 2) + 1, 9, 5);
VERIFY ((i0 ? a8 + i1: b8 + i2) + 1, 8, 5);
VERIFY ((i0 ? a8 + i1: b8 + 2) + 1, 8, 5);
VERIFY ((i0 ? a8 + i2: b8 + i1) + 1, 8, 6);
VERIFY ((i0 ? a8 + 2: b8 + i1) + 1, 8, 6);
#define T(N) test_ ## N (); memset (buf, 0, sizeof buf)
int main (void)
{
T (1000);
T (1001);
T (1002);
T (1003);
T (1004);
T (1005);
T (1006);
T (1007);
T (1008);
T (1009);
T (1010);
T (1011);
T (1012);
T (1013);
T (1014);
T (1015);
T (1016);
T (1017);
T (1018);
T (1019);
T (1020);
T (1021);
T (1022);
T (1023);
T (1024);
T (1025);
T (1026);
T (1027);
T (1028);
T (1029);
T (1030);
T (1031);
T (1032);
T (1033);
T (1034);
T (1035);
T (1036);
T (1037);
T (1038);
T (1039);
T (1040);
T (1041);
T (1042);
T (1043);
T (1044);
T (1045);
T (1046);
T (1047);
T (1048);
T (1049);
T (1050);
T (1051);
T (1052);
T (1053);
T (1054);
T (1055);
T (1056);
T (1057);
T (1058);
if (nfails)
abort ();
}
/* PR tree-optimization/91294 - strlen result of a conditional with
an offset
{ dg-do run }
{ dg-options "-O2 -Wall" } */
#include "strlenopt.h"
#define NOIPA __attribute__ ((noclone, noinline, noipa))
int i = 0;
const char s[] = "1234567";
char a[32];
/* Exercise a memcpy overwriting a destination string of known length
with a source argument involving a conditional expression with strings
of unqual lengths, with the selected one being the longer of the two
and resulting in no change to the length of the overwritten destination
string. */
NOIPA void test_memcpy_same_length ()
{
memcpy (a, "123456789a", 11);
memcpy (a + 6, i ? "78\0" : "789\0", 4);
if (strlen (a) != 9)
abort ();
}
/* Same as above but with strcpy/strcat. */
NOIPA void test_strcpy_strcat_same_length ()
{
strcpy (a, "12345678");
strcat (a, "9a");
memcpy (a + 6, i ? "78\0" : "789\0", 4);
if (strlen (a) != 9)
abort ();
}
/* Same as above but using a memcpy of a power-of-two size that gets
(on some targets) transformed into a single MEM_REF assignment. */
NOIPA void test_assign_same_length ()
{
memcpy (a, s, 8);
memcpy (a + 5, i ? "67\0" : "678\0", 4);
if (strlen (a) != 8)
abort ();
}
/* Same as above but resulting in increasing the length of the destination
string. */
NOIPA void test_memcpy_lengthen ()
{
memcpy (a, "123456789a", 11);
memcpy (a + 8, i ? "9a\0" : "9ab\0", 4);
if (strlen (a) != 11)
abort ();
}
NOIPA void test_strcpy_strcat_lengthen ()
{
strcpy (a, "12345678");
strcat (a, "9a");
memcpy (a + 8, i ? "9a\0" : "9ab\0", 4);
if (strlen (a) != 11)
abort ();
}
NOIPA void test_assign_lengthen ()
{
memcpy (a, s, 8);
memcpy (a + 6, i ? "78\0" : "789\0", 4);
if (strlen (a) != 9)
abort ();
}
NOIPA void test_memcpy_shorten ()
{
memcpy (a, "123456789a", 11);
memcpy (a + 6, i ? "789\0" : "78\0", 4);
if (strlen (a) != 8)
abort ();
}
NOIPA void test_strcpy_strcat_shorten ()
{
strcpy (a, "12345678");
strcat (a, "9a");
memcpy (a + 6, i ? "789\0" : "78\0", 4);
if (strlen (a) != 8)
abort ();
}
NOIPA void test_assign_shorten ()
{
memcpy (a, s, 8);
memcpy (a + 6, i ? "789\0" : "78\0", 4);
if (strlen (a) != 8)
abort ();
}
int main (void)
{
test_memcpy_same_length ();
test_strcpy_strcat_same_length ();
test_assign_same_length ();
test_memcpy_lengthen ();
test_strcpy_strcat_lengthen ();
test_assign_lengthen ();
test_memcpy_shorten ();
test_strcpy_strcat_shorten ();
test_assign_shorten ();
}
/* PR tree-optimization/91294 - strlen result of a conditional with
an offset
{ dg-do run }
{ dg-options "-O2 -Wall" } */
#include "strlenopt.h"
#define NOIPA __attribute__ ((noclone, noinline, noipa))
#define assert(expr) \
((expr) \
? (void)0 \
: (__builtin_printf ("line %i %s: assertion failed: %s\n", \
__LINE__, __func__, #expr), \
__builtin_abort ()))
int i = 0;
const char s[] = "1234567";
char a[32];
NOIPA void lower_bound_assign_into_empty (void)
{
a[0] = '1';
a[1] = '2';
a[2] = '3';
assert (strlen (a) == 3);
}
NOIPA void lower_bound_assign_into_longest (void)
{
a[0] = '1';
a[1] = '2';
a[2] = '3';
assert (strlen (a) == 31);
}
NOIPA void lower_bound_assign_into_empty_idx_3 (int idx)
{
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[idx] = 'x';
assert (strlen (a) == 4);
}
NOIPA void lower_bound_assign_into_longest_idx_2 (int idx)
{
a[0] = '1';
a[1] = '2';
a[2] = '3';
a[idx] = '\0';
assert (strlen (a) == 2);
}
NOIPA void lower_bound_memcpy_into_empty (void)
{
memcpy (a, "123", 3);
assert (strlen (a) == 3);
}
NOIPA void lower_bound_memcpy_into_longest (void)
{
memcpy (a, "123", 3);
assert (strlen (a) == 31);
}
NOIPA void lower_bound_memcpy_memcpy_into_empty (void)
{
memcpy (a, "123", 3);
memcpy (a + 2, "345", 3);
assert (strlen (a) == 5);
}
NOIPA void lower_bound_memcpy_memcpy_into_longest (void)
{
memcpy (a, "123", 3);
memcpy (a + 2, "345", 3);
assert (strlen (a) == 31);
}
NOIPA void memove_forward_strlen (void)
{
char a[] = "123456";
memmove (a, a + 1, sizeof a - 1);
assert (strlen (a) == 5);
}
NOIPA void memove_backward_into_empty_strlen (void)
{
strcpy (a, "123456");
memmove (a + 1, a, 6);
assert (strlen (a) == 7);
}
NOIPA void memove_backward_into_longest_strlen (void)
{
memcpy (a, "123456", 6);
memmove (a + 1, a, 6);
assert (strlen (a) == 31);
}
NOIPA void memove_strcmp (void)
{
/* Test derived from libstdc++-v3's
20_util/specialized_algorithms/memory_management_tools/1.cc */
char a[] = "123456";
char b[] = "000000";
memmove (b, a, sizeof a);
assert (strlen (a) == 6);
assert (strlen (b) == 6);
assert (strcmp (a, b) == 0);
}
int main (void)
{
memset (a, '\0', sizeof a);
lower_bound_assign_into_empty ();
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
lower_bound_assign_into_longest ();
memset (a, '\0', sizeof a);
lower_bound_assign_into_empty_idx_3 (3);
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
lower_bound_assign_into_longest_idx_2 (2);
memset (a, '\0', sizeof a);
lower_bound_memcpy_into_empty ();
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
lower_bound_memcpy_into_longest ();
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
lower_bound_memcpy_into_longest ();
memset (a, '\0', sizeof a);
lower_bound_memcpy_memcpy_into_empty ();
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
lower_bound_memcpy_memcpy_into_longest ();
memove_forward_strlen ();
memset (a, '\0', sizeof a);
memove_backward_into_empty_strlen ();
memset (a, 'x', sizeof a - 1);
a[sizeof a - 1] = '\0';
memove_backward_into_longest_strlen ();
memove_strcmp ();
}
/* PR tree-optimization/91315 - missing strlen lower bound of a string
known to be at least N characters
{ dg-do compile }
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
#include "strlenopt.h"
#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 function 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 ASSERT_ELIM(expr) \
if (!!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
char a[32];
void lower_bound_assign_1 (void)
{
a[0] = '1';
ASSERT_ELIM (strlen (a) < 1);
}
void lower_bound_assign_2 (void)
{
a[0] = '1';
a[1] = '2';
ASSERT_ELIM (strlen (a) < 2);
}
void lower_bound_assign_3 (void)
{
a[0] = '1';
a[1] = '2';
a[2] = '3';
ASSERT_ELIM (strlen (a) < 3);
}
void lower_bound_memcpy (void)
{
memcpy (a, "123", 3);
ASSERT_ELIM (strlen (a) < 3);
}
void lower_bound_memcpy_memcpy_2 (void)
{
memcpy (a, "123", 3);
memcpy (a + 2, "345", 3);
ASSERT_ELIM (strlen (a) < 5);
}
void lower_bound_memcpy_memcpy_3 (void)
{
memcpy (a, "123", 3);
memcpy (a + 3, "456", 3);
ASSERT_ELIM (strlen (a) < 6);
}
/* FIXME: Not optimized yet.
void lower_bound_stpcpy_stpcpy_assign (void)
{
*stpcpy (strcpy (a, "123"), "4567") = '8';
ASSERT_ELIM (strlen (a) < 8);
}
*/
void lower_bound_strcpy_strcat_assign (void)
{
strcpy (a, "123");
strcat (a, "45");
a[5] = '6';
ASSERT_ELIM (strlen (a) < 6);
}
/* { dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated_" 0 "optimized" } } */
......@@ -23,6 +23,6 @@
extern bool is_strlen_related_p (tree, tree);
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
extern tree set_strlen_range (tree, wide_int, tree = NULL_TREE);
extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE);
#endif // GCC_TREE_SSA_STRLEN_H
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