| /* Code for range related grange gimple statement. |
| Copyright (C) 2019 Free Software Foundation, Inc. |
| Contributed by Andrew MacLeod <amacleod@redhat.com> |
| and Aldy Hernandez <aldyh@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 "insn-codes.h" |
| #include "rtl.h" |
| #include "tree.h" |
| #include "gimple.h" |
| #include "cfghooks.h" |
| #include "tree-pass.h" |
| #include "ssa.h" |
| #include "optabs-tree.h" |
| #include "gimple-pretty-print.h" |
| #include "diagnostic-core.h" |
| #include "flags.h" |
| #include "fold-const.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "cfganal.h" |
| #include "gimple-fold.h" |
| #include "tree-eh.h" |
| #include "gimple-iterator.h" |
| #include "gimple-walk.h" |
| #include "tree-cfg.h" |
| #include "wide-int.h" |
| #include "range.h" |
| #include "grange.h" |
| #include "ssa-range.h" |
| |
| // This function looks for situations when walking the use/def chains |
| // may provide additonal contextual range information not exposed on |
| // this statement. Like knowing the IMAGPART return value from a |
| // builtin function is a boolean result. |
| |
| void |
| gimple_range_adjustment (const grange *s, irange &res) |
| { |
| switch (gimple_expr_code (s)) |
| { |
| case IMAGPART_EXPR: |
| { |
| irange r; |
| tree name; |
| tree type = TREE_TYPE (gimple_assign_lhs (s)); |
| |
| name = TREE_OPERAND (gimple_assign_rhs1 (s), 0); |
| if (TREE_CODE (name) == SSA_NAME) |
| { |
| gimple *def_stmt = SSA_NAME_DEF_STMT (name); |
| if (def_stmt && is_gimple_call (def_stmt) |
| && gimple_call_internal_p (def_stmt)) |
| { |
| switch (gimple_call_internal_fn (def_stmt)) |
| { |
| case IFN_ADD_OVERFLOW: |
| case IFN_SUB_OVERFLOW: |
| case IFN_MUL_OVERFLOW: |
| case IFN_ATOMIC_COMPARE_EXCHANGE: |
| r.set_varying (boolean_type_node); |
| range_cast (r, type); |
| res.intersect (r); |
| default: |
| break; |
| } |
| } |
| } |
| break; |
| } |
| |
| default: |
| break; |
| } |
| } |
| |
| |
| // This file implements the gimple range statement and associated data. |
| // the grange statement kind provides access to the range-op fold machinery |
| // as well as to a set of range adjustemnts which are gimple IL aware. |
| // |
| // This allows a statement to make adjustments to operands |
| // or results based on IL contextual information such as specific feeding |
| // statements or operand position. |
| // |
| // 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 into the table for use when it is encountered. |
| |
| static gimple * |
| calc_single_range (irange &r, gswitch *sw, edge e) |
| { |
| unsigned x, lim; |
| lim = gimple_switch_num_labels (sw); |
| tree type = TREE_TYPE (gimple_switch_index (sw)); |
| |
| // ADA currently has cases where the index is 64 bits and the case |
| // arguments are 32 bit, causing a trap when we create a case_range. |
| // Until this is resolved (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=87798) |
| // punt on these switches. |
| // cfamily fails during a bootstrap due to a signed index and unsigned cases. |
| // so changing to types_compatible_p for now. |
| tree case_type = TREE_TYPE (CASE_LOW (gimple_switch_label (sw, 1))); |
| if (lim > 1 && !types_compatible_p (type, case_type)) |
| return NULL; |
| |
| |
| if (e != gimple_switch_default_edge (cfun, sw)) |
| { |
| r.set_undefined (); |
| // Loop through all the switches edges, ignoring the default edge. |
| // unioning the ranges together. |
| for (x = 1; x < lim; x++) |
| { |
| if (gimple_switch_edge (cfun, sw, x) != e) |
| continue; |
| tree low = CASE_LOW (gimple_switch_label (sw, x)); |
| tree high = CASE_HIGH (gimple_switch_label (sw, x)); |
| if (!high) |
| high = low; |
| irange case_range (low, high); |
| r.union_ (case_range); |
| } |
| } |
| else |
| { |
| r.set_varying (type); |
| // Loop through all the switches edges, ignoring the default edge. |
| // intersecting the ranges not covered by the case. |
| for (x = 1; x < lim; x++) |
| { |
| tree low = CASE_LOW (gimple_switch_label (sw, x)); |
| tree high = CASE_HIGH (gimple_switch_label (sw, x)); |
| if (!high) |
| high = low; |
| irange case_range (VR_ANTI_RANGE, low, high); |
| r.intersect (case_range); |
| } |
| } |
| return sw; |
| } |
| |
| |
| // If there is a range control statment at the end of block BB, return it. |
| |
| gimple_stmt_iterator |
| gsi_outgoing_range_stmt (basic_block bb) |
| { |
| gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); |
| if (!gsi_end_p (gsi)) |
| { |
| gimple *s = gsi_stmt (gsi); |
| if (is_a<gcond *> (s) || is_a<gswitch *> (s)) |
| return gsi; |
| } |
| return gsi_none (); |
| } |
| |
| gimple * |
| gimple_outgoing_range_stmt_p (basic_block bb) |
| { |
| // This will return NULL if there is not a branch statement. |
| return gsi_stmt (gsi_outgoing_range_stmt (bb)); |
| } |
| |
| // Calculate the range forced on on edge E by control flow, if any, and |
| // return it in R. Return the statment which defines the range, otherwise |
| // return NULL; |
| |
| gimple * |
| gimple_outgoing_edge_range_p (irange &r, edge e) |
| { |
| // Determine if there is an outgoing edge. |
| gimple *s = gimple_outgoing_range_stmt_p (e->src); |
| if (!s) |
| return NULL; |
| if (is_a<gcond *> (s)) |
| { |
| if (e->flags & EDGE_TRUE_VALUE) |
| r = irange (boolean_true_node, boolean_true_node); |
| else if (e->flags & EDGE_FALSE_VALUE) |
| r = irange (boolean_false_node, boolean_false_node); |
| else |
| gcc_unreachable (); |
| return s; |
| } |
| |
| gcc_checking_assert (is_a<gswitch *> (s)); |
| gswitch *sw = as_a<gswitch *> (s); |
| tree type = TREE_TYPE (gimple_switch_index (sw)); |
| |
| if (!irange::supports_type_p (type)) |
| return NULL; |
| |
| return calc_single_range (r, sw, e); |
| } |
| |
| |
| // ------------------------------------------------------------------------ |
| // grange statement kind implementation. |
| |
| // Return the grange_adjust pointer for this statement, if there is one.. |
| |
| // Return the range_operator pointer for this statement. |
| |
| inline range_operator * |
| gimple_range_handler (const grange *s) |
| { |
| return range_op_handler (gimple_expr_code (s), gimple_expr_type (s)); |
| } |
| |
| // Return the first operand of this statement if it is a valid operand |
| // supported by ranges, otherwise return NULL_TREE. |
| |
| tree |
| gimple_range_operand1 (const grange *s) |
| { |
| switch (gimple_code (s)) |
| { |
| case GIMPLE_COND: |
| return gimple_cond_lhs (s); |
| case GIMPLE_ASSIGN: |
| { |
| tree expr = gimple_assign_rhs1 (s); |
| if (gimple_assign_rhs_code (s) == ADDR_EXPR) |
| { |
| // If the base address is an SSA_NAME, we return it here. |
| // This allows processing of the range of that name, while the |
| // rest of the expression is simply ignored. The code in |
| // range_ops will see the ADDR_EXPR and do the right thing. |
| tree base = get_base_address (TREE_OPERAND (expr, 0)); |
| if (base != NULL_TREE && TREE_CODE (base) == MEM_REF) |
| { |
| // If the base address is an SSA_NAME, return it. |
| tree b = TREE_OPERAND (base, 0); |
| if (TREE_CODE (b) == SSA_NAME) |
| return b; |
| } |
| } |
| return expr; |
| } |
| default: |
| break; |
| } |
| return NULL; |
| } |
| |
| |
| // Fold this unary statement uusing R1 as operand1's range, returning the |
| // result in RES. Return false if the operation fails. |
| |
| bool |
| gimple_range_fold (const grange *s, irange &res, const irange &r1) |
| { |
| tree type = gimple_expr_type (s);; |
| irange r2 (type); |
| // Single ssa operations require the LHS type as the second range. |
| |
| return gimple_range_fold (s, res, r1, r2); |
| } |
| |
| |
| // Fold this binary statement using R1 and R2 as the operands ranges, |
| // returning the result in RES. Return false if the operation fails. |
| |
| bool |
| gimple_range_fold (const grange *s, irange &res, const irange &r1, |
| const irange &r2) |
| { |
| irange adj_range; |
| |
| res = gimple_range_handler (s)->fold_range (gimple_expr_type (s), r1, r2); |
| |
| // If there are any gimple lookups, do those now. |
| gimple_range_adjustment (s, res); |
| return true; |
| } |
| |
| |
| // Calculate what we can determine of the range of this unary statement's |
| // operand if the lhs of the expression has the range LHS_RANGE. Return false |
| // if nothing can be determined. |
| |
| bool |
| gimple_range_calc_op1 (const grange *s, irange &r, const irange &lhs_range) |
| { |
| irange type_range; |
| gcc_checking_assert (gimple_num_ops (s) < 3); |
| // An empty range is viral, so return an empty range. |
| |
| tree type = TREE_TYPE (gimple_range_operand1 (s)); |
| if (lhs_range.undefined_p ()) |
| { |
| r.set_undefined (); |
| return true; |
| } |
| // Unary operations require the type of the first operand in the second range |
| // position. |
| type_range.set_varying (type); |
| return gimple_range_handler (s)->op1_range (r, type, lhs_range, type_range); |
| } |
| |
| |
| // Calculate what we can determine of the range of this statement's first |
| // operand if the lhs of the expression has the range LHS_RANGE and the second |
| // operand has the range OP2_RANGE. Return false if nothing can be determined. |
| |
| bool |
| gimple_range_calc_op1 (const grange *s, irange &r, const irange &lhs_range, |
| const irange &op2_range) |
| { |
| // Unary operation are allowed to pass a range in for second operand |
| // as there are often additional restrictions beyond the type which can |
| // be imposed. See operator_cast::op1_irange.() |
| |
| tree type = TREE_TYPE (gimple_range_operand1 (s)); |
| // An empty range is viral, so return an empty range. |
| if (op2_range.undefined_p () || lhs_range.undefined_p ()) |
| { |
| r.set_undefined (); |
| return true; |
| } |
| return gimple_range_handler (s)->op1_range (r, type, lhs_range, op2_range); |
| } |
| |
| |
| // Calculate what we can determine of the range of this statement's second |
| // operand if the lhs of the expression has the range LHS_RANGE and the first |
| // operand has the range OP1_RANGE. Return false if nothing can be determined. |
| |
| bool |
| gimple_range_calc_op2 (const grange *s, irange &r, const irange &lhs_range, |
| const irange &op1_range) |
| { |
| tree type = TREE_TYPE (gimple_range_operand2 (s)); |
| // An empty range is viral, so return an empty range. |
| if (op1_range.undefined_p () || lhs_range.undefined_p ()) |
| { |
| r.set_undefined (); |
| return true; |
| } |
| return gimple_range_handler (s)->op2_range (r, type, lhs_range, op1_range); |
| } |