diff options
author | Martin Sebor <msebor@redhat.com> | 2018-06-18 16:32:59 +0000 |
---|---|---|
committer | Martin Sebor <msebor@gcc.gnu.org> | 2018-06-18 10:32:59 -0600 |
commit | 781ff3d80e88d7d0df019eb3e82ef2a3fb64429c (patch) | |
tree | 01c31801fe48b1c21114b772785de9eefe119e7b /gcc/builtins.c | |
parent | 7314856c61938db90d66f4cead8e4df73ea5d3af (diff) | |
download | gcc-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.c | 105 |
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; |