diff mbox

[MPX,2/X] Pointers Checker [12/25] Expand bounded params

Message ID 20131118100647.GF21297@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Nov. 18, 2013, 10:06 a.m. UTC
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.enkovich@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 mbox

Patch

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, &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],