diff mbox

[Pointer,Bounds,Checker,22/x] Inline

Message ID 20140818153557.GE29976@msticlxl57.ims.intel.com
State New
Headers show

Commit Message

Ilya Enkovich Aug. 18, 2014, 3:35 p.m. UTC
On 06 Jun 11:59, Ilya Enkovich wrote:
> 2014-06-03 13:07 GMT+04:00 Richard Biener <richard.guenther@gmail.com>:
> > On Mon, Jun 2, 2014 at 5:56 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
> >> +
> >> +      /* If indirect call has following BUILT_IN_CHKP_BNDRET
> >> +        call then we need to make it's copy for the direct
> >> +        call.  */
> >> +      if (iretbnd_stmt)
> >> +       {
> >> +         if (gimple_call_lhs (iretbnd_stmt))
> >> +           {
> >> +             gimple copy;
> >> +
> >> +             gimple_set_vdef (iretbnd_stmt, NULL_TREE);
> >> +             gimple_set_vuse (iretbnd_stmt, NULL_TREE);
> >> +             update_stmt (iretbnd_stmt);
> >
> > This looks bogus - what are you trying to workaround?
> 
> I did not try to workaround something. I just looked at how this
> function makes a copy for a call and repeated the process for retbnd
> call.
> 
> >
> > Richard.
> >
> >> +             result = gimple_call_lhs (iretbnd_stmt);
> >> +             phi = create_phi_node (result, join_bb);
> >> +
> >> +             copy = gimple_copy (iretbnd_stmt);
> >> +             gimple_call_set_arg (copy, 0,
> >> +                                  gimple_call_lhs (dcall_stmt));
> >> +             gimple_call_set_lhs (copy, duplicate_ssa_name (result, copy));
> >> +             gsi_insert_on_edge (e_dj, copy);
> >> +             add_phi_arg (phi, gimple_call_lhs (copy),
> >> +                          e_dj, UNKNOWN_LOCATION);
> >> +
> >> +             gimple_call_set_arg (iretbnd_stmt, 0,
> >> +                                  gimple_call_lhs (icall_stmt));
> >> +             gimple_call_set_lhs (iretbnd_stmt,
> >> +                                  duplicate_ssa_name (result, iretbnd_stmt));
> >> +             psi = gsi_for_stmt (iretbnd_stmt);
> >> +             gsi_remove (&psi, false);
> >> +             gsi_insert_on_edge (e_ij, iretbnd_stmt);
> >> +             add_phi_arg (phi, gimple_call_lhs (iretbnd_stmt),
> >> +                          e_ij, UNKNOWN_LOCATION);
> >> +
> >> +             gsi_commit_edge_inserts ();
> >
> > Are you sure this is a good idea?  IMNSHO you should be using
> > either gsi_commit_one_edge_insert or be using gsi_insert_on_edge_immediate.
> 
> Will replace it with a couple of gsi_commit_one_edge_insert.
> 
> Thanks,
> Ilya
> >
> > Richard.
> >
> >

Here is an updated version.

Thanks,
Ilya
--
2014-08-15  Ilya Enkovich  <ilya.enkovich@intel.com>

	* ipa-inline.c (early_inliner): Check edge has summary allocated.
	* tree-inline.c: Include tree-chkp.h.
	(declare_return_variable): Add arg holding
	returned bounds slot.  Create and initialize returned bounds var.
	(remap_gimple_stmt): Handle returned bounds.
	Return sequence of statements instead of a single statement.
	(insert_init_stmt): Add declaration.
	(remap_gimple_seq): Adjust to new remap_gimple_stmt signature.
	(copy_bb): Adjust to changed return type of remap_gimple_stmt.
	(expand_call_inline): Handle returned bounds.  Add bounds copy
	for generated mem to mem assignments.
	* tree-inline.h (copy_body_data): Add fields retbnd and
	assign_stmts.
	* cgraph.c: Include tree-chkp.h.
	(cgraph_redirect_edge_call_stmt_to_callee): Support
	returned bounds.
	* value-prof.c: Include tree-chkp.h.
	(gimple_ic): Support returned bounds.

Comments

Ilya Enkovich Sept. 15, 2014, 7:22 a.m. UTC | #1
Ping

2014-08-18 19:35 GMT+04:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
> On 06 Jun 11:59, Ilya Enkovich wrote:
>> 2014-06-03 13:07 GMT+04:00 Richard Biener <richard.guenther@gmail.com>:
>> > On Mon, Jun 2, 2014 at 5:56 PM, Ilya Enkovich <enkovich.gnu@gmail.com> wrote:
>> >> +
>> >> +      /* If indirect call has following BUILT_IN_CHKP_BNDRET
>> >> +        call then we need to make it's copy for the direct
>> >> +        call.  */
>> >> +      if (iretbnd_stmt)
>> >> +       {
>> >> +         if (gimple_call_lhs (iretbnd_stmt))
>> >> +           {
>> >> +             gimple copy;
>> >> +
>> >> +             gimple_set_vdef (iretbnd_stmt, NULL_TREE);
>> >> +             gimple_set_vuse (iretbnd_stmt, NULL_TREE);
>> >> +             update_stmt (iretbnd_stmt);
>> >
>> > This looks bogus - what are you trying to workaround?
>>
>> I did not try to workaround something. I just looked at how this
>> function makes a copy for a call and repeated the process for retbnd
>> call.
>>
>> >
>> > Richard.
>> >
>> >> +             result = gimple_call_lhs (iretbnd_stmt);
>> >> +             phi = create_phi_node (result, join_bb);
>> >> +
>> >> +             copy = gimple_copy (iretbnd_stmt);
>> >> +             gimple_call_set_arg (copy, 0,
>> >> +                                  gimple_call_lhs (dcall_stmt));
>> >> +             gimple_call_set_lhs (copy, duplicate_ssa_name (result, copy));
>> >> +             gsi_insert_on_edge (e_dj, copy);
>> >> +             add_phi_arg (phi, gimple_call_lhs (copy),
>> >> +                          e_dj, UNKNOWN_LOCATION);
>> >> +
>> >> +             gimple_call_set_arg (iretbnd_stmt, 0,
>> >> +                                  gimple_call_lhs (icall_stmt));
>> >> +             gimple_call_set_lhs (iretbnd_stmt,
>> >> +                                  duplicate_ssa_name (result, iretbnd_stmt));
>> >> +             psi = gsi_for_stmt (iretbnd_stmt);
>> >> +             gsi_remove (&psi, false);
>> >> +             gsi_insert_on_edge (e_ij, iretbnd_stmt);
>> >> +             add_phi_arg (phi, gimple_call_lhs (iretbnd_stmt),
>> >> +                          e_ij, UNKNOWN_LOCATION);
>> >> +
>> >> +             gsi_commit_edge_inserts ();
>> >
>> > Are you sure this is a good idea?  IMNSHO you should be using
>> > either gsi_commit_one_edge_insert or be using gsi_insert_on_edge_immediate.
>>
>> Will replace it with a couple of gsi_commit_one_edge_insert.
>>
>> Thanks,
>> Ilya
>> >
>> > Richard.
>> >
>> >
>
> Here is an updated version.
>
> Thanks,
> Ilya
> --
> 2014-08-15  Ilya Enkovich  <ilya.enkovich@intel.com>
>
>         * ipa-inline.c (early_inliner): Check edge has summary allocated.
>         * tree-inline.c: Include tree-chkp.h.
>         (declare_return_variable): Add arg holding
>         returned bounds slot.  Create and initialize returned bounds var.
>         (remap_gimple_stmt): Handle returned bounds.
>         Return sequence of statements instead of a single statement.
>         (insert_init_stmt): Add declaration.
>         (remap_gimple_seq): Adjust to new remap_gimple_stmt signature.
>         (copy_bb): Adjust to changed return type of remap_gimple_stmt.
>         (expand_call_inline): Handle returned bounds.  Add bounds copy
>         for generated mem to mem assignments.
>         * tree-inline.h (copy_body_data): Add fields retbnd and
>         assign_stmts.
>         * cgraph.c: Include tree-chkp.h.
>         (cgraph_redirect_edge_call_stmt_to_callee): Support
>         returned bounds.
>         * value-prof.c: Include tree-chkp.h.
>         (gimple_ic): Support returned bounds.
>
>
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index 0dfcce2..dcd54a6 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -1394,6 +1394,33 @@ cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
>           e->speculative = false;
>           e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt,
>                                                      false);
> +
> +         /* Fix edges for BUILT_IN_CHKP_BNDRET calls attached to the
> +            processed call stmt.  */
> +         if (gimple_call_with_bounds_p (new_stmt)
> +             && gimple_call_lhs (new_stmt)
> +             && chkp_retbnd_call_by_val (gimple_call_lhs (e2->call_stmt)))
> +           {
> +             tree dresult = gimple_call_lhs (new_stmt);
> +             tree iresult = gimple_call_lhs (e2->call_stmt);
> +             gimple dbndret = chkp_retbnd_call_by_val (dresult);
> +             gimple ibndret = chkp_retbnd_call_by_val (iresult);
> +             struct cgraph_edge *iedge
> +               = e2->caller->cgraph_node::get_edge (ibndret);
> +             struct cgraph_edge *dedge;
> +
> +             if (dbndret)
> +               {
> +                 dedge = iedge->caller->create_edge (iedge->callee,
> +                                                     dbndret, e->count,
> +                                                     e->frequency);
> +                 dedge->frequency = compute_call_stmt_bb_frequency
> +                   (dedge->caller->decl, gimple_bb (dedge->call_stmt));
> +               }
> +             iedge->frequency = compute_call_stmt_bb_frequency
> +               (iedge->caller->decl, gimple_bb (iedge->call_stmt));
> +           }
> +
>           e->frequency = compute_call_stmt_bb_frequency
>                            (e->caller->decl, gimple_bb (e->call_stmt));
>           e2->frequency = compute_call_stmt_bb_frequency
> diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
> index 5f1c9b0..b89f591 100644
> --- a/gcc/ipa-inline.c
> +++ b/gcc/ipa-inline.c
> @@ -2468,11 +2468,15 @@ pass_early_inline::execute (function *fun)
>              info that might be cleared out for newly discovered edges.  */
>           for (edge = node->callees; edge; edge = edge->next_callee)
>             {
> -             struct inline_edge_summary *es = inline_edge_summary (edge);
> -             es->call_stmt_size
> -               = estimate_num_insns (edge->call_stmt, &eni_size_weights);
> -             es->call_stmt_time
> -               = estimate_num_insns (edge->call_stmt, &eni_time_weights);
> +             /* We have no summary for new bound store calls yet.  */
> +             if (inline_edge_summary_vec.length () > (unsigned)edge->uid)
> +               {
> +                 struct inline_edge_summary *es = inline_edge_summary (edge);
> +                 es->call_stmt_size
> +                   = estimate_num_insns (edge->call_stmt, &eni_size_weights);
> +                 es->call_stmt_time
> +                   = estimate_num_insns (edge->call_stmt, &eni_time_weights);
> +               }
>               if (edge->callee->decl
>                   && !gimple_check_call_matching_types (
>                       edge->call_stmt, edge->callee->decl, false))
> diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
> index e2b7990..6ec1a81 100644
> --- a/gcc/tree-inline.c
> +++ b/gcc/tree-inline.c
> @@ -68,6 +68,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "target.h"
>  #include "cfgloop.h"
>  #include "builtins.h"
> +#include "tree-chkp.h"
>
>  #include "rtl.h"       /* FIXME: For asm_str_count.  */
>
> @@ -131,7 +132,8 @@ eni_weights eni_time_weights;
>
>  /* Prototypes.  */
>
> -static tree declare_return_variable (copy_body_data *, tree, tree, basic_block);
> +static tree declare_return_variable (copy_body_data *, tree, tree, tree,
> +                                    basic_block);
>  static void remap_block (tree *, copy_body_data *);
>  static void copy_bind_expr (tree *, int *, copy_body_data *);
>  static void declare_inline_vars (tree, tree);
> @@ -140,8 +142,9 @@ static void prepend_lexical_block (tree current_block, tree new_block);
>  static tree copy_decl_to_var (tree, copy_body_data *);
>  static tree copy_result_decl_to_var (tree, copy_body_data *);
>  static tree copy_decl_maybe_to_var (tree, copy_body_data *);
> -static gimple remap_gimple_stmt (gimple, copy_body_data *);
> +static gimple_seq remap_gimple_stmt (gimple, copy_body_data *);
>  static bool delete_unreachable_blocks_update_callgraph (copy_body_data *id);
> +static void insert_init_stmt (copy_body_data *, basic_block, gimple);
>
>  /* Insert a tree->tree mapping for ID.  Despite the name suggests
>     that the trees should be variables, it is used for more than that.  */
> @@ -779,8 +782,8 @@ remap_gimple_seq (gimple_seq body, copy_body_data *id)
>
>    for (si = gsi_start (body); !gsi_end_p (si); gsi_next (&si))
>      {
> -      gimple new_stmt = remap_gimple_stmt (gsi_stmt (si), id);
> -      gimple_seq_add_stmt (&new_body, new_stmt);
> +      gimple_seq new_stmts = remap_gimple_stmt (gsi_stmt (si), id);
> +      gimple_seq_add_seq (&new_body, new_stmts);
>      }
>
>    return new_body;
> @@ -1282,12 +1285,13 @@ remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id)
>  /* Helper for copy_bb.  Remap statement STMT using the inlining
>     information in ID.  Return the new statement copy.  */
>
> -static gimple
> +static gimple_seq
>  remap_gimple_stmt (gimple stmt, copy_body_data *id)
>  {
>    gimple copy = NULL;
>    struct walk_stmt_info wi;
>    bool skip_first = false;
> +  gimple_seq stmts = NULL;
>
>    /* Begin by recognizing trees that we'll completely rewrite for the
>       inlining context.  Our output for these trees is completely
> @@ -1302,6 +1306,17 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>    if (gimple_code (stmt) == GIMPLE_RETURN && id->transform_return_to_modify)
>      {
>        tree retval = gimple_return_retval (stmt);
> +      tree retbnd = gimple_return_retbnd (stmt);
> +      tree bndslot = id->retbnd;
> +
> +      if (retbnd && bndslot)
> +       {
> +         gimple bndcopy = gimple_build_assign (bndslot, retbnd);
> +         memset (&wi, 0, sizeof (wi));
> +         wi.info = id;
> +         walk_gimple_op (bndcopy, remap_gimple_op_r, &wi);
> +         gimple_seq_add_stmt (&stmts, bndcopy);
> +       }
>
>        /* If we're returning something, just turn that into an
>          assignment into the equivalent of the original RESULT_DECL.
> @@ -1319,9 +1334,18 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>                                       retval);
>           /* id->retvar is already substituted.  Skip it on later remapping.  */
>           skip_first = true;
> +
> +         /* We need to copy bounds if return structure with pointers into
> +            instrumented function.  */
> +         if (chkp_function_instrumented_p (id->dst_fn)
> +             && !bndslot
> +             && !BOUNDED_P (id->retvar)
> +             && chkp_type_has_pointer (TREE_TYPE (id->retvar)))
> +           id->assign_stmts.safe_push (copy);
> +
>         }
>        else
> -       return gimple_build_nop ();
> +       return stmts;
>      }
>    else if (gimple_has_substatements (stmt))
>      {
> @@ -1485,7 +1509,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>               value = *n;
>               STRIP_TYPE_NOPS (value);
>               if (TREE_CONSTANT (value) || TREE_READONLY (value))
> -               return gimple_build_nop ();
> +               return NULL;
>             }
>         }
>
> @@ -1502,7 +1526,7 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>               if (gimple_bb (def_stmt)
>                   && !bitmap_bit_p (id->blocks_to_copy,
>                                     gimple_bb (def_stmt)->index))
> -               return gimple_build_nop ();
> +               return NULL;
>             }
>         }
>
> @@ -1512,7 +1536,8 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>                                           gimple_debug_bind_get_value (stmt),
>                                           stmt);
>           id->debug_stmts.safe_push (copy);
> -         return copy;
> +         gimple_seq_add_stmt (&stmts, copy);
> +         return stmts;
>         }
>        if (gimple_debug_source_bind_p (stmt))
>         {
> @@ -1520,7 +1545,8 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>                    (gimple_debug_source_bind_get_var (stmt),
>                     gimple_debug_source_bind_get_value (stmt), stmt);
>           id->debug_stmts.safe_push (copy);
> -         return copy;
> +         gimple_seq_add_stmt (&stmts, copy);
> +         return stmts;
>         }
>
>        /* Create a new deep copy of the statement.  */
> @@ -1599,7 +1625,10 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>      }
>
>    if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
> -    return copy;
> +    {
> +      gimple_seq_add_stmt (&stmts, copy);
> +      return stmts;
> +    }
>
>    /* Remap all the operands in COPY.  */
>    memset (&wi, 0, sizeof (wi));
> @@ -1617,7 +1646,8 @@ remap_gimple_stmt (gimple stmt, copy_body_data *id)
>        gimple_set_vuse (copy, NULL_TREE);
>      }
>
> -  return copy;
> +  gimple_seq_add_stmt (&stmts, copy);
> +  return stmts;
>  }
>
>
> @@ -1658,36 +1688,59 @@ copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
>
>    for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
>      {
> +      gimple_seq stmts;
>        gimple stmt = gsi_stmt (gsi);
>        gimple orig_stmt = stmt;
> +      gimple_stmt_iterator stmts_gsi;
> +      bool stmt_added = false;
>
>        id->regimplify = false;
> -      stmt = remap_gimple_stmt (stmt, id);
> -      if (gimple_nop_p (stmt))
> +      stmts = remap_gimple_stmt (stmt, id);
> +
> +      if (gimple_seq_empty_p (stmts))
>         continue;
>
> -      gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun, orig_stmt);
>        seq_gsi = copy_gsi;
>
> -      /* With return slot optimization we can end up with
> -        non-gimple (foo *)&this->m, fix that here.  */
> -      if (is_gimple_assign (stmt)
> -         && gimple_assign_rhs_code (stmt) == NOP_EXPR
> -         && !is_gimple_val (gimple_assign_rhs1 (stmt)))
> +      for (stmts_gsi = gsi_start (stmts);
> +          !gsi_end_p (stmts_gsi); )
>         {
> -         tree new_rhs;
> -         new_rhs = force_gimple_operand_gsi (&seq_gsi,
> -                                             gimple_assign_rhs1 (stmt),
> -                                             true, NULL, false,
> -                                             GSI_CONTINUE_LINKING);
> -         gimple_assign_set_rhs1 (stmt, new_rhs);
> -         id->regimplify = false;
> -       }
> +         stmt = gsi_stmt (stmts_gsi);
> +
> +         /* Advance iterator now before stmt is moved to seq_gsi.  */
> +         gsi_next (&stmts_gsi);
> +
> +         if (gimple_nop_p (stmt))
> +             continue;
> +
> +         gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun,
> +                                           orig_stmt);
> +
> +         /* With return slot optimization we can end up with
> +            non-gimple (foo *)&this->m, fix that here.  */
> +         if (is_gimple_assign (stmt)
> +             && gimple_assign_rhs_code (stmt) == NOP_EXPR
> +             && !is_gimple_val (gimple_assign_rhs1 (stmt)))
> +           {
> +             tree new_rhs;
> +             new_rhs = force_gimple_operand_gsi (&seq_gsi,
> +                                                 gimple_assign_rhs1 (stmt),
> +                                                 true, NULL, false,
> +                                                 GSI_CONTINUE_LINKING);
> +             gimple_assign_set_rhs1 (stmt, new_rhs);
> +             id->regimplify = false;
> +           }
>
> -      gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT);
> +         gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT);
>
> -      if (id->regimplify)
> -       gimple_regimplify_operands (stmt, &seq_gsi);
> +         if (id->regimplify)
> +           gimple_regimplify_operands (stmt, &seq_gsi);
> +
> +         stmt_added = true;
> +       }
> +
> +      if (!stmt_added)
> +       continue;
>
>        /* If copy_basic_block has been empty at the start of this iteration,
>          call gsi_start_bb again to get at the newly added statements.  */
> @@ -3117,12 +3170,14 @@ initialize_inlined_parameters (copy_body_data *id, gimple stmt,
>     is set only for CALL_EXPR_RETURN_SLOT_OPT.  MODIFY_DEST, if non-null,
>     was the LHS of the MODIFY_EXPR to which this call is the RHS.
>
> +   RETURN_BOUNDS holds a destination for returned bounds.
> +
>     The return value is a (possibly null) value that holds the result
>     as seen by the caller.  */
>
>  static tree
>  declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
> -                        basic_block entry_bb)
> +                        tree return_bounds, basic_block entry_bb)
>  {
>    tree callee = id->src_fn;
>    tree result = DECL_RESULT (callee);
> @@ -3302,6 +3357,19 @@ declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
>    /* Remember this so we can ignore it in remap_decls.  */
>    id->retvar = var;
>
> +  /* If returned bounds are used, then make var for them.  */
> +  if (return_bounds)
> +  {
> +    tree bndtemp = create_tmp_var (pointer_bounds_type_node, "retbnd");
> +    DECL_SEEN_IN_BIND_EXPR_P (bndtemp) = 1;
> +    TREE_NO_WARNING (bndtemp) = 1;
> +    declare_inline_vars (id->block, bndtemp);
> +
> +    id->retbnd = bndtemp;
> +    insert_init_stmt (id, entry_bb,
> +                     gimple_build_assign (bndtemp, chkp_get_zero_bounds_var ()));
> +  }
> +
>    return use;
>  }
>
> @@ -4134,6 +4202,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>    hash_map<tree, tree> *st = NULL;
>    tree return_slot;
>    tree modify_dest;
> +  tree return_bounds = NULL;
>    location_t saved_location;
>    struct cgraph_edge *cg_edge;
>    cgraph_inline_failed_t reason;
> @@ -4142,6 +4211,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>    gimple_stmt_iterator gsi, stmt_gsi;
>    bool successfully_inlined = FALSE;
>    bool purge_dead_abnormal_edges;
> +  unsigned int i;
>
>    /* Set input_location here so we get the right instantiation context
>       if we call instantiate_decl from inlinable_function_p.  */
> @@ -4230,6 +4300,7 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>
>    /* We will be inlining this callee.  */
>    id->eh_lp_nr = lookup_stmt_eh_lp (stmt);
> +  id->assign_stmts.create (0);
>
>    /* Update the callers EH personality.  */
>    if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl))
> @@ -4351,6 +4422,24 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>      {
>        modify_dest = gimple_call_lhs (stmt);
>
> +      /* Remember where to copy returned bounds.  */
> +      if (gimple_call_with_bounds_p (stmt)
> +         && TREE_CODE (modify_dest) == SSA_NAME)
> +       {
> +         gimple retbnd = chkp_retbnd_call_by_val (modify_dest);
> +         if (retbnd)
> +           {
> +             return_bounds = gimple_call_lhs (retbnd);
> +             /* If returned bounds are not used then just
> +                remove unused call.  */
> +             if (!return_bounds)
> +               {
> +                 gimple_stmt_iterator iter = gsi_for_stmt (retbnd);
> +                 gsi_remove (&iter, true);
> +               }
> +           }
> +       }
> +
>        /* The function which we are inlining might not return a value,
>          in which case we should issue a warning that the function
>          does not return a value.  In that case the optimizers will
> @@ -4381,7 +4470,8 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>      }
>
>    /* Declare the return variable for the function.  */
> -  use_retvar = declare_return_variable (id, return_slot, modify_dest, bb);
> +  use_retvar = declare_return_variable (id, return_slot, modify_dest,
> +                                       return_bounds, bb);
>
>    /* Add local vars in this inlined callee to caller.  */
>    add_local_variables (id->src_cfun, cfun, id);
> @@ -4433,6 +4523,12 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>        stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar);
>        gsi_replace (&stmt_gsi, stmt, false);
>        maybe_clean_or_replace_eh_stmt (old_stmt, stmt);
> +
> +      /* Copy bounds if we copy structure with bounds.  */
> +      if (chkp_function_instrumented_p (id->dst_fn)
> +         && !BOUNDED_P (use_retvar)
> +         && chkp_type_has_pointer (TREE_TYPE (use_retvar)))
> +       id->assign_stmts.safe_push (stmt);
>      }
>    else
>      {
> @@ -4464,6 +4560,20 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>          gsi_remove (&stmt_gsi, true);
>      }
>
> +  /* Put returned bounds into the correct place if required.  */
> +  if (return_bounds)
> +    {
> +      gimple old_stmt = SSA_NAME_DEF_STMT (return_bounds);
> +      gimple new_stmt = gimple_build_assign (return_bounds, id->retbnd);
> +      gimple_stmt_iterator bnd_gsi = gsi_for_stmt (old_stmt);
> +      unlink_stmt_vdef (old_stmt);
> +      gsi_replace (&bnd_gsi, new_stmt, false);
> +      maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt);
> +      cgraph_update_edges_for_call_stmt (old_stmt,
> +                                        gimple_call_fndecl (old_stmt),
> +                                        new_stmt);
> +    }
> +
>    if (purge_dead_abnormal_edges)
>      {
>        gimple_purge_dead_eh_edges (return_block);
> @@ -4480,6 +4590,11 @@ expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
>        TREE_USED (gimple_assign_rhs1 (stmt)) = 1;
>      }
>
> +  /* Copy bounds for all generated assigns that need it.  */
> +  for (i = 0; i < id->assign_stmts.length (); i++)
> +    chkp_copy_bounds_for_assign (id->assign_stmts[i], cg_edge);
> +  id->assign_stmts.release ();
> +
>    /* Output the inlining info for this abstract function, since it has been
>       inlined.  If we don't do this now, we can lose the information about the
>       variables in the function when the blocks get blown away as soon as we
> diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h
> index 53059da..9eb75c7 100644
> --- a/gcc/tree-inline.h
> +++ b/gcc/tree-inline.h
> @@ -63,6 +63,12 @@ struct copy_body_data
>    /* The VAR_DECL for the return value.  */
>    tree retvar;
>
> +  /* The VAR_DECL for the return bounds.  */
> +  tree retbnd;
> +
> +  /* Assign statements that need bounds copy.  */
> +  vec<gimple> assign_stmts;
> +
>    /* The map from local declarations in the inlined function to
>       equivalents in the function into which it is being inlined.  */
>    hash_map<tree, tree> *decl_map;
> diff --git a/gcc/value-prof.c b/gcc/value-prof.c
> index ffdee65..dd8a4a1 100644
> --- a/gcc/value-prof.c
> +++ b/gcc/value-prof.c
> @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.  If not see
>  #include "builtins.h"
>  #include "tree-nested.h"
>  #include "hash-set.h"
> +#include "tree-chkp.h"
>
>  /* In this file value profile based optimizations are placed.  Currently the
>     following optimizations are implemented (for more detailed descriptions
> @@ -1335,7 +1336,7 @@ gimple
>  gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
>            int prob, gcov_type count, gcov_type all)
>  {
> -  gimple dcall_stmt, load_stmt, cond_stmt;
> +  gimple dcall_stmt, load_stmt, cond_stmt, iretbnd_stmt = NULL;
>    tree tmp0, tmp1, tmp;
>    basic_block cond_bb, dcall_bb, icall_bb, join_bb = NULL;
>    tree optype = build_pointer_type (void_type_node);
> @@ -1349,6 +1350,9 @@ gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
>    cond_bb = gimple_bb (icall_stmt);
>    gsi = gsi_for_stmt (icall_stmt);
>
> +  if (gimple_call_with_bounds_p (icall_stmt) && gimple_call_lhs (icall_stmt))
> +    iretbnd_stmt = chkp_retbnd_call_by_val (gimple_call_lhs (icall_stmt));
> +
>    tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
>    tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
>    tmp = unshare_expr (gimple_call_fn (icall_stmt));
> @@ -1441,6 +1445,50 @@ gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
>        gimple_call_set_lhs (dcall_stmt,
>                            duplicate_ssa_name (result, dcall_stmt));
>        add_phi_arg (phi, gimple_call_lhs (dcall_stmt), e_dj, UNKNOWN_LOCATION);
> +
> +      /* If indirect call has following BUILT_IN_CHKP_BNDRET
> +        call then we need to make it's copy for the direct
> +        call.  */
> +      if (iretbnd_stmt)
> +       {
> +         if (gimple_call_lhs (iretbnd_stmt))
> +           {
> +             gimple copy;
> +
> +             gimple_set_vdef (iretbnd_stmt, NULL_TREE);
> +             gimple_set_vuse (iretbnd_stmt, NULL_TREE);
> +             update_stmt (iretbnd_stmt);
> +
> +             result = gimple_call_lhs (iretbnd_stmt);
> +             phi = create_phi_node (result, join_bb);
> +
> +             copy = gimple_copy (iretbnd_stmt);
> +             gimple_call_set_arg (copy, 0,
> +                                  gimple_call_lhs (dcall_stmt));
> +             gimple_call_set_lhs (copy, duplicate_ssa_name (result, copy));
> +             gsi_insert_on_edge (e_dj, copy);
> +             add_phi_arg (phi, gimple_call_lhs (copy),
> +                          e_dj, UNKNOWN_LOCATION);
> +
> +             gimple_call_set_arg (iretbnd_stmt, 0,
> +                                  gimple_call_lhs (icall_stmt));
> +             gimple_call_set_lhs (iretbnd_stmt,
> +                                  duplicate_ssa_name (result, iretbnd_stmt));
> +             psi = gsi_for_stmt (iretbnd_stmt);
> +             gsi_remove (&psi, false);
> +             gsi_insert_on_edge (e_ij, iretbnd_stmt);
> +             add_phi_arg (phi, gimple_call_lhs (iretbnd_stmt),
> +                          e_ij, UNKNOWN_LOCATION);
> +
> +             gsi_commit_one_edge_insert (e_dj, NULL);
> +             gsi_commit_one_edge_insert (e_ij, NULL);
> +           }
> +         else
> +           {
> +             psi = gsi_for_stmt (iretbnd_stmt);
> +             gsi_remove (&psi, true);
> +           }
> +       }
>      }
>
>    /* Build an EH edge for the direct call if necessary.  */
Jeff Law Sept. 23, 2014, 7:55 p.m. UTC | #2
On 08/18/14 09:35, Ilya Enkovich wrote:
> Here is an updated version.
>
> Thanks,
> Ilya
> --
> 2014-08-15  Ilya Enkovich  <ilya.enkovich@intel.com>
>
> 	* ipa-inline.c (early_inliner): Check edge has summary allocated.
> 	* tree-inline.c: Include tree-chkp.h.
> 	(declare_return_variable): Add arg holding
> 	returned bounds slot.  Create and initialize returned bounds var.
> 	(remap_gimple_stmt): Handle returned bounds.
> 	Return sequence of statements instead of a single statement.
> 	(insert_init_stmt): Add declaration.
> 	(remap_gimple_seq): Adjust to new remap_gimple_stmt signature.
> 	(copy_bb): Adjust to changed return type of remap_gimple_stmt.
> 	(expand_call_inline): Handle returned bounds.  Add bounds copy
> 	for generated mem to mem assignments.
> 	* tree-inline.h (copy_body_data): Add fields retbnd and
> 	assign_stmts.
> 	* cgraph.c: Include tree-chkp.h.
> 	(cgraph_redirect_edge_call_stmt_to_callee): Support
> 	returned bounds.
> 	* value-prof.c: Include tree-chkp.h.
> 	(gimple_ic): Support returned bounds.
OK for the trunk.

