mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-22 22:01:20 +08:00
Move gimple_edge code ito grange remove switch cache...
Move gimple_edge code ito grange remove switch cache, just calculate each time move ssa_range::valid_ssa_p to valid_range_ssa_p in grange.h From-SVN: r275363
This commit is contained in:
parent
4ad015fcfb
commit
7212e9c519
117
gcc/grange.cc
117
gcc/grange.cc
@ -60,6 +60,116 @@ along with GCC; see the file COPYING3. If not see
|
||||
// table where a class is implemented for a given tree code, and
|
||||
// auto-registered intot he table for use when it is encountered.
|
||||
|
||||
|
||||
static gimple *
|
||||
calc_single_range (irange &r, gswitch *sw, edge e)
|
||||
{
|
||||
unsigned x, lim;
|
||||
lim = gimple_switch_num_labels (sw);
|
||||
tree type = TREE_TYPE (gimple_switch_index (sw));
|
||||
|
||||
// ADA currently has cases where the index is 64 bits and the case
|
||||
// arguments are 32 bit, causing a trap when we create a case_range.
|
||||
// Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
|
||||
// punt on these switches.
|
||||
// cfamily fails during a bootstrap due to a signed index and unsigned cases.
|
||||
// so changing to types_compatible_p for now.
|
||||
tree case_type = TREE_TYPE (CASE_LOW (gimple_switch_label (sw, 1)));
|
||||
if (lim > 1 && !types_compatible_p (type, case_type))
|
||||
return NULL;
|
||||
|
||||
|
||||
if (e != gimple_switch_default_edge (cfun, sw))
|
||||
{
|
||||
r.set_undefined ();
|
||||
// Loop through all the switches edges, ignoring the default edge.
|
||||
// unioning the ranges together.
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
if (gimple_switch_edge (cfun, sw, x) != e)
|
||||
continue;
|
||||
tree low = CASE_LOW (gimple_switch_label (sw, x));
|
||||
tree high = CASE_HIGH (gimple_switch_label (sw, x));
|
||||
if (!high)
|
||||
high = low;
|
||||
irange case_range (low, high);
|
||||
r.union_ (case_range);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r.set_varying (type);
|
||||
// Loop through all the switches edges, ignoring the default edge.
|
||||
// intersecting the ranges not covered by the case.
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
tree low = CASE_LOW (gimple_switch_label (sw, x));
|
||||
tree high = CASE_HIGH (gimple_switch_label (sw, x));
|
||||
if (!high)
|
||||
high = low;
|
||||
irange case_range (VR_ANTI_RANGE, low, high);
|
||||
r.intersect (case_range);
|
||||
}
|
||||
}
|
||||
return sw;
|
||||
}
|
||||
|
||||
|
||||
// If there is a range control statment at the end of block BB, return it.
|
||||
|
||||
gimple_stmt_iterator
|
||||
gsi_outgoing_range_stmt (basic_block bb)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
|
||||
if (!gsi_end_p (gsi))
|
||||
{
|
||||
gimple *s = gsi_stmt (gsi);
|
||||
if (is_a<gcond *> (s) || is_a<gswitch *> (s))
|
||||
return gsi;
|
||||
}
|
||||
return gsi_none ();
|
||||
}
|
||||
|
||||
gimple *
|
||||
gimple_outgoing_range_stmt_p (basic_block bb)
|
||||
{
|
||||
// This will return NULL if there is not a branch statement.
|
||||
return gsi_stmt (gsi_outgoing_range_stmt (bb));
|
||||
}
|
||||
|
||||
// Calculate the range forced on on edge E by control flow, if any, and
|
||||
// return it in R. Return the statment which defines the range, otherwise
|
||||
// return NULL;
|
||||
|
||||
gimple *
|
||||
gimple_outgoing_edge_range_p (irange &r, edge e)
|
||||
{
|
||||
// Determine if there is an outgoing edge.
|
||||
gimple *s = gimple_outgoing_range_stmt_p (e->src);
|
||||
if (!s)
|
||||
return NULL;
|
||||
if (is_a<gcond *> (s))
|
||||
{
|
||||
if (e->flags & EDGE_TRUE_VALUE)
|
||||
r = irange (boolean_true_node, boolean_true_node);
|
||||
else if (e->flags & EDGE_FALSE_VALUE)
|
||||
r = irange (boolean_false_node, boolean_false_node);
|
||||
else
|
||||
gcc_unreachable ();
|
||||
return s;
|
||||
}
|
||||
|
||||
gcc_checking_assert (is_a<gswitch *> (s));
|
||||
gswitch *sw = as_a<gswitch *> (s);
|
||||
tree type = TREE_TYPE (gimple_switch_index (sw));
|
||||
|
||||
if (!irange::supports_type_p (type))
|
||||
return NULL;
|
||||
|
||||
return calc_single_range (r, sw, e);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
// This is the class which is used to implement range adjustments in GIMPLE.
|
||||
@ -266,7 +376,6 @@ grange_op::operand1 () const
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Fold this unary statement uusing R1 as operand1's range, returning the
|
||||
// result in RES. Return false if the operation fails.
|
||||
|
||||
@ -284,6 +393,7 @@ grange_op::fold (irange &res, const irange &orig_r1) const
|
||||
return fold (res, r1, r2);
|
||||
}
|
||||
|
||||
|
||||
// Fold this binary statement using R1 and R2 as the operands ranges,
|
||||
// returning the result in RES. Return false if the operation fails.
|
||||
|
||||
@ -316,6 +426,7 @@ grange_op::fold (irange &res, const irange &r1, const irange &r2) const
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Calculate what we can determine of the range of this unary statement's
|
||||
// operand if the lhs of the expression has the range LHS_RANGE. Return false
|
||||
// if nothing can be determined.
|
||||
@ -339,6 +450,7 @@ grange_op::calc_op1_irange (irange &r, const irange &lhs_range) const
|
||||
return handler ()->op1_range (r, type, lhs_range, type_range);
|
||||
}
|
||||
|
||||
|
||||
// Calculate what we can determine of the range of this statement's first
|
||||
// operand if the lhs of the expression has the range LHS_RANGE and the second
|
||||
// operand has the range OP2_RANGE. Return false if nothing can be determined.
|
||||
@ -361,6 +473,7 @@ grange_op::calc_op1_irange (irange &r, const irange &lhs_range,
|
||||
return handler ()->op1_range (r, type, lhs_range, op2_range);
|
||||
}
|
||||
|
||||
|
||||
// Calculate what we can determine of the range of this statement's second
|
||||
// operand if the lhs of the expression has the range LHS_RANGE and the first
|
||||
// operand has the range OP1_RANGE. Return false if nothing can be determined.
|
||||
@ -378,5 +491,3 @@ grange_op::calc_op2_irange (irange &r, const irange &lhs_range,
|
||||
}
|
||||
return handler ()->op2_range (r, type, lhs_range, op1_range);
|
||||
}
|
||||
|
||||
|
||||
|
@ -24,6 +24,10 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "range.h"
|
||||
#include "range-op.h"
|
||||
|
||||
extern gimple_stmt_iterator gsi_outgoing_range_stmt (basic_block bb);
|
||||
extern gimple *gimple_outgoing_range_stmt_p (basic_block bb);
|
||||
extern gimple *gimple_outgoing_edge_range_p (irange &r, edge e);
|
||||
|
||||
// Gimple statement which supports range_op operations.
|
||||
// This can map to gimple assign or cond statements, so quick access to the
|
||||
// operands is provided so the user does not need to know which it is.
|
||||
|
@ -350,7 +350,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
|
||||
bool summarize_varying = false;
|
||||
for (x = 1; x < m_ssa_ranges.length (); ++x)
|
||||
{
|
||||
if (!ssa_ranger::valid_ssa_p (ssa_name (x)))
|
||||
if (!valid_range_ssa_p (ssa_name (x)))
|
||||
continue;
|
||||
if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
|
||||
{
|
||||
@ -371,7 +371,7 @@ block_range_cache::dump (FILE *f, basic_block bb, bool print_varying)
|
||||
fprintf (f, "VARYING_P on entry : ");
|
||||
for (x = 1; x < num_ssa_names; ++x)
|
||||
{
|
||||
if (!ssa_ranger::valid_ssa_p (ssa_name (x)))
|
||||
if (!valid_range_ssa_p (ssa_name (x)))
|
||||
continue;
|
||||
if (m_ssa_ranges[x] && m_ssa_ranges[x]->get_bb_range (r, bb))
|
||||
{
|
||||
@ -467,7 +467,7 @@ ssa_global_cache::dump (FILE *f)
|
||||
fprintf (f, "Non-varying global ranges:\n");
|
||||
fprintf (f, "=========================:\n");
|
||||
for ( x = 1; x < num_ssa_names; x++)
|
||||
if (ssa_ranger::valid_ssa_p (ssa_name (x)) &&
|
||||
if (valid_range_ssa_p (ssa_name (x)) &&
|
||||
get_global_range (r, ssa_name (x)) && !r.varying_p ())
|
||||
{
|
||||
print_generic_expr (f, ssa_name (x), TDF_NONE);
|
||||
@ -524,7 +524,7 @@ gori_cache::block_range (irange &r, basic_block bb, tree name, bool calc)
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (name);
|
||||
basic_block def_bb = NULL;
|
||||
|
||||
gcc_checking_assert (ssa_ranger::valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
|
||||
if (calc)
|
||||
{
|
||||
|
@ -28,7 +28,8 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "gimple-pretty-print.h"
|
||||
#include "diagnostic-core.h"
|
||||
#include "wide-int.h"
|
||||
#include "ssa-range.h"
|
||||
#include "grange.h"
|
||||
#include "ssa-range-gori.h"
|
||||
#include "fold-const.h"
|
||||
|
||||
// Construct a range_def_chain
|
||||
@ -59,8 +60,8 @@ range_def_chain::~range_def_chain ()
|
||||
bool
|
||||
range_def_chain::in_chain_p (tree name, tree def)
|
||||
{
|
||||
gcc_checking_assert (ssa_ranger::valid_ssa_p (def));
|
||||
gcc_checking_assert (ssa_ranger::valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (def));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
|
||||
// Get the defintion chain for DEF
|
||||
bitmap chain = get_def_chain (def);
|
||||
@ -169,16 +170,16 @@ range_def_chain::get_def_chain (tree name)
|
||||
if (is_a<grange_op *> (s))
|
||||
{
|
||||
grange_op *stmt = as_a<grange_op *> (s);
|
||||
ssa1 = ssa_ranger::valid_ssa_p (stmt->operand1 ());
|
||||
ssa2 = ssa_ranger::valid_ssa_p (stmt->operand2 ());
|
||||
ssa1 = valid_range_ssa_p (stmt->operand1 ());
|
||||
ssa2 = valid_range_ssa_p (stmt->operand2 ());
|
||||
ssa3 = NULL_TREE;
|
||||
}
|
||||
else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR)
|
||||
{
|
||||
gassign *st = as_a<gassign *> (s);
|
||||
ssa1 = ssa_ranger::valid_ssa_p (gimple_assign_rhs1 (st));
|
||||
ssa2 = ssa_ranger::valid_ssa_p (gimple_assign_rhs2 (st));
|
||||
ssa3 = ssa_ranger::valid_ssa_p (gimple_assign_rhs3 (st));
|
||||
ssa1 = valid_range_ssa_p (gimple_assign_rhs1 (st));
|
||||
ssa2 = valid_range_ssa_p (gimple_assign_rhs2 (st));
|
||||
ssa3 = valid_range_ssa_p (gimple_assign_rhs3 (st));
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
@ -353,16 +354,16 @@ gori_map::calculate_gori (basic_block bb)
|
||||
if (is_a<gcond *> (s))
|
||||
{
|
||||
gcond *gc = as_a<gcond *>(s);
|
||||
name = ssa_ranger::valid_ssa_p (gimple_cond_lhs (gc));
|
||||
name = valid_range_ssa_p (gimple_cond_lhs (gc));
|
||||
maybe_add_gori (name, gimple_bb (s));
|
||||
|
||||
name = ssa_ranger::valid_ssa_p (gimple_cond_rhs (gc));
|
||||
name = valid_range_ssa_p (gimple_cond_rhs (gc));
|
||||
maybe_add_gori (name, gimple_bb (s));
|
||||
}
|
||||
else
|
||||
{
|
||||
gswitch *gs = as_a<gswitch *>(s);
|
||||
name = ssa_ranger::valid_ssa_p (gimple_switch_index (gs));
|
||||
name = valid_range_ssa_p (gimple_switch_index (gs));
|
||||
maybe_add_gori (name, gimple_bb (s));
|
||||
}
|
||||
}
|
||||
@ -688,7 +689,7 @@ gori_compute::compute_operand_range_switch (irange &r, gswitch *s,
|
||||
}
|
||||
|
||||
// If op1 is in the defintion chain, pass lhs back.
|
||||
if (ssa_ranger::valid_ssa_p (op1) && in_chain_p (name, op1))
|
||||
if (valid_range_ssa_p (op1) && in_chain_p (name, op1))
|
||||
return compute_operand_range (r, SSA_NAME_DEF_STMT (op1), lhs, name,
|
||||
name_range);
|
||||
|
||||
@ -742,8 +743,8 @@ gori_compute::compute_operand_range_op (irange &r, grange_op *stmt,
|
||||
return true;
|
||||
}
|
||||
|
||||
op1 = ssa_ranger::valid_ssa_p (stmt->operand1 ());
|
||||
op2 = ssa_ranger::valid_ssa_p (stmt->operand2 ());
|
||||
op1 = valid_range_ssa_p (stmt->operand1 ());
|
||||
op2 = valid_range_ssa_p (stmt->operand2 ());
|
||||
|
||||
// The base ranger handles NAME on this statement.
|
||||
if (op1 == name || op2 == name)
|
||||
@ -902,8 +903,8 @@ gori_compute::compute_logical_operands (irange &r, grange_op *s,
|
||||
op2 = s->operand2 ();
|
||||
gcc_checking_assert (op1 != name && op2 != name);
|
||||
|
||||
op1_in_chain = ssa_ranger::valid_ssa_p (op1) && in_chain_p (name, op1);
|
||||
op2_in_chain = ssa_ranger::valid_ssa_p (op2) && in_chain_p (name, op2);
|
||||
op1_in_chain = valid_range_ssa_p (op1) && in_chain_p (name, op1);
|
||||
op2_in_chain = valid_range_ssa_p (op2) && in_chain_p (name, op2);
|
||||
|
||||
/* If neither operand is derived, then this stmt tells us nothing. */
|
||||
if (!op1_in_chain && !op2_in_chain)
|
||||
@ -1067,6 +1068,13 @@ gori_compute::compute_operand1_and_operand2_range (irange &r, grange_op *s,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
gori_compute::has_edge_range_p (edge e, tree name)
|
||||
{
|
||||
return (is_export_p (name, e->src) || def_chain_in_export_p (name, e->src));
|
||||
}
|
||||
|
||||
|
||||
// If the src block of edge E defines an outgoing range for a name that is
|
||||
// is in the def_chain for NAME, get the outgoing range for that ssa_name
|
||||
// and re-evaluate NAME using this value. If NAME_RANGE is supplied (normally
|
||||
@ -1075,6 +1083,8 @@ gori_compute::compute_operand1_and_operand2_range (irange &r, grange_op *s,
|
||||
// Return false if nothing can be re-evaluated, or if NAME is actually exported
|
||||
// and doesnt need redefining.
|
||||
|
||||
#include "ssa-range.h"
|
||||
|
||||
bool
|
||||
gori_compute::reevaluate_definition (irange &r, tree name, edge e,
|
||||
irange *name_range)
|
||||
@ -1097,7 +1107,7 @@ gori_compute::reevaluate_definition (irange &r, tree name, edge e,
|
||||
// We know its possible to evaluate NAME from SOMETHING in its defintion.
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_USE)
|
||||
{
|
||||
tree use = ssa_ranger::valid_ssa_p (USE_FROM_PTR (use_p));
|
||||
tree use = valid_range_ssa_p (USE_FROM_PTR (use_p));
|
||||
if (use)
|
||||
{
|
||||
irange use_range;
|
||||
@ -1124,12 +1134,6 @@ gori_compute::reevaluate_definition (irange &r, tree name, edge e,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
gori_compute::has_edge_range_p (edge e, tree name)
|
||||
{
|
||||
return (is_export_p (name, e->src) || def_chain_in_export_p (name, e->src));
|
||||
}
|
||||
|
||||
// Calculate a range on edge E and return it in R. Try to evaluate a range
|
||||
// for NAME on this edge. Return FALSE if this is either not a control edge
|
||||
// or NAME is not defined by this edge.
|
||||
@ -1140,7 +1144,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
|
||||
{
|
||||
irange lhs;
|
||||
|
||||
gcc_checking_assert (ssa_ranger::valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
// Determine if there is an outgoing edge.
|
||||
gimple *s = gimple_outgoing_edge_range_p (lhs, e);
|
||||
if (!s)
|
||||
@ -1149,7 +1153,7 @@ gori_compute::outgoing_edge_range_p (irange &r, edge e, tree name,
|
||||
// If NAME can be calculated on the edge, use that.
|
||||
if (is_export_p (name, e->src))
|
||||
return compute_operand_range (r, s, lhs, name, name_range);
|
||||
|
||||
|
||||
// Otherwise see if NAME is derived from something that can be calculated.
|
||||
// This performs no dynamic lookups whatsover, so it is low cost.
|
||||
return reevaluate_definition (r, name, e, name_range);
|
||||
@ -1192,7 +1196,7 @@ gori_compute::range_from_import (irange &r, tree name, irange &import_range)
|
||||
tree op2 = s->operand2 ();
|
||||
|
||||
// Evaluate op1
|
||||
if (ssa_ranger::valid_ssa_p (op1))
|
||||
if (valid_range_ssa_p (op1))
|
||||
{
|
||||
if (op1 == import)
|
||||
{
|
||||
@ -1211,7 +1215,7 @@ gori_compute::range_from_import (irange &r, tree name, irange &import_range)
|
||||
return s->fold (r, r1);
|
||||
|
||||
// Now evaluate op2.
|
||||
if (ssa_ranger::valid_ssa_p (op2))
|
||||
if (valid_range_ssa_p (op2))
|
||||
{
|
||||
if (op2 == import)
|
||||
{
|
||||
|
@ -189,4 +189,12 @@ private:
|
||||
bool get_tree_range (irange &r, tree expr);
|
||||
irange range_from_ssa (tree ssa);
|
||||
|
||||
static inline tree
|
||||
valid_range_ssa_p (tree exp)
|
||||
{
|
||||
if (exp && TREE_CODE (exp) == SSA_NAME && irange::supports_ssa_p (exp))
|
||||
return exp;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
#endif // GCC_SSA_RANGE_GORI_H
|
||||
|
@ -404,7 +404,7 @@ rvrp_engine::fold_and_simplify (gimple_stmt_iterator &gsi)
|
||||
|
||||
// Only process statements which are a COND expr or have a valid LHS.
|
||||
if (gimple_code (stmt) != GIMPLE_COND &&
|
||||
!m_ranger->valid_ssa_p (gimple_get_lhs (stmt)))
|
||||
!valid_range_ssa_p (gimple_get_lhs (stmt)))
|
||||
return;
|
||||
|
||||
// ?? This is only needed for propagate_mark_stmt_for_cleanup.
|
||||
@ -446,7 +446,7 @@ rvrp_engine::visit (basic_block bb)
|
||||
{
|
||||
gphi *phi = gpi.phi ();
|
||||
tree phi_def = gimple_phi_result (phi);
|
||||
if (m_ranger->valid_ssa_p (phi_def))
|
||||
if (valid_range_ssa_p (phi_def))
|
||||
m_ranger->range_of_stmt (r, phi);
|
||||
}
|
||||
|
||||
|
287
gcc/ssa-range.cc
287
gcc/ssa-range.cc
@ -53,279 +53,16 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "vr-values.h"
|
||||
#include "dbgcnt.h"
|
||||
|
||||
// #define RANGER_SWITCH_NONE
|
||||
// #define RANGER_SWITCH_CALC
|
||||
|
||||
|
||||
class switch_edge_manager
|
||||
{
|
||||
public:
|
||||
switch_edge_manager ();
|
||||
~switch_edge_manager ();
|
||||
gimple *get_range (irange &r, gimple *s, edge e, bool must_exist = false);
|
||||
void clear_ranges ();
|
||||
private:
|
||||
void calc_switch_ranges (gswitch *sw);
|
||||
void calc_single_range (irange &r, gswitch *sw, edge e);
|
||||
void init_ranges ();
|
||||
irange *new_range ();
|
||||
hash_map<edge, irange *> *m_edge_table;
|
||||
obstack m_rstack;
|
||||
} switch_edge_range;
|
||||
|
||||
switch_edge_manager::switch_edge_manager ()
|
||||
{
|
||||
m_edge_table = NULL;
|
||||
}
|
||||
|
||||
switch_edge_manager::~switch_edge_manager ()
|
||||
{
|
||||
clear_ranges ();
|
||||
}
|
||||
|
||||
void
|
||||
switch_edge_manager::init_ranges ()
|
||||
{
|
||||
gcc_assert (!m_edge_table);
|
||||
m_edge_table = new hash_map<edge, irange *> (n_edges_for_fn (cfun));
|
||||
gcc_obstack_init (&m_rstack);
|
||||
}
|
||||
|
||||
void
|
||||
switch_edge_manager::clear_ranges ()
|
||||
{
|
||||
if (m_edge_table)
|
||||
{
|
||||
delete m_edge_table;
|
||||
obstack_free (&m_rstack, NULL);
|
||||
}
|
||||
m_edge_table = NULL;
|
||||
}
|
||||
|
||||
inline irange *
|
||||
switch_edge_manager::new_range ()
|
||||
{
|
||||
return XOBNEW (&m_rstack, irange);
|
||||
}
|
||||
|
||||
|
||||
gimple *
|
||||
switch_edge_manager::get_range (irange &r, gimple *s, edge e, bool must_exist)
|
||||
{
|
||||
gcc_checking_assert (is_a<gswitch *> (s));
|
||||
gswitch *sw = as_a<gswitch *> (s);
|
||||
|
||||
// ADA currently has cases where the index is 64 bits and the case
|
||||
// arguments are 32 bit, causing a trap when we create a case_range.
|
||||
// Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798)
|
||||
// punt on these switches.
|
||||
if (gimple_switch_num_labels (sw) > 1 &&
|
||||
TYPE_PRECISION (TREE_TYPE (CASE_LOW (gimple_switch_label (sw, 1)))) !=
|
||||
TYPE_PRECISION (TREE_TYPE (gimple_switch_index (sw))))
|
||||
return NULL;
|
||||
|
||||
if (!m_edge_table)
|
||||
init_ranges ();
|
||||
|
||||
#ifdef RANGER_SWITCH_NONE
|
||||
// Turn off switch support in ranger
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
#ifdef RANGER_SWITCH_CALC
|
||||
// Calculate the switch edge each time.
|
||||
calc_single_range (r, sw, e);
|
||||
return s;
|
||||
#endif
|
||||
|
||||
irange **val = m_edge_table->get (e);
|
||||
if (!val)
|
||||
{
|
||||
// Avoid infinite recursion in case of a bug.
|
||||
gcc_assert (!must_exist);
|
||||
// calculate ranges for the entire switch.
|
||||
calc_switch_ranges (sw);
|
||||
return get_range (r, s, e, true);
|
||||
}
|
||||
|
||||
r = **val;
|
||||
#ifdef VERIFY_SWITCH
|
||||
// Verify the range is as expected.
|
||||
irange verify;
|
||||
calc_single_range (verify, sw, e);
|
||||
gcc_assert (verify == r);
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
void
|
||||
switch_edge_manager::calc_switch_ranges (gswitch *sw)
|
||||
{
|
||||
bool existed;
|
||||
unsigned x, lim;
|
||||
lim = gimple_switch_num_labels (sw);
|
||||
tree type = TREE_TYPE (gimple_switch_index (sw));
|
||||
|
||||
edge default_edge = gimple_switch_default_edge (cfun, sw);
|
||||
irange *&default_slot = m_edge_table->get_or_insert (default_edge, &existed);
|
||||
// This should be the first call into this switch.
|
||||
// For the default range case, start with varying and intersect each other
|
||||
// case from it.
|
||||
gcc_assert (!existed);
|
||||
default_slot = new_range ();
|
||||
default_slot->set_varying (type);
|
||||
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
edge e = gimple_switch_edge (cfun, sw, x);
|
||||
|
||||
// If this edge is the same as the default edge, do nothing else.
|
||||
if (e == default_edge)
|
||||
continue;
|
||||
|
||||
tree low = CASE_LOW (gimple_switch_label (sw, x));
|
||||
tree high = CASE_HIGH (gimple_switch_label (sw, x));
|
||||
if (!high)
|
||||
high = low;
|
||||
|
||||
irange def_case_range (VR_ANTI_RANGE, low, high);
|
||||
range_cast (def_case_range, type);
|
||||
default_slot->intersect (def_case_range);
|
||||
|
||||
irange case_range (low, high);
|
||||
range_cast (case_range, type);
|
||||
irange *&slot = m_edge_table->get_or_insert (e, &existed);
|
||||
if (!existed)
|
||||
{
|
||||
slot = new_range ();
|
||||
*slot = case_range;
|
||||
}
|
||||
else
|
||||
// Add this case range to the existing ranges on the edge.
|
||||
slot->union_ (case_range);
|
||||
}
|
||||
|
||||
#ifdef VERIFY_SWITCH
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
edge e = gimple_switch_edge (cfun, sw, x);
|
||||
irange r1;
|
||||
// get range verifies it as is it should be.
|
||||
gcc_assert (get_range (r1, sw, e, true));
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
switch_edge_manager::calc_single_range (irange &r, gswitch *sw, edge e)
|
||||
{
|
||||
tree type = TREE_TYPE (gimple_switch_index (sw));
|
||||
|
||||
unsigned x, lim;
|
||||
lim = gimple_switch_num_labels (sw);
|
||||
|
||||
if (e != gimple_switch_default_edge (cfun, sw))
|
||||
{
|
||||
r.set_undefined ();
|
||||
// Loop through all the switches edges, ignoring the default edge.
|
||||
// unioning the ranges together.
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
if (gimple_switch_edge (cfun, sw, x) != e)
|
||||
continue;
|
||||
tree low = CASE_LOW (gimple_switch_label (sw, x));
|
||||
tree high = CASE_HIGH (gimple_switch_label (sw, x));
|
||||
if (!high)
|
||||
high = low;
|
||||
irange case_range (low, high);
|
||||
r.union_ (case_range);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
r.set_varying (type);
|
||||
// Loop through all the switches edges, ignoring the default edge.
|
||||
// intersecting the ranges not covered by the case.
|
||||
for (x = 1; x < lim; x++)
|
||||
{
|
||||
tree low = CASE_LOW (gimple_switch_label (sw, x));
|
||||
tree high = CASE_HIGH (gimple_switch_label (sw, x));
|
||||
if (!high)
|
||||
high = low;
|
||||
irange case_range (VR_ANTI_RANGE, low, high);
|
||||
r.intersect (case_range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If there is a range control statment at the end of block BB, return it.
|
||||
|
||||
gimple_stmt_iterator
|
||||
gsi_outgoing_range_stmt (basic_block bb)
|
||||
{
|
||||
gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
|
||||
if (!gsi_end_p (gsi))
|
||||
{
|
||||
gimple *s = gsi_stmt (gsi);
|
||||
if (is_a<gcond *> (s) || is_a<gswitch *> (s))
|
||||
return gsi;
|
||||
}
|
||||
return gsi_none ();
|
||||
}
|
||||
|
||||
gimple *
|
||||
gimple_outgoing_range_stmt_p (basic_block bb)
|
||||
{
|
||||
// This will return NULL if there is not a branch statement.
|
||||
return gsi_stmt (gsi_outgoing_range_stmt (bb));
|
||||
}
|
||||
|
||||
// Calculate the range forced on on edge E by control flow, if any, and
|
||||
// return it in R. Return the statment which defines the range, otherwise
|
||||
// return NULL;
|
||||
|
||||
gimple *
|
||||
gimple_outgoing_edge_range_p (irange &r, edge e)
|
||||
{
|
||||
// Determine if there is an outgoing edge.
|
||||
gimple *s = gimple_outgoing_range_stmt_p (e->src);
|
||||
if (!s)
|
||||
return NULL;
|
||||
if (is_a<gcond *> (s))
|
||||
{
|
||||
if (e->flags & EDGE_TRUE_VALUE)
|
||||
r = irange (boolean_true_node, boolean_true_node);
|
||||
else if (e->flags & EDGE_FALSE_VALUE)
|
||||
r = irange (boolean_false_node, boolean_false_node);
|
||||
else
|
||||
gcc_unreachable ();
|
||||
return s;
|
||||
}
|
||||
|
||||
gcc_checking_assert (is_a<gswitch *> (s));
|
||||
gswitch *sw = as_a<gswitch *> (s);
|
||||
tree type = TREE_TYPE (gimple_switch_index (sw));
|
||||
|
||||
if (!irange::supports_type_p (type))
|
||||
return NULL;
|
||||
|
||||
return switch_edge_range.get_range (r, s, e);
|
||||
}
|
||||
|
||||
// Initialize a ranger.
|
||||
|
||||
ssa_ranger::ssa_ranger ()
|
||||
{
|
||||
switch_edge_range.clear_ranges ();
|
||||
}
|
||||
|
||||
// Destruct a ranger.
|
||||
|
||||
ssa_ranger::~ssa_ranger ()
|
||||
{
|
||||
switch_edge_range.clear_ranges ();
|
||||
}
|
||||
|
||||
// This function returns a range for a tree node. If optional statement S
|
||||
@ -345,7 +82,7 @@ ssa_ranger::range_of_expr (irange&r, tree op, edge e)
|
||||
{
|
||||
if (!irange::supports_p (op))
|
||||
return false;
|
||||
if (valid_ssa_p (op))
|
||||
if (valid_range_ssa_p (op))
|
||||
{
|
||||
range_on_edge (r, e, op);
|
||||
return true;
|
||||
@ -364,7 +101,7 @@ ssa_ranger::outgoing_edge_range_p (irange &r, edge e, tree name,
|
||||
{
|
||||
irange lhs;
|
||||
|
||||
gcc_checking_assert (valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
// Determine if there is an outgoing edge.
|
||||
gimple *s = gimple_outgoing_edge_range_p (lhs, e);
|
||||
|
||||
@ -384,7 +121,7 @@ void
|
||||
ssa_ranger::range_on_edge (irange &r, edge e, tree name)
|
||||
{
|
||||
irange edge_range;
|
||||
gcc_checking_assert (valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
|
||||
range_on_exit (r, e->src, name);
|
||||
gcc_checking_assert (r.undefined_p ()
|
||||
@ -674,7 +411,7 @@ ssa_ranger::range_of_phi (irange &r, gphi *phi, tree name,
|
||||
continue;
|
||||
if (name == arg)
|
||||
arg_range = *name_range;
|
||||
else if (valid_ssa_p (arg) && !eval_from)
|
||||
else if (valid_range_ssa_p (arg) && !eval_from)
|
||||
// Try to find a range from the edge. If that fails, return varying.
|
||||
range_on_edge (arg_range, e, arg);
|
||||
else
|
||||
@ -824,7 +561,7 @@ void
|
||||
global_ranger::range_on_entry (irange &r, basic_block bb, tree name)
|
||||
{
|
||||
irange entry_range;
|
||||
gcc_checking_assert (valid_ssa_p (name));
|
||||
gcc_checking_assert (valid_range_ssa_p (name));
|
||||
|
||||
// Start with any known range
|
||||
gcc_assert (range_of_stmt (r, SSA_NAME_DEF_STMT (name), name));
|
||||
@ -889,7 +626,7 @@ global_ranger::range_of_expr (irange &r, tree op, gimple *s)
|
||||
return false;
|
||||
|
||||
// If there is a statement, and a valid ssa_name, try to find a range.
|
||||
if (s && valid_ssa_p (op))
|
||||
if (s && valid_range_ssa_p (op))
|
||||
{
|
||||
basic_block bb = gimple_bb (s);
|
||||
gimple *def_stmt = SSA_NAME_DEF_STMT (op);
|
||||
@ -956,7 +693,7 @@ global_ranger::export_global_ranges ()
|
||||
{
|
||||
tree name = ssa_name (x);
|
||||
if (name && !SSA_NAME_IN_FREE_LIST (name) &&
|
||||
valid_ssa_p (name) && m_gori.m_globals.get_global_range (r, name) &&
|
||||
valid_range_ssa_p (name) && m_gori.m_globals.get_global_range (r, name) &&
|
||||
!r.varying_p())
|
||||
{
|
||||
// Make sure the new range is a subset of the old range.
|
||||
@ -1011,7 +748,7 @@ global_ranger::dump (FILE *f)
|
||||
for (x = 1; x < num_ssa_names; x++)
|
||||
{
|
||||
tree name = ssa_name (x);
|
||||
if (valid_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
|
||||
if (valid_range_ssa_p (name) && SSA_NAME_DEF_STMT (name) &&
|
||||
gimple_bb (SSA_NAME_DEF_STMT (name)) == bb &&
|
||||
m_gori.m_globals.get_global_range (range, name))
|
||||
{
|
||||
@ -1031,7 +768,7 @@ global_ranger::dump (FILE *f)
|
||||
{
|
||||
for (x = 1; x < num_ssa_names; x++)
|
||||
{
|
||||
tree name = valid_ssa_p (ssa_name (x));
|
||||
tree name = valid_range_ssa_p (ssa_name (x));
|
||||
if (name && outgoing_edge_range_p (range, e, name))
|
||||
{
|
||||
gimple *s = SSA_NAME_DEF_STMT (name);
|
||||
@ -1092,7 +829,7 @@ global_ranger::calculate_and_dump (FILE *output)
|
||||
{
|
||||
gphi *phi = gpi.phi ();
|
||||
tree phi_def = gimple_phi_result (phi);
|
||||
if (valid_ssa_p (phi_def))
|
||||
if (valid_range_ssa_p (phi_def))
|
||||
gcc_assert (range_of_stmt (r, phi));
|
||||
}
|
||||
|
||||
@ -1104,12 +841,12 @@ global_ranger::calculate_and_dump (FILE *output)
|
||||
use_operand_p use_p;
|
||||
|
||||
// Calculate a range for the LHS if there is one.
|
||||
if (valid_ssa_p (gimple_get_lhs (stmt)))
|
||||
if (valid_range_ssa_p (gimple_get_lhs (stmt)))
|
||||
range_of_stmt (r, stmt);
|
||||
// and make sure to query every operand.
|
||||
FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
|
||||
{
|
||||
tree use = valid_ssa_p (USE_FROM_PTR (use_p));
|
||||
tree use = valid_range_ssa_p (USE_FROM_PTR (use_p));
|
||||
if (use)
|
||||
range_of_expr (r, use, stmt);
|
||||
}
|
||||
|
@ -25,10 +25,6 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "ssa-range-gori.h"
|
||||
#include "ssa-range-cache.h"
|
||||
|
||||
extern gimple_stmt_iterator gsi_outgoing_range_stmt (basic_block bb);
|
||||
extern gimple *gimple_outgoing_range_stmt_p (basic_block bb);
|
||||
extern gimple *gimple_outgoing_edge_range_p (irange &r, edge e);
|
||||
|
||||
// This is the basic range generator interface.
|
||||
//
|
||||
// This base class provides all the API entry points, but only provides
|
||||
@ -52,8 +48,6 @@ class ssa_ranger
|
||||
ssa_ranger ();
|
||||
~ssa_ranger ();
|
||||
|
||||
static tree valid_ssa_p (tree exp);
|
||||
|
||||
virtual bool range_of_expr (irange &r, tree expr, gimple *s = NULL);
|
||||
virtual bool range_of_expr (irange &r, tree expr, edge e);
|
||||
virtual bool range_of_stmt (irange &r, gimple *s, tree name = NULL_TREE);
|
||||
@ -208,17 +202,4 @@ on_demand_get_range_on_stmt (irange &r, tree ssa, gimple *stmt)
|
||||
return false;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// This function returns EXP if EXP is an ssa_name and is supported by ranges.
|
||||
// Otherwise it returns NULL_TREE
|
||||
|
||||
inline tree
|
||||
ssa_ranger::valid_ssa_p (tree exp)
|
||||
{
|
||||
if (exp && TREE_CODE (exp) == SSA_NAME && irange::supports_ssa_p (exp))
|
||||
return exp;
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
|
||||
#endif // GCC_SSA_RANGE_H
|
||||
|
@ -123,7 +123,7 @@ thread_ranger::range_of_stmt_edge (irange &r, gimple *g, edge e)
|
||||
irange range1, range2;
|
||||
|
||||
tree op = stmt->operand1 ();
|
||||
if (!valid_ssa_p (op) || !ssa_name_same_bb_p (op, bb) ||
|
||||
if (!valid_range_ssa_p (op) || !ssa_name_same_bb_p (op, bb) ||
|
||||
!range_of_stmt_edge (range1, SSA_NAME_DEF_STMT (op), e))
|
||||
if (!range_of_expr (range1, op))
|
||||
return false;
|
||||
@ -132,7 +132,7 @@ thread_ranger::range_of_stmt_edge (irange &r, gimple *g, edge e)
|
||||
if (!op)
|
||||
return stmt->fold (r, range1);
|
||||
|
||||
if (!valid_ssa_p (op) || !ssa_name_same_bb_p (op, bb) ||
|
||||
if (!valid_range_ssa_p (op) || !ssa_name_same_bb_p (op, bb) ||
|
||||
!range_of_stmt_edge (range2, SSA_NAME_DEF_STMT (op), e))
|
||||
if (!range_of_expr (range2, op))
|
||||
return false;
|
||||
|
Loading…
x
Reference in New Issue
Block a user