diff options
Diffstat (limited to 'gcc/ipa-split.c')
-rw-r--r-- | gcc/ipa-split.c | 107 |
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); } |