aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range-stmt.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/gimple-range-stmt.cc')
-rw-r--r--gcc/gimple-range-stmt.cc426
1 files changed, 0 insertions, 426 deletions
diff --git a/gcc/gimple-range-stmt.cc b/gcc/gimple-range-stmt.cc
deleted file mode 100644
index 81f2bb5..0000000
--- a/gcc/gimple-range-stmt.cc
+++ /dev/null
@@ -1,426 +0,0 @@
-/* Code for GIMPLE range related routines.
- Copyright (C) 2019-2020 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 "ssa.h"
-#include "gimple-iterator.h"
-#include "tree-cfg.h"
-#include "gimple-range-stmt.h"
-
-// Adjust the range for a pointer difference where the operands came
-// from a memchr.
-//
-// This notices the following sequence:
-//
-// def = __builtin_memchr (arg, 0, sz)
-// n = def - arg
-//
-// The range for N can be narrowed to [0, PTRDIFF_MAX - 1].
-
-static void
-adjust_pointer_diff_expr (irange &res, const gimple *diff_stmt)
-{
- tree op0 = gimple_assign_rhs1 (diff_stmt);
- tree op1 = gimple_assign_rhs2 (diff_stmt);
- tree op0_ptype = TREE_TYPE (TREE_TYPE (op0));
- tree op1_ptype = TREE_TYPE (TREE_TYPE (op1));
- gimple *call;
-
- if (TREE_CODE (op0) == SSA_NAME
- && TREE_CODE (op1) == SSA_NAME
- && (call = SSA_NAME_DEF_STMT (op0))
- && is_gimple_call (call)
- && gimple_call_builtin_p (call, BUILT_IN_MEMCHR)
- && TYPE_MODE (op0_ptype) == TYPE_MODE (char_type_node)
- && TYPE_PRECISION (op0_ptype) == TYPE_PRECISION (char_type_node)
- && TYPE_MODE (op1_ptype) == TYPE_MODE (char_type_node)
- && TYPE_PRECISION (op1_ptype) == TYPE_PRECISION (char_type_node)
- && gimple_call_builtin_p (call, BUILT_IN_MEMCHR)
- && vrp_operand_equal_p (op1, gimple_call_arg (call, 0))
- && integer_zerop (gimple_call_arg (call, 1)))
- {
- tree max = vrp_val_max (ptrdiff_type_node);
- wide_int wmax = wi::to_wide (max, TYPE_PRECISION (TREE_TYPE (max)));
- tree expr_type = gimple_expr_type (diff_stmt);
- tree range_min = build_zero_cst (expr_type);
- tree range_max = wide_int_to_tree (expr_type, wmax - 1);
- int_range<1> r (range_min, range_max);
- res.intersect (r);
- }
-}
-
-// 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.
-
-// We should rework how we're called, as we have an op_unknown entry
-// for IMAGPART_EXPR and POINTER_DIFF_EXPR in range-ops just so this
-// function gets called.
-
-static void
-gimple_range_adjustment (irange &res, const gimple *stmt)
-{
- switch (gimple_expr_code (stmt))
- {
- case POINTER_DIFF_EXPR:
- adjust_pointer_diff_expr (res, stmt);
- return;
-
- case IMAGPART_EXPR:
- {
- tree name = TREE_OPERAND (gimple_assign_rhs1 (stmt), 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:
- {
- int_range<1> r;
- r.set_varying (boolean_type_node);
- tree type = TREE_TYPE (gimple_assign_lhs (stmt));
- range_cast (r, type);
- res.intersect (r);
- }
- default:
- break;
- }
- }
- }
- break;
- }
-
- default:
- break;
- }
-}
-
-// ------------------------------------------------------------------------
-
-// This function will calculate the "constant" range on edge E from
-// switch SW returning it in R, and return the switch statement
-// itself. This is currently not very efficent as the way we
-// represent switches in GIMPLE does not map well to this calculation.
-
-static gimple *
-calc_range_for_switch_on_edge (irange &r, gswitch *sw, edge e)
-{
- unsigned x, lim;
- lim = gimple_switch_num_labels (sw);
- tree type = TREE_TYPE (gimple_switch_index (sw));
-
- // ADA and FORTRAN currently have 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. Furthermore, cfamily fails during a bootstrap
- // due to a signed index and unsigned cases. So punting unless
- // 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;
-
- edge default_edge = gimple_switch_default_edge (cfun, sw);
- if (e != default_edge)
- {
- r.set_undefined ();
- // Union all the ranges for each switch edge, ignoring the
- // default edge.
- 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;
- int_range<1> case_range (low, high);
- r.union_ (case_range);
- }
- }
- else
- {
- r.set_varying (type);
- // Loop through all the switches edges, ignoring the default
- // edge, while intersecting the ranges not covered by the case.
- for (x = 1; x < lim; x++)
- {
- // Some other edge could still point to the default edge
- // destination. Ignore it.
- if (gimple_switch_edge (cfun, sw, x) == default_edge)
- continue;
- tree low = CASE_LOW (gimple_switch_label (sw, x));
- tree high = CASE_HIGH (gimple_switch_label (sw, x));
- if (!high)
- high = low;
- int_range<1> case_range (low, high, VR_ANTI_RANGE);
- 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 ();
-}
-
-
-// If there is a range control statment at the end of block BB, return it.
-
-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, 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 = int_range<1> (boolean_true_node, boolean_true_node);
- else if (e->flags & EDGE_FALSE_VALUE)
- r = int_range<1> (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_range_for_switch_on_edge (r, sw, e);
-}
-
-
-
-// Fold this unary statement using R1 as operand1's range, returning
-// the result in RES. Return false if the operation fails.
-
-bool
-gimple_range_fold (const gimple *stmt, irange &res, const irange &r1)
-{
- gcc_checking_assert (gimple_range_handler (stmt));
-
- tree type = gimple_expr_type (stmt);
- // Unary SSA operations require the LHS type as the second range.
- int_range<1> r2 (type);
-
- return gimple_range_fold (stmt, 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 gimple *stmt, irange &res,
- const irange &r1, const irange &r2)
-{
- gcc_checking_assert (gimple_range_handler (stmt));
-
- gimple_range_handler (stmt)->fold_range (res, gimple_expr_type (stmt),
- r1, r2);
-
- // If there are any gimple lookups, do those now.
- gimple_range_adjustment (res, stmt);
- return true;
-}
-
-// Return the base of the RHS of an assignment.
-
-tree
-gimple_range_base_of_assignment (const gimple *stmt)
-{
- gcc_checking_assert (gimple_code (stmt) == GIMPLE_ASSIGN);
- tree op1 = gimple_assign_rhs1 (stmt);
- if (gimple_assign_rhs_code (stmt) == ADDR_EXPR)
- return get_base_address (TREE_OPERAND (op1, 0));
- return op1;
-}
-
-// Return the first operand of this statement if it is a valid operand
-// supported by ranges, otherwise return NULL_TREE. Special case is
-// &(SSA_NAME expr), return the SSA_NAME instead of the ADDR expr.
-
-tree
-gimple_range_operand1 (const gimple *stmt)
-{
- gcc_checking_assert (gimple_range_handler (stmt));
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_COND:
- return gimple_cond_lhs (stmt);
- case GIMPLE_ASSIGN:
- {
- tree base = gimple_range_base_of_assignment (stmt);
- if (base && TREE_CODE (base) == MEM_REF)
- {
- // 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 ssa = TREE_OPERAND (base, 0);
- if (TREE_CODE (ssa) == SSA_NAME)
- return ssa;
- }
- return base;
- }
- default:
- break;
- }
- return NULL;
-}
-
-
-// Return the second operand of statement STMT, otherwise return NULL_TREE.
-
-tree
-gimple_range_operand2 (const gimple *stmt)
-{
- gcc_checking_assert (gimple_range_handler (stmt));
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_COND:
- return gimple_cond_rhs (stmt);
- case GIMPLE_ASSIGN:
- if (gimple_num_ops (stmt) >= 3)
- return gimple_assign_rhs2 (stmt);
- default:
- break;
- }
- return NULL_TREE;
-}
-
-
-
-// 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 gimple *stmt, irange &r, const irange &lhs_range)
-{
- gcc_checking_assert (gimple_num_ops (stmt) < 3);
- // An empty range is viral, so return an empty range.
-
- tree type = TREE_TYPE (gimple_range_operand1 (stmt));
- if (lhs_range.undefined_p ())
- {
- r.set_undefined ();
- return true;
- }
- // Unary operations require the type of the first operand in the
- // second range position.
- int_range<1> type_range (type);
- return gimple_range_handler (stmt)->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 gimple *stmt, 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_range.()
- tree type = TREE_TYPE (gimple_range_operand1 (stmt));
- // 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 (stmt)->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 gimple *stmt, irange &r,
- const irange &lhs_range, const irange &op1_range)
-{
- tree type = TREE_TYPE (gimple_range_operand2 (stmt));
- // 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 (stmt)->op2_range (r, type, lhs_range,
- op1_range);
-}