diff options
author | Ilya Enkovich <ilya.enkovich@intel.com> | 2014-11-17 13:45:55 +0000 |
---|---|---|
committer | Ilya Enkovich <ienkovich@gcc.gnu.org> | 2014-11-17 13:45:55 +0000 |
commit | edcf72f3c9e070fe904ff9ff2f2fd145e694af83 (patch) | |
tree | bc2f2a46968faabdbe890355b0f2b9b151a106bb /gcc/builtins.c | |
parent | 5134529b25c1fd448e6589876a84d0095a5ffc35 (diff) | |
download | gcc-edcf72f3c9e070fe904ff9ff2f2fd145e694af83.zip gcc-edcf72f3c9e070fe904ff9ff2f2fd145e694af83.tar.gz gcc-edcf72f3c9e070fe904ff9ff2f2fd145e694af83.tar.bz2 |
tree-core.h (built_in_class): Add builtin codes to be used by Pointer Bounds Checker for instrumented builtin...
* tree-core.h (built_in_class): Add builtin codes to be used
by Pointer Bounds Checker for instrumented builtin functions.
* tree-streamer-in.c: Include ipa-chkp.h.
(streamer_get_builtin_tree): Created instrumented decl if
required.
* ipa-chkp.h (chkp_maybe_clone_builtin_fndecl): New.
* ipa-chkp.c (chkp_build_instrumented_fndecl): Support builtin
function decls.
(chkp_maybe_clone_builtin_fndecl): New.
(chkp_maybe_create_clone): Support builtin function decls.
(chkp_versioning): Clone builtin functions.
* tree-chkp.c (chkp_instrument_normal_builtin): New.
(chkp_add_bounds_to_call_stmt): Support builtin functions.
(chkp_replace_function_pointer): Likewise.
* builtins.c (expand_builtin_memcpy_args): New.
(expand_builtin_memcpy): Call expand_builtin_memcpy_args.
(expand_builtin_memcpy_with_bounds): New.
(expand_builtin_mempcpy_with_bounds): New.
(expand_builtin_mempcpy_args): Add orig_exp arg. Support
BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK
(expand_builtin_memset_with_bounds): New.
(expand_builtin_memset_args): Support BUILT_IN_CHKP_MEMSET_NOBND_NOCHK.
(expand_builtin_with_bounds): New.
* builtins.h (expand_builtin_with_bounds): New.
* expr.c (expand_expr_real_1): Support instrumented builtin calls.
From-SVN: r217655
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r-- | gcc/builtins.c | 307 |
1 files changed, 239 insertions, 68 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c index 311c0e3..7ec2d5f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -132,15 +132,19 @@ static rtx expand_builtin_strcmp (tree, rtx); static rtx expand_builtin_strncmp (tree, rtx, machine_mode); static rtx builtin_memcpy_read_str (void *, HOST_WIDE_INT, machine_mode); static rtx expand_builtin_memcpy (tree, rtx); +static rtx expand_builtin_memcpy_with_bounds (tree, rtx); +static rtx expand_builtin_memcpy_args (tree, tree, tree, rtx, tree); static rtx expand_builtin_mempcpy (tree, rtx, machine_mode); +static rtx expand_builtin_mempcpy_with_bounds (tree, rtx, machine_mode); static rtx expand_builtin_mempcpy_args (tree, tree, tree, rtx, - machine_mode, int); + machine_mode, int, tree); static rtx expand_builtin_strcpy (tree, rtx); static rtx expand_builtin_strcpy_args (tree, tree, rtx); static rtx expand_builtin_stpcpy (tree, rtx, machine_mode); static rtx expand_builtin_strncpy (tree, rtx); static rtx builtin_memset_gen_str (void *, HOST_WIDE_INT, machine_mode); static rtx expand_builtin_memset (tree, rtx, machine_mode); +static rtx expand_builtin_memset_with_bounds (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); @@ -3175,6 +3179,81 @@ determine_block_size (tree len, rtx len_rtx, GET_MODE_MASK (GET_MODE (len_rtx))); } +/* Helper function to do the actual work for expand_builtin_memcpy. */ + +static rtx +expand_builtin_memcpy_args (tree dest, tree src, tree len, rtx target, tree exp) +{ + const char *src_str; + unsigned int src_align = get_pointer_alignment (src); + unsigned int dest_align = get_pointer_alignment (dest); + rtx dest_mem, src_mem, dest_addr, len_rtx; + HOST_WIDE_INT expected_size = -1; + unsigned int expected_align = 0; + unsigned HOST_WIDE_INT min_size; + unsigned HOST_WIDE_INT max_size; + unsigned HOST_WIDE_INT probable_max_size; + + /* If DEST is not a pointer type, call the normal function. */ + if (dest_align == 0) + return NULL_RTX; + + /* If either SRC is not a pointer type, don't do this + operation in-line. */ + if (src_align == 0) + return NULL_RTX; + + if (currently_expanding_gimple_stmt) + stringop_block_profile (currently_expanding_gimple_stmt, + &expected_align, &expected_size); + + if (expected_align < dest_align) + expected_align = dest_align; + dest_mem = get_memory_rtx (dest, len); + set_mem_align (dest_mem, dest_align); + len_rtx = expand_normal (len); + determine_block_size (len, len_rtx, &min_size, &max_size, + &probable_max_size); + src_str = c_getstr (src); + + /* If SRC is a string constant and block move would be done + by pieces, we can avoid loading the string from memory + and only stored the computed constants. */ + if (src_str + && CONST_INT_P (len_rtx) + && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 + && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, + CONST_CAST (char *, src_str), + dest_align, false)) + { + dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx), + builtin_memcpy_read_str, + CONST_CAST (char *, src_str), + dest_align, false, 0); + dest_mem = force_operand (XEXP (dest_mem, 0), target); + dest_mem = convert_memory_address (ptr_mode, dest_mem); + return dest_mem; + } + + src_mem = get_memory_rtx (src, len); + set_mem_align (src_mem, src_align); + + /* Copy word part most expediently. */ + dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, + CALL_EXPR_TAILCALL (exp) + ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL, + expected_align, expected_size, + min_size, max_size, probable_max_size); + + if (dest_addr == 0) + { + dest_addr = force_operand (XEXP (dest_mem, 0), target); + dest_addr = convert_memory_address (ptr_mode, dest_addr); + } + + return dest_addr; +} + /* Expand a call EXP to the memcpy builtin. Return NULL_RTX if we failed, the caller should emit a normal call, otherwise try to get the result in TARGET, if convenient (and in @@ -3191,73 +3270,38 @@ expand_builtin_memcpy (tree exp, rtx target) tree dest = CALL_EXPR_ARG (exp, 0); tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); - const char *src_str; - unsigned int src_align = get_pointer_alignment (src); - unsigned int dest_align = get_pointer_alignment (dest); - rtx dest_mem, src_mem, dest_addr, len_rtx; - HOST_WIDE_INT expected_size = -1; - unsigned int expected_align = 0; - unsigned HOST_WIDE_INT min_size; - unsigned HOST_WIDE_INT max_size; - unsigned HOST_WIDE_INT probable_max_size; - - /* If DEST is not a pointer type, call the normal function. */ - if (dest_align == 0) - return NULL_RTX; - - /* If either SRC is not a pointer type, don't do this - operation in-line. */ - if (src_align == 0) - return NULL_RTX; - - if (currently_expanding_gimple_stmt) - stringop_block_profile (currently_expanding_gimple_stmt, - &expected_align, &expected_size); - - if (expected_align < dest_align) - expected_align = dest_align; - dest_mem = get_memory_rtx (dest, len); - set_mem_align (dest_mem, dest_align); - len_rtx = expand_normal (len); - determine_block_size (len, len_rtx, &min_size, &max_size, - &probable_max_size); - src_str = c_getstr (src); - - /* If SRC is a string constant and block move would be done - by pieces, we can avoid loading the string from memory - and only stored the computed constants. */ - if (src_str - && CONST_INT_P (len_rtx) - && (unsigned HOST_WIDE_INT) INTVAL (len_rtx) <= strlen (src_str) + 1 - && can_store_by_pieces (INTVAL (len_rtx), builtin_memcpy_read_str, - CONST_CAST (char *, src_str), - dest_align, false)) - { - dest_mem = store_by_pieces (dest_mem, INTVAL (len_rtx), - builtin_memcpy_read_str, - CONST_CAST (char *, src_str), - dest_align, false, 0); - dest_mem = force_operand (XEXP (dest_mem, 0), target); - dest_mem = convert_memory_address (ptr_mode, dest_mem); - return dest_mem; - } + return expand_builtin_memcpy_args (dest, src, len, target, exp); + } +} - src_mem = get_memory_rtx (src, len); - set_mem_align (src_mem, src_align); +/* Expand an instrumented call EXP to the memcpy builtin. + Return NULL_RTX if we failed, the caller should emit a normal call, + otherwise try to get the result in TARGET, if convenient (and in + mode MODE if that's convenient). */ - /* Copy word part most expediently. */ - dest_addr = emit_block_move_hints (dest_mem, src_mem, len_rtx, - CALL_EXPR_TAILCALL (exp) - ? BLOCK_OP_TAILCALL : BLOCK_OP_NORMAL, - expected_align, expected_size, - min_size, max_size, probable_max_size); +static rtx +expand_builtin_memcpy_with_bounds (tree exp, rtx target) +{ + if (!validate_arglist (exp, + POINTER_TYPE, POINTER_BOUNDS_TYPE, + POINTER_TYPE, POINTER_BOUNDS_TYPE, + INTEGER_TYPE, VOID_TYPE)) + return NULL_RTX; + else + { + tree dest = CALL_EXPR_ARG (exp, 0); + tree src = CALL_EXPR_ARG (exp, 2); + tree len = CALL_EXPR_ARG (exp, 4); + rtx res = expand_builtin_memcpy_args (dest, src, len, target, exp); - if (dest_addr == 0) + /* Return src bounds with the result. */ + if (res) { - dest_addr = force_operand (XEXP (dest_mem, 0), target); - dest_addr = convert_memory_address (ptr_mode, dest_addr); + rtx bnd = force_reg (BNDmode, + expand_normal (CALL_EXPR_ARG (exp, 1))); + res = chkp_join_splitted_slot (res, bnd); } - return dest_addr; + return res; } } @@ -3281,7 +3325,40 @@ expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode) tree src = CALL_EXPR_ARG (exp, 1); tree len = CALL_EXPR_ARG (exp, 2); return expand_builtin_mempcpy_args (dest, src, len, - target, mode, /*endp=*/ 1); + target, mode, /*endp=*/ 1, + exp); + } +} + +/* Expand an instrumented call EXP to the mempcpy builtin. + Return NULL_RTX if we failed, the caller should emit a normal call, + otherwise try to get the result in TARGET, if convenient (and in + mode MODE if that's convenient). */ + +static rtx +expand_builtin_mempcpy_with_bounds (tree exp, rtx target, machine_mode mode) +{ + if (!validate_arglist (exp, + POINTER_TYPE, POINTER_BOUNDS_TYPE, + POINTER_TYPE, POINTER_BOUNDS_TYPE, + INTEGER_TYPE, VOID_TYPE)) + return NULL_RTX; + else + { + tree dest = CALL_EXPR_ARG (exp, 0); + tree src = CALL_EXPR_ARG (exp, 2); + tree len = CALL_EXPR_ARG (exp, 4); + rtx res = expand_builtin_mempcpy_args (dest, src, len, target, + mode, 1, exp); + + /* Return src bounds with the result. */ + if (res) + { + rtx bnd = force_reg (BNDmode, + expand_normal (CALL_EXPR_ARG (exp, 1))); + res = chkp_join_splitted_slot (res, bnd); + } + return res; } } @@ -3293,10 +3370,23 @@ expand_builtin_mempcpy (tree exp, rtx target, machine_mode mode) static rtx expand_builtin_mempcpy_args (tree dest, tree src, tree len, - rtx target, machine_mode mode, int endp) + rtx target, machine_mode mode, int endp, + tree orig_exp) { + tree fndecl = get_callee_fndecl (orig_exp); + /* If return value is ignored, transform mempcpy into memcpy. */ - if (target == const0_rtx && builtin_decl_implicit_p (BUILT_IN_MEMCPY)) + if (target == const0_rtx + && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP + && builtin_decl_implicit_p (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP)) + { + tree fn = builtin_decl_implicit (BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP); + tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3, + dest, src, len); + return expand_expr (result, target, mode, EXPAND_NORMAL); + } + else if (target == const0_rtx + && builtin_decl_implicit_p (BUILT_IN_MEMCPY)) { tree fn = builtin_decl_implicit (BUILT_IN_MEMCPY); tree result = build_call_nofold_loc (UNKNOWN_LOCATION, fn, 3, @@ -3481,7 +3571,8 @@ expand_builtin_stpcpy (tree exp, rtx target, machine_mode mode) lenp1 = size_binop_loc (loc, PLUS_EXPR, len, ssize_int (1)); ret = expand_builtin_mempcpy_args (dst, src, lenp1, - target, mode, /*endp=*/2); + target, mode, /*endp=*/2, + exp); if (ret) return ret; @@ -3647,6 +3738,36 @@ expand_builtin_memset (tree exp, rtx target, machine_mode mode) } } +/* Expand expression EXP, which is an instrumented call to the memset builtin. + Return NULL_RTX if we failed the caller should emit a normal call, otherwise + try to get the result in TARGET, if convenient (and in mode MODE if that's + convenient). */ + +static rtx +expand_builtin_memset_with_bounds (tree exp, rtx target, machine_mode mode) +{ + if (!validate_arglist (exp, + POINTER_TYPE, POINTER_BOUNDS_TYPE, + INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)) + return NULL_RTX; + else + { + tree dest = CALL_EXPR_ARG (exp, 0); + tree val = CALL_EXPR_ARG (exp, 2); + tree len = CALL_EXPR_ARG (exp, 3); + rtx res = expand_builtin_memset_args (dest, val, len, target, mode, exp); + + /* Return src bounds with the result. */ + if (res) + { + rtx bnd = force_reg (BNDmode, + expand_normal (CALL_EXPR_ARG (exp, 1))); + res = chkp_join_splitted_slot (res, bnd); + } + return res; + } +} + /* Helper function to do the actual work for expand_builtin_memset. The arguments to the builtin_memset call DEST, VAL, and LEN are broken out so that this can also be called without constructing an actual CALL_EXPR. @@ -3775,7 +3896,8 @@ expand_builtin_memset_args (tree dest, tree val, tree len, do_libcall: fndecl = get_callee_fndecl (orig_exp); fcode = DECL_FUNCTION_CODE (fndecl); - if (fcode == BUILT_IN_MEMSET) + if (fcode == BUILT_IN_MEMSET + || fcode == BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP) fn = build_call_nofold_loc (EXPR_LOCATION (orig_exp), fndecl, 3, dest, val, len); else if (fcode == BUILT_IN_BZERO) @@ -5848,6 +5970,8 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, } } + /* expand_builtin_with_bounds is supposed to be used for + instrumented builtin calls. */ gcc_assert (!CALL_WITH_BOUNDS_P (exp)); switch (fcode) @@ -6908,6 +7032,53 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode, return expand_call (exp, target, ignore); } +/* Similar to expand_builtin but is used for instrumented calls. */ + +rtx +expand_builtin_with_bounds (tree exp, rtx target, + rtx subtarget ATTRIBUTE_UNUSED, + machine_mode mode, int ignore) +{ + tree fndecl = get_callee_fndecl (exp); + enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl); + + gcc_assert (CALL_WITH_BOUNDS_P (exp)); + + if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD) + return targetm.expand_builtin (exp, target, subtarget, mode, ignore); + + gcc_assert (fcode > BEGIN_CHKP_BUILTINS + && fcode < END_CHKP_BUILTINS); + + switch (fcode) + { + case BUILT_IN_CHKP_MEMCPY_NOBND_NOCHK_CHKP: + target = expand_builtin_memcpy_with_bounds (exp, target); + if (target) + return target; + break; + + case BUILT_IN_CHKP_MEMPCPY_NOBND_NOCHK_CHKP: + target = expand_builtin_mempcpy_with_bounds (exp, target, mode); + if (target) + return target; + break; + + case BUILT_IN_CHKP_MEMSET_NOBND_NOCHK_CHKP: + target = expand_builtin_memset_with_bounds (exp, target, mode); + if (target) + return target; + break; + + default: + break; + } + + /* The switch statement above can drop through to cause the function + to be called normally. */ + return expand_call (exp, target, ignore); + } + /* Determine whether a tree node represents a call to a built-in function. If the tree T is a call to a built-in function with the right number of arguments of the appropriate types, return |