aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-split.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/ipa-split.c')
-rw-r--r--gcc/ipa-split.c107
1 files changed, 102 insertions, 5 deletions
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index ac68c87..98dbc63 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -127,6 +127,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "ipa-inline.h"
#include "cfgloop.h"
+#include "tree-chkp.h"
/* Per basic block info. */
@@ -168,6 +169,7 @@ struct split_point best_split_point;
static bitmap forbidden_dominators;
static tree find_retval (basic_block return_bb);
+static tree find_retbnd (basic_block return_bb);
/* Callback for walk_stmt_load_store_addr_ops. If T is non-SSA automatic
variable, check it if it is present in bitmap passed via DATA. */
@@ -413,6 +415,21 @@ dominated_by_forbidden (basic_block bb)
return false;
}
+/* For give split point CURRENT and return block RETURN_BB return 1
+ if ssa name VAL is set by split part and 0 otherwise. */
+static bool
+split_part_set_ssa_name_p (tree val, struct split_point *current,
+ basic_block return_bb)
+{
+ if (TREE_CODE (val) != SSA_NAME)
+ return false;
+
+ return (!SSA_NAME_IS_DEFAULT_DEF (val)
+ && (bitmap_bit_p (current->split_bbs,
+ gimple_bb (SSA_NAME_DEF_STMT (val))->index)
+ || gimple_bb (SSA_NAME_DEF_STMT (val)) == return_bb));
+}
+
/* We found an split_point CURRENT. NON_SSA_VARS is bitmap of all non ssa
variables used and RETURN_BB is return basic block.
See if we can split function here. */
@@ -430,6 +447,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
unsigned int i;
int incoming_freq = 0;
tree retval;
+ tree retbnd;
bool back_edge = false;
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -618,10 +636,7 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
= bitmap_bit_p (non_ssa_vars, DECL_UID (SSA_NAME_VAR (retval)));
else if (TREE_CODE (retval) == SSA_NAME)
current->split_part_set_retval
- = (!SSA_NAME_IS_DEFAULT_DEF (retval)
- && (bitmap_bit_p (current->split_bbs,
- gimple_bb (SSA_NAME_DEF_STMT (retval))->index)
- || gimple_bb (SSA_NAME_DEF_STMT (retval)) == return_bb));
+ = split_part_set_ssa_name_p (retval, current, return_bb);
else if (TREE_CODE (retval) == PARM_DECL)
current->split_part_set_retval = false;
else if (TREE_CODE (retval) == VAR_DECL
@@ -631,6 +646,29 @@ consider_split (struct split_point *current, bitmap non_ssa_vars,
else
current->split_part_set_retval = true;
+ /* See if retbnd used by return bb is computed by header or split part. */
+ retbnd = find_retbnd (return_bb);
+ if (retbnd)
+ {
+ bool split_part_set_retbnd
+ = split_part_set_ssa_name_p (retbnd, current, return_bb);
+
+ /* If we have both return value and bounds then keep their definitions
+ in a single function. We use SSA names to link returned bounds and
+ value and therefore do not handle cases when result is passed by
+ reference (which should not be our case anyway since bounds are
+ returned for pointers only). */
+ if ((DECL_BY_REFERENCE (DECL_RESULT (current_function_decl))
+ && current->split_part_set_retval)
+ || split_part_set_retbnd != current->split_part_set_retval)
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file,
+ " Refused: split point splits return value and bounds\n");
+ return;
+ }
+ }
+
/* split_function fixes up at most one PHI non-virtual PHI node in return_bb,
for the return value. If there are other PHIs, give up. */
if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
@@ -753,6 +791,18 @@ find_retval (basic_block return_bb)
return NULL;
}
+/* Given return basic block RETURN_BB, see where return bounds are really
+ stored. */
+static tree
+find_retbnd (basic_block return_bb)
+{
+ gimple_stmt_iterator bsi;
+ for (bsi = gsi_last_bb (return_bb); !gsi_end_p (bsi); gsi_prev (&bsi))
+ if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
+ return gimple_return_retbnd (gsi_stmt (bsi));
+ return NULL;
+}
+
/* Callback for walk_stmt_load_store_addr_ops. If T is non-SSA automatic
variable, mark it as used in bitmap passed via DATA.
Return true when access to T prevents splitting the function. */
@@ -1123,6 +1173,19 @@ find_split_points (int overall_time, int overall_size)
BITMAP_FREE (current.ssa_names_to_pass);
}
+/* Build and insert initialization of returned bounds RETBND
+ for returned value RETVAL. Statements are inserted after
+ a statement pointed by GSI and GSI is modified to point to
+ the last inserted statement. */
+
+static void
+insert_bndret_call_after (tree retbnd, tree retval, gimple_stmt_iterator *gsi)
+{
+ tree fndecl = targetm.builtin_chkp_function (BUILT_IN_CHKP_BNDRET);
+ gimple bndret = gimple_build_call (fndecl, 1, retval);
+ gimple_call_set_lhs (bndret, retbnd);
+ gsi_insert_after (gsi, bndret, GSI_CONTINUE_LINKING);
+}
/* Split function at SPLIT_POINT. */
static void
@@ -1139,8 +1202,9 @@ split_function (struct split_point *split_point)
gimple call;
edge e;
edge_iterator ei;
- tree retval = NULL, real_retval = NULL;
+ tree retval = NULL, real_retval = NULL, retbnd = NULL;
bool split_part_return_p = false;
+ bool with_bounds = chkp_function_instrumented_p (current_function_decl);
gimple last_stmt = NULL;
unsigned int i;
tree arg, ddef;
@@ -1289,6 +1353,12 @@ split_function (struct split_point *split_point)
DECL_BUILT_IN_CLASS (node->decl) = NOT_BUILT_IN;
DECL_FUNCTION_CODE (node->decl) = (enum built_in_function) 0;
}
+
+ /* If the original function is instrumented then it's
+ part is also instrumented. */
+ if (with_bounds)
+ chkp_function_mark_instrumented (node->decl);
+
/* If the original function is declared inline, there is no point in issuing
a warning for the non-inlinable part. */
DECL_NO_INLINE_WARNING_P (node->decl) = 1;
@@ -1323,6 +1393,7 @@ split_function (struct split_point *split_point)
args_to_pass[i] = arg;
}
call = gimple_build_call_vec (node->decl, args_to_pass);
+ gimple_call_set_with_bounds (call, with_bounds);
gimple_set_block (call, DECL_INITIAL (current_function_decl));
args_to_pass.release ();
@@ -1429,6 +1500,7 @@ split_function (struct split_point *split_point)
if (return_bb != EXIT_BLOCK_PTR_FOR_FN (cfun))
{
real_retval = retval = find_retval (return_bb);
+ retbnd = find_retbnd (return_bb);
if (real_retval && split_point->split_part_set_retval)
{
@@ -1473,6 +1545,21 @@ split_function (struct split_point *split_point)
}
update_stmt (gsi_stmt (bsi));
}
+
+ /* Replace retbnd with new one. */
+ if (retbnd)
+ {
+ gimple_stmt_iterator bsi;
+ for (bsi = gsi_last_bb (return_bb); !gsi_end_p (bsi);
+ gsi_prev (&bsi))
+ if (gimple_code (gsi_stmt (bsi)) == GIMPLE_RETURN)
+ {
+ retbnd = copy_ssa_name (retbnd, call);
+ gimple_return_set_retbnd (gsi_stmt (bsi), retbnd);
+ update_stmt (gsi_stmt (bsi));
+ break;
+ }
+ }
}
if (DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
{
@@ -1494,6 +1581,9 @@ split_function (struct split_point *split_point)
gsi_insert_after (&gsi, cpy, GSI_NEW_STMT);
retval = tem;
}
+ /* Build bndret call to obtain returned bounds. */
+ if (retbnd)
+ insert_bndret_call_after (retbnd, retval, &gsi);
gimple_call_set_lhs (call, retval);
update_stmt (call);
}
@@ -1512,6 +1602,10 @@ split_function (struct split_point *split_point)
{
retval = DECL_RESULT (current_function_decl);
+ if (chkp_function_instrumented_p (current_function_decl)
+ && BOUNDED_P (retval))
+ retbnd = create_tmp_reg (pointer_bounds_type_node, NULL);
+
/* We use temporary register to hold value when aggregate_value_p
is false. Similarly for DECL_BY_REFERENCE we must avoid extra
copy. */
@@ -1535,6 +1629,9 @@ split_function (struct split_point *split_point)
gimple_call_set_lhs (call, retval);
}
gsi_insert_after (&gsi, call, GSI_NEW_STMT);
+ /* Build bndret call to obtain returned bounds. */
+ if (retbnd)
+ insert_bndret_call_after (retbnd, retval, &gsi);
ret = gimple_build_return (retval);
gsi_insert_after (&gsi, ret, GSI_NEW_STMT);
}