mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-22 00:01:10 +08:00
PR tree-optimization/92765 - wrong code for strcmp of a union member
gcc/ChangeLog: PR tree-optimization/92765 * gimple-fold.c (get_range_strlen_tree): Handle MEM_REF and PARM_DECL. * tree-ssa-strlen.c (compute_string_length): Remove. (determine_min_objsize): Remove. (get_len_or_size): Add an argument. Call get_range_strlen_dynamic. Avoid using type size as the upper bound on string length. (handle_builtin_string_cmp): Add an argument. Adjust. (strlen_check_and_optimize_call): Pass additional argument to handle_builtin_string_cmp. gcc/testsuite/ChangeLog: PR tree-optimization/92765 * g++.dg/tree-ssa/strlenopt-1.C: New test. * g++.dg/tree-ssa/strlenopt-2.C: New test. * gcc.dg/Warray-bounds-58.c: New test. * gcc.dg/Wrestrict-20.c: Avoid a valid -Wformat-overflow. * gcc.dg/Wstring-compare.c: Xfail a test. * gcc.dg/strcmpopt_2.c: Disable tests. * gcc.dg/strcmpopt_4.c: Adjust tests. * gcc.dg/strcmpopt_10.c: New test. * gcc.dg/strcmpopt_11.c: New test. * gcc.dg/strlenopt-69.c: Disable tests. * gcc.dg/strlenopt-92.c: New test. * gcc.dg/strlenopt-93.c: New test. * gcc.dg/strlenopt.h: Declare calloc. * gcc.dg/tree-ssa/pr92056.c: Xfail tests until pr93518 is resolved. * gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Correct test (pr93517).
This commit is contained in:
parent
f6bef09771
commit
e7868dc6a7
@ -1,3 +1,15 @@
|
||||
2020-02-05 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/92765
|
||||
* gimple-fold.c (get_range_strlen_tree): Handle MEM_REF and PARM_DECL.
|
||||
* tree-ssa-strlen.c (compute_string_length): Remove.
|
||||
(determine_min_objsize): Remove.
|
||||
(get_len_or_size): Add an argument. Call get_range_strlen_dynamic.
|
||||
Avoid using type size as the upper bound on string length.
|
||||
(handle_builtin_string_cmp): Add an argument. Adjust.
|
||||
(strlen_check_and_optimize_call): Pass additional argument to
|
||||
handle_builtin_string_cmp.
|
||||
|
||||
2020-02-05 Uroš Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* config/i386/i386.md (*pushdi2_rex64 peephole2): Remove.
|
||||
|
@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "calls.h"
|
||||
#include "tree-vector-builder.h"
|
||||
#include "tree-ssa-strlen.h"
|
||||
#include "varasm.h"
|
||||
|
||||
enum strlen_range_kind {
|
||||
/* Compute the exact constant string length. */
|
||||
@ -1280,7 +1281,7 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
|
||||
c_strlen_data *pdata, unsigned eltsize)
|
||||
{
|
||||
gcc_assert (TREE_CODE (arg) != SSA_NAME);
|
||||
|
||||
|
||||
/* The length computed by this invocation of the function. */
|
||||
tree val = NULL_TREE;
|
||||
|
||||
@ -1422,7 +1423,44 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
|
||||
type about the length here. */
|
||||
tight_bound = true;
|
||||
}
|
||||
else if (VAR_P (arg))
|
||||
else if (TREE_CODE (arg) == MEM_REF
|
||||
&& TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE
|
||||
&& TREE_CODE (TREE_TYPE (TREE_TYPE (arg))) == INTEGER_TYPE
|
||||
&& TREE_CODE (TREE_OPERAND (arg, 0)) == ADDR_EXPR)
|
||||
{
|
||||
/* Handle a MEM_REF into a DECL accessing an array of integers,
|
||||
being conservative about references to extern structures with
|
||||
flexible array members that can be initialized to arbitrary
|
||||
numbers of elements as an extension (static structs are okay).
|
||||
FIXME: Make this less conservative -- see
|
||||
component_ref_size in tree.c. */
|
||||
tree ref = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
|
||||
if ((TREE_CODE (ref) == PARM_DECL || VAR_P (ref))
|
||||
&& (decl_binds_to_current_def_p (ref)
|
||||
|| !array_at_struct_end_p (arg)))
|
||||
{
|
||||
/* Fail if the offset is out of bounds. Such accesses
|
||||
should be diagnosed at some point. */
|
||||
val = DECL_SIZE_UNIT (ref);
|
||||
if (!val || integer_zerop (val))
|
||||
return false;
|
||||
|
||||
poly_offset_int psiz = wi::to_offset (val);
|
||||
poly_offset_int poff = mem_ref_offset (arg);
|
||||
if (known_le (psiz, poff))
|
||||
return false;
|
||||
|
||||
pdata->minlen = ssize_int (0);
|
||||
|
||||
/* Subtract the offset and one for the terminating nul. */
|
||||
psiz -= poff;
|
||||
psiz -= 1;
|
||||
val = wide_int_to_tree (TREE_TYPE (val), psiz);
|
||||
/* Since VAL reflects the size of a declared object
|
||||
rather the type of the access it is not a tight bound. */
|
||||
}
|
||||
}
|
||||
else if (TREE_CODE (arg) == PARM_DECL || VAR_P (arg))
|
||||
{
|
||||
/* Avoid handling pointers to arrays. GCC might misuse
|
||||
a pointer to an array of one bound to point to an array
|
||||
@ -1500,7 +1538,8 @@ get_range_strlen_tree (tree arg, bitmap *visited, strlen_range_kind rkind,
|
||||
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)))
|
||||
|| (TREE_CODE (base) != PARM_DECL && !VAR_P (base))
|
||||
|| !(val = DECL_SIZE_UNIT (base)))
|
||||
val = build_all_ones_cst (size_type_node);
|
||||
else
|
||||
{
|
||||
|
@ -1,3 +1,22 @@
|
||||
2020-02-05 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR tree-optimization/92765
|
||||
* g++.dg/tree-ssa/strlenopt-1.C: New test.
|
||||
* g++.dg/tree-ssa/strlenopt-2.C: New test.
|
||||
* gcc.dg/Warray-bounds-58.c: New test.
|
||||
* gcc.dg/Wrestrict-20.c: Avoid a valid -Wformat-overflow.
|
||||
* gcc.dg/Wstring-compare.c: Xfail a test.
|
||||
* gcc.dg/strcmpopt_2.c: Disable tests.
|
||||
* gcc.dg/strcmpopt_4.c: Adjust tests.
|
||||
* gcc.dg/strcmpopt_10.c: New test.
|
||||
* gcc.dg/strcmpopt_11.c: New test.
|
||||
* gcc.dg/strlenopt-69.c: Disable tests.
|
||||
* gcc.dg/strlenopt-92.c: New test.
|
||||
* gcc.dg/strlenopt-93.c: New test.
|
||||
* gcc.dg/strlenopt.h: Declare calloc.
|
||||
* gcc.dg/tree-ssa/pr92056.c: Xfail tests until pr93518 is resolved.
|
||||
* gcc.dg/tree-ssa/builtin-sprintf-warn-23.c: Correct test (pr93517).
|
||||
|
||||
2020-02-05 Marek Polacek <polacek@redhat.com>
|
||||
|
||||
PR c++/93559 - ICE with CONSTRUCTOR flags verification.
|
||||
|
42
gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C
Normal file
42
gcc/testsuite/g++.dg/tree-ssa/strlenopt-1.C
Normal file
@ -0,0 +1,42 @@
|
||||
/* PR tree-optimization/92765 - wrong code for strcmp of a union member
|
||||
{ dg-do run }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
inline void* operator new (size_t, void *p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
struct A { char a2[2]; };
|
||||
struct B { char a4[4]; };
|
||||
|
||||
__attribute__((noipa)) void
|
||||
sink (void*) { }
|
||||
|
||||
__attribute__((noipa)) void
|
||||
copy (char *d, const char *s)
|
||||
{
|
||||
while ((*d++ = *s++));
|
||||
}
|
||||
|
||||
__attribute__((noipa)) void
|
||||
store_and_compare (void *p)
|
||||
{
|
||||
A *a = new (p) A;
|
||||
sink (a->a2);
|
||||
|
||||
B *b = new (p) B;
|
||||
char *q = (char *) b->a4;
|
||||
copy (q, "abc");
|
||||
|
||||
if (__builtin_strcmp (q, "abc"))
|
||||
__builtin_abort ();
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
char a [sizeof (A) > sizeof (B) ? sizeof (A) : sizeof (B)];
|
||||
store_and_compare (a);
|
||||
}
|
56
gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C
Normal file
56
gcc/testsuite/g++.dg/tree-ssa/strlenopt-2.C
Normal file
@ -0,0 +1,56 @@
|
||||
/* PR tree-optimization/92765 - wrong code for strcmp of a union member
|
||||
{ dg-do run }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
inline void* operator new (size_t, void *p)
|
||||
{
|
||||
return p;
|
||||
}
|
||||
|
||||
struct A
|
||||
{
|
||||
char a[2]; char b[2]; char c[2];
|
||||
A () { a[0] = 0; b[0] = 0; c[0] = 0; };
|
||||
~A () { }
|
||||
};
|
||||
|
||||
struct B
|
||||
{
|
||||
char d[6];
|
||||
B () { d[0] = 0; d[2] = 0; }
|
||||
~B () { }
|
||||
};
|
||||
|
||||
__attribute__((noipa)) void
|
||||
sink (void *) { }
|
||||
|
||||
__attribute__((noipa)) void
|
||||
copy (char *d, const char *s)
|
||||
{
|
||||
while ((*d++ = *s++));
|
||||
}
|
||||
|
||||
__attribute__((noipa)) void
|
||||
store_and_compare (void *p)
|
||||
{
|
||||
A *a = new (p) A ();
|
||||
sink (&a->b);
|
||||
a->~A ();
|
||||
|
||||
B *b = new (p) B ();
|
||||
char *q = &b->d[2];
|
||||
copy (q, "abc");
|
||||
|
||||
if (__builtin_strcmp (q, "abc"))
|
||||
__builtin_abort ();
|
||||
b->~B ();
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
char a [sizeof (A) > sizeof (B) ? sizeof (A) : sizeof (B)];
|
||||
store_and_compare (a);
|
||||
return 0;
|
||||
}
|
81
gcc/testsuite/gcc.dg/Warray-bounds-58.c
Normal file
81
gcc/testsuite/gcc.dg/Warray-bounds-58.c
Normal file
@ -0,0 +1,81 @@
|
||||
/* { dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
extern size_t strlen (const char*);
|
||||
|
||||
void sink (size_t);
|
||||
|
||||
struct A0 { char i, a[0]; };
|
||||
|
||||
extern struct A0 ea0;
|
||||
|
||||
void fa0_extern (void)
|
||||
{
|
||||
sink (strlen (ea0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ea0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ea0.a)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ea0.a + 1)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static struct A0 sa0 = { 0 };
|
||||
|
||||
void fa0_static (void)
|
||||
{
|
||||
sink (strlen (sa0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (sa0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (sa0.a)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (sa0.a + 1)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
|
||||
struct Ax { char i, a[]; };
|
||||
|
||||
extern struct Ax ax;
|
||||
|
||||
void fax_extern (void)
|
||||
{
|
||||
sink (strlen (ax.a - 2)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax.a));
|
||||
sink (strlen (ax.a + 123));
|
||||
}
|
||||
|
||||
static struct Ax ax0 = { 0, { 0 } };
|
||||
static struct Ax ax1 = { 1, { 1, 0 } };
|
||||
static struct Ax ax2 = { 2, { 2, 1, 0 } };
|
||||
static struct Ax ax3 = { 3, { 3, 2, 1, 0 } };
|
||||
|
||||
void fax_static (void)
|
||||
{
|
||||
sink (strlen (ax0.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax0.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax0.a));
|
||||
sink (strlen (ax0.a + 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax0.a + 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
sink (strlen (ax1.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax1.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax1.a));
|
||||
sink (strlen (ax1.a + 1));
|
||||
sink (strlen (ax1.a + 2)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax1.a + 3)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
sink (strlen (ax2.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax2.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax2.a));
|
||||
sink (strlen (ax2.a + 1));
|
||||
sink (strlen (ax2.a + 2));
|
||||
sink (strlen (ax2.a + 3)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax2.a + 4)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
sink (strlen (ax3.a - 2)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
sink (strlen (ax3.a - 1)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax3.a));
|
||||
sink (strlen (ax3.a + 1));
|
||||
sink (strlen (ax3.a + 2));
|
||||
sink (strlen (ax3.a + 3));
|
||||
sink (strlen (ax3.a + 4)); // { dg-warning "\\\[-Warray-bounds" "pr93514" { xfail *-*-* } }
|
||||
sink (strlen (ax3.a + 5)); // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
@ -15,7 +15,7 @@ void test_warn (char *p)
|
||||
sprintf (a, "a=%s", a); /* { dg-warning "-Wrestrict" } */
|
||||
|
||||
p = a;
|
||||
char *q = p + 1;
|
||||
char *q = p + 3;
|
||||
sprintf (p, "a=%s", q); /* { dg-warning "-Wrestrict" } */
|
||||
}
|
||||
|
||||
@ -31,7 +31,7 @@ void test_nowarn_front_end (char *d)
|
||||
void test_nowarn_sprintf_pass (char *d)
|
||||
{
|
||||
char *q = d;
|
||||
|
||||
|
||||
sprintf (d, "p=%p", q);
|
||||
snprintf (d, 32, "p=%p", q);
|
||||
|
||||
|
@ -120,7 +120,8 @@ void strcmp_array_copy (void)
|
||||
|
||||
void strcmp_member_array_lit (const struct S *p)
|
||||
{
|
||||
T (p->a4, "1234"); // { dg-warning "length 4 and an array of size 4 " }
|
||||
// Not handled due to the fix for PR 92756.
|
||||
T (p->a4, "1234"); // { dg-warning "length 4 and an array of size 4 " "pr92765" { xfail *-*-* } }
|
||||
}
|
||||
|
||||
|
||||
|
130
gcc/testsuite/gcc.dg/strcmpopt_10.c
Normal file
130
gcc/testsuite/gcc.dg/strcmpopt_10.c
Normal file
@ -0,0 +1,130 @@
|
||||
/* Verify that strncmp equalities aren't eliminated when the trailing array
|
||||
type referenced by a member pointer is smaller than the string in cases
|
||||
when the pointer pointed to by the enclosing object references an object
|
||||
sufficiently large to store a string of equal length.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wextra -fdump-tree-optimized" } */
|
||||
|
||||
void init (void*);
|
||||
|
||||
struct A1 { char i, a[1]; };
|
||||
|
||||
void f1_arr (void)
|
||||
{
|
||||
char a[9];
|
||||
init (a);
|
||||
|
||||
struct A1 *p = (struct A1*)a;
|
||||
|
||||
if (__builtin_strncmp (p->a, "01234567", 8) == 0)
|
||||
{
|
||||
extern void array_test (void);
|
||||
array_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f1_ptr (void)
|
||||
{
|
||||
void *p;
|
||||
init (&p);
|
||||
|
||||
struct A1 *q = (struct A1*)p;
|
||||
|
||||
if (__builtin_strncmp (q->a, "0123456789", 10) == 0)
|
||||
{
|
||||
extern void pointer_test (void);
|
||||
pointer_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f1_struct (void)
|
||||
{
|
||||
struct { char a[9]; } b;
|
||||
init (&b);
|
||||
|
||||
struct A1 *p = (struct A1*)&b;
|
||||
|
||||
if (__builtin_strncmp (p->a, "01234567", 8) == 0)
|
||||
{
|
||||
extern void struct_test (void);
|
||||
struct_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f1_memptr (void)
|
||||
{
|
||||
struct { void *p; } b;
|
||||
init (&b);
|
||||
|
||||
struct A1 *p = (struct A1*)b.p;
|
||||
|
||||
if (__builtin_strncmp (p->a, "0123456789", 10) == 0)
|
||||
{
|
||||
extern void memptr_test (void);
|
||||
memptr_test ();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct A2 { char i, a[2]; };
|
||||
|
||||
void f2_arr (void)
|
||||
{
|
||||
char a[8];
|
||||
init (a);
|
||||
|
||||
struct A2 *p = (struct A2*)a;
|
||||
|
||||
if (__builtin_strncmp (p->a, "0123456", 7) == 0)
|
||||
{
|
||||
extern void array_test (void);
|
||||
array_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f2_ptr (void)
|
||||
{
|
||||
void *p;
|
||||
init (&p);
|
||||
|
||||
struct A2 *q = (struct A2*)p;
|
||||
|
||||
if (__builtin_strncmp (q->a, "0123456789", 10) == 0)
|
||||
{
|
||||
extern void pointer_test (void);
|
||||
pointer_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f2_struct (void)
|
||||
{
|
||||
struct { char a[8]; } b;
|
||||
init (&b);
|
||||
|
||||
struct A2 *p = (struct A2*)&b;
|
||||
|
||||
if (__builtin_strncmp (p->a, "0123456", 7) == 0)
|
||||
{
|
||||
extern void struct_test (void);
|
||||
struct_test ();
|
||||
}
|
||||
}
|
||||
|
||||
void f2_memptr (void)
|
||||
{
|
||||
struct { void *p; } b;
|
||||
init (&b);
|
||||
|
||||
struct A2 *p = (struct A2*)b.p;
|
||||
|
||||
if (__builtin_strncmp (p->a, "0123456789", 10) == 0)
|
||||
{
|
||||
extern void memptr_test (void);
|
||||
memptr_test ();
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "array_test" 2 "optimized" } }
|
||||
{ dg-final { scan-tree-dump-times "pointer_test" 2 "optimized" } }
|
||||
{ dg-final { scan-tree-dump-times "struct_test" 2 "optimized" } }
|
||||
{ dg-final { scan-tree-dump-times "memptr_test" 2 "optimized" } } */
|
16
gcc/testsuite/gcc.dg/strcmpopt_11.c
Normal file
16
gcc/testsuite/gcc.dg/strcmpopt_11.c
Normal file
@ -0,0 +1,16 @@
|
||||
/* Verify that strcmp doesn't make assumptions about the size of a weak
|
||||
symbol.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
/* An ordinary definition of A with more elements might be provided
|
||||
in another translation unit. Even though that would be undefined
|
||||
(the type of the actual definition must be the same as the type
|
||||
of the weak declaration) this test verifies that GCC doesn't rely
|
||||
on the size of this A for optimization (as a matter of QoI). */
|
||||
__attribute__ ((weak)) char a[3];
|
||||
|
||||
int cmp_a3_x (void)
|
||||
{
|
||||
return __builtin_strcmp (a, "1234567") == 0;
|
||||
}
|
@ -4,52 +4,53 @@
|
||||
char s[100] = {'a','b','c','d'};
|
||||
typedef struct { char s[8]; int x; } S;
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f1 (S *s)
|
||||
{
|
||||
return __builtin_strcmp (s->s, "abc") != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f1 (S *s)
|
||||
{
|
||||
/* Member arrays not handled due to the fix for PR 92765. */
|
||||
return 0; // __builtin_strcmp (s->s, "abc") != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f2 (void)
|
||||
{
|
||||
return __builtin_strcmp (s, "abc") != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f2 (void)
|
||||
{
|
||||
return __builtin_strcmp (s, "abc") != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f3 (S *s)
|
||||
{
|
||||
return __builtin_strcmp ("abc", s->s) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f3 (S *s)
|
||||
{
|
||||
return 0; // __builtin_strcmp ("abc", s->s) != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f4 (void)
|
||||
{
|
||||
return __builtin_strcmp ("abc", s) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f4 (void)
|
||||
{
|
||||
return __builtin_strcmp ("abc", s) != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f5 (S *s)
|
||||
{
|
||||
return __builtin_strncmp (s->s, "abc", 3) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f5 (S *s)
|
||||
{
|
||||
return 0; // __builtin_strncmp (s->s, "abc", 3) != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f6 (void)
|
||||
{
|
||||
return __builtin_strncmp (s, "abc", 2) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f6 (void)
|
||||
{
|
||||
return __builtin_strncmp (s, "abc", 2) != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f7 (S *s)
|
||||
{
|
||||
return __builtin_strncmp ("abc", s->s, 3) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f7 (S *s)
|
||||
{
|
||||
return 0; // __builtin_strncmp ("abc", s->s, 3) != 0;
|
||||
}
|
||||
|
||||
__attribute__ ((noinline)) int
|
||||
f8 (void)
|
||||
{
|
||||
return __builtin_strncmp ("abc", s, 2) != 0;
|
||||
__attribute__ ((noinline)) int
|
||||
f8 (void)
|
||||
{
|
||||
return __builtin_strncmp ("abc", s, 2) != 0;
|
||||
}
|
||||
|
||||
int main (void)
|
||||
@ -64,4 +65,4 @@ int main (void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 8 "strlen1" } } */
|
||||
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 4 "strlen1" } } */
|
||||
|
@ -2,15 +2,26 @@
|
||||
/* { dg-options "-O2 -fdump-tree-strlen" } */
|
||||
|
||||
typedef struct { char s[8]; int x; } S;
|
||||
|
||||
extern int max_i;
|
||||
|
||||
int
|
||||
f1 (S * s)
|
||||
{
|
||||
int result, i;
|
||||
for (i = 0; i < max_i; i++)
|
||||
result += __builtin_strcmp (s->s, "abc") != 0 ? 2 : 1;
|
||||
int f_param (S s)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < max_i; i++)
|
||||
result += __builtin_strcmp (s.s, "abc") != 0 ? 2 : 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 1 "strlen1" } } */
|
||||
|
||||
S s;
|
||||
|
||||
int f_object (void)
|
||||
{
|
||||
int result = 0;
|
||||
for (int i = 0; i < max_i; i++)
|
||||
result += __builtin_strcmp (s.s, "abc") != 0 ? 2 : 1;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "cmp_eq \\(" 2 "strlen1" } } */
|
||||
|
@ -35,6 +35,8 @@ void test_array_lit (void)
|
||||
|
||||
void test_memarray_lit (struct S *p)
|
||||
{
|
||||
#if 0
|
||||
/* Member arrays not handled due to the fix for PR 92765. */
|
||||
A (strcmp (p->a4, "1234"));
|
||||
A (strcmp (p->a4, "12345"));
|
||||
A (strcmp (p->a4, "123456"));
|
||||
@ -42,6 +44,7 @@ void test_memarray_lit (struct S *p)
|
||||
A (strcmp ("1234", p->a4));
|
||||
A (strcmp ("12345", p->a4));
|
||||
A (strcmp ("123456", p->a4));
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Verify that the equality of empty strings is folded. */
|
||||
|
58
gcc/testsuite/gcc.dg/strlenopt-92.c
Normal file
58
gcc/testsuite/gcc.dg/strlenopt-92.c
Normal file
@ -0,0 +1,58 @@
|
||||
/* PR tree-optimization/92765 - wrong code for strcmp of a union member
|
||||
{ dg-do run }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
#include "strlenopt.h"
|
||||
|
||||
__attribute__((noipa)) int
|
||||
copy (char *x, int y)
|
||||
{
|
||||
if (y == 0)
|
||||
strcpy (x, "abcd");
|
||||
return y;
|
||||
}
|
||||
|
||||
__attribute__((noipa)) char *
|
||||
alloc_2_copy_compare (int x)
|
||||
{
|
||||
char *p;
|
||||
if (x)
|
||||
p = malloc (4);
|
||||
else
|
||||
p = calloc (16, 1);
|
||||
|
||||
char *q = p + 2;
|
||||
if (copy (q, x))
|
||||
return p;
|
||||
|
||||
if (strcmp (q, "abcd") != 0)
|
||||
abort ();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
char a5[5], a6[6], a7[7];
|
||||
|
||||
__attribute__((noipa)) char *
|
||||
decl_3_copy_compare (int x)
|
||||
{
|
||||
char *p = x < 0 ? a5 : 0 < x ? a6 : a7;
|
||||
char *q = p + 1;
|
||||
if (copy (q, x))
|
||||
return p;
|
||||
|
||||
if (strcmp (q, "abcd") != 0)
|
||||
abort ();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
free (alloc_2_copy_compare (0));
|
||||
free (alloc_2_copy_compare (1));
|
||||
|
||||
decl_3_copy_compare (-1);
|
||||
decl_3_copy_compare (0);
|
||||
decl_3_copy_compare (1);
|
||||
}
|
71
gcc/testsuite/gcc.dg/strlenopt-93.c
Normal file
71
gcc/testsuite/gcc.dg/strlenopt-93.c
Normal file
@ -0,0 +1,71 @@
|
||||
/* Verify that strlen doesn't (inadvertently) use the size of an array
|
||||
of char pointers to put an upper bound on the length of the strings
|
||||
they point to.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -fdump-tree-optimized" } */
|
||||
|
||||
void eaa_test (void)
|
||||
{
|
||||
extern char eaa[4][4];
|
||||
|
||||
char (*p)[4] = eaa;
|
||||
|
||||
if (!*p)
|
||||
return;
|
||||
|
||||
/* The longest string stored in EAA is 15 characters. */
|
||||
if (__builtin_strlen (*p) > 14)
|
||||
{
|
||||
extern void eaa_ok (void);
|
||||
eaa_ok ();
|
||||
}
|
||||
|
||||
if (__builtin_strlen (*p) > 15)
|
||||
{
|
||||
extern void eaa_fail (void);
|
||||
eaa_fail ();
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "eaa_ok" 1 "optimized" } }
|
||||
{ dg-final { scan-tree-dump-not "eaa_fail" "optimized" } } */
|
||||
|
||||
|
||||
void epa_test (void)
|
||||
{
|
||||
extern char* epa[4];
|
||||
char **p = epa;
|
||||
|
||||
if (*p && __builtin_strlen (*p) > 123)
|
||||
{
|
||||
extern void epa_ok (void);
|
||||
epa_ok ();
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "epa_ok" 1 "optimized" } } */
|
||||
|
||||
|
||||
static char* spa[4];
|
||||
|
||||
void spa_test (void)
|
||||
{
|
||||
char **p = spa;
|
||||
|
||||
if (*p && __builtin_strlen (*p) > 123)
|
||||
{
|
||||
extern void spa_ok ();
|
||||
spa_ok ();
|
||||
}
|
||||
}
|
||||
|
||||
/* { dg-final { scan-tree-dump-times "spa_ok" 1 "optimized" } } */
|
||||
|
||||
|
||||
void sink (void*, ...);
|
||||
|
||||
void init (void)
|
||||
{
|
||||
/* Make believe even the static array SA may be non-zero. */
|
||||
sink (spa);
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#define NULL ((void *) 0)
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
extern void abort (void);
|
||||
void *calloc (size_t, size_t);
|
||||
void *malloc (size_t);
|
||||
void free (void *);
|
||||
char *strdup (const char *);
|
||||
|
@ -642,10 +642,22 @@ void test_multiple_overlap (int i)
|
||||
}
|
||||
|
||||
{
|
||||
char a[4]; /* { dg-message "declared here" } */
|
||||
char a[4];
|
||||
|
||||
/* There is no overlap here because the length of a3 is at most 1
|
||||
and a4 is necessarily the empty string. */
|
||||
char *d = a;
|
||||
char *a3 = a + 2;
|
||||
char *a4 = a + 3;
|
||||
|
||||
T (d, "%s%s", a3, a4);
|
||||
}
|
||||
|
||||
{
|
||||
char a[5]; /* { dg-message "declared here" } */
|
||||
|
||||
/* a3 and a4 may overlap the output. They will only not overlap
|
||||
it when a3 is empty, and a4 is at most chaeracter byte long. */
|
||||
it when a3 is empty, and a4 is at most 1 character long. */
|
||||
char *d = a;
|
||||
char *a3 = a + 2;
|
||||
char *a4 = a + 3;
|
||||
|
@ -1,8 +1,9 @@
|
||||
/* PR tree-optimization/92056 */
|
||||
/* { dg-do compile } */
|
||||
/* { dg-options "-O2 -fdump-tree-optimized" } */
|
||||
/* { dg-final { scan-tree-dump-times "return 1;" 2 "optimized" } } */
|
||||
/* { dg-final { scan-tree-dump-not "strcmp \\(" "optimized" } } */
|
||||
/* PR tree-optimization/92056
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -fdump-tree-optimized" }
|
||||
Xfailed until pr93518 is resolved.
|
||||
{ dg-final { scan-tree-dump-times "return 1;" 2 "optimized" { xfail *-*-* } } }
|
||||
{ dg-final { scan-tree-dump-not "strcmp \\(" "optimized" { xfail *-*-* } } } */
|
||||
|
||||
void bar (int, char *);
|
||||
|
||||
|
@ -327,7 +327,8 @@ get_next_strinfo (strinfo *si)
|
||||
/* Helper function for get_stridx. Return the strinfo index of the address
|
||||
of EXP, which is available in PTR if nonnull. If OFFSET_OUT, it is
|
||||
OK to return the index for some X <= &EXP and store &EXP - X in
|
||||
*OFFSET_OUT. When nonnull uses RVALS to determine range information. */
|
||||
*OFFSET_OUT. When RVALS is nonnull uses it to determine range
|
||||
information. */
|
||||
|
||||
static int
|
||||
get_addr_stridx (tree exp, tree ptr, unsigned HOST_WIDE_INT *offset_out,
|
||||
@ -4061,105 +4062,20 @@ handle_builtin_memcmp (gimple_stmt_iterator *gsi)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Given an index to the strinfo vector, compute the string length
|
||||
for the corresponding string. Return -1 when unknown. */
|
||||
|
||||
static HOST_WIDE_INT
|
||||
compute_string_length (int idx)
|
||||
{
|
||||
HOST_WIDE_INT string_leni = -1;
|
||||
gcc_assert (idx != 0);
|
||||
|
||||
if (idx < 0)
|
||||
return ~idx;
|
||||
|
||||
strinfo *si = get_strinfo (idx);
|
||||
if (si)
|
||||
{
|
||||
tree const_string_len = get_string_length (si);
|
||||
if (const_string_len && tree_fits_shwi_p (const_string_len))
|
||||
string_leni = tree_to_shwi (const_string_len);
|
||||
}
|
||||
|
||||
if (string_leni < 0)
|
||||
return -1;
|
||||
|
||||
return string_leni;
|
||||
}
|
||||
|
||||
/* Determine the minimum size of the object referenced by DEST expression
|
||||
which must have a pointer type.
|
||||
Return the minimum size of the object if successful or HWI_M1U when
|
||||
the size cannot be determined. */
|
||||
|
||||
static unsigned HOST_WIDE_INT
|
||||
determine_min_objsize (tree dest)
|
||||
{
|
||||
unsigned HOST_WIDE_INT size = 0;
|
||||
|
||||
init_object_sizes ();
|
||||
|
||||
if (compute_builtin_object_size (dest, 2, &size))
|
||||
return size;
|
||||
|
||||
/* Try to determine the size of the object through the RHS
|
||||
of the assign statement. */
|
||||
if (TREE_CODE (dest) == SSA_NAME)
|
||||
{
|
||||
gimple *stmt = SSA_NAME_DEF_STMT (dest);
|
||||
if (!is_gimple_assign (stmt))
|
||||
return HOST_WIDE_INT_M1U;
|
||||
|
||||
if (!gimple_assign_single_p (stmt)
|
||||
&& !gimple_assign_unary_nop_p (stmt))
|
||||
return HOST_WIDE_INT_M1U;
|
||||
|
||||
dest = gimple_assign_rhs1 (stmt);
|
||||
return determine_min_objsize (dest);
|
||||
}
|
||||
|
||||
/* Try to determine the size of the object from its type. */
|
||||
if (TREE_CODE (dest) != ADDR_EXPR)
|
||||
return HOST_WIDE_INT_M1U;
|
||||
|
||||
tree type = TREE_TYPE (dest);
|
||||
if (TREE_CODE (type) == POINTER_TYPE)
|
||||
type = TREE_TYPE (type);
|
||||
|
||||
type = TYPE_MAIN_VARIANT (type);
|
||||
|
||||
/* The size of a flexible array cannot be determined. Otherwise,
|
||||
for arrays with more than one element, return the size of its
|
||||
type. GCC itself misuses arrays of both zero and one elements
|
||||
as flexible array members so they are excluded as well. */
|
||||
if (TREE_CODE (type) != ARRAY_TYPE
|
||||
|| !array_at_struct_end_p (dest))
|
||||
{
|
||||
tree type_size = TYPE_SIZE_UNIT (type);
|
||||
if (type_size && TREE_CODE (type_size) == INTEGER_CST
|
||||
&& !integer_onep (type_size)
|
||||
&& !integer_zerop (type_size))
|
||||
return tree_to_uhwi (type_size);
|
||||
}
|
||||
|
||||
return HOST_WIDE_INT_M1U;
|
||||
}
|
||||
|
||||
/* Given strinfo IDX for ARG, set LENRNG[] to the range of lengths
|
||||
of the string(s) referenced by ARG if it can be determined.
|
||||
If the length cannot be determined, set *SIZE to the size of
|
||||
/* Given strinfo IDX for ARG, sets LENRNG[] to the range of lengths
|
||||
of the string(s) referenced by ARG if it can be determined.
|
||||
If the length cannot be determined, sets *SIZE to the size of
|
||||
the array the string is stored in, if any. If no such array is
|
||||
known, set *SIZE to -1. When the strings are nul-terminated set
|
||||
*NULTERM to true, otherwise to false. Return true on success. */
|
||||
known, sets *SIZE to -1. When the strings are nul-terminated sets
|
||||
*NULTERM to true, otherwise to false. When nonnull uses RVALS to
|
||||
determine range information. Returns true on success. */
|
||||
|
||||
static bool
|
||||
get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
|
||||
unsigned HOST_WIDE_INT *size, bool *nulterm)
|
||||
unsigned HOST_WIDE_INT *size, bool *nulterm,
|
||||
const vr_values *rvals)
|
||||
{
|
||||
/* Set so that both LEN and ~LEN are invalid lengths, i.e.,
|
||||
maximum possible length + 1. */
|
||||
lenrng[0] = lenrng[1] = HOST_WIDE_INT_MAX;
|
||||
|
||||
/* Invalidate. */
|
||||
*size = HOST_WIDE_INT_M1U;
|
||||
|
||||
if (idx < 0)
|
||||
@ -4168,13 +4084,18 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
|
||||
lenrng[0] = ~idx;
|
||||
lenrng[1] = lenrng[0];
|
||||
*nulterm = true;
|
||||
return true;
|
||||
}
|
||||
else if (idx == 0)
|
||||
; /* Handled below. */
|
||||
else if (strinfo *si = get_strinfo (idx))
|
||||
|
||||
/* Set so that both LEN and ~LEN are invalid lengths, i.e., maximum
|
||||
possible length + 1. */
|
||||
lenrng[0] = lenrng[1] = HOST_WIDE_INT_MAX;
|
||||
|
||||
if (strinfo *si = idx ? get_strinfo (idx) : NULL)
|
||||
{
|
||||
/* FIXME: Handle all this in_range_strlen_dynamic. */
|
||||
if (!si->nonzero_chars)
|
||||
arg = si->ptr;
|
||||
;
|
||||
else if (tree_fits_uhwi_p (si->nonzero_chars))
|
||||
{
|
||||
lenrng[0] = tree_to_uhwi (si->nonzero_chars);
|
||||
@ -4195,42 +4116,62 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
|
||||
*nulterm = si->full_string_p;
|
||||
}
|
||||
}
|
||||
else if (si->ptr)
|
||||
arg = si->ptr;
|
||||
}
|
||||
|
||||
if (lenrng[0] == HOST_WIDE_INT_MAX)
|
||||
if (lenrng[0] != HOST_WIDE_INT_MAX)
|
||||
return true;
|
||||
|
||||
/* Compute the minimum and maximum real or possible lengths. */
|
||||
c_strlen_data lendata = { };
|
||||
/* Set MAXBOUND to an arbitrary non-null non-integer node as a request
|
||||
to have it set to the length of the longest string in a PHI. */
|
||||
lendata.maxbound = arg;
|
||||
get_range_strlen_dynamic (arg, &lendata, rvals);
|
||||
|
||||
unsigned HOST_WIDE_INT maxbound = HOST_WIDE_INT_M1U;
|
||||
if (tree_fits_uhwi_p (lendata.maxbound)
|
||||
&& !integer_all_onesp (lendata.maxbound))
|
||||
maxbound = tree_to_uhwi (lendata.maxbound);
|
||||
|
||||
if (tree_fits_uhwi_p (lendata.minlen) && tree_fits_uhwi_p (lendata.maxlen))
|
||||
{
|
||||
/* Compute the minimum and maximum real or possible lengths. */
|
||||
c_strlen_data lendata = { };
|
||||
if (get_range_strlen (arg, &lendata, /* eltsize = */1))
|
||||
unsigned HOST_WIDE_INT minlen = tree_to_uhwi (lendata.minlen);
|
||||
unsigned HOST_WIDE_INT maxlen = tree_to_uhwi (lendata.maxlen);
|
||||
|
||||
/* The longest string in this data model. */
|
||||
const unsigned HOST_WIDE_INT lenmax
|
||||
= tree_to_uhwi (max_object_size ()) - 2;
|
||||
|
||||
if (maxbound == HOST_WIDE_INT_M1U)
|
||||
{
|
||||
if (tree_fits_shwi_p (lendata.maxlen) && !lendata.maxbound)
|
||||
{
|
||||
lenrng[0] = tree_to_shwi (lendata.minlen);
|
||||
lenrng[1] = tree_to_shwi (lendata.maxlen);
|
||||
*nulterm = true;
|
||||
}
|
||||
else if (lendata.maxbound && tree_fits_shwi_p (lendata.maxbound))
|
||||
{
|
||||
/* Set *SIZE to the conservative LENDATA.MAXBOUND which
|
||||
is a conservative estimate of the longest string based
|
||||
on the sizes of the arrays referenced by ARG. */
|
||||
*size = tree_to_uhwi (lendata.maxbound) + 1;
|
||||
*nulterm = false;
|
||||
}
|
||||
lenrng[0] = minlen;
|
||||
lenrng[1] = maxlen;
|
||||
*nulterm = minlen == maxlen;
|
||||
}
|
||||
else
|
||||
else if (maxlen < lenmax)
|
||||
{
|
||||
/* Set *SIZE to the size of the smallest object referenced
|
||||
by ARG if ARG denotes a single object, or to HWI_M1U
|
||||
otherwise. */
|
||||
*size = determine_min_objsize (arg);
|
||||
*size = maxbound + 1;
|
||||
*nulterm = false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return lenrng[0] != HOST_WIDE_INT_MAX || *size != HOST_WIDE_INT_M1U;
|
||||
if (maxbound != HOST_WIDE_INT_M1U
|
||||
&& lendata.maxlen
|
||||
&& !integer_all_onesp (lendata.maxlen))
|
||||
{
|
||||
/* Set *SIZE to LENDATA.MAXBOUND which is a conservative estimate
|
||||
of the longest string based on the sizes of the arrays referenced
|
||||
by ARG. */
|
||||
*size = maxbound + 1;
|
||||
*nulterm = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If IDX1 and IDX2 refer to strings A and B of unequal lengths, return
|
||||
@ -4245,15 +4186,15 @@ get_len_or_size (tree arg, int idx, unsigned HOST_WIDE_INT lenrng[2],
|
||||
static tree
|
||||
strxcmp_eqz_result (tree arg1, int idx1, tree arg2, int idx2,
|
||||
unsigned HOST_WIDE_INT bound, unsigned HOST_WIDE_INT len[2],
|
||||
unsigned HOST_WIDE_INT *psize)
|
||||
unsigned HOST_WIDE_INT *psize, const vr_values *rvals)
|
||||
{
|
||||
/* Determine the range the length of each string is in and whether it's
|
||||
known to be nul-terminated, or the size of the array it's stored in. */
|
||||
bool nul1, nul2;
|
||||
unsigned HOST_WIDE_INT siz1, siz2;
|
||||
unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
|
||||
if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1)
|
||||
|| !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2))
|
||||
if (!get_len_or_size (arg1, idx1, len1rng, &siz1, &nul1, rvals)
|
||||
|| !get_len_or_size (arg2, idx2, len2rng, &siz2, &nul2, rvals))
|
||||
return NULL_TREE;
|
||||
|
||||
/* BOUND is set to HWI_M1U for strcmp and less to strncmp, and LENiRNG
|
||||
@ -4405,7 +4346,7 @@ maybe_warn_pointless_strcmp (gimple *stmt, HOST_WIDE_INT bound,
|
||||
another and false otherwise. */
|
||||
|
||||
static bool
|
||||
handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
|
||||
handle_builtin_string_cmp (gimple_stmt_iterator *gsi, const vr_values *rvals)
|
||||
{
|
||||
gcall *stmt = as_a <gcall *> (gsi_stmt (*gsi));
|
||||
tree lhs = gimple_call_lhs (stmt);
|
||||
@ -4451,7 +4392,7 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
|
||||
or definitely unequal and if so, either fold the result to zero
|
||||
(when equal) or set the range of the result to ~[0, 0] otherwise. */
|
||||
if (tree eqz = strxcmp_eqz_result (arg1, idx1, arg2, idx2, bound,
|
||||
len, &siz))
|
||||
len, &siz, rvals))
|
||||
{
|
||||
if (integer_zerop (eqz))
|
||||
{
|
||||
@ -4482,26 +4423,31 @@ handle_builtin_string_cmp (gimple_stmt_iterator *gsi)
|
||||
HOST_WIDE_INT cstlen1 = -1, cstlen2 = -1;
|
||||
HOST_WIDE_INT arysiz1 = -1, arysiz2 = -1;
|
||||
|
||||
if (idx1)
|
||||
cstlen1 = compute_string_length (idx1);
|
||||
else
|
||||
arysiz1 = determine_min_objsize (arg1);
|
||||
{
|
||||
unsigned HOST_WIDE_INT len1rng[2], len2rng[2];
|
||||
unsigned HOST_WIDE_INT arsz1, arsz2;
|
||||
bool nulterm[2];
|
||||
|
||||
if (!get_len_or_size (arg1, idx1, len1rng, &arsz1, nulterm, rvals)
|
||||
|| !get_len_or_size (arg2, idx2, len2rng, &arsz2, nulterm + 1, rvals))
|
||||
return false;
|
||||
|
||||
if (len1rng[0] == len1rng[1] && len1rng[0] < HOST_WIDE_INT_MAX)
|
||||
cstlen1 = len1rng[0];
|
||||
else if (arsz1 < HOST_WIDE_INT_M1U)
|
||||
arysiz1 = arsz1;
|
||||
|
||||
if (len2rng[0] == len2rng[1] && len2rng[0] < HOST_WIDE_INT_MAX)
|
||||
cstlen2 = len2rng[0];
|
||||
else if (arsz2 < HOST_WIDE_INT_M1U)
|
||||
arysiz2 = arsz2;
|
||||
}
|
||||
|
||||
/* Bail if neither the string length nor the size of the array
|
||||
it is stored in can be determined. */
|
||||
if (cstlen1 < 0 && arysiz1 < 0)
|
||||
return false;
|
||||
|
||||
/* Repeat for the second argument. */
|
||||
if (idx2)
|
||||
cstlen2 = compute_string_length (idx2);
|
||||
else
|
||||
arysiz2 = determine_min_objsize (arg2);
|
||||
|
||||
if (cstlen2 < 0 && arysiz2 < 0)
|
||||
return false;
|
||||
|
||||
if (cstlen1 < 0 && cstlen2 < 0)
|
||||
if ((cstlen1 < 0 && arysiz1 < 0)
|
||||
|| (cstlen2 < 0 && arysiz2 < 0)
|
||||
|| (cstlen1 < 0 && cstlen2 < 0))
|
||||
return false;
|
||||
|
||||
if (cstlen1 >= 0)
|
||||
@ -5435,7 +5381,7 @@ strlen_check_and_optimize_call (gimple_stmt_iterator *gsi, bool *zero_write,
|
||||
break;
|
||||
case BUILT_IN_STRCMP:
|
||||
case BUILT_IN_STRNCMP:
|
||||
if (handle_builtin_string_cmp (gsi))
|
||||
if (handle_builtin_string_cmp (gsi, rvals))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
|
Loading…
x
Reference in New Issue
Block a user