aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range-op.cc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2022-09-01 10:34:55 -0400
committerAndrew MacLeod <amacleod@redhat.com>2022-09-22 14:48:12 -0400
commit51ce06385bf259a092f830f1a6dcc4b98757919e (patch)
treef7ea0f2f2b93e69910b98cb38c1a32d2367cf4d1 /gcc/gimple-range-op.cc
parent24c473a14d3cbe6fc44997122b532cb9406497cb (diff)
downloadgcc-51ce06385bf259a092f830f1a6dcc4b98757919e.zip
gcc-51ce06385bf259a092f830f1a6dcc4b98757919e.tar.gz
gcc-51ce06385bf259a092f830f1a6dcc4b98757919e.tar.bz2
Create gimple_range_op_handler in a new source file.
Range-ops is meant to be IL independent. Some gimple processing has be placed in range-ops, and some is located in gori. Split it all into a file and isolate it in a new class gimple_range_op_handler. * Makefile.in (OBJS): Add gimple-range-op.o. * gimple-range-edge.cc (gimple_outgoing_range_stmt_p): Use gimple_range_op_handler. * gimple-range-fold.cc (gimple_range_base_of_assignment): Move to a method in gimple_range_op_handler. (gimple_range_operand1): Ditto. (gimple_range_operand2): Ditto. (fold_using_range::fold_stmt): Use gimple_range_op_handler. (fold_using_range::range_of_range_op): Ditto. (fold_using_range::relation_fold_and_or): Ditto. (fur_source::register_outgoing_edges): Ditto. (gimple_range_ssa_names): Relocate to gimple-range-op.cc. * gimple-range-fold.h: Adjust prototypes. * gimple-range-gori.cc (gimple_range_calc_op1): Move to a method in gimple_range_op_handler. (gimple_range_calc_op2): Ditto. (gori_compute::compute_operand_range): Use gimple_range_op_handler. (gori_compute::compute_logical_operands): Ditto. (compute_operand1_range): Ditto. (gori_compute::compute_operand2_range): Ditto. (gori_compute::compute_operand1_and_operand2_range): Ditto. * gimple-range-gori.h: Adjust protoypes. * gimple-range-op.cc: New. Supply gimple_range_op_handler methods. * gimple-range-op.h: New. Supply gimple_range_op_handler class. * gimple-range.cc (gimple_ranger::prefill_name): Use gimple_range_op_handler. (gimple_ranger::prefill_stmt_dependencies): Ditto. * gimple-range.h: Include gimple-range-op.h. * range-op.cc (range_op_handler::range_op_handler): Adjust and remove gimple * parameter option. * range-op.h: Adjust prototypes.
Diffstat (limited to 'gcc/gimple-range-op.cc')
-rw-r--r--gcc/gimple-range-op.cc245
1 files changed, 245 insertions, 0 deletions
diff --git a/gcc/gimple-range-op.cc b/gcc/gimple-range-op.cc
new file mode 100644
index 0000000..f03125a
--- /dev/null
+++ b/gcc/gimple-range-op.cc
@@ -0,0 +1,245 @@
+/* Code for GIMPLE range op related routines.
+ Copyright (C) 2019-2022 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 "tree.h"
+#include "gimple.h"
+#include "ssa.h"
+#include "gimple-pretty-print.h"
+#include "optabs-tree.h"
+#include "gimple-iterator.h"
+#include "gimple-fold.h"
+#include "wide-int.h"
+#include "fold-const.h"
+#include "case-cfn-macros.h"
+#include "omp-general.h"
+#include "cfgloop.h"
+#include "tree-ssa-loop.h"
+#include "tree-scalar-evolution.h"
+#include "langhooks.h"
+#include "vr-values.h"
+#include "range.h"
+#include "value-query.h"
+#include "gimple-range.h"
+
+// Given stmt S, fill VEC, up to VEC_SIZE elements, with relevant ssa-names
+// on the statement. For efficiency, it is an error to not pass in enough
+// elements for the vector. Return the number of ssa-names.
+
+unsigned
+gimple_range_ssa_names (tree *vec, unsigned vec_size, gimple *stmt)
+{
+ tree ssa;
+ int count = 0;
+
+ gimple_range_op_handler handler (stmt);
+ if (handler)
+ {
+ gcc_checking_assert (vec_size >= 2);
+ if ((ssa = gimple_range_ssa_p (handler.operand1 ())))
+ vec[count++] = ssa;
+ if ((ssa = gimple_range_ssa_p (handler.operand2 ())))
+ vec[count++] = ssa;
+ }
+ else if (is_a<gassign *> (stmt)
+ && gimple_assign_rhs_code (stmt) == COND_EXPR)
+ {
+ gcc_checking_assert (vec_size >= 3);
+ gassign *st = as_a<gassign *> (stmt);
+ if ((ssa = gimple_range_ssa_p (gimple_assign_rhs1 (st))))
+ vec[count++] = ssa;
+ if ((ssa = gimple_range_ssa_p (gimple_assign_rhs2 (st))))
+ vec[count++] = ssa;
+ if ((ssa = gimple_range_ssa_p (gimple_assign_rhs3 (st))))
+ vec[count++] = ssa;
+ }
+ return count;
+}
+
+// Return the base of the RHS of an assignment.
+
+static 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;
+}
+
+// If statement is supported by range-ops, set the CODE and return the TYPE.
+
+static tree
+get_code_and_type (gimple *s, enum tree_code &code)
+{
+ tree type = NULL_TREE;
+ code = NOP_EXPR;
+
+ if (const gassign *ass = dyn_cast<const gassign *> (s))
+ {
+ code = gimple_assign_rhs_code (ass);
+ // The LHS of a comparison is always an int, so we must look at
+ // the operands.
+ if (TREE_CODE_CLASS (code) == tcc_comparison)
+ type = TREE_TYPE (gimple_assign_rhs1 (ass));
+ else
+ type = TREE_TYPE (gimple_assign_lhs (ass));
+ }
+ else if (const gcond *cond = dyn_cast<const gcond *> (s))
+ {
+ code = gimple_cond_code (cond);
+ type = TREE_TYPE (gimple_cond_lhs (cond));
+ }
+ return type;
+}
+
+// If statement S has a supported range_op handler return TRUE.
+
+bool
+gimple_range_op_handler::supported_p (gimple *s)
+{
+ enum tree_code code;
+ tree type = get_code_and_type (s, code);
+ return (type && range_op_handler (code, type));
+}
+
+// Construct a handler object for statement S.
+
+gimple_range_op_handler::gimple_range_op_handler (gimple *s)
+{
+ enum tree_code code;
+ tree type = get_code_and_type (s, code);
+ m_stmt = s;
+ if (type)
+ set_op_handler (code, type);
+
+ if (m_valid)
+ switch (gimple_code (m_stmt))
+ {
+ case GIMPLE_COND:
+ m_op1 = gimple_cond_lhs (m_stmt);
+ m_op2 = gimple_cond_rhs (m_stmt);
+ break;
+ case GIMPLE_ASSIGN:
+ m_op1 = gimple_range_base_of_assignment (m_stmt);
+ if (m_op1 && TREE_CODE (m_op1) == 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 (m_op1, 0);
+ if (TREE_CODE (ssa) == SSA_NAME)
+ m_op1 = ssa;
+ }
+ if (gimple_num_ops (m_stmt) >= 3)
+ m_op2 = gimple_assign_rhs2 (m_stmt);
+ else
+ m_op2 = NULL_TREE;
+ break;
+ default:
+ m_op1 = NULL_TREE;
+ m_op2 = NULL_TREE;
+ break;
+ }
+}
+
+// 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_op_handler::calc_op1 (vrange &r, const vrange &lhs_range)
+{
+ gcc_checking_assert (gimple_num_ops (m_stmt) < 3);
+ // Give up on empty ranges.
+ if (lhs_range.undefined_p ())
+ return false;
+
+ // Unary operations require the type of the first operand in the
+ // second range position.
+ tree type = TREE_TYPE (operand1 ());
+ Value_Range type_range (type);
+ type_range.set_varying (type);
+ return 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_op_handler::calc_op1 (vrange &r, const vrange &lhs_range,
+ const vrange &op2_range)
+{
+ // Give up on empty ranges.
+ if (lhs_range.undefined_p ())
+ return false;
+
+ // 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 (operand1 ());
+ // If op2 is undefined, solve as if it is varying.
+ if (op2_range.undefined_p ())
+ {
+ // This is sometimes invoked on single operand stmts.
+ if (gimple_num_ops (m_stmt) < 3)
+ return false;
+ tree op2_type = TREE_TYPE (operand2 ());
+ Value_Range trange (op2_type);
+ trange.set_varying (op2_type);
+ return op1_range (r, type, lhs_range, trange);
+ }
+ return 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_op_handler::calc_op2 (vrange &r, const vrange &lhs_range,
+ const vrange &op1_range)
+{
+ // Give up on empty ranges.
+ if (lhs_range.undefined_p ())
+ return false;
+
+ tree type = TREE_TYPE (operand2 ());
+ // If op1 is undefined, solve as if it is varying.
+ if (op1_range.undefined_p ())
+ {
+ tree op1_type = TREE_TYPE (operand1 ());
+ Value_Range trange (op1_type);
+ trange.set_varying (op1_type);
+ return op2_range (r, type, lhs_range, trange);
+ }
+ return op2_range (r, type, lhs_range, op1_range);
+}