]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
ipa: Skip widening type conversions in jump function constructions
authorMartin Jambor <mjambor@suse.cz>
Tue, 17 Dec 2024 10:17:14 +0000 (11:17 +0100)
committerMartin Jambor <jamborm@gcc.gnu.org>
Tue, 17 Dec 2024 10:17:59 +0000 (11:17 +0100)
Originally, we did not stream any formal parameter types into WPA and
were generally very conservative when it came to type mismatches in
IPA-CP.  Over the time, mismatches that happen in code and blew up in
WPA made us to be much more resilient and also to stream the types of
the parameters which we now use commonly.

With that information, we can safely skip conversions when looking at
the IL from which we build jump functions and then simply fold convert
the constants and ranges to the resulting type, as long as we are
careful that performing the corresponding folding of constants gives
the corresponding results.  In order to do that, we must ensure that
the old value can be represented in the new one without any loss.
With this change, we can nicely propagate non-NULLness in IPA-VR as
demonstrated with the new test case.

I have gone through all other uses of (all components of) jump
functions which could be affected by this and verified they do indeed
check types and can handle mismatches.

gcc/ChangeLog:

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

* ipa-prop.cc: Include vr-values.h.
(skip_a_safe_conversion_op): New function.
(ipa_compute_jump_functions_for_edge): Use it.

gcc/testsuite/ChangeLog:

2024-11-01  Martin Jambor  <mjambor@suse.cz>

* gcc.dg/ipa/vrp9.c: New test.

gcc/ipa-prop.cc
gcc/testsuite/gcc.dg/ipa/vrp9.c [new file with mode: 0644]

index 3d72794e37c456e58c07cc7bd4ab81980eba2494..ae309ec78a2dbbce788b47633c030b714cf00d0f 100644 (file)
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "attr-fnspec.h"
 #include "gimple-range.h"
 #include "value-range-storage.h"
+#include "vr-values.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -2311,6 +2312,44 @@ ipa_set_jfunc_vr (ipa_jump_func *jf, const ipa_vr &vr)
   ipa_set_jfunc_vr (jf, tmp);
 }
 
+
+/* 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
+   represent the values the operand of the conversion can hold, return the
+   operand of that conversion, otherwise return T.  */
+
+static tree
+skip_a_safe_conversion_op (tree t)
+{
+  if (TREE_CODE (t) != SSA_NAME
+      || SSA_NAME_IS_DEFAULT_DEF (t))
+    return t;
+
+  gimple *def = SSA_NAME_DEF_STMT (t);
+  if (!is_gimple_assign (def)
+      || !CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (def))
+      || !INTEGRAL_TYPE_P (TREE_TYPE (t))
+      || !INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (def))))
+    return t;
+
+  tree rhs1 = gimple_assign_rhs1 (def);
+  if (TYPE_PRECISION (TREE_TYPE (t))
+      >= TYPE_PRECISION (TREE_TYPE (rhs1)))
+    return gimple_assign_rhs1 (def);
+
+  value_range vr (TREE_TYPE (rhs1));
+  if (!get_range_query (cfun)->range_of_expr (vr, rhs1, def)
+      || vr.undefined_p ())
+    return t;
+
+  irange &ir = as_a <irange> (vr);
+  if (range_fits_type_p (&ir, TYPE_PRECISION (TREE_TYPE (t)),
+                        TYPE_SIGN (TREE_TYPE (t))))
+      return gimple_assign_rhs1 (def);
+
+  return t;
+}
+
 /* Compute jump function for all arguments of callsite CS and insert the
    information in the jump_functions array in the ipa_edge_args corresponding
    to this callsite.  */
@@ -2415,6 +2454,7 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
            gcc_assert (!jfunc->m_vr);
        }
 
+      arg = skip_a_safe_conversion_op (arg);
       if (is_gimple_ip_invariant (arg)
          || (VAR_P (arg)
              && is_global_var (arg)
diff --git a/gcc/testsuite/gcc.dg/ipa/vrp9.c b/gcc/testsuite/gcc.dg/ipa/vrp9.c
new file mode 100644 (file)
index 0000000..461a2e7
--- /dev/null
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized"  }  */
+
+int some_f1 (int);
+int some_f2 (int);
+int some_f3 (int);
+
+void remove_this_call ();
+
+int g;
+
+static int __attribute__((noinline))
+bar (int p)
+{
+  if (p)
+    remove_this_call ();
+  return g++;
+}
+
+static int __attribute__((noinline))
+foo (int (*f)(int))
+{
+  return bar (f == (void *)0);
+}
+
+int
+baz1 (void)
+{
+  int (*f)(int);
+  if (g)
+    f = some_f1;
+  else
+    f = some_f2;
+  return foo (f);
+}
+
+int
+baz2 (void)
+{
+  int (*f)(int);
+  if (g)
+    f = some_f2;
+  else
+    f = some_f3;
+  return foo (f);
+}
+
+/* { dg-final { scan-tree-dump-not "remove_this_call"  "optimized"  } } */