I've back ported and committed the 3 patch set for assume p;rocessing to
GCC14. The new file is almost the same, just a couple of minor
differences related to
1) value_range in gcc15 was Value_Range in gcc14, and
2) there was no gori() component to a range_query, so I had to pass a
ranger instance into the assume pass to access gori.
Other than that, they are pretty much in sync.
Bootstrapped on x86_64-pc-linux-gnu with no regressions. Pushed.
Andrew
From 34db084961e01172de81f7689f31fe30fb0a781a Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Thu, 31 Oct 2024 14:07:00 -0400
Subject: [PATCH 3/3] Update bitwise_or op_range.
If the LHS of a bitwise OR is positive, then so are both operands when
using op1_range or op2_range.
gcc/
* range-op.cc (operator_bitwise_or::op1_range): If LHS is signed
positive, so are both operands.
gcc/testsuite
* g++.dg/cpp23/attr-assume-opt.C (f2b): Alternate flow test.
---
gcc/range-op.cc | 13 +++++++
gcc/testsuite/g++.dg/cpp23/attr-assume-opt.C | 37 +++++++++++++++++++-
2 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index 4ccb86ef0ba..d1a1cd73687 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -3738,6 +3738,19 @@ operator_bitwise_or::op1_range (irange &r, tree type,
r.set_zero (type);
return true;
}
+
+ // if (A < 0 && B < 0)
+ // Sometimes gets translated to
+ // _1 = A | B
+ // if (_1 < 0))
+ // It is useful for ranger to recognize a positive LHS means the RHS
+ // operands are also positive when dealing with the ELSE range..
+ if (TYPE_SIGN (type) == SIGNED && wi::ge_p (lhs.lower_bound (), 0, SIGNED))
+ {
+ unsigned prec = TYPE_PRECISION (type);
+ r.set (type, wi::zero (prec), wi::max_value (prec, SIGNED));
+ return true;
+ }
r.set_varying (type);
return true;
}
diff --git a/gcc/testsuite/g++.dg/cpp23/attr-assume-opt.C b/gcc/testsuite/g++.dg/cpp23/attr-assume-opt.C
index 88d5e78dbba..e61ba7a27e0 100644
--- a/gcc/testsuite/g++.dg/cpp23/attr-assume-opt.C
+++ b/gcc/testsuite/g++.dg/cpp23/attr-assume-opt.C
@@ -38,5 +38,40 @@ f3 (int x, int y, int z)
return 1;
}
+// This is the same as f2, except there is more complicated flow and
+// required a range-op update to bitwise or.
+
+void barn(int x);
+// assume (x+12 == 14 && y >= 0 && y + 10 < 13 && z + 4 >= 4 && z - 2 < 18)
+// in different order and form with function calls to cause branches.
+bool assume_func (int x, int y, int z)
+{
+ if (z - 2 >= 18)
+ return false;
+ if (x+12 != 14)
+ return false;
+ barn (x);
+ if (y < 0)
+ return false;
+ if (z + 4 < 4)
+ return false;
+ barn (y);
+ if (y + 10 >= 13)
+ return false;
+ barn (z);
+ return true;
+}
+
+int
+f2b (int x, int y, int z)
+{
+ [[assume (assume_func (x, y, z))]];
+ unsigned q = x + y + z;
+ if (q*2 > 46)
+ return 0;
+ return 1;
+}
+
+
/* { dg-final { scan-tree-dump-times "return 0" 0 "vrp2" } } */
-/* { dg-final { scan-tree-dump-times "return 1" 3 "vrp2" } } */
+/* { dg-final { scan-tree-dump-times "return 1" 4 "vrp2" } } */
--
2.45.0
From 6736649222082805b9f6cb84e94650edff2e7549 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Fri, 1 Nov 2024 12:46:39 -0400
Subject: [PATCH 2/3] Reimplement 'assume' processing pass.
Rework the assume pass to work properly and fail conservatively when it
does. Also move it to its own file.
PR tree-optimization/117287
gcc/
* Makefile.in (IBJS): Add tree-assume.o
* gimple-range.cc (assume_query::assume_range_p): Remove.
(assume_query::range_of_expr): Remove.
(assume_query::assume_query): Move to tree-assume.cc.
(assume_query::~assume_query): Remove.
(assume_query::calculate_op): Move to tree-assume.cc.
(assume_query::calculate_phi): Likewise.
(assume_query::check_taken_edge): Remove.
(assume_query::calculate_stmt): Move to tree-assume.cc.
(assume_query::dump): Remove.
* gimple-range.h (class assume_query): Move to tree-assume.cc
* tree-assume.cc: New
* tree-vrp.cc (struct pass_data_assumptions): Move to tree-assume.cc.
(class pass_assumptions): Likewise.
(make_pass_assumptions): Likewise.
gcc/testsuite/
* g++.dg/cpp23/pr117287-attr.C: New.
---
gcc/Makefile.in | 1 +
gcc/gimple-range.cc | 188 ----------
gcc/gimple-range.h | 17 -
gcc/testsuite/g++.dg/cpp23/pr117287-attr.C | 38 ++
gcc/tree-assume.cc | 384 +++++++++++++++++++++
gcc/tree-vrp.cc | 68 ----
6 files changed, 423 insertions(+), 273 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
create mode 100644 gcc/tree-assume.cc
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index a74761b7ab3..d475bf1c32e 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1697,6 +1697,7 @@ OBJS = \
ubsan.o \
sanopt.o \
sancov.o \
+ tree-assume.o \
tree-call-cdce.o \
tree-cfg.o \
tree-cfgcleanup.o \
diff --git a/gcc/gimple-range.cc b/gcc/gimple-range.cc
index 4d3b1ce8588..5ad658cab39 100644
--- a/gcc/gimple-range.cc
+++ b/gcc/gimple-range.cc
@@ -711,194 +711,6 @@ disable_ranger (struct function *fun)
bitmap_obstack_release (NULL);
}
-// ------------------------------------------------------------------------
-
-// If there is a non-varying value associated with NAME, return true and the
-// range in R.
-
-bool
-assume_query::assume_range_p (vrange &r, tree name)
-{
- if (global.get_range (r, name))
- return !r.varying_p ();
- return false;
-}
-
-// Query used by GORI to pick up any known value on entry to a block.
-
-bool
-assume_query::range_of_expr (vrange &r, tree expr, gimple *stmt)
-{
- if (!gimple_range_ssa_p (expr))
- return get_tree_range (r, expr, stmt);
-
- if (!global.get_range (r, expr))
- r.set_varying (TREE_TYPE (expr));
- return true;
-}
-
-// If the current function returns an integral value, and has a single return
-// statement, it will calculate any SSA_NAMES it can determine ranges for
-// assuming the function returns 1.
-
-assume_query::assume_query ()
-{
- basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (cfun);
- if (single_pred_p (exit_bb))
- {
- basic_block bb = single_pred (exit_bb);
- gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
- if (gsi_end_p (gsi))
- return;
- gimple *s = gsi_stmt (gsi);
- if (!is_a<greturn *> (s))
- return;
- greturn *gret = as_a<greturn *> (s);
- tree op = gimple_return_retval (gret);
- if (!gimple_range_ssa_p (op))
- return;
- tree lhs_type = TREE_TYPE (op);
- if (!irange::supports_p (lhs_type))
- return;
-
- unsigned prec = TYPE_PRECISION (lhs_type);
- int_range<2> lhs_range (lhs_type, wi::one (prec), wi::one (prec));
- global.set_range (op, lhs_range);
-
- gimple *def = SSA_NAME_DEF_STMT (op);
- if (!def || gimple_get_lhs (def) != op)
- return;
- fur_stmt src (gret, this);
- calculate_stmt (def, lhs_range, src);
- }
-}
-
-// Evaluate operand OP on statement S, using the provided LHS range.
-// If successful, set the range in the global table, then visit OP's def stmt.
-
-void
-assume_query::calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src)
-{
- Value_Range op_range (TREE_TYPE (op));
- if (m_gori.compute_operand_range (op_range, s, lhs, op, src)
- && !op_range.varying_p ())
- {
- // Set the global range, merging if there is already a range.
- global.merge_range (op, op_range);
- gimple *def_stmt = SSA_NAME_DEF_STMT (op);
- if (def_stmt && gimple_get_lhs (def_stmt) == op)
- calculate_stmt (def_stmt, op_range, src);
- }
-}
-
-// Evaluate PHI statement, using the provided LHS range.
-// Check each constant argument predecessor if it can be taken
-// provide LHS to any symbolic arguments, and process their def statements.
-
-void
-assume_query::calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src)
-{
- for (unsigned x= 0; x < gimple_phi_num_args (phi); x++)
- {
- tree arg = gimple_phi_arg_def (phi, x);
- Value_Range arg_range (TREE_TYPE (arg));
- if (gimple_range_ssa_p (arg))
- {
- // A symbol arg will be the LHS value.
- arg_range = lhs_range;
- range_cast (arg_range, TREE_TYPE (arg));
- if (!global.get_range (arg_range, arg))
- {
- global.set_range (arg, arg_range);
- gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
- if (def_stmt && gimple_get_lhs (def_stmt) == arg)
- calculate_stmt (def_stmt, arg_range, src);
- }
- }
- else if (get_tree_range (arg_range, arg, NULL))
- {
- // If this is a constant value that differs from LHS, this
- // edge cannot be taken.
- arg_range.intersect (lhs_range);
- if (arg_range.undefined_p ())
- continue;
- // Otherwise check the condition feeding this edge.
- edge e = gimple_phi_arg_edge (phi, x);
- check_taken_edge (e, src);
- }
- }
-}
-
-// If an edge is known to be taken, examine the outgoing edge to see
-// if it carries any range information that can also be evaluated.
-
-void
-assume_query::check_taken_edge (edge e, fur_source &src)
-{
- gimple *stmt = gimple_outgoing_range_stmt_p (e->src);
- if (stmt && is_a<gcond *> (stmt))
- {
- int_range<2> cond;
- gcond_edge_range (cond, e);
- calculate_stmt (stmt, cond, src);
- }
-}
-
-// Evaluate statement S which produces range LHS_RANGE.
-
-void
-assume_query::calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src)
-{
- gimple_range_op_handler handler (s);
- if (handler)
- {
- tree op = gimple_range_ssa_p (handler.operand1 ());
- if (op)
- calculate_op (op, s, lhs_range, src);
- op = gimple_range_ssa_p (handler.operand2 ());
- if (op)
- calculate_op (op, s, lhs_range, src);
- }
- else if (is_a<gphi *> (s))
- {
- calculate_phi (as_a<gphi *> (s), lhs_range, src);
- // Don't further check predecessors of blocks with PHIs.
- return;
- }
-
- // Even if the walk back terminates before the top, if this is a single
- // predecessor block, see if the predecessor provided any ranges to get here.
- if (single_pred_p (gimple_bb (s)))
- check_taken_edge (single_pred_edge (gimple_bb (s)), src);
-}
-
-// Show everything that was calculated.
-
-void
-assume_query::dump (FILE *f)
-{
- fprintf (f, "Assumption details calculated:\n");
- for (unsigned i = 0; i < num_ssa_names; i++)
- {
- tree name = ssa_name (i);
- if (!name || !gimple_range_ssa_p (name))
- continue;
- tree type = TREE_TYPE (name);
- if (!Value_Range::supports_type_p (type))
- continue;
-
- Value_Range assume_range (type);
- if (assume_range_p (assume_range, name))
- {
- print_generic_expr (f, name, TDF_SLIM);
- fprintf (f, " -> ");
- assume_range.dump (f);
- fputc ('\n', f);
- }
- }
- fprintf (f, "------------------------------\n");
-}
-
// ---------------------------------------------------------------------------
diff --git a/gcc/gimple-range.h b/gcc/gimple-range.h
index 8739ab6a2ef..6e926c23f51 100644
--- a/gcc/gimple-range.h
+++ b/gcc/gimple-range.h
@@ -83,23 +83,6 @@ extern gimple_ranger *enable_ranger (struct function *m,
bool use_imm_uses = true);
extern void disable_ranger (struct function *);
-class assume_query : public range_query
-{
-public:
- assume_query ();
- bool assume_range_p (vrange &r, tree name);
- virtual bool range_of_expr (vrange &r, tree expr, gimple * = NULL);
- void dump (FILE *f);
-protected:
- void calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src);
- void calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src);
- void calculate_phi (gphi *phi, vrange &lhs_range, fur_source &src);
- void check_taken_edge (edge e, fur_source &src);
-
- ssa_lazy_cache global;
- gori_compute m_gori;
-};
-
// DOM based ranger for fast VRP.
// This must be processed in DOM order, and does only basic range operations.
diff --git a/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C b/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
new file mode 100644
index 00000000000..759c21dc283
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp23/pr117287-attr.C
@@ -0,0 +1,38 @@
+// P1774R8 - Portable assumptions
+// { dg-do run { target c++23 } }
+// { dg-options "-O2 --param=logical-op-non-short-circuit=0" }
+// Test the we can optimize based on conditions in assume.
+
+static inline bool
+foo (unsigned x)
+{
+ return x == 4 || x == 5 || x == 9 || x == 10;
+}
+
+int v;
+
+[[gnu::noipa]] void
+bar (const char *p)
+{
+ if (p[0] != (v ? 'a' : 'b') || p[1])
+ __builtin_abort ();
+}
+
+[[gnu::noipa]] void
+baz (unsigned x)
+{
+ bool a = x == 5;
+ [[assume (foo (x))]];
+ bar (a ? "a" : "b");
+}
+
+int
+main ()
+{
+ baz (4);
+ v = 1;
+ baz (5);
+ v = 0;
+ baz (9);
+ baz (10);
+}
diff --git a/gcc/tree-assume.cc b/gcc/tree-assume.cc
new file mode 100644
index 00000000000..897b5ce3baf
--- /dev/null
+++ b/gcc/tree-assume.cc
@@ -0,0 +1,384 @@
+/* Support for C++23 ASSUME keyword functionailty.
+ Copyright (C) 2023-2024 Free Software Foundation, Inc.
+ Contributed by Andrew MacLeod <amacl...@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 "basic-block.h"
+#include "bitmap.h"
+#include "options.h"
+#include "function.h"
+#include "cfg.h"
+#include "tree.h"
+#include "gimple.h"
+#include "tree-pass.h"
+#include "ssa.h"
+#include "gimple-iterator.h"
+#include "gimple-range.h"
+#include "tree-dfa.h"
+#include "gimple-pretty-print.h"
+#include "tree-cfg.h"
+
+// An assume query utilizes the current range query to implelemtn the assume
+// keyword.
+// For any return value of 1 from the function, it attempts to determine
+// which paths leads to a 1 value being returned. On those paths, what
+// the ranges of any ssa_names listed in bitmap P (usually the parm list for
+// the function) are, and combined them all.
+// These ranges are then set as the global ranges for those parms in this
+// function.
+// Other functions which then refer to this function in an assume builtin
+// will then pick up these ranges for the paramters via the inferred range
+// mechanism.
+// See gimple-range-infer.cc::gimple_infer_range::check_assume_func ()
+//
+// my_func (int x)
+// {
+// <...>
+// assume [[(x == 1 || x ==4))]]
+// if (x ==3)
+//
+// a small temporary assume function consisting of
+// assume_f1 (int x) { return x == 1 || x == 4; }
+// is constructed by the front end, and optimzed, at the very end of
+// optimization, instead of generating code, we instead invoke the assume pass
+// which uses this query to set the the global value of parm x to [1,1][4,4]
+//
+// Meanwhile., my_Fund has been rewritten to be:
+//
+// my_func (int x_2)
+// {
+// <...>
+// assume_builtin_call assume_f1 (x_2);
+// if (x_2 == 3)
+//
+// When ranger is processing the assume_builtin_call, it looks up the global
+// value of the paramter in assume_f1, which is [1,1][4,4]. It then registers
+// and inferred range at this statement setting the value x_2 to [1,1][4,4]
+//
+// Any uses of x_2 after this statement will now utilzie this inferred range.
+//
+// When VRP precoesses if (x_2 == 3), it picks up the inferred range, and
+// determines that x_2 can never be 3, and will rewrite the branch to
+// if (0 != 0)
+
+class assume_query
+{
+public:
+ assume_query (gimple_ranger *ranger, function *f, bitmap p);
+protected:
+ inline void process_stmts (gimple *s, vrange &lhs_range)
+ {
+ fur_depend src (s, &(m_ranger->gori ()), m_ranger);
+ calculate_stmt (s, lhs_range, src);
+ update_parms (src);
+ }
+ void update_parms (fur_source &src);
+ void calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src);
+ void calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src);
+ void calculate_phi (gphi *phi, vrange &lhs_range);
+
+ ssa_lazy_cache m_path; // Values found on path
+ ssa_lazy_cache m_parms; // Cumulative parameter value calculated
+ gimple_ranger *m_ranger;
+ bitmap &m_parm_list; // Parameter ssa-names list.
+ function *m_func;
+};
+
+// If function F returns a integral value, and has a single return
+// statement, try to calculate the range of each value in P that leads
+// to the return statement returning TRUE.
+
+assume_query::assume_query (gimple_ranger *ranger, function *f, bitmap p)
+ : m_ranger (ranger), m_parm_list (p), m_func (f)
+{
+ basic_block exit_bb = EXIT_BLOCK_PTR_FOR_FN (f);
+ // If there is more than one precessor to the exit block, bail.
+ if (!single_pred_p (exit_bb))
+ return;
+
+ basic_block bb = single_pred (exit_bb);
+ gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb);
+ if (gsi_end_p (gsi))
+ return;
+ gimple *s = gsi_stmt (gsi);
+ if (!is_a<greturn *> (s))
+ return;
+
+ // Check if the single return value is a symbolic and supported type.
+ greturn *gret = as_a<greturn *> (s);
+ tree op = gimple_return_retval (gret);
+ if (!gimple_range_ssa_p (op))
+ return;
+ tree lhs_type = TREE_TYPE (op);
+ if (!irange::supports_p (lhs_type))
+ return;
+
+ // Only values of interest are when the return value is 1. The defintion
+ // of the return value must be in the same block, or we have
+ // complicated flow control we don't understand, and just return.
+ unsigned prec = TYPE_PRECISION (lhs_type);
+ int_range<2> lhs_range (lhs_type, wi::one (prec), wi::one (prec));
+
+ gimple *def = SSA_NAME_DEF_STMT (op);
+ if (!def || gimple_get_lhs (def) != op || gimple_bb (def) != bb)
+ return;
+
+ // Determine if this is a PHI or a linear sequence to deal with.
+ if (is_a<gphi *> (def))
+ calculate_phi (as_a<gphi *> (def), lhs_range);
+ else
+ process_stmts (def, lhs_range);
+
+ if (dump_file)
+ fprintf (dump_file, "Assumptions :\n--------------\n");
+
+ // Now export any interesting values that were found.
+ bitmap_iterator bi;
+ unsigned x;
+ EXECUTE_IF_SET_IN_BITMAP (m_parm_list, 0, x, bi)
+ {
+ tree name = ssa_name (x);
+ tree type = TREE_TYPE (name);
+ Value_Range assume_range (type);
+ // Set the global range of NAME to anything calculated.
+ if (m_parms.get_range (assume_range, name) && !assume_range.varying_p ())
+ {
+ set_range_info (name, assume_range);
+ if (dump_file)
+ {
+ print_generic_expr (dump_file, name, TDF_SLIM);
+ fprintf (dump_file, " -> ");
+ assume_range.dump (dump_file);
+ fputc ('\n', dump_file);
+ }
+ }
+ }
+}
+
+// This function Will update all the current value of interesting parameters.
+// It tries, in order:
+// a) a range found via path calculations.
+// b) range of the parm at SRC point in the IL. (either edge or stmt)
+// c) VARYING if those options fail.
+// The value is then unioned with any existing value, allowing for the
+// cumulation of all ranges leading to the return that return 1.
+
+void
+assume_query::update_parms (fur_source &src)
+{
+ // Merge any parameter values.
+ bitmap_iterator bi;
+ unsigned x;
+ EXECUTE_IF_SET_IN_BITMAP (m_parm_list, 0, x, bi)
+ {
+ tree name = ssa_name (x);
+ tree type = TREE_TYPE (name);
+
+ // Find a valu efrom calculations.
+ Value_Range glob_range (type);
+ if (!m_path.get_range (glob_range, name)
+ && !src.get_operand (glob_range, name))
+ glob_range.set_varying (type);
+
+ // Find any current value of parm, and combine them.
+ Value_Range parm_range (type);
+ if (m_parms.get_range (parm_range, name))
+ glob_range.union_ (parm_range);
+
+ // Set this new value.
+ m_parms.set_range (name, glob_range);
+ }
+ // Now reset the path values for the next path.
+ m_path.clear ();
+}
+
+
+// Evaluate PHI statement, using the provided LHS range.
+// Only process edge that are both taken and returns the LHS of the PHI.
+
+void
+assume_query::calculate_phi (gphi *phi, vrange &lhs_range)
+{
+ for (unsigned x= 0; x < gimple_phi_num_args (phi); x++)
+ {
+ tree arg = gimple_phi_arg_def (phi, x);
+ Value_Range arg_range (TREE_TYPE (arg));
+ edge e = gimple_phi_arg_edge (phi, x);
+ Value_Range edge_range (TREE_TYPE (arg));
+ // If we can't get an edge range, be conservative and assume the
+ // edge can be taken.
+ // NOte this can be either an ssa_name or a constant.
+ if (m_ranger->range_on_edge (edge_range, e, arg))
+ {
+ if (gimple_range_ssa_p (arg))
+ {
+ arg_range = lhs_range;
+ range_cast (arg_range, TREE_TYPE (arg));
+
+ // An SSA_NAME arg will start with the LHS value.
+ // Check the range of ARG on the edge leading here. If that range
+ // cannot be any value from the LHS of the PHI, then this branch
+ // will not be taken to return the LHS value and can be ignored.
+ arg_range.intersect (edge_range);
+ if (arg_range.undefined_p ())
+ continue;
+
+ // If the def is in the immediate preceeding block, process it
+ // with GORI to determine what values can produce this
+ // argument value. Otherwise there is more flow, so just query
+ // the edge for parm ranges and be conservative.
+ gimple *def_stmt = SSA_NAME_DEF_STMT (arg);
+ if (def_stmt && gimple_get_lhs (def_stmt) == arg
+ && gimple_bb (def_stmt) == e->src)
+ {
+ process_stmts (def_stmt, arg_range);
+ continue;
+ }
+ // Fall through to process the edge.
+ }
+ else
+ {
+ // If this is a constant value that differs from LHS, this
+ // edge cannot be taken and we can ignore it. Otherwise fall
+ // thorugh and process the edge.
+ edge_range.intersect (lhs_range);
+ if (edge_range.undefined_p ())
+ continue;
+ }
+ }
+ // If this point is reached the edge needs processing.
+ fur_edge src (e, m_ranger);
+ update_parms (src);
+ }
+}
+
+// Evaluate operand OP on statement S, using the provided LHS range.
+// If successful, set the range in path table, then visit OP's def stmt
+// if it is in the same BB.
+
+void
+assume_query::calculate_op (tree op, gimple *s, vrange &lhs, fur_source &src)
+{
+ basic_block bb = gimple_bb (s);
+ Value_Range op_range (TREE_TYPE (op));
+ if (src.gori () &&
+ src.gori ()->compute_operand_range (op_range, s, lhs, op, src)
+ && !op_range.varying_p ())
+ {
+ // Set the global range, merging if there is already a range.
+ m_path.merge_range (op, op_range);
+ gimple *def_stmt = SSA_NAME_DEF_STMT (op);
+ // Terminate if the patway leads to a different block as we
+ // are not analyzing flow.
+ if (def_stmt && gimple_get_lhs (def_stmt) == op
+ && gimple_bb (def_stmt) == bb)
+ calculate_stmt (def_stmt, op_range, src);
+ }
+}
+
+
+// Evaluate statement S which produces range LHS_RANGE. Use GORI to
+// determine what values the operands can have to produce the LHS,
+// and set these in the M_PATH table.
+
+void
+assume_query::calculate_stmt (gimple *s, vrange &lhs_range, fur_source &src)
+{
+ gimple_range_op_handler handler (s);
+ if (handler)
+ {
+ tree op = gimple_range_ssa_p (handler.operand1 ());
+ if (op)
+ calculate_op (op, s, lhs_range, src);
+ op = gimple_range_ssa_p (handler.operand2 ());
+ if (op)
+ calculate_op (op, s, lhs_range, src);
+ }
+}
+
+namespace {
+
+const pass_data pass_data_assumptions =
+{
+ GIMPLE_PASS, /* type */
+ "assumptions", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_TREE_ASSUMPTIONS, /* tv_id */
+ PROP_ssa, /* properties_required */
+ PROP_assumptions_done, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_end */
+};
+
+
+class pass_assumptions : public gimple_opt_pass
+{
+public:
+ pass_assumptions (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_assumptions, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ bool gate (function *fun) final override { return fun->assume_function; }
+ unsigned int execute (function *fun) final override
+ {
+ // Create a bitmap of all the paramters in this function.
+ // Invoke the assume_query to detemine what values these parameters
+ // have when the function returns TRUE, and set the globals value of
+ // those parameters in this function based on that. This will later be
+ // utilized by ranger when prcessing the builtin_assumer function.
+ auto_bitmap decls;
+ for (tree arg = DECL_ARGUMENTS (fun->decl); arg; arg = DECL_CHAIN (arg))
+ {
+ tree name = ssa_default_def (fun, arg);
+ if (!name || !gimple_range_ssa_p (name))
+ continue;
+ tree type = TREE_TYPE (name);
+ if (!Value_Range::supports_type_p (type))
+ continue;
+ bitmap_set_bit (decls, SSA_NAME_VERSION (name));
+ }
+ // If there are no parameters to map, simply return;
+ if (bitmap_empty_p (decls))
+ return TODO_discard_function;
+
+ gimple_ranger *ranger = enable_ranger (fun);
+
+ // This assume query will set any global values required.
+ assume_query query (ranger, fun, decls);
+
+ disable_ranger (fun);
+ if (dump_file)
+ gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
+
+ return TODO_discard_function;
+ }
+
+}; // class pass_assumptions
+
+} // anon namespace
+
+gimple_opt_pass *
+make_pass_assumptions (gcc::context *ctx)
+{
+ return new pass_assumptions (ctx);
+}
diff --git a/gcc/tree-vrp.cc b/gcc/tree-vrp.cc
index a36c08f469a..252a43427f8 100644
--- a/gcc/tree-vrp.cc
+++ b/gcc/tree-vrp.cc
@@ -1315,68 +1315,6 @@ public:
bool final_p;
}; // class pass_vrp
-const pass_data pass_data_assumptions =
-{
- GIMPLE_PASS, /* type */
- "assumptions", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_TREE_ASSUMPTIONS, /* tv_id */
- PROP_ssa, /* properties_required */
- PROP_assumptions_done, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- 0, /* todo_flags_end */
-};
-
-class pass_assumptions : public gimple_opt_pass
-{
-public:
- pass_assumptions (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_assumptions, ctxt)
- {}
-
- /* opt_pass methods: */
- bool gate (function *fun) final override { return fun->assume_function; }
- unsigned int execute (function *) final override
- {
- assume_query query;
- if (dump_file)
- fprintf (dump_file, "Assumptions :\n--------------\n");
-
- for (tree arg = DECL_ARGUMENTS (cfun->decl); arg; arg = DECL_CHAIN (arg))
- {
- tree name = ssa_default_def (cfun, arg);
- if (!name || !gimple_range_ssa_p (name))
- continue;
- tree type = TREE_TYPE (name);
- if (!Value_Range::supports_type_p (type))
- continue;
- Value_Range assume_range (type);
- if (query.assume_range_p (assume_range, name))
- {
- // Set the global range of NAME to anything calculated.
- set_range_info (name, assume_range);
- if (dump_file)
- {
- print_generic_expr (dump_file, name, TDF_SLIM);
- fprintf (dump_file, " -> ");
- assume_range.dump (dump_file);
- fputc ('\n', dump_file);
- }
- }
- }
- if (dump_file)
- {
- fputc ('\n', dump_file);
- gimple_dump_cfg (dump_file, dump_flags & ~TDF_DETAILS);
- if (dump_flags & TDF_DETAILS)
- query.dump (dump_file);
- }
- return TODO_discard_function;
- }
-
-}; // class pass_assumptions
-
} // anon namespace
gimple_opt_pass *
@@ -1396,9 +1334,3 @@ make_pass_fast_vrp (gcc::context *ctxt)
{
return new pass_vrp (ctxt, pass_data_fast_vrp, false);
}
-
-gimple_opt_pass *
-make_pass_assumptions (gcc::context *ctx)
-{
- return new pass_assumptions (ctx);
-}
--
2.45.0
From 4e8c8eed82e190f5f819e75088d8e05a851b41e7 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacl...@redhat.com>
Date: Fri, 1 Nov 2024 10:56:54 -0400
Subject: [PATCH 1/3] Make fur_edge accessible.
Move the decl of fur_edge out of the source file into the header file.
* gimple-range-fold.cc (class fur_edge): Relocate from here.
(fur_edge::fur_edge): Also move to:
* gimple-range-fold.h (class fur_edge): Relocate to here.
(fur_edge::fur_edge): Likewise.
---
gcc/gimple-range-fold.cc | 20 --------------------
gcc/gimple-range-fold.h | 14 ++++++++++++++
2 files changed, 14 insertions(+), 20 deletions(-)
diff --git a/gcc/gimple-range-fold.cc b/gcc/gimple-range-fold.cc
index 9c4ad1ee7b9..8020a1a3c63 100644
--- a/gcc/gimple-range-fold.cc
+++ b/gcc/gimple-range-fold.cc
@@ -108,26 +108,6 @@ fur_source::register_relation (edge e ATTRIBUTE_UNUSED,
{
}
-// This version of fur_source will pick a range up off an edge.
-
-class fur_edge : public fur_source
-{
-public:
- fur_edge (edge e, range_query *q = NULL);
- virtual bool get_operand (vrange &r, tree expr) override;
- virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
-private:
- edge m_edge;
-};
-
-// Instantiate an edge based fur_source.
-
-inline
-fur_edge::fur_edge (edge e, range_query *q) : fur_source (q)
-{
- m_edge = e;
-}
-
// Get the value of EXPR on edge m_edge.
bool
diff --git a/gcc/gimple-range-fold.h b/gcc/gimple-range-fold.h
index 7cbe15d05e5..a619a530769 100644
--- a/gcc/gimple-range-fold.h
+++ b/gcc/gimple-range-fold.h
@@ -142,6 +142,20 @@ protected:
relation_oracle *m_oracle;
};
+
+// This version of fur_source will pick a range up off an edge.
+
+class fur_edge : public fur_source
+{
+public:
+ fur_edge (edge e, range_query *q = NULL) : fur_source (q)
+ { m_edge = e; }
+ virtual bool get_operand (vrange &r, tree expr) override;
+ virtual bool get_phi_operand (vrange &r, tree expr, edge e) override;
+private:
+ edge m_edge;
+};
+
// This class uses ranges to fold a gimple statement producing a range for
// the LHS. The source of all operands is supplied via the fur_source class
// which provides a range_query as well as a source location and any other
--
2.45.0