Message ID | ri6r2d0vcal.fsf@suse.cz |
---|---|
State | New |
Headers | show |
Series | [PR,ipa/88933] Careful CFG cleanup in IPA-CP function transformation | expand |
Dne 2019-01-25 19:10, Martin Jambor napsal: > Hi, > > the following patch fixes a verification ICE because of mismatching BB > and cgraph_edge counts arising as a consequence of cleaning-up CFG > after > IPA-CP transformation, which is currently done as if it was a normal > tree pass, and which IPA passes should not attempt exaclty because of > this reason. > > Fixed (hopefully) exactly as I was told by Honza in Bugzilla, by > resorting to calling delete_unreachable_blocks_update_callgraph > instead. The aforementioned function had to be made public and in the > process was moved to a more suitable file. > > Bootstrapped and tested on x86_64-linux. OK for trunk? OK, Honza > > Thanks, > > Martin > > > > 2019-01-25 Martin Jambor <mjambor@suse.cz> > > * tree-inline.c: Include tree-cfgcleanup.h. > (delete_unreachable_blocks_update_callgraph): Move... > * tree-cfgcleanup.c (delete_unreachable_blocks_update_callgraph): > ...here, make externally visible, make second argument bool, adjust > all callers. > * tree-cfgcleanup.c: Include cgraph.h. > * tree-cfgcleanup.h (delete_unreachable_blocks_update_callgraph): > Declare. > * ipa-prop.c: Include tree-cfgcleanup.h. > (ipcp_transform_function): Call > delete_unreachable_blocks_update_callgraph instead of cleaning uo CFG. > > testsuite/ > * gfortran.dg/gomp/pr88933.f90: New test. > --- > gcc/ipa-prop.c | 10 +-- > gcc/testsuite/gfortran.dg/gomp/pr88933.f90 | 39 +++++++++++ > gcc/tree-cfgcleanup.c | 75 +++++++++++++++++++- > gcc/tree-cfgcleanup.h | 2 + > gcc/tree-inline.c | 80 ++-------------------- > 5 files changed, 125 insertions(+), 81 deletions(-) > create mode 100644 gcc/testsuite/gfortran.dg/gomp/pr88933.f90 > > diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c > index 40ab130b750..d86c2f3db55 100644 > --- a/gcc/ipa-prop.c > +++ b/gcc/ipa-prop.c > @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see > #include "dbgcnt.h" > #include "domwalk.h" > #include "builtins.h" > +#include "tree-cfgcleanup.h" > > /* Function summary where the parameter infos are actually stored. */ > ipa_node_params_t *ipa_node_params_sum = NULL; > @@ -5173,10 +5174,11 @@ ipcp_transform_function (struct cgraph_node > *node) > > if (!something_changed) > return 0; > - else if (cfg_changed) > - return TODO_update_ssa_only_virtuals | TODO_cleanup_cfg; > - else > - return TODO_update_ssa_only_virtuals; > + > + if (cfg_changed) > + delete_unreachable_blocks_update_callgraph (node, false); > + > + return TODO_update_ssa_only_virtuals; > } > > #include "gt-ipa-prop.h" > diff --git a/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 > b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 > new file mode 100644 > index 00000000000..e4f30ae9f3e > --- /dev/null > +++ b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 > @@ -0,0 +1,39 @@ > +! PR ipa/88933 > +! { dg-do compile } > +! { dg-options "-O1 -fexceptions -fipa-cp -fnon-call-exceptions > -fopenmp -fno-inline-functions-called-once" } > + > +!$omp parallel > +!$omp single > + call a > +!$omp end single > +!$omp end parallel > +contains > + subroutine b (c, d, e, f, g, h, i, j, k, m) > + character (*) c > + character d > + integer, dimension (m) :: e > + integer, dimension (m) :: f > + character g > + character h > + real, dimension (:, :, :) :: i > + double precision, dimension (:, :, :) :: j > + integer, dimension (:, :, :) :: k > + > + integer, dimension (m) :: l > +!$omp task firstprivate (k) firstprivate (l) > + !$omp end task > + c = '' > + end > + subroutine a > + character c > + character d > + integer, dimension (7) :: e > + integer, dimension (7) :: f > + character g > + character h > + real, dimension (5, 6, 7) :: i > + double precision, dimension (6, 6, 7) :: j > + integer, dimension (5, 7, 6) :: k > + call b (c, d, e, f, g, h, i, j, k, 7) > + end > +end > diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c > index 2adb3953d6b..f2e8b96ee8e 100644 > --- a/gcc/tree-cfgcleanup.c > +++ b/gcc/tree-cfgcleanup.c > @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see > #include "gimple-match.h" > #include "gimple-fold.h" > #include "tree-ssa-loop-niter.h" > - > +#include "cgraph.h" > > /* The set of blocks in that at least one of the following changes > happened: > -- the statement at the end of the block was changed > @@ -1380,3 +1380,76 @@ make_pass_cleanup_cfg_post_optimizing > (gcc::context *ctxt) > } > > > +/* Delete all unreachable basic blocks and update callgraph. > + Doing so is somewhat nontrivial because we need to update all > clones and > + remove inline function that become unreachable. */ > + > +bool > +delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node, > + bool update_clones) > +{ > + bool changed = false; > + basic_block b, next_bb; > + > + find_unreachable_blocks (); > + > + /* Delete all unreachable basic blocks. */ > + > + for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b > + != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb) > + { > + next_bb = b->next_bb; > + > + if (!(b->flags & BB_REACHABLE)) > + { > + gimple_stmt_iterator bsi; > + > + for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next > (&bsi)) > + { > + struct cgraph_edge *e; > + struct cgraph_node *node; > + > + dst_node->remove_stmt_references (gsi_stmt (bsi)); > + > + if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL > + &&(e = dst_node->get_edge (gsi_stmt (bsi))) != NULL) > + { > + if (!e->inline_failed) > + e->callee->remove_symbol_and_inline_clones (dst_node); > + else > + e->remove (); > + } > + if (update_clones && dst_node->clones) > + for (node = dst_node->clones; node != dst_node;) > + { > + node->remove_stmt_references (gsi_stmt (bsi)); > + if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL > + && (e = node->get_edge (gsi_stmt (bsi))) != NULL) > + { > + if (!e->inline_failed) > + e->callee->remove_symbol_and_inline_clones (dst_node); > + else > + e->remove (); > + } > + > + if (node->clones) > + node = node->clones; > + else if (node->next_sibling_clone) > + node = node->next_sibling_clone; > + else > + { > + while (node != dst_node && !node->next_sibling_clone) > + node = node->clone_of; > + if (node != dst_node) > + node = node->next_sibling_clone; > + } > + } > + } > + delete_basic_block (b); > + changed = true; > + } > + } > + > + return changed; > +} > + > diff --git a/gcc/tree-cfgcleanup.h b/gcc/tree-cfgcleanup.h > index e133bbdfbec..bd27505fd5c 100644 > --- a/gcc/tree-cfgcleanup.h > +++ b/gcc/tree-cfgcleanup.h > @@ -24,5 +24,7 @@ along with GCC; see the file COPYING3. If not see > extern bitmap cfgcleanup_altered_bbs; > extern bool cleanup_tree_cfg (void); > extern bool fixup_noreturn_call (gimple *stmt); > +extern bool delete_unreachable_blocks_update_callgraph (cgraph_node > *dst_node, > + bool update_clones); > > #endif /* GCC_TREE_CFGCLEANUP_H */ > diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c > index 29f119ade77..d8bed50d78e 100644 > --- a/gcc/tree-inline.c > +++ b/gcc/tree-inline.c > @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see > #include "stringpool.h" > #include "attribs.h" > #include "sreal.h" > +#include "tree-cfgcleanup.h" > > /* I'm not real happy about this, but we need to handle gimple and > non-gimple trees. */ > @@ -132,7 +133,6 @@ static tree copy_decl_to_var (tree, copy_body_data > *); > static tree copy_result_decl_to_var (tree, copy_body_data *); > static tree copy_decl_maybe_to_var (tree, copy_body_data *); > static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *); > -static bool delete_unreachable_blocks_update_callgraph (copy_body_data > *id); > static void insert_init_stmt (copy_body_data *, basic_block, gimple > *); > > /* Insert a tree->tree mapping for ID. Despite the name suggests > @@ -5123,7 +5123,8 @@ optimize_inline_calls (tree fn) > /* Renumber the lexical scoping (non-code) blocks consecutively. */ > number_blocks (fn); > > - delete_unreachable_blocks_update_callgraph (&id); > + delete_unreachable_blocks_update_callgraph (id.dst_node, false); > + > if (flag_checking) > id.dst_node->verify (); > > @@ -5707,79 +5708,6 @@ tree_versionable_function_p (tree fndecl) > && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL); > } > > -/* Delete all unreachable basic blocks and update callgraph. > - Doing so is somewhat nontrivial because we need to update all > clones and > - remove inline function that become unreachable. */ > - > -static bool > -delete_unreachable_blocks_update_callgraph (copy_body_data *id) > -{ > - bool changed = false; > - basic_block b, next_bb; > - > - find_unreachable_blocks (); > - > - /* Delete all unreachable basic blocks. */ > - > - for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b > - != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb) > - { > - next_bb = b->next_bb; > - > - if (!(b->flags & BB_REACHABLE)) > - { > - gimple_stmt_iterator bsi; > - > - for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next > (&bsi)) > - { > - struct cgraph_edge *e; > - struct cgraph_node *node; > - > - id->dst_node->remove_stmt_references (gsi_stmt (bsi)); > - > - if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL > - &&(e = id->dst_node->get_edge (gsi_stmt (bsi))) != NULL) > - { > - if (!e->inline_failed) > - e->callee->remove_symbol_and_inline_clones (id->dst_node); > - else > - e->remove (); > - } > - if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES > - && id->dst_node->clones) > - for (node = id->dst_node->clones; node != id->dst_node;) > - { > - node->remove_stmt_references (gsi_stmt (bsi)); > - if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL > - && (e = node->get_edge (gsi_stmt (bsi))) != NULL) > - { > - if (!e->inline_failed) > - e->callee->remove_symbol_and_inline_clones (id->dst_node); > - else > - e->remove (); > - } > - > - if (node->clones) > - node = node->clones; > - else if (node->next_sibling_clone) > - node = node->next_sibling_clone; > - else > - { > - while (node != id->dst_node && !node->next_sibling_clone) > - node = node->clone_of; > - if (node != id->dst_node) > - node = node->next_sibling_clone; > - } > - } > - } > - delete_basic_block (b); > - changed = true; > - } > - } > - > - return changed; > -} > - > /* Update clone info after duplication. */ > > static void > @@ -6093,7 +6021,7 @@ tree_function_versioning (tree old_decl, tree > new_decl, > update_max_bb_count (); > fold_marked_statements (0, id.statements_to_fold); > delete id.statements_to_fold; > - delete_unreachable_blocks_update_callgraph (&id); > + delete_unreachable_blocks_update_callgraph (id.dst_node, > update_clones); > if (id.dst_node->definition) > cgraph_edge::rebuild_references (); > if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index 40ab130b750..d86c2f3db55 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -52,6 +52,7 @@ along with GCC; see the file COPYING3. If not see #include "dbgcnt.h" #include "domwalk.h" #include "builtins.h" +#include "tree-cfgcleanup.h" /* Function summary where the parameter infos are actually stored. */ ipa_node_params_t *ipa_node_params_sum = NULL; @@ -5173,10 +5174,11 @@ ipcp_transform_function (struct cgraph_node *node) if (!something_changed) return 0; - else if (cfg_changed) - return TODO_update_ssa_only_virtuals | TODO_cleanup_cfg; - else - return TODO_update_ssa_only_virtuals; + + if (cfg_changed) + delete_unreachable_blocks_update_callgraph (node, false); + + return TODO_update_ssa_only_virtuals; } #include "gt-ipa-prop.h" diff --git a/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 new file mode 100644 index 00000000000..e4f30ae9f3e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/pr88933.f90 @@ -0,0 +1,39 @@ +! PR ipa/88933 +! { dg-do compile } +! { dg-options "-O1 -fexceptions -fipa-cp -fnon-call-exceptions -fopenmp -fno-inline-functions-called-once" } + +!$omp parallel +!$omp single + call a +!$omp end single +!$omp end parallel +contains + subroutine b (c, d, e, f, g, h, i, j, k, m) + character (*) c + character d + integer, dimension (m) :: e + integer, dimension (m) :: f + character g + character h + real, dimension (:, :, :) :: i + double precision, dimension (:, :, :) :: j + integer, dimension (:, :, :) :: k + + integer, dimension (m) :: l +!$omp task firstprivate (k) firstprivate (l) + !$omp end task + c = '' + end + subroutine a + character c + character d + integer, dimension (7) :: e + integer, dimension (7) :: f + character g + character h + real, dimension (5, 6, 7) :: i + double precision, dimension (6, 6, 7) :: j + integer, dimension (5, 7, 6) :: k + call b (c, d, e, f, g, h, i, j, k, 7) + end +end diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index 2adb3953d6b..f2e8b96ee8e 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -43,7 +43,7 @@ along with GCC; see the file COPYING3. If not see #include "gimple-match.h" #include "gimple-fold.h" #include "tree-ssa-loop-niter.h" - +#include "cgraph.h" /* The set of blocks in that at least one of the following changes happened: -- the statement at the end of the block was changed @@ -1380,3 +1380,76 @@ make_pass_cleanup_cfg_post_optimizing (gcc::context *ctxt) } +/* Delete all unreachable basic blocks and update callgraph. + Doing so is somewhat nontrivial because we need to update all clones and + remove inline function that become unreachable. */ + +bool +delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node, + bool update_clones) +{ + bool changed = false; + basic_block b, next_bb; + + find_unreachable_blocks (); + + /* Delete all unreachable basic blocks. */ + + for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b + != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb) + { + next_bb = b->next_bb; + + if (!(b->flags & BB_REACHABLE)) + { + gimple_stmt_iterator bsi; + + for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi)) + { + struct cgraph_edge *e; + struct cgraph_node *node; + + dst_node->remove_stmt_references (gsi_stmt (bsi)); + + if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL + &&(e = dst_node->get_edge (gsi_stmt (bsi))) != NULL) + { + if (!e->inline_failed) + e->callee->remove_symbol_and_inline_clones (dst_node); + else + e->remove (); + } + if (update_clones && dst_node->clones) + for (node = dst_node->clones; node != dst_node;) + { + node->remove_stmt_references (gsi_stmt (bsi)); + if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL + && (e = node->get_edge (gsi_stmt (bsi))) != NULL) + { + if (!e->inline_failed) + e->callee->remove_symbol_and_inline_clones (dst_node); + else + e->remove (); + } + + if (node->clones) + node = node->clones; + else if (node->next_sibling_clone) + node = node->next_sibling_clone; + else + { + while (node != dst_node && !node->next_sibling_clone) + node = node->clone_of; + if (node != dst_node) + node = node->next_sibling_clone; + } + } + } + delete_basic_block (b); + changed = true; + } + } + + return changed; +} + diff --git a/gcc/tree-cfgcleanup.h b/gcc/tree-cfgcleanup.h index e133bbdfbec..bd27505fd5c 100644 --- a/gcc/tree-cfgcleanup.h +++ b/gcc/tree-cfgcleanup.h @@ -24,5 +24,7 @@ along with GCC; see the file COPYING3. If not see extern bitmap cfgcleanup_altered_bbs; extern bool cleanup_tree_cfg (void); extern bool fixup_noreturn_call (gimple *stmt); +extern bool delete_unreachable_blocks_update_callgraph (cgraph_node *dst_node, + bool update_clones); #endif /* GCC_TREE_CFGCLEANUP_H */ diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 29f119ade77..d8bed50d78e 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -60,6 +60,7 @@ along with GCC; see the file COPYING3. If not see #include "stringpool.h" #include "attribs.h" #include "sreal.h" +#include "tree-cfgcleanup.h" /* I'm not real happy about this, but we need to handle gimple and non-gimple trees. */ @@ -132,7 +133,6 @@ static tree copy_decl_to_var (tree, copy_body_data *); static tree copy_result_decl_to_var (tree, copy_body_data *); static tree copy_decl_maybe_to_var (tree, copy_body_data *); static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *); -static bool delete_unreachable_blocks_update_callgraph (copy_body_data *id); static void insert_init_stmt (copy_body_data *, basic_block, gimple *); /* Insert a tree->tree mapping for ID. Despite the name suggests @@ -5123,7 +5123,8 @@ optimize_inline_calls (tree fn) /* Renumber the lexical scoping (non-code) blocks consecutively. */ number_blocks (fn); - delete_unreachable_blocks_update_callgraph (&id); + delete_unreachable_blocks_update_callgraph (id.dst_node, false); + if (flag_checking) id.dst_node->verify (); @@ -5707,79 +5708,6 @@ tree_versionable_function_p (tree fndecl) && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL); } -/* Delete all unreachable basic blocks and update callgraph. - Doing so is somewhat nontrivial because we need to update all clones and - remove inline function that become unreachable. */ - -static bool -delete_unreachable_blocks_update_callgraph (copy_body_data *id) -{ - bool changed = false; - basic_block b, next_bb; - - find_unreachable_blocks (); - - /* Delete all unreachable basic blocks. */ - - for (b = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb; b - != EXIT_BLOCK_PTR_FOR_FN (cfun); b = next_bb) - { - next_bb = b->next_bb; - - if (!(b->flags & BB_REACHABLE)) - { - gimple_stmt_iterator bsi; - - for (bsi = gsi_start_bb (b); !gsi_end_p (bsi); gsi_next (&bsi)) - { - struct cgraph_edge *e; - struct cgraph_node *node; - - id->dst_node->remove_stmt_references (gsi_stmt (bsi)); - - if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL - &&(e = id->dst_node->get_edge (gsi_stmt (bsi))) != NULL) - { - if (!e->inline_failed) - e->callee->remove_symbol_and_inline_clones (id->dst_node); - else - e->remove (); - } - if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES - && id->dst_node->clones) - for (node = id->dst_node->clones; node != id->dst_node;) - { - node->remove_stmt_references (gsi_stmt (bsi)); - if (gimple_code (gsi_stmt (bsi)) == GIMPLE_CALL - && (e = node->get_edge (gsi_stmt (bsi))) != NULL) - { - if (!e->inline_failed) - e->callee->remove_symbol_and_inline_clones (id->dst_node); - else - e->remove (); - } - - if (node->clones) - node = node->clones; - else if (node->next_sibling_clone) - node = node->next_sibling_clone; - else - { - while (node != id->dst_node && !node->next_sibling_clone) - node = node->clone_of; - if (node != id->dst_node) - node = node->next_sibling_clone; - } - } - } - delete_basic_block (b); - changed = true; - } - } - - return changed; -} - /* Update clone info after duplication. */ static void @@ -6093,7 +6021,7 @@ tree_function_versioning (tree old_decl, tree new_decl, update_max_bb_count (); fold_marked_statements (0, id.statements_to_fold); delete id.statements_to_fold; - delete_unreachable_blocks_update_callgraph (&id); + delete_unreachable_blocks_update_callgraph (id.dst_node, update_clones); if (id.dst_node->definition) cgraph_edge::rebuild_references (); if (loops_state_satisfies_p (LOOPS_NEED_FIXUP))