Ping
2014-06-05 18:46 GMT+04:00 Ilya Enkovich <enkovich....@gmail.com>: > On 04 Jun 16:36, Michael Matz wrote: >> Hi, >> >> On Mon, 2 Jun 2014, Ilya Enkovich wrote: >> >> > > There is exactly one place (except for the self-recursive ones) where >> > > you call the new store_expr with a non-null argument for bounds >> > > target, and it seems to be only necessary for when some sub-expression >> > > of the RHS is a call. Can you somehow arrange to move that handling >> > > to the single place in expand_assignment() so that you don't need to >> > > change the signature of store_expr? >> > >> > I see the only nice way to do it - store_expr should return bounds of >> > expanded exp. Currently it always return NULL_RTX. Does it look better >> > than a new argument? >> >> IMHO it does. That or introducing a new store_expr_with_bounds (with the >> new argument) and letting store_expr be a wrapper for that, passing the >> NULL. Basically anything that avoids adding a new parameter for most of >> the existing calls to store_expr. >> >> >> Ciao, >> Michael. > > Here is an updated version using store_expr_with_bounds and store_expr as a > wrapper for it. > > Bootstrapped and tested on linux-x86_64. > > Thanks, > Ilya > -- > gcc/ > > 2014-06-05 Ilya Enkovich <ilya.enkov...@intel.com> > > * calls.c: Include tree-chkp.h, rtl-chkp.h, bitmap.h. > (arg_data): Add fields special_slot, pointer_arg and > pointer_offset. > (store_bounds): New. > (emit_call_1): Propagate instrumentation flag for CALL. > (initialize_argument_information): Compute pointer_arg, > pointer_offset and special_slot for pointer bounds arguments. > (finalize_must_preallocate): Preallocate when storing bounds > in bounds table. > (compute_argument_addresses): Skip pointer bounds. > (expand_call): Store bounds into tables separately. Return > result joined with resulting bounds. > * cfgexpand.c: Include tree-chkp.h, rtl-chkp.h. > (expand_call_stmt): Propagate bounds flag for CALL_EXPR. > (expand_return): Add returned bounds arg. Handle returned bounds. > (expand_gimple_stmt_1): Adjust to new expand_return signature. > (gimple_expand_cfg): Reset rtx bounds map. > * expr.c: Include tree-chkp.h, rtl-chkp.h. > (expand_assignment): Handle returned bounds. > (store_expr_with_bounds): New. Replaces store_expr with new bounds > target argument. Handle bounds returned by calls. > (store_expr): Now wraps store_expr_with_bounds. > * expr.h (store_expr_with_bounds): New. > * function.c: Include tree-chkp.h, rtl-chkp.h. > (bounds_parm_data): New. > (use_register_for_decl): Do not registerize decls used for bounds > stores and loads. > (assign_parms_augmented_arg_list): Add bounds of the result > structure pointer as the second argument. > (assign_parm_find_entry_rtl): Mark bounds are never passed on > the stack. > (assign_parm_is_stack_parm): Likewise. > (assign_parm_load_bounds): New. > (assign_bounds): New. > (assign_parms): Load bounds and determine a location for > returned bounds. > (diddle_return_value_1): New. > (diddle_return_value): Handle returned bounds. > * function.h (rtl_data): Add field for returned bounds. > > > diff --git a/gcc/calls.c b/gcc/calls.c > index e1dc8eb..5fbbe9f 100644 > --- a/gcc/calls.c > +++ b/gcc/calls.c > @@ -44,11 +44,14 @@ along with GCC; see the file COPYING3. If not see > #include "tm_p.h" > #include "timevar.h" > #include "sbitmap.h" > +#include "bitmap.h" > #include "langhooks.h" > #include "target.h" > #include "cgraph.h" > #include "except.h" > #include "dbgcnt.h" > +#include "tree-chkp.h" > +#include "rtl-chkp.h" > > /* Like PREFERRED_STACK_BOUNDARY but in units of bytes, not bits. */ > #define STACK_BYTES (PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT) > @@ -76,6 +79,15 @@ struct arg_data > /* If REG is a PARALLEL, this is a copy of VALUE pulled into the correct > form for emit_group_move. */ > rtx parallel_value; > + /* If value is passed in neither reg nor stack, this field holds a number > + of a special slot to be used. */ > + rtx special_slot; > + /* For pointer bounds hold an index of parm bounds are bound to. -1 if > + there is no such pointer. */ > + int pointer_arg; > + /* If pointer_arg refers a structure, then pointer_offset holds an offset > + of a pointer in this structure. */ > + int pointer_offset; > /* If REG was promoted from the actual mode of the argument expression, > indicates whether the promotion is sign- or zero-extended. */ > int unsignedp; > @@ -133,6 +145,7 @@ static void emit_call_1 (rtx, tree, tree, tree, > HOST_WIDE_INT, HOST_WIDE_INT, > HOST_WIDE_INT, rtx, rtx, int, rtx, int, > cumulative_args_t); > static void precompute_register_parameters (int, struct arg_data *, int *); > +static void store_bounds (struct arg_data *, struct arg_data *); > static int store_one_arg (struct arg_data *, rtx, int, int, int); > static void store_unaligned_arguments_into_pseudos (struct arg_data *, int); > static int finalize_must_preallocate (int, int, struct arg_data *, > @@ -396,6 +409,10 @@ emit_call_1 (rtx funexp, tree fntree ATTRIBUTE_UNUSED, > tree fndecl ATTRIBUTE_UNU > && MEM_EXPR (funmem) != NULL_TREE) > set_mem_expr (XEXP (call, 0), MEM_EXPR (funmem)); > > + /* Mark instrumented calls. */ > + if (call && fntree) > + CALL_EXPR_WITH_BOUNDS_P (call) = CALL_WITH_BOUNDS_P (fntree); > + > /* Put the register usage information there. */ > add_function_usage_to (call_insn, call_fusage); > > @@ -1141,18 +1158,84 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > /* First fill in the actual arguments in the ARGS array, splitting > complex arguments if necessary. */ > { > - int j = i; > + int j = i, ptr_arg = -1; > call_expr_arg_iterator iter; > tree arg; > + bitmap slots = NULL; > > if (struct_value_addr_value) > { > args[j].tree_value = struct_value_addr_value; > + > j += inc; > + > + /* If we pass structure address then we need to > + create bounds for it. Since created bounds is > + a call statement, we expand it right here to avoid > + fixing all other places where it may be expanded. */ > + if (CALL_WITH_BOUNDS_P (exp)) > + { > + args[j].value = gen_reg_rtx (targetm.chkp_bound_mode ()); > + args[j].tree_value > + = chkp_make_bounds_for_struct_addr (struct_value_addr_value); > + expand_expr_real (args[j].tree_value, args[j].value, VOIDmode, > + EXPAND_NORMAL, 0, false); > + args[j].pointer_arg = j - inc; > + > + j += inc; > + } > } > FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) > { > tree argtype = TREE_TYPE (arg); > + > + /* Remember last param with pointer and associate it > + with following pointer bounds. */ > + if (CALL_WITH_BOUNDS_P (exp) > + && chkp_type_has_pointer (argtype)) > + { > + if (slots) > + { > + BITMAP_FREE (slots); > + slots = NULL; > + } > + ptr_arg = j; > + if (!BOUNDED_TYPE_P (argtype)) > + slots = chkp_find_bound_slots (argtype); > + } > + else if (POINTER_BOUNDS_TYPE_P (argtype)) > + { > + /* We expect bounds in instrumented calls only. > + Otherwise it is a sign we lost flag due to some optimization > + and may emit call args incorrectly. */ > + gcc_assert (CALL_WITH_BOUNDS_P (exp)); > + > + /* For structures look for the next available pointer. */ > + if (ptr_arg != -1 && slots) > + { > + unsigned bnd_no = bitmap_first_set_bit (slots); > + args[j].pointer_offset = > + bnd_no * POINTER_SIZE / BITS_PER_UNIT; > + > + bitmap_clear_bit (slots, bnd_no); > + > + /* Check we have no more pointers in the structure. */ > + if (bitmap_empty_p (slots)) > + { > + BITMAP_FREE (slots); > + slots = NULL; > + } > + } > + args[j].pointer_arg = ptr_arg; > + > + /* Check we covered all pointers in the previous > + non bounds arg. */ > + if (!slots) > + ptr_arg = -1; > + } > + else > + ptr_arg = -1; > + > if (targetm.calls.split_complex_arg > && argtype > && TREE_CODE (argtype) == COMPLEX_TYPE > @@ -1167,6 +1250,9 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > args[j].tree_value = arg; > j += inc; > } > + > + if (slots) > + BITMAP_FREE (slots); > } > > /* I counts args in order (to be) pushed; ARGPOS counts in order written. > */ > @@ -1302,6 +1388,12 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > args[i].reg = targetm.calls.function_arg (args_so_far, mode, type, > argpos < n_named_args); > > + if (args[i].reg && CONST_INT_P (args[i].reg)) > + { > + args[i].special_slot = args[i].reg; > + args[i].reg = NULL; > + } > + > /* If this is a sibling call and the machine has register windows, the > register window has to be unwinded before calling the routine, so > arguments have to go into the incoming registers. */ > @@ -1335,10 +1427,13 @@ initialize_argument_information (int num_actuals > ATTRIBUTE_UNUSED, > || (args[i].pass_on_stack && args[i].reg != 0)) > *must_preallocate = 1; > > + /* No stack allocation and padding for bounds. */ > + if (POINTER_BOUNDS_P (args[i].tree_value)) > + ; > /* Compute the stack-size of this argument. */ > - if (args[i].reg == 0 || args[i].partial != 0 > - || reg_parm_stack_space > 0 > - || args[i].pass_on_stack) > + else if (args[i].reg == 0 || args[i].partial != 0 > + || reg_parm_stack_space > 0 > + || args[i].pass_on_stack) > locate_and_pad_parm (mode, type, > #ifdef STACK_PARMS_IN_REG_PARM_AREA > 1, > @@ -1553,6 +1648,12 @@ finalize_must_preallocate (int must_preallocate, int > num_actuals, > partial_seen = 1; > else if (partial_seen && args[i].reg == 0) > must_preallocate = 1; > + /* We preallocate in case there are bounds passed > + in the bounds table to have precomputed address > + for bounds association. */ > + else if (POINTER_BOUNDS_P (args[i].tree_value) > + && !args[i].reg) > + must_preallocate = 1; > > if (TYPE_MODE (TREE_TYPE (args[i].tree_value)) == BLKmode > && (TREE_CODE (args[i].tree_value) == CALL_EXPR > @@ -1604,6 +1705,10 @@ compute_argument_addresses (struct arg_data *args, rtx > argblock, int num_actuals > && args[i].partial == 0) > continue; > > + /* Pointer Bounds are never passed on the stack. */ > + if (POINTER_BOUNDS_P (args[i].tree_value)) > + continue; > + > if (CONST_INT_P (offset)) > addr = plus_constant (Pmode, arg_reg, INTVAL (offset)); > else > @@ -2233,6 +2338,8 @@ expand_call (tree exp, rtx target, int ignore) > /* Register in which non-BLKmode value will be returned, > or 0 if no value or if value is BLKmode. */ > rtx valreg; > + /* Register(s) in which bounds are returned. */ > + rtx valbnd = NULL; > /* Address where we should return a BLKmode value; > 0 if value not BLKmode. */ > rtx structure_value_addr = 0; > @@ -2484,7 +2591,7 @@ expand_call (tree exp, rtx target, int ignore) > > structure_value_addr_value = > make_tree (build_pointer_type (TREE_TYPE (funtype)), temp); > - structure_value_addr_parm = 1; > + structure_value_addr_parm = CALL_WITH_BOUNDS_P (exp) ? 2 : 1; > } > > /* Count the arguments and set NUM_ACTUALS. */ > @@ -3003,15 +3110,28 @@ expand_call (tree exp, rtx target, int ignore) > > /* Figure out the register where the value, if any, will come back. */ > valreg = 0; > + valbnd = 0; > if (TYPE_MODE (rettype) != VOIDmode > && ! structure_value_addr) > { > if (pcc_struct_value) > - valreg = hard_function_value (build_pointer_type (rettype), > - fndecl, NULL, (pass == 0)); > + { > + valreg = hard_function_value (build_pointer_type (rettype), > + fndecl, NULL, (pass == 0)); > + if (CALL_WITH_BOUNDS_P (exp)) > + valbnd = targetm.calls. > + chkp_function_value_bounds (build_pointer_type (rettype), > + fndecl, (pass == 0)); > + } > else > - valreg = hard_function_value (rettype, fndecl, fntype, > - (pass == 0)); > + { > + valreg = hard_function_value (rettype, fndecl, fntype, > + (pass == 0)); > + if (CALL_WITH_BOUNDS_P (exp)) > + valbnd = targetm.calls.chkp_function_value_bounds (rettype, > + fndecl, > + (pass == > 0)); > + } > > /* If VALREG is a PARALLEL whose first member has a zero > offset, use that. This is for targets such as m68k that > @@ -3052,7 +3172,10 @@ expand_call (tree exp, rtx target, int ignore) > > for (i = 0; i < num_actuals; i++) > { > - if (args[i].reg == 0 || args[i].pass_on_stack) > + /* Delay bounds until all other args are stored. */ > + if (POINTER_BOUNDS_P (args[i].tree_value)) > + continue; > + else if (args[i].reg == 0 || args[i].pass_on_stack) > { > rtx before_arg = get_last_insn (); > > @@ -3105,6 +3228,17 @@ expand_call (tree exp, rtx target, int ignore) > sibcall_failure = 1; > } > > + /* Store all bounds not passed in registers. */ > + for (i = 0; i < num_actuals; i++) > + { > + if (POINTER_BOUNDS_P (args[i].tree_value) > + && !args[i].reg) > + store_bounds (&args[i], > + args[i].pointer_arg == -1 > + ? NULL > + : &args[args[i].pointer_arg]); > + } > + > /* If we pushed args in forward order, perform stack alignment > after pushing the last arg. */ > if (!PUSH_ARGS_REVERSED && argblock == 0) > @@ -3502,6 +3636,9 @@ expand_call (tree exp, rtx target, int ignore) > > free (stack_usage_map_buf); > > + /* Join result with returned bounds so caller may use them if needed. */ > + target = chkp_join_splitted_slot (target, valbnd); > + > return target; > } > > @@ -4380,6 +4517,68 @@ emit_library_call_value (rtx orgfun, rtx value, > return result; > } > > + > +/* Store pointer bounds argument ARG into Bounds Table entry > + associated with PARM. */ > +static void > +store_bounds (struct arg_data *arg, struct arg_data *parm) > +{ > + rtx slot = NULL, ptr = NULL, addr = NULL; > + > + /* We may pass bounds not associated with any pointer. */ > + if (!parm) > + { > + gcc_assert (arg->special_slot); > + slot = arg->special_slot; > + ptr = const0_rtx; > + } > + /* Find pointer associated with bounds and where it is > + passed. */ > + else > + { > + if (!parm->reg) > + { > + gcc_assert (!arg->special_slot); > + > + addr = adjust_address (parm->stack, Pmode, arg->pointer_offset); > + } > + else if (REG_P (parm->reg)) > + { > + gcc_assert (arg->special_slot); > + slot = arg->special_slot; > + > + if (MEM_P (parm->value)) > + addr = adjust_address (parm->value, Pmode, arg->pointer_offset); > + else if (REG_P (parm->value)) > + ptr = gen_rtx_SUBREG (Pmode, parm->value, arg->pointer_offset); > + else > + { > + gcc_assert (!arg->pointer_offset); > + ptr = parm->value; > + } > + } > + else > + { > + gcc_assert (GET_CODE (parm->reg) == PARALLEL); > + > + gcc_assert (arg->special_slot); > + slot = arg->special_slot; > + > + if (parm->parallel_value) > + ptr = chkp_get_value_with_offs (parm->parallel_value, > + GEN_INT (arg->pointer_offset)); > + else > + gcc_unreachable (); > + } > + } > + > + /* Expand bounds. */ > + if (!arg->value) > + arg->value = expand_normal (arg->tree_value); > + > + targetm.calls.store_bounds_for_arg (ptr, addr, arg->value, slot); > +} > + > /* Store a single argument for a function call > into the register or memory area where it must be passed. > *ARG describes the argument value and where to pass it. > diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c > index b7f6360..1c75586 100644 > --- a/gcc/cfgexpand.c > +++ b/gcc/cfgexpand.c > @@ -73,6 +73,8 @@ along with GCC; see the file COPYING3. If not see > #include "tree-ssa-address.h" > #include "recog.h" > #include "output.h" > +#include "tree-chkp.h" > +#include "rtl-chkp.h" > > /* Some systems use __main in a way incompatible with its use in gcc, in > these > cases use the macros NAME__MAIN to give a quoted symbol and SYMBOL__MAIN > to > @@ -2238,6 +2240,7 @@ expand_call_stmt (gimple stmt) > CALL_FROM_THUNK_P (exp) = gimple_call_from_thunk_p (stmt); > CALL_EXPR_VA_ARG_PACK (exp) = gimple_call_va_arg_pack_p (stmt); > SET_EXPR_LOCATION (exp, gimple_location (stmt)); > + CALL_WITH_BOUNDS_P (exp) = gimple_call_with_bounds_p (stmt); > > /* Ensure RTL is created for debug args. */ > if (decl && DECL_HAS_DEBUG_ARGS_P (decl)) > @@ -3048,11 +3051,12 @@ expand_value_return (rtx val) > from the current function. */ > > static void > -expand_return (tree retval) > +expand_return (tree retval, tree bounds) > { > rtx result_rtl; > rtx val = 0; > tree retval_rhs; > + rtx bounds_rtl; > > /* If function wants no value, give it none. */ > if (TREE_CODE (TREE_TYPE (TREE_TYPE (current_function_decl))) == VOID_TYPE) > @@ -3078,6 +3082,56 @@ expand_return (tree retval) > > result_rtl = DECL_RTL (DECL_RESULT (current_function_decl)); > > + /* Put returned bounds to the right place. */ > + bounds_rtl = DECL_BOUNDS_RTL (DECL_RESULT (current_function_decl)); > + if (bounds_rtl) > + { > + rtx addr, bnd; > + > + if (bounds) > + { > + bnd = expand_normal (bounds); > + targetm.calls.store_returned_bounds (bounds_rtl, bnd); > + } > + else if (REG_P (bounds_rtl)) > + { > + addr = expand_normal (build_fold_addr_expr (retval_rhs)); > + addr = gen_rtx_MEM (Pmode, addr); > + bnd = targetm.calls.load_bounds_for_arg (addr, NULL, NULL); > + targetm.calls.store_returned_bounds (bounds_rtl, bnd); > + } > + else > + { > + int n; > + > + gcc_assert (GET_CODE (bounds_rtl) == PARALLEL); > + > + addr = expand_normal (build_fold_addr_expr (retval_rhs)); > + addr = gen_rtx_MEM (Pmode, addr); > + > + for (n = 0; n < XVECLEN (bounds_rtl, 0); n++) > + { > + rtx offs = XEXP (XVECEXP (bounds_rtl, 0, n), 1); > + rtx slot = XEXP (XVECEXP (bounds_rtl, 0, n), 0); > + rtx from = adjust_address (addr, Pmode, INTVAL (offs)); > + rtx bnd = targetm.calls.load_bounds_for_arg (from, NULL, NULL); > + targetm.calls.store_returned_bounds (slot, bnd); > + } > + } > + } > + else if (chkp_function_instrumented_p (current_function_decl) > + && !BOUNDED_P (retval_rhs) > + && chkp_type_has_pointer (TREE_TYPE (retval_rhs)) > + && TREE_CODE (retval_rhs) != RESULT_DECL) > + { > + rtx addr = expand_normal (build_fold_addr_expr (retval_rhs)); > + addr = gen_rtx_MEM (Pmode, addr); > + > + gcc_assert (MEM_P (result_rtl)); > + > + chkp_copy_bounds_for_stack_parm (result_rtl, addr, TREE_TYPE > (retval_rhs)); > + } > + > /* If we are returning the RESULT_DECL, then the value has already > been stored into it, so we don't have to do anything special. */ > if (TREE_CODE (retval_rhs) == RESULT_DECL) > @@ -3183,7 +3237,7 @@ expand_gimple_stmt_1 (gimple stmt) > if (!op0) > expand_null_return (); > else > - expand_return (op0); > + expand_return (op0, gimple_return_retbnd (stmt)); > break; > > case GIMPLE_ASSIGN: > @@ -5556,6 +5610,9 @@ gimple_expand_cfg (void) > > rtl_profile_for_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun)); > > + if (chkp_function_instrumented_p (current_function_decl)) > + chkp_reset_rtl_bounds (); > + > insn_locations_init (); > if (!DECL_IS_BUILTIN (current_function_decl)) > { > diff --git a/gcc/expr.c b/gcc/expr.c > index 72e4401..40cf67e 100644 > --- a/gcc/expr.c > +++ b/gcc/expr.c > @@ -67,6 +67,8 @@ along with GCC; see the file COPYING3. If not see > #include "params.h" > #include "tree-ssa-address.h" > #include "cfgexpand.h" > +#include "tree-chkp.h" > +#include "rtl-chkp.h" > > /* Decide whether a function's arguments should be processed > from first to last or from last to first. > @@ -5008,9 +5010,14 @@ expand_assignment (tree to, tree from, bool > nontemporal) > || TREE_CODE (to) == SSA_NAME)) > { > rtx value; > + rtx bounds; > > push_temp_slots (); > value = expand_normal (from); > + > + /* Split value and bounds to store them separately. */ > + chkp_split_slot (value, &value, &bounds); > + > if (to_rtx == 0) > to_rtx = expand_expr (to, NULL_RTX, VOIDmode, EXPAND_WRITE); > > @@ -5044,6 +5051,15 @@ expand_assignment (tree to, tree from, bool > nontemporal) > > emit_move_insn (to_rtx, value); > } > + > + /* Store bounds if required. */ > + if (bounds > + && (BOUNDED_P (to) || chkp_type_has_pointer (TREE_TYPE (to)))) > + { > + gcc_assert (MEM_P (to_rtx)); > + chkp_emit_bounds_store (bounds, value, to_rtx); > + } > + > preserve_temp_slots (to_rtx); > pop_temp_slots (); > return; > @@ -5119,7 +5135,7 @@ expand_assignment (tree to, tree from, bool nontemporal) > /* Compute FROM and store the value in the rtx we got. */ > > push_temp_slots (); > - result = store_expr (from, to_rtx, 0, nontemporal); > + result = store_expr_with_bounds (from, to_rtx, 0, nontemporal, to); > preserve_temp_slots (result); > pop_temp_slots (); > return; > @@ -5156,10 +5172,14 @@ emit_storent_insn (rtx to, rtx from) > If CALL_PARAM_P is nonzero, this is a store into a call param on the > stack, and block moves may need to be treated specially. > > - If NONTEMPORAL is true, try using a nontemporal store instruction. */ > + If NONTEMPORAL is true, try using a nontemporal store instruction. > + > + If BTARGET is not NULL then computed bounds of EXP are > + associated with BTARGET. */ > > rtx > -store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) > +store_expr_with_bounds (tree exp, rtx target, int call_param_p, > + bool nontemporal, tree btarget) > { > rtx temp; > rtx alt_rtl = NULL_RTX; > @@ -5180,8 +5200,8 @@ store_expr (tree exp, rtx target, int call_param_p, > bool nontemporal) > part. */ > expand_expr (TREE_OPERAND (exp, 0), const0_rtx, VOIDmode, > call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL); > - return store_expr (TREE_OPERAND (exp, 1), target, call_param_p, > - nontemporal); > + return store_expr_with_bounds (TREE_OPERAND (exp, 1), target, > + call_param_p, nontemporal, btarget); > } > else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode) > { > @@ -5195,13 +5215,13 @@ store_expr (tree exp, rtx target, int call_param_p, > bool nontemporal) > do_pending_stack_adjust (); > NO_DEFER_POP; > jumpifnot (TREE_OPERAND (exp, 0), lab1, -1); > - store_expr (TREE_OPERAND (exp, 1), target, call_param_p, > - nontemporal); > + store_expr_with_bounds (TREE_OPERAND (exp, 1), target, call_param_p, > + nontemporal, btarget); > emit_jump_insn (gen_jump (lab2)); > emit_barrier (); > emit_label (lab1); > - store_expr (TREE_OPERAND (exp, 2), target, call_param_p, > - nontemporal); > + store_expr_with_bounds (TREE_OPERAND (exp, 2), target, call_param_p, > + nontemporal, btarget); > emit_label (lab2); > OK_DEFER_POP; > > @@ -5253,6 +5273,19 @@ store_expr (tree exp, rtx target, int call_param_p, > bool nontemporal) > temp = expand_expr (exp, inner_target, VOIDmode, > call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL); > > + /* Handle bounds returned by call. */ > + if (TREE_CODE (exp) == CALL_EXPR) > + { > + rtx bounds; > + chkp_split_slot (temp, &temp, &bounds); > + if (bounds && btarget) > + { > + gcc_assert (TREE_CODE (btarget) == SSA_NAME); > + rtx tmp = targetm.calls.load_returned_bounds (bounds); > + chkp_set_rtl_bounds (btarget, tmp); > + } > + } > + > /* If TEMP is a VOIDmode constant, use convert_modes to make > sure that we properly convert it. */ > if (CONSTANT_P (temp) && GET_MODE (temp) == VOIDmode) > @@ -5334,6 +5367,19 @@ store_expr (tree exp, rtx target, int call_param_p, > bool nontemporal) > (call_param_p > ? EXPAND_STACK_PARM : EXPAND_NORMAL), > &alt_rtl, false); > + > + /* Handle bounds returned by call. */ > + if (TREE_CODE (exp) == CALL_EXPR) > + { > + rtx bounds; > + chkp_split_slot (temp, &temp, &bounds); > + if (bounds && btarget) > + { > + gcc_assert (TREE_CODE (btarget) == SSA_NAME); > + rtx tmp = targetm.calls.load_returned_bounds (bounds); > + chkp_set_rtl_bounds (btarget, tmp); > + } > + } > } > > /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not > @@ -5498,6 +5544,13 @@ store_expr (tree exp, rtx target, int call_param_p, > bool nontemporal) > > return NULL_RTX; > } > + > +/* Same as store_expr_with_bounds but ignoring bounds of EXP. */ > +rtx > +store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) > +{ > + return store_expr_with_bounds (exp, target, call_param_p, nontemporal, > NULL); > +} > > /* Return true if field F of structure TYPE is a flexible array. */ > > diff --git a/gcc/expr.h b/gcc/expr.h > index 524da67..d06468d 100644 > --- a/gcc/expr.h > +++ b/gcc/expr.h > @@ -432,6 +432,7 @@ extern void expand_assignment (tree, tree, bool); > and storing the value into TARGET. > If SUGGEST_REG is nonzero, copy the value through a register > and return that register, if that is possible. */ > +extern rtx store_expr_with_bounds (tree, rtx, int, bool, tree); > extern rtx store_expr (tree, rtx, int, bool); > > /* Given an rtx that may include add and multiply operations, > diff --git a/gcc/function.c b/gcc/function.c > index a61e475..a08d4ad 100644 > --- a/gcc/function.c > +++ b/gcc/function.c > @@ -63,6 +63,8 @@ along with GCC; see the file COPYING3. If not see > #include "df.h" > #include "params.h" > #include "bb-reorder.h" > +#include "tree-chkp.h" > +#include "rtl-chkp.h" > > /* So we can assign to cfun in this file. */ > #undef cfun > @@ -2082,6 +2084,14 @@ use_register_for_decl (const_tree decl) > if (TREE_ADDRESSABLE (decl)) > return false; > > + /* Decl is implicitly addressible by bound stores and loads > + if it is an aggregate holding bounds. */ > + if (chkp_function_instrumented_p (current_function_decl) > + && TREE_TYPE (decl) > + && !BOUNDED_P (decl) > + && chkp_type_has_pointer (TREE_TYPE (decl))) > + return false; > + > /* Only register-like things go in registers. */ > if (DECL_MODE (decl) == BLKmode) > return false; > @@ -2202,6 +2212,15 @@ struct assign_parm_data_one > BOOL_BITFIELD loaded_in_reg : 1; > }; > > +struct bounds_parm_data > +{ > + assign_parm_data_one parm_data; > + tree bounds_parm; > + tree ptr_parm; > + rtx ptr_entry; > + int bound_no; > +}; > + > /* A subroutine of assign_parms. Initialize ALL. */ > > static void > @@ -2312,6 +2331,23 @@ assign_parms_augmented_arg_list (struct > assign_parm_data_all *all) > fnargs.safe_insert (0, decl); > > all->function_result_decl = decl; > + > + /* If function is instrumented then bounds of the > + passed structure address is the second argument. */ > + if (chkp_function_instrumented_p (fndecl)) > + { > + decl = build_decl (DECL_SOURCE_LOCATION (fndecl), > + PARM_DECL, get_identifier (".result_bnd"), > + pointer_bounds_type_node); > + DECL_ARG_TYPE (decl) = pointer_bounds_type_node; > + DECL_ARTIFICIAL (decl) = 1; > + DECL_NAMELESS (decl) = 1; > + TREE_CONSTANT (decl) = 1; > + > + DECL_CHAIN (decl) = DECL_CHAIN (all->orig_fnargs); > + DECL_CHAIN (all->orig_fnargs) = decl; > + fnargs.safe_insert (1, decl); > + } > } > > /* If the target wants to split complex arguments into scalars, do so. */ > @@ -2452,7 +2488,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all > *all, > it came in a register so that REG_PARM_STACK_SPACE isn't skipped. > In this case, we call FUNCTION_ARG with NAMED set to 1 instead of 0 > as it was the previous time. */ > - in_regs = entry_parm != 0; > + in_regs = (entry_parm != 0) || POINTER_BOUNDS_TYPE_P (data->passed_type); > #ifdef STACK_PARMS_IN_REG_PARM_AREA > in_regs = true; > #endif > @@ -2541,8 +2577,12 @@ static bool > assign_parm_is_stack_parm (struct assign_parm_data_all *all, > struct assign_parm_data_one *data) > { > + /* Bounds are never passed on the stack to keep compatibility > + with not instrumented code. */ > + if (POINTER_BOUNDS_TYPE_P (data->passed_type)) > + return false; > /* Trivially true if we've no incoming register. */ > - if (data->entry_parm == NULL) > + else if (data->entry_parm == NULL) > ; > /* Also true if we're partially in registers and partially not, > since we've arranged to drop the entire argument on the stack. */ > @@ -3348,6 +3388,119 @@ assign_parms_unsplit_complex (struct > assign_parm_data_all *all, > } > } > > +/* Load bounds PARM from bounds table. */ > +static void > +assign_parm_load_bounds (struct assign_parm_data_one *data, > + tree parm, > + rtx entry, > + unsigned bound_no) > +{ > + bitmap_iterator bi; > + unsigned i, offs = 0; > + int bnd_no = -1; > + rtx slot = NULL, ptr = NULL; > + > + if (parm) > + { > + bitmap slots = chkp_find_bound_slots (TREE_TYPE (parm)); > + EXECUTE_IF_SET_IN_BITMAP (slots, 0, i, bi) > + { > + if (bound_no) > + bound_no--; > + else > + { > + bnd_no = i; > + break; > + } > + } > + BITMAP_FREE (slots); > + } > + > + /* We may have bounds not associated with any pointer. */ > + if (bnd_no != -1) > + offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT; > + > + /* Find associated pointer. */ > + if (bnd_no == -1) > + { > + /* If bounds are not associated with any bounds, > + then it is passed in a register or special slot. */ > + gcc_assert (data->entry_parm); > + ptr = const0_rtx; > + } > + else if (MEM_P (entry)) > + slot = adjust_address (entry, Pmode, offs); > + else if (REG_P (entry)) > + ptr = gen_rtx_REG (Pmode, REGNO (entry) + bnd_no); > + else if (GET_CODE (entry) == PARALLEL) > + ptr = chkp_get_value_with_offs (entry, GEN_INT (offs)); > + else > + gcc_unreachable (); > + data->entry_parm = targetm.calls.load_bounds_for_arg (slot, ptr, > + data->entry_parm); > +} > + > +/* Assign RTL expressions to the function's bounds parameters BNDARGS. */ > + > +static void > +assign_bounds (vec<bounds_parm_data> &bndargs, > + struct assign_parm_data_all &all) > +{ > + unsigned i, pass, handled = 0; > + bounds_parm_data *pbdata; > + > + if (!bndargs.exists ()) > + return; > + > + /* We make few passes to store input bounds. Firstly handle bounds > + passed in registers. After that we load bounds passed in special > + slots. Finally we load bounds from Bounds Table. */ > + for (pass = 0; pass < 3; pass++) > + FOR_EACH_VEC_ELT (bndargs, i, pbdata) > + { > + /* Pass 0 => regs only. */ > + if (pass == 0 > + && (!pbdata->parm_data.entry_parm > + || GET_CODE (pbdata->parm_data.entry_parm) != REG)) > + continue; > + /* Pass 1 => slots only. */ > + else if (pass == 1 > + && (!pbdata->parm_data.entry_parm > + || GET_CODE (pbdata->parm_data.entry_parm) == REG)) > + continue; > + /* Pass 2 => BT only. */ > + else if (pass == 2 > + && pbdata->parm_data.entry_parm) > + continue; > + > + if (!pbdata->parm_data.entry_parm > + || GET_CODE (pbdata->parm_data.entry_parm) != REG) > + assign_parm_load_bounds (&pbdata->parm_data, pbdata->ptr_parm, > + pbdata->ptr_entry, pbdata->bound_no); > + > + set_decl_incoming_rtl (pbdata->bounds_parm, > + pbdata->parm_data.entry_parm, false); > + > + if (assign_parm_setup_block_p (&pbdata->parm_data)) > + assign_parm_setup_block (&all, pbdata->bounds_parm, > + &pbdata->parm_data); > + else if (pbdata->parm_data.passed_pointer > + || use_register_for_decl (pbdata->bounds_parm)) > + assign_parm_setup_reg (&all, pbdata->bounds_parm, > + &pbdata->parm_data); > + else > + assign_parm_setup_stack (&all, pbdata->bounds_parm, > + &pbdata->parm_data); > + > + /* Count handled bounds to make sure we miss nothing. */ > + handled++; > + } > + > + gcc_assert (handled == bndargs.length ()); > + > + bndargs.release (); > +} > + > /* Assign RTL expressions to the function's parameters. This may involve > copying them into registers and using those registers as the DECL_RTL. */ > > @@ -3357,7 +3510,11 @@ assign_parms (tree fndecl) > struct assign_parm_data_all all; > tree parm; > vec<tree> fnargs; > - unsigned i; > + unsigned i, bound_no = 0; > + tree last_arg = NULL; > + rtx last_arg_entry = NULL; > + vec<bounds_parm_data> bndargs = vNULL; > + bounds_parm_data bdata; > > crtl->args.internal_arg_pointer > = targetm.calls.internal_arg_pointer (); > @@ -3399,9 +3556,6 @@ assign_parms (tree fndecl) > } > } > > - if (cfun->stdarg && !DECL_CHAIN (parm)) > - assign_parms_setup_varargs (&all, &data, false); > - > /* Find out where the parameter arrives in this function. */ > assign_parm_find_entry_rtl (&all, &data); > > @@ -3411,7 +3565,15 @@ assign_parms (tree fndecl) > assign_parm_find_stack_rtl (parm, &data); > assign_parm_adjust_entry_rtl (&data); > } > - > + if (!POINTER_BOUNDS_TYPE_P (data.passed_type)) > + { > + /* Remember where last non bounds arg was passed in case > + we have to load associated bounds for it from Bounds > + Table. */ > + last_arg = parm; > + last_arg_entry = data.entry_parm; > + bound_no = 0; > + } > /* Record permanently how this parm was passed. */ > if (data.passed_pointer) > { > @@ -3423,20 +3585,63 @@ assign_parms (tree fndecl) > else > set_decl_incoming_rtl (parm, data.entry_parm, false); > > + /* Boudns should be loaded in the particular order to > + have registers allocated correctly. Collect info about > + input bounds and load them later. */ > + if (POINTER_BOUNDS_TYPE_P (data.passed_type)) > + { > + /* Expect bounds in instrumented functions only. */ > + gcc_assert (chkp_function_instrumented_p (fndecl)); > + > + bdata.parm_data = data; > + bdata.bounds_parm = parm; > + bdata.ptr_parm = last_arg; > + bdata.ptr_entry = last_arg_entry; > + bdata.bound_no = bound_no; > + bndargs.safe_push (bdata); > + } > + else > + { > + assign_parm_adjust_stack_rtl (&data); > + > + if (assign_parm_setup_block_p (&data)) > + assign_parm_setup_block (&all, parm, &data); > + else if (data.passed_pointer || use_register_for_decl (parm)) > + assign_parm_setup_reg (&all, parm, &data); > + else > + assign_parm_setup_stack (&all, parm, &data); > + } > + > + if (cfun->stdarg && !DECL_CHAIN (parm)) > + { > + int pretend_bytes = 0; > + > + assign_parms_setup_varargs (&all, &data, false); > + > + if (chkp_function_instrumented_p (fndecl)) > + { > + /* We expect this is the last parm. Otherwise it is wrong > + to assign bounds right now. */ > + gcc_assert (i == (fnargs.length () - 1)); > + assign_bounds (bndargs, all); > + targetm.calls.setup_incoming_vararg_bounds (all.args_so_far, > + data.promoted_mode, > + data.passed_type, > + &pretend_bytes, > + false); > + } > + } > + > /* Update info on where next arg arrives in registers. */ > targetm.calls.function_arg_advance (all.args_so_far, > data.promoted_mode, > data.passed_type, data.named_arg); > > - assign_parm_adjust_stack_rtl (&data); > - > - if (assign_parm_setup_block_p (&data)) > - assign_parm_setup_block (&all, parm, &data); > - else if (data.passed_pointer || use_register_for_decl (parm)) > - assign_parm_setup_reg (&all, parm, &data); > - else > - assign_parm_setup_stack (&all, parm, &data); > + if (POINTER_BOUNDS_TYPE_P (data.passed_type)) > + bound_no++; > } > > + assign_bounds (bndargs, all); > + > if (targetm.calls.split_complex_arg) > assign_parms_unsplit_complex (&all, fnargs); > > @@ -3557,6 +3762,10 @@ assign_parms (tree fndecl) > > real_decl_rtl = targetm.calls.function_value (TREE_TYPE > (decl_result), > fndecl, true); > + if (chkp_function_instrumented_p (fndecl)) > + crtl->return_bnd > + = targetm.calls.chkp_function_value_bounds (TREE_TYPE > (decl_result), > + fndecl, true); > REG_FUNCTION_VALUE_P (real_decl_rtl) = 1; > /* The delay slot scheduler assumes that crtl->return_rtx > holds the hard register containing the return value, not a > @@ -4778,6 +4987,14 @@ expand_function_start (tree subr) > /* Set DECL_REGISTER flag so that expand_function_end will copy the > result to the real return register(s). */ > DECL_REGISTER (DECL_RESULT (subr)) = 1; > + > + if (chkp_function_instrumented_p (current_function_decl)) > + { > + tree return_type = TREE_TYPE (DECL_RESULT (subr)); > + rtx bounds = targetm.calls.chkp_function_value_bounds (return_type, > + subr, 1); > + SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds); > + } > } > > /* Initialize rtx for parameters and local variables. > @@ -4867,14 +5084,11 @@ expand_dummy_function_end (void) > in_dummy_function = false; > } > > -/* Call DOIT for each hard register used as a return value from > - the current function. */ > +/* Helper for diddle_return_value. */ > > void > -diddle_return_value (void (*doit) (rtx, void *), void *arg) > +diddle_return_value_1 (void (*doit) (rtx, void *), void *arg, rtx outgoing) > { > - rtx outgoing = crtl->return_rtx; > - > if (! outgoing) > return; > > @@ -4894,6 +5108,16 @@ diddle_return_value (void (*doit) (rtx, void *), void > *arg) > } > } > > +/* Call DOIT for each hard register used as a return value from > + the current function. */ > + > +void > +diddle_return_value (void (*doit) (rtx, void *), void *arg) > +{ > + diddle_return_value_1 (doit, arg, crtl->return_rtx); > + diddle_return_value_1 (doit, arg, crtl->return_bnd); > +} > + > static void > do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED) > { > diff --git a/gcc/function.h b/gcc/function.h > index 38a0fc4..736bb02 100644 > --- a/gcc/function.h > +++ b/gcc/function.h > @@ -252,6 +252,9 @@ struct GTY(()) rtl_data { > result in a register, current_function_return_rtx will always be > the hard register containing the result. */ > rtx return_rtx; > + /* If nonxero, an RTL expression for the lcoation at which the current > + function returns bounds for its result. */ > + rtx return_bnd; > > /* Vector of initial-value pairs. Each pair consists of a pseudo > register of approprite mode that stores the initial value a hard