Merge evrp uses of substitute_and_fold_engine into the engine itself.

This patch merges the evrp uses of the substitute and fold engine into
the engine itself, at least the parts that can be re-used by other
engine uses.  It also adds a context parameter to get_value() for
further use.

gcc/
	* gimple-loop-versioning.cc (loop_versioning::name_prop::get_value):
	Add stmt parameter.
	* gimple-ssa-evrp.c (class evrp_folder): New.
	(class evrp_dom_walker): Remove.
	(execute_early_vrp): Use evrp_folder instead of evrp_dom_walker.
	* tree-ssa-ccp.c (ccp_folder::get_value): Add stmt parameter.
	* tree-ssa-copy.c (copy_folder::get_value): Same.
	* tree-ssa-propagate.c (substitute_and_fold_engine::replace_uses_in):
	Pass stmt to get_value.
	(substitute_and_fold_engine::replace_phi_args_in): Same.
	(substitute_and_fold_dom_walker::after_dom_children): Call
	post_fold_bb.
	(substitute_and_fold_dom_walker::foreach_new_stmt_in_bb): New.
	(substitute_and_fold_dom_walker::propagate_into_phi_args): New.
	(substitute_and_fold_dom_walker::before_dom_children): Adjust to
	call virtual functions for folding, pre_folding, and post folding.
	Call get_value with PHI.  Tweak dump.
	* tree-ssa-propagate.h (class substitute_and_fold_engine):
	New argument to get_value.
	New virtual function pre_fold_bb.
	New virtual function post_fold_bb.
	New virtual function pre_fold_stmt.
	New virtual function post_new_stmt.
	New function propagate_into_phi_args.
	* tree-vrp.c (vrp_folder::get_value): Add stmt argument.
	* vr-values.c (vr_values::extract_range_from_stmt): Adjust dump
	output.
	(vr_values::fold_cond): New.
	(vr_values::simplify_cond_using_ranges_1): Call fold_cond.
	* vr-values.h (class vr_values): Add
	simplify_cond_using_ranges_when_edge_is_known.
gcc/testsuite/
	* gcc.dg/tree-ssa/ssa-dse-30.c: Adjust test for folding of
	memmove happening later.
This commit is contained in:
Aldy Hernandez 2020-05-05 13:45:39 +02:00
parent 8b6731e674
commit 1396fa5b91
10 changed files with 218 additions and 301 deletions

View File