FWIW, when building up gimple (or RTL if you were ever to do that one 
day), it's sometimes helpful to the reviewer to show what you're doing. 
  For example, it took me a bit of time to realize that you needed the 
output from the direct call as an argument to the duplicated RETBND 
statement.  It looked for quite a while like you'd simply made a mistake.

I'm a bit curious why you removed the original RETBND statement in 
value-prof, only to reinsert it.  Is there some reason you needed to do 
that?

Richi -- in response to your comment about working around a bug earlier 
in this thread.  As Ilya mentioned, he just cloned existing practice in 
that code for creating the copy of the call.


Jeff
Ilya Enkovich Sept. 24, 2014, 7:28 a.m. UTC | #3
2014-09-23 23:55 GMT+04:00 Jeff Law <law@redhat.com>:
> On 08/18/14 09:35, Ilya Enkovich wrote:
>>
>> Here is an updated version.
>>
>> Thanks,
>> Ilya
>> --
>> 2014-08-15  Ilya Enkovich  <ilya.enkovich@intel.com>
>>
>>         * ipa-inline.c (early_inliner): Check edge has summary allocated.
>>         * tree-inline.c: Include tree-chkp.h.
>>         (declare_return_variable): Add arg holding
>>         returned bounds slot.  Create and initialize returned bounds var.
>>         (remap_gimple_stmt): Handle returned bounds.
>>         Return sequence of statements instead of a single statement.
>>         (insert_init_stmt): Add declaration.
>>         (remap_gimple_seq): Adjust to new remap_gimple_stmt signature.
>>         (copy_bb): Adjust to changed return type of remap_gimple_stmt.
>>         (expand_call_inline): Handle returned bounds.  Add bounds copy
>>         for generated mem to mem assignments.
>>         * tree-inline.h (copy_body_data): Add fields retbnd and
>>         assign_stmts.
>>         * cgraph.c: Include tree-chkp.h.
>>         (cgraph_redirect_edge_call_stmt_to_callee): Support
>>         returned bounds.
>>         * value-prof.c: Include tree-chkp.h.
>>         (gimple_ic): Support returned bounds.
>
> OK for the trunk.
>
> FWIW, when building up gimple (or RTL if you were ever to do that one day),
> it's sometimes helpful to the reviewer to show what you're doing.  For
> example, it took me a bit of time to realize that you needed the output from
> the direct call as an argument to the duplicated RETBND statement.  It
> looked for quite a while like you'd simply made a mistake.

