aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree.c')
-rw-r--r--gcc/tree.c103
1 files changed, 83 insertions, 20 deletions
diff --git a/gcc/tree.c b/gcc/tree.c
index bace9c8..28952e5 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -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
- 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
-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);
+ unsigned HOST_WIDE_INT off = 0;
+
switch (TREE_CODE (init))
{
case INTEGER_CST:
- return integer_zerop (init);
+ if (integer_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case REAL_CST:
/* ??? 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
negative exponent. */
- return real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init));
+ if (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (init)))
+ return true;
+
+ *nonzero = true;
+ return false;
case FIXED_CST:
- return fixed_zerop (init);
+ if (fixed_zerop (init))
+ return true;
+
+ *nonzero = true;
+ return false;
case COMPLEX_CST:
- return integer_zerop (init)
- || (real_zerop (init)
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
- && ! REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init))));
+ if (integer_zerop (init)
+ || (real_zerop (init)
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_REALPART (init)))
+ && !REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (TREE_IMAGPART (init)))))
+ return true;
+
+ *nonzero = true;
+ return false;
case VECTOR_CST:
- return (VECTOR_CST_NPATTERNS (init) == 1
- && VECTOR_CST_DUPLICATE_P (init)
- && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)));
+ if (VECTOR_CST_NPATTERNS (init) == 1
+ && VECTOR_CST_DUPLICATE_P (init)
+ && initializer_zerop (VECTOR_CST_ENCODED_ELT (init, 0)))
+ return true;
+
+ *nonzero = true;
+ return false;
case CONSTRUCTOR:
{
- unsigned HOST_WIDE_INT idx;
-
if (TREE_CLOBBER_P (init))
return false;
+
+ unsigned HOST_WIDE_INT idx;
+ tree elt;
+
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (init), idx, elt)
- if (!initializer_zerop (elt))
+ if (!initializer_zerop (elt, nonzero))
return false;
+
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:
{
- 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
"\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')
- return false;
+ {
+ *nonzero = true;
+ return false;
+ }
return true;
}