aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Macleod <amacleod@redhat.com>2019-09-04 11:42:20 +0000
committerAndrew Macleod <amacleod@redhat.com>2019-09-04 11:42:20 +0000
commitebb00f2f2a2ccfb8c5caa9c49aa11657105ae830 (patch)
tree6efbfca63de5ecde22eaaaaa68cb5d30dba3fecd
parent53b7cb68ecb4e9daf8236c51b80c6f934b13d43d (diff)
split ssa-ranger into stmt-ranger and cfg related stuff
move get_tree_range and have it return a ranger rather than a bool remove range_of_expr for edges, just use range_on_edge git-svn-id: https://gcc.gnu.org/svn/gcc/branches/ssa-range@275371 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/grange.cc50
-rw-r--r--gcc/grange.h9
-rw-r--r--gcc/ssa-range-cache.cc2
-rw-r--r--gcc/ssa-range-gori.cc158
-rw-r--r--gcc/ssa-range-gori.h11
-rw-r--r--gcc/ssa-range.cc442
-rw-r--r--gcc/ssa-range.h40
7 files changed, 349 insertions, 363 deletions
diff --git a/gcc/grange.cc b/gcc/grange.cc
index f700170b16e..65c1f897000 100644
--- a/gcc/grange.cc
+++ b/gcc/grange.cc
@@ -58,8 +58,56 @@ along with GCC; see the file COPYING3. If not see
// A table is indexed by tree-code which provides any neccessary code
// for implementing the IL specific work. It is modelled after the range op
// table where a class is implemented for a given tree code, and
-// auto-registered intot he table for use when it is encountered.
+// auto-registered into the table for use when it is encountered.
+// This function returns a range for tree node EXPR in R. Return
+// false if ranges are not supported.
+
+irange
+get_tree_range (tree expr)
+{
+ tree type;
+ if (TYPE_P (expr))
+ type = expr;
+ else
+ type = TREE_TYPE (expr);
+
+ gcc_checking_assert (irange::supports_type_p (type));
+
+ switch (TREE_CODE (expr))
+ {
+ case INTEGER_CST:
+ // If we encounter an overflow, simply punt and drop to varying
+ // since we have no idea how it will be used.
+ if (!TREE_OVERFLOW_P (expr))
+ return irange (expr, expr);
+ break;
+
+ case SSA_NAME:
+ if (irange::supports_ssa_p (expr) && SSA_NAME_RANGE_INFO (expr)
+ && !POINTER_TYPE_P (type))
+ {
+ // Return a range from an SSA_NAME's available range.
+ wide_int min, max;
+ enum value_range_kind kind = get_range_info (expr, &min, &max);
+ return irange (kind, type, min, max);
+ }
+ break;
+
+ case ADDR_EXPR:
+ {
+ // handle &var which can show up in phi arguments
+ bool ov;
+ if (tree_single_nonzero_warnv_p (expr, &ov))
+ return range_nonzero (type);
+ break;
+ }
+
+ default:
+ break;
+ }
+ return irange (type);
+}
static gimple *
calc_single_range (irange &r, gswitch *sw, edge e)
diff --git a/gcc/grange.h b/gcc/grange.h
index a83db7c4e89..fa115bec10c 100644
--- a/gcc/grange.h
+++ b/gcc/grange.h
@@ -27,6 +27,15 @@ along with GCC; see the file COPYING3. If not see
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);
+extern irange get_tree_range (tree expr);
+
+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;
+}
// Gimple statement which supports range_op operations.
// This can map to gimple assign or cond statements, so quick access to the
diff --git a/gcc/ssa-range-cache.cc b/gcc/ssa-range-cache.cc
index c7e364bbc8b..53af02bf039 100644
--- a/gcc/ssa-range-cache.cc
+++ b/gcc/ssa-range-cache.cc
@@ -578,7 +578,7 @@ gori_cache::edge_range (irange &r, edge e, tree name)
{
// Try to pick up any known value first.
if (!m_globals.get_global_range (r, name))
- r = range_from_ssa (name);
+ r = get_tree_range (name);
}
}
else
diff --git a/gcc/ssa-range-gori.cc b/gcc/ssa-range-gori.cc
index 334f349d3fa..8540fbab0e8 100644
--- a/gcc/ssa-range-gori.cc
+++ b/gcc/ssa-range-gori.cc
@@ -472,90 +472,17 @@ gori_map::dump(FILE *f)
}
}
-// Return a range from an SSA_NAME's available range. If there is no
-// available range, build a range for its entire domain.
-
-irange
-range_from_ssa (tree ssa)
-{
- tree type = TREE_TYPE (ssa);
- gcc_checking_assert (irange::supports_type_p (type));
- if (!SSA_NAME_RANGE_INFO (ssa) || POINTER_TYPE_P (type))
- return irange (type);
- wide_int min, max;
- enum value_range_kind kind = get_range_info (ssa, &min, &max);
- return irange (kind, type, min, max);
-}
-
-// This function returns a range for tree node EXPR in R. Return
-// false if ranges are not supported.
-
-bool
-get_tree_range (irange &r, tree expr)
-{
- tree type;
- switch (TREE_CODE (expr))
- {
- case INTEGER_CST:
- if (!TREE_OVERFLOW_P (expr))
- r = irange (expr, expr);
- else
- // If we encounter an overflow, simply punt and drop to varying
- // since we hvae no idea how it will be used.
- r.set_varying (TREE_TYPE (expr));
- return true;
-
- case SSA_NAME:
- if (irange::supports_ssa_p (expr))
- {
- r = range_from_ssa (expr);
- return true;
- }
- break;
-
- case ADDR_EXPR:
- {
- // handle &var which can show up in phi arguments
- bool ov;
- type = TREE_TYPE (expr);
- if (irange::supports_type_p (type))
- {
- if (tree_single_nonzero_warnv_p (expr, &ov))
- r = range_nonzero (type);
- else
- r.set_varying (type);
- return true;
- }
- break;
- }
-
- default:
- if (TYPE_P (expr))
- type = expr;
- else
- type = TREE_TYPE (expr);
- if (irange::supports_type_p (type))
- {
- // Set to range for this type.
- r.set_varying (type);
- return true;
- }
- break;
- }
- return false;
-}
-
// Same but perform substitution of NAME with RANGE_OF_NAME if expr
// happens to match it.
-static bool
-get_tree_range (irange &r, tree expr, tree name, irange *range_of_name)
+static irange
+get_tree_range (tree expr, tree name, irange *range_of_name)
{
if (expr != name || !range_of_name)
- return get_tree_range (r, expr);
+ return get_tree_range (expr);
- r = *range_of_name;
- return true;
+ gcc_checking_assert (range_of_name != NULL);
+ return *range_of_name;
}
// Calculate the range for NAME if the lhs of statement S has the range LHS.
@@ -579,31 +506,32 @@ compute_operand_range_on_stmt (irange &r, grange_op *s, const irange &lhs,
// The second parameter to a unary operation is the range for the type
// of operand1, but if it can be reduced further, the results will
// be better. Start with what we know of the range of OP1.
- if (get_tree_range (op1_range, op1, name, name_range))
- return s->calc_op1_irange (r, lhs, op1_range);
- else
- return s->calc_op1_irange (r, lhs);
+ op1_range = get_tree_range (op1, name, name_range);
+ return s->calc_op1_irange (r, lhs, op1_range);
}
// If we need the second operand, get a value and evaluate.
- if (get_tree_range (op2_range, op2, name, name_range))
- if (s->calc_op1_irange (r, lhs, op2_range))
- {
- // If op1 also has a range, intersect the 2 ranges.
- if (name_range)
- r.intersect (*name_range);
- return true;
- }
+ op2_range = get_tree_range (op2, name, name_range);
+ if (s->calc_op1_irange (r, lhs, op2_range))
+ {
+ // If op1 also has a range, intersect the 2 ranges.
+ if (name_range)
+ r.intersect (*name_range);
+ return true;
+ }
return false;
}
- if (op2 == name && get_tree_range (op1_range, op1, name, name_range))
- if (s->calc_op2_irange (r, lhs, op1_range))
- {
- // If op2 also has a range, intersect the 2 ranges.
- if (name_range)
- r.intersect (*name_range);
- return true;
- }
+ if (op2 == name)
+ {
+ op1_range = get_tree_range (op1, name, name_range);
+ if (s->calc_op2_irange (r, lhs, op1_range))
+ {
+ // If op2 also has a range, intersect the 2 ranges.
+ if (name_range)
+ r.intersect (*name_range);
+ return true;
+ }
+ }
return false;
}
@@ -624,7 +552,7 @@ compute_operand_range_on_stmt (irange &r, gimple *s, const irange &lhs,
{
if (gimple_switch_index (as_a<gswitch *>(s)) == name)
{
- gcc_assert (get_tree_range (r, name, name, name_range));
+ r = get_tree_range (name, name, name_range);
r.intersect (lhs);
return true;
}
@@ -933,7 +861,7 @@ gori_compute::compute_logical_operands (irange &r, grange_op *s,
else
{
// Otherwise just get the value for name in operand 1 position
- gcc_assert (get_tree_range (op1_true, name, name, name_range));
+ op1_true = get_tree_range (name, name, name_range);
op1_false = op1_true;
}
@@ -950,7 +878,7 @@ gori_compute::compute_logical_operands (irange &r, grange_op *s,
else
{
// Otherwise just get the value for name in operand 2 position
- gcc_assert (get_tree_range (op2_true, name, name, name_range));
+ op2_true = get_tree_range (name, name, name_range);
op2_false = op2_true;
}
}
@@ -978,8 +906,7 @@ gori_compute::compute_operand1_range (irange &r, grange_op *s,
tree op2 = s->operand2 ();
// Determine a known range for operand1 ().
- if (!get_tree_range (op1_range, op1, name, name_range))
- return false;
+ op1_range = get_tree_range (op1, name, name_range);
// Now calcuated the operand and put that result in r.
if (!op2)
@@ -992,8 +919,7 @@ gori_compute::compute_operand1_range (irange &r, grange_op *s,
}
else
{
- if (!get_tree_range (op2_range, op2, name, name_range))
- return false;
+ op2_range = get_tree_range (op2, name, name_range);
if (!s->calc_op1_irange (r, lhs, op2_range))
return false;
}
@@ -1022,16 +948,14 @@ gori_compute::compute_operand2_range (irange &r, grange_op *s,
tree op2 = s->operand2 ();
// Get a range for op1.
- if (!get_tree_range (op1_range, op1, name, name_range))
- return false;
+ op1_range = get_tree_range (op1, name, name_range);
// calculate the range for op2 based on lhs and op1.
if (!s->calc_op2_irange (op2_range, lhs, op1_range))
return false;
// Also pick up what is known about op2's range at this point
- if (!get_tree_range (r, op2, name, name_range))
- return false;
+ r = get_tree_range (op2, name, name_range);
// And intersect it with the calculated result.
op2_range.intersect (r);
@@ -1166,7 +1090,7 @@ bool
gori_compute::range_from_import (irange &r, tree name, irange &import_range)
{
irange r1, r2;
- bool res;
+ bool res = true;
tree import = terminal_name (name);
gcc_checking_assert
@@ -1199,15 +1123,12 @@ gori_compute::range_from_import (irange &r, tree name, irange &import_range)
if (valid_range_ssa_p (op1))
{
if (op1 == import)
- {
- res = true;
- r1 = import_range;
- }
+ r1 = import_range;
else
res = range_from_import (r1, op1, import_range);
}
else
- res = get_tree_range (r1, op1);
+ r1 = get_tree_range (op1);
if (!res)
return false;
@@ -1218,15 +1139,12 @@ gori_compute::range_from_import (irange &r, tree name, irange &import_range)
if (valid_range_ssa_p (op2))
{
if (op2 == import)
- {
- res = true;
- r2 = import_range;
- }
+ r2 = import_range;
else
res = range_from_import (r2, op2, import_range);
}
else
- res = get_tree_range (r2, op2);
+ r2 = get_tree_range (op2);
if (res)
return s->fold (r, r1, r2);
diff --git a/gcc/ssa-range-gori.h b/gcc/ssa-range-gori.h
index 91978b4ae2e..715d58977c5 100644
--- a/gcc/ssa-range-gori.h
+++ b/gcc/ssa-range-gori.h
@@ -186,15 +186,4 @@ private:
irange m_bool_one; /* Boolean true cached. */
};
-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
diff --git a/gcc/ssa-range.cc b/gcc/ssa-range.cc
index 7137194202e..a498329824f 100644
--- a/gcc/ssa-range.cc
+++ b/gcc/ssa-range.cc
@@ -55,13 +55,13 @@ along with GCC; see the file COPYING3. If not see
// Initialize a ranger.
-ssa_ranger::ssa_ranger ()
+stmt_ranger::stmt_ranger ()
{
}
// Destruct a ranger.
-ssa_ranger::~ssa_ranger ()
+stmt_ranger::~stmt_ranger ()
{
}
@@ -70,76 +70,19 @@ ssa_ranger::~ssa_ranger ()
// Return false if ranges are not supported.
bool
-ssa_ranger::range_of_expr (irange &r, tree expr, gimple *s ATTRIBUTE_UNUSED)
-{
- return get_tree_range (r, expr);
-}
-
-// Determine a range for OP on edge E, returning the result in R.
-
-bool
-ssa_ranger::range_of_expr (irange&r, tree op, edge e)
-{
- if (!irange::supports_p (op))
- return false;
- if (valid_range_ssa_p (op))
- {
- range_on_edge (r, e, op);
- return true;
- }
- // If it is not an SSA_NAME, just get the basic range.
- return get_tree_range (r, op);
-}
-
-// 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.
-
-bool
-ssa_ranger::outgoing_edge_range_p (irange &r, edge e, tree name,
- irange *name_range)
-{
- irange lhs;
-
- 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 there is no outgoing stmt, there is no range produced.
- if (!s)
- return false;
-
- // Otherwise use the outgoing edge as a LHS and try to calculate a range.
- return compute_operand_range_on_stmt (r, s, lhs, name, name_range);
-}
-
-// Calculate a range for NAME on edge E and return it in R.
-// if NAME is a PHI node at the dest of E, get the argument result.
-// Return false if no range can be determined.
-
-void
-ssa_ranger::range_on_edge (irange &r, edge e, tree name)
+stmt_ranger::range_of_expr (irange &r, tree expr, gimple *s ATTRIBUTE_UNUSED)
{
- irange edge_range;
- gcc_checking_assert (valid_range_ssa_p (name));
-
- range_on_exit (r, e->src, name);
- gcc_checking_assert (r.undefined_p ()
- || types_compatible_p (r.type(), TREE_TYPE (name)));
-
- // Check to see if NAME is defined on edge e.
- if (outgoing_edge_range_p (edge_range, e, name, &r))
- r = edge_range;
+ r = get_tree_range (expr);
+ return true;
}
-
// Calculate a range for statement S and return it in R. If NAME is provided it
// represents the SSA_NAME on the LHS of the statement. It is only required
// if there is more than one lhs/output. If a range cannot
// be calculated, return false.
bool
-ssa_ranger::range_of_stmt (irange &r, gimple *s, tree name)
+stmt_ranger::range_of_stmt (irange &r, gimple *s, tree name)
{
bool res = false;
// If name is specified, make sure it a LHS of S.
@@ -165,7 +108,7 @@ ssa_ranger::range_of_stmt (irange &r, gimple *s, tree name)
return true;
}
// We don't understand the stmt, so return the global range.
- r = range_from_ssa (name);
+ r = get_tree_range (name);
return true;
}
if (res)
@@ -184,7 +127,7 @@ ssa_ranger::range_of_stmt (irange &r, gimple *s, tree name)
// up. If a range cannot be calculated on this statement, return false.
bool
-ssa_ranger::range_of_stmt_with_range (irange &r, gimple *s, tree name,
+stmt_ranger::range_of_stmt_with_range (irange &r, gimple *s, tree name,
const irange &name_range)
{
if (is_a<grange_op *> (s))
@@ -199,65 +142,13 @@ ssa_ranger::range_of_stmt_with_range (irange &r, gimple *s, tree name,
return false;
}
-// Return the range for NAME on entry to basic block BB in R.
-// Return false if no range can be calculated.
-// Calculation is performed by unioning all the ranges on incoming edges.
-
-void
-ssa_ranger::range_on_entry (irange &r, basic_block bb, tree name)
-{
- edge_iterator ei;
- edge e;
- tree type = TREE_TYPE (name);
- irange pred_range;
-
- gcc_checking_assert (irange::supports_type_p (type));
-
- // Start with an empty range.
- r.set_undefined ();
-
- gcc_checking_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
-
- // Visit each predecessor to resolve them.
- FOR_EACH_EDGE (e, ei, bb->preds)
- {
- range_on_edge (pred_range, e, name);
- r.union_ (pred_range);
- // If varying is reach, stop processing.
- if (r.varying_p ())
- break;
- }
-}
-
-
-// Calculate the range for NAME at the end of block BB and return it in R.
-// Return false if no range can be calculated.
-
-void
-ssa_ranger::range_on_exit (irange &r, basic_block bb, tree name)
-{
- // on-exit from the exit block?
- gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
-
- gimple *s = last_stmt (bb);
- // If there is no statement in the block and this isnt the entry block,
- // go get the range_on_entry for this block.
- // For the entry block, a NULL stmt will return the global value for NAME.
- if (!s && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- range_on_entry (r, bb, name);
- else
- gcc_assert (range_of_expr (r, name, s));
- gcc_checking_assert (r.undefined_p ()
- || types_compatible_p (r.type(), TREE_TYPE (name)));
-}
-
// Calculate a range for range_op statement S given RANGE1 and RANGE2 and
// return it in R. If a range cannot be calculated, return false.
// If valid is false, then one or more of the ranges are invalid, and
// return false.
inline bool
-ssa_ranger::range_of_range_op_core (irange &r, grange_op *s, bool valid,
+stmt_ranger::range_of_range_op_core (irange &r, grange_op *s, bool valid,
irange &range1, irange &range2)
{
if (valid)
@@ -278,7 +169,7 @@ ssa_ranger::range_of_range_op_core (irange &r, grange_op *s, bool valid,
// cannot be calculated, return false.
bool
-ssa_ranger::range_of_range_op (irange &r, grange_op *s)
+stmt_ranger::range_of_range_op (irange &r, grange_op *s)
{
irange range1, range2;
bool res = true;
@@ -302,7 +193,7 @@ ssa_ranger::range_of_range_op (irange &r, grange_op *s)
// cannot be calculated, return false.
bool
-ssa_ranger::range_of_range_op (irange &r, grange_op *s, tree name,
+stmt_ranger::range_of_range_op (irange &r, grange_op *s, tree name,
const irange &name_range)
{
irange range1, range2;
@@ -335,7 +226,7 @@ ssa_ranger::range_of_range_op (irange &r, grange_op *s, tree name,
// cannot be calculated, return false.
bool
-ssa_ranger::range_of_range_op (irange &r, grange_op *s, gimple *eval_from)
+stmt_ranger::range_of_range_op (irange &r, grange_op *s, gimple *eval_from)
{
irange range1, range2;
bool res = true;
@@ -355,30 +246,6 @@ ssa_ranger::range_of_range_op (irange &r, grange_op *s, gimple *eval_from)
}
-// Calculate a range for range_op statement S and return it in R. Evaluate
-// the statement as if it were on edge EVAL_ON. If a range cannot be
-// calculated, return false.
-
-bool
-ssa_ranger::range_of_range_op (irange &r, grange_op *s, edge eval_on)
-{
- irange range1, range2;
- bool res = true;
- gcc_checking_assert (irange::supports_type_p (gimple_expr_type (s)));
-
- tree op1 = s->operand1 ();
- tree op2 = s->operand2 ();
-
- // Calculate a range for operand 1.
- res = range_of_expr (range1, op1, eval_on);
-
- // Calculate a result for op2 if it is needed.
- if (res && op2)
- res = range_of_expr (range2, op2, eval_on);
-
- return range_of_range_op_core (r, s, res, range1, range2);
-}
-
// Calculate a range for phi statement S and return it in R.
// If NAME is non-null, replace any occurences of NAME in arguments with
// NAME_RANGE.
@@ -388,7 +255,7 @@ ssa_ranger::range_of_range_op (irange &r, grange_op *s, edge eval_on)
// If a range cannot be calculated, return false.
bool
-ssa_ranger::range_of_phi (irange &r, gphi *phi, tree name,
+stmt_ranger::range_of_phi (irange &r, gphi *phi, tree name,
const irange *name_range, gimple *eval_from,
edge on_edge)
{
@@ -412,10 +279,7 @@ ssa_ranger::range_of_phi (irange &r, gphi *phi, tree name,
if (name == arg)
arg_range = *name_range;
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
- gcc_assert (range_of_expr (arg_range, arg, eval_from));
+ gcc_assert (range_of_expr (arg_range, arg, eval_from));
r.union_ (arg_range);
// Once the value reaches varying, stop looking.
@@ -435,7 +299,7 @@ ssa_ranger::range_of_phi (irange &r, gphi *phi, tree name,
// If a range cannot be calculated, return false.
bool
-ssa_ranger::range_of_call (irange &r, gcall *call, tree name ATTRIBUTE_UNUSED,
+stmt_ranger::range_of_call (irange &r, gcall *call, tree name ATTRIBUTE_UNUSED,
const irange *name_range ATTRIBUTE_UNUSED,
gimple *eval_from ATTRIBUTE_UNUSED,
edge on_edge ATTRIBUTE_UNUSED)
@@ -453,12 +317,18 @@ ssa_ranger::range_of_call (irange &r, gcall *call, tree name ATTRIBUTE_UNUSED,
return true;
}
-// Calculate a range for COND_EXPR statement S and return it in R. Evaluate
-// the stateemnt as if it occured on edge ON_EDGE.
-// If a range cannot be calculated, return false.
+
+
+// Calculate a range for COND_EXPR statement S and return it in R.
+// If NAME is non-null, replace any occurences of NAME in arguments with
+// NAME_RANGE.
+// If EVAL_FOM is non-null, evaluate the COND_EXPR as if it occured right
+// before EVAL_FROM.
+// If a range cannot be calculated, return false.
bool
-ssa_ranger::range_of_cond_expr (irange &r, gassign *s, edge on_edge)
+stmt_ranger::range_of_cond_expr (irange &r, gassign *s, tree name,
+ const irange *name_range, gimple *eval_from)
{
irange cond_range, range1, range2;
tree cond = gimple_assign_rhs1 (s);
@@ -471,9 +341,23 @@ ssa_ranger::range_of_cond_expr (irange &r, gassign *s, edge on_edge)
if (!irange::supports_type_p (TREE_TYPE (op1)))
return false;
- gcc_assert (range_of_expr (cond_range, cond, on_edge));
- gcc_assert (range_of_expr (range1, op1, on_edge));
- gcc_assert (range_of_expr (range2, op2, on_edge));
+ if (!eval_from)
+ eval_from = s;
+
+ if (name == cond)
+ cond_range = *name_range;
+ else
+ gcc_assert (range_of_expr (cond_range, cond, eval_from));
+
+ if (name == op1)
+ range1 = *name_range;
+ else
+ gcc_assert (range_of_expr (range1, op1, eval_from));
+
+ if (name == op2)
+ range2 = *name_range;
+ else
+ gcc_assert (range_of_expr (range2, op2, eval_from));
if (cond_range.singleton_p ())
{
@@ -488,16 +372,188 @@ ssa_ranger::range_of_cond_expr (irange &r, gassign *s, edge on_edge)
return true;
}
-// Calculate a range for COND_EXPR statement S and return it in R.
-// If NAME is non-null, replace any occurences of NAME in arguments with
-// NAME_RANGE.
-// If EVAL_FOM is non-null, evaluate the COND_EXPR as if it occured right
-// before EVAL_FROM.
-// If a range cannot be calculated, return false.
+
+// Initialize a CFG ranger.
+
+ssa_ranger::ssa_ranger ()
+{
+}
+
+// Destruct a ranger.
+
+ssa_ranger::~ssa_ranger ()
+{
+}
+
+
+// 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.
bool
-ssa_ranger::range_of_cond_expr (irange &r, gassign *s, tree name,
- const irange *name_range, gimple *eval_from)
+ssa_ranger::outgoing_edge_range_p (irange &r, edge e, tree name,
+ irange *name_range)
+{
+ irange lhs;
+
+ 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 there is no outgoing stmt, there is no range produced.
+ if (!s)
+ return false;
+
+ // Otherwise use the outgoing edge as a LHS and try to calculate a range.
+ return compute_operand_range_on_stmt (r, s, lhs, name, name_range);
+}
+
+// Calculate a range for NAME on edge E and return it in R.
+// if NAME is a PHI node at the dest of E, get the argument result.
+// Return false if no range can be determined.
+
+void
+ssa_ranger::range_on_edge (irange &r, edge e, tree name)
+{
+ irange edge_range;
+ gcc_checking_assert (irange::supports_p (name));
+
+ if (!valid_range_ssa_p (name))
+ {
+ r = get_tree_range (name);
+ return;
+ }
+ range_on_exit (r, e->src, name);
+ gcc_checking_assert (r.undefined_p ()
+ || types_compatible_p (r.type(), TREE_TYPE (name)));
+
+ // Check to see if NAME is defined on edge e.
+ if (outgoing_edge_range_p (edge_range, e, name, &r))
+ r = edge_range;
+}
+
+
+// Return the range for NAME on entry to basic block BB in R.
+// Return false if no range can be calculated.
+// Calculation is performed by unioning all the ranges on incoming edges.
+
+void
+ssa_ranger::range_on_entry (irange &r, basic_block bb, tree name)
+{
+ edge_iterator ei;
+ edge e;
+ tree type = TREE_TYPE (name);
+ irange pred_range;
+
+ gcc_checking_assert (irange::supports_type_p (type));
+
+ // Start with an empty range.
+ r.set_undefined ();
+
+ gcc_checking_assert (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun));
+
+ // Visit each predecessor to resolve them.
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ {
+ range_on_edge (pred_range, e, name);
+ r.union_ (pred_range);
+ // If varying is reach, stop processing.
+ if (r.varying_p ())
+ break;
+ }
+}
+
+
+// Calculate the range for NAME at the end of block BB and return it in R.
+// Return false if no range can be calculated.
+
+void
+ssa_ranger::range_on_exit (irange &r, basic_block bb, tree name)
+{
+ // on-exit from the exit block?
+ gcc_checking_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
+
+ gimple *s = last_stmt (bb);
+ // If there is no statement in the block and this isnt the entry block,
+ // go get the range_on_entry for this block.
+ // For the entry block, a NULL stmt will return the global value for NAME.
+ if (!s && bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
+ range_on_entry (r, bb, name);
+ else
+ gcc_assert (range_of_expr (r, name, s));
+ gcc_checking_assert (r.undefined_p ()
+ || types_compatible_p (r.type(), TREE_TYPE (name)));
+}
+
+// Calculate a range for range_op statement S and return it in R. Evaluate
+// the statement as if it were on edge EVAL_ON. If a range cannot be
+// calculated, return false.
+
+bool
+ssa_ranger::range_of_range_op (irange &r, grange_op *s, edge eval_on)
+{
+ irange range1, range2;
+ bool res = true;
+ gcc_checking_assert (irange::supports_type_p (gimple_expr_type (s)));
+
+ tree op1 = s->operand1 ();
+ tree op2 = s->operand2 ();
+
+ // Calculate a range for operand 1.
+ range_on_edge (range1, eval_on, op1);
+
+ // Calculate a result for op2 if it is needed.
+ if (op2)
+ range_on_edge (range2, eval_on, op2);
+
+ return range_of_range_op_core (r, s, res, range1, range2);
+}
+
+bool
+ssa_ranger::range_of_phi (irange &r, gphi *phi, tree name,
+ const irange *name_range, gimple *eval_from,
+ edge on_edge)
+{
+ tree phi_def = gimple_phi_result (phi);
+ tree type = TREE_TYPE (phi_def);
+ irange phi_range;
+ unsigned x;
+
+ if (!irange::supports_type_p (type))
+ return false;
+
+ // And start with an empty range, unioning in each argument's range.
+ r.set_undefined ();
+ for (x = 0; x < gimple_phi_num_args (phi); x++)
+ {
+ irange arg_range;
+ tree arg = gimple_phi_arg_def (phi, x);
+ edge e = gimple_phi_arg_edge (phi, x);
+ if (on_edge && e != on_edge)
+ continue;
+ if (name == arg)
+ arg_range = *name_range;
+ 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
+ gcc_assert (range_of_expr (arg_range, arg, eval_from));
+
+ r.union_ (arg_range);
+ // Once the value reaches varying, stop looking.
+ if (r.varying_p ())
+ break;
+ }
+
+ return true;
+}
+
+// Calculate a range for COND_EXPR statement S and return it in R. Evaluate
+// the stateemnt as if it occured on edge ON_EDGE.
+// If a range cannot be calculated, return false.
+
+bool
+ssa_ranger::range_of_cond_expr (irange &r, gassign *s, edge on_edge)
{
irange cond_range, range1, range2;
tree cond = gimple_assign_rhs1 (s);
@@ -510,23 +566,9 @@ ssa_ranger::range_of_cond_expr (irange &r, gassign *s, tree name,
if (!irange::supports_type_p (TREE_TYPE (op1)))
return false;
- if (!eval_from)
- eval_from = s;
-
- if (name == cond)
- cond_range = *name_range;
- else
- gcc_assert (range_of_expr (cond_range, cond, eval_from));
-
- if (name == op1)
- range1 = *name_range;
- else
- gcc_assert (range_of_expr (range1, op1, eval_from));
-
- if (name == op2)
- range2 = *name_range;
- else
- gcc_assert (range_of_expr (range2, op2, eval_from));
+ range_on_edge (cond_range, on_edge, cond);
+ range_on_edge (range1, on_edge, op1);
+ range_on_edge (range2, on_edge, op2);
if (cond_range.singleton_p ())
{
@@ -596,8 +638,7 @@ global_ranger::range_of_stmt (irange &r, gimple *s, tree name)
return true;
// Avoid infinite recursion by initializing global cache
- irange tmp;
- tmp = range_from_ssa (name);
+ irange tmp = get_tree_range (name);
m_gori.m_globals.set_global_range (name, tmp);
gcc_assert (ssa_ranger::range_of_stmt (r, s, name));
@@ -608,14 +649,6 @@ global_ranger::range_of_stmt (irange &r, gimple *s, tree name)
return true;
}
-// Return the range of expr OP on edge E in R.
-
-bool
-global_ranger::range_of_expr (irange &r, tree op, edge e)
-{
- return ssa_ranger::range_of_expr (r, op, e);
-}
-
// Determine a range for OP on stmt S, returning the result in R.
// If OP is not defined in BB, find the range on entry to this block.
@@ -697,7 +730,8 @@ global_ranger::export_global_ranges ()
!r.varying_p())
{
// Make sure the new range is a subset of the old range.
- irange old_range = range_from_ssa (name);
+ irange old_range;
+ old_range = get_tree_range (name);
old_range.intersect (r);
/* Disable this while we fix tree-ssa/pr61743-2.c. */
//gcc_checking_assert (old_range == r);
@@ -996,26 +1030,6 @@ trace_ranger::range_of_expr (irange &r, tree expr, gimple *s)
return trailer (idx, "range_of_expr", res, expr, r);
}
-// Tracing version of edge range_of_expr. Call it with printing wrappers.
-
-bool
-trace_ranger::range_of_expr (irange &r, tree expr, edge e)
-{
- bool res;
- unsigned idx = ++trace_count;
- if (dumping (idx))
- {
- fprintf (dump_file, "range_of_expr (");
- print_generic_expr (dump_file, expr, TDF_SLIM);
- fprintf (dump_file, ") on edge %d->%d\n", e->src->index, e->dest->index);
- indent += bump;
- }
-
- res = super::range_of_expr (r, expr, e);
-
- return trailer (idx, "range_of_expr", res, expr, r);
-}
-
// Tracing version of range_on_edge. Call it with printing wrappers.
void
diff --git a/gcc/ssa-range.h b/gcc/ssa-range.h
index 8a3ea8c6054..38a15a7fc92 100644
--- a/gcc/ssa-range.h
+++ b/gcc/ssa-range.h
@@ -41,25 +41,17 @@ along with GCC; see the file COPYING3. If not see
// outgoing_edge_range_p will only return a range if the edge specified
// defines a range for the specified name. Otherwise false is returned.
//
-
-class ssa_ranger
+//
+class stmt_ranger
{
public:
- ssa_ranger ();
- ~ssa_ranger ();
+ stmt_ranger ();
+ ~stmt_ranger ();
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);
virtual bool range_of_stmt_with_range (irange &r, gimple *s, tree name,
const irange &name_range);
- virtual void range_on_edge (irange &r, edge e, tree name);
- virtual void range_on_entry (irange &r, basic_block bb, tree name);
- virtual void range_on_exit (irange &r, basic_block bb, tree name);
-
- virtual bool outgoing_edge_range_p (irange &r, edge e, tree name,
- irange *name_range = NULL);
-
protected:
// Calculate a range for a kind of gimple statement .
bool range_of_range_op_core (irange &r, grange_op *s, bool valid,
@@ -68,7 +60,6 @@ protected:
bool range_of_range_op (irange &r, grange_op *s, tree name,
const irange &name_range);
bool range_of_range_op (irange &r, grange_op *s, gimple *eval_from);
- bool range_of_range_op (irange &r, grange_op *s, edge on_edge);
virtual bool range_of_phi (irange &r, gphi *phi, tree name = NULL_TREE,
const irange *name_range = NULL,
@@ -78,12 +69,31 @@ protected:
const irange *name_range = NULL,
gimple *eval_from = NULL, edge on_edge = NULL);
- bool range_of_cond_expr (irange &r, gassign* call, edge on_edge);
bool range_of_cond_expr (irange &r, gassign* call, tree name = NULL_TREE,
const irange *name_range = NULL,
gimple *eval_from = NULL);
};
+class ssa_ranger : public stmt_ranger
+{
+ public:
+ ssa_ranger ();
+ ~ssa_ranger ();
+ virtual void range_on_edge (irange &r, edge e, tree name);
+ virtual void range_on_entry (irange &r, basic_block bb, tree name);
+ virtual void range_on_exit (irange &r, basic_block bb, tree name);
+
+ virtual bool outgoing_edge_range_p (irange &r, edge e, tree name,
+ irange *name_range = NULL);
+
+protected:
+ bool range_of_cond_expr (irange &r, gassign* call, edge on_edge);
+ bool range_of_range_op (irange &r, grange_op *s, edge on_edge);
+ virtual bool range_of_phi (irange &r, gphi *phi, tree name = NULL_TREE,
+ const irange *name_range = NULL,
+ gimple *eval_from = NULL, edge on_edge = NULL);
+};
+
// This class utilizes the gori summary to query the range
// of SSA_NAMEs across multiple basic blocks and edges. It builds a cache
// of range on entry to blocks. All work is done on-demand so it is relatively
@@ -117,7 +127,6 @@ public:
~global_ranger ();
virtual bool range_of_expr (irange &r, tree op, 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);
virtual void range_on_entry (irange &r, basic_block bb, tree name);
@@ -159,7 +168,6 @@ public:
trace_ranger();
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);
virtual void range_on_edge (irange &r, edge e, tree name);
virtual void range_on_entry (irange &r, basic_block bb, tree name);