Got it.  Will try to give more useful descriptions for my patches in the future.

>
> I'm a bit curious why you removed the original RETBND statement in
> value-prof, only to reinsert it.  Is there some reason you needed to do
> that?

After call transformation we have smth like that:

if (<confition>)
  new_lhs = direct_call (...);
else
  old_lhs = call (...);
old_bnd = __builtin_retbnd (old_lhs);

Original retbnd statement removal + reinsertion is used to transform it into:

if (<confition>)
  new_lhs = direct_call (...);
else
{
  old_lhs = call (...);
  old_bnd = __builtin_retbnd (old_lhs);
}

The rest of code inserts bounds for new_lhs and creates phi node for
bounds similar to what is done for call return value.

Thanks,
Ilya

>
> Richi -- in response to your comment about working around a bug earlier in
> this thread.  As Ilya mentioned, he just cloned existing practice in that
> code for creating the copy of the call.
>
>
> Jeff
Jeff Law Sept. 24, 2014, 3:17 p.m. UTC | #4
On 09/24/14 01:28, Ilya Enkovich wrote:
>
>>
>> I'm a bit curious why you removed the original RETBND statement in
>> value-prof, only to reinsert it.  Is there some reason you needed to do
>> that?
>
> After call transformation we have smth like that:
>
> if (<confition>)
>    new_lhs = direct_call (...);
> else
>    old_lhs = call (...);
> old_bnd = __builtin_retbnd (old_lhs);
>
> Original retbnd statement removal + reinsertion is used to transform it into:
>
> if (<confition>)
>    new_lhs = direct_call (...);
> else
> {
>    old_lhs = call (...);
>    old_bnd = __builtin_retbnd (old_lhs);
> }
>
> The rest of code inserts bounds for new_lhs and creates phi node for
> bounds similar to what is done for call return value.
Oh yea, makes perfect sense, the earlier code inserted the conditional, 
but left the bounds setting bits in their prior (now the merge point) 
location.

