diff options
| author | wmi <wmi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-08-20 17:09:25 +0000 |
|---|---|---|
| committer | wmi <wmi@138bc75d-0d04-0410-961f-82ee72b054a4> | 2014-08-20 17:09:25 +0000 |
| commit | 8cd632ca12901df4f20e5983aacdac27613e2c7c (patch) | |
| tree | 4d6703dd7b75169c7eb611e76e526578ffb7ea68 | |
| parent | b8ee8ca8fffbf2c32a8b76f1b4cabb0544b0c1e4 (diff) | |
| download | ppe42-gcc-8cd632ca12901df4f20e5983aacdac27613e2c7c.tar.gz ppe42-gcc-8cd632ca12901df4f20e5983aacdac27613e2c7c.zip | |
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 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.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/gcc-4_9-branch@214237 138bc75d-0d04-0410-961f-82ee72b054a4
| -rw-r--r-- | gcc/ChangeLog | 21 | ||||
| -rw-r--r-- | gcc/gimple.h | 24 | ||||
| -rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
| -rw-r--r-- | gcc/testsuite/gcc.dg/lto/pr60449_0.c | 30 | ||||
| -rw-r--r-- | gcc/testsuite/gcc.dg/lto/pr60449_1.c | 76 | ||||
| -rw-r--r-- | gcc/testsuite/gcc.dg/pr61776.c | 27 | ||||
| -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 |
10 files changed, 261 insertions, 56 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3ae03d8f9c7..eb05afa9ce7 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 Ramana Radhakrishnan <ramana.radhakrishnan@arm.com> Backport from mainline. diff --git a/gcc/gimple.h b/gcc/gimple.h index 11959a82e62..50a5a8620c3 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 = 3 << 0, GF_OMP_FOR_KIND_FOR = 0 << 0, @@ -2447,6 +2448,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 a1106d1c038..14e3788f857 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-19 Janis Johnson <janisjo@codesourcery.com> Backport from mainline: diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_0.c b/gcc/testsuite/gcc.dg/lto/pr60449_0.c new file mode 100644 index 00000000000..a430830cbed --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr60449_0.c @@ -0,0 +1,30 @@ +/* { dg-lto-do link } */ + +extern int printf (const char *__restrict __format, ...); +typedef long int __time_t; +typedef long int __suseconds_t; + +struct timeval + { + __time_t tv_sec; + __suseconds_t tv_usec; + }; + +struct timezone + { + int tz_minuteswest; + int tz_dsttime; + }; +typedef struct timezone *__restrict __timezone_ptr_t; + +extern int gettimeofday (struct timeval *__restrict __tv, __timezone_ptr_t __tz); + +int bar (void) +{ + struct timeval tv; + struct timezone tz; + + gettimeofday (&tv, &tz); + printf ("This is from bar %i\n", tz.tz_dsttime); + return 5; +} diff --git a/gcc/testsuite/gcc.dg/lto/pr60449_1.c b/gcc/testsuite/gcc.dg/lto/pr60449_1.c new file mode 100644 index 00000000000..ddc25296d8a --- /dev/null +++ b/gcc/testsuite/gcc.dg/lto/pr60449_1.c @@ -0,0 +1,76 @@ +extern int printf (const char *__restrict __format, ...); +typedef long int __time_t; +typedef long int __suseconds_t; +struct timeval + { + __time_t tv_sec; + __suseconds_t tv_usec; + }; +struct timezone + { + int tz_minuteswest; + int tz_dsttime; + }; +typedef struct timezone *__restrict __timezone_ptr_t; +extern int gettimeofday (struct timeval *__restrict __tv, + __timezone_ptr_t __tz) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__nonnull__ (1))); + +typedef long int __jmp_buf[8]; +typedef struct + { + unsigned long int __val[(1024 / (8 * sizeof (unsigned long int)))]; + } __sigset_t; +struct __jmp_buf_tag + { + __jmp_buf __jmpbuf; + int __mask_was_saved; + __sigset_t __saved_mask; + }; +typedef struct __jmp_buf_tag jmp_buf[1]; + +extern int setjmp (jmp_buf __env) __attribute__ ((__nothrow__)); +extern void longjmp (struct __jmp_buf_tag __env[1], int __val) + __attribute__ ((__nothrow__)) __attribute__ ((__noreturn__)); + +extern int bar (void); + +int __attribute__ ((noinline, noclone)) +get_input (void) +{ + return 0; +} + +static jmp_buf buf; + +int foo (void) +{ + if (get_input ()) + longjmp(buf, 1); + return 0; +} + +volatile int z; + + +int main (void) +{ + struct timeval tv; + struct timezone tz; + + bar(); + if (setjmp (buf)) + return 1; + + if (!get_input ()) + { + gettimeofday (&tv, &tz); + z = 0; + printf ("This is from main %i\n", tz.tz_dsttime); + } + + foo (); + bar (); + bar (); + + return 0; +} diff --git a/gcc/testsuite/gcc.dg/pr61776.c b/gcc/testsuite/gcc.dg/pr61776.c new file mode 100644 index 00000000000..8768c546bda --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr61776.c @@ -0,0 +1,27 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fprofile-generate" } */ + +#include <setjmp.h> + +int cond1, cond2; + +int goo() __attribute__((noinline)); + +int goo() { + if (cond1) + return 1; + else + return 2; +} + +jmp_buf env; +int foo() { + int a; + + setjmp(env); + if (cond2) + a = goo(); + else + a = 3; + return a; +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 56b6c3595b8..1469d782f73 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -162,6 +162,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); @@ -424,6 +425,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 @@ -442,6 +469,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. */ @@ -2349,28 +2379,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: @@ -8470,6 +8482,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); @@ -8480,10 +8494,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 b7882cf6762..51b764f816a 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 c525fe579ea..76d046309bc 100644 --- a/gcc/tree-ssa-operands.c +++ b/gcc/tree-ssa-operands.c @@ -1091,12 +1091,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 bb3b5e6c1df..b8729ad1242 100644 --- a/gcc/tree-ssanames.h +++ b/gcc/tree-ssanames.h @@ -58,7 +58,6 @@ struct GTY (()) 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)) |

