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

Reply via email to