Hi, Here is a patch to expand bounded arguments for calls, input bounds for bounded params and returned bounds.
Thanks, Ilya -- 2013-11-15 Ilya Enkovich <ilya.enkov...@intel.com> * calls.c: Include tree-chkp.h, rtl-chkp.h. (arg_data): Add fields for bounds information and to store value pushed to the stack. (emit_call_1): Propagate instrumentation flag for CALL. (precompute_register_parameters): Expand bounds of the arg. (initialize_argument_information): Fill bounds information. (load_register_parameters): Load passed bounds. (expand_call): Handle passed and returned bounds. (emit_library_call_value_1): Filter out returned bounds. (store_one_arg): Store bounds of arg. * cfgexpand.c: Include tree-chkp.h, rtl-chkp.h. (expand_call_stmt): Propagate instrumentation flag for CALL_EXPR. (expand_return): Handle returned bounds. (expand_gimple_stmt_1): Adjust to new expand_return signature. (gimple_expand_cfg): Reset rtx bounds map. * explow.c: Include rtl-chkp.h. (hard_function_value): Handle returned bounds. * expr.h (store_expr): Add param for bounds target. * expr.c: Include tree-chkp.h, rtl-chkp.h. (expand_assignment): Handle returned bounds. (store_expr): Likewise. (store_constructor): Adjust to new store_expr signature. (store_field): Likewise. (expand_expr_real_2): Likewise. (expand_expr_real_1): Likewise. * tree-outof-ssa.c (insert_value_copy_on_edge): Adjust to new store_expr signature. * function.c: Include tree-chkp.h, rtl-chkp.h. (aggregate_value_p): Handle returned bounds. (use_register_for_decl): Do not registerize decls used for bounds stores and loads. (assign_parm_data_one): Add field for bounds. (assign_parm_find_entry_rtl): Fill bounds info. (assign_parms): Initialize input bounds for args. (expand_function_start): Handle returned bounds. (diddle_return_value_1): New. (diddle_return_value): Handle returned bounds. (expand_function_end): Likewise. * function.h (rtl_data): Add field for returned bounds. diff --git a/gcc/calls.c b/gcc/calls.c index 4dcdb27..7ebf310 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -40,6 +40,8 @@ along with GCC; see the file COPYING3. If not see #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) @@ -50,12 +52,20 @@ struct arg_data { /* Tree node for this argument. */ tree tree_value; + /* Bounds tree node for this argument. */ + tree bounds_value; + /* Bounds RTL for this argument. */ + rtx bounds; + /* Slot to be used to pass bounds. */ + rtx bounds_slot; /* Mode for value; TYPE_MODE unless promoted. */ enum machine_mode mode; /* Current RTL value for argument, or 0 if it isn't precomputed. */ rtx value; /* Initially-compute RTL value for argument; only for const functions. */ rtx initial_value; + /* Pushed value. */ + rtx pushed_value; /* Register to pass this argument in, 0 if passed on stack, or an PARALLEL if the arg is to be copied into multiple non-contiguous registers. */ @@ -387,6 +397,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); @@ -865,6 +879,59 @@ precompute_register_parameters (int num_actuals, struct arg_data *args, && targetm.small_register_classes_for_mode_p (args[i].mode)) || optimize)) args[i].value = copy_to_mode_reg (args[i].mode, args[i].value); + + /* Expand argument bounds if any. */ + if (args[i].bounds_value) + { + /* If bounds_value is a list then we pass bounds + for a structure. TREE_VALUE of each node holds + base structure address and TREE_PURPOSE holds + corresponding offset of the pointer field in + structure. */ + if (TREE_CODE (args[i].bounds_value) == TREE_LIST) + { + tree node = args[i].bounds_value; + unsigned bnd_num = list_length (args[i].bounds_value); + rtx *bounds = XALLOCAVEC (rtx, bnd_num); + unsigned bnd_no = 0; + tree base_addr = TREE_VALUE (node); + rtx base = expand_normal (base_addr); + + /* Expand all nodes in the list. */ + while (node) + { + tree bnd_offs = TREE_PURPOSE (node); + HOST_WIDE_INT offs = TREE_INT_CST_LOW (bnd_offs); + rtx field_addr = plus_constant (Pmode, base, offs); + rtx ptr = gen_rtx_MEM (Pmode, field_addr); + rtx bnd_expr + = targetm.calls.load_bounds_for_arg (ptr, ptr, NULL); + + bounds[bnd_no] = gen_rtx_EXPR_LIST (VOIDmode, + bnd_expr, + GEN_INT (offs)); + + node = TREE_CHAIN (node); + bnd_no++; + } + + /* Make PARALLEL holding all expanded bounds. */ + args[i].bounds = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (bnd_num, + bounds)); + } + /* We have to make a temporary for bounds if there is a bndmk. */ + else if (TREE_CODE (args[i].bounds_value) == CALL_EXPR) + { + args[i].bounds = gen_reg_rtx (targetm.chkp_bound_mode ()); + expand_expr_real (args[i].bounds_value, args[i].bounds, + VOIDmode, EXPAND_NORMAL, 0); + } + else + args[i].bounds = expand_normal (args[i].bounds_value); + } + else + args[i].bounds = NULL; } } @@ -1129,11 +1196,47 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, if (struct_value_addr_value) { args[j].tree_value = struct_value_addr_value; + + /* If we pass structure address then we need to + create bounds for it. */ + if (CALL_WITH_BOUNDS_P (exp)) + args[j].bounds_value + = chkp_make_bounds_for_struct_addr (struct_value_addr_value); + j += inc; } FOR_EACH_CALL_EXPR_ARG (arg, iter, exp) { tree argtype = TREE_TYPE (arg); + + /* For instrumented calls get all bounds passed for arg. */ + if (CALL_WITH_BOUNDS_P (exp)) + { + /* For bounded types bounds are passed via + bounds binding calls. */ + if (BOUNDED_TYPE_P (argtype)) + args[j].bounds_value = chkp_get_call_arg_bounds (arg); + /* For structures we create a list holding structure address + and offset of pointer in that structure. */ + else if (chkp_type_has_pointer (argtype)) + { + tree base_addr = build_fold_addr_expr (arg); + vec<bool> struct_bounds = chkp_find_bound_slots (argtype); + tree bounds_val = NULL; + HOST_WIDE_INT bnd_no, offs; + for (bnd_no = 0; bnd_no < struct_bounds.length (); bnd_no++) + if (struct_bounds[bnd_no]) + { + offs = bnd_no * POINTER_SIZE / BITS_PER_UNIT; + bounds_val = tree_cons (build_int_cst (NULL, offs), + base_addr, + bounds_val); + } + struct_bounds.release (); + args[j].bounds_value = bounds_val; + } + } + if (targetm.calls.split_complex_arg && argtype && TREE_CODE (argtype) == COMPLEX_TYPE @@ -1252,7 +1355,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, else copy = assign_temp (type, 1, 0); - store_expr (args[i].tree_value, copy, 0, false); + store_expr (args[i].tree_value, copy, 0, false, NULL); /* Just change the const function to pure and then let the next test clear the pure based on @@ -1282,6 +1385,7 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED, args[i].reg = targetm.calls.function_arg (args_so_far, mode, type, argpos < n_named_args); + chkp_split_slot (args[i].reg, &args[i].reg, &args[i].bounds_slot); /* If this is a sibling call and the machine has register windows, the register window has to be unwinded before calling the routine, so @@ -1992,6 +2096,70 @@ load_register_parameters (struct arg_data *args, int num_actuals, TYPE_MODE (TREE_TYPE (args[i].tree_value))); else if (nregs > 0) use_regs (call_fusage, REGNO (reg), nregs); + + /* Handle passed bounds. */ + if (args[i].bounds_slot && args[i].bounds) + { + if (GET_CODE (args[i].bounds_slot) == PARALLEL) + { + HOST_WIDE_INT n; + + gcc_assert (GET_CODE (args[i].bounds) == PARALLEL); + + for (n = 0; n < XVECLEN (args[i].bounds_slot, 0); n++) + { + rtx reg = XEXP (XVECEXP (args[i].bounds_slot, 0, n), 0); + rtx offs = XEXP (XVECEXP (args[i].bounds_slot, 0, n), 1); + rtx bnd = chkp_get_value_with_offs (args[i].bounds, offs); + + /* For vararg functions it is possible we have + slot for bounds but do not have bounds. */ + if (bnd) + { + if (REG_P (reg)) + { + emit_move_insn (reg, bnd); + use_reg (call_fusage, reg); + } + else + { + rtx ptr = chkp_get_value_with_offs (args[i].reg, + offs); + targetm.calls.store_bounds_for_arg (ptr, ptr, + bnd, reg); + } + } + } + } + else + { + rtx bnd = args[i].bounds; + + /* We may have PARALLEL in bounds if handle structure + fitting single register. */ + if (GET_CODE (bnd) == PARALLEL) + { + gcc_assert (XVECLEN (bnd, 0) == 1); + gcc_assert (INTVAL (XEXP (XVECEXP (bnd, 0, 0), 1)) == 0); + bnd = XEXP (XVECEXP (bnd, 0, 0), 0); + } + + gcc_assert (REG_P (args[i].bounds_slot) + || CONST_INT_P (args[i].bounds_slot)); + gcc_assert (REG_P (args[i].reg)); + + if (REG_P (args[i].bounds_slot)) + { + emit_move_insn (args[i].bounds_slot, bnd); + use_reg (call_fusage, args[i].bounds_slot); + } + else + targetm.calls.store_bounds_for_arg (args[i].reg, + args[i].reg, + bnd, + args[i].bounds_slot); + } + } } } } @@ -2214,6 +2382,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; @@ -2995,6 +3165,10 @@ expand_call (tree exp, rtx target, int ignore) valreg = hard_function_value (rettype, fndecl, fntype, (pass == 0)); + /* Returned bound registers are handled later. Slit them right now and + join back before rerurn. */ + chkp_split_slot (valreg, &valreg, &valbnd); + /* If VALREG is a PARALLEL whose first member has a zero offset, use that. This is for targets such as m68k that return the same value in multiple places. */ @@ -3476,6 +3650,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; } @@ -3598,6 +3775,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, rtx call_fusage = 0; rtx mem_value = 0; rtx valreg; + rtx valbnd; int pcc_struct_value = 0; int struct_value_size = 0; int flags; @@ -4236,6 +4414,9 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value, pop_temp_slots (); + /* Returned bound registers are handled later. */ + chkp_split_slot (valreg, &valreg, &valbnd); + /* Copy the value to the right place. */ if (outmode != VOIDmode && retval) { @@ -4582,7 +4763,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* Unless this is a partially-in-register argument, the argument is now in the stack. */ if (partial == 0) - arg->value = arg->stack; + { + arg->pushed_value = arg->value; + arg->value = arg->stack; + } } else { @@ -4693,7 +4877,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, it's properly aligned for word-by-word copying or something like that. It's not clear that this is always correct. */ if (partial == 0) - arg->value = arg->stack_slot; + { + arg->pushed_value = arg->value; + arg->value = arg->stack_slot; + } } if (arg->reg && GET_CODE (arg->reg) == PARALLEL) @@ -4704,6 +4891,59 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, int_size_in_bytes (type)); } + /* Store computed bounds for argument. */ + if (arg->bounds_value) + { + tree bounds = arg->bounds_value; + + if (TREE_CODE (bounds) == TREE_LIST) + { + tree base_addr = TREE_VALUE (bounds); + rtx base = expand_normal (base_addr); + + while (bounds) + { + HOST_WIDE_INT bnd_offs + = TREE_INT_CST_LOW (TREE_PURPOSE (bounds)); + rtx slot = arg->stack_slot + ? arg->stack_slot + : gen_rtx_MEM (Pmode, stack_pointer_rtx); + rtx field_addr = plus_constant (Pmode, base, bnd_offs); + rtx ptr = gen_rtx_MEM (Pmode, field_addr); + rtx bnd = targetm.calls.load_bounds_for_arg (ptr, ptr, NULL); + rtx ptr_slot; + + ptr = arg->pushed_value ? arg->pushed_value : arg->value; + ptr = adjust_address (ptr, Pmode, bnd_offs); + + ptr_slot = adjust_address (slot, Pmode, bnd_offs); + + targetm.calls.store_bounds_for_arg (ptr, ptr_slot, bnd, NULL_RTX); + + bounds = TREE_CHAIN (bounds); + } + } + else + { + rtx ptr = arg->pushed_value ? arg->pushed_value : arg->value; + rtx slot = arg->stack_slot + ? arg->stack_slot + : gen_rtx_MEM (Pmode, stack_pointer_rtx); + rtx bnd; + + if (TREE_CODE (bounds) == CALL_EXPR) + { + bnd = gen_reg_rtx (targetm.chkp_bound_mode ()); + expand_expr_real (bounds, bnd, VOIDmode, EXPAND_NORMAL, 0); + } + else + bnd = expand_normal (bounds); + + targetm.calls.store_bounds_for_arg (ptr, slot, + bnd, NULL_RTX); + } + } + /* Mark all slots this store used. */ if (ACCUMULATE_OUTGOING_ARGS && !(flags & ECF_SIBCALL) && argblock && ! variable_size && arg->stack) diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c index 124a4b8..479d12c 100644 --- a/gcc/cfgexpand.c +++ b/gcc/cfgexpand.c @@ -62,6 +62,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 @@ -2211,6 +2213,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)) @@ -3020,11 +3023,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) @@ -3050,6 +3054,57 @@ 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); + gcc_assert (REG_P (bounds_rtl)); + emit_move_insn (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); + emit_move_insn (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 reg = XEXP (XVECEXP (bounds_rtl, 0, n), 0); + rtx offs = XEXP (XVECEXP (bounds_rtl, 0, n), 1); + rtx from = adjust_address (addr, Pmode, INTVAL (offs)); + rtx bnd = targetm.calls.load_bounds_for_arg (from, NULL, NULL); + emit_move_insn (reg, 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) @@ -3159,7 +3214,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: @@ -5518,6 +5573,9 @@ gimple_expand_cfg (void) rtl_profile_for_bb (ENTRY_BLOCK_PTR); + 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/explow.c b/gcc/explow.c index 5277f1e..825550c 100644 --- a/gcc/explow.c +++ b/gcc/explow.c @@ -40,6 +40,7 @@ along with GCC; see the file COPYING3. If not see #include "target.h" #include "common/common-target.h" #include "output.h" +#include "rtl-chkp.h" static rtx break_out_memory_refs (rtx); @@ -1871,10 +1872,14 @@ rtx hard_function_value (const_tree valtype, const_tree func, const_tree fntype, int outgoing ATTRIBUTE_UNUSED) { - rtx val; + rtx val, bnd; val = targetm.calls.function_value (valtype, func ? func : fntype, outgoing); + /* Split bound registers to process non-bound values separately. + Join back after processing. */ + chkp_split_slot (val, &val, &bnd); + if (REG_P (val) && GET_MODE (val) == BLKmode) { @@ -1899,7 +1904,7 @@ hard_function_value (const_tree valtype, const_tree func, const_tree fntype, PUT_MODE (val, tmpmode); } - return val; + return chkp_join_splitted_slot (val, bnd); } /* Return an rtx representing the register or memory location diff --git a/gcc/expr.c b/gcc/expr.c index 28b4332..093c903 100644 --- a/gcc/expr.c +++ b/gcc/expr.c @@ -57,6 +57,8 @@ along with GCC; see the file COPYING3. If not see #include "target-globals.h" #include "params.h" #include "tree-ssa-address.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. @@ -4793,11 +4795,11 @@ expand_assignment (tree to, tree from, bool nontemporal) if (COMPLEX_MODE_P (TYPE_MODE (TREE_TYPE (from))) && bitpos == 0 && bitsize == mode_bitsize) - result = store_expr (from, to_rtx, false, nontemporal); + result = store_expr (from, to_rtx, false, nontemporal, NULL); else if (bitsize == mode_bitsize / 2 && (bitpos == 0 || bitpos == mode_bitsize / 2)) result = store_expr (from, XEXP (to_rtx, bitpos != 0), false, - nontemporal); + nontemporal, NULL); else if (bitpos + bitsize <= mode_bitsize / 2) result = store_field (XEXP (to_rtx, 0), bitsize, bitpos, bitregion_start, bitregion_end, @@ -4884,9 +4886,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); @@ -4920,6 +4927,17 @@ 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)); + gcc_assert (!CONST_INT_P (bounds)); + + chkp_emit_bounds_store (bounds, value, to_rtx); + } + preserve_temp_slots (to_rtx); pop_temp_slots (); return; @@ -4995,7 +5013,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 (from, to_rtx, 0, nontemporal, to); preserve_temp_slots (result); pop_temp_slots (); return; @@ -5032,10 +5050,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 TARGET are + associated with BTARGET. */ rtx -store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) +store_expr (tree exp, rtx target, int call_param_p, bool nontemporal, + tree btarget) { rtx temp; rtx alt_rtl = NULL_RTX; @@ -5057,7 +5079,7 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) 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); + nontemporal, btarget); } else if (TREE_CODE (exp) == COND_EXPR && GET_MODE (target) == BLKmode) { @@ -5072,12 +5094,12 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) NO_DEFER_POP; jumpifnot (TREE_OPERAND (exp, 0), lab1, -1); store_expr (TREE_OPERAND (exp, 1), target, call_param_p, - nontemporal); + nontemporal, btarget); emit_jump_insn (gen_jump (lab2)); emit_barrier (); emit_label (lab1); store_expr (TREE_OPERAND (exp, 2), target, call_param_p, - nontemporal); + nontemporal, btarget); emit_label (lab2); OK_DEFER_POP; @@ -5129,6 +5151,21 @@ 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); + gcc_assert (REG_P (bounds)); + rtx tmp = gen_reg_rtx (targetm.chkp_bound_mode ()); + emit_move_insn (tmp, 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) @@ -5210,6 +5247,21 @@ store_expr (tree exp, rtx target, int call_param_p, bool nontemporal) (call_param_p ? EXPAND_STACK_PARM : EXPAND_NORMAL), &alt_rtl); + + /* 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); + gcc_assert (REG_P (bounds)); + rtx tmp = gen_reg_rtx (targetm.chkp_bound_mode ()); + emit_move_insn (tmp, bounds); + chkp_set_rtl_bounds (btarget, tmp); + } + } } /* If TEMP is a VOIDmode constant and the mode of the type of EXP is not @@ -6098,7 +6150,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) VAR_DECL, NULL_TREE, domain); index_r = gen_reg_rtx (promote_decl_mode (index, NULL)); SET_DECL_RTL (index, index_r); - store_expr (lo_index, index_r, 0, false); + store_expr (lo_index, index_r, 0, false, NULL); /* Build the head of the loop. */ do_pending_stack_adjust (); @@ -6125,7 +6177,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) store_constructor (value, xtarget, cleared, bitsize / BITS_PER_UNIT); else - store_expr (value, xtarget, 0, false); + store_expr (value, xtarget, 0, false, NULL); /* Generate a conditional jump to exit the loop. */ exit_cond = build2 (LT_EXPR, integer_type_node, @@ -6168,7 +6220,7 @@ store_constructor (tree exp, rtx target, int cleared, HOST_WIDE_INT size) expand_normal (position), highest_pow2_factor (position)); xtarget = adjust_address (xtarget, mode, 0); - store_expr (value, xtarget, 0, false); + store_expr (value, xtarget, 0, false, NULL); } else { @@ -6362,7 +6414,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, /* We're storing into a struct containing a single __complex. */ gcc_assert (!bitpos); - return store_expr (exp, target, 0, nontemporal); + return store_expr (exp, target, 0, nontemporal, NULL); } /* If the structure is in a register or if the component @@ -6515,7 +6567,7 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos, if (!MEM_KEEP_ALIAS_SET_P (to_rtx) && MEM_ALIAS_SET (to_rtx) != 0) set_mem_alias_set (to_rtx, alias_set); - return store_expr (exp, to_rtx, 0, nontemporal); + return store_expr (exp, to_rtx, 0, nontemporal, NULL); } } @@ -7993,7 +8045,7 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, store_expr (treeop0, adjust_address (target, TYPE_MODE (valtype), 0), modifier == EXPAND_STACK_PARM, - false); + false, NULL); else { @@ -9047,14 +9099,14 @@ expand_expr_real_2 (sepops ops, rtx target, enum machine_mode tmode, jumpifnot (treeop0, op0, -1); store_expr (treeop1, temp, modifier == EXPAND_STACK_PARM, - false); + false, NULL); emit_jump_insn (gen_jump (op1)); emit_barrier (); emit_label (op0); store_expr (treeop2, temp, modifier == EXPAND_STACK_PARM, - false); + false, NULL); emit_label (op1); OK_DEFER_POP; @@ -9580,7 +9632,7 @@ expand_expr_real_1 (tree exp, rtx target, enum machine_mode tmode, { temp = assign_stack_temp (DECL_MODE (base), GET_MODE_SIZE (DECL_MODE (base))); - store_expr (base, temp, 0, false); + store_expr (base, temp, 0, false, NULL); temp = adjust_address (temp, BLKmode, offset); set_mem_size (temp, int_size_in_bytes (type)); return temp; diff --git a/gcc/expr.h b/gcc/expr.h index 2923b81..803a231 100644 --- a/gcc/expr.h +++ b/gcc/expr.h @@ -419,7 +419,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 (tree, rtx, int, bool); +extern rtx store_expr (tree, rtx, int, bool, tree); /* Given an rtx that may include add and multiply operations, generate them as insns and return a pseudo-reg containing the value. diff --git a/gcc/function.c b/gcc/function.c index eddffdb..e04f1f6 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -62,6 +62,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 @@ -1990,7 +1992,7 @@ aggregate_value_p (const_tree exp, const_tree fntype) { const_tree type = (TYPE_P (exp)) ? exp : TREE_TYPE (exp); int i, regno, nregs; - rtx reg; + rtx reg, bnd; if (fntype) switch (TREE_CODE (fntype)) @@ -2050,6 +2052,9 @@ aggregate_value_p (const_tree exp, const_tree fntype) the value in; if not, we must return it in memory. */ reg = hard_function_value (type, 0, fntype, 0); + /* Do not care about returned bounds here. */ + chkp_split_slot (reg, ®, &bnd); + /* If we have something other than a REG (e.g. a PARALLEL), then assume it is OK. */ if (!REG_P (reg)) @@ -2081,6 +2086,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; @@ -2190,6 +2203,7 @@ struct assign_parm_data_one tree passed_type; rtx entry_parm; rtx stack_parm; + rtx bound_parm; enum machine_mode nominal_mode; enum machine_mode passed_mode; enum machine_mode promoted_mode; @@ -2424,7 +2438,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, struct assign_parm_data_one *data) { HOST_WIDE_INT pretend_bytes = 0; - rtx entry_parm; + rtx entry_parm, bound_parm = 0; bool in_regs; if (data->promoted_mode == VOIDmode) @@ -2437,6 +2451,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, data->promoted_mode, data->passed_type, data->named_arg); + chkp_split_slot (entry_parm, &entry_parm, &bound_parm); if (entry_parm == 0) data->promoted_mode = data->passed_mode; @@ -2531,6 +2546,7 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all, data->locate.offset.constant += pretend_bytes; data->entry_parm = entry_parm; + data->bound_parm = bound_parm; } /* A subroutine of assign_parms. If there is actually space on the stack @@ -3411,6 +3427,59 @@ assign_parms (tree fndecl) assign_parm_adjust_entry_rtl (&data); } + /* Find out where bounds for parameter are. + Load them if required and associate them with parm. */ + if (chkp_function_instrumented_p (fndecl) + && (data.bound_parm || BOUNDED_TYPE_P (data.passed_type))) + { + if (!data.bound_parm || CONST_INT_P (data.bound_parm)) + data.bound_parm + = targetm.calls.load_bounds_for_arg (data.entry_parm, + NULL, + data.bound_parm); + else if (GET_CODE (data.bound_parm) == PARALLEL) + { + rtx *tmps = XALLOCAVEC (rtx, XVECLEN (data.bound_parm, 0)); + int n; + + for (n = 0; n < XVECLEN (data.bound_parm, 0); n++) + { + rtx reg = XEXP (XVECEXP (data.bound_parm, 0, n), 0); + rtx offs = XEXP (XVECEXP (data.bound_parm, 0, n), 1); + + if (!REG_P (reg)) + { + rtx p = chkp_get_value_with_offs (data.entry_parm, offs); + reg = targetm.calls.load_bounds_for_arg (p, NULL, reg); + } + + tmps[n] = gen_rtx_EXPR_LIST (VOIDmode, reg, offs); + } + + data.bound_parm + = gen_rtx_PARALLEL (VOIDmode, + gen_rtvec_v (XVECLEN (data.bound_parm, 0), + tmps)); + } + else if (!AGGREGATE_TYPE_P (data.passed_type)) + { + int align = + STACK_SLOT_ALIGNMENT (pointer_bounds_type_node, + targetm.chkp_bound_mode (), + TYPE_ALIGN (pointer_bounds_type_node)); + rtx stack + = assign_stack_local (targetm.chkp_bound_mode (), + GET_MODE_SIZE (targetm.chkp_bound_mode ()), + align); + + gcc_assert (REG_P (data.bound_parm)); + emit_move_insn (stack, data.bound_parm); + + data.bound_parm = stack; + } + } + SET_DECL_BOUNDS_RTL (parm, data.bound_parm); + /* Record permanently how this parm was passed. */ if (data.passed_pointer) { @@ -3434,6 +3503,42 @@ assign_parms (tree fndecl) assign_parm_setup_reg (&all, parm, &data); else assign_parm_setup_stack (&all, parm, &data); + + /* If parm decl is addressable then we have to store its + bounds. */ + if (chkp_function_instrumented_p (fndecl) + && TREE_ADDRESSABLE (parm) + && data.bound_parm) + { + rtx mem = validize_mem (data.stack_parm); + + if (GET_CODE (data.bound_parm) == PARALLEL) + { + int n; + + for (n = 0; n < XVECLEN (data.bound_parm, 0); n++) + { + rtx bnd = XEXP (XVECEXP (data.bound_parm, 0, n), 0); + rtx offs = XEXP (XVECEXP (data.bound_parm, 0, n), 1); + rtx slot = adjust_address (mem, Pmode, INTVAL (offs)); + + if (!REG_P (bnd)) + { + rtx tmp = gen_reg_rtx (targetm.chkp_bound_mode ()); + emit_move_insn (tmp, bnd); + bnd = tmp; + } + + targetm.calls.store_bounds_for_arg (slot, slot, bnd, NULL); + } + } + else + { + rtx slot = adjust_address (mem, Pmode, 0); + targetm.calls.store_bounds_for_arg (slot, slot, + data.bound_parm, NULL); + } + } } if (targetm.calls.split_complex_arg) @@ -3556,6 +3661,7 @@ assign_parms (tree fndecl) real_decl_rtl = targetm.calls.function_value (TREE_TYPE (decl_result), fndecl, true); + chkp_split_slot (real_decl_rtl, &real_decl_rtl, &crtl->return_bnd); 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 @@ -4760,6 +4866,9 @@ expand_function_start (tree subr) figure out what the mode of the eventual return register will actually be, and use that. */ rtx hard_reg = hard_function_value (return_type, subr, 0, 1); + rtx bounds; + + chkp_split_slot (hard_reg, &hard_reg, &bounds); /* Structures that are returned in registers are not aggregate_value_p, so we may see a PARALLEL or a REG. */ @@ -4771,6 +4880,7 @@ expand_function_start (tree subr) gcc_assert (GET_CODE (hard_reg) == PARALLEL); SET_DECL_RTL (DECL_RESULT (subr), gen_group_rtx (hard_reg)); } + SET_DECL_BOUNDS_RTL (DECL_RESULT (subr), bounds); } /* Set DECL_REGISTER flag so that expand_function_end will copy the @@ -4865,14 +4975,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; @@ -4892,6 +4999,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) { @@ -5138,6 +5255,11 @@ expand_function_end (void) outgoing = targetm.calls.function_value (build_pointer_type (type), current_function_decl, true); + chkp_split_slot (outgoing, &outgoing, &crtl->return_bnd); + + if (chkp_function_instrumented_p (current_function_decl) + && GET_CODE (outgoing) == PARALLEL) + outgoing = XEXP (XVECEXP (outgoing, 0, 0), 0); /* Mark this as a function return value so integrate will delete the assignment and USE below when inlining this function. */ diff --git a/gcc/function.h b/gcc/function.h index 9bb6ff0..303145b 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 diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c index eb11c88..665aa1a 100644 --- a/gcc/tree-outof-ssa.c +++ b/gcc/tree-outof-ssa.c @@ -307,7 +307,7 @@ insert_value_copy_on_edge (edge e, int dest, tree src, source_location locus) else if (src_mode == BLKmode) { x = SA.partition_to_pseudo[dest]; - store_expr (src, x, 0, false); + store_expr (src, x, 0, false, NULL); } else x = expand_expr (src, SA.partition_to_pseudo[dest],