Commit aca8570e by Martin Sebor Committed by Martin Sebor

PR tree-optimization/86043 - strlen after memcpy partially overwriting a string not optimized

PR tree-optimization/86043 - strlen after memcpy partially overwriting a string not optimized
PR tree-optimization/86042 - missing strlen optimization after second strcpy

gcc/ChangeLog:

	PR tree-optimization/86043
	PR tree-optimization/86042
	* tree-ssa-strlen.c (handle_builtin_memcpy): Handle strict overlaps.
	(get_string_cst_length): Rename...
	(get_min_string_length): ...to this.  Add argument.
	(handle_char_store): Extend to handle multi-character stores by
	MEM_REF.
	* tree.c (initializer_zerop): Use new argument.  Handle MEM_REF.
	* tree.h (initializer_zerop): Add argument.

gcc/testsuite/ChangeLog:

	PR tree-optimization/86043
	PR tree-optimization/86042
	* gcc/testsuite/gcc.dg/attr-nonstring-2.c: Xfail test cases due to
	pr86688.
	* gcc.dg/strlenopt-44.c: New test.

From-SVN: r263018
parent 4b8b1f59
2018-07-26 Martin Sebor <msebor@redhat.com>
PR tree-optimization/86043
PR tree-optimization/86042
* tree-ssa-strlen.c (handle_builtin_memcpy): Handle strict overlaps.
(get_string_cst_length): Rename...
(get_min_string_length): ...to this. Add argument.
(handle_char_store): Extend to handle multi-character stores by
MEM_REF.
* tree.c (initializer_zerop): Use new argument. Handle MEM_REF.
* tree.h (initializer_zerop): Add argument.
2018-07-26 Jakub Jelinek <jakub@redhat.com> 2018-07-26 Jakub Jelinek <jakub@redhat.com>
PR middle-end/86660 PR middle-end/86660
......
2018-07-26 Martin Sebor <msebor@redhat.com>
PR tree-optimization/86043
PR tree-optimization/86042
* gcc/testsuite/gcc.dg/attr-nonstring-2.c: Xfail test cases due to
pr86688.
* gcc.dg/strlenopt-44.c: New test.
2018-07-26 Martin Liska <mliska@suse.cz> 2018-07-26 Martin Liska <mliska@suse.cz>
PR gcov-profile/86536 PR gcov-profile/86536
......
...@@ -73,8 +73,8 @@ void test_strnlen_string_cst (void) ...@@ -73,8 +73,8 @@ void test_strnlen_string_cst (void)
T (3, "12", 3, 1); T (3, "12", 3, 1);
T (3, "12", 3, 9); T (3, "12", 3, 9);
T (3, "123", 3, 1); T (3, "123", 3, 1);
T (3, "123", 3, 4); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 4" } */ T (3, "123", 3, 4); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 4" "bug 86688" { xfail *-*-* } } */
T (3, "123", 3, 9); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 9" } */ T (3, "123", 3, 9); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound 9" "bug 86688" { xfail *-*-* } } */
T (5, "1", 2, 1); T (5, "1", 2, 1);
T (5, "1", 2, 2); T (5, "1", 2, 2);
...@@ -110,6 +110,6 @@ void test_strnlen_string_range (void) ...@@ -110,6 +110,6 @@ void test_strnlen_string_range (void)
{ {
T (3, "1", 2, UR (0, 1)); T (3, "1", 2, UR (0, 1));
T (3, "1", 2, UR (3, 9)); T (3, "1", 2, UR (3, 9));
T (3, "123", 3, UR (4, 5)); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[4, 5]" } */ T (3, "123", 3, UR (4, 5)); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[4, 5]" "bug 86688" { xfail *-*-* } } */
T (3, "123", 3, UR (5, 9)); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[5, 9]" } */ T (3, "123", 3, UR (5, 9)); /* { dg-warning "argument 1 declared attribute .nonstring. is smaller than the specified bound \\\[5, 9]" "bug 86688" { xfail *-*-* } } */
} }
/* PR tree-optimization/86042 - missing strlen optimization after second strcpy
{ 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 ELIM(expr) \
if (!(expr)) FAIL (in_true_branch_not_eliminated); else (void)0
void elim_after_duplicate_strcpy (void)
{
#define T(N, assign, off, str, r0, r1) \
do { \
char a[N]; \
strcpy (a, assign); \
unsigned n0 = strlen (a); \
strcpy (a + off, str); \
unsigned n1 = strlen (a); \
ELIM (n0 == r0 && n1 == r1); \
} while (0)
T (2, "", 0, "1", 0, 1);
T (2, "1", 0, "2", 1, 1);
T (2, "1", 1, "", 1, 1);
T (3, "\0", 0, "1", 0, 1);
T (3, "1", 1, "2", 1, 2);
T (3, "12", 0, "23", 2, 2);
T (3, "12", 1, "3", 2, 2);
T (3, "12", 2, "", 2, 2);
T (4, "1", 1, "23", 1, 3);
T (4, "12", 1, "23", 2, 3);
T (4, "123", 0, "234", 3, 3);
T (4, "123", 1, "34", 3, 3);
T (4, "123", 2, "4", 3, 3);
T (4, "123", 3, "", 3, 3);
T (5, "1234", 0, "1", 4, 1);
T (5, "1234", 0, "12", 4, 2);
T (5, "1234", 0, "123", 4, 3);
T (5, "1234", 0, "1234", 4, 4);
T (5, "123", 1, "234", 3, 4);
T (6, "123", 2, "234", 3, 5);
}
void elim_after_init_memcpy (void)
{
#undef T
#define T(init, off, str, n, res) \
do { \
char a[] = init; \
memcpy (a + off, str, n); \
ELIM (strlen (a) == res); \
} while (0)
T ("\0", 0, "1", 2, 1);
T ("\0\0", 0, "12", 3, 2);
#define INIT { '1', '2', '3', '4' }
T (INIT, 0, "", 1, 0);
T (INIT, 0, "1", 2, 1);
T (INIT, 0, "12", 3, 2);
T (INIT, 0, "123", 4, 3);
T ("1234", 0, "2", 1, 4);
T ("1234", 0, "23", 2, 4);
T ("1234", 0, "234", 3, 4);
T ("1234", 0, "2345", 4, 4);
T ("1234", 0, "2345", 5, 4);
T ("1234", 1, "2", 1, 4);
T ("1234", 1, "23", 2, 4);
T ("1234", 1, "234", 3, 4);
T ("1234", 1, "234", 4, 4);
T ("1234", 2, "3", 1, 4);
T ("1234", 2, "3", 2, 3);
T ("1234", 2, "34", 2, 4);
T ("1234", 2, "34", 3, 4);
T ("12\00034", 0, "1", 1, 2);
T ("12\00034", 0, "1", 2, 1);
T ("AB\000CD", 0, "ab", 2, 2);
T ("AB\000CD", 0, "ab", 3, 2);
T ("AB\000CD", 0, "ab\000c", 4, 2);
}
/* { dg-final { scan-tree-dump-times "strlen" 0 "optimized" } }
{ dg-final { scan-tree-dump-times "call_in_true_branch_not_eliminated" 0 "optimized" } } */
...@@ -2326,6 +2326,18 @@ handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi) ...@@ -2326,6 +2326,18 @@ handle_builtin_memcpy (enum built_in_function bcode, gimple_stmt_iterator *gsi)
full_string_p = clen > nonzero_chars; full_string_p = clen > nonzero_chars;
} }
if (!full_string_p
&& olddsi
&& olddsi->nonzero_chars
&& TREE_CODE (olddsi->nonzero_chars) == INTEGER_CST
&& tree_int_cst_le (newlen, olddsi->nonzero_chars))
{
/* The SRC substring being written strictly overlaps
a subsequence of the existing string OLDDSI. */
newlen = olddsi->nonzero_chars;
full_string_p = olddsi->full_string_p;
}
if (olddsi != NULL && TREE_CODE (len) == SSA_NAME) if (olddsi != NULL && TREE_CODE (len) == SSA_NAME)
adjust_last_stmt (olddsi, stmt, false); adjust_last_stmt (olddsi, stmt, false);
...@@ -3131,11 +3143,25 @@ handle_pointer_plus (gimple_stmt_iterator *gsi) ...@@ -3131,11 +3143,25 @@ handle_pointer_plus (gimple_stmt_iterator *gsi)
} }
/* If RHS, either directly or indirectly, refers to a string of constant /* If RHS, either directly or indirectly, refers to a string of constant
length, return it. Otherwise return a negative value. */ length, return the length. Otherwise, if it refers to a character
constant, return 1 if the constant is non-zero and 0 if it is nul.
Otherwise, return a negative value. */
static HOST_WIDE_INT static HOST_WIDE_INT
get_string_cst_length (tree rhs) get_min_string_length (tree rhs, bool *full_string_p)
{ {
if (TREE_CODE (TREE_TYPE (rhs)) == INTEGER_TYPE)
{
if (tree_expr_nonzero_p (rhs))
{
*full_string_p = false;
return 1;
}
*full_string_p = true;
return 0;
}
if (TREE_CODE (rhs) == MEM_REF if (TREE_CODE (rhs) == MEM_REF
&& integer_zerop (TREE_OPERAND (rhs, 1))) && integer_zerop (TREE_OPERAND (rhs, 1)))
{ {
...@@ -3152,9 +3178,11 @@ get_string_cst_length (tree rhs) ...@@ -3152,9 +3178,11 @@ get_string_cst_length (tree rhs)
{ {
strinfo *si = get_strinfo (idx); strinfo *si = get_strinfo (idx);
if (si if (si
&& si->full_string_p
&& tree_fits_shwi_p (si->nonzero_chars)) && tree_fits_shwi_p (si->nonzero_chars))
return tree_to_shwi (si->nonzero_chars); {
*full_string_p = si->full_string_p;
return tree_to_shwi (si->nonzero_chars);
}
} }
} }
} }
...@@ -3165,12 +3193,17 @@ get_string_cst_length (tree rhs) ...@@ -3165,12 +3193,17 @@ get_string_cst_length (tree rhs)
rhs = DECL_INITIAL (rhs); rhs = DECL_INITIAL (rhs);
if (rhs && TREE_CODE (rhs) == STRING_CST) if (rhs && TREE_CODE (rhs) == STRING_CST)
return strlen (TREE_STRING_POINTER (rhs)); {
*full_string_p = true;
return strlen (TREE_STRING_POINTER (rhs));
}
return -1; return -1;
} }
/* Handle a single character store. */ /* Handle a single or multiple character store either by single
character assignment or by multi-character assignment from
MEM_REF. */
static bool static bool
handle_char_store (gimple_stmt_iterator *gsi) handle_char_store (gimple_stmt_iterator *gsi)
...@@ -3208,8 +3241,15 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3208,8 +3241,15 @@ handle_char_store (gimple_stmt_iterator *gsi)
si = get_strinfo (idx); si = get_strinfo (idx);
} }
bool storing_zero_p = initializer_zerop (rhs); /* STORING_NONZERO_P is true iff not all stored characters are zero.
bool storing_nonzero_p = !storing_zero_p && tree_expr_nonzero_p (rhs); STORING_ALL_ZEROS_P is true iff all stored characters are zero.
Both are false when it's impossible to determine which is true. */
bool storing_nonzero_p;
bool storing_all_zeros_p = initializer_zerop (rhs, &storing_nonzero_p);
if (!storing_nonzero_p)
storing_nonzero_p = tree_expr_nonzero_p (rhs);
bool full_string_p = storing_all_zeros_p;
/* Set to the length of the string being assigned if known. */ /* Set to the length of the string being assigned if known. */
HOST_WIDE_INT rhslen; HOST_WIDE_INT rhslen;
...@@ -3217,7 +3257,7 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3217,7 +3257,7 @@ handle_char_store (gimple_stmt_iterator *gsi)
{ {
int cmp = compare_nonzero_chars (si, offset); int cmp = compare_nonzero_chars (si, offset);
gcc_assert (offset == 0 || cmp >= 0); gcc_assert (offset == 0 || cmp >= 0);
if (storing_zero_p && cmp == 0 && si->full_string_p) if (storing_all_zeros_p && cmp == 0 && si->full_string_p)
{ {
/* When overwriting a '\0' with a '\0', the store can be removed /* When overwriting a '\0' with a '\0', the store can be removed
if we know it has been stored in the current function. */ if we know it has been stored in the current function. */
...@@ -3260,17 +3300,25 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3260,17 +3300,25 @@ handle_char_store (gimple_stmt_iterator *gsi)
gsi_next (gsi); gsi_next (gsi);
return false; return false;
} }
else if (storing_zero_p || storing_nonzero_p || (offset != 0 && cmp > 0)) else if (storing_all_zeros_p || storing_nonzero_p || (offset != 0 && cmp > 0))
{ {
/* When storing_nonzero_p, we know that the string now starts /* When STORING_NONZERO_P, we know that the string will start
with OFFSET + 1 nonzero characters, but don't know whether with at least OFFSET + 1 nonzero characters. If storing
there's a following nul terminator. a single character, set si->NONZERO_CHARS to the result.
If storing multiple characters, try to determine the number
of leading non-zero characters and set si->NONZERO_CHARS to
the result instead.
When storing_zero_p, we know that the string is now OFFSET When STORING_ALL_ZEROS_P, we know that the string is now
characters long. OFFSET characters long.
Otherwise, we're storing an unknown value at offset OFFSET, Otherwise, we're storing an unknown value at offset OFFSET,
so need to clip the nonzero_chars to OFFSET. */ so need to clip the nonzero_chars to OFFSET. */
bool full_string_p = storing_all_zeros_p;
HOST_WIDE_INT len = (storing_nonzero_p
? get_min_string_length (rhs, &full_string_p)
: 1);
location_t loc = gimple_location (stmt); location_t loc = gimple_location (stmt);
tree oldlen = si->nonzero_chars; tree oldlen = si->nonzero_chars;
if (cmp == 0 && si->full_string_p) if (cmp == 0 && si->full_string_p)
...@@ -3280,11 +3328,14 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3280,11 +3328,14 @@ handle_char_store (gimple_stmt_iterator *gsi)
adjust_last_stmt (si, stmt, false); adjust_last_stmt (si, stmt, false);
si = unshare_strinfo (si); si = unshare_strinfo (si);
if (storing_nonzero_p) if (storing_nonzero_p)
si->nonzero_chars = build_int_cst (size_type_node, offset + 1); {
gcc_assert (len >= 0);
si->nonzero_chars = build_int_cst (size_type_node, offset + len);
}
else else
si->nonzero_chars = build_int_cst (size_type_node, offset); si->nonzero_chars = build_int_cst (size_type_node, offset);
si->full_string_p = storing_zero_p; si->full_string_p = full_string_p;
if (storing_zero_p if (storing_all_zeros_p
&& ssaname && ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname)) && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
si->endptr = ssaname; si->endptr = ssaname;
...@@ -3304,7 +3355,7 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3304,7 +3355,7 @@ handle_char_store (gimple_stmt_iterator *gsi)
si->prev = 0; si->prev = 0;
} }
} }
else if (idx == 0 && (storing_zero_p || storing_nonzero_p)) else if (idx == 0 && (storing_all_zeros_p || storing_nonzero_p))
{ {
if (ssaname) if (ssaname)
idx = new_stridx (ssaname); idx = new_stridx (ssaname);
...@@ -3313,10 +3364,17 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3313,10 +3364,17 @@ handle_char_store (gimple_stmt_iterator *gsi)
if (idx != 0) if (idx != 0)
{ {
tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs)); tree ptr = (ssaname ? ssaname : build_fold_addr_expr (lhs));
tree len = storing_nonzero_p ? size_one_node : size_zero_node; HOST_WIDE_INT slen = (storing_all_zeros_p
si = new_strinfo (ptr, idx, len, storing_zero_p); ? 0
: (storing_nonzero_p
? get_min_string_length (rhs, &full_string_p)
: -1));
tree len = (slen <= 0
? size_zero_node
: build_int_cst (size_type_node, slen));
si = new_strinfo (ptr, idx, len, slen >= 0 && full_string_p);
set_strinfo (idx, si); set_strinfo (idx, si);
if (storing_zero_p if (storing_all_zeros_p
&& ssaname && ssaname
&& !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname)) && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (ssaname))
si->endptr = ssaname; si->endptr = ssaname;
...@@ -3325,7 +3383,7 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3325,7 +3383,7 @@ handle_char_store (gimple_stmt_iterator *gsi)
} }
} }
else if (idx == 0 else if (idx == 0
&& (rhslen = get_string_cst_length (gimple_assign_rhs1 (stmt))) >= 0 && (rhslen = get_min_string_length (rhs, &full_string_p)) >= 0
&& ssaname == NULL_TREE && ssaname == NULL_TREE
&& TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE) && TREE_CODE (TREE_TYPE (lhs)) == ARRAY_TYPE)
{ {
...@@ -3336,14 +3394,15 @@ handle_char_store (gimple_stmt_iterator *gsi) ...@@ -3336,14 +3394,15 @@ handle_char_store (gimple_stmt_iterator *gsi)
if (idx != 0) if (idx != 0)
{ {
si = new_strinfo (build_fold_addr_expr (lhs), idx, si = new_strinfo (build_fold_addr_expr (lhs), idx,
build_int_cst (size_type_node, rhslen), true); build_int_cst (size_type_node, rhslen),
full_string_p);
set_strinfo (idx, si); set_strinfo (idx, si);
si->dont_invalidate = true; si->dont_invalidate = true;
} }
} }
} }
if (si != NULL && offset == 0 && storing_zero_p) if (si != NULL && offset == 0 && storing_all_zeros_p)
{ {
/* Allow adjust_last_stmt to remove it if the stored '\0' /* Allow adjust_last_stmt to remove it if the stored '\0'
is immediately overwritten. */ is immediately overwritten. */
......
...@@ -10643,61 +10643,124 @@ vector_cst_elt (const_tree t, unsigned int i) ...@@ -10643,61 +10643,124 @@ vector_cst_elt (const_tree t, unsigned int i)
} }
/* Given an initializer INIT, return TRUE if INIT is zero or some /* Given an initializer INIT, return TRUE if INIT is zero or some
aggregate of zeros. Otherwise return FALSE. */ aggregate of zeros. Otherwise return FALSE. If NONZERO is not
null, set *NONZERO if and only if INIT is known not to be all
zeros. The combination of return value of false and *NONZERO
false implies that INIT may but need not be all zeros. Other
combinations indicate definitive answers. */
bool bool
initializer_zerop (const_tree init) initializer_zerop (const_tree init, bool *nonzero /* = NULL */)
{ {
tree elt; bool dummy;
if (!nonzero)
nonzero = &dummy;
/* Conservatively clear NONZERO and set it only if INIT is definitely
not all zero. */
*nonzero = false;
STRIP_NOPS (init); STRIP_NOPS (init);
unsigned HOST_WIDE_INT off = 0;
switch (TREE_CODE (init)) switch (TREE_CODE (init))
{ {
case INTEGER_CST: case INTEGER_CST:
return integer_zerop (init); if (integer_zerop (init))
return true;
*nonzero = true;
return false;
case REAL_CST: case REAL_CST:
/* ??? Note that this is not correct for C4X float formats. There, /* ??? Note that this is not correct for C4X float formats. There,
a bit pattern of all zeros is 1.0; 0.0 is encoded with the most a bit pattern of all zeros is 1.0; 0.0 is encoded with the most
negative exponent. */ negative exponent. */
return real_zerop (init) if (real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)); && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)))
return true;
*nonzero = true;
return false;
case FIXED_CST: case FIXED_CST:
return fixed_zerop (init); if (fixed_zerop (init))
return true;
*nonzero = true;
return false;
case COMPLEX_CST: case COMPLEX_CST:
return integer_zerop (init) if (integer_zerop (init)
|| (real_zerop (init) || (real_zerop (init)
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init))) && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
&& ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))); && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))))
return true;
*nonzero = true;
return false;
case VECTOR_CST: case VECTOR_CST:
return (VECTOR_CST_NPATTERNS (init) == 1 if (VECTOR_CST_NPATTERNS (init) == 1
&& VECTOR_CST_DUPLICATE_P (init) && VECTOR_CST_DUPLICATE_P (init)
&& initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0))); && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)))
return true;
*nonzero = true;
return false;
case CONSTRUCTOR: case CONSTRUCTOR:
{ {
unsigned HOST_WIDE_INT idx;
if (TREE_CLOBBER_P (init)) if (TREE_CLOBBER_P (init))
return false; return false;
unsigned HOST_WIDE_INT idx;
tree elt;
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt) FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
if (!initializer_zerop (elt)) if (!initializer_zerop (elt, nonzero))
return false; return false;
return true; return true;
} }
case MEM_REF:
{
tree arg = TREE_OPERAND (init, 0);
if (TREE_CODE (arg) != ADDR_EXPR)
return false;
tree offset = TREE_OPERAND (init, 1);
if (TREE_CODE (offset) != INTEGER_CST
|| !tree_fits_uhwi_p (offset))
return false;
off = tree_to_uhwi (offset);
if (INT_MAX < off)
return false;
arg = TREE_OPERAND (arg, 0);
if (TREE_CODE (arg) != STRING_CST)
return false;
init = arg;
}
/* Fall through. */
case STRING_CST: case STRING_CST:
{ {
int i; gcc_assert (off <= INT_MAX);
int i = off;
int n = TREE_STRING_LENGTH (init);
if (n <= i)
return false;
/* We need to loop through all elements to handle cases like /* We need to loop through all elements to handle cases like
"\0" and "\0foobar". */ "\0" and "\0foobar". */
for (i = 0; i < TREE_STRING_LENGTH (init); ++i) for (i = 0; i < n; ++i)
if (TREE_STRING_POINTER (init)[i] != '\0') if (TREE_STRING_POINTER (init)[i] != '\0')
return false; {
*nonzero = true;
return false;
}
return true; return true;
} }
......
...@@ -4429,9 +4429,13 @@ extern int list_length (const_tree); ...@@ -4429,9 +4429,13 @@ extern int list_length (const_tree);
extern tree first_field (const_tree); extern tree first_field (const_tree);
/* Given an initializer INIT, return TRUE if INIT is zero or some /* Given an initializer INIT, return TRUE if INIT is zero or some
aggregate of zeros. Otherwise return FALSE. */ aggregate of zeros. Otherwise return FALSE. If NONZERO is not
null, set *NONZERO if and only if INIT is known not to be all
zeros. The combination of return value of false and *NONZERO
false implies that INIT may but need not be all zeros. Other
combinations indicate definitive answers. */
extern bool initializer_zerop (const_tree); extern bool initializer_zerop (const_tree, bool * = NULL);
extern wide_int vector_cst_int_elt (const_tree, unsigned int); extern wide_int vector_cst_int_elt (const_tree, unsigned int);
extern tree vector_cst_elt (const_tree, unsigned int); extern tree vector_cst_elt (const_tree, unsigned int);
......
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