diff options
author | Andrew Macleod <amacleod@gcc.gnu.org> | 2018-04-11 21:16:31 +0000 |
---|---|---|
committer | Andrew Macleod <amacleod@gcc.gnu.org> | 2018-04-11 21:16:31 +0000 |
commit | 663eea09fa2afa008a06f41af6fad2c4230c86d5 (patch) | |
tree | 7f0bf150b66df37f7e1a7b418ec7cf480fd6d11f | |
parent | 57e7640ca39e7a63b5bca0bb890f127f5e3c058d (diff) |
make get_operand virtual, move logical and folding into stmt
From-SVN: r259332
-rw-r--r-- | gcc/ssa-range-bb.c | 112 | ||||
-rw-r--r-- | gcc/ssa-range-bb.h | 5 | ||||
-rw-r--r-- | gcc/ssa-range-stmt.c | 15 | ||||
-rw-r--r-- | gcc/ssa-range-stmt.h | 15 | ||||
-rw-r--r-- | gcc/ssa-range.c | 298 | ||||
-rw-r--r-- | gcc/ssa-range.h | 7 |
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, |