@ -277,7 +277,7 @@ private:
{
public:
name_prop (loop_info &li) : m_li (li) {}
tree get_value (tree) FINAL OVERRIDE;
tree get_value (tree, gimple *) FINAL OVERRIDE;
private:
/* Information about the versioning we've performed on the loop. */
@ -534,7 +534,8 @@ loop_versioning::lv_dom_walker::after_dom_children (basic_block bb)
Return the new value if so, otherwise return null. */
tree
loop_versioning::name_prop::get_value (tree val)
loop_versioning::name_prop::get_value (tree val,
gimple *stmt ATTRIBUTE_UNUSED)
{
if (TREE_CODE (val) == SSA_NAME
&& bitmap_bit_p (&m_li.unity_names, SSA_NAME_VERSION (val)))

View File

@ -43,273 +43,68 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-ssa-evrp-analyze.h"
class evrp_folder : public substitute_and_fold_engine
{
public:
tree get_value (tree) FINAL OVERRIDE;
evrp_folder (class vr_values *vr_values_) : vr_values (vr_values_) { }
bool simplify_stmt_using_ranges (gimple_stmt_iterator *gsi)
{ return vr_values->simplify_stmt_using_ranges (gsi); }
class vr_values *vr_values;
private:
DISABLE_COPY_AND_ASSIGN (evrp_folder);
};
tree
evrp_folder::get_value (tree op)
{
return vr_values->op_with_constant_singleton_value_range (op);
}
/* evrp_dom_walker visits the basic blocks in the dominance order and set
the Value Ranges (VR) for SSA_NAMEs in the scope. Use this VR to
discover more VRs. */
class evrp_dom_walker : public dom_walker
{
public:
evrp_dom_walker ()
: dom_walker (CDI_DOMINATORS),
evrp_range_analyzer (true),
evrp_folder (evrp_range_analyzer.get_vr_values ())
{
need_eh_cleanup = BITMAP_ALLOC (NULL);
}
~evrp_dom_walker ()
{
BITMAP_FREE (need_eh_cleanup);
}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
void cleanup (void);
evrp_folder () : m_range_analyzer (/*update_global_ranges=*/true),
m_vr_values (m_range_analyzer.get_vr_values ())
{
}
private:
DISABLE_COPY_AND_ASSIGN (evrp_dom_walker);
bitmap need_eh_cleanup;
auto_vec<gimple *> stmts_to_fixup;
auto_vec<gimple *> stmts_to_remove;
~evrp_folder ()
{
m_vr_values->cleanup_edges_and_switches ();
class evrp_range_analyzer evrp_range_analyzer;
class evrp_folder evrp_folder;
if (dump_file)
{
fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
m_range_analyzer.dump_all_value_ranges (dump_file);
fprintf (dump_file, "\n");
}
}
tree get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED) OVERRIDE
{
return m_vr_values->op_with_constant_singleton_value_range (op);
}
void pre_fold_bb (basic_block bb) OVERRIDE
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "evrp visiting BB%d\n", bb->index);
m_range_analyzer.enter (bb);
}
void pre_fold_stmt (gimple *stmt) OVERRIDE
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "evrp visiting stmt ");
print_gimple_stmt (dump_file, stmt, 0);
}
m_range_analyzer.record_ranges_from_stmt (stmt, false);
}
bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
{
return m_vr_values->simplify_stmt_using_ranges (gsi);
}
void post_fold_bb (basic_block bb) OVERRIDE
{
m_range_analyzer.leave (bb);
}
void post_new_stmt (gimple *stmt) OVERRIDE
{
m_vr_values->set_defs_to_varying (stmt);
}
private:
DISABLE_COPY_AND_ASSIGN (evrp_folder);
class evrp_range_analyzer m_range_analyzer;
class vr_values *m_vr_values;
};
edge
evrp_dom_walker::before_dom_children (basic_block bb)
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Visiting BB%d\n", bb->index);
evrp_range_analyzer.enter (bb);
for (gphi_iterator gpi = gsi_start_phis (bb);
!gsi_end_p (gpi); gsi_next (&gpi))
{
gphi *phi = gpi.phi ();
tree lhs = PHI_RESULT (phi);
if (virtual_operand_p (lhs))
continue;
const value_range_equiv *vr = evrp_range_analyzer.get_value_range (lhs);
/* Mark PHIs whose lhs we fully propagate for removal. */
tree val;
if (vr->singleton_p (&val) && may_propagate_copy (lhs, val))
{
stmts_to_remove.safe_push (phi);
continue;
}
}
edge taken_edge = NULL;
/* Visit all other stmts and discover any new VRs possible. */
for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
!gsi_end_p (gsi); gsi_next (&gsi))
{
gimple *stmt = gsi_stmt (gsi);
tree output = NULL_TREE;
gimple *old_stmt = stmt;
bool was_noreturn = (is_gimple_call (stmt)
&& gimple_call_noreturn_p (stmt));
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Visiting stmt ");
print_gimple_stmt (dump_file, stmt, 0);
}
evrp_range_analyzer.record_ranges_from_stmt (stmt, false);
if (gcond *cond = dyn_cast <gcond *> (stmt))
{
evrp_range_analyzer.vrp_visit_cond_stmt (cond, &taken_edge);
if (taken_edge)
{
if (taken_edge->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond);
else if (taken_edge->flags & EDGE_FALSE_VALUE)
gimple_cond_make_false (cond);
else
gcc_unreachable ();
update_stmt (stmt);
}
}
else if (stmt_interesting_for_vrp (stmt))
{
output = get_output_for_vrp (stmt);
if (output)
{
const value_range_equiv *vr
= evrp_range_analyzer.get_value_range (output);
/* Mark stmts whose output we fully propagate for removal. */
tree val;
if (vr->singleton_p (&val)
&& may_propagate_copy (output, val)
&& !stmt_could_throw_p (cfun, stmt)
&& !gimple_has_side_effects (stmt))
{
stmts_to_remove.safe_push (stmt);
continue;
}
}
}
/* Try folding stmts with the VR discovered. */
bool did_replace = evrp_folder.replace_uses_in (stmt);
gimple_stmt_iterator prev_gsi = gsi;
gsi_prev (&prev_gsi);
if (fold_stmt (&gsi, follow_single_use_edges)
|| did_replace)
{
stmt = gsi_stmt (gsi);
update_stmt (stmt);
did_replace = true;
}
if (evrp_folder.simplify_stmt_using_ranges (&gsi))
{
stmt = gsi_stmt (gsi);
update_stmt (stmt);
did_replace = true;
}
if (did_replace)
{
/* If we wound up generating new stmts during folding
drop all their defs to VARYING. We can't easily
process them because we've already instantiated
ranges on uses on STMT that only hold after it. */
if (gsi_end_p (prev_gsi))
prev_gsi = gsi_start_bb (bb);
else
gsi_next (&prev_gsi);
while (gsi_stmt (prev_gsi) != gsi_stmt (gsi))
{
evrp_range_analyzer.get_vr_values ()
->set_defs_to_varying (gsi_stmt (prev_gsi));
gsi_next (&prev_gsi);
}
/* If we cleaned up EH information from the statement,
remove EH edges. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
bitmap_set_bit (need_eh_cleanup, bb->index);
/* If we turned a not noreturn call into a noreturn one
schedule it for fixup. */
if (!was_noreturn
&& is_gimple_call (stmt)
&& gimple_call_noreturn_p (stmt))
stmts_to_fixup.safe_push (stmt);
if (gimple_assign_single_p (stmt))
{
tree rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (rhs) == ADDR_EXPR)
recompute_tree_invariant_for_addr_expr (rhs);
}
}
}
/* Visit BB successor PHI nodes and replace PHI args. */
edge e;
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
{
for (gphi_iterator gpi = gsi_start_phis (e->dest);
!gsi_end_p (gpi); gsi_next (&gpi))
{
gphi *phi = gpi.phi ();
use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
tree arg = USE_FROM_PTR (use_p);
if (TREE_CODE (arg) != SSA_NAME
|| virtual_operand_p (arg))
continue;
const value_range_equiv
*vr = evrp_range_analyzer.get_value_range (arg);
tree val;
if (vr->singleton_p (&val) && may_propagate_copy (arg, val))
propagate_value (use_p, val);
}
}
return taken_edge;
}
void
evrp_dom_walker::after_dom_children (basic_block bb)
{
evrp_range_analyzer.leave (bb);
}
/* Perform any cleanups after the main phase of EVRP has completed. */
void
evrp_dom_walker::cleanup (void)
{
if (dump_file)
{
fprintf (dump_file, "\nValue ranges after Early VRP:\n\n");
evrp_range_analyzer.dump_all_value_ranges (dump_file);
fprintf (dump_file, "\n");
}
/* Remove stmts in reverse order to make debug stmt creation possible. */
while (! stmts_to_remove.is_empty ())
{
gimple *stmt = stmts_to_remove.pop ();
if (dump_file && dump_flags & TDF_DETAILS)
{
fprintf (dump_file, "Removing dead stmt ");
print_gimple_stmt (dump_file, stmt, 0);
fprintf (dump_file, "\n");
}
gimple_stmt_iterator gsi = gsi_for_stmt (stmt);
if (gimple_code (stmt) == GIMPLE_PHI)
remove_phi_node (&gsi, true);
else
{
unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
release_defs (stmt);
}
}
if (!bitmap_empty_p (need_eh_cleanup))
gimple_purge_all_dead_eh_edges (need_eh_cleanup);
/* Fixup stmts that became noreturn calls. This may require splitting
blocks and thus isn't possible during the dominator walk. Do this
in reverse order so we don't inadvertedly remove a stmt we want to
fixup by visiting a dominating now noreturn call first. */
while (!stmts_to_fixup.is_empty ())
{
gimple *stmt = stmts_to_fixup.pop ();
fixup_noreturn_call (stmt);
}
evrp_folder.vr_values->cleanup_edges_and_switches ();
}
/* Main entry point for the early vrp pass which is a simplified non-iterative
version of vrp where basic blocks are visited in dominance order. Value
ranges discovered in early vrp will also be used by ipa-vrp. */
@ -317,19 +112,17 @@ evrp_dom_walker::cleanup (void)
static unsigned int
execute_early_vrp ()
{
/* Ideally this setup code would move into the ctor for the dominator
walk. However, this setup can change the number of blocks which
/* Ideally this setup code would move into the ctor for the folder
However, this setup can change the number of blocks which
invalidates the internal arrays that are set up by the dominator
walker. */
walker in substitute_and_fold_engine. */
loop_optimizer_init (LOOPS_NORMAL | LOOPS_HAVE_RECORDED_EXITS);
rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
scev_initialize ();
calculate_dominance_info (CDI_DOMINATORS);
/* Walk stmts in dominance order and propagate VRP. */
evrp_dom_walker walker;
walker.walk (ENTRY_BLOCK_PTR_FOR_FN (cfun));
walker.cleanup ();
evrp_folder folder;
folder.substitute_and_fold ();
scev_finalize ();
loop_optimizer_finalize ();
@ -375,4 +168,3 @@ make_pass_early_vrp (gcc::context *ctxt)
{
return new pass_early_vrp (ctxt);
}

View File

@ -8,9 +8,8 @@ void test_bcopy (const void *s)
{
char d[33];
/* Bcopy is transformed into memmove and those calls are expanded
inline in EVRP, before DSE runs, so this test doesn't actually
verify that DSE does its job. */
/* Bcopy is transformed into memmove before DSE runs, so this test
doesn't actually verify that DSE does its job. */
__builtin_bcopy (s, d, sizeof d);
__builtin_bcopy (s, d, sizeof d);
@ -28,4 +27,17 @@ void test_bzero (void)
}
/* { dg-final { scan-tree-dump-times "builtin_memset" 1 "dse1" } } */
/* { dg-final { scan-tree-dump-not "builtin_(bcopy|bzero|memcpy|memmove)" "dse1" } } */
/* Merging the evrp folder into substitute_and_fold_engine shuffled
the order of gimple_fold a bit, so evrp is no longer folding the
memmove inline. This folding is instead done by forwprop. Thus, I
have remmoved the |memmove in the test below as this is not done
until after dse.
What happened was that the propagator engine only called gimple
fold if replace_uses_in() was successful. On the other hand, EVRP
called gimple fold regardless.
If we really care about previous behavior, we could put a call to
gimple ::fold_stmt into evrp_folder::fold_stmt(). */
/* { dg-final { scan-tree-dump-not "builtin_(bcopy|bzero|memcpy)" "dse1" } } */

View File

@ -943,7 +943,7 @@ do_dbg_cnt (void)
class ccp_folder : public substitute_and_fold_engine
{
public:
tree get_value (tree) FINAL OVERRIDE;
tree get_value (tree, gimple *) FINAL OVERRIDE;
bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
};
@ -952,7 +952,7 @@ class ccp_folder : public substitute_and_fold_engine
of calling member functions. */
tree
ccp_folder::get_value (tree op)
ccp_folder::get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED)
{
return get_constant_value (op);
}