Thanks,
Jeff
diff mbox

Patch

diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 0dfcce2..dcd54a6 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -1394,6 +1394,33 @@  cgraph_redirect_edge_call_stmt_to_callee (struct cgraph_edge *e)
 	  e->speculative = false;
 	  e->caller->set_call_stmt_including_clones (e->call_stmt, new_stmt,
 						     false);
+
+	  /* Fix edges for BUILT_IN_CHKP_BNDRET calls attached to the
+	     processed call stmt.  */
+	  if (gimple_call_with_bounds_p (new_stmt)
+	      && gimple_call_lhs (new_stmt)
+	      && chkp_retbnd_call_by_val (gimple_call_lhs (e2->call_stmt)))
+	    {
+	      tree dresult = gimple_call_lhs (new_stmt);
+	      tree iresult = gimple_call_lhs (e2->call_stmt);
+	      gimple dbndret = chkp_retbnd_call_by_val (dresult);
+	      gimple ibndret = chkp_retbnd_call_by_val (iresult);
+	      struct cgraph_edge *iedge
+		= e2->caller->cgraph_node::get_edge (ibndret);
+	      struct cgraph_edge *dedge;
+
+	      if (dbndret)
+		{
+		  dedge = iedge->caller->create_edge (iedge->callee,
+						      dbndret, e->count,
+						      e->frequency);
+		  dedge->frequency = compute_call_stmt_bb_frequency
+		    (dedge->caller->decl, gimple_bb (dedge->call_stmt));
+		}
+	      iedge->frequency = compute_call_stmt_bb_frequency
+		(iedge->caller->decl, gimple_bb (iedge->call_stmt));
+	    }
+
 	  e->frequency = compute_call_stmt_bb_frequency
 			   (e->caller->decl, gimple_bb (e->call_stmt));
 	  e2->frequency = compute_call_stmt_bb_frequency
