diff options
-rw-r--r-- | gcc/grange.cc | 50 | ||||
-rw-r--r-- | gcc/grange.h | 9 | ||||
-rw-r--r-- | gcc/ssa-range-cache.cc | 2 | ||||
-rw-r--r-- | gcc/ssa-range-gori.cc | 158 | ||||
-rw-r--r-- | gcc/ssa-range-gori.h | 11 | ||||
-rw-r--r-- | gcc/ssa-range.cc | 442 | ||||
-rw-r--r-- | gcc/ssa-range.h | 40 |
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); |