Hi,

On Tue, Nov 05 2024, Jan Hubicka wrote:
>> Hi,
>> 
>> I believe that the current function ipa_range_set_and_normalize lacks
>> a check that a base of an ADDR_EXPR lacks a test whether the base
>> really cannot be NULL, so this patch adds it.  Moreover, I never liked
>> the name as I do not think it makes the value of ranges any more
>> normal but rather just special-cases non-zero ip_invariant pointers.
>> Therefore, I have given it a different name and moved it to a .cc
>> file, our LTO bootstrap should inline (and/or split) it if necessary
>> anyway.
>> 
>> Bootstrapped and tested on x86_64-linux, the whole patch series has
>> additionally passed LTO and profiled-LTO bootstrap on the same platform
>> and a bootstrap and testsuite on ppc64-linux.  Aarch64-linux bootstrap
>> and testing is in progress.  OK for master is that passes too?
>> 
>> Thanks,
>> 
>> Martin
>> 
>> 
>> gcc/ChangeLog:
>> 
>> 2024-11-04  Martin Jambor  <mjam...@suse.cz>
>> 
>>      * ipa-prop.h (ipa_get_range_from_ip_invariant): Declare.
>>      (ipa_range_set_and_normalize): Remove.
>>      * ipa-prop.cc (ipa_get_range_from_ip_invariant): New function.
>>      * ipa-cp.cc (ipa_vr_intersect_with_arith_jfunc): Use
>>      ipa_get_range_from_ip_invariant instead of
>>      ipa_range_set_and_normalize.
>>      * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Likewise.
>> +/* Given VAL that conforms to is_gimple_ip_invariant, produce a VRANGE that
>> +   represents it as a range.  */
>> +
>> +void
>> +ipa_get_range_from_ip_invariant (vrange &r, tree val)
>> +{
>> +  if (TREE_CODE (val) == ADDR_EXPR)
>> +    {
>> +      bool strict_overflow = false;
>> +      if (tree_single_nonzero_warnv_p (val, &strict_overflow))
> this function uses maybe_nonzero_address that in turn checks
> symtab_node::nonzero_address which uses flag_delete_null_pointer_checks
> to verify that we can assume that defined symbols are non-NULL.
> Now -fdelete-null-pointer-checks is defined in common.opt as
> optimization and thus is stored in TREE_OPTIMIZATION_NODE.
>
> The patch is definitely an improvement. But it seems to me that we need
> to add function argument to tree_single_nonzero_warnv_p and propagate it
> down to symtab_node::nonzero_address so it can query in correct function
> context. This can be done incrementally, so the patch is OK.
>

I was looking for the use of the flag but somehow did not see it and in
some less-than-ideal state of mind assumed it must therefore be a global
option.  Below is a patch that takes that into account.

The patch has been pre-approved by Honza and which has passed bootstrap
and testing on x86_64 and together with other two patches also on
ppc64le-linux and an LTO bootstrap on x86_64-linux, so I am going to
push it to master in a few moments.

Thanks,

Martin


---------- 8< ----------

I believe that the current function ipa_range_set_and_normalize lacks
a check that a base of an ADDR_EXPR lacks a test whether the base
really cannot be NULL, so this patch adds it.  Moreover, I never liked
the name as I do not think it makes the value of ranges any more
normal but rather just special-cases non-zero ip_invariant pointers.
Therefore, I have given it a different name and moved it to a .cc
file, our LTO bootstrap should inline (and/or split) it if necessary
anyway.

Because, as Honza correctly pointed out, deriving non-NULLness from a
pointer depends on flag_delete_null_pointer_checks which is an
optimization flag and thus depends on a given function, in this
version of the patch ipa_get_range_from_ip_invariant gets a
context_node parameter for that purpose.  This then needs to be used
within symtab_node::nonzero_address which gets a special overload in
which the value of the flag can be provided as a parameter.

gcc/ChangeLog:

2024-12-11  Martin Jambor  <mjam...@suse.cz>

        * cgraph.h (symtab_node): Add a new overload of nonzero_address.
        * symtab.cc (symtab_node::nonzero_address): Add a new overload whith a
        parameter for delete_null_pointer_checks.  Make the original overload
        call the new one which has retains the actual implementation.
        * ipa-prop.h (ipa_get_range_from_ip_invariant): Declare.
        (ipa_range_set_and_normalize): Remove.
        * ipa-prop.c (ipa_get_range_from_ip_invariant): New function.
        (ipa_range_set_and_normalize): Remove.
        * ipa-cp.cc (ipa_vr_intersect_with_arith_jfunc): Add a new parameter
        context_node. Use ipa_get_range_from_ip_invariant instead of
        ipa_range_set_and_normalize and pass to it the new parameter.
        (ipa_value_range_from_jfunc): Pass cs->caller as the context_node to
        ipa_vr_intersect_with_arith_jfunc.
        (propagate_vr_across_jump_function): Likewise.
        (ipa_get_range_from_ip_invariant): New function.
        * ipa-fnsummary.cc (evaluate_conditions_for_known_args): Use
        ipa_get_range_from_ip_invariant instead of ipa_range_set_and_normalize
---
 gcc/cgraph.h         |  4 ++++
 gcc/ipa-cp.cc        | 12 ++++++++----
 gcc/ipa-fnsummary.cc |  4 ++--
 gcc/ipa-prop.cc      | 37 +++++++++++++++++++++++++++++++++++++
 gcc/ipa-prop.h       | 15 +--------------
 gcc/symtab.cc        | 21 +++++++++++++++------
 6 files changed, 67 insertions(+), 26 deletions(-)

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 50bae96de4c..9b4cb6383af 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -431,6 +431,10 @@ public:
   /* Return true if ONE and TWO are part of the same COMDAT group.  */
   inline bool in_same_comdat_group_p (symtab_node *target);
 
+  /* Return true if symbol is known to be nonzero, assume that
+     flag_delete_null_pointer_checks is equal to delete_null_pointer_checks.  
*/
+  bool nonzero_address (bool delete_null_pointer_checks);
+
   /* Return true if symbol is known to be nonzero.  */
   bool nonzero_address ();
 
diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index a664bc03f62..5d7b3d25df5 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1693,11 +1693,14 @@ ipa_vr_operation_and_type_effects (vrange &dst_vr,
 
 /* Given a PASS_THROUGH jump function JFUNC that takes as its source SRC_VR of
    SRC_TYPE and the result needs to be DST_TYPE, if any value range information
-   can be deduced at all, intersect VR with it.  */
+   can be deduced at all, intersect VR with it.  CONTEXT_NODE is the call graph
+   node representing the function for which optimization flags should be
+   evaluated.  */
 
 static void
 ipa_vr_intersect_with_arith_jfunc (vrange &vr,
                                   ipa_jump_func *jfunc,
+                                  cgraph_node *context_node,
                                   const value_range &src_vr,
                                   tree src_type,
                                   tree dst_type)
@@ -1720,7 +1723,7 @@ ipa_vr_intersect_with_arith_jfunc (vrange &vr,
   if (!handler)
     return;
   value_range op_vr (TREE_TYPE (operand));
-  ipa_range_set_and_normalize (op_vr, operand);
+  ipa_get_range_from_ip_invariant (op_vr, operand, context_node);
 
   tree operation_type;
   if (TREE_CODE_CLASS (operation) == tcc_comparison)
@@ -1776,7 +1779,8 @@ ipa_value_range_from_jfunc (vrange &vr,
       value_range srcvr;
       (*sum->m_vr)[idx].get_vrange (srcvr);
 
-      ipa_vr_intersect_with_arith_jfunc (vr, jfunc, srcvr, src_type, 
parm_type);
+      ipa_vr_intersect_with_arith_jfunc (vr, jfunc, cs->caller, srcvr, 
src_type,
+                                        parm_type);
     }
 }
 
@@ -2562,7 +2566,7 @@ propagate_vr_across_jump_function (cgraph_edge *cs, 
ipa_jump_func *jfunc,
 
       if (ipa_get_jf_pass_through_operation (jfunc) == NOP_EXPR
          || !ipa_edge_within_scc (cs))
-       ipa_vr_intersect_with_arith_jfunc (vr, jfunc,
+       ipa_vr_intersect_with_arith_jfunc (vr, jfunc, cs->caller,
                                           src_lats->m_value_range.m_vr,
                                           operand_type, param_type);
     }
diff --git a/gcc/ipa-fnsummary.cc b/gcc/ipa-fnsummary.cc
index 3f5e09960ef..6799ffe0b9a 100644
--- a/gcc/ipa-fnsummary.cc
+++ b/gcc/ipa-fnsummary.cc
@@ -518,7 +518,7 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
                      value_range op0 (TREE_TYPE (op->val[0]));
                      range_op_handler handler (op->code);
 
-                     ipa_range_set_and_normalize (op0, op->val[0]);
+                     ipa_get_range_from_ip_invariant (op0, op->val[0], node);
 
                      if (!handler
                          || !res.supports_type_p (op->type)
@@ -537,7 +537,7 @@ evaluate_conditions_for_known_args (struct cgraph_node 
*node,
                  value_range val_vr (TREE_TYPE (c->val));
                  range_op_handler handler (c->code);
 
-                 ipa_range_set_and_normalize (val_vr, c->val);
+                 ipa_get_range_from_ip_invariant (val_vr, c->val, node);
 
                  if (!handler
                      || !val_vr.supports_type_p (TREE_TYPE (c->val))
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index f0b915ba2be..0daa950985b 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -2312,6 +2312,43 @@ ipa_set_jfunc_vr (ipa_jump_func *jf, const ipa_vr &vr)
   ipa_set_jfunc_vr (jf, tmp);
 }
 
+/* Given VAL that conforms to is_gimple_ip_invariant, produce a VRANGE that
+   represents it as a range.  CONTEXT_NODE is the call graph node representing
+   the function for which optimization flags should be evaluated.  */
+
+void
+ipa_get_range_from_ip_invariant (vrange &r, tree val, cgraph_node 
*context_node)
+{
+  if (TREE_CODE (val) == ADDR_EXPR)
+    {
+      symtab_node *symbol;
+      tree base = TREE_OPERAND (val, 0);
+      if (!DECL_P (base))
+       {
+         r.set_varying (TREE_TYPE (val));
+         return;
+       }
+      if (!decl_in_symtab_p (base))
+       {
+         r.set_nonzero (TREE_TYPE (val));
+         return;
+       }
+      if (!(symbol = symtab_node::get (base)))
+       {
+         r.set_varying (TREE_TYPE (val));
+         return;
+       }
+
+      bool delete_null_pointer_checks
+       = opt_for_fn (context_node->decl, flag_delete_null_pointer_checks);
+      if (symbol->nonzero_address (delete_null_pointer_checks))
+       r.set_nonzero (TREE_TYPE (val));
+      else
+       r.set_varying (TREE_TYPE (val));
+    }
+  else
+    r.set (val, val);
+}
 
 /* If T is an SSA_NAME that is the result of a simple type conversion statement
    from an integer type to another integer type which is known to be able to
diff --git a/gcc/ipa-prop.h b/gcc/ipa-prop.h
index 1ff71aba830..d77340bfb6e 100644
--- a/gcc/ipa-prop.h
+++ b/gcc/ipa-prop.h
@@ -1258,7 +1258,7 @@ tree ipcp_get_aggregate_const (struct function *func, 
tree parm, bool by_ref,
                               HOST_WIDE_INT bit_size);
 bool unadjusted_ptr_and_unit_offset (tree op, tree *ret,
                                     poly_int64 *offset_ret);
-
+void ipa_get_range_from_ip_invariant (vrange &r, tree val, cgraph_node *node);
 void ipa_prop_cc_finalize (void);
 
 /* From tree-sra.cc:  */
@@ -1267,19 +1267,6 @@ tree build_ref_for_offset (location_t, tree, poly_int64, 
bool, tree,
 
 /* In ipa-cp.cc  */
 void ipa_cp_cc_finalize (void);
-
-/* Set R to the range of [VAL, VAL] while normalizing addresses to
-   non-zero.  */
-
-inline void
-ipa_range_set_and_normalize (vrange &r, tree val)
-{
-  if (TREE_CODE (val) == ADDR_EXPR)
-    r.set_nonzero (TREE_TYPE (val));
-  else
-    r.set (val, val);
-}
-
 bool ipa_return_value_range (value_range &range, tree decl);
 void ipa_record_return_value_range (value_range val);
 bool ipa_jump_functions_equivalent_p (ipa_jump_func *jf1, ipa_jump_func *jf2);
diff --git a/gcc/symtab.cc b/gcc/symtab.cc
index 5be463ff768..3804383a4e1 100644
--- a/gcc/symtab.cc
+++ b/gcc/symtab.cc
@@ -2207,10 +2207,11 @@ symtab_node::get_partitioning_class (void)
   return SYMBOL_PARTITION;
 }
 
-/* Return true when symbol is known to be non-zero.  */
+/* Return true when symbol is known to be non-zero, assume that
+   flag_delete_null_pointer_checks is equal to delete_null_pointer_checks.  */
 
 bool
-symtab_node::nonzero_address ()
+symtab_node::nonzero_address (bool delete_null_pointer_checks)
 {
   /* Weakrefs may be NULL when their target is not defined.  */
   if (alias && weakref)
@@ -2234,7 +2235,7 @@ symtab_node::nonzero_address ()
          if (target->resolution != LDPR_UNKNOWN
              && target->resolution != LDPR_UNDEF
              && !target->can_be_discarded_p ()
-             && flag_delete_null_pointer_checks)
+             && delete_null_pointer_checks)
            return true;
          return false;
        }
@@ -2251,7 +2252,7 @@ symtab_node::nonzero_address ()
 
      When parsing, beware the cases when WEAK attribute is added later.  */
   if ((!DECL_WEAK (decl) || DECL_COMDAT (decl))
-      && flag_delete_null_pointer_checks)
+      && delete_null_pointer_checks)
     {
       refuse_visibility_changes = true;
       return true;
@@ -2262,7 +2263,7 @@ symtab_node::nonzero_address ()
      Play safe for flag_delete_null_pointer_checks where weak definition may
      be re-defined by NULL.  */
   if (definition && !DECL_EXTERNAL (decl)
-      && (flag_delete_null_pointer_checks || !DECL_WEAK (decl)))
+      && (delete_null_pointer_checks || !DECL_WEAK (decl)))
     {
       if (!DECL_WEAK (decl))
         refuse_visibility_changes = true;
@@ -2273,11 +2274,19 @@ symtab_node::nonzero_address ()
   if (resolution != LDPR_UNKNOWN
       && resolution != LDPR_UNDEF
       && !can_be_discarded_p ()
-      && flag_delete_null_pointer_checks)
+      && delete_null_pointer_checks)
     return true;
   return false;
 }
 
+/* Return true when symbol is known to be non-zero.  */
+
+bool
+symtab_node::nonzero_address ()
+{
+  return nonzero_address (flag_delete_null_pointer_checks);
+}
+
 /* Return 0 if symbol is known to have different address than S2,
    Return 1 if symbol is known to have same address as S2,
    return -1 otherwise.
-- 
2.47.1

Reply via email to