diff --git a/gcc/ipa-inline.c b/gcc/ipa-inline.c
index 5f1c9b0..b89f591 100644
--- a/gcc/ipa-inline.c
+++ b/gcc/ipa-inline.c
@@ -2468,11 +2468,15 @@  pass_early_inline::execute (function *fun)
 	     info that might be cleared out for newly discovered edges.  */
 	  for (edge = node->callees; edge; edge = edge->next_callee)
 	    {
-	      struct inline_edge_summary *es = inline_edge_summary (edge);
-	      es->call_stmt_size
-		= estimate_num_insns (edge->call_stmt, &eni_size_weights);
-	      es->call_stmt_time
-		= estimate_num_insns (edge->call_stmt, &eni_time_weights);
+	      /* We have no summary for new bound store calls yet.  */
+	      if (inline_edge_summary_vec.length () > (unsigned)edge->uid)
+		{
+		  struct inline_edge_summary *es = inline_edge_summary (edge);
+		  es->call_stmt_size
+		    = estimate_num_insns (edge->call_stmt, &eni_size_weights);
+		  es->call_stmt_time
+		    = estimate_num_insns (edge->call_stmt, &eni_time_weights);
+		}
 	      if (edge->callee->decl
 		  && !gimple_check_call_matching_types (
 		      edge->call_stmt, edge->callee->decl, false))
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index e2b7990..6ec1a81 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -68,6 +68,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "target.h"
 #include "cfgloop.h"
 #include "builtins.h"
+#include "tree-chkp.h"
 
 #include "rtl.h"	/* FIXME: For asm_str_count.  */
 
@@ -131,7 +132,8 @@  eni_weights eni_time_weights;
 
 /* Prototypes.  */
 
-static tree declare_return_variable (copy_body_data *, tree, tree, basic_block);
+static tree declare_return_variable (copy_body_data *, tree, tree, tree,
+				     basic_block);
 static void remap_block (tree *, copy_body_data *);
 static void copy_bind_expr (tree *, int *, copy_body_data *);
 static void declare_inline_vars (tree, tree);
@@ -140,8 +142,9 @@  static void prepend_lexical_block (tree current_block, tree new_block);
 static tree copy_decl_to_var (tree, copy_body_data *);
 static tree copy_result_decl_to_var (tree, copy_body_data *);
 static tree copy_decl_maybe_to_var (tree, copy_body_data *);
-static gimple remap_gimple_stmt (gimple, copy_body_data *);
+static gimple_seq remap_gimple_stmt (gimple, copy_body_data *);
 static bool delete_unreachable_blocks_update_callgraph (copy_body_data *id);
+static void insert_init_stmt (copy_body_data *, basic_block, gimple);
 
 /* Insert a tree->tree mapping for ID.  Despite the name suggests
    that the trees should be variables, it is used for more than that.  */
@@ -779,8 +782,8 @@  remap_gimple_seq (gimple_seq body, copy_body_data *id)
 
   for (si = gsi_start (body); !gsi_end_p (si); gsi_next (&si))
     {
-      gimple new_stmt = remap_gimple_stmt (gsi_stmt (si), id);
-      gimple_seq_add_stmt (&new_body, new_stmt);
+      gimple_seq new_stmts = remap_gimple_stmt (gsi_stmt (si), id);
+      gimple_seq_add_seq (&new_body, new_stmts);
     }
 
   return new_body;
@@ -1282,12 +1285,13 @@  remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id)
 /* Helper for copy_bb.  Remap statement STMT using the inlining
    information in ID.  Return the new statement copy.  */
 
