mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-20 09:20:42 +08:00
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
This commit is contained in:
parent
b1c0d18515
commit
34fcf41e30
@ -1,3 +1,9 @@
|
||||
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;
|
||||
}
|
||||
|
@ -1,3 +1,14 @@
|
||||
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");
|
||||
uint32_t x123_ = I32 ("123\0");
|
||||
uint32_t x12__ = I32 ("12\0\0");
|
||||
uint32_t x1___ = 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);
|
||||
// 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");
|
||||
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");
|
||||
|
||||
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);
|
||||
/* 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__
|
||||
|
133
gcc/testsuite/gcc.dg/strlenopt-73.c
Normal file
133
gcc/testsuite/gcc.dg/strlenopt-73.c
Normal file
@ -0,0 +1,133 @@
|
||||
/* 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" } } */
|
175
gcc/testsuite/gcc.dg/strlenopt-74.c
Normal file
175
gcc/testsuite/gcc.dg/strlenopt-74.c
Normal file
@ -0,0 +1,175 @@
|
||||
/* 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 ();
|
||||
}
|
||||
|
118
gcc/testsuite/gcc.dg/strlenopt-75.c
Normal file
118
gcc/testsuite/gcc.dg/strlenopt-75.c
Normal file
@ -0,0 +1,118 @@
|
||||
/* 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 ();
|
||||
}
|
174
gcc/testsuite/gcc.dg/strlenopt-76.c
Normal file
174
gcc/testsuite/gcc.dg/strlenopt-76.c
Normal file
@ -0,0 +1,174 @@
|
||||
/* 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 ();
|
||||
}
|
84
gcc/testsuite/gcc.dg/strlenopt-77.c
Normal file
84
gcc/testsuite/gcc.dg/strlenopt-77.c
Normal file
@ -0,0 +1,84 @@
|
||||
/* 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" } } */
|
@ -1195,14 +1195,13 @@ adjust_last_stmt (strinfo *si, gimple *stmt, bool is_strcat)
|
||||
to constants. */
|
||||
|
||||
tree
|
||||
set_strlen_range (tree lhs, wide_int max, tree bound /* = NULL_TREE */)
|
||||
set_strlen_range (tree lhs, wide_int min, wide_int max,
|
||||
tree bound /* = NULL_TREE */)
|
||||
{
|
||||
if (TREE_CODE (lhs) != SSA_NAME
|
||||
|| !INTEGRAL_TYPE_P (TREE_TYPE (lhs)))
|
||||
return NULL_TREE;
|
||||
|
||||
wide_int min = wi::zero (max.get_precision ());
|
||||
|
||||
if (bound)
|
||||
{
|
||||
/* For strnlen, adjust MIN and MAX as necessary. If the bound
|
||||
@ -1312,7 +1311,8 @@ maybe_set_strlen_range (tree lhs, tree src, tree bound)
|
||||
}
|
||||
}
|
||||
|
||||
return set_strlen_range (lhs, max, bound);
|
||||
wide_int min = wi::zero (max.get_precision ());
|
||||
return set_strlen_range (lhs, min, max, bound);
|
||||
}
|
||||
|
||||
/* Handle a strlen call. If strlen of the argument is known, replace
|
||||
@ -1434,6 +1434,12 @@ handle_builtin_strlen (gimple_stmt_iterator *gsi)
|
||||
tree adj = fold_build2_loc (loc, MINUS_EXPR,
|
||||
TREE_TYPE (lhs), lhs, old);
|
||||
adjust_related_strinfos (loc, si, adj);
|
||||
/* Use the constant minimim length as the lower bound
|
||||
of the non-constant length. */
|
||||
wide_int min = wi::to_wide (old);
|
||||
wide_int max
|
||||
= wi::to_wide (TYPE_MAX_VALUE (ptrdiff_type_node)) - 2;
|
||||
set_strlen_range (lhs, min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3386,9 +3392,51 @@ int ssa_name_limit_t::next_ssa_name (tree ssa_name)
|
||||
on success and false otherwise. */
|
||||
|
||||
static bool
|
||||
count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
count_nonzero_bytes (tree exp, unsigned HOST_WIDE_INT offset,
|
||||
unsigned HOST_WIDE_INT nbytes,
|
||||
unsigned lenrange[3], bool *nulterm,
|
||||
bool *allnul, bool *allnonnul, ssa_name_limit_t &snlim)
|
||||
{
|
||||
int idx = get_stridx (exp);
|
||||
if (idx > 0)
|
||||
{
|
||||
strinfo *si = get_strinfo (idx);
|
||||
/* FIXME: Handle non-constant lengths in some range. */
|
||||
if (!si || !tree_fits_shwi_p (si->nonzero_chars))
|
||||
return false;
|
||||
|
||||
unsigned len = tree_to_shwi (si->nonzero_chars);
|
||||
unsigned size = len + si->full_string_p;
|
||||
if (size <= offset)
|
||||
return false;
|
||||
|
||||
len -= offset;
|
||||
size -= offset;
|
||||
|
||||
if (size < nbytes)
|
||||
return false;
|
||||
|
||||
if (len < lenrange[0])
|
||||
lenrange[0] = len;
|
||||
if (lenrange[1] < len)
|
||||
lenrange[1] = len;
|
||||
|
||||
if (!si->full_string_p)
|
||||
*nulterm = false;
|
||||
|
||||
/* Since only the length of the string are known and
|
||||
its contents, clear ALLNUL and ALLNONNUL purely on
|
||||
the basis of the length. */
|
||||
if (len)
|
||||
*allnul = false;
|
||||
else
|
||||
*allnonnul = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (TREE_CODE (exp) == ADDR_EXPR)
|
||||
exp = TREE_OPERAND (exp, 0);
|
||||
|
||||
if (TREE_CODE (exp) == SSA_NAME)
|
||||
{
|
||||
/* Handle a single-character specially. */
|
||||
@ -3401,7 +3449,8 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
(even if its exact value is not known) and if so, recurse
|
||||
once to set the range, etc. */
|
||||
if (tree_expr_nonzero_p (exp))
|
||||
return count_nonzero_bytes (build_int_cst (type, 1), lenrange,
|
||||
return count_nonzero_bytes (build_int_cst (type, 1),
|
||||
offset, nbytes, lenrange,
|
||||
nulterm, allnul, allnonnul, snlim);
|
||||
/* Don't know whether EXP is or isn't nonzero. */
|
||||
return false;
|
||||
@ -3422,35 +3471,28 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
for (unsigned i = 0; i != n; i++)
|
||||
{
|
||||
tree def = gimple_phi_arg_def (stmt, i);
|
||||
if (!count_nonzero_bytes (def, lenrange, nulterm, allnul, allnonnul,
|
||||
snlim))
|
||||
if (!count_nonzero_bytes (def, offset, nbytes, lenrange, nulterm,
|
||||
allnul, allnonnul, snlim))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Offset from the beginning of the representation bytes, a pointer
|
||||
to the representation, and the number of bytes of the representation
|
||||
to consider (may be less than the object size for MEM_REF). */
|
||||
unsigned HOST_WIDE_INT offset = 0;
|
||||
const char *prep = NULL;
|
||||
unsigned nbytes = 0;
|
||||
|
||||
if (TREE_CODE (exp) == MEM_REF)
|
||||
{
|
||||
/* If the MEM_REF operand is the address of an object such as
|
||||
a string or integer, extract it and the offset into it. */
|
||||
tree arg = TREE_OPERAND (exp, 0);
|
||||
if (TREE_CODE (arg) != ADDR_EXPR)
|
||||
return false;
|
||||
|
||||
tree off = TREE_OPERAND (exp, 1);
|
||||
|
||||
if (TREE_CODE (off) != INTEGER_CST
|
||||
|| !tree_fits_uhwi_p (off))
|
||||
return false;
|
||||
|
||||
offset = tree_to_uhwi (off);
|
||||
unsigned HOST_WIDE_INT wioff = tree_to_uhwi (off);
|
||||
if (INT_MAX < wioff)
|
||||
return false;
|
||||
|
||||
offset += wioff;
|
||||
if (INT_MAX < offset)
|
||||
return false;
|
||||
|
||||
@ -3458,38 +3500,12 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
tree type = TREE_TYPE (exp);
|
||||
if (tree typesize = TYPE_SIZE_UNIT (type))
|
||||
nbytes = tree_to_uhwi (typesize);
|
||||
else
|
||||
return false;
|
||||
|
||||
if (offset == 0 && TREE_CODE (exp) != STRING_CST)
|
||||
{
|
||||
int idx = get_stridx (arg);
|
||||
if (idx > 0)
|
||||
{
|
||||
strinfo *si = get_strinfo (idx);
|
||||
if (si && tree_fits_shwi_p (si->nonzero_chars))
|
||||
{
|
||||
unsigned len = tree_to_shwi (si->nonzero_chars);
|
||||
if (len < lenrange[0])
|
||||
lenrange[0] = len;
|
||||
if (lenrange[1] < len)
|
||||
lenrange[1] = len;
|
||||
|
||||
if (!si->full_string_p)
|
||||
*nulterm = false;
|
||||
|
||||
/* Since only the length of the string are known and
|
||||
its contents, clear ALLNUL and ALLNONNUL purely on
|
||||
the basis of the length. */
|
||||
if (len)
|
||||
*allnul = false;
|
||||
else
|
||||
*allnonnul = false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Proceed to extract the object representation below. */
|
||||
exp = TREE_OPERAND (arg, 0);
|
||||
/* Handle MEM_REF = SSA_NAME types of assignments. */
|
||||
return count_nonzero_bytes (arg, offset, nbytes, lenrange, nulterm,
|
||||
allnul, allnonnul, snlim);
|
||||
}
|
||||
|
||||
if (TREE_CODE (exp) == VAR_DECL && TREE_READONLY (exp))
|
||||
@ -3499,20 +3515,18 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *prep = NULL;
|
||||
if (TREE_CODE (exp) == STRING_CST)
|
||||
{
|
||||
/* Set PREP and NBYTES to the string representation. */
|
||||
gcc_assert (offset <= INT_MAX);
|
||||
unsigned nchars = TREE_STRING_LENGTH (exp);
|
||||
if (nchars < offset)
|
||||
return false;
|
||||
|
||||
if (!nbytes)
|
||||
{
|
||||
/* Unless NBYTES has already been determined above from
|
||||
MEM_REF, set it here. It includes all internal nuls,
|
||||
including the terminating one if the string has one. */
|
||||
nbytes = TREE_STRING_LENGTH (exp);
|
||||
if (nbytes <= offset)
|
||||
return false;
|
||||
}
|
||||
/* If NBYTES hasn't been determined earlier from MEM_REF,
|
||||
set it here. It includes all internal nuls, including
|
||||
the terminating one if the string has one. */
|
||||
nbytes = nchars - offset;
|
||||
|
||||
prep = TREE_STRING_POINTER (exp) + offset;
|
||||
}
|
||||
@ -3520,12 +3534,14 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
unsigned char buf[256];
|
||||
if (!prep)
|
||||
{
|
||||
/* Try to extract the representation of the constant object. */
|
||||
nbytes = native_encode_expr (exp, buf, sizeof buf, -1);
|
||||
/* If the pointer to representation hasn't been set above
|
||||
for STRING_CST point it at the buffer. */
|
||||
prep = reinterpret_cast <char *>(buf);
|
||||
/* Try to extract the representation of the constant object
|
||||
or expression starting from the offset. */
|
||||
nbytes = native_encode_expr (exp, buf, sizeof buf, offset);
|
||||
if (!nbytes)
|
||||
return false;
|
||||
|
||||
prep = reinterpret_cast <char *>(buf);
|
||||
}
|
||||
|
||||
/* Compute the number of leading nonzero bytes in the representation
|
||||
@ -3591,7 +3607,8 @@ count_nonzero_bytes (tree exp, unsigned lenrange[3], bool *nulterm,
|
||||
*allnonnul = true;
|
||||
|
||||
ssa_name_limit_t snlim;
|
||||
return count_nonzero_bytes (exp, lenrange, nulterm, allnul, allnonnul, snlim);
|
||||
return count_nonzero_bytes (exp, 0, 0, lenrange, nulterm, allnul, allnonnul,
|
||||
snlim);
|
||||
}
|
||||
|
||||
/* Handle a single or multibyte store other than by a built-in function,
|
||||
@ -3664,11 +3681,14 @@ handle_store (gimple_stmt_iterator *gsi)
|
||||
|
||||
if (tree dstsize = compute_objsize (lhs, 1))
|
||||
if (compare_tree_int (dstsize, lenrange[2]) < 0)
|
||||
warning_n (gimple_location (stmt), OPT_Wstringop_overflow_,
|
||||
lenrange[2],
|
||||
"%Gwriting %u byte into a region of size %E",
|
||||
"%Gwriting %u bytes into a region of size %E",
|
||||
stmt, lenrange[2], dstsize);
|
||||
{
|
||||
location_t loc = gimple_nonartificial_location (stmt);
|
||||
warning_n (loc, OPT_Wstringop_overflow_,
|
||||
lenrange[2],
|
||||
"%Gwriting %u byte into a region of size %E",
|
||||
"%Gwriting %u bytes into a region of size %E",
|
||||
stmt, lenrange[2], dstsize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -3795,7 +3815,14 @@ handle_store (gimple_stmt_iterator *gsi)
|
||||
}
|
||||
else
|
||||
si->nonzero_chars = build_int_cst (size_type_node, offset);
|
||||
si->full_string_p = full_string_p;
|
||||
|
||||
/* Set FULL_STRING_P only if the length of the strings being
|
||||
written is the same, and clear it if the strings have
|
||||
different lengths. In the latter case the length stored
|
||||
in si->NONZERO_CHARS becomes the lower bound.
|
||||
FIXME: Handle the upper bound of the length if possible. */
|
||||
si->full_string_p = full_string_p && lenrange[0] == lenrange[1];
|
||||
|
||||
if (storing_all_zeros_p
|
||||
&& ssaname
|
||||
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
|
||||
@ -3825,10 +3852,23 @@ handle_store (gimple_stmt_iterator *gsi)
|
||||
if (idx != 0)
|
||||
{
|
||||
tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs));
|
||||
HOST_WIDE_INT slen = (storing_all_zeros_p
|
||||
? 0
|
||||
: (storing_nonzero_p
|
||||
&& ranges_valid ? lenrange[0] : -1));
|
||||
|
||||
HOST_WIDE_INT slen;
|
||||
if (storing_all_zeros_p)
|
||||
slen = 0;
|
||||
else if (storing_nonzero_p && ranges_valid)
|
||||
{
|
||||
/* FIXME: Handle the upper bound of the length when
|
||||
LENRANGE[0] != LENRANGE[1]. */
|
||||
slen = lenrange[0];
|
||||
if (lenrange[0] != lenrange[1])
|
||||
/* Set the minimum length but ignore the maximum
|
||||
for now. */
|
||||
full_string_p = false;
|
||||
}
|
||||
else
|
||||
slen = -1;
|
||||
|
||||
tree len = (slen <= 0
|
||||
? size_zero_node
|
||||
: build_int_cst (size_type_node, slen));
|
||||
|
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user