View File

@ -492,13 +492,13 @@ init_copy_prop (void)
class copy_folder : public substitute_and_fold_engine
{
public:
tree get_value (tree) FINAL OVERRIDE;
tree get_value (tree, gimple *) FINAL OVERRIDE;
};
/* Callback for substitute_and_fold to get at the final copy-of values. */
tree
copy_folder::get_value (tree name)
copy_folder::get_value (tree name, gimple *stmt ATTRIBUTE_UNUSED)
{
tree val;
if (SSA_NAME_VERSION (name) >= n_copy_of)

View File

@ -868,7 +868,7 @@ substitute_and_fold_engine::replace_uses_in (gimple *stmt)
FOR_EACH_SSA_USE_OPERAND (use, stmt, iter, SSA_OP_USE)
{
tree tuse = USE_FROM_PTR (use);
tree val = get_value (tuse);
tree val = get_value (tuse, stmt);
if (val == tuse || val == NULL_TREE)
continue;
@ -903,19 +903,13 @@ substitute_and_fold_engine::replace_phi_args_in (gphi *phi)
size_t i;
bool replaced = false;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding PHI node: ");
print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
}
for (i = 0; i < gimple_phi_num_args (phi); i++)
{
tree arg = gimple_phi_arg_def (phi, i);
if (TREE_CODE (arg) == SSA_NAME)
{
tree val = get_value (arg);
tree val = get_value (arg, phi);
if (val && val != arg && may_propagate_copy (arg, val))
{
@ -983,7 +977,10 @@ public:
}
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block) {}
virtual void after_dom_children (basic_block bb)
{
substitute_and_fold_engine->post_fold_bb (bb);
}
bool something_changed;
vec<gimple *> stmts_to_remove;
@ -991,11 +988,64 @@ public:
bitmap need_eh_cleanup;
class substitute_and_fold_engine *substitute_and_fold_engine;
private:
void foreach_new_stmt_in_bb (gimple_stmt_iterator old_gsi,
gimple_stmt_iterator new_gsi);
};
/* Call post_new_stmt for each each new statement that has been added
to the current BB. OLD_GSI is the statement iterator before the BB
changes ocurred. NEW_GSI is the iterator which may contain new
statements. */
void
substitute_and_fold_dom_walker::foreach_new_stmt_in_bb
(gimple_stmt_iterator old_gsi,
gimple_stmt_iterator new_gsi)
{
basic_block bb = gsi_bb (new_gsi);
if (gsi_end_p (old_gsi))
old_gsi = gsi_start_bb (bb);
else
gsi_next (&old_gsi);
while (gsi_stmt (old_gsi) != gsi_stmt (new_gsi))
{
gimple *stmt = gsi_stmt (old_gsi);
substitute_and_fold_engine->post_new_stmt (stmt);
gsi_next (&old_gsi);
}
}
void
substitute_and_fold_engine::propagate_into_phi_args (basic_block bb)
{
edge e;
edge_iterator ei;
/* Visit BB successor PHI nodes and replace PHI args. */
FOR_EACH_EDGE (e, ei, bb->succs)
{
for (gphi_iterator gpi = gsi_start_phis (e->dest);
!gsi_end_p (gpi); gsi_next (&gpi))
{
gphi *phi = gpi.phi ();
use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
tree arg = USE_FROM_PTR (use_p);
if (TREE_CODE (arg) != SSA_NAME
|| virtual_operand_p (arg))
continue;
tree val = get_value (arg, phi);
if (val && may_propagate_copy (arg, val))
propagate_value (use_p, val);
}
}
}
edge
substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
{
substitute_and_fold_engine->pre_fold_bb (bb);
/* Propagate known values into PHI nodes. */
for (gphi_iterator i = gsi_start_phis (bb);
!gsi_end_p (i);
@ -1005,13 +1055,24 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
tree res = gimple_phi_result (phi);
if (virtual_operand_p (res))
continue;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding PHI node: ");
print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
}
if (res && TREE_CODE (res) == SSA_NAME)
{
tree sprime = substitute_and_fold_engine->get_value (res);
tree sprime = substitute_and_fold_engine->get_value (res, phi);
if (sprime
&& sprime != res
&& may_propagate_copy (res, sprime))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Queued PHI for removal. Folds to: ");
print_generic_expr (dump_file, sprime);
fprintf (dump_file, "\n");
}
stmts_to_remove.safe_push (phi);
continue;
}
@ -1028,12 +1089,20 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
bool did_replace;
gimple *stmt = gsi_stmt (i);
substitute_and_fold_engine->pre_fold_stmt (stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding statement: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
/* No point propagating into a stmt we have a value for we
can propagate into all uses. Mark it for removal instead. */
tree lhs = gimple_get_lhs (stmt);
if (lhs && TREE_CODE (lhs) == SSA_NAME)
{
tree sprime = substitute_and_fold_engine->get_value (lhs);
tree sprime = substitute_and_fold_engine->get_value (lhs, stmt);
if (sprime
&& sprime != lhs
&& may_propagate_copy (lhs, sprime)
@ -1043,6 +1112,12 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
&& (!is_gimple_assign (stmt)
|| gimple_assign_rhs_code (stmt) != ASSERT_EXPR))
{
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Queued stmt for removal. Folds to: ");
print_generic_expr (dump_file, sprime);
fprintf (dump_file, "\n");
}
stmts_to_remove.safe_push (stmt);
continue;
}
@ -1051,12 +1126,6 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
/* Replace the statement with its folded version and mark it
folded. */
did_replace = false;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Folding statement: ");
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
gimple *old_stmt = stmt;
bool was_noreturn = (is_gimple_call (stmt)
&& gimple_call_noreturn_p (stmt));
@ -1064,6 +1133,9 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
/* Replace real uses in the statement. */
did_replace |= substitute_and_fold_engine->replace_uses_in (stmt);
gimple_stmt_iterator prev_gsi = i;
gsi_prev (&prev_gsi);
/* If we made a replacement, fold the statement. */
if (did_replace)
{
@ -1084,7 +1156,7 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
specific information. Do this before propagating
into the stmt to not disturb pass specific information. */
update_stmt_if_modified (stmt);
if (substitute_and_fold_engine->fold_stmt(&i))
if (substitute_and_fold_engine->fold_stmt (&i))
{
did_replace = true;
prop_stats.num_stmts_folded++;
@ -1115,6 +1187,8 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
/* Now cleanup. */
if (did_replace)
{
foreach_new_stmt_in_bb (prev_gsi, i);
/* If we cleaned up EH information from the statement,
remove EH edges. */
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
@ -1153,6 +1227,9 @@ substitute_and_fold_dom_walker::before_dom_children (basic_block bb)
fprintf (dump_file, "Not folded\n");
}
}
substitute_and_fold_engine->propagate_into_phi_args (bb);
return NULL;
}

View File

@ -104,12 +104,19 @@ class substitute_and_fold_engine
: fold_all_stmts (fold_all_stmts) { }
virtual ~substitute_and_fold_engine (void) { }
virtual bool fold_stmt (gimple_stmt_iterator *) { return false; }
virtual tree get_value (tree) { return NULL_TREE; }
virtual tree get_value (tree, gimple *) { return NULL_TREE; }
bool substitute_and_fold (basic_block = NULL);
bool replace_uses_in (gimple *);
bool replace_phi_args_in (gphi *);
virtual void pre_fold_bb (basic_block) { }
virtual void post_fold_bb (basic_block) { }
virtual void pre_fold_stmt (gimple *) { }
virtual void post_new_stmt (gimple *) { }
void propagate_into_phi_args (basic_block);
/* Users like VRP can set this when they want to perform
folding for every propagation. */
bool fold_all_stmts;

View File

@ -3940,7 +3940,7 @@ class vrp_folder : public substitute_and_fold_engine
{
public:
vrp_folder () : substitute_and_fold_engine (/* Fold all stmts. */ true) { }
tree get_value (tree) FINAL OVERRIDE;
tree get_value (tree, gimple *stmt) FINAL OVERRIDE;
bool fold_stmt (gimple_stmt_iterator *) FINAL OVERRIDE;
class vr_values *vr_values;
@ -4037,7 +4037,7 @@ vrp_folder::fold_stmt (gimple_stmt_iterator *si)
Implemented as a pure wrapper right now, but this will change. */
tree
vrp_folder::get_value (tree op)
vrp_folder::get_value (tree op, gimple *stmt ATTRIBUTE_UNUSED)
{
return op_with_constant_singleton_value_range (op);
}

View File

@ -2799,7 +2799,7 @@ vr_values::extract_range_from_stmt (gimple *stmt, edge *taken_edge_p,
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "\nVisiting statement:\n");
fprintf (dump_file, "\nextract_range_from_stmt visiting:\n");
print_gimple_stmt (dump_file, stmt, 0, dump_flags);
}
@ -3550,6 +3550,30 @@ range_fits_type_p (const value_range_equiv *vr,
return true;
}
/* If COND can be folded entirely as TRUE or FALSE, rewrite the
conditional as such, and return TRUE. */
bool
vr_values::fold_cond (gcond *cond)
{
/* ?? vrp_folder::fold_predicate_in() is a superset of this. At
some point we should merge all variants of this code. */
edge taken_edge;
vrp_visit_cond_stmt (cond, &taken_edge);
if (taken_edge)
{
if (taken_edge->flags & EDGE_TRUE_VALUE)
gimple_cond_make_true (cond);
else if (taken_edge->flags & EDGE_FALSE_VALUE)
gimple_cond_make_false (cond);
else
gcc_unreachable ();
update_stmt (cond);
return true;
}
return false;
}
/* Simplify a conditional using a relational operator to an equality
test if the range information indicates only one value can satisfy
the original conditional. */
@ -3561,6 +3585,9 @@ vr_values::simplify_cond_using_ranges_1 (gcond *stmt)
tree op1 = gimple_cond_rhs (stmt);
enum tree_code cond_code = gimple_cond_code (stmt);
if (fold_cond (stmt))
return true;
if (cond_code != NE_EXPR
&& cond_code != EQ_EXPR
&& TREE_CODE (op0) == SSA_NAME

View File

@ -112,6 +112,7 @@ class vr_values
bool simplify_bit_ops_using_ranges (gimple_stmt_iterator *, gimple *);
bool simplify_min_or_max_using_ranges (gimple_stmt_iterator *, gimple *);
bool simplify_cond_using_ranges_1 (gcond *);
bool fold_cond (gcond *);
bool simplify_switch_using_ranges (gswitch *);
bool simplify_float_conversion_using_ranges (gimple_stmt_iterator *,
gimple *);