-static gimple
+static gimple_seq
 remap_gimple_stmt (gimple stmt, copy_body_data *id)
 {
   gimple copy = NULL;
   struct walk_stmt_info wi;
   bool skip_first = false;
+  gimple_seq stmts = NULL;
 
   /* Begin by recognizing trees that we'll completely rewrite for the
      inlining context.  Our output for these trees is completely
@@ -1302,6 +1306,17 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
   if (gimple_code (stmt) == GIMPLE_RETURN && id->transform_return_to_modify)
     {
       tree retval = gimple_return_retval (stmt);
+      tree retbnd = gimple_return_retbnd (stmt);
+      tree bndslot = id->retbnd;
+
+      if (retbnd && bndslot)
+	{
+	  gimple bndcopy = gimple_build_assign (bndslot, retbnd);
+	  memset (&wi, 0, sizeof (wi));
+	  wi.info = id;
+	  walk_gimple_op (bndcopy, remap_gimple_op_r, &wi);
+	  gimple_seq_add_stmt (&stmts, bndcopy);
+	}
 
       /* If we're returning something, just turn that into an
 	 assignment into the equivalent of the original RESULT_DECL.
@@ -1319,9 +1334,18 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
 				      retval);
 	  /* id->retvar is already substituted.  Skip it on later remapping.  */
 	  skip_first = true;
+
+	  /* We need to copy bounds if return structure with pointers into
+	     instrumented function.  */
+	  if (chkp_function_instrumented_p (id->dst_fn)
+	      && !bndslot
+	      && !BOUNDED_P (id->retvar)
+	      && chkp_type_has_pointer (TREE_TYPE (id->retvar)))
+	    id->assign_stmts.safe_push (copy);
+
 	}
       else
-	return gimple_build_nop ();
+	return stmts;
     }
   else if (gimple_has_substatements (stmt))
     {
@@ -1485,7 +1509,7 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
 	      value = *n;
 	      STRIP_TYPE_NOPS (value);
 	      if (TREE_CONSTANT (value) || TREE_READONLY (value))
-		return gimple_build_nop ();
+		return NULL;
 	    }
 	}
 
