aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-fold.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-fold.c')
-rw-r--r--gcc/gimple-fold.c140
1 files changed, 113 insertions, 27 deletions
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index 7e4cb74..504a85d 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -1299,7 +1299,7 @@ static bool
get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
bool fuzzy, bool *flexp)
{
- tree var, val;
+ tree var, val = NULL_TREE;
gimple *def_stmt;
/* The minimum and maximum length. The MAXLEN pointer stays unchanged
@@ -1311,14 +1311,33 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
{
/* We can end up with &(*iftmp_1)[0] here as well, so handle it. */
if (TREE_CODE (arg) == ADDR_EXPR
- && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF
- && integer_zerop (TREE_OPERAND (TREE_OPERAND (arg, 0), 1)))
+ && TREE_CODE (TREE_OPERAND (arg, 0)) == ARRAY_REF)
{
- tree aop0 = TREE_OPERAND (TREE_OPERAND (arg, 0), 0);
- if (TREE_CODE (aop0) == INDIRECT_REF
- && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
- return get_range_strlen (TREE_OPERAND (aop0, 0),
- length, visited, type, fuzzy, flexp);
+ tree op = TREE_OPERAND (arg, 0);
+ if (integer_zerop (TREE_OPERAND (op, 1)))
+ {
+ tree aop0 = TREE_OPERAND (op, 0);
+ if (TREE_CODE (aop0) == INDIRECT_REF
+ && TREE_CODE (TREE_OPERAND (aop0, 0)) == SSA_NAME)
+ return get_range_strlen (TREE_OPERAND (aop0, 0),
+ length, visited, type, fuzzy, flexp);
+ }
+ else if (TREE_CODE (TREE_OPERAND (op, 0)) == COMPONENT_REF && fuzzy)
+ {
+ /* Fail if an array is the last member of a struct object
+ since it could be treated as a (fake) flexible array
+ member. */
+ tree idx = TREE_OPERAND (op, 1);
+
+ arg = TREE_OPERAND (op, 0);
+ tree optype = TREE_TYPE (arg);
+ if (tree dom = TYPE_DOMAIN (optype))
+ if (tree bound = TYPE_MAX_VALUE (dom))
+ if (TREE_CODE (bound) == INTEGER_CST
+ && TREE_CODE (idx) == INTEGER_CST
+ && tree_int_cst_lt (bound, idx))
+ return false;
+ }
}
if (type == 2)
@@ -1337,21 +1356,48 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
return get_range_strlen (TREE_OPERAND (arg, 0), length,
visited, type, fuzzy, flexp);
- if (TREE_CODE (arg) == COMPONENT_REF
+ if (TREE_CODE (arg) == ARRAY_REF)
+ {
+ tree type = TREE_TYPE (TREE_OPERAND (arg, 0));
+
+ while (TREE_CODE (type) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ val = TYPE_SIZE_UNIT (type);
+ if (!val || integer_zerop (val))
+ return false;
+
+ val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
+ integer_one_node);
+ /* Set the minimum size to zero since the string in
+ the array could have zero length. */
+ *minlen = ssize_int (0);
+ }
+ else if (TREE_CODE (arg) == COMPONENT_REF
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (arg, 1))) == ARRAY_TYPE)
{
/* Use the type of the member array to determine the upper
bound on the length of the array. This may be overly
optimistic if the array itself isn't NUL-terminated and
the caller relies on the subsequent member to contain
- the NUL.
+ the NUL but that would only be considered valid if
+ the array were the last member of a struct.
Set *FLEXP to true if the array whose bound is being
used is at the end of a struct. */
if (array_at_struct_end_p (arg))
*flexp = true;
arg = TREE_OPERAND (arg, 1);
- val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
+
+ tree type = TREE_TYPE (arg);
+
+ while (TREE_CODE (type) == ARRAY_TYPE
+ && TREE_CODE (TREE_TYPE (type)) == ARRAY_TYPE)
+ type = TREE_TYPE (type);
+
+ /* Fail when the array bound is unknown or zero. */
+ val = TYPE_SIZE_UNIT (type);
if (!val || integer_zerop (val))
return false;
val = fold_build2 (MINUS_EXPR, TREE_TYPE (val), val,
@@ -1361,17 +1407,25 @@ get_range_strlen (tree arg, tree length[2], bitmap *visited, int type,
*minlen = ssize_int (0);
}
- if (VAR_P (arg)
- && TREE_CODE (TREE_TYPE (arg)) == ARRAY_TYPE)
+ if (VAR_P (arg))
{
- val = TYPE_SIZE_UNIT (TREE_TYPE (arg));
- if (!val || TREE_CODE (val) != INTEGER_CST || integer_zerop (val))
- return false;
- val = wide_int_to_tree (TREE_TYPE (val),
- wi::sub(wi::to_wide (val), 1));
- /* Set the minimum size to zero since the string in
- the array could have zero length. */
- *minlen = ssize_int (0);
+ tree type = TREE_TYPE (arg);
+ if (POINTER_TYPE_P (type))
+ type = TREE_TYPE (type);
+
+ if (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ val = TYPE_SIZE_UNIT (type);
+ if (!val
+ || TREE_CODE (val) != INTEGER_CST
+ || integer_zerop (val))
+ return false;
+ val = wide_int_to_tree (TREE_TYPE (val),
+ wi::sub(wi::to_wide (val), 1));
+ /* Set the minimum size to zero since the string in
+ the array could have zero length. */
+ *minlen = ssize_int (0);
+ }
}
}
@@ -3462,12 +3516,44 @@ static bool
gimple_fold_builtin_strlen (gimple_stmt_iterator *gsi)
{
gimple *stmt = gsi_stmt (*gsi);
- tree len = get_maxval_strlen (gimple_call_arg (stmt, 0), 0);
- if (!len)
- return false;
- len = force_gimple_operand_gsi (gsi, len, true, NULL, true, GSI_SAME_STMT);
- replace_call_with_value (gsi, len);
- return true;
+
+ wide_int minlen;
+ wide_int maxlen;
+
+ tree lenrange[2];
+ if (!get_range_strlen (gimple_call_arg (stmt, 0), lenrange)
+ && lenrange[0] && TREE_CODE (lenrange[0]) == INTEGER_CST
+ && lenrange[1] && TREE_CODE (lenrange[1]) == INTEGER_CST)
+ {
+ /* The range of lengths refers to either a single constant
+ string or to the longest and shortest constant string
+ referenced by the argument of the strlen() call, or to
+ the strings that can possibly be stored in the arrays
+ the argument refers to. */
+ minlen = wi::to_wide (lenrange[0]);
+ maxlen = wi::to_wide (lenrange[1]);
+ }
+ else
+ {
+ unsigned prec = TYPE_PRECISION (sizetype);
+
+ minlen = wi::shwi (0, prec);
+ maxlen = wi::to_wide (max_object_size (), prec) - 2;
+ }
+
+ if (minlen == maxlen)
+ {
+ lenrange[0] = force_gimple_operand_gsi (gsi, lenrange[0], true, NULL,
+ true, GSI_SAME_STMT);
+ replace_call_with_value (gsi, lenrange[0]);
+ return true;
+ }
+
+ tree lhs = gimple_call_lhs (stmt);
+ if (lhs && TREE_CODE (lhs) == SSA_NAME)
+ set_range_info (lhs, VR_RANGE, minlen, maxlen);
+
+ return false;
}
/* Fold a call to __builtin_acc_on_device. */