diff options
author | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-05-30 12:19:15 +0000 |
---|---|---|
committer | hubicka <hubicka@138bc75d-0d04-0410-961f-82ee72b054a4> | 2010-05-30 12:19:15 +0000 |
commit | fc94a528c3d458df4efa5634622b145a9bb46071 (patch) | |
tree | 95c8141edd637bb1eaf3d0b8672e60d8c734e72b | |
parent | 64a6fb275006cad125879af9db6dcbe991ebdf57 (diff) | |
download | gcc-fc94a528c3d458df4efa5634622b145a9bb46071.tar.gz |
* cgraph.h (cgraph_node_cannot_return,
cgraph_edge_cannot_lead_to_return): New functions.
* cgraph.c (cgraph_node_cannot_return,
cgraph_edge_cannot_lead_to_return): Use them.
* ipa-pure-const.c (pure_const_names): New static var.
(check_call): Handle calls not leading to return.
(pure_const_read_summary): Dump info read.
(propagate): Dump info about propagation process; ignore side
effects of functions not leading to exit; fix handling of
pure functions.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@160051 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/cgraph.c | 35 | ||||
-rw-r--r-- | gcc/cgraph.h | 2 | ||||
-rw-r--r-- | gcc/ipa-pure-const.c | 132 |
4 files changed, 170 insertions, 12 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 005db41a894..b31797b19b1 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2010-05-30 Jan Hubicka <jh@suse.cz> + * cgraph.h (cgraph_node_cannot_return, + cgraph_edge_cannot_lead_to_return): New functions. + * cgraph.c (cgraph_node_cannot_return, + cgraph_edge_cannot_lead_to_return): Use them. + * ipa-pure-const.c (pure_const_names): New static var. + (check_call): Handle calls not leading to return. + (pure_const_read_summary): Dump info read. + (propagate): Dump info about propagation process; ignore side + effects of functions not leading to exit; fix handling of + pure functions. + +2010-05-30 Jan Hubicka <jh@suse.cz> + * config/i386/i386.c (pro_epilogue_adjust_stack): Use EBP for tail call epilogues. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index 8c7916865fe..0c2441fcf6f 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -2584,4 +2584,39 @@ cgraph_propagate_frequency (struct cgraph_node *node) return false; } +/* Return true when NODE can not return or throw and thus + it is safe to ignore its side effects for IPA analysis. */ + +bool +cgraph_node_cannot_return (struct cgraph_node *node) +{ + int flags = flags_from_decl_or_type (node->decl); + if (!flag_exceptions) + return (flags & ECF_NORETURN) != 0; + else + return ((flags & (ECF_NORETURN | ECF_NOTHROW)) + == (ECF_NORETURN | ECF_NOTHROW)); +} + +/* Return true when call of E can not lead to return from caller + and thus it is safe to ignore its side effects for IPA analysis + when computing side effects of the caller. + FIXME: We could actually mark all edges that have no reaching + patch to EXIT_BLOCK_PTR or throw to get better results. */ +bool +cgraph_edge_cannot_lead_to_return (struct cgraph_edge *e) +{ + if (e->indirect_unknown_callee) + { + int flags = e->indirect_info->ecf_flags; + if (!flag_exceptions) + return (flags & ECF_NORETURN) != 0; + else + return ((flags & (ECF_NORETURN | ECF_NOTHROW)) + == (ECF_NORETURN | ECF_NOTHROW)); + } + else + return cgraph_node_cannot_return (e->callee); +} + #include "gt-cgraph.h" diff --git a/gcc/cgraph.h b/gcc/cgraph.h index 5b1960f819f..8e2be0862c4 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -594,6 +594,8 @@ void cgraph_set_readonly_flag (struct cgraph_node *, bool); void cgraph_set_pure_flag (struct cgraph_node *, bool); void cgraph_set_looping_const_or_pure_flag (struct cgraph_node *, bool); tree clone_function_name (tree decl, const char *); +bool cgraph_node_cannot_return (struct cgraph_node *); +bool cgraph_edge_cannot_lead_to_return (struct cgraph_edge *); /* In cgraphunit.c */ void cgraph_finalize_function (tree, bool); diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c index 02a1e0386ab..864e49dc8a9 100644 --- a/gcc/ipa-pure-const.c +++ b/gcc/ipa-pure-const.c @@ -72,6 +72,8 @@ enum pure_const_state_e IPA_NEITHER }; +const char *pure_const_names[3] = {"const", "pure", "neither"}; + /* Holder for the const_state. There is one of these per function decl. */ struct funct_state_d @@ -445,6 +447,16 @@ check_call (funct_state local, gimple call, bool ipa) if (local->pure_const_state == IPA_CONST) local->pure_const_state = IPA_PURE; } + else if ((flags & (ECF_NORETURN | ECF_NOTHROW)) + == (ECF_NORETURN | ECF_NOTHROW) + || (!flag_exceptions && (flags & ECF_NORETURN))) + { + if (dump_file) + fprintf (dump_file, " noreturn nothrow call is looping pure\n"); + if (local->pure_const_state == IPA_CONST) + local->pure_const_state = IPA_PURE; + local->looping = true; + } else { if (dump_file) @@ -872,6 +884,29 @@ pure_const_read_summary (void) fs->looping_previously_known = bp_unpack_value (bp, 1); fs->looping = bp_unpack_value (bp, 1); fs->can_throw = bp_unpack_value (bp, 1); + if (dump_file) + { + int flags = flags_from_decl_or_type (node->decl); + fprintf (dump_file, "Read info for %s/%i ", + cgraph_node_name (node), + node->uid); + if (flags & ECF_CONST) + fprintf (dump_file, " const"); + if (flags & ECF_PURE) + fprintf (dump_file, " pure"); + if (flags & ECF_NOTHROW) + fprintf (dump_file, " nothrow"); + fprintf (dump_file, "\n pure const state: %s\n", + pure_const_names[fs->pure_const_state]); + fprintf (dump_file, " previously known state: %s\n", + pure_const_names[fs->looping_previously_known]); + if (fs->looping) + fprintf (dump_file," function is locally looping\n"); + if (fs->looping_previously_known) + fprintf (dump_file," function is previously known looping\n"); + if (fs->can_throw) + fprintf (dump_file," function is locally throwing\n"); + } bitpack_delete (bp); } @@ -938,12 +973,21 @@ propagate (void) int count = 0; node = order[i]; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Starting cycle\n"); + /* Find the worst state for any node in the cycle. */ w = node; while (w) { struct cgraph_edge *e; funct_state w_l = get_function_state (w); + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " Visiting %s/%i state:%s looping %i\n", + cgraph_node_name (w), + w->uid, + pure_const_names[w_l->pure_const_state], + w_l->looping); if (pure_const_state < w_l->pure_const_state) pure_const_state = w_l->pure_const_state; @@ -954,6 +998,13 @@ propagate (void) looping |= w_l->looping_previously_known; if (pure_const_state < w_l->state_previously_known) pure_const_state = w_l->state_previously_known; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + " Overwritable. state %s looping %i\n", + pure_const_names[w_l->state_previously_known], + w_l->looping_previously_known); + } } if (pure_const_state == IPA_NEITHER) @@ -967,35 +1018,92 @@ propagate (void) for (e = w->callees; e; e = e->next_callee) { struct cgraph_node *y = e->callee; + enum pure_const_state_e edge_state = IPA_CONST; + bool edge_looping = false; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + " Call to %s/%i", + cgraph_node_name (e->callee), + e->callee->uid); + } if (cgraph_function_body_availability (y) > AVAIL_OVERWRITABLE) { funct_state y_l = get_function_state (y); - if (pure_const_state < y_l->pure_const_state) - pure_const_state = y_l->pure_const_state; - if (pure_const_state == IPA_NEITHER) - break; - if (y_l->looping) - looping = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + " state:%s looping:%i\n", + pure_const_names[y_l->pure_const_state], + y_l->looping); + } + else if (y_l->pure_const_state > ECF_PURE + && cgraph_edge_cannot_lead_to_return (e)) + { + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + " Ignoring side effects -> pure, looping\n"); + } + edge_state = IPA_PURE; + edge_looping = true; + } + else + { + edge_state = y_l->pure_const_state; + edge_looping = y_l->looping; + } } else { int flags = flags_from_decl_or_type (y->decl); if (flags & ECF_LOOPING_CONST_OR_PURE) - looping = true; + { + edge_looping = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " unavailable looping"); + } if (flags & ECF_CONST) - ; - else if ((flags & ECF_PURE) && pure_const_state == IPA_CONST) - pure_const_state = IPA_PURE; + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " const\n"); + } + else if (flags & ECF_PURE) + { + edge_state = IPA_PURE; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " pure\n"); + } + else if (cgraph_edge_cannot_lead_to_return (e)) + { + edge_state = IPA_PURE; + edge_looping = true; + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " ignoring side effects->pure looping\n"); + } else - pure_const_state = IPA_NEITHER, looping = true; - + { + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, " neihter\n"); + edge_state = IPA_NEITHER; + edge_looping = true; + } } + pure_const_state = MAX (pure_const_state, MIN (edge_state, + w_l->state_previously_known)); + looping = MAX (looping, MIN (edge_looping, edge_state)); + if (pure_const_state == IPA_NEITHER) + break; } w_info = (struct ipa_dfs_info *) w->aux; w = w_info->next_cycle; } + if (dump_file && (dump_flags & TDF_DETAILS)) + fprintf (dump_file, "Result %s looping %i\n", + pure_const_names [pure_const_state], + looping); /* Copy back the region's pure_const_state which is shared by all nodes in the region. */ |