@@ -1502,7 +1526,7 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
 	      if (gimple_bb (def_stmt)
 		  && !bitmap_bit_p (id->blocks_to_copy,
 				    gimple_bb (def_stmt)->index))
-		return gimple_build_nop ();
+		return NULL;
 	    }
 	}
 
@@ -1512,7 +1536,8 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
 					  gimple_debug_bind_get_value (stmt),
 					  stmt);
 	  id->debug_stmts.safe_push (copy);
-	  return copy;
+	  gimple_seq_add_stmt (&stmts, copy);
+	  return stmts;
 	}
       if (gimple_debug_source_bind_p (stmt))
 	{
@@ -1520,7 +1545,8 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
 		   (gimple_debug_source_bind_get_var (stmt),
 		    gimple_debug_source_bind_get_value (stmt), stmt);
 	  id->debug_stmts.safe_push (copy);
-	  return copy;
+	  gimple_seq_add_stmt (&stmts, copy);
+	  return stmts;
 	}
 
       /* Create a new deep copy of the statement.  */
@@ -1599,7 +1625,10 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
     }
 
   if (gimple_debug_bind_p (copy) || gimple_debug_source_bind_p (copy))
-    return copy;
+    {
+      gimple_seq_add_stmt (&stmts, copy);
+      return stmts;
+    }
 
   /* Remap all the operands in COPY.  */
   memset (&wi, 0, sizeof (wi));
@@ -1617,7 +1646,8 @@  remap_gimple_stmt (gimple stmt, copy_body_data *id)
       gimple_set_vuse (copy, NULL_TREE);
     }
 
-  return copy;
+  gimple_seq_add_stmt (&stmts, copy);
+  return stmts;
 }
 
 
@@ -1658,36 +1688,59 @@  copy_bb (copy_body_data *id, basic_block bb, int frequency_scale,
 
   for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
     {
+      gimple_seq stmts;
       gimple stmt = gsi_stmt (gsi);
       gimple orig_stmt = stmt;
+      gimple_stmt_iterator stmts_gsi;
+      bool stmt_added = false;
 
       id->regimplify = false;
-      stmt = remap_gimple_stmt (stmt, id);
-      if (gimple_nop_p (stmt))
+      stmts = remap_gimple_stmt (stmt, id);
+
+      if (gimple_seq_empty_p (stmts))
 	continue;
 
-      gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun, orig_stmt);
       seq_gsi = copy_gsi;
 
-      /* With return slot optimization we can end up with
-	 non-gimple (foo *)&this->m, fix that here.  */
-      if (is_gimple_assign (stmt)
-	  && gimple_assign_rhs_code (stmt) == NOP_EXPR
-	  && !is_gimple_val (gimple_assign_rhs1 (stmt)))
+      for (stmts_gsi = gsi_start (stmts);
+	   !gsi_end_p (stmts_gsi); )
 	{
-	  tree new_rhs;
-	  new_rhs = force_gimple_operand_gsi (&seq_gsi,
-					      gimple_assign_rhs1 (stmt),
-					      true, NULL, false,
-					      GSI_CONTINUE_LINKING);
-	  gimple_assign_set_rhs1 (stmt, new_rhs);
-	  id->regimplify = false;
-	}
+	  stmt = gsi_stmt (stmts_gsi);
+
+	  /* Advance iterator now before stmt is moved to seq_gsi.  */
+	  gsi_next (&stmts_gsi);
+
+	  if (gimple_nop_p (stmt))
+	      continue;
+
+	  gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun,
+					    orig_stmt);
+
+	  /* With return slot optimization we can end up with
+	     non-gimple (foo *)&this->m, fix that here.  */
+	  if (is_gimple_assign (stmt)
+	      && gimple_assign_rhs_code (stmt) == NOP_EXPR
+	      && !is_gimple_val (gimple_assign_rhs1 (stmt)))
+	    {
+	      tree new_rhs;
+	      new_rhs = force_gimple_operand_gsi (&seq_gsi,
+						  gimple_assign_rhs1 (stmt),
+						  true, NULL, false,
+						  GSI_CONTINUE_LINKING);
+	      gimple_assign_set_rhs1 (stmt, new_rhs);
+	      id->regimplify = false;
+	    }
 
-      gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT);
+	  gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT);
 
-      if (id->regimplify)
-	gimple_regimplify_operands (stmt, &seq_gsi);
+	  if (id->regimplify)
+	    gimple_regimplify_operands (stmt, &seq_gsi);
+
+	  stmt_added = true;
+	}
+
+      if (!stmt_added)
+	continue;
 
       /* If copy_basic_block has been empty at the start of this iteration,
 	 call gsi_start_bb again to get at the newly added statements.  */
@@ -3117,12 +3170,14 @@  initialize_inlined_parameters (copy_body_data *id, gimple stmt,
    is set only for CALL_EXPR_RETURN_SLOT_OPT.  MODIFY_DEST, if non-null,
    was the LHS of the MODIFY_EXPR to which this call is the RHS.
 
+   RETURN_BOUNDS holds a destination for returned bounds.
+
    The return value is a (possibly null) value that holds the result
    as seen by the caller.  */
 
 static tree
 declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
-			 basic_block entry_bb)
+			 tree return_bounds, basic_block entry_bb)
 {
   tree callee = id->src_fn;
   tree result = DECL_RESULT (callee);
@@ -3302,6 +3357,19 @@  declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest,
   /* Remember this so we can ignore it in remap_decls.  */
   id->retvar = var;
 
+  /* If returned bounds are used, then make var for them.  */
+  if (return_bounds)
+  {
+    tree bndtemp = create_tmp_var (pointer_bounds_type_node, "retbnd");
+    DECL_SEEN_IN_BIND_EXPR_P (bndtemp) = 1;
+    TREE_NO_WARNING (bndtemp) = 1;
+    declare_inline_vars (id->block, bndtemp);
+
+    id->retbnd = bndtemp;
+    insert_init_stmt (id, entry_bb,
+		      gimple_build_assign (bndtemp, chkp_get_zero_bounds_var ()));
+  }
+
   return use;
 }
 
@@ -4134,6 +4202,7 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   hash_map<tree, tree> *st = NULL;
   tree return_slot;
   tree modify_dest;
+  tree return_bounds = NULL;
   location_t saved_location;
   struct cgraph_edge *cg_edge;
   cgraph_inline_failed_t reason;
@@ -4142,6 +4211,7 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
   gimple_stmt_iterator gsi, stmt_gsi;
   bool successfully_inlined = FALSE;
   bool purge_dead_abnormal_edges;
+  unsigned int i;
 
   /* Set input_location here so we get the right instantiation context
      if we call instantiate_decl from inlinable_function_p.  */
@@ -4230,6 +4300,7 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
 
   /* We will be inlining this callee.  */
   id->eh_lp_nr = lookup_stmt_eh_lp (stmt);
+  id->assign_stmts.create (0);
 
   /* Update the callers EH personality.  */
   if (DECL_FUNCTION_PERSONALITY (cg_edge->callee->decl))
