From ba55e50356632210db368c5f7a84b3e608d21b60 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Fri, 4 Feb 2022 16:50:31 -0500
Subject: [PATCH 3/3] Update non-null interface to provide better precision.
This changes the non-null interface to provide more granularity and faciltate
more precise queries using the new 2 bit system. This enables the new
register_side_effects code to more precisely track the non-null property.
PR tree-optimization/104288
gcc/
* gimple-range-cache.cc (non_null_ref::non_null_deref_p): Delete.
(non_null_ref::always_nonnull_p): New.
(non_null_ref::contains_nonnull_p): New.
(non_null_ref::is_nonnull_dominated_p): New.
(non_null_ref::adjust_range): Delete.
(non_null_ref::maybe_adjust_range: New.
(ranger_cache::range_of_def): Remove call to adjust_range.
(ranger_cache::entry_range): Remove call to adjust_range.
(ranger_cache::exit_range): Use contains_nonnull_p.
(ranger_cache::range_of_expr): Use always_nonnull_p.
(ranger_cache::fill_block_cache): Call contains_nonnull_p.
(ranger_cache::range_from_dom): Call contains_nonnull_p.
* gimple-range-cache.h (class non_null_ref): Change prototypes.
* gimple-range-path.cc (path_range_query::range_defined_in_block): Use
contains_nonnull_p.
(path_range_query::adjust_for_non_null_uses): Use contains_nonnull_p.
* gimple-range.cc (gimple_ranger::range_of_expr): Use always_nonnull_p.
(gimple_ranger::range_on_entry): Use is_nonnull_dominated_p.
(gimple_ranger::range_on_exit): Use contains_nonnull_p.
testsuite/gcc/
* gcc.dg/pr104288.c: New.
---
gcc/gimple-range-cache.cc | 89 +++++++++++++++++++--------------
gcc/gimple-range-cache.h | 7 +--
gcc/gimple-range-path.cc | 7 +--
gcc/gimple-range.cc | 16 ++++--
gcc/testsuite/gcc.dg/pr104288.c | 23 +++++++++
5 files changed, 94 insertions(+), 48 deletions(-)
create mode 100644 gcc/testsuite/gcc.dg/pr104288.c
@@ -92,64 +92,79 @@ non_null_ref::set_bb_state (tree name, basic_block bb, unsigned long val)
bitmap_set_aligned_chunk (m_nn[v], bb->index, 2, val);
}
-// 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.
+// Return true if the state of NAME is always non-zero in BB.
bool
-non_null_ref::non_null_deref_p (tree name, basic_block bb, bool search_dom)
+non_null_ref::always_nonnull_p (tree name, basic_block bb)
+{
+ if (POINTER_TYPE_P (TREE_TYPE (name))
+ && get_bb_state (name, bb) == NN_NON_ZERO)
+ return true;
+ return false;
+}
+
+// Return true if the state of NAME is non-zero at any point in BB.
+
+bool
+non_null_ref::contains_nonnull_p (tree name, basic_block bb)
+{
+ if (POINTER_TYPE_P (TREE_TYPE (name))
+ && get_bb_state (name, bb) >= NN_NON_ZERO)
+ return true;
+ return false;
+}
+
+// Return true if NAME has a non-null reference in a block dominated by BB.
+// If dominators are not available, simple return false.
+
+bool
+non_null_ref::is_nonnull_dominated_p (tree name, basic_block bb)
{
- unsigned v = SSA_NAME_VERSION (name);
if (!POINTER_TYPE_P (TREE_TYPE (name)))
return false;
- if (get_bb_state (name, bb) >= NN_NON_ZERO)
- return true;
+ // Ensure the tables are allocated and available.
+ get_bb_state (name, bb);
// See if any dominator has set non-zero.
- if (search_dom && dom_info_available_p (CDI_DOMINATORS))
+ if (dom_info_available_p (CDI_DOMINATORS))
{
// Search back to the Def block, or the top, whichever is closer.
+ // As long as it is non-zero somewhere in a pred block, its nonzero here.
+ unsigned v = SSA_NAME_VERSION (name);
basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (name));
+ gcc_checking_assert (bb && def_bb != bb);
basic_block def_dom = def_bb
? get_immediate_dominator (CDI_DOMINATORS, def_bb)
: NULL;
- for ( ;
- bb && bb != def_dom;
- bb = get_immediate_dominator (CDI_DOMINATORS, bb))
+ for (bb = get_immediate_dominator (CDI_DOMINATORS, bb);
+ bb && bb != def_dom;
+ bb = get_immediate_dominator (CDI_DOMINATORS, bb))
if (bitmap_get_aligned_chunk (m_nn[v], bb->index, 2) >= NN_NON_ZERO)
return true;
}
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.
+// If the range of R is not already non-null, and we are allowing non-null
+// ranges to be adjusted, then remove 0 from the range and return TRUE.
bool
-non_null_ref::adjust_range (irange &r, tree name, basic_block bb,
- bool search_dom)
+non_null_ref::maybe_adjust_range (irange &r)
{
// 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)
+ if (r.undefined_p () || !POINTER_TYPE_P (r.type ())
+ || 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;
+
+ // Remove zero from the range.
+ unsigned prec = TYPE_PRECISION (r.type ());
+ r.intersect (wi::one (prec), wi::max_value (prec, UNSIGNED));
+ return true;
}
// Allocate and populate the non-null state map for NAME.
@@ -1158,9 +1173,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.
@@ -1178,8 +1190,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.
@@ -1199,6 +1209,9 @@ ranger_cache::exit_range (irange &r, tree name, basic_block bb)
range_of_def (r, name, bb);
else
entry_range (r, name, bb);
+
+ if (m_non_null.contains_nonnull_p (name, bb))
+ m_non_null.maybe_adjust_range (r);
}
@@ -1221,6 +1234,9 @@ ranger_cache::range_of_expr (irange &r, tree name, gimple *stmt)
range_of_def (r, name, bb);
else
entry_range (r, name, bb);
+
+ if (m_non_null.always_nonnull_p (name, bb))
+ m_non_null.maybe_adjust_range (r);
return true;
}
@@ -1506,8 +1522,7 @@ ranger_cache::fill_block_cache (tree name, basic_block bb, basic_block def_bb)
// Regardless of whether we have visited pred or not, if the
// pred has a non-null reference, revisit this block.
- // Don't search the DOM tree.
- if (m_non_null.non_null_deref_p (name, pred, false))
+ if (m_non_null.contains_nonnull_p (name, pred))
{
if (DEBUG_RANGE_CACHE)
fprintf (dump_file, "nonnull: update ");
@@ -1582,7 +1597,7 @@ ranger_cache::range_from_dom (irange &r, tree name, basic_block bb)
}
// Flag if we see a non-null reference during this walk.
- if (m_non_null.non_null_deref_p (name, bb, false))
+ if (m_non_null.contains_nonnull_p (name, bb))
non_null = true;
// If range-on-entry is set in this block, it can be used.
@@ -33,9 +33,10 @@ class non_null_ref
public:
non_null_ref ();
~non_null_ref ();
- bool non_null_deref_p (tree name, basic_block bb, bool search_dom = true);
- bool adjust_range (irange &r, tree name, basic_block bb,
- bool search_dom = true);
+ bool always_nonnull_p (tree name, basic_block bb);
+ bool contains_nonnull_p (tree name, basic_block bb);
+ bool is_nonnull_dominated_p (tree name, basic_block bb);
+ bool maybe_adjust_range (irange &r);
void block_apply_nonnull (gimple *s);
void try_update_to_always_nonnull (gimple *s, tree name);
private:
@@ -354,8 +354,8 @@ path_range_query::range_defined_in_block (irange &r, tree name, basic_block bb)
r.set_varying (TREE_TYPE (name));
}
- if (bb)
- m_non_null.adjust_range (r, name, bb);
+ if (bb && m_non_null.contains_nonnull_p (name, bb))
+ m_non_null.maybe_adjust_range (r);
if (DEBUG_SOLVER && (bb || !r.varying_p ()))
{
@@ -525,7 +525,8 @@ path_range_query::adjust_for_non_null_uses (basic_block bb)
else
r.set_varying (TREE_TYPE (name));
- if (m_non_null.adjust_range (r, name, bb))
+ if (m_non_null.contains_nonnull_p (name, bb)
+ && m_non_null.maybe_adjust_range (r))
set_cache (r, name);
}
}
@@ -117,13 +117,13 @@ gimple_ranger::range_of_expr (irange &r, tree expr, gimple *stmt)
// If name is defined in this block, try to get an range from S.
if (def_stmt && gimple_bb (def_stmt) == bb)
- {
- range_of_stmt (r, def_stmt, expr);
- m_cache.m_non_null.adjust_range (r, expr, bb, true);
- }
+ range_of_stmt (r, def_stmt, expr);
// Otherwise OP comes from outside this block, use range on entry.
else
range_on_entry (r, bb, expr);
+ // If NAME is known to be non-null in this block, adjust the range.
+ if (r.varying_p () && m_cache.m_non_null.always_nonnull_p (expr, bb))
+ m_cache.m_non_null.maybe_adjust_range (r);
}
if (idx)
tracer.trailer (idx, "range_of_expr", true, expr, r);
@@ -152,7 +152,9 @@ gimple_ranger::range_on_entry (irange &r, basic_block bb, tree name)
if (m_cache.block_range (entry_range, bb, name))
r.intersect (entry_range);
- m_cache.m_non_null.adjust_range (r, name, bb, true);
+ // Pick up any nonnull info from the dominating predecessor.
+ if (r.varying_p () && m_cache.m_non_null.is_nonnull_dominated_p (name, bb))
+ m_cache.m_non_null.maybe_adjust_range (r);
if (idx)
tracer.trailer (idx, "range_on_entry", true, name, r);
@@ -186,6 +188,10 @@ gimple_ranger::range_on_exit (irange &r, basic_block bb, tree name)
range_of_expr (r, name, s);
else
range_on_entry (r, bb, name);
+
+ if (r.varying_p () && m_cache.m_non_null.contains_nonnull_p (name, bb))
+ m_cache.m_non_null.maybe_adjust_range (r);
+
gcc_checking_assert (r.undefined_p ()
|| range_compatible_p (r.type (), TREE_TYPE (name)));
new file mode 100644
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-evrp -fdelete-null-pointer-checks" } */
+/* { dg-skip-if "" { keeps_null_pointer_checks } } */
+
+void keep(int result) __attribute__((noipa));
+void keep(int result)
+{
+ if (result)
+ __builtin_exit(0);
+}
+
+void foo (void *p) __attribute__((nonnull(1)));
+
+void bar (void *p)
+{
+ keep (p == 0);
+ foo (p);
+ if (!p)
+ __builtin_abort ();
+}
+
+/* { dg-final { scan-tree-dump-not "abort" "evrp" } } */
+/* { dg-final { scan-tree-dump-times "== 0B;" 1 "evrp" } } */
--
2.17.2