aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Macleod <amacleod@gcc.gnu.org>2018-04-11 21:16:31 +0000
committerAndrew Macleod <amacleod@gcc.gnu.org>2018-04-11 21:16:31 +0000
commit663eea09fa2afa008a06f41af6fad2c4230c86d5 (patch)
tree7f0bf150b66df37f7e1a7b418ec7cf480fd6d11f
parent57e7640ca39e7a63b5bca0bb890f127f5e3c058d (diff)
make get_operand virtual, move logical and folding into stmt
From-SVN: r259332
-rw-r--r--gcc/ssa-range-bb.c112
-rw-r--r--gcc/ssa-range-bb.h5
-rw-r--r--gcc/ssa-range-stmt.c15
-rw-r--r--gcc/ssa-range-stmt.h15
-rw-r--r--gcc/ssa-range.c298
-rw-r--r--gcc/ssa-range.h7
6 files changed, 228 insertions, 224 deletions
diff --git a/gcc/ssa-range-bb.c b/gcc/ssa-range-bb.c
index bafee0f817b..c9408ae4f65 100644
--- a/gcc/ssa-range-bb.c
+++ b/gcc/ssa-range-bb.c
@@ -349,10 +349,38 @@ block_ranger::~block_ranger ()
delete gori;
}
+
+// Internally, the range operators all use boolen_type_node when comparisons
+// and such are made to create ranges for logical operations.
+// some languages, such as fortran, may use boolean types with different
+// precisions and these are incompatible. This routine will look at the
+// 2 ranges, and if there is a mismatch between the boolean types, will change
+// the range generated from the default node to the other type.
+//
+void
+block_ranger::normalize_bool_type (irange& r1, irange& r2)
+{
+ const_tree t1 = r1.get_type ();
+ const_tree t2 = r2.get_type ();
+ if (TREE_CODE (t1) != BOOLEAN_TYPE || TREE_CODE (t2) != BOOLEAN_TYPE)
+ return;
+
+ if (t1 == t2)
+ return;
+
+ /* If neither is boolean_type_node, assume they are compatible. */
+ if (t1 == boolean_type_node)
+ r1.cast (t2);
+ else
+ if (t2 == boolean_type_node)
+ r2.cast (t1);
+}
+
/* This routine will return what is globally known about the range for an
operand of any kind. */
bool
-block_ranger::get_operand_range (irange& r, tree op)
+block_ranger::get_operand_range (irange& r, tree op,
+ gimple *s ATTRIBUTE_UNUSED)
{
/* This check allows unary operations to be handled without having to
make an explicit check for the existence of a second operand. */
@@ -412,8 +440,8 @@ block_ranger::process_logical (range_stmt stmt, irange& r, tree name,
}
else
{
- ret = get_operand_range (op1_true, name);
- ret &= get_operand_range (op1_false, name);
+ ret = get_operand_range (op1_true, name, stmt);
+ ret &= get_operand_range (op1_false, name, stmt);
}
/* If operand1 evaluated OK, move on to operand 2. */
@@ -428,8 +456,8 @@ block_ranger::process_logical (range_stmt stmt, irange& r, tree name,
}
else
{
- ret &= get_operand_range (op2_true, name);
- ret &= get_operand_range (op2_false, name);
+ ret &= get_operand_range (op2_true, name, stmt);
+ ret &= get_operand_range (op2_false, name, stmt);
}
}
@@ -446,7 +474,7 @@ bool
block_ranger::get_range_from_stmt (range_stmt stmt, irange& r, tree name,
const irange& lhs)
{
- irange op1_range, op2_range;
+ irange op1_range, op2_range, tmp_range;
tree op1, op2;
bool op1_in_chain, op2_in_chain;
@@ -466,7 +494,7 @@ block_ranger::get_range_from_stmt (range_stmt stmt, irange& r, tree name,
{
if (!op2)
return stmt.op1_irange (r, lhs);
- if (get_operand_range (op2_range, op2))
+ if (get_operand_range (op2_range, op2, stmt))
return stmt.op1_irange (r, lhs, op2_range);
else
return false;
@@ -474,7 +502,7 @@ block_ranger::get_range_from_stmt (range_stmt stmt, irange& r, tree name,
if (op2 == name)
{
- if (get_operand_range (op1_range, op1))
+ if (get_operand_range (op1_range, op1, stmt))
return stmt.op2_irange (r, lhs, op1_range);
else
return false;
@@ -493,51 +521,59 @@ block_ranger::get_range_from_stmt (range_stmt stmt, irange& r, tree name,
if (!op1_in_chain && !op2_in_chain)
return false;
+ /* Pick up an operand range for each argument. */
+ if (!get_operand_range (op1_range, op1, stmt))
+ return false;
+ if (op2 && !get_operand_range (op2_range, op2, stmt))
+ return false;
+
/* Can't resolve both sides at once, so take a guess at operand 1, calculate
operand 2 and check if the guess at operand 1 was good. */
if (op1_in_chain && op2_in_chain)
{
- irange tmp_op1_range;
- if (!get_operand_range (tmp_op1_range, op1))
- return false;
- if (!stmt.op2_irange (op2_range, lhs, tmp_op1_range))
+ // Get an op2_range based on the op1 range.
+ if (!stmt.op2_irange (tmp_range, lhs, op1_range))
return false;
+ // And combine it with the raw possibilty.
+ normalize_bool_type (op2_range, tmp_range);
+ op2_range.intersect (tmp_range);
if (!get_range_from_stmt (SSA_NAME_DEF_STMT (op2), r, name, op2_range))
return false;
- if (!stmt.op1_irange (op1_range, lhs, op2_range))
+
+ // Now the same for operand 1
+ if (!stmt.op1_irange (tmp_range, lhs, op2_range))
return false;
+ normalize_bool_type (op1_range, tmp_range);
+ op1_range.intersect (tmp_range);
if (!get_range_from_stmt (SSA_NAME_DEF_STMT (op1), r, name, op1_range))
return false;
-
- /* If the guess is good, we're done. */
- if (op1_range == tmp_op1_range)
- return true;
- /* Otherwise fall thru and calculate op2_range with this range. */
+ // Do we need to possibly reevaluate op2?
+ return true;
}
else
if (op1_in_chain)
{
if (!op2)
{
- if (!stmt.op1_irange (op1_range, lhs))
+ if (!stmt.op1_irange (tmp_range, lhs))
return false;
}
else
{
- if (!get_operand_range (op2_range, op2))
- return false;
- if (!stmt.op1_irange (op1_range, lhs, op2_range))
+ if (!stmt.op1_irange (tmp_range, lhs, op2_range))
return false;
}
+ normalize_bool_type (op1_range, tmp_range);
+ op1_range.intersect (tmp_range);
return get_range_from_stmt (SSA_NAME_DEF_STMT (op1), r, name,
op1_range);
}
else
- if (!get_operand_range (op1_range, op1))
- return false;
- if (!stmt.op2_irange (op2_range, lhs, op1_range))
+ if (!stmt.op2_irange (tmp_range, lhs, op1_range))
return false;
+ normalize_bool_type (op2_range, tmp_range);
+ op2_range.intersect (tmp_range);
return get_range_from_stmt (SSA_NAME_DEF_STMT (op2), r, name, op2_range);
}
@@ -694,32 +730,6 @@ block_ranger::exercise (FILE *output)
}
-
-bool
-block_ranger::range_on_stmt (irange& r, tree name, gimple *g)
-{
- range_stmt rn (g);
- irange lhs;
-
- /* If we don't understand the stmt... */
- if (!rn.valid())
- return false;
-
- /* If neither operand is what we are looking for, then return nothing. */
- if (rn.operand1 () != name && rn.operand2 () != name)
- return false;
-
- /* Only works if there is a LHS. */
- if (!gimple_get_lhs (g))
- return false;
-
- if (get_operand_range (lhs, gimple_get_lhs (g)))
- return get_range_from_stmt (rn, r, name, lhs);
-
- return false;
-}
-
-
/* Attempt to evaluate the epression using whatever is globally known about
the operands. If it can be evaluated, TRUE is returned
and the range is returned in R. */
diff --git a/gcc/ssa-range-bb.h b/gcc/ssa-range-bb.h
index e4895566f78..81e71c3513a 100644
--- a/gcc/ssa-range-bb.h
+++ b/gcc/ssa-range-bb.h
@@ -39,7 +39,8 @@ class block_ranger
bool get_range_from_stmt (range_stmt stmt, irange& r, tree name,
const irange& lhs);
protected:
- bool get_operand_range (irange& r, tree op);
+ virtual bool get_operand_range (irange& r, tree op, gimple *s = NULL);
+ void normalize_bool_type (irange& r1, irange& r2);
public:
block_ranger ();
~block_ranger ();
@@ -48,8 +49,6 @@ public:
bool range_p (basic_block bb, tree name);
/* What is the static calculated range of NAME on outgoing edge E. */
bool range_on_edge (irange& r, tree name, edge e);
- /* What range does NAME have on entry to statement g. */
- bool range_on_stmt (irange& r, tree name, gimple *g);
/* What infomation does stmt g provide about the lhs. */
bool range_of_def (irange& r, gimple *g);
/* What does g provide about the lhs if NAME has RANGE_FOR_NAME. */
diff --git a/gcc/ssa-range-stmt.c b/gcc/ssa-range-stmt.c
index 3e6eccf2947..7a4e0ce885a 100644
--- a/gcc/ssa-range-stmt.c
+++ b/gcc/ssa-range-stmt.c
@@ -235,6 +235,11 @@ bool
range_stmt::op1_irange (irange& r, const irange& lhs_range) const
{
irange type_range;
+ if (lhs_range.empty_p ())
+ {
+ r.clear (TREE_TYPE (operand1 ()));
+ return true;
+ }
type_range.set_range_for_type (TREE_TYPE (operand1 ()));
return handler ()->op1_irange (r, lhs_range, type_range);
}
@@ -248,6 +253,11 @@ range_stmt::op1_irange (irange& r, const irange& lhs_range,
const irange& op2_range) const
{
gcc_assert (operand2 () != NULL);
+ if (op2_range.empty_p () || lhs_range.empty_p ())
+ {
+ r.clear (op2_range.get_type ());
+ return true;
+ }
return handler ()->op1_irange (r, lhs_range, op2_range);
}
@@ -259,6 +269,11 @@ bool
range_stmt::op2_irange (irange& r, const irange& lhs_range,
const irange& op1_range) const
{
+ if (op1_range.empty_p () || lhs_range.empty_p ())
+ {
+ r.clear (op1_range.get_type ());
+ return true;
+ }
return handler ()->op2_irange (r, lhs_range, op1_range);
}
diff --git a/gcc/ssa-range-stmt.h b/gcc/ssa-range-stmt.h
index e0d9bf78906..dc8b1a338ad 100644
--- a/gcc/ssa-range-stmt.h
+++ b/gcc/ssa-range-stmt.h
@@ -43,30 +43,30 @@ private:
gimple *g;
void validate_stmt (gimple *s);
class irange_operator *handler() const;
+ tree_code get_code () const;
public:
range_stmt ();
range_stmt (gimple *stmt);
range_stmt &operator= (gimple *stmt);
bool valid () const;
- tree_code get_code () const;
+ operator gimple *() const;
tree operand1 () const;
tree operand2 () const;
-
tree ssa_operand1 () const;
tree ssa_operand2 () const;
- bool logical_expr_p () const;
-
bool fold (irange& res, const irange& r1) const;
- bool fold (irange& res, const irange& r1, const irange& r2) const;
bool op1_irange (irange& r, const irange& lhs_range) const;
+
+ bool fold (irange& res, const irange& r1, const irange& r2) const;
bool op1_irange (irange& r, const irange& lhs_range,
const irange& op2_range) const;
bool op2_irange (irange& r, const irange& lhs_range,
const irange& op1_range) const;
+ bool logical_expr_p () const;
bool fold_logical (irange& r, const irange& lhs, const irange& op1_true,
const irange& op1_false, const irange& op2_true,
const irange& op2_false) const;
@@ -167,4 +167,9 @@ range_stmt::handler () const
return irange_op_handler (get_code ());
}
+inline
+range_stmt::operator gimple *() const
+{
+ return g;
+}
#endif /* GCC_SSA_RANGE_STMT_H */
diff --git a/gcc/ssa-range.c b/gcc/ssa-range.c
index 7a63089d0d3..61aa0c6d6ac 100644
--- a/gcc/ssa-range.c
+++ b/gcc/ssa-range.c
@@ -48,33 +48,6 @@ along with GCC; see the file COPYING3. If not see
#include "ssa-range-global.h"
-// Internally, the range operators all use boolen_type_node when comparisons
-// and such are made to create ranges for logical operations.
-// some languages, such as fortran, may use boolean types with different
-// precisions and these are incompatible. This routine will look at the
-// 2 ranges, and if there is a mismatch between the boolean types, will change
-// the range generated from the default node to the other type.
-//
-static void
-normalize_bool_type (irange& r1, irange& r2)
-{
- const_tree t1 = r1.get_type ();
- const_tree t2 = r2.get_type ();
- if (TREE_CODE (t1) != BOOLEAN_TYPE || TREE_CODE (t2) != BOOLEAN_TYPE)
- return;
-
- if (t1 == t2)
- return;
-
- /* If neither is boolean_type_node, assume they are compatible. */
- if (t1 == boolean_type_node)
- r1.cast (t2);
- else
- if (t2 == boolean_type_node)
- r2.cast (t1);
-}
-
-
class ssa_block_ranges
{
private:
@@ -416,12 +389,6 @@ path_ranger::process_phi (irange &r, gphi *phi)
return true;
}
-bool
-path_ranger::path_range_stmt (irange& r, tree name, gimple *g)
-{
- return path_get_operand (r, name, gimple_bb (g));
-}
-
bool
path_ranger::path_range_stmt (irange& r, gimple *g)
@@ -511,15 +478,24 @@ path_ranger::path_get_operand (irange &r, tree name, basic_block bb)
// This means NAME is defined in the same block, simply try to extract
// a range from that statement.
if (!path_range_stmt (r, s))
- return get_operand_range (r, name);
+ return block_ranger::get_operand_range (r, name);
return true;
}
if (path_range_entry (r, name, bb))
return true;
- return get_operand_range (r, name);
+ return block_ranger::get_operand_range (r, name);
}
+bool
+path_ranger::get_operand_range (irange&r, tree op, gimple *s)
+{
+
+ if (!s)
+ return block_ranger::get_operand_range (r, op, s);
+ else
+ return path_get_operand (r, op, gimple_bb (s));
+}
bool
path_ranger::path_fold_stmt (irange &r, range_stmt &rn, basic_block bb, edge e)
@@ -570,145 +546,145 @@ path_ranger::path_range_of_def (irange &r, gimple *g, edge e)
gcc_assert (e->dest == bb);
arg = gimple_phi_arg_def (phi, e->dest_idx);
// Pick up anything simple we might know about the incoming edge.
- if (!range_on_edge (r, arg, e))
- return get_operand_range (r, arg);
- return true;
- }
-
- range_stmt rn(g);
- if (!rn.valid())
- return false;
- return path_fold_stmt (r, rn, bb, e);
-
-}
+ if (!range_on_edge (r, arg, e))
+ return get_operand_range (r, arg);
+ return true;
+ }
-// Attempt to evaluate NAME within the basic block it is defined as far
-// as possible. IF a PHI is encountered at the beginning of the block, either
-// fully evalaute it, or if E is provided, use just the value from that edge.
-bool
-path_ranger::path_range_of_def (irange &r, gimple *g)
-{
- tree name;
- basic_block bb = gimple_bb (g);
- tree arg;
- irange range_op1, range_op2;
+ range_stmt rn(g);
+ if (!rn.valid())
+ return false;
+ return path_fold_stmt (r, rn, bb, e);
+
+ }
+
+ // Attempt to evaluate NAME within the basic block it is defined as far
+ // as possible. IF a PHI is encountered at the beginning of the block, either
+ // fully evalaute it, or if E is provided, use just the value from that edge.
+ bool
+ path_ranger::path_range_of_def (irange &r, gimple *g)
+ {
+ tree name;
+ basic_block bb = gimple_bb (g);
+ tree arg;
+ irange range_op1, range_op2;
+
+ // Note that since we are remaining within BB, we do not attempt to further
+ // evaluate any of the arguments of a PHI at this point.
+ // a recursive call could be made to evaluate any SSA_NAMEs on their
+ // repsective edgesin PATH form, but we leave that as something to look into
+ // later. For the moment, just pick up any edge information since its cheap.
+ if (is_a <gphi *> (g))
+ {
+ gphi *phi = as_a <gphi *> (g);
+ tree phi_def = gimple_phi_result (phi);
+ irange tmp;
+ unsigned x;
+ edge e;
- // Note that since we are remaining within BB, we do not attempt to further
- // evaluate any of the arguments of a PHI at this point.
- // a recursive call could be made to evaluate any SSA_NAMEs on their
- // repsective edgesin PATH form, but we leave that as something to look into
- // later. For the moment, just pick up any edge information since its cheap.
- if (is_a <gphi *> (g))
- {
- gphi *phi = as_a <gphi *> (g);
- tree phi_def = gimple_phi_result (phi);
- irange tmp;
- unsigned x;
- edge e;
+ if (!valid_irange_ssa (phi_def))
+ return false;
+ if (get_global_ssa_range (r, phi_def))
+ return true;
+
+ // Avoid infinite recursion by initializing global cache
+ r.set_range (phi_def);
+ set_global_ssa_range (phi_def, r);
+
+ r.clear (TREE_TYPE (phi_def));
+ for (x = 0; x < gimple_phi_num_args (phi); x++)
+ {
+ arg = gimple_phi_arg_def (phi, x);
+ e = gimple_phi_arg_edge (phi, x);
+ if (!path_range_edge (range_op2, arg, e))
+ if (!get_operand_range (range_op2, arg))
+ return false;
+
+ normalize_bool_type (r, range_op2);
+ r.union_ (range_op2);
+ if (r.range_for_type_p ())
+ return true;
+ }
+
+ set_global_ssa_range (phi_def, r);
+ return true;
+ }
- if (!valid_irange_ssa (phi_def))
- return false;
- if (get_global_ssa_range (r, phi_def))
- return true;
+ range_stmt rn(g);
+ if (!rn.valid())
+ return false;
- // Avoid infinite recursion by initializing global cache
- r.set_range (phi_def);
- set_global_ssa_range (phi_def, r);
+ name = gimple_get_lhs (g);
- r.clear (TREE_TYPE (phi_def));
- for (x = 0; x < gimple_phi_num_args (phi); x++)
- {
- arg = gimple_phi_arg_def (phi, x);
- e = gimple_phi_arg_edge (phi, x);
- if (!path_range_edge (range_op2, arg, e))
- if (!get_operand_range (range_op2, arg))
- return false;
-
- normalize_bool_type (r, range_op2);
- r.union_ (range_op2);
- if (r.range_for_type_p ())
- return true;
- }
+ /* If there is no LHS, then we are simply folding an expression. */
+ if (!name)
+ return path_fold_stmt (r, rn, bb);
- set_global_ssa_range (phi_def, r);
+ if (get_global_ssa_range (r, name))
return true;
- }
- range_stmt rn(g);
- if (!rn.valid())
- return false;
-
- name = gimple_get_lhs (g);
-
- /* If there is no LHS, then we are simply folding an expression. */
- if (!name)
- return path_fold_stmt (r, rn, bb);
-
- if (get_global_ssa_range (r, name))
- return true;
-
- // avoid infinite recursion by initializing global cache
- r.set_range (name);
- set_global_ssa_range (name, r);
-
- bool res = path_fold_stmt (r, rn, bb);
-
- if (res)
+ // avoid infinite recursion by initializing global cache
+ r.set_range (name);
set_global_ssa_range (name, r);
- return res;
-}
-
-/* Calculate the known range for NAME on a path of basic blocks in
- BBS. If such a range exists, store it in R and return TRUE,
- otherwise return FALSE.
-
- DIR is FORWARD if BBS[0] is the definition and the last block is
- the use. DIR is REVERSE if the blocks are in reverse order.
- If there is an edge leading into this path that we'd like to take
- into account, such edge is START_EDGE. Otherwise, START_EDGE is
- set to NULL. */
+ bool res = path_fold_stmt (r, rn, bb);
-bool
-path_ranger::path_range (irange &r, tree name, const vec<basic_block> &bbs,
- enum path_range_direction dir, edge start_edge)
-{
- if (bbs.is_empty ())
- return false;
-
- /* If the first block defines NAME and it has meaningful range
- information, use it, otherwise fall back to range for type.
-
- Note: The first block may not always define NAME because we may
- have pruned the paths such that the first block (bb1) is just the
- first block that contains range info (bb99). For example:
-
- bb1:
- x = 55;
- ...
- ...
- bb99:
- if (x > blah).
- */
- basic_block first_bb = dir == FORWARD ? bbs[0] : bbs[bbs.length () - 1];
- gimple *def_stmt = SSA_NAME_DEF_STMT (name);
- if (gimple_bb (def_stmt) == first_bb && start_edge)
- {
- if (!path_range_of_def (r, def_stmt, start_edge))
- get_global_ssa_range (r, name);
- }
- else
- get_global_ssa_range (r, name);
+ if (res)
+ set_global_ssa_range (name, r);
+ return res;
+ }
+
+ /* Calculate the known range for NAME on a path of basic blocks in
+ BBS. If such a range exists, store it in R and return TRUE,
+ otherwise return FALSE.
+
+ DIR is FORWARD if BBS[0] is the definition and the last block is
+ the use. DIR is REVERSE if the blocks are in reverse order.
+
+ If there is an edge leading into this path that we'd like to take
+ into account, such edge is START_EDGE. Otherwise, START_EDGE is
+ set to NULL. */
+
+ bool
+ path_ranger::path_range (irange &r, tree name, const vec<basic_block> &bbs,
+ enum path_range_direction dir, edge start_edge)
+ {
+ if (bbs.is_empty ())
+ return false;
+
+ /* If the first block defines NAME and it has meaningful range
+ information, use it, otherwise fall back to range for type.
+
+ Note: The first block may not always define NAME because we may
+ have pruned the paths such that the first block (bb1) is just the
+ first block that contains range info (bb99). For example:
+
+ bb1:
+ x = 55;
+ ...
+ ...
+ bb99:
+ if (x > blah).
+ */
+ basic_block first_bb = dir == FORWARD ? bbs[0] : bbs[bbs.length () - 1];
+ gimple *def_stmt = SSA_NAME_DEF_STMT (name);
+ if (gimple_bb (def_stmt) == first_bb && start_edge)
+ {
+ if (!path_range_of_def (r, def_stmt, start_edge))
+ get_global_ssa_range (r, name);
+ }
+ else
+ get_global_ssa_range (r, name);
- if (dir == REVERSE)
- return path_range_reverse (r, name, bbs);
+ if (dir == REVERSE)
+ return path_range_reverse (r, name, bbs);
- for (unsigned i = 1; i < bbs.length (); ++i)
- {
- edge e = find_edge (bbs[i - 1], bbs[i]);
- gcc_assert (e);
- irange redge;
- if (range_on_edge (redge, name, e))
+ for (unsigned i = 1; i < bbs.length (); ++i)
+ {
+ edge e = find_edge (bbs[i - 1], bbs[i]);
+ gcc_assert (e);
+ irange redge;
+ if (range_on_edge (redge, name, e))
r.intersect (redge);
}
diff --git a/gcc/ssa-range.h b/gcc/ssa-range.h
index 98fb5801376..f505311f928 100644
--- a/gcc/ssa-range.h
+++ b/gcc/ssa-range.h
@@ -37,7 +37,8 @@ private:
edge e = NULL);
bool process_phi (irange &r, gphi *phi);
bool path_get_operand (irange &r, tree name, basic_block bb);
-
+protected:
+ virtual bool get_operand_range (irange &r, tree op, gimple *s = NULL);
public:
enum path_range_direction { FORWARD, REVERSE };
path_ranger ();
@@ -46,9 +47,7 @@ public:
/* What is the known range of name from its DEF point to edge E. */
bool path_range_edge (irange& r, tree name, edge e);
bool path_range_entry (irange& r, tree name, basic_block bb);
- // Specifying NAME give the range of NAME before G is executed.
- bool path_range_stmt (irange& r, tree name, gimple *g);
- // no NAME, give the range of the LHS of the statement.
+ // Get ive the range of the LHS of the statement.
bool path_range_stmt (irange& r, gimple *g);
bool path_range (irange &r, tree name, const vec<basic_block> &bbs,