On 04 Jun 16:36, Michael Matz wrote:
> Hi,
> 
> On Mon, 2 Jun 2014, Ilya Enkovich wrote:
> 
> > > There is exactly one place (except for the self-recursive ones) where 
> > > you call the new store_expr with a non-null argument for bounds 
> > > target, and it seems to be only necessary for when some sub-expression 
> > > of the RHS is a call.  Can you somehow arrange to move that handling 
> > > to the single place in expand_assignment() so that you don't need to 
> > > change the signature of store_expr?
> > 
> > I see the only nice way to do it - store_expr should return bounds of 
> > expanded exp. Currently it always return NULL_RTX. Does it look better 
> > than a new argument?
> 
> IMHO it does.  That or introducing a new store_expr_with_bounds (with the 
> new argument) and letting store_expr be a wrapper for that, passing the 
> NULL.  Basically anything that avoids adding a new parameter for most of 
> the existing calls to store_expr.
> 
> 
> Ciao,
> Michael.

Here is an updated version using store_expr_with_bounds and store_expr as a 
wrapper for it.

Bootstrapped and tested on linux-x86_64.

Thanks,
Ilya
--
gcc/

2014-06-05  Ilya Enkovich  <ilya.enkov...@intel.com>

        * calls.c: Include tree-chkp.h, rtl-chkp.h, bitmap.h.
        (arg_data): Add fields special_slot, pointer_arg and
        pointer_offset.
        (store_bounds): New.
        (emit_call_1): Propagate instrumentation flag for CALL.
        (initialize_argument_information): Compute pointer_arg,
        pointer_offset and special_slot for pointer bounds arguments.
        (finalize_must_preallocate): Preallocate when storing bounds
        in bounds table.
        (compute_argument_addresses): Skip pointer bounds.
        (expand_call): Store bounds into tables separately.  Return
        result joined with resulting bounds.
        * cfgexpand.c: Include tree-chkp.h, rtl-chkp.h.
        (expand_call_stmt): Propagate bounds flag for CALL_EXPR.
        (expand_return): Add returned bounds arg.  Handle returned bounds.
        (expand_gimple_stmt_1): Adjust to new expand_return signature.
        (gimple_expand_cfg): Reset rtx bounds map.
        * expr.c: Include tree-chkp.h, rtl-chkp.h.
        (expand_assignment): Handle returned bounds.
        (store_expr_with_bounds): New.  Replaces store_expr with new bounds
        target argument.  Handle bounds returned by calls.
        (store_expr): Now wraps store_expr_with_bounds.
        * expr.h (store_expr_with_bounds): New.
        * function.c: Include tree-chkp.h, rtl-chkp.h.
        (bounds_parm_data): New.
        (use_register_for_decl): Do not registerize decls used for bounds
        stores and loads.
        (assign_parms_augmented_arg_list): Add bounds of the result
        structure pointer as the second argument.
        (assign_parm_find_entry_rtl): Mark bounds are never passed on
        the stack.
        (assign_parm_is_stack_parm): Likewise.
        (assign_parm_load_bounds): New.
        (assign_bounds): New.
        (assign_parms): Load bounds and determine a location for
        returned bounds.
        (diddle_return_value_1): New.
        (diddle_return_value): Handle returned bounds.
        * function.h (rtl_data): Add field for returned bounds.


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

Reply via email to