diff options
author | Aldy Hernandez <aldyh@redhat.com> | 2021-07-15 15:06:36 +0200 |
---|---|---|
committer | Aldy Hernandez <aldyh@redhat.com> | 2021-07-27 17:58:14 +0200 |
commit | 573e20aaca836029b309a053c8ef19367f27bdc1 (patch) | |
tree | 03319e23c9e231bbe65ed6e6eaa43af98c8c2970 /gcc/tree-ssa-threadedge.c | |
parent | bee2f80b901d73f50275f2b44932067ffcf616ca (diff) | |
download | gcc-573e20aaca836029b309a053c8ef19367f27bdc1.zip gcc-573e20aaca836029b309a053c8ef19367f27bdc1.tar.gz gcc-573e20aaca836029b309a053c8ef19367f27bdc1.tar.bz2 |
Abstract out (forward) jump threader state handling.
The *forward* jump threader has multiple places where it pushes and
pops state, and where it sets context up for the jump threading
simplifier callback. Not only are the idioms repetitive, but the only
reason for passing const_and_copies, avail_exprs_stack, and the evrp
engine around are so we can set up context.
As part of my jump threading work, I will divorce the evrp engine from
the DOM jump threader, replacing it with a subset of the path solver I
have just contributed. Since this will entail passing even more
context around, I've abstracted out the state handling so it can be
passed around in one object. This cleans up the code, and also makes
it trivial to set up context with another engine in the future.
FWIW, I've used these cleanups and the path solver in a POC to improve
DOM's threaded edges by an additional 5%, and the overall threading
opportunities in the compiler by 1%. This is in addition to the gains
I have documented in the backwards threader rewrite.
There are no functional changes with this patch.
Tested on x86-64 Linux.
gcc/ChangeLog:
* tree-ssa-dom.c (dom_jump_threader_simplifier):
Put avail_exprs_stack in the class, instead of passing it to
jump_threader_simplifier.
(dom_jump_threader_simplifier::simplify): Add state argument.
(dom_opt_dom_walker): Add state.
(pass_dominator::execute): Pass state to threader.
(dom_opt_dom_walker::before_dom_children): Use state.
* tree-ssa-threadedge.c (jump_threader::jump_threader): Replace
arguments by state.
(jump_threader::record_temporary_equivalences_from_phis):
Register equivalences through the state variable.
(jump_threader::record_temporary_equivalences_from_stmts_at_dest):
Record ranges in a statement through the state variable.
(jump_threader::simplify_control_stmt_condition): Pass state to
simplify.
(jump_threader::simplify_control_stmt_condition_1): Same.
(jump_threader::thread_around_empty_blocks): Remove obsolete
comment.
(jump_threader::thread_through_normal_block): Record equivalences
on edge through the state variable.
(jump_threader::thread_across_edge): Abstract state pushing.
(jt_state::jt_state): New.
(jt_state::push): New.
(jt_state::pop): New.
(jt_state::register_equiv): New.
(jt_state::record_ranges_from_stmt): New.
(jt_state::register_equivs_on_edge): New.
(jump_threader_simplifier::jump_threader_simplifier): Move from
header.
(jump_threader_simplifier::simplify): Add state argument.
* tree-ssa-threadedge.h (class jt_state): New.
(class jump_threader): Add state to constructor.
(class jump_threader_simplifier): Add state to simplify. Remove
avail_exprs_stack from class.
* tree-vrp.c (vrp_jump_threader_simplifier::simplify): Add state
argument.
(vrp_jump_threader::vrp_jump_threader): Add state.
(vrp_jump_threader::~vrp_jump_threader): Cleanup state.
Diffstat (limited to 'gcc/tree-ssa-threadedge.c')
-rw-r--r-- | gcc/tree-ssa-threadedge.c | 219 |
1 files changed, 124 insertions, 95 deletions
diff --git a/gcc/tree-ssa-threadedge.c b/gcc/tree-ssa-threadedge.c index 6ce3264..24ccf01 100644 --- a/gcc/tree-ssa-threadedge.c +++ b/gcc/tree-ssa-threadedge.c @@ -61,10 +61,8 @@ set_ssa_name_value (tree name, tree value) ssa_name_values[SSA_NAME_VERSION (name)] = value; } -jump_threader::jump_threader (const_and_copies *copies, - avail_exprs_stack *avails, - jump_threader_simplifier *simplifier, - evrp_range_analyzer *analyzer) +jump_threader::jump_threader (jump_threader_simplifier *simplifier, + jt_state *state) { /* Initialize the per SSA_NAME value-handles array. */ gcc_assert (!ssa_name_values.exists ()); @@ -73,11 +71,9 @@ jump_threader::jump_threader (const_and_copies *copies, dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node, integer_zero_node, NULL, NULL); - m_const_and_copies = copies; - m_avail_exprs_stack = avails; m_registry = new jump_thread_path_registry (); m_simplifier = simplifier; - m_evrp_range_analyzer = analyzer; + m_state = state; } jump_threader::~jump_threader (void) @@ -168,41 +164,7 @@ jump_threader::record_temporary_equivalences_from_phis (edge e) if (!virtual_operand_p (dst)) stmt_count++; - m_const_and_copies->record_const_or_copy (dst, src); - - /* Also update the value range associated with DST, using - the range from SRC. - - Note that even if SRC is a constant we need to set a suitable - output range so that VR_UNDEFINED ranges do not leak through. */ - if (m_evrp_range_analyzer) - { - /* Get an empty new VR we can pass to update_value_range and save - away in the VR stack. */ - value_range_equiv *new_vr - = m_evrp_range_analyzer->allocate_value_range_equiv (); - new (new_vr) value_range_equiv (); - - /* There are three cases to consider: - - First if SRC is an SSA_NAME, then we can copy the value - range from SRC into NEW_VR. - - Second if SRC is an INTEGER_CST, then we can just wet - NEW_VR to a singleton range. - - Otherwise set NEW_VR to varying. This may be overly - conservative. */ - if (TREE_CODE (src) == SSA_NAME) - new_vr->deep_copy (m_evrp_range_analyzer->get_value_range (src)); - else if (TREE_CODE (src) == INTEGER_CST) - new_vr->set (src); - else - new_vr->set_varying (TREE_TYPE (src)); - - /* This is a temporary range for DST, so push it. */ - m_evrp_range_analyzer->push_value_range (dst, new_vr); - } + m_state->register_equiv (dst, src, /*update_range=*/true); } return true; } @@ -304,10 +266,7 @@ jump_threader::record_temporary_equivalences_from_stmts_at_dest (edge e) return NULL; } - /* These are temporary ranges, do nto reflect them back into - the global range data. */ - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->record_ranges_from_stmt (stmt, true); + m_state->record_ranges_from_stmt (stmt, true); /* If this is not a statement that sets an SSA_NAME to a new value, then do not try to simplify this statement as it will @@ -408,7 +367,7 @@ jump_threader::record_temporary_equivalences_from_stmts_at_dest (edge e) SET_USE (use_p, tmp); } - cached_lhs = m_simplifier->simplify (stmt, stmt, e->src); + cached_lhs = m_simplifier->simplify (stmt, stmt, e->src, m_state); /* Restore the statement's original uses/defs. */ i = 0; @@ -422,8 +381,7 @@ jump_threader::record_temporary_equivalences_from_stmts_at_dest (edge e) if (cached_lhs && (TREE_CODE (cached_lhs) == SSA_NAME || is_gimple_min_invariant (cached_lhs))) - m_const_and_copies->record_const_or_copy (gimple_get_lhs (stmt), - cached_lhs); + m_state->register_equiv (gimple_get_lhs (stmt), cached_lhs); } return stmt; } @@ -552,11 +510,12 @@ jump_threader::simplify_control_stmt_condition (edge e, gimple *stmt) the label that is proven to be taken. */ gswitch *dummy_switch = as_a<gswitch *> (gimple_copy (stmt)); gimple_switch_set_index (dummy_switch, cached_lhs); - cached_lhs = m_simplifier->simplify (dummy_switch, stmt, e->src); + cached_lhs = m_simplifier->simplify (dummy_switch, stmt, e->src, + m_state); ggc_free (dummy_switch); } else - cached_lhs = m_simplifier->simplify (stmt, stmt, e->src); + cached_lhs = m_simplifier->simplify (stmt, stmt, e->src, m_state); } /* We couldn't find an invariant. But, callers of this @@ -733,7 +692,7 @@ jump_threader::simplify_control_stmt_condition_1 then use the pass specific callback to simplify the condition. */ if (!res || !is_gimple_min_invariant (res)) - res = m_simplifier->simplify (dummy_cond, stmt, e->src); + res = m_simplifier->simplify (dummy_cond, stmt, e->src, m_state); return res; } @@ -880,9 +839,7 @@ propagate_threaded_block_debug_into (basic_block dest, basic_block src) If it is threadable, add it to PATH and VISITED and recurse, ultimately returning TRUE from the toplevel call. Otherwise do nothing and - return false. - - The available expression table is referenced via AVAIL_EXPRS_STACK. */ + return false. */ bool jump_threader::thread_around_empty_blocks (vec<jump_thread_edge *> *path, @@ -997,12 +954,6 @@ jump_threader::thread_around_empty_blocks (vec<jump_thread_edge *> *path, limited in that case to avoid short-circuiting the loop incorrectly. - STACK is used to undo temporary equivalences created during the walk of - E->dest. - - Our caller is responsible for restoring the state of the expression - and const_and_copies stacks. - Positive return value is success. Zero return value is failure, but the block can still be duplicated as a joiner in a jump thread path, negative indicates the block should not be duplicated and thus is not @@ -1012,8 +963,7 @@ int jump_threader::thread_through_normal_block (vec<jump_thread_edge *> *path, edge e, bitmap visited) { - /* We want to record any equivalences created by traversing E. */ - record_temporary_equivalences (e, m_const_and_copies, m_avail_exprs_stack); + m_state->register_equivs_on_edge (e); /* PHIs create temporary equivalences. Note that if we found a PHI that made the block non-threadable, then @@ -1186,10 +1136,7 @@ jump_threader::thread_across_edge (edge e) { bitmap visited = BITMAP_ALLOC (NULL); - m_const_and_copies->push_marker (); - m_avail_exprs_stack->push_marker (); - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->push_marker (); + m_state->push (e); stmt_count = 0; @@ -1208,10 +1155,7 @@ jump_threader::thread_across_edge (edge e) { propagate_threaded_block_debug_into (path->last ()->e->dest, e->dest); - m_const_and_copies->pop_to_marker (); - m_avail_exprs_stack->pop_to_marker (); - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->pop_to_marker (); + m_state->pop (); BITMAP_FREE (visited); m_registry->register_jump_thread (path); return; @@ -1234,10 +1178,7 @@ jump_threader::thread_across_edge (edge e) if (threaded < 0) { BITMAP_FREE (visited); - m_const_and_copies->pop_to_marker (); - m_avail_exprs_stack->pop_to_marker (); - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->pop_to_marker (); + m_state->pop (); return; } } @@ -1263,10 +1204,7 @@ jump_threader::thread_across_edge (edge e) FOR_EACH_EDGE (taken_edge, ei, e->dest->succs) if (taken_edge->flags & EDGE_COMPLEX) { - m_const_and_copies->pop_to_marker (); - m_avail_exprs_stack->pop_to_marker (); - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->pop_to_marker (); + m_state->pop (); BITMAP_FREE (visited); return; } @@ -1278,12 +1216,7 @@ jump_threader::thread_across_edge (edge e) || (taken_edge->flags & EDGE_DFS_BACK) != 0) continue; - /* Push a fresh marker so we can unwind the equivalences created - for each of E->dest's successors. */ - m_const_and_copies->push_marker (); - m_avail_exprs_stack->push_marker (); - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->push_marker (); + m_state->push (taken_edge); /* Avoid threading to any block we have already visited. */ bitmap_clear (visited); @@ -1320,19 +1253,12 @@ jump_threader::thread_across_edge (edge e) else path->release (); - /* And unwind the equivalence table. */ - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->pop_to_marker (); - m_avail_exprs_stack->pop_to_marker (); - m_const_and_copies->pop_to_marker (); + m_state->pop (); } BITMAP_FREE (visited); } - if (m_evrp_range_analyzer) - m_evrp_range_analyzer->pop_to_marker (); - m_const_and_copies->pop_to_marker (); - m_avail_exprs_stack->pop_to_marker (); + m_state->pop (); } /* Examine the outgoing edges from BB and conditionally @@ -1375,10 +1301,113 @@ jump_threader::thread_outgoing_edges (basic_block bb) } } +jt_state::jt_state (const_and_copies *copies, + avail_exprs_stack *exprs, + evrp_range_analyzer *evrp) +{ + m_copies = copies; + m_exprs = exprs; + m_evrp = evrp; +} + +// Record that E is being crossed. + +void +jt_state::push (edge) +{ + m_copies->push_marker (); + m_exprs->push_marker (); + if (m_evrp) + m_evrp->push_marker (); +} + +// Pop to the last pushed state. + +void +jt_state::pop () +{ + m_copies->pop_to_marker (); + m_exprs->pop_to_marker (); + if (m_evrp) + m_evrp->pop_to_marker (); +} + +// Record an equivalence from DST to SRC. If UPDATE_RANGE is TRUE, +// update the value range associated with DST. + +void +jt_state::register_equiv (tree dst, tree src, bool update_range) +{ + m_copies->record_const_or_copy (dst, src); + + /* If requested, update the value range associated with DST, using + the range from SRC. */ + if (m_evrp && update_range) + { + /* Get new VR we can pass to push_value_range. */ + value_range_equiv *new_vr = m_evrp->allocate_value_range_equiv (); + new (new_vr) value_range_equiv (); + + /* There are three cases to consider: + + First if SRC is an SSA_NAME, then we can copy the value range + from SRC into NEW_VR. + + Second if SRC is an INTEGER_CST, then we can just set NEW_VR + to a singleton range. Note that even if SRC is a constant we + need to set a suitable output range so that VR_UNDEFINED + ranges do not leak through. + + Otherwise set NEW_VR to varying. This may be overly + conservative. */ + if (TREE_CODE (src) == SSA_NAME) + new_vr->deep_copy (m_evrp->get_value_range (src)); + else if (TREE_CODE (src) == INTEGER_CST) + new_vr->set (src); + else + new_vr->set_varying (TREE_TYPE (src)); + + /* This is a temporary range for DST, so push it. */ + m_evrp->push_value_range (dst, new_vr); + } +} + +// Record any ranges calculated in STMT. If TEMPORARY is TRUE, then +// this is a temporary equivalence and should be recorded into the +// unwind table, instead of the global table. + +void +jt_state::record_ranges_from_stmt (gimple *stmt, bool temporary) +{ + if (m_evrp) + m_evrp->record_ranges_from_stmt (stmt, temporary); +} + +// Record any equivalences created by traversing E. + +void +jt_state::register_equivs_on_edge (edge e) +{ + record_temporary_equivalences (e, m_copies, m_exprs); +} + +jump_threader_simplifier::jump_threader_simplifier (vr_values *v) +{ + m_vr_values = v; +} + +// Return the singleton that resolves STMT, if it is possible to +// simplify it. +// +// STMT may be a dummy statement, not necessarily in the CFG, in which +// case WITHIN_STMT can be used to determine the position in the CFG +// where STMT should be evaluated as being in. + tree jump_threader_simplifier::simplify (gimple *stmt, gimple *within_stmt, - basic_block) + basic_block, + jt_state *) { if (gcond *cond_stmt = dyn_cast <gcond *> (stmt)) { |