From c4a1e28b5b1dd8f22e7d87f34961596a816c7ad7 Mon Sep 17 00:00:00 2001
From: Andrew MacLeod <amacleod@redhat.com>
Date: Wed, 2 Feb 2022 14:44:57 -0500
Subject: [PATCH 2/3] Register side effects during ranger block walk.
This patch adds the ability to register statement side effects within a block
for ranger. This is currently only for tracking non-null values.
* gimple-range-cache.cc (non_null_ref::try_update_to_always_nonnull):
New.
(non_null_ref::infer_nonnull_call_attributes): New.
(non_null_loadstore): New.
(non_null_ref::block_apply_nonnull): New.
* gimple-range-cache.h (class non_null_ref): New prototypes.
* gimple-range.cc (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/gimple-range-cache.cc | 106 ++++++++++++++++++++++++++++++++++++++
gcc/gimple-range-cache.h | 3 ++
gcc/gimple-range.cc | 11 ++++
gcc/gimple-range.h | 1 +
gcc/tree-vrp.cc | 8 +--
5 files changed, 126 insertions(+), 3 deletions(-)
@@ -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))
@@ -197,6 +201,108 @@ non_null_ref::process_name (tree name)
}
}
+// This routine will update NAME on stmt S to always_nonnull state, if it
+// is in contains_nonull state. This is used during a block walk to move
+// NAME to known nonnull.
+
+void
+non_null_ref::try_update_to_always_nonnull (gimple *s, tree name)
+{
+ if (gimple_range_ssa_p (name) && POINTER_TYPE_P (TREE_TYPE (name)))
+ {
+ unsigned long state = get_bb_state (name, gimple_bb (s));
+ // Only process when both conditions exist in the BB.
+ if (state != NN_BOTH)
+ return;
+ // From this point forward, we'll be NON-NULL for sure if we see one.
+ set_bb_state (name, gimple_bb (s), NN_NON_ZERO);
+ }
+}
+
+// Adapted from infer_nonnull_range_by_attribute for calls to process
+// all operands which have the nonnull attribute set in stmt.
+
+void
+non_null_ref::infer_nonnull_call_attributes (gcall *stmt)
+{
+ if (gimple_call_internal_p (stmt))
+ return;
+
+ tree fntype = gimple_call_fntype (stmt);
+ tree attrs = TYPE_ATTRIBUTES (fntype);
+ for (; attrs; attrs = TREE_CHAIN (attrs))
+ {
+ attrs = lookup_attribute ("nonnull", attrs);
+
+ /* If "nonnull" wasn't specified, we know nothing about
+ the argument. */
+ if (attrs == NULL_TREE)
+ return;
+
+ /* Check if "nonnull" applies to all the arguments. */
+ if (TREE_VALUE (attrs) == NULL_TREE)
+ {
+ for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
+ {
+ tree op = gimple_call_arg (stmt, i);
+ try_update_to_always_nonnull (stmt, op);
+ }
+ return;
+ }
+
+ /* Now see whats in this nonnull list. */
+ for (tree t = TREE_VALUE (attrs); t; t = TREE_CHAIN (t))
+ {
+ unsigned int idx = TREE_INT_CST_LOW (TREE_VALUE (t)) - 1;
+ if (idx < gimple_call_num_args (stmt))
+ {
+ tree op = gimple_call_arg (stmt, idx);
+ try_update_to_always_nonnull (stmt, op);
+ }
+ }
+ }
+}
+
+// Adapted from infer_nonnull_range_by_dereference and check_loadstore
+// to work for all operands.
+
+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);
+ ((non_null_ref *)data)->try_update_to_always_nonnull (s, 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 always nonnull.
+
+void
+non_null_ref::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))
+ {
+ infer_nonnull_call_attributes (as_a<gcall *> (s));
+ return;
+ }
+ walk_stmt_load_store_ops (s, (void *)this, non_null_loadstore,
+ non_null_loadstore);
+}
+
// -------------------------------------------------------------------------
// This class represents the API into a cache of ranges for an SSA_NAME.
@@ -36,9 +36,12 @@ public:
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);
+ void block_apply_nonnull (gimple *s);
+ void try_update_to_always_nonnull (gimple *s, tree name);
private:
vec <bitmap> m_nn;
void process_name (tree name);
+ void infer_nonnull_call_attributes (gcall *stmt);
unsigned long get_bb_state (tree name, basic_block bb);
void set_bb_state (tree name, basic_block bb, unsigned long);
bitmap_obstack m_bitmaps;
@@ -35,6 +35,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-scalar-evolution.h"
#include "gimple-range.h"
#include "gimple-fold.h"
+#include "gimple-walk.h"
gimple_ranger::gimple_ranger () :
non_executable_edge_flag (cfun),
@@ -436,6 +437,16 @@ gimple_ranger::fold_stmt (gimple_stmt_iterator *gsi, tree (*valueize) (tree))
return ret;
}
+// Called during dominator walks to register any side effects that take effect
+// from this point forward. Current release is only for tracking non-null
+// within a block.
+
+void
+gimple_ranger::register_side_effects (gimple *s)
+{
+ m_cache.m_non_null.block_apply_nonnull (s);
+}
+
// This routine will export whatever global ranges are known to GCC
// SSA_RANGE_NAME_INFO and SSA_NAME_PTR_INFO fields.
@@ -60,6 +60,7 @@ public:
void dump_bb (FILE *f, basic_block bb);
auto_edge_flag non_executable_edge_flag;
bool fold_stmt (gimple_stmt_iterator *gsi, tree (*) (tree));
+ void register_side_effects (gimple *s);
protected:
bool fold_range_internal (irange &r, gimple *s, tree name);
void prefill_name (irange &r, tree name);
@@ -4309,9 +4309,11 @@ public:
bool fold_stmt (gimple_stmt_iterator *gsi) OVERRIDE
{
- if (m_simplifier.simplify (gsi))
- return true;
- return m_ranger->fold_stmt (gsi, follow_single_use_edges);
+ bool ret = m_simplifier.simplify (gsi);
+ if (!ret)
+ ret = m_ranger->fold_stmt (gsi, follow_single_use_edges);
+ m_ranger->register_side_effects (gsi_stmt (*gsi));
+ return ret;
}
private:
--
2.17.2