From 51ce06385bf259a092f830f1a6dcc4b98757919e Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Thu, 1 Sep 2022 10:34:55 -0400
Subject: [PATCH 03/17] 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.
---
gcc/Makefile.in | 1 +
gcc/gimple-range-edge.cc | 2 +-
gcc/gimple-range-fold.cc | 153 +++++-------------------
gcc/gimple-range-fold.h | 12 +-
gcc/gimple-range-gori.cc | 134 ++++++---------------
gcc/gimple-range-gori.h | 27 ++---
gcc/gimple-range-op.cc | 245 +++++++++++++++++++++++++++++++++++++++
gcc/gimple-range-op.h | 51 ++++++++
gcc/gimple-range.cc | 11 +-
gcc/gimple-range.h | 2 +-
gcc/range-op.cc | 37 ++----
gcc/range-op.h | 4 +-
12 files changed, 386 insertions(+), 293 deletions(-)
create mode 100644 gcc/gimple-range-op.cc
create mode 100644 gcc/gimple-range-op.h
@@ -1416,6 +1416,7 @@ OBJS = \
gimple-range-fold.o \
gimple-range-gori.o \
gimple-range-infer.o \
+ gimple-range-op.o \
gimple-range-trace.o \
gimple-ssa-backprop.o \
gimple-ssa-isolate-paths.o \
@@ -43,7 +43,7 @@ gimple_outgoing_range_stmt_p (basic_block bb)
if (!gsi_end_p (gsi))
{
gimple *s = gsi_stmt (gsi);
- if (is_a<gcond *> (s) && range_op_handler (s))
+ if (is_a<gcond *> (s) && gimple_range_op_handler::supported_p (s))
return gsi_stmt (gsi);
if (is_a <gswitch *> (s))
return gsi_stmt (gsi);
@@ -42,7 +42,7 @@ along with GCC; see the file COPYING3. If not see
#include "vr-values.h"
#include "range.h"
#include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
#include "gimple-range.h"
// Construct a fur_source, and set the m_query field.
@@ -463,73 +463,6 @@ gimple_range_adjustment (vrange &res, const gimple *stmt)
}
}
-// 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;
-}
-
-// 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 (range_op_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 (range_op_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 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
@@ -551,8 +484,9 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
&& gimple_assign_rhs_code (s) == ADDR_EXPR)
return range_of_address (as_a <irange> (r), s, src);
- if (range_op_handler (s))
- res = range_of_range_op (r, s, src);
+ gimple_range_op_handler handler (s);
+ if (handler)
+ res = range_of_range_op (r, handler, src);
else if (is_a<gphi *>(s))
res = range_of_phi (r, as_a<gphi *> (s), src);
else if (is_a<gcall *>(s))
@@ -587,17 +521,19 @@ fold_using_range::fold_stmt (vrange &r, gimple *s, fur_source &src, tree name)
// If a range cannot be calculated, return false.
bool
-fold_using_range::range_of_range_op (vrange &r, gimple *s, fur_source &src)
+fold_using_range::range_of_range_op (vrange &r,
+ gimple_range_op_handler &handler,
+ fur_source &src)
{
+ gcc_checking_assert (handler);
+ gimple *s = handler.stmt ();
tree type = gimple_range_type (s);
if (!type)
return false;
- range_op_handler handler (s);
- gcc_checking_assert (handler);
- tree lhs = gimple_get_lhs (s);
- tree op1 = gimple_range_operand1 (s);
- tree op2 = gimple_range_operand2 (s);
+ tree lhs = handler.lhs ();
+ tree op1 = handler.operand1 ();
+ tree op2 = handler.operand2 ();
Value_Range range1 (TREE_TYPE (op1));
Value_Range range2 (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
@@ -1430,9 +1366,10 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
else if (code != BIT_IOR_EXPR && code != TRUTH_OR_EXPR)
return;
- tree lhs = gimple_get_lhs (s);
- tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
- tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+ gimple_range_op_handler handler (s);
+ tree lhs = handler.lhs ();
+ tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+ tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
// Deal with || and && only when there is a full set of symbolics.
if (!lhs || !ssa1 || !ssa2
@@ -1448,18 +1385,18 @@ fold_using_range::relation_fold_and_or (irange& lhs_range, gimple *s,
gimple *ssa1_stmt = SSA_NAME_DEF_STMT (ssa1);
gimple *ssa2_stmt = SSA_NAME_DEF_STMT (ssa2);
- range_op_handler handler1 (SSA_NAME_DEF_STMT (ssa1));
- range_op_handler handler2 (SSA_NAME_DEF_STMT (ssa2));
+ gimple_range_op_handler handler1 (ssa1_stmt);
+ gimple_range_op_handler handler2 (ssa2_stmt);
// If either handler is not present, no relation can be found.
if (!handler1 || !handler2)
return;
// Both stmts will need to have 2 ssa names in the stmt.
- tree ssa1_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa1_stmt));
- tree ssa1_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa1_stmt));
- tree ssa2_dep1 = gimple_range_ssa_p (gimple_range_operand1 (ssa2_stmt));
- tree ssa2_dep2 = gimple_range_ssa_p (gimple_range_operand2 (ssa2_stmt));
+ tree ssa1_dep1 = gimple_range_ssa_p (handler1.operand1 ());
+ tree ssa1_dep2 = gimple_range_ssa_p (handler1.operand2 ());
+ tree ssa2_dep1 = gimple_range_ssa_p (handler2.operand1 ());
+ tree ssa2_dep2 = gimple_range_ssa_p (handler2.operand2 ());
if (!ssa1_dep1 || !ssa1_dep2 || !ssa2_dep1 || !ssa2_dep2)
return;
@@ -1516,7 +1453,7 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
tree name;
basic_block bb = gimple_bb (s);
- range_op_handler handler (s);
+ gimple_range_op_handler handler (s);
if (!handler)
return;
@@ -1529,7 +1466,6 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
e0 = NULL;
}
-
if (e1)
{
// If this edge is never taken, ignore it.
@@ -1544,8 +1480,8 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
// First, register the gcond itself. This will catch statements like
// if (a_2 < b_5)
- tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (s));
- tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (s));
+ tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+ tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
if (ssa1 && ssa2)
{
if (e0)
@@ -1575,11 +1511,11 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
if (TREE_CODE (TREE_TYPE (name)) != BOOLEAN_TYPE)
continue;
gimple *stmt = SSA_NAME_DEF_STMT (name);
- range_op_handler handler (stmt);
+ gimple_range_op_handler handler (stmt);
if (!handler)
continue;
- tree ssa1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
- tree ssa2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+ tree ssa1 = gimple_range_ssa_p (handler.operand1 ());
+ tree ssa2 = gimple_range_ssa_p (handler.operand2 ());
Value_Range r (TREE_TYPE (name));
if (ssa1 && ssa2)
{
@@ -1600,36 +1536,3 @@ fur_source::register_outgoing_edges (gcond *s, irange &lhs_range, edge e0, edge
}
}
}
-
-// 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;
-
- if (range_op_handler (stmt))
- {
- gcc_checking_assert (vec_size >= 2);
- if ((ssa = gimple_range_ssa_p (gimple_range_operand1 (stmt))))
- vec[count++] = ssa;
- if ((ssa = gimple_range_ssa_p (gimple_range_operand2 (stmt))))
- 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;
-}
@@ -96,15 +96,6 @@ range_compatible_p (tree type1, tree type2)
&& TYPE_SIGN (type1) == TYPE_SIGN (type2));
}
-extern tree gimple_range_operand1 (const gimple *s);
-extern tree gimple_range_operand2 (const gimple *s);
-
-// 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);
-
// Source of all operands for fold_using_range and gori_compute.
// It abstracts out the source of an operand so it can come from a stmt or
// and edge or anywhere a derived class of fur_source wants.
@@ -169,7 +160,8 @@ public:
bool fold_stmt (vrange &r, gimple *s, class fur_source &src,
tree name = NULL_TREE);
protected:
- bool range_of_range_op (vrange &r, gimple *s, fur_source &src);
+ bool range_of_range_op (vrange &r, gimple_range_op_handler &handler,
+ fur_source &src);
bool range_of_call (vrange &r, gcall *call, fur_source &src);
bool range_of_cond_expr (vrange &r, gassign* cond, fur_source &src);
bool range_of_address (irange &r, gimple *s, fur_source &src);
@@ -29,83 +29,6 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "gimple-range.h"
-// 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 (vrange &r, const gimple *stmt, const vrange &lhs_range)
-{
- gcc_checking_assert (gimple_num_ops (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 (gimple_range_operand1 (stmt));
- Value_Range type_range (type);
- type_range.set_varying (type);
- return range_op_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 (vrange &r, const gimple *stmt,
- 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 (gimple_range_operand1 (stmt));
- // 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 (stmt) < 3)
- return false;
- tree op2_type = TREE_TYPE (gimple_range_operand2 (stmt));
- Value_Range trange (op2_type);
- trange.set_varying (op2_type);
- return range_op_handler (stmt).op1_range (r, type, lhs_range, trange);
- }
- return range_op_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 (vrange &r, const gimple *stmt,
- const vrange &lhs_range, const vrange &op1_range)
-{
- // Give up on empty ranges.
- if (lhs_range.undefined_p ())
- return false;
-
- tree type = TREE_TYPE (gimple_range_operand2 (stmt));
- // If op1 is undefined, solve as if it is varying.
- if (op1_range.undefined_p ())
- {
- tree op1_type = TREE_TYPE (gimple_range_operand1 (stmt));
- Value_Range trange (op1_type);
- trange.set_varying (op1_type);
- return range_op_handler (stmt).op2_range (r, type, lhs_range, trange);
- }
- return range_op_handler (stmt).op2_range (r, type, lhs_range,
- op1_range);
-}
-
// Return TRUE if GS is a logical && or || expression.
static inline bool
@@ -695,17 +618,18 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
if (is_a<gswitch *> (stmt))
return compute_operand_range_switch (r, as_a<gswitch *> (stmt), lhs, name,
src);
- if (!range_op_handler (stmt))
+ gimple_range_op_handler handler (stmt);
+ if (!handler)
return false;
- tree op1 = gimple_range_ssa_p (gimple_range_operand1 (stmt));
- tree op2 = gimple_range_ssa_p (gimple_range_operand2 (stmt));
+ tree op1 = gimple_range_ssa_p (handler.operand1 ());
+ tree op2 = gimple_range_ssa_p (handler.operand2 ());
// Handle end of lookup first.
if (op1 == name)
- return compute_operand1_range (r, stmt, lhs, name, src);
+ return compute_operand1_range (r, handler, lhs, name, src);
if (op2 == name)
- return compute_operand2_range (r, stmt, lhs, name, src);
+ return compute_operand2_range (r, handler, lhs, name, src);
// NAME is not in this stmt, but one of the names in it ought to be
// derived from it.
@@ -733,10 +657,10 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
tree type = TREE_TYPE (name);
Value_Range op1_trange (type), op1_frange (type);
Value_Range op2_trange (type), op2_frange (type);
- compute_logical_operands (op1_trange, op1_frange, stmt,
+ compute_logical_operands (op1_trange, op1_frange, handler,
as_a <irange> (lhs),
name, src, op1, op1_in_chain);
- compute_logical_operands (op2_trange, op2_frange, stmt,
+ compute_logical_operands (op2_trange, op2_frange, handler,
as_a <irange> (lhs),
name, src, op2, op2_in_chain);
res = logical_combine (r,
@@ -748,11 +672,11 @@ gori_compute::compute_operand_range (vrange &r, gimple *stmt,
}
// Follow the appropriate operands now.
else if (op1_in_chain && op2_in_chain)
- res = compute_operand1_and_operand2_range (r, stmt, lhs, name, src);
+ res = compute_operand1_and_operand2_range (r, handler, lhs, name, src);
else if (op1_in_chain)
- res = compute_operand1_range (r, stmt, lhs, name, src);
+ res = compute_operand1_range (r, handler, lhs, name, src);
else if (op2_in_chain)
- res = compute_operand2_range (r, stmt, lhs, name, src);
+ res = compute_operand2_range (r, handler, lhs, name, src);
else
gcc_unreachable ();
@@ -944,13 +868,14 @@ gori_compute::logical_combine (vrange &r, enum tree_code code,
void
gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
- gimple *stmt,
+ gimple_range_op_handler &handler,
const irange &lhs,
tree name, fur_source &src,
tree op, bool op_in_chain)
{
+ gimple *stmt = handler.stmt ();
gimple *src_stmt = gimple_range_ssa_p (op) ? SSA_NAME_DEF_STMT (op) : NULL;
- if (!op_in_chain || !src_stmt || chain_import_p (gimple_get_lhs (stmt), op))
+ if (!op_in_chain || !src_stmt || chain_import_p (handler.lhs (), op))
{
// If op is not in the def chain, or defined in this block,
// use its known value on entry to the block.
@@ -999,12 +924,15 @@ gori_compute::compute_logical_operands (vrange &true_range, vrange &false_range,
// R, or false if no range could be calculated.
bool
-gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand1_range (vrange &r,
+ gimple_range_op_handler &handler,
const vrange &lhs, tree name,
fur_source &src)
{
- tree op1 = gimple_range_operand1 (stmt);
- tree op2 = gimple_range_operand2 (stmt);
+ gimple *stmt = handler.stmt ();
+ tree op1 = handler.operand1 ();
+ tree op2 = handler.operand2 ();
+
Value_Range op1_range (TREE_TYPE (op1));
Value_Range tmp (TREE_TYPE (op1));
Value_Range op2_range (op2 ? TREE_TYPE (op2) : TREE_TYPE (op1));
@@ -1016,7 +944,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
if (op2)
{
src.get_operand (op2_range, op2);
- if (!gimple_range_calc_op1 (tmp, stmt, lhs, op2_range))
+ if (!handler.calc_op1 (tmp, lhs, op2_range))
return false;
}
else
@@ -1024,7 +952,7 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
// 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 (tmp, stmt, lhs, op1_range))
+ if (!handler.calc_op1 (tmp, lhs, op1_range))
return false;
}
@@ -1079,12 +1007,15 @@ gori_compute::compute_operand1_range (vrange &r, gimple *stmt,
// R, or false if no range could be calculated.
bool
-gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
+gori_compute::compute_operand2_range (vrange &r,
+ gimple_range_op_handler &handler,
const vrange &lhs, tree name,
fur_source &src)
{
- tree op1 = gimple_range_operand1 (stmt);
- tree op2 = gimple_range_operand2 (stmt);
+ gimple *stmt = handler.stmt ();
+ tree op1 = handler.operand1 ();
+ tree op2 = handler.operand2 ();
+
Value_Range op1_range (TREE_TYPE (op1));
Value_Range op2_range (TREE_TYPE (op2));
Value_Range tmp (TREE_TYPE (op2));
@@ -1093,7 +1024,7 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
src.get_operand (op2_range, op2);
// Intersect with range for op2 based on lhs and op1.
- if (!gimple_range_calc_op2 (tmp, stmt, lhs, op1_range))
+ if (!handler.calc_op2 (tmp, lhs, op1_range))
return false;
unsigned idx;
@@ -1148,7 +1079,8 @@ gori_compute::compute_operand2_range (vrange &r, gimple *stmt,
bool
gori_compute::compute_operand1_and_operand2_range (vrange &r,
- gimple *stmt,
+ gimple_range_op_handler
+ &handler,
const vrange &lhs,
tree name,
fur_source &src)
@@ -1157,11 +1089,11 @@ gori_compute::compute_operand1_and_operand2_range (vrange &r,
// 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, stmt, lhs, name, src))
+ if (!compute_operand2_range (op_range, handler, lhs, name, src))
return false;
// Now get the range thru op1.
- if (!compute_operand1_range (r, stmt, lhs, name, src))
+ if (!compute_operand1_range (r, handler, lhs, name, src))
return false;
// Both operands have to be simultaneously true, so perform an intersection.
@@ -170,17 +170,18 @@ private:
tree name, class fur_source &src);
bool compute_operand_range_switch (vrange &r, gswitch *s, const vrange &lhs,
tree name, fur_source &src);
- bool compute_operand1_range (vrange &r, gimple *stmt, const vrange &lhs,
- tree name, fur_source &src);
- bool compute_operand2_range (vrange &r, gimple *stmt, const vrange &lhs,
- tree name, fur_source &src);
- bool compute_operand1_and_operand2_range (vrange &r, gimple *stmt,
+ bool compute_operand1_range (vrange &r, gimple_range_op_handler &handler,
+ const vrange &lhs, tree name, fur_source &src);
+ bool compute_operand2_range (vrange &r, gimple_range_op_handler &handler,
+ const vrange &lhs, tree name, fur_source &src);
+ bool compute_operand1_and_operand2_range (vrange &r,
+ gimple_range_op_handler &handler,
const vrange &lhs, tree name,
fur_source &src);
void compute_logical_operands (vrange &true_range, vrange &false_range,
- gimple *stmt, const irange &lhs,
- tree name, fur_source &src, tree op,
- bool op_in_chain);
+ gimple_range_op_handler &handler,
+ const irange &lhs, tree name, fur_source &src,
+ tree op, bool op_in_chain);
bool logical_combine (vrange &r, enum tree_code code, const irange &lhs,
const vrange &op1_true, const vrange &op1_false,
const vrange &op2_true, const vrange &op2_false);
@@ -192,16 +193,6 @@ private:
int m_not_executable_flag;
};
-// These routines provide a GIMPLE interface to the range-ops code.
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
- const vrange &lhs_range);
-extern bool gimple_range_calc_op1 (vrange &r, const gimple *s,
- const vrange &lhs_range,
- const vrange &op2_range);
-extern bool gimple_range_calc_op2 (vrange &r, const gimple *s,
- const vrange &lhs_range,
- const vrange &op1_range);
-
// For each name that is an import into BB's exports..
#define FOR_EACH_GORI_IMPORT_NAME(gori, bb, name) \
for (gori_export_iterator iter ((gori).imports ((bb))); \
new file mode 100644
@@ -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);
+}
new file mode 100644
@@ -0,0 +1,51 @@
+/* Header file for the GIMPLE range-op interface.
+ Copyright (C) 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/>. */
+
+#ifndef GCC_GIMPLE_RANGE_OP_H
+#define GCC_GIMPLE_RANGE_OP_H
+
+#include "range-op.h"
+
+
+class gimple_range_op_handler : public range_op_handler
+{
+public:
+ static bool supported_p (gimple *s);
+ gimple_range_op_handler (gimple *s);
+ inline gimple *stmt () const { return m_stmt; }
+ inline tree lhs () const { return gimple_get_lhs (m_stmt); }
+ tree operand1 () const { gcc_checking_assert (m_valid); return m_op1; }
+ tree operand2 () const { gcc_checking_assert (m_valid); return m_op2; }
+ bool calc_op1 (vrange &r, const vrange &lhs_range);
+ bool calc_op1 (vrange &r, const vrange &lhs_range, const vrange &op2_range);
+ bool calc_op2 (vrange &r, const vrange &lhs_range, const vrange &op1_range);
+private:
+ gimple *m_stmt;
+ tree m_op1, m_op2;
+};
+
+// 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);
+
+#endif // GCC_GIMPLE_RANGE_OP_H
@@ -341,7 +341,7 @@ gimple_ranger::prefill_name (vrange &r, tree name)
if (!gimple_range_ssa_p (name))
return;
gimple *stmt = SSA_NAME_DEF_STMT (name);
- if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+ if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
return;
bool current;
@@ -364,7 +364,7 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
gcc_checking_assert (stmt && gimple_bb (stmt));
// Only pre-process range-ops and phis.
- if (!range_op_handler (stmt) && !is_a<gphi *> (stmt))
+ if (!gimple_range_op_handler::supported_p (stmt) && !is_a<gphi *> (stmt))
return;
// Mark where on the stack we are starting.
@@ -422,14 +422,15 @@ gimple_ranger::prefill_stmt_dependencies (tree ssa)
}
else
{
- gcc_checking_assert (range_op_handler (stmt));
- tree op = gimple_range_operand2 (stmt);
+ gimple_range_op_handler handler (stmt);
+ gcc_checking_assert (handler);
+ tree op = handler.operand2 ();
if (op)
{
Value_Range r (TREE_TYPE (op));
prefill_name (r, op);
}
- op = gimple_range_operand1 (stmt);
+ op = handler.operand1 ();
if (op)
{
Value_Range r (TREE_TYPE (op));
@@ -24,7 +24,7 @@ along with GCC; see the file COPYING3. If not see
#include "range.h"
#include "value-query.h"
-#include "range-op.h"
+#include "gimple-range-op.h"
#include "gimple-range-trace.h"
#include "gimple-range-edge.h"
#include "gimple-range-fold.h"
@@ -4182,42 +4182,19 @@ range_op_handler::set_op_handler (tree_code code, tree type)
}
}
-range_op_handler::range_op_handler (tree_code code, tree type)
+range_op_handler::range_op_handler ()
{
- set_op_handler (code, type);
+ m_int = NULL;
+ m_float = NULL;
+ m_valid = false;
}
-range_op_handler::range_op_handler (const gimple *s)
+range_op_handler::range_op_handler (tree_code code, tree type)
{
- tree_code code = NOP_EXPR;
- tree type = NULL_TREE;
-
- 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));
- }
-
- if (!type)
- {
- m_int = NULL;
- m_float = NULL;
- m_valid = false;
- }
- else
- set_op_handler (code, type);
+ set_op_handler (code, type);
}
+
bool
range_op_handler::fold_range (vrange &r, tree type,
const vrange &lh,
@@ -160,8 +160,8 @@ public:
class range_op_handler
{
public:
+ range_op_handler ();
range_op_handler (enum tree_code code, tree type);
- range_op_handler (const gimple *s);
inline operator bool () const { return m_valid; }
bool fold_range (vrange &r, tree type,
@@ -185,7 +185,7 @@ public:
const vrange &op2,
relation_kind = VREL_VARYING) const;
relation_kind op1_op2_relation (const vrange &lhs) const;
-private:
+protected:
void set_op_handler (enum tree_code code, tree type);
bool m_valid;
range_operator *m_int;
--
2.37.3