diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3cad7bb512c..b512e4b9bbc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2016-10-17 Yuri Rumyantsev + + * dominance.c (dom_info::dom_info): Add new constructor for region + which is vector of basic blocks. + (dom_init): New method to initialize members common for both + constructors. + (dom_info::dom_info): Invoke dom_init for partial initialization. + (dom_info::get_idom): Add check to corner cases on basic blocks which + are not in region. + (dom_info::calc_dfs_tree): Check M_FAKE_EXIT_EDGE instead of M_REVERSE + to detect unreachable bbs. + (dom_info::calc_idoms): Likewise. + (compute_dom_fast_query_in_region): New function. + (calculate_dominance_info_for_region): Likewise. + (free_dominance_info_for_region): Likewise. + * dominance.h: Add prototypes for introduced region-based functions + tree-if-conv.c: (build_region): New function. + (if_convertible_loop_p_1): Invoke local version of post-dominators + calculation before basic block predication with subsequent freeing + post-dominator info. + (tree_if_conversion): Remove free of post-dominator info + (pass_if_conversion::execute): Delete detection of infinite loops + and fake edges to exit block since post-dominator calculation is + performed per if-converted loop only. + 2016-10-17 Bernd Edlinger PR target/77308 diff --git a/gcc/dominance.c b/gcc/dominance.c index e3308cc1927..90bd00dab15 100644 --- a/gcc/dominance.c +++ b/gcc/dominance.c @@ -60,6 +60,7 @@ class dom_info { public: dom_info (function *, cdi_direction); + dom_info (vec , cdi_direction); ~dom_info (); void calc_dfs_tree (); void calc_idoms (); @@ -68,6 +69,7 @@ public: private: void calc_dfs_tree_nonrec (basic_block); void compress (TBB); + void dom_init (void); TBB eval (TBB); void link_roots (TBB, TBB); @@ -153,12 +155,12 @@ inline T *new_zero_array (size_t num) return result; } -/* Allocate all needed memory in a pessimistic fashion (so we round up). */ +/* Helper function for constructors to initialize a part of class members. */ -dom_info::dom_info (function *fn, cdi_direction dir) +void +dom_info::dom_init (void) { - /* We need memory for n_basic_blocks nodes. */ - size_t num = m_n_basic_blocks = n_basic_blocks_for_fn (fn); + size_t num = m_n_basic_blocks; m_dfs_parent = new_zero_array (num); m_dom = new_zero_array (num); @@ -177,13 +179,23 @@ dom_info::dom_info (function *fn, cdi_direction dir) m_set_chain = new_zero_array (num); m_set_child = new_zero_array (num); - unsigned last_bb_index = last_basic_block_for_fn (fn); - m_dfs_order = new_zero_array (last_bb_index + 1); - m_dfs_last = &m_dfs_order[last_bb_index]; m_dfs_to_bb = new_zero_array (num); m_dfsnum = 1; m_nodes = 0; +} + +/* Allocate all needed memory in a pessimistic fashion (so we round up). */ + +dom_info::dom_info (function *fn, cdi_direction dir) +{ + m_n_basic_blocks = n_basic_blocks_for_fn (fn); + + dom_init (); + + unsigned last_bb_index = last_basic_block_for_fn (fn); + m_dfs_order = new_zero_array (last_bb_index + 1); + m_dfs_last = &m_dfs_order[last_bb_index]; switch (dir) { @@ -204,6 +216,44 @@ dom_info::dom_info (function *fn, cdi_direction dir) } } +/* Constructor for reducible region REGION. */ + +dom_info::dom_info (vec region, cdi_direction dir) +{ + m_n_basic_blocks = region.length (); + unsigned int nm1 = m_n_basic_blocks - 1; + + dom_init (); + + /* Determine max basic block index in region. */ + int max_index = region[0]->index; + for (size_t i = 1; i <= nm1; i++) + if (region[i]->index > max_index) + max_index = region[i]->index; + max_index += 1; /* set index on the first bb out of region. */ + + m_dfs_order = new_zero_array (max_index + 1); + m_dfs_last = &m_dfs_order[max_index]; + + m_fake_exit_edge = NULL; /* Assume that region is reducible. */ + + switch (dir) + { + case CDI_DOMINATORS: + m_reverse = false; + m_start_block = region[0]; + m_end_block = region[nm1]; + break; + case CDI_POST_DOMINATORS: + m_reverse = true; + m_start_block = region[nm1]; + m_end_block = region[0]; + break; + default: + gcc_unreachable (); + } +} + inline basic_block dom_info::get_idom (basic_block bb) { @@ -252,6 +302,8 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb) { edge_iterator *stack = new edge_iterator[m_n_basic_blocks + 1]; int sp = 0; + unsigned d_i = dom_convert_dir_to_idx (m_reverse ? CDI_POST_DOMINATORS + : CDI_DOMINATORS); /* Initialize the first edge. */ edge_iterator ei = m_reverse ? ei_start (bb->preds) @@ -276,9 +328,10 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb) bn = e->src; /* If the next node BN is either already visited or a border - block the current edge is useless, and simply overwritten - with the next edge out of the current node. */ - if (bn == m_end_block || m_dfs_order[bn->index]) + block or out of region the current edge is useless, and simply + overwritten with the next edge out of the current node. */ + if (bn == m_end_block || bn->dom[d_i] == NULL + || m_dfs_order[bn->index]) { ei_next (&ei); continue; @@ -289,7 +342,8 @@ dom_info::calc_dfs_tree_nonrec (basic_block bb) else { bn = e->dest; - if (bn == m_end_block || m_dfs_order[bn->index]) + if (bn == m_end_block || bn->dom[d_i] == NULL + || m_dfs_order[bn->index]) { ei_next (&ei); continue; @@ -347,7 +401,7 @@ dom_info::calc_dfs_tree () calc_dfs_tree_nonrec (m_start_block); - if (m_reverse) + if (m_fake_exit_edge) { /* In the post-dom case we may have nodes without a path to EXIT_BLOCK. They are reverse-unreachable. In the dom-case we disallow such @@ -511,7 +565,7 @@ dom_info::calc_idoms () : ei_start (bb->preds); edge_iterator einext; - if (m_reverse) + if (m_fake_exit_edge) { /* If this block has a fake edge to exit, process that first. */ if (bitmap_bit_p (m_fake_exit_edge, bb->index)) @@ -622,6 +676,33 @@ compute_dom_fast_query (enum cdi_direction dir) dom_computed[dir_index] = DOM_OK; } +/* Analogous to the previous function but compute the data for reducible + region REGION. */ + +static void +compute_dom_fast_query_in_region (enum cdi_direction dir, + vec region) +{ + int num = 0; + basic_block bb; + unsigned int dir_index = dom_convert_dir_to_idx (dir); + + gcc_checking_assert (dom_info_available_p (dir)); + + if (dom_computed[dir_index] == DOM_OK) + return; + + /* Assign dfs numbers for region nodes except for entry and exit nodes. */ + for (unsigned int i = 1; i < region.length () - 1; i++) + { + bb = region[i]; + if (!bb->dom[dir_index]->father) + assign_dfs_numbers (bb->dom[dir_index], &num); + } + + dom_computed[dir_index] = DOM_OK; +} + /* The main entry point into this module. DIR is set depending on whether we want to compute dominators or postdominators. */ @@ -668,6 +749,43 @@ calculate_dominance_info (cdi_direction dir) timevar_pop (TV_DOMINANCE); } +/* Analogous to the previous function but compute dominance info for regions + which are single entry, multiple exit regions for CDI_DOMINATORs and + multiple entry, single exit regions for CDI_POST_DOMINATORs. */ + +void +calculate_dominance_info_for_region (cdi_direction dir, + vec region) +{ + unsigned int dir_index = dom_convert_dir_to_idx (dir); + basic_block bb; + unsigned int i; + + if (dom_computed[dir_index] == DOM_OK) + return; + + timevar_push (TV_DOMINANCE); + /* Assume that dom info is not partially computed. */ + gcc_assert (!dom_info_available_p (dir)); + + FOR_EACH_VEC_ELT (region, i, bb) + { + bb->dom[dir_index] = et_new_tree (bb); + } + dom_info di (region, dir); + di.calc_dfs_tree (); + di.calc_idoms (); + + FOR_EACH_VEC_ELT (region, i, bb) + if (basic_block d = di.get_idom (bb)) + et_set_father (bb->dom[dir_index], d->dom[dir_index]); + + dom_computed[dir_index] = DOM_NO_FAST_QUERY; + compute_dom_fast_query_in_region (dir, region); + + timevar_pop (TV_DOMINANCE); +} + /* Free dominance information for direction DIR. */ void free_dominance_info (function *fn, enum cdi_direction dir) @@ -696,6 +814,32 @@ free_dominance_info (enum cdi_direction dir) free_dominance_info (cfun, dir); } +/* Free dominance information for direction DIR in region REGION. */ + +void +free_dominance_info_for_region (function *fn, + enum cdi_direction dir, + vec region) +{ + basic_block bb; + unsigned int i; + unsigned int dir_index = dom_convert_dir_to_idx (dir); + + if (!dom_info_available_p (dir)) + return; + + FOR_EACH_VEC_ELT (region, i, bb) + { + et_free_tree_force (bb->dom[dir_index]); + bb->dom[dir_index] = NULL; + } + et_free_pools (); + + fn->cfg->x_dom_computed[dir_index] = DOM_NONE; + + fn->cfg->x_n_bbs_in_dom_tree[dir_index] = 0; +} + /* Return the immediate dominator of basic block BB. */ basic_block get_immediate_dominator (enum cdi_direction dir, basic_block bb) diff --git a/gcc/dominance.h b/gcc/dominance.h index 961c4e2bdd9..ddbfa003662 100644 --- a/gcc/dominance.h +++ b/gcc/dominance.h @@ -36,8 +36,13 @@ enum dom_state }; extern void calculate_dominance_info (enum cdi_direction); +extern void calculate_dominance_info_for_region (enum cdi_direction, + vec); extern void free_dominance_info (function *, enum cdi_direction); extern void free_dominance_info (enum cdi_direction); +extern void free_dominance_info_for_region (function *, + enum cdi_direction, + vec); extern basic_block get_immediate_dominator (enum cdi_direction, basic_block); extern void set_immediate_dominator (enum cdi_direction, basic_block, basic_block); diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c index eec431e6a4f..0a201898177 100644 --- a/gcc/tree-if-conv.c +++ b/gcc/tree-if-conv.c @@ -1309,6 +1309,38 @@ predicate_bbs (loop_p loop) && bb_predicate_gimplified_stmts (loop->latch) == NULL); } +/* Build region by adding loop pre-header and post-header blocks. */ + +static vec +build_region (struct loop *loop) +{ + vec region = vNULL; + basic_block exit_bb = NULL; + + gcc_assert (ifc_bbs); + /* The first element is loop pre-header. */ + region.safe_push (loop_preheader_edge (loop)->src); + + for (unsigned int i = 0; i < loop->num_nodes; i++) + { + basic_block bb = ifc_bbs[i]; + region.safe_push (bb); + /* Find loop postheader. */ + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, bb->succs) + if (loop_exit_edge_p (loop, e)) + { + exit_bb = e->dest; + break; + } + } + /* The last element is loop post-header. */ + gcc_assert (exit_bb); + region.safe_push (exit_bb); + return region; +} + /* Return true when LOOP is if-convertible. This is a helper function for if_convertible_loop_p. REFS and DDRS are initialized and freed in if_convertible_loop_p. */ @@ -1318,6 +1350,7 @@ if_convertible_loop_p_1 (struct loop *loop, vec *refs) { unsigned int i; basic_block exit_bb = NULL; + vec region; if (find_data_references_in_loop (loop, refs) == chrec_dont_know) return false; @@ -1370,9 +1403,16 @@ if_convertible_loop_p_1 (struct loop *loop, vec *refs) = new hash_map; baseref_DR_map = new hash_map; - calculate_dominance_info (CDI_POST_DOMINATORS); + /* Compute post-dominator tree locally. */ + region = build_region (loop); + calculate_dominance_info_for_region (CDI_POST_DOMINATORS, region); + predicate_bbs (loop); + /* Free post-dominator tree since it is not used after predication. */ + free_dominance_info_for_region (cfun, CDI_POST_DOMINATORS, region); + region.release (); + for (i = 0; refs->iterate (i, &dr); i++) { tree ref = DR_REF (dr); @@ -2752,7 +2792,6 @@ tree_if_conversion (struct loop *loop) free (ifc_bbs); ifc_bbs = NULL; } - free_dominance_info (CDI_POST_DOMINATORS); return todo; } @@ -2805,14 +2844,6 @@ pass_if_conversion::execute (function *fun) if (number_of_loops (fun) <= 1) return 0; - /* If there are infinite loops, during CDI_POST_DOMINATORS computation - we can pick pretty much random bb inside of the infinite loop that - has the fake edge. If we are unlucky enough, this can confuse the - add_to_predicate_list post-dominator check to optimize as if that - bb or some other one is a join block when it actually is not. - See PR70916. */ - connect_infinite_loops_to_exit (); - FOR_EACH_LOOP (loop, 0) if (flag_tree_loop_if_convert == 1 || flag_tree_loop_if_convert_stores == 1 @@ -2820,8 +2851,6 @@ pass_if_conversion::execute (function *fun) && !loop->dont_vectorize)) todo |= tree_if_conversion (loop); - remove_fake_exit_edges (); - if (flag_checking) { basic_block bb;