| /* SSA range GORI functions. |
| Copyright (C) 2017-2018 Free Software Foundation, Inc. |
| Contributed by Andrew MacLeod <amacleod@redhat.com>. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 3, or (at your option) |
| any later version. |
| |
| GCC is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "backend.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "ssa.h" |
| #include "gimple-pretty-print.h" |
| #include "diagnostic-core.h" |
| #include "wide-int.h" |
| #include "grange.h" |
| #include "ssa-range-gori.h" |
| #include "fold-const.h" |
| #include "ssa-range.h" |
| |
| // Construct a range_def_chain |
| |
| range_def_chain::range_def_chain () |
| { |
| m_def_chain.create (0); |
| m_def_chain.safe_grow_cleared (num_ssa_names); |
| m_terminal.create (0); |
| m_terminal.safe_grow_cleared (num_ssa_names); |
| } |
| |
| // Destruct a range_def_chain |
| |
| range_def_chain::~range_def_chain () |
| { |
| unsigned x; |
| for (x = 0; x < m_def_chain.length (); ++x) |
| if (m_def_chain[x]) |
| BITMAP_FREE (m_def_chain[x]); |
| m_def_chain.release (); |
| m_terminal.release (); |
| } |
| |
| // Return true if NAME is in the def chain of DEF. If BB is provided, only |
| // return true if the defining statement of DEF is in BB. |
| |
| bool |
| range_def_chain::in_chain_p (tree name, tree def) |
| { |
| gcc_checking_assert (valid_range_ssa_p (def)); |
| gcc_checking_assert (valid_range_ssa_p (name)); |
| |
| // Get the defintion chain for DEF |
| bitmap chain = get_def_chain (def); |
| |
| if (chain == NULL) |
| return false; |
| return bitmap_bit_p (chain, SSA_NAME_VERSION (name)); |
| } |
| |
| // If NAME has a definition chain, and the chain has a single import into |
| // the block, return the name of that import. |
| |
| tree |
| range_def_chain::terminal_name (tree name) |
| { |
| // Ensure the def chain has been calculated. |
| get_def_chain (name); |
| return m_terminal[SSA_NAME_VERSION (name)]; |
| } |
| |
| // Given up to 3 ssa names, return the common name or NULL_TREE. NULL_TREE's |
| // passed in can be ignored, but all specified ssa-names must be the same name. |
| |
| static inline tree |
| pick_import (tree ssa1, tree ssa2, tree ssa3) |
| { |
| if (ssa1) |
| { |
| if (ssa2 && ssa1 != ssa2) |
| return NULL_TREE; // No match. |
| // Either ssa2 is NULL, or it is the same as ssa1. |
| if (!ssa3 || ssa1 == ssa3) |
| return ssa1; // ssa1 is the import. |
| return NULL_TREE; |
| } |
| if (ssa2) |
| { |
| // If there is no ssa3 or ssa3 is the same as ssa2, thats the import. |
| if (!ssa3 || ssa2 == ssa3) |
| return ssa2; |
| // They must both be different, so no import. |
| return NULL_TREE; |
| } |
| return ssa3; |
| } |
| |
| // Build def_chains for NAME if it is in BB.. copy the def chain into RESULT. |
| // Return the import for name, or NAME if it is an import. |
| |
| tree |
| range_def_chain::build_def_chain (tree name, bitmap result, basic_block bb) |
| { |
| bitmap b; |
| gimple *def_stmt = SSA_NAME_DEF_STMT (name); |
| // Add this operand into the result. |
| bitmap_set_bit (result, SSA_NAME_VERSION (name)); |
| |
| if (gimple_bb (def_stmt) == bb && !is_a<gphi *>(def_stmt)) |
| { |
| // Get the def chain for the operand |
| b = get_def_chain (name); |
| // If there was one, copy it into result and retuirn the terminal name. |
| if (b) |
| { |
| bitmap_ior_into (result, b); |
| return m_terminal [SSA_NAME_VERSION (name)]; |
| } |
| // If there is no def chain, this terminal is within the same BB. |
| } |
| return name; // This is an import. |
| } |
| |
| // Return TRUE if NAME has been processed for a def_chain. |
| |
| inline bool |
| range_def_chain::has_def_chain (tree name) |
| { |
| unsigned v = SSA_NAME_VERSION (name); |
| if (v >= m_def_chain.length ()) |
| { |
| m_def_chain.safe_grow_cleared (num_ssa_names + 1); |
| m_terminal.safe_grow_cleared (num_ssa_names + 1); |
| } |
| return (m_def_chain[v] != NULL); |
| } |
| |
| // Calculate the def chain for NAME and all of its dependent operands. Only |
| // using names in the same BB. Return the bitmap of all names in the |
| // m_def_chain. This only works for supported range statements. |
| |
| bitmap |
| range_def_chain::get_def_chain (tree name) |
| { |
| tree ssa1, ssa2, ssa3; |
| unsigned v = SSA_NAME_VERSION (name); |
| |
| // If it has already been processed, just return the cached value. |
| if (has_def_chain (name)) |
| return m_def_chain[v]; |
| |
| // No definition chain for default defs. |
| if (SSA_NAME_IS_DEFAULT_DEF (name)) |
| return NULL; |
| |
| gimple *s = SSA_NAME_DEF_STMT (name); |
| if (is_a<grange *> (s)) |
| { |
| grange *stmt = as_a<grange *> (s); |
| ssa1 = valid_range_ssa_p (gimple_range_operand1 (stmt)); |
| ssa2 = valid_range_ssa_p (gimple_range_operand2 (stmt)); |
| ssa3 = NULL_TREE; |
| } |
| else if (is_a<gassign *> (s) && gimple_assign_rhs_code (s) == COND_EXPR) |
| { |
| gassign *st = as_a<gassign *> (s); |
| ssa1 = valid_range_ssa_p (gimple_assign_rhs1 (st)); |
| ssa2 = valid_range_ssa_p (gimple_assign_rhs2 (st)); |
| ssa3 = valid_range_ssa_p (gimple_assign_rhs3 (st)); |
| } |
| else |
| return NULL; |
| |
| basic_block bb = gimple_bb (s); |
| |
| // Allocate a new bitmap and initialize it. |
| m_def_chain[v] = BITMAP_ALLOC (NULL); |
| |
| // build_def_chain returns the terminal name. If we have more than one unique |
| // terminal name, then this statement will have no terminal. |
| bool has_term = true; |
| m_terminal[v] = NULL_TREE; |
| if (ssa1) |
| { |
| ssa1 = build_def_chain (ssa1, m_def_chain[v], bb); |
| // if this chain has no terminal, root cannot either. |
| if (!ssa1) |
| has_term = false; |
| } |
| if (ssa2) |
| { |
| ssa2 = build_def_chain (ssa2, m_def_chain[v], bb); |
| if (!ssa2) |
| has_term = false; |
| } |
| if (ssa3) |
| { |
| ssa3 = build_def_chain (ssa3, m_def_chain[v], bb); |
| if (!ssa3) |
| has_term = false; |
| } |
| |
| if (has_term) |
| m_terminal[v] = pick_import (ssa1, ssa2, ssa3); |
| else |
| m_terminal[v] = NULL_TREE; |
| |
| // If we run into pathological cases where the defintion chains are huge |
| // (I'm thinking fppp for instance.. huge basic block fully unrolled) |
| // we might be able to limit this by deciding here that if there is no |
| // import AND 2 or more ssa names, we change the def_chain back to be |
| // just the ssa-names. that should prevent a_2 = b_6 + a_8 from creating |
| // a pathological case yet allow us to still handle it when b_6 and a_8 are |
| // derived from the same base name. |
| // thoughts? |
| return m_def_chain[v]; |
| } |
| |
| |
| // Initialize a gori-map structure. |
| |
| gori_map::gori_map () |
| { |
| m_outgoing.create (0); |
| m_outgoing.safe_grow_cleared (last_basic_block_for_fn (cfun)); |
| m_incoming.create (0); |
| m_incoming.safe_grow_cleared (last_basic_block_for_fn (cfun)); |
| |
| } |
| |
| // Free any memory the GORI map allocated. |
| |
| gori_map::~gori_map () |
| { |
| unsigned bb; |
| for (bb = 0; bb < m_outgoing.length (); ++bb) |
| if (m_outgoing[bb]) |
| BITMAP_FREE (m_outgoing[bb]); |
| m_outgoing.release (); |
| |
| for (bb = 0; bb < m_incoming.length (); ++bb) |
| if (m_incoming[bb]) |
| BITMAP_FREE (m_incoming[bb]); |
| m_incoming.release (); |
| |
| } |
| |
| // Return the bitmap vector of all imports to BB. Calculate if necessary |
| |
| bitmap |
| gori_map::imports (basic_block bb) |
| { |
| if (!m_incoming[bb->index]) |
| calculate_gori (bb); |
| return m_incoming[bb->index]; |
| } |
| |
| // Return true if NAME is an import to basic block BB |
| |
| bool |
| gori_map::is_import_p (tree name, basic_block bb) |
| { |
| return bitmap_bit_p (imports (bb), SSA_NAME_VERSION (name)); |
| } |
| |
| // Return the bitmap vector of all export from BB. Calculate if necessary |
| |
| bitmap |
| gori_map::exports (basic_block bb) |
| { |
| if (!m_outgoing[bb->index]) |
| calculate_gori (bb); |
| return m_outgoing[bb->index]; |
| } |
| |
| // Return true if NAME is can have ranges generated for it from basic block BB. |
| |
| bool |
| gori_map::is_export_p (tree name, basic_block bb) |
| { |
| return bitmap_bit_p (exports (bb), SSA_NAME_VERSION (name)); |
| } |
| |
| // Return true if any element in the def chain of NAME is in the export list |
| // for BB. |
| |
| bool |
| gori_map::def_chain_in_export_p (tree name, basic_block bb) |
| { |
| bitmap a = exports (bb); |
| bitmap b = get_def_chain (name); |
| if (a && b) |
| return bitmap_intersect_p (a, b); |
| return false; |
| } |
| |
| // If NAME is non-NULL and defined in block BB, calculate the def chain |
| // and add it to m_outgoing, and any imports to m_incoming. |
| |
| void |
| gori_map::maybe_add_gori (tree name, basic_block bb) |
| { |
| if (name) |
| { |
| bitmap r = get_def_chain (name); |
| if (r) |
| { |
| bitmap_copy (m_outgoing[bb->index], r); |
| tree im = terminal_name (name); |
| if (im) |
| bitmap_set_bit (m_incoming[bb->index], SSA_NAME_VERSION (im)); |
| } |
| else |
| { |
| // IF there is no def chain, and name originates outside this block |
| // then this name is also an import. |
| if (gimple_bb (SSA_NAME_DEF_STMT (name)) != bb) |
| bitmap_set_bit (m_incoming[bb->index], SSA_NAME_VERSION (name)); |
| } |
| // Def chain doesn't include itself, and even if there isn't a def |
| // chain, this name should be added to exports. |
| bitmap_set_bit (m_outgoing[bb->index], SSA_NAME_VERSION (name)); |
| } |
| } |
| |
| // Calculate all the required information for BB. |
| |
| void |
| gori_map::calculate_gori (basic_block bb) |
| { |
| tree name; |
| gcc_assert (m_outgoing[bb->index] == NULL); |
| m_outgoing[bb->index] = BITMAP_ALLOC (NULL); |
| m_incoming[bb->index] = BITMAP_ALLOC (NULL); |
| |
| // If this block's last statement may generate range informaiton, |
| // go calculate it. |
| gimple *s = gimple_outgoing_range_stmt_p (bb); |
| if (!s) |
| return; |
| if (is_a<gcond *> (s)) |
| { |
| gcond *gc = as_a<gcond *>(s); |
| name = valid_range_ssa_p (gimple_cond_lhs (gc)); |
| maybe_add_gori (name, gimple_bb (s)); |
| |
| name = valid_range_ssa_p (gimple_cond_rhs (gc)); |
| maybe_add_gori (name, gimple_bb (s)); |
| } |
| else |
| { |
| gswitch *gs = as_a<gswitch *>(s); |
| name = valid_range_ssa_p (gimple_switch_index (gs)); |
| maybe_add_gori (name, gimple_bb (s)); |
| } |
| } |
| |
| // Dump the table information for BB to file F. |
| |
| void |
| gori_map::dump(FILE *f, basic_block bb) |
| { |
| tree t; |
| bool header = false; |
| const char *header_string = "bb%-4d "; |
| const char *header2 = " "; |
| bool printed_something = false;; |
| unsigned x, y; |
| bitmap_iterator bi; |
| |
| if (!m_outgoing[bb->index]) |
| { |
| fprintf (f, "bb%d was not processed.\n", bb->index); |
| return; |
| } |
| |
| // Dump the def chain for each SSA_NAME defined in BB. |
| for (x = 1; x < num_ssa_names; x++) |
| { |
| tree name = ssa_name (x); |
| if (!name) |
| continue; |
| gimple *stmt = SSA_NAME_DEF_STMT (name); |
| bitmap chain = (has_def_chain (name) ? get_def_chain (name) : NULL); |
| if (stmt && gimple_bb (stmt) == bb && chain && !bitmap_empty_p (chain)) |
| { |
| fprintf (f, header_string, bb->index); |
| header_string = header2; |
| header = true; |
| print_generic_expr (f, name, TDF_SLIM); |
| if ((t = terminal_name (name))) |
| { |
| fprintf (f, " : (terminal "); |
| print_generic_expr (f, t, TDF_SLIM); |
| fprintf (f, ")"); |
| } |
| fprintf (f, " : "); |
| EXECUTE_IF_SET_IN_BITMAP (chain, 0, y, bi) |
| { |
| print_generic_expr (f, ssa_name (y), TDF_SLIM); |
| fprintf (f, " "); |
| } |
| fprintf (f, "\n"); |
| } |
| } |
| |
| printed_something |= header; |
| // Now dump the incoming vector. |
| header = false; |
| EXECUTE_IF_SET_IN_BITMAP (m_incoming[bb->index], 0, y, bi) |
| { |
| if (!header) |
| { |
| fprintf (f, header_string, bb->index); |
| fprintf (f, "imports: "); |
| header_string = header2; |
| header = true; |
| } |
| print_generic_expr (f, ssa_name (y), TDF_SLIM); |
| fprintf (f, " "); |
| } |
| |
| if (header) |
| fputc ('\n', f); |
| |
| // Now dump the export vector. |
| printed_something |= header; |
| header = false; |
| EXECUTE_IF_SET_IN_BITMAP (m_outgoing[bb->index], 0, y, bi) |
| { |
| if (!header) |
| { |
| fprintf (f, header_string, bb->index); |
| fprintf (f, "exports: "); |
| header_string = header2; |
| header = true; |
| } |
| print_generic_expr (f, ssa_name (y), TDF_SLIM); |
| fprintf (f, " "); |
| } |
| if (header) |
| fputc ('\n', f); |
| |
| printed_something |= header; |
| if (printed_something) |
| fprintf (f, "\n"); |
| } |
| |
| // Dump the entire GORI map structure to file F. |
| // |
| void |
| gori_map::dump(FILE *f) |
| { |
| basic_block bb; |
| FOR_EACH_BB_FN (bb, cfun) |
| { |
| dump (f, bb); |
| fprintf (f, "\n"); |
| } |
| } |
| |
| // Same but perform substitution of NAME with RANGE_OF_NAME if expr |
| // happens to match it. |
| |
| static irange |
| get_tree_range (tree expr, tree name, irange *range_of_name) |
| { |
| static stmt_ranger sr; |
| if (expr == name && range_of_name) |
| return *range_of_name; |
| |
| irange r; |
| gcc_assert (sr.range_of_expr (r, expr)); |
| return r; |
| } |
| |
| // Calculate the range for NAME if the lhs of statement S has the range LHS. |
| // If present, NAME_RANGE is any known range for NAME coming into this stmt. |
| // Return the result in R. Return false if no range can be calculated. |
| |
| static bool |
| compute_operand_range_on_stmt (irange &r, grange *s, const irange &lhs, |
| tree name, irange *name_range) |
| { |
| irange op1_range, op2_range; |
| |
| tree op1 = gimple_range_operand1 (s); |
| tree op2 = gimple_range_operand2 (s); |
| |
| // Operand 1 is the name being looked for, evaluate it. |
| if (op1 == name) |
| { |
| if (!op2) |
| { |
| // 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. |
| op1_range = get_tree_range (op1, name, name_range); |
| return gimple_range_calc_op1 (s, r, lhs, op1_range); |
| } |
| // If we need the second operand, get a value and evaluate. |
| op2_range = get_tree_range (op2, name, name_range); |
| if (gimple_range_calc_op1 (s, 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) |
| { |
| op1_range = get_tree_range (op1, name, name_range); |
| if (gimple_range_calc_op2 (s, 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; |
| } |
| |
| |
| // External entry point to calculate the range of NAME on statement S assuming |
| // the lhs's range is LHS. Return TRUE and the result in R if it is possible |
| // to calculate, otherwise return FALSE. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| compute_operand_range_on_stmt (irange &r, gimple *s, const irange &lhs, |
| tree name, irange *name_range) |
| { |
| if (is_a<grange *> (s)) |
| return compute_operand_range_on_stmt (r, as_a<grange *> (s), lhs, name, |
| name_range); |
| if (is_a<gswitch *> (s)) |
| { |
| if (gimple_switch_index (as_a<gswitch *>(s)) == name) |
| { |
| r = get_tree_range (name, name, name_range); |
| r.intersect (lhs); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // Construct a gori_compute object. |
| |
| gori_compute::gori_compute () |
| { |
| // Create a boolean_type true and false range. |
| m_bool_zero = irange (boolean_false_node, boolean_false_node); |
| m_bool_one = irange (boolean_true_node, boolean_true_node); |
| } |
| |
| // Destruct a gori_compute_object |
| |
| gori_compute::~gori_compute () |
| { |
| } |
| |
| // Given the statement S, return an evaluation in R for NAME |
| // when the lhs evaluates to LHS. Returning false means the name being |
| // looked for was not resolvable. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand_range (irange &r, gimple *s, const irange &lhs, |
| tree name, irange *name_range) |
| { |
| if (is_a<grange *> (s)) |
| return compute_operand_range_op (r, as_a<grange *> (s), lhs, name, |
| name_range); |
| if (is_a<gswitch *> (s)) |
| return compute_operand_range_switch (r, as_a<gswitch *> (s), lhs, name, |
| name_range); |
| return false; |
| } |
| |
| // Given the switch S, return an evaluation in R for NAME |
| // when the lhs evaluates to LHS. Returning false means the name being |
| // looked for was not resolvable. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand_range_switch (irange &r, gswitch *s, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| tree op1 = gimple_switch_index (s); |
| |
| // If name matches, the range is simply the range from the edge. |
| // Empty ranges are viral as they are on a path which isn't executable. |
| if (op1 == name || lhs.undefined_p ()) |
| { |
| r = lhs; |
| // If this is also the terminal |
| if (name && name_range) |
| r.intersect (*name_range); |
| return true; |
| } |
| |
| // If op1 is in the defintion chain, pass lhs back. |
| if (valid_range_ssa_p (op1) && in_chain_p (name, op1)) |
| return compute_operand_range (r, SSA_NAME_DEF_STMT (op1), lhs, name, |
| name_range); |
| |
| return false; |
| } |
| |
| // Return TRUE if GS is a logical && or || expression. |
| |
| static inline bool |
| is_gimple_logical_p (const gimple *gs) |
| { |
| /* Look for boolean and/or condition. */ |
| if (gimple_code (gs) == GIMPLE_ASSIGN) |
| switch (gimple_expr_code (gs)) |
| { |
| case TRUTH_AND_EXPR: |
| case TRUTH_OR_EXPR: |
| return true; |
| |
| case BIT_AND_EXPR: |
| case BIT_IOR_EXPR: |
| // Bitwise operations on single bits are logical too. |
| if (types_compatible_p (TREE_TYPE (gimple_assign_rhs1 (gs)), |
| boolean_type_node)) |
| return true; |
| break; |
| |
| default: |
| break; |
| } |
| return false; |
| } |
| |
| // Given the range_op S, return an evaluation in R for NAME |
| // when the lhs evaluates to LHS. Returning false means the name being |
| // looked for was not resolvable. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand_range_op (irange &r, grange *stmt, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| tree op1, op2; |
| bool op1_in_chain, op2_in_chain; |
| |
| // Empty ranges are viral as they are on a path which isn't executable. |
| if (lhs.undefined_p ()) |
| { |
| r.set_undefined (); |
| return true; |
| } |
| |
| op1 = valid_range_ssa_p (gimple_range_operand1 (stmt)); |
| op2 = valid_range_ssa_p (gimple_range_operand2 (stmt)); |
| |
| // The base ranger handles NAME on this statement. |
| if (op1 == name || op2 == name) |
| return compute_operand_range_on_stmt (r, stmt, lhs, name, name_range); |
| |
| // Check for logical combination cases which require developing ranges |
| // and combining the results based on the operation. |
| if (is_gimple_logical_p (stmt)) |
| return compute_logical_operands (r, stmt, lhs, name, name_range); |
| |
| // Reaching this point means NAME is not in this stmt, but one of the |
| // names in it ought to be derived from it. |
| op1_in_chain = op1 && in_chain_p (name, op1); |
| op2_in_chain = op2 && in_chain_p (name, op2); |
| |
| if (op2_in_chain) |
| { |
| if (op1_in_chain) |
| return compute_operand1_and_operand2_range (r, stmt, lhs, name, |
| name_range); |
| else |
| return compute_operand2_range (r, stmt, lhs, name, name_range); |
| } |
| else |
| if (op1_in_chain) |
| return compute_operand1_range (r, stmt, lhs, name, name_range); |
| |
| // If neither operand is derived, then this stmt tells us nothing. |
| return false; |
| } |
| |
| // Evaluate a binary logical expression by combining the true and false |
| // ranges for each of the operands based on the result value in the LHS. |
| |
| bool |
| gori_compute::logical_combine (irange &r, enum tree_code code, |
| const irange &lhs, |
| const irange &op1_true, const irange &op1_false, |
| const irange &op2_true, const irange &op2_false) |
| { |
| // This is not a simple fold of a logical expression, rather it determines |
| // ranges which flow through the logical expression. |
| // Assuming x_8 is an unsigned char, and relational statements: |
| // b_1 = x_8 < 20 |
| // b_2 = x_8 > 5 |
| // consider the logical expression and branch: |
| // c_2 = b_1 && b_2 |
| // if (c_2) |
| // To determine the range of x_8 on either edge of the branch, |
| // one must first determine what the range of x_8 is when the boolean |
| // values of b_1 and b_2 are both true and false. |
| // b_1 TRUE x_8 = [0, 19] |
| // b_1 FALSE x_8 = [20, 255] |
| // b_2 TRUE x_8 = [6, 255] |
| // b_2 FALSE x_8 = [0,5]. |
| // |
| // These ranges are then combined based on the expected outcome of the branch |
| // The range on the TRUE side of the branch must satisfy |
| // b_1 == true && b_2 == true |
| // in terms of x_8, that means both x_8 == [0, 19] and x_8 = [6, 255] |
| // must be true. The range of x_8 on the true side must be the intersection |
| // of both ranges since both must be true. Thus the range of x_8 |
| // on the true side is [6, 19] |
| // |
| // To determine the ranges on the FALSE side, all 3 combinations of |
| // failing ranges must be considered, and combined as any of them can cause |
| // the false result. |
| |
| // If the LHS can be TRUE OR FALSE, then evaluate both a TRUE and FALSE |
| // results and combine them. If we fell back to VARYING any range |
| // restrictions that have been discovered up to this point would be lost. */ |
| if (!lhs.singleton_p ()) |
| { |
| irange r1; |
| if (logical_combine (r1, code, m_bool_zero, op1_true, op1_false, op2_true, |
| op2_false) && |
| logical_combine (r, code, m_bool_one, op1_true, op1_false, op2_true, |
| op2_false)) |
| { |
| r.union_ (r1); |
| return true; |
| } |
| return false; |
| |
| } |
| |
| switch (code) |
| { |
| // A logical AND combines ranges from 2 boolean conditions. |
| // c_2 = b_1 && b_2 |
| case TRUTH_AND_EXPR: |
| case BIT_AND_EXPR: |
| if (!lhs.zero_p ()) |
| // The TRUE side is the intersection of the the 2 true ranges. |
| r = range_intersect (op1_true, op2_true); |
| else |
| { |
| // The FALSE side is the union of the other 3 cases. |
| irange ff = range_intersect (op1_false, op2_false); |
| irange tf = range_intersect (op1_true, op2_false); |
| irange ft = range_intersect (op1_false, op2_true); |
| r = range_union (ff, tf); |
| r.union_ (ft); |
| } |
| break; |
| |
| // A logical OR combines ranges from 2 boolean conditons. |
| // c_2 = b_1 || b_2 |
| case TRUTH_OR_EXPR: |
| case BIT_IOR_EXPR: |
| if (lhs.zero_p ()) |
| // An OR operation will only take the FALSE path if both operands |
| // are false. so [20, 255] intersect [0, 5] is the |
| // union: [0,5][20,255]. */ |
| r = range_intersect (op1_false, op2_false); |
| else |
| { |
| // The TRUE side of an OR operation will be the union of the other |
| // three combinations. |
| irange tt = range_intersect (op1_true, op2_true); |
| irange tf = range_intersect (op1_true, op2_false); |
| irange ft = range_intersect (op1_false, op2_true); |
| r = range_union (tt, tf); |
| r.union_ (ft); |
| } |
| break; |
| |
| default: |
| gcc_unreachable (); |
| } |
| |
| return true; |
| } |
| |
| // Given a logical STMT, calculate true and false for each potential path |
| // using NAME and resolve the outcome based on the logical operator. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_logical_operands (irange &r, grange *s, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| irange op1_range, op2_range; |
| tree op1, op2; |
| bool op1_in_chain, op2_in_chain; |
| bool ret = true; |
| const unsigned depth_limit = 6; // Max depth of logical recursion. |
| static unsigned depth = 0; // Current depth of recursion. |
| |
| irange op1_true, op1_false, op2_true, op2_false; |
| |
| // Reaching this point means NAME is not in this stmt, but one of the |
| // names in it ought to be derived from it. */ |
| op1 = gimple_range_operand1 (s); |
| op2 = gimple_range_operand2 (s); |
| gcc_checking_assert (op1 != name && op2 != name); |
| |
| op1_in_chain = valid_range_ssa_p (op1) && in_chain_p (name, op1); |
| op2_in_chain = valid_range_ssa_p (op2) && in_chain_p (name, op2); |
| |
| /* If neither operand is derived, then this stmt tells us nothing. */ |
| if (!op1_in_chain && !op2_in_chain) |
| return false; |
| |
| // Long chains of nested logical expressions rarely produce good ranges |
| // but can take exponential times to compute since we are recursively |
| // evaluating them for the true and false result. If the depth is too great |
| // simply terminate the calculation. See gcc testcase rvrp-logic-1.c. |
| if (depth > depth_limit) |
| { |
| r.set_varying (TREE_TYPE (name)); |
| return true; |
| } |
| depth++; |
| |
| /* The false path is not always a simple inversion of the true side. |
| Calulate ranges for true and false on both sides. */ |
| if (op1_in_chain) |
| { |
| ret = compute_operand_range (op1_true, SSA_NAME_DEF_STMT (op1), |
| m_bool_one, name, name_range); |
| ret &= compute_operand_range (op1_false, SSA_NAME_DEF_STMT (op1), |
| m_bool_zero, name, name_range); |
| } |
| else |
| { |
| // Otherwise just get the value for name in operand 1 position |
| op1_true = get_tree_range (name, name, name_range); |
| op1_false = op1_true; |
| } |
| |
| /* If operand1 evaluated OK, move on to operand 2. */ |
| if (ret) |
| { |
| if (op2_in_chain) |
| { |
| ret &= compute_operand_range (op2_true, SSA_NAME_DEF_STMT (op2), |
| m_bool_one, name, name_range); |
| ret &= compute_operand_range (op2_false, SSA_NAME_DEF_STMT (op2), |
| m_bool_zero, name, name_range); |
| } |
| else |
| { |
| // Otherwise just get the value for name in operand 2 position |
| op2_true = get_tree_range (name, name, name_range); |
| op2_false = op2_true; |
| } |
| } |
| if (!ret || !logical_combine (r, gimple_expr_code (s), lhs, op1_true, |
| op1_false, op2_true, op2_false)) |
| r.set_varying (TREE_TYPE (name)); |
| |
| depth--; |
| return true; |
| } |
| |
| |
| // Calculate a range for NAME from the operand 1 position of S assuming the |
| // result of the statement is LHS. Return the range in R, or false if no |
| // range could be calculated. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand1_range (irange &r, grange *s, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| irange op1_range, op2_range; |
| tree op1 = gimple_range_operand1 (s); |
| tree op2 = gimple_range_operand2 (s); |
| |
| // Determine a known range for operand1 (). |
| op1_range = get_tree_range (op1, name, name_range); |
| |
| // Now calcuated the operand and put that result in r. |
| if (!op2) |
| { |
| // we pass op1_range to the unary operation. Nomally it's a hidden |
| // range_for_type parameter, but sometimes having the actual range |
| // can result in better information. |
| if (!gimple_range_calc_op1 (s, r, lhs, op1_range)) |
| return false; |
| } |
| else |
| { |
| op2_range = get_tree_range (op2, name, name_range); |
| if (!gimple_range_calc_op1 (s, r, lhs, op2_range)) |
| return false; |
| } |
| |
| // Intersect the calculated result with the known result. |
| op1_range.intersect (r); |
| |
| // Then feed this range back as the LHS of the defining statement. |
| return compute_operand_range (r, SSA_NAME_DEF_STMT (op1), op1_range, name, |
| name_range); |
| } |
| |
| |
| // Calculate a range for NAME from the operand 2 position of S assuming the |
| // result of the statement is LHS. Return the range in R, or false if no |
| // range could be calculated. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand2_range (irange &r, grange *s, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| irange op1_range, op2_range; |
| tree op1 = gimple_range_operand1 (s); |
| tree op2 = gimple_range_operand2 (s); |
| |
| // Get a range for op1. |
| op1_range = get_tree_range (op1, name, name_range); |
| |
| // calculate the range for op2 based on lhs and op1. |
| if (!gimple_range_calc_op2 (s, op2_range, lhs, op1_range)) |
| return false; |
| |
| // Also pick up what is known about op2's range at this point |
| r = get_tree_range (op2, name, name_range); |
| |
| // And intersect it with the calculated result. |
| op2_range.intersect (r); |
| |
| // Then feed this range back as the LHS of the defining statement. |
| return compute_operand_range (r, SSA_NAME_DEF_STMT (op2), op2_range, name, |
| name_range); |
| } |
| |
| // Calculate a range for NAME from both operand positions of S assuming the |
| // result of the statement is LHS. Return the range in R, or false if no |
| // range could be calculated. |
| // If present, NAME_RANGE is any known range for NAME coming into S. |
| |
| bool |
| gori_compute::compute_operand1_and_operand2_range (irange &r, grange *s, |
| const irange &lhs, tree name, |
| irange *name_range) |
| { |
| irange op_range; |
| |
| // Calculate a good a range for op2. Since op1 == op2, this will have |
| // already included whatever the actual range of name is. |
| if (!compute_operand2_range (op_range, s, lhs, name, name_range)) |
| return false; |
| |
| // Now get the range thru op1... |
| if (!compute_operand1_range (r, s, lhs, name, name_range)) |
| return false; |
| |
| // Whichever range is the most permissive is the one we need to use. (?) |
| // OR is that true? Maybe this should be intersection? |
| r.union_ (op_range); |
| return true; |
| } |
| |
| bool |
| gori_compute::has_edge_range_p (edge e, tree name) |
| { |
| return (is_export_p (name, e->src) || def_chain_in_export_p (name, e->src)); |
| } |
| |
| |
| // If the src block of edge E defines an outgoing range for a name that is |
| // is in the def_chain for NAME, get the outgoing range for that ssa_name |
| // and re-evaluate NAME using this value. If NAME_RANGE is supplied (normally |
| // the current value of NAME), intersect this with the edge range to produce |
| // and accurate outgoing range on edge E for NAME. Return the results in R. |
| // Return false if nothing can be re-evaluated, or if NAME is actually exported |
| // and doesnt need redefining. |
| |
| #include "ssa-range.h" |
| |
| bool |
| gori_compute::reevaluate_definition (irange &r, tree name, edge e, |
| irange *name_range) |
| { |
| basic_block bb = e->src; |
| gimple *def_stmt; |
| ssa_op_iter iter; |
| use_operand_p use_p; |
| |
| // Ensure there is no outgoing range for NAME. |
| gcc_checking_assert (!is_export_p (name, bb)); |
| |
| // If nothing in the def chain is exported, there is no evaluation. |
| if (!def_chain_in_export_p (name, bb)) |
| return false; |
| |
| def_stmt = SSA_NAME_DEF_STMT (name); |
| gcc_checking_assert (def_stmt); |
| |
| // We know its possible to evaluate NAME from SOMETHING in its defintion. |
| FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_USE) |
| { |
| tree use = valid_range_ssa_p (USE_FROM_PTR (use_p)); |
| if (use) |
| { |
| irange use_range; |
| if (is_export_p (use, bb)) |
| { |
| if (!outgoing_edge_range_p (use_range, e, use)) |
| continue; |
| } |
| // Try reevaluating USE. we have no range on entry for USE. |
| else if (!reevaluate_definition (use_range, use, e, NULL)) |
| continue; |
| // Invoke basic range calculator for the statement so we dont |
| // get any dynamic calls to range_of_expr which could cause another |
| // iterative evaluation to fill a cache. |
| stmt_ranger eval; |
| gcc_assert (eval.range_of_stmt_with_range (r, def_stmt, use, |
| use_range)); |
| // If this is the root def and it has a range, combine them. |
| if (name_range) |
| r.intersect (*name_range); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // 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 |
| gori_compute::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 (!s) |
| return false; |
| |
| // If NAME can be calculated on the edge, use that. |
| if (is_export_p (name, e->src)) |
| return compute_operand_range (r, s, lhs, name, name_range); |
| |
| // Otherwise see if NAME is derived from something that can be calculated. |
| // This performs no dynamic lookups whatsover, so it is low cost. |
| return reevaluate_definition (r, name, e, name_range); |
| } |
| |
| // Calculate a range for NAME given an import range of IMPORT_RANGE and |
| // return it in r. Return true if successful. |
| |
| bool |
| gori_compute::range_from_import (irange &r, tree name, irange &import_range) |
| { |
| irange r1, r2; |
| bool res = true; |
| tree import = terminal_name (name); |
| |
| gcc_checking_assert |
| (import |
| && (import_range.undefined_p () |
| || useless_type_conversion_p (TREE_TYPE (import), |
| import_range.type ()))); |
| |
| // Only handling range_ops until we find a cond-expr that matters. |
| // We process this specially so we can handle self-referencing chains. ie: |
| // b_3 = b_1 + 10 |
| // b_4 = b_3 + b_1 // b_4 = b_1 * 2 + 10 really |
| // if (b_4 < 20) |
| // |
| // import b_1 = [0,0] |
| // we want to make sure b_4 evaluates both b_3 and b_1 with this import value |
| // Due to the nature of def chains, there can only be one import in the chain. |
| // its possible 2 different chains occur in one stmt, ie: |
| // if (b_4 < d_6), but there is no DEF for this stmt, so it can't happen. |
| // f_5 = b_4 + d_6 would have no import since there are 2 symbolics. |
| |
| grange *s = dyn_cast<grange *> (SSA_NAME_DEF_STMT (name)); |
| if (!s) |
| return false; |
| |
| tree op1 = gimple_range_operand1 (s); |
| tree op2 = gimple_range_operand2 (s); |
| |
| // Evaluate op1 |
| if (valid_range_ssa_p (op1)) |
| { |
| if (op1 == import) |
| r1 = import_range; |
| else |
| res = range_from_import (r1, op1, import_range); |
| } |
| else |
| r1 = get_tree_range (op1, NULL_TREE, NULL); |
| |
| if (!res) |
| return false; |
| if (!op2) |
| return gimple_range_fold (s, r, r1); |
| |
| // Now evaluate op2. |
| if (valid_range_ssa_p (op2)) |
| { |
| if (op2 == import) |
| r2 = import_range; |
| else |
| res = range_from_import (r2, op2, import_range); |
| } |
| else |
| r2 = get_tree_range (op2, NULL_TREE, NULL); |
| |
| if (res) |
| return gimple_range_fold (s, r, r1, r2); |
| |
| return false; |
| } |
| |