aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorMartin Sebor <msebor@redhat.com>2018-06-18 16:32:59 +0000
committerMartin Sebor <msebor@gcc.gnu.org>2018-06-18 10:32:59 -0600
commit781ff3d80e88d7d0df019eb3e82ef2a3fb64429c (patch)
tree01c31801fe48b1c21114b772785de9eefe119e7b /gcc/builtins.c
parent7314856c61938db90d66f4cead8e4df73ea5d3af (diff)
downloadgcc-781ff3d80e88d7d0df019eb3e82ef2a3fb64429c.zip
gcc-781ff3d80e88d7d0df019eb3e82ef2a3fb64429c.tar.gz
gcc-781ff3d80e88d7d0df019eb3e82ef2a3fb64429c.tar.bz2
PR tree-optimization/81384 - built-in form of strnlen missing
gcc/ChangeLog: PR tree-optimization/81384 * builtin-types.def (BT_FN_SIZE_CONST_STRING_SIZE): New. * builtins.c (expand_builtin_strnlen): New function. (expand_builtin): Call it. (fold_builtin_n): Avoid setting TREE_NO_WARNING. * builtins.def (BUILT_IN_STRNLEN): New. * calls.c (maybe_warn_nonstring_arg): Handle BUILT_IN_STRNLEN. Warn for bounds in excess of maximum object size. * tree-ssa-strlen.c (maybe_set_strlen_range): Return tree representing single-value ranges. Handle strnlen. (handle_builtin_strlen): Handle strnlen. (strlen_check_and_optimize_stmt): Same. * doc/extend.texi (Other Builtins): Document strnlen. gcc/testsuite/ChangeLog: PR tree-optimization/81384 * gcc.c-torture/execute/builtins/lib/strnlen.c: New test. * gcc.c-torture/execute/builtins/strnlen-lib.c: New test. * gcc.c-torture/execute/builtins/strnlen.c: New test. * gcc.dg/attr-nonstring-2.c: New test. * gcc.dg/attr-nonstring-3.c: New test. * gcc.dg/attr-nonstring-4.c: New test. * gcc.dg/strlenopt-45.c: New test. * gcc.dg/strlenopt.h (strnlen): Declare. From-SVN: r261705
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c105
1 files changed, 93 insertions, 12 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 6b3e6b2..91658e8 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -140,6 +140,7 @@ static rtx expand_builtin_memset (tree, rtx, machine_mode);
static rtx expand_builtin_memset_args (tree, tree, tree, rtx, machine_mode, tree);
static rtx expand_builtin_bzero (tree);
static rtx expand_builtin_strlen (tree, rtx, machine_mode);
+static rtx expand_builtin_strnlen (tree, rtx, machine_mode);
static rtx expand_builtin_alloca (tree);
static rtx expand_builtin_unop (machine_mode, tree, rtx, rtx, optab);
static rtx expand_builtin_frame_address (tree, tree);
@@ -2820,7 +2821,7 @@ expand_builtin_powi (tree exp, rtx target)
}
/* Expand expression EXP which is a call to the strlen builtin. Return
- NULL_RTX if we failed the caller should emit a normal call, otherwise
+ NULL_RTX if we failed and the caller should emit a normal call, otherwise
try to get the result in TARGET, if convenient. */
static rtx
@@ -2925,6 +2926,74 @@ expand_builtin_strlen (tree exp, rtx target,
return target;
}
+/* Expand call EXP to the strnlen built-in, returning the result
+ and setting it in TARGET. Otherwise return NULL_RTX on failure. */
+
+static rtx
+expand_builtin_strnlen (tree exp, rtx target, machine_mode target_mode)
+{
+ if (!validate_arglist (exp, POINTER_TYPE, INTEGER_TYPE, VOID_TYPE))
+ return NULL_RTX;
+
+ tree src = CALL_EXPR_ARG (exp, 0);
+ tree bound = CALL_EXPR_ARG (exp, 1);
+
+ if (!bound)
+ return NULL_RTX;
+
+ location_t loc = UNKNOWN_LOCATION;
+ if (EXPR_HAS_LOCATION (exp))
+ loc = EXPR_LOCATION (exp);
+
+ tree maxobjsize = max_object_size ();
+ tree func = get_callee_fndecl (exp);
+
+ tree len = c_strlen (src, 0);
+
+ if (TREE_CODE (bound) == INTEGER_CST)
+ {
+ if (!TREE_NO_WARNING (exp)
+ && tree_int_cst_lt (maxobjsize, bound)
+ && warning_at (loc, OPT_Wstringop_overflow_,
+ "%K%qD specified bound %E "
+ "exceeds maximum object size %E",
+ exp, func, bound, maxobjsize))
+ TREE_NO_WARNING (exp) = true;
+
+ if (!len || TREE_CODE (len) != INTEGER_CST)
+ return NULL_RTX;
+
+ len = fold_convert_loc (loc, size_type_node, len);
+ len = fold_build2_loc (loc, MIN_EXPR, size_type_node, len, bound);
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+ }
+
+ if (TREE_CODE (bound) != SSA_NAME)
+ return NULL_RTX;
+
+ wide_int min, max;
+ enum value_range_type rng = get_range_info (bound, &min, &max);
+ if (rng != VR_RANGE)
+ return NULL_RTX;
+
+ if (!TREE_NO_WARNING (exp)
+ && wi::ltu_p (wi::to_wide (maxobjsize), min)
+ && warning_at (loc, OPT_Wstringop_overflow_,
+ "%K%qD specified bound [%wu, %wu] "
+ "exceeds maximum object size %E",
+ exp, func, min.to_uhwi (), max.to_uhwi (), maxobjsize))
+ TREE_NO_WARNING (exp) = true;
+
+ if (!len || TREE_CODE (len) != INTEGER_CST)
+ return NULL_RTX;
+
+ if (wi::gtu_p (min, wi::to_wide (len)))
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+
+ len = fold_build2_loc (loc, MIN_EXPR, TREE_TYPE (len), len, bound);
+ return expand_expr (len, target, target_mode, EXPAND_NORMAL);
+}
+
/* Callback routine for store_by_pieces. Read GET_MODE_BITSIZE (MODE)
bytes from constant string DATA + OFFSET and return it as target
constant. */
@@ -3121,20 +3190,27 @@ check_access (tree exp, tree, tree, tree dstwrite,
object size. */
if (range[0] && tree_int_cst_lt (maxobjsize, range[0]))
{
+ if (TREE_NO_WARNING (exp))
+ return false;
+
location_t loc = tree_nonartificial_location (exp);
loc = expansion_point_location_if_in_system_header (loc);
+ bool warned;
if (range[0] == range[1])
- warning_at (loc, opt,
- "%K%qD specified size %E "
- "exceeds maximum object size %E",
- exp, func, range[0], maxobjsize);
- else
- warning_at (loc, opt,
- "%K%qD specified size between %E and %E "
- "exceeds maximum object size %E",
- exp, func,
- range[0], range[1], maxobjsize);
+ warned = warning_at (loc, opt,
+ "%K%qD specified size %E "
+ "exceeds maximum object size %E",
+ exp, func, range[0], maxobjsize);
+ else
+ warned = warning_at (loc, opt,
+ "%K%qD specified size between %E and %E "
+ "exceeds maximum object size %E",
+ exp, func,
+ range[0], range[1], maxobjsize);
+ if (warned)
+ TREE_NO_WARNING (exp) = true;
+
return false;
}
@@ -6963,6 +7039,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
return target;
break;
+ case BUILT_IN_STRNLEN:
+ target = expand_builtin_strnlen (exp, target, target_mode);
+ if (target)
+ return target;
+ break;
+
case BUILT_IN_STRCAT:
target = expand_builtin_strcat (exp, target);
if (target)
@@ -9174,7 +9256,6 @@ fold_builtin_n (location_t loc, tree fndecl, tree *args, int nargs, bool)
{
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
SET_EXPR_LOCATION (ret, loc);
- TREE_NO_WARNING (ret) = 1;
return ret;
}
return NULL_TREE;