@@ -4351,6 +4422,24 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     {
       modify_dest = gimple_call_lhs (stmt);
 
+      /* Remember where to copy returned bounds.  */
+      if (gimple_call_with_bounds_p (stmt)
+	  && TREE_CODE (modify_dest) == SSA_NAME)
+	{
+	  gimple retbnd = chkp_retbnd_call_by_val (modify_dest);
+	  if (retbnd)
+	    {
+	      return_bounds = gimple_call_lhs (retbnd);
+	      /* If returned bounds are not used then just
+		 remove unused call.  */
+	      if (!return_bounds)
+		{
+		  gimple_stmt_iterator iter = gsi_for_stmt (retbnd);
+		  gsi_remove (&iter, true);
+		}
+	    }
+	}
+
       /* The function which we are inlining might not return a value,
 	 in which case we should issue a warning that the function
 	 does not return a value.  In that case the optimizers will
@@ -4381,7 +4470,8 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
     }
 
   /* Declare the return variable for the function.  */
-  use_retvar = declare_return_variable (id, return_slot, modify_dest, bb);
+  use_retvar = declare_return_variable (id, return_slot, modify_dest,
+					return_bounds, bb);
 
   /* Add local vars in this inlined callee to caller.  */
   add_local_variables (id->src_cfun, cfun, id);
@@ -4433,6 +4523,12 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar);
       gsi_replace (&stmt_gsi, stmt, false);
       maybe_clean_or_replace_eh_stmt (old_stmt, stmt);
+
+      /* Copy bounds if we copy structure with bounds.  */
+      if (chkp_function_instrumented_p (id->dst_fn)
+	  && !BOUNDED_P (use_retvar)
+	  && chkp_type_has_pointer (TREE_TYPE (use_retvar)))
+	id->assign_stmts.safe_push (stmt);
     }
   else
     {
@@ -4464,6 +4560,20 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
         gsi_remove (&stmt_gsi, true);
     }
 
+  /* Put returned bounds into the correct place if required.  */
+  if (return_bounds)
+    {
+      gimple old_stmt = SSA_NAME_DEF_STMT (return_bounds);
+      gimple new_stmt = gimple_build_assign (return_bounds, id->retbnd);
+      gimple_stmt_iterator bnd_gsi = gsi_for_stmt (old_stmt);
+      unlink_stmt_vdef (old_stmt);
+      gsi_replace (&bnd_gsi, new_stmt, false);
+      maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt);
+      cgraph_update_edges_for_call_stmt (old_stmt,
+					 gimple_call_fndecl (old_stmt),
+					 new_stmt);
+    }
+
   if (purge_dead_abnormal_edges)
     {
       gimple_purge_dead_eh_edges (return_block);
@@ -4480,6 +4590,11 @@  expand_call_inline (basic_block bb, gimple stmt, copy_body_data *id)
       TREE_USED (gimple_assign_rhs1 (stmt)) = 1;
     }
 
+  /* Copy bounds for all generated assigns that need it.  */
+  for (i = 0; i < id->assign_stmts.length (); i++)
+    chkp_copy_bounds_for_assign (id->assign_stmts[i], cg_edge);
+  id->assign_stmts.release ();
+
   /* Output the inlining info for this abstract function, since it has been
      inlined.  If we don't do this now, we can lose the information about the
      variables in the function when the blocks get blown away as soon as we
diff --git a/gcc/tree-inline.h b/gcc/tree-inline.h
index 53059da..9eb75c7 100644
--- a/gcc/tree-inline.h
+++ b/gcc/tree-inline.h
@@ -63,6 +63,12 @@  struct copy_body_data
   /* The VAR_DECL for the return value.  */
   tree retvar;
 
+  /* The VAR_DECL for the return bounds.  */
+  tree retbnd;
+
+  /* Assign statements that need bounds copy.  */
+  vec<gimple> assign_stmts;
+
   /* The map from local declarations in the inlined function to
      equivalents in the function into which it is being inlined.  */
   hash_map<tree, tree> *decl_map;
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index ffdee65..dd8a4a1 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -60,6 +60,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "builtins.h"
 #include "tree-nested.h"
 #include "hash-set.h"
+#include "tree-chkp.h"
 
 /* In this file value profile based optimizations are placed.  Currently the
    following optimizations are implemented (for more detailed descriptions
@@ -1335,7 +1336,7 @@  gimple
 gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
 	   int prob, gcov_type count, gcov_type all)
 {
-  gimple dcall_stmt, load_stmt, cond_stmt;
+  gimple dcall_stmt, load_stmt, cond_stmt, iretbnd_stmt = NULL;
   tree tmp0, tmp1, tmp;
   basic_block cond_bb, dcall_bb, icall_bb, join_bb = NULL;
   tree optype = build_pointer_type (void_type_node);
@@ -1349,6 +1350,9 @@  gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
   cond_bb = gimple_bb (icall_stmt);
   gsi = gsi_for_stmt (icall_stmt);
 
+  if (gimple_call_with_bounds_p (icall_stmt) && gimple_call_lhs (icall_stmt))
+    iretbnd_stmt = chkp_retbnd_call_by_val (gimple_call_lhs (icall_stmt));
+
   tmp0 = make_temp_ssa_name (optype, NULL, "PROF");
   tmp1 = make_temp_ssa_name (optype, NULL, "PROF");
   tmp = unshare_expr (gimple_call_fn (icall_stmt));
@@ -1441,6 +1445,50 @@  gimple_ic (gimple icall_stmt, struct cgraph_node *direct_call,
       gimple_call_set_lhs (dcall_stmt,
 			   duplicate_ssa_name (result, dcall_stmt));
       add_phi_arg (phi, gimple_call_lhs (dcall_stmt), e_dj, UNKNOWN_LOCATION);
+
+      /* If indirect call has following BUILT_IN_CHKP_BNDRET
+	 call then we need to make it's copy for the direct
+	 call.  */
+      if (iretbnd_stmt)
+	{
+	  if (gimple_call_lhs (iretbnd_stmt))
+	    {
+	      gimple copy;
+
+	      gimple_set_vdef (iretbnd_stmt, NULL_TREE);
+	      gimple_set_vuse (iretbnd_stmt, NULL_TREE);
+	      update_stmt (iretbnd_stmt);
+
+	      result = gimple_call_lhs (iretbnd_stmt);
+	      phi = create_phi_node (result, join_bb);
+
+	      copy = gimple_copy (iretbnd_stmt);
+	      gimple_call_set_arg (copy, 0,
+				   gimple_call_lhs (dcall_stmt));
+	      gimple_call_set_lhs (copy, duplicate_ssa_name (result, copy));
+	      gsi_insert_on_edge (e_dj, copy);
+	      add_phi_arg (phi, gimple_call_lhs (copy),
+			   e_dj, UNKNOWN_LOCATION);
+
+	      gimple_call_set_arg (iretbnd_stmt, 0,
+				   gimple_call_lhs (icall_stmt));
+	      gimple_call_set_lhs (iretbnd_stmt,
+				   duplicate_ssa_name (result, iretbnd_stmt));
+	      psi = gsi_for_stmt (iretbnd_stmt);
+	      gsi_remove (&psi, false);
+	      gsi_insert_on_edge (e_ij, iretbnd_stmt);
+	      add_phi_arg (phi, gimple_call_lhs (iretbnd_stmt),
+			   e_ij, UNKNOWN_LOCATION);
+
+	      gsi_commit_one_edge_insert (e_dj, NULL);
+	      gsi_commit_one_edge_insert (e_ij, NULL);
+	    }
+	  else
+	    {
+	      psi = gsi_for_stmt (iretbnd_stmt);
+	      gsi_remove (&psi, true);
+	    }
+	}
     }
 
   /* Build an EH edge for the direct call if necessary.  */