aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimple-range-cache.cc
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2022-02-07 15:52:16 -0500
committerAndrew MacLeod <amacleod@redhat.com>2022-02-09 09:09:54 -0500
commitc6bb1db76b3ac127aff7dacf391fc1798a94bb7d (patch)
treeece35b744603236671d2ee0e8cc8fdf1c8f06828 /gcc/gimple-range-cache.cc
parentda2bf62d9e2a25f2d6a99176144c250b51fbdee7 (diff)
downloadgcc-c6bb1db76b3ac127aff7dacf391fc1798a94bb7d.zip
gcc-c6bb1db76b3ac127aff7dacf391fc1798a94bb7d.tar.gz
gcc-c6bb1db76b3ac127aff7dacf391fc1798a94bb7d.tar.bz2
Register non-null side effects properly.
This patch adjusts uses of nonnull to accurately reflect "somewhere in block". It also adds the ability to register statement side effects within a block for ranger which will apply for the rest of the block. PR tree-optimization/104288 gcc/ * gimple-range-cache.cc (non_null_ref::set_nonnull): New. (non_null_ref::adjust_range): Move to header. (ranger_cache::range_of_def): Don't check non-null. (ranger_cache::entry_range): Don't check non-null. (ranger_cache::range_on_edge): Check for nonnull on normal edges. (ranger_cache::update_to_nonnull): New. (non_null_loadstore): New. (ranger_cache::block_apply_nonnull): New. * gimple-range-cache.h (class non_null_ref): Update prototypes. (non_null_ref::adjust_range): Move to here and inline. (class ranger_cache): Update prototypes. * gimple-range-path.cc (path_range_query::range_defined_in_block): Do not search dominators. (path_range_query::adjust_for_non_null_uses): Ditto. * gimple-range.cc (gimple_ranger::range_of_expr): Check on-entry for def overrides. Do not check nonnull. (gimple_ranger::range_on_entry): Check dominators for nonnull. (gimple_ranger::range_on_edge): Check for nonnull on normal edges.. (gimple_ranger::register_side_effects): New. * gimple-range.h (gimple_ranger::register_side_effects): New. * tree-vrp.cc (rvrp_folder::fold_stmt): Call register_side_effects. gcc/testsuite/ * gcc.dg/pr104288.c: New.
Diffstat (limited to 'gcc/gimple-range-cache.cc')
-rw-r--r--gcc/gimple-range-cache.cc135
1 files changed, 101 insertions, 34 deletions
diff --git a/gcc/gimple-range-cache.cc b/gcc/gimple-range-cache.cc
index 16c881b..6131352 100644
--- a/gcc/gimple-range-cache.cc
+++ b/gcc/gimple-range-cache.cc
@@ -29,6 +29,10 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "gimple-range.h"
#include "tree-cfg.h"
+#include "target.h"
+#include "attribs.h"
+#include "gimple-iterator.h"
+#include "gimple-walk.h"
#define DEBUG_RANGE_CACHE (dump_file \
&& (param_ranger_debug & RANGER_DEBUG_CACHE))
@@ -50,6 +54,21 @@ non_null_ref::~non_null_ref ()
m_nn.release ();
}
+// This routine will update NAME in BB to be nonnull if it is not already.
+// return TRUE if the update happens.
+
+bool
+non_null_ref::set_nonnull (basic_block bb, tree name)
+{
+ gcc_checking_assert (gimple_range_ssa_p (name)
+ && POINTER_TYPE_P (TREE_TYPE (name)));
+ // Only process when its not already set.
+ if (non_null_deref_p (name, bb, false))
+ return false;
+ bitmap_set_bit (m_nn[SSA_NAME_VERSION (name)], bb->index);
+ return true;
+}
+
// Return true if NAME has a non-null dereference in block bb. If this is the
// first query for NAME, calculate the summary first.
// If SEARCH_DOM is true, the search the dominator tree as well.
@@ -87,35 +106,6 @@ non_null_ref::non_null_deref_p (tree name, basic_block bb, bool search_dom)
return false;
}
-// If NAME has a non-null dereference in block BB, adjust R with the
-// non-zero information from non_null_deref_p, and return TRUE. If
-// SEARCH_DOM is true, non_null_deref_p should search the dominator tree.
-
-bool
-non_null_ref::adjust_range (irange &r, tree name, basic_block bb,
- bool search_dom)
-{
- // Non-call exceptions mean we could throw in the middle of the
- // block, so just punt on those for now.
- if (cfun->can_throw_non_call_exceptions)
- return false;
-
- // We only care about the null / non-null property of pointers.
- if (!POINTER_TYPE_P (TREE_TYPE (name)))
- return false;
- if (r.undefined_p () || r.lower_bound () != 0 || r.upper_bound () == 0)
- return false;
- // Check if pointers have any non-null dereferences.
- if (non_null_deref_p (name, bb, search_dom))
- {
- // Remove zero from the range.
- unsigned prec = TYPE_PRECISION (TREE_TYPE (name));
- r.intersect (wi::one (prec), wi::max_value (prec, UNSIGNED));
- return true;
- }
- return false;
-}
-
// Allocate an populate the bitmap for NAME. An ON bit for a block
// index indicates there is a non-null reference in that block. In
// order to populate the bitmap, a quick run of all the immediate uses
@@ -1014,9 +1004,6 @@ ranger_cache::range_of_def (irange &r, tree name, basic_block bb)
else
r = gimple_range_global (name);
}
-
- if (bb)
- m_non_null.adjust_range (r, name, bb, false);
}
// Get the range of NAME as it occurs on entry to block BB.
@@ -1034,8 +1021,6 @@ ranger_cache::entry_range (irange &r, tree name, basic_block bb)
// Otherwise pick up the best available global value.
if (!m_on_entry.get_bb_range (r, name, bb))
range_of_def (r, name);
-
- m_non_null.adjust_range (r, name, bb, false);
}
// Get the range of NAME as it occurs on exit from block BB.
@@ -1089,6 +1074,9 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
if (gimple_range_ssa_p (expr))
{
exit_range (r, expr, e->src);
+ // If this is not an abnormal edge, check for a non-null exit.
+ if ((e->flags & (EDGE_EH | EDGE_ABNORMAL)) == 0)
+ m_non_null.adjust_range (r, expr, e->src, false);
int_range_max edge_range;
if (m_gori.outgoing_edge_range_p (edge_range, e, expr, *this))
r.intersect (edge_range);
@@ -1467,3 +1455,82 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block bb)
}
return true;
}
+
+// This routine will update NAME in block BB to the nonnull state.
+// It will then update the on-entry cache for this block to be non-null
+// if it isn't already.
+
+void
+ranger_cache::update_to_nonnull (basic_block bb, tree name)
+{
+ tree type = TREE_TYPE (name);
+ if (gimple_range_ssa_p (name) && POINTER_TYPE_P (type))
+ {
+ m_non_null.set_nonnull (bb, name);
+ // Update the on-entry cache for BB to be non-zero. Note this can set
+ // the on entry value in the DEF block, which can override the def.
+ int_range_max r;
+ exit_range (r, name, bb);
+ if (r.varying_p ())
+ {
+ r.set_nonzero (type);
+ m_on_entry.set_bb_range (name, bb, r);
+ }
+ }
+}
+
+// Adapted from infer_nonnull_range_by_dereference and check_loadstore
+// to process nonnull ssa_name OP in S. DATA contains the ranger_cache.
+
+static bool
+non_null_loadstore (gimple *s, tree op, tree, void *data)
+{
+ if (TREE_CODE (op) == MEM_REF || TREE_CODE (op) == TARGET_MEM_REF)
+ {
+ /* Some address spaces may legitimately dereference zero. */
+ addr_space_t as = TYPE_ADDR_SPACE (TREE_TYPE (op));
+ if (!targetm.addr_space.zero_address_valid (as))
+ {
+ tree ssa = TREE_OPERAND (op, 0);
+ basic_block bb = gimple_bb (s);
+ ((ranger_cache *)data)->update_to_nonnull (bb, ssa);
+ }
+ }
+ return false;
+}
+
+// This routine is used during a block walk to move the state of non-null for
+// any operands on stmt S to nonnull.
+
+void
+ranger_cache::block_apply_nonnull (gimple *s)
+{
+ if (!flag_delete_null_pointer_checks)
+ return;
+ if (is_a<gphi *> (s))
+ return;
+ if (gimple_code (s) == GIMPLE_ASM || gimple_clobber_p (s))
+ return;
+ if (is_a<gcall *> (s))
+ {
+ tree fntype = gimple_call_fntype (s);
+ bitmap nonnullargs = get_nonnull_args (fntype);
+ // Process any non-null arguments
+ if (nonnullargs)
+ {
+ basic_block bb = gimple_bb (s);
+ for (unsigned i = 0; i < gimple_call_num_args (s); i++)
+ {
+ if (bitmap_empty_p (nonnullargs) || bitmap_bit_p (nonnullargs, i))
+ {
+ tree op = gimple_call_arg (s, i);
+ update_to_nonnull (bb, op);
+ }
+ }
+ BITMAP_FREE (nonnullargs);
+ }
+ // Fallthru and walk load/store ops now.
+ }
+ walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore,
+ non_null_loadstore);
+}