diff options
-rw-r--r-- | gcc/ChangeLog | 21 | ||||
-rw-r--r-- | gcc/gimple.h | 24 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 62 | ||||
-rw-r--r-- | gcc/tree-cfgcleanup.c | 61 | ||||
-rw-r--r-- | gcc/tree-ssa-operands.c | 6 | ||||
-rw-r--r-- | gcc/tree-ssanames.h | 1 |
7 files changed, 128 insertions, 56 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 40c0a99..8f9b113 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,24 @@ +2014-08-20 Martin Jambor <mjambor@suse.cz> + Wei Mi <wmi@google.com> + + PR ipa/60449 + PR middle-end/61776 + * tree-ssa-operands.c (update_stmt_operands): Remove + MODIFIED_NORETURN_CALLS. + * tree-cfgcleanup.c (cleanup_call_ctrl_altering_flag): New func. + (cleanup_control_flow_bb): Use cleanup_call_ctrl_altering_flag. + (split_bb_on_noreturn_calls): Renamed from split_bbs_on_noreturn_calls. + (cleanup_tree_cfg_1): Use split_bb_on_noreturn_calls. + * tree-ssanames.h: Remove MODIFIED_NORETURN_CALLS. + * gimple.h (enum gf_mask): Add GF_CALL_CTRL_ALTERING. + (gimple_call_set_ctrl_altering): New func. + (gimple_call_ctrl_altering_p): Ditto. + * tree-cfg.c (gimple_call_initialize_ctrl_altering): Ditto. + (make_blocks): Use gimple_call_initialize_ctrl_altering. + (is_ctrl_altering_stmt): Use gimple_call_ctrl_altering_p. + (execute_fixup_cfg): Use gimple_call_ctrl_altering_p and + remove MODIFIED_NORETURN_CALLS. + 2014-08-20 Jan Hubicka <hubicka@ucw.cz> * coverage.c (coverage_compute_profile_id): Return non-0; diff --git a/gcc/gimple.h b/gcc/gimple.h index a517dee..51814ba 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -90,6 +90,7 @@ enum gf_mask { GF_CALL_NOTHROW = 1 << 4, GF_CALL_ALLOCA_FOR_VAR = 1 << 5, GF_CALL_INTERNAL = 1 << 6, + GF_CALL_CTRL_ALTERING = 1 << 7, GF_OMP_PARALLEL_COMBINED = 1 << 0, GF_OMP_FOR_KIND_MASK = (1 << 2) - 1, GF_OMP_FOR_KIND_FOR = 0, @@ -2459,6 +2460,29 @@ gimple_call_internal_fn (const_gimple gs) return static_cast <const gimple_statement_call *> (gs)->u.internal_fn; } +/* If CTRL_ALTERING_P is true, mark GIMPLE_CALL S to be a stmt + that could alter control flow. */ + +static inline void +gimple_call_set_ctrl_altering (gimple s, bool ctrl_altering_p) +{ + GIMPLE_CHECK (s, GIMPLE_CALL); + if (ctrl_altering_p) + s->subcode |= GF_CALL_CTRL_ALTERING; + else + s->subcode &= ~GF_CALL_CTRL_ALTERING; +} + +/* Return true if call GS calls an func whose GF_CALL_CTRL_ALTERING + flag is set. Such call could not be a stmt in the middle of a bb. */ + +static inline bool +gimple_call_ctrl_altering_p (const_gimple gs) +{ + GIMPLE_CHECK (gs, GIMPLE_CALL); + return (gs->subcode & GF_CALL_CTRL_ALTERING) != 0; +} + /* Return the function type of the function called by GS. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ab39fd6..0957925 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2014-08-20 Martin Jambor <mjambor@suse.cz> + Wei Mi <wmi@google.com> + + PR ipa/60449 + PR middle-end/61776 + * testsuite/gcc.dg/lto/pr60449_1.c: New test. + * testsuite/gcc.dg/lto/pr60449_0.c: New test. + * testsuite/gcc.dg/pr61776.c: New test. + 2014-08-20 Steve Ellcey <sellcey@mips.com> PR middle-end/49191 diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 9d1de010..700a998 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -164,6 +164,7 @@ static int gimple_verify_flow_info (void); static void gimple_make_forwarder_block (edge); static gimple first_non_label_stmt (basic_block); static bool verify_gimple_transaction (gimple); +static bool call_can_make_abnormal_goto (gimple); /* Flowgraph optimization and cleanup. */ static void gimple_merge_blocks (basic_block, basic_block); @@ -437,6 +438,32 @@ assert_unreachable_fallthru_edge_p (edge e) } +/* Initialize GF_CALL_CTRL_ALTERING flag, which indicates the call + could alter control flow except via eh. We initialize the flag at + CFG build time and only ever clear it later. */ + +static void +gimple_call_initialize_ctrl_altering (gimple stmt) +{ + int flags = gimple_call_flags (stmt); + + /* A call alters control flow if it can make an abnormal goto. */ + if (call_can_make_abnormal_goto (stmt) + /* A call also alters control flow if it does not return. */ + || flags & ECF_NORETURN + /* TM ending statements have backedges out of the transaction. + Return true so we split the basic block containing them. + Note that the TM_BUILTIN test is merely an optimization. */ + || ((flags & ECF_TM_BUILTIN) + && is_tm_ending_fndecl (gimple_call_fndecl (stmt))) + /* BUILT_IN_RETURN call is same as return statement. */ + || gimple_call_builtin_p (stmt, BUILT_IN_RETURN)) + gimple_call_set_ctrl_altering (stmt, true); + else + gimple_call_set_ctrl_altering (stmt, false); +} + + /* Build a flowgraph for the sequence of stmts SEQ. */ static void @@ -455,6 +482,9 @@ make_blocks (gimple_seq seq) prev_stmt = stmt; stmt = gsi_stmt (i); + if (stmt && is_gimple_call (stmt)) + gimple_call_initialize_ctrl_altering (stmt); + /* If the statement starts a new basic block or if we have determined in a previous pass that we need to create a new block for STMT, do so now. */ @@ -2372,28 +2402,10 @@ is_ctrl_altering_stmt (gimple t) switch (gimple_code (t)) { case GIMPLE_CALL: - { - int flags = gimple_call_flags (t); - - /* A call alters control flow if it can make an abnormal goto. */ - if (call_can_make_abnormal_goto (t)) - return true; - - /* A call also alters control flow if it does not return. */ - if (flags & ECF_NORETURN) - return true; - - /* TM ending statements have backedges out of the transaction. - Return true so we split the basic block containing them. - Note that the TM_BUILTIN test is merely an optimization. */ - if ((flags & ECF_TM_BUILTIN) - && is_tm_ending_fndecl (gimple_call_fndecl (t))) - return true; - - /* BUILT_IN_RETURN call is same as return statement. */ - if (gimple_call_builtin_p (t, BUILT_IN_RETURN)) - return true; - } + /* Per stmt call flag indicates whether the call could alter + controlflow. */ + if (gimple_call_ctrl_altering_p (t)) + return true; break; case GIMPLE_EH_DISPATCH: @@ -8533,6 +8545,8 @@ execute_fixup_cfg (void) && (!is_gimple_call (stmt) || (gimple_call_flags (stmt) & ECF_NORETURN) == 0))) { + if (stmt && is_gimple_call (stmt)) + gimple_call_set_ctrl_altering (stmt, false); stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0); gimple_stmt_iterator gsi = gsi_last_bb (bb); @@ -8543,10 +8557,6 @@ execute_fixup_cfg (void) if (count_scale != REG_BR_PROB_BASE) compute_function_frequency (); - /* We just processed all calls. */ - if (cfun->gimple_df) - vec_free (MODIFIED_NORETURN_CALLS (cfun)); - /* Dump a textual representation of the flowgraph. */ if (dump_file) gimple_dump_cfg (dump_file, dump_flags); diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 2b6927e..a66ec6e 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -162,6 +162,23 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi) return retval; } +/* Cleanup the GF_CALL_CTRL_ALTERING flag according to + to updated gimple_call_flags. */ + +static void +cleanup_call_ctrl_altering_flag (gimple bb_end) +{ + if (!is_gimple_call (bb_end) + || !gimple_call_ctrl_altering_p (bb_end)) + return; + + int flags = gimple_call_flags (bb_end); + if (((flags & (ECF_CONST | ECF_PURE)) + && !(flags & ECF_LOOPING_CONST_OR_PURE)) + || (flags & ECF_LEAF)) + gimple_call_set_ctrl_altering (bb_end, false); +} + /* Try to remove superfluous control structures in basic block BB. Returns true if anything changes. */ @@ -182,6 +199,9 @@ cleanup_control_flow_bb (basic_block bb) stmt = gsi_stmt (gsi); + /* Try to cleanup ctrl altering flag for call which ends bb. */ + cleanup_call_ctrl_altering_flag (stmt); + if (gimple_code (stmt) == GIMPLE_COND || gimple_code (stmt) == GIMPLE_SWITCH) retval |= cleanup_control_expr_graph (bb, gsi); @@ -594,30 +614,24 @@ fixup_noreturn_call (gimple stmt) known not to return, and remove the unreachable code. */ static bool -split_bbs_on_noreturn_calls (void) +split_bb_on_noreturn_calls (basic_block bb) { bool changed = false; - gimple stmt; - basic_block bb; + gimple_stmt_iterator gsi; - /* Detect cases where a mid-block call is now known not to return. */ - if (cfun->gimple_df) - while (vec_safe_length (MODIFIED_NORETURN_CALLS (cfun))) - { - stmt = MODIFIED_NORETURN_CALLS (cfun)->pop (); - bb = gimple_bb (stmt); - /* BB might be deleted at this point, so verify first - BB is present in the cfg. */ - if (bb == NULL - || bb->index < NUM_FIXED_BLOCKS - || bb->index >= last_basic_block_for_fn (cfun) - || BASIC_BLOCK_FOR_FN (cfun, bb->index) != bb - || !gimple_call_noreturn_p (stmt)) - continue; + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (!is_gimple_call (stmt)) + continue; + + if (gimple_call_noreturn_p (stmt)) changed |= fixup_noreturn_call (stmt); - } + } + if (changed) + bitmap_set_bit (cfgcleanup_altered_bbs, bb->index); return changed; } @@ -655,8 +669,6 @@ cleanup_tree_cfg_1 (void) basic_block bb; unsigned i, n; - retval |= split_bbs_on_noreturn_calls (); - /* Prepare the worklists of altered blocks. */ cfgcleanup_altered_bbs = BITMAP_ALLOC (NULL); @@ -672,7 +684,10 @@ cleanup_tree_cfg_1 (void) { bb = BASIC_BLOCK_FOR_FN (cfun, i); if (bb) - retval |= cleanup_tree_cfg_bb (bb); + { + retval |= cleanup_tree_cfg_bb (bb); + retval |= split_bb_on_noreturn_calls (bb); + } } /* Now process the altered blocks, as long as any are available. */ @@ -689,9 +704,9 @@ cleanup_tree_cfg_1 (void) retval |= cleanup_tree_cfg_bb (bb); - /* Rerun split_bbs_on_noreturn_calls, in case we have altered any noreturn + /* Rerun split_bb_on_noreturn_calls, in case we have altered any noreturn calls. */ - retval |= split_bbs_on_noreturn_calls (); + retval |= split_bb_on_noreturn_calls (bb); } end_recording_case_labels (); diff --git a/gcc/tree-ssa-operands.c b/gcc/tree-ssa-operands.c index a939d41..a7ccf04 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -1087,12 +1087,6 @@ update_stmt_operands (struct function *fn, gimple stmt) timevar_push (TV_TREE_OPS); - /* If the stmt is a noreturn call queue it to be processed by - split_bbs_on_noreturn_calls during cfg cleanup. */ - if (is_gimple_call (stmt) - && gimple_call_noreturn_p (stmt)) - vec_safe_push (MODIFIED_NORETURN_CALLS (fn), stmt); - gcc_assert (gimple_modified_p (stmt)); build_ssa_operands (fn, stmt); gimple_set_modified (stmt, false); diff --git a/gcc/tree-ssanames.h b/gcc/tree-ssanames.h index 4fc9f69..22570cd 100644 --- a/gcc/tree-ssanames.h +++ b/gcc/tree-ssanames.h @@ -57,7 +57,6 @@ struct GTY ((variable_size)) range_info_def { #define SSANAMES(fun) (fun)->gimple_df->ssa_names -#define MODIFIED_NORETURN_CALLS(fun) (fun)->gimple_df->modified_noreturn_calls #define DEFAULT_DEFS(fun) (fun)->gimple_df->default_defs #define num_ssa_names (vec_safe_length (cfun->gimple_df->ssa_names)) |