@@ -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)
@@ -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))
{
@@ -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
@@ -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;
@@ -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.
@@ -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. */
@@ -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
@@ -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],