ipa: Type-convert constants in jump functions during inlining (PR124777)

Message ID ri6wlyhzl8w.fsf@virgil.suse.cz
State New
Headers
Series ipa: Type-convert constants in jump functions during inlining (PR124777) |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Build passed
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Build passed

Commit Message

Martin Jambor April 8, 2026, 12:31 p.m. UTC
  Hi,

PR 124777 revealed that update_jump_functions_after_inlining does not
properly fold_convert constants when it propagates them from constant
jump functions to formerly pass-through ones, leading to expectations
of wrong constants in parameters leading to inserting bogus
builtin_unreachables during inlining.

This patch fixes it by calling ipacp_value_safe_for_type which is what
IPA-CP uses during its propagation and moved handling of the case to a
separate function.

Bootstrapped and LTO-bootstrapped and tested on x86_64-linux.  OK for
master?

Thanks,

Martin


gcc/ChangeLog:

2026-04-07  Martin Jambor  <mjambor@suse.cz>

	PR ipa/124777
	* ipa-cp.h (ipacp_value_safe_for_type): Declare.
	* ipa-cp.cc (ipacp_value_safe_for_type): Make public.
	* ipa-prop.cc (ipa_set_jf_cst_copy): Fix comment.
	(ipa_convert_prop_cst_jf): New function.
	(update_jump_functions_after_inlining): Handle the constant to
	pass-through case by calling ipa_convert_prop_cst_jf.

gcc/testsuite/ChangeLog:

2026-04-07  Martin Jambor  <mjambor@suse.cz>

	PR ipa/124777
	* gcc.dg/ipa/pr124777.c: New test.
---
 gcc/ipa-cp.cc                       |  2 +-
 gcc/ipa-cp.h                        |  1 +
 gcc/ipa-prop.cc                     | 44 +++++++++++++++++++++++------
 gcc/testsuite/gcc.dg/ipa/pr124777.c | 38 +++++++++++++++++++++++++
 4 files changed, 75 insertions(+), 10 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/ipa/pr124777.c
  

Patch

diff --git a/gcc/ipa-cp.cc b/gcc/ipa-cp.cc
index e96b1dc8391..337fca71013 100644
--- a/gcc/ipa-cp.cc
+++ b/gcc/ipa-cp.cc
@@ -1544,7 +1544,7 @@  initialize_node_lattices (struct cgraph_node *node)
    propagated to a parameter of type PARAM_TYPE, or return a fold-converted
    VALUE to PARAM_TYPE if that is possible.  Return NULL_TREE otherwise.  */
 
-static tree
+tree
 ipacp_value_safe_for_type (tree param_type, tree value)
 {
   if (!value)
diff --git a/gcc/ipa-cp.h b/gcc/ipa-cp.h
index 45da483e9ab..8191aac5c5b 100644
--- a/gcc/ipa-cp.h
+++ b/gcc/ipa-cp.h
@@ -323,6 +323,7 @@  bool ipa_vr_operation_and_type_effects (vrange &dst_vr,
 					const ipa_vr &src_vr,
 					enum tree_code operation,
 					tree dst_type, tree src_type);
+tree ipacp_value_safe_for_type (tree param_type, tree value);
 
 
 
diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index ea7519a17d3..dee7632eef0 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -680,8 +680,8 @@  ipa_set_jf_unknown (struct ipa_jump_func *jfunc)
   jfunc->type = IPA_JF_UNKNOWN;
 }
 
-/* Set JFUNC to be a copy of another jmp (to be used by jump function
-   combination code).  The two functions will share their rdesc.  */
+/* Set DST to be a copy of another SRC.  The two functions will share their
+   rdesc.  */
 
 static void
 ipa_set_jf_cst_copy (struct ipa_jump_func *dst,
@@ -693,6 +693,36 @@  ipa_set_jf_cst_copy (struct ipa_jump_func *dst,
   dst->value.constant = src->value.constant;
 }
 
+/* Set DST to be a copy of another jump function SRC but possibly adjust it to
+   a new passed type PARM_TYPE.  If the adjustment fails, the jump function can
+   end up being set to the unknown type.  If the conversion is not necessary or
+   it succeeds and if the destination rdesc has not been already used, the two
+   functions will share their rdesc.  */
+
+static void
+ipa_convert_prop_cst_jf (struct ipa_jump_func *dst,
+			 struct ipa_jump_func *src,
+			 tree parm_type)
+
+{
+  gcc_checking_assert (src->type == IPA_JF_CONST);
+  tree new_val = ipacp_value_safe_for_type (parm_type,
+					    ipa_get_jf_constant (src));
+  if (new_val)
+    {
+      bool rd = ipa_get_jf_pass_through_refdesc_decremented (dst);
+
+      dst->type = IPA_JF_CONST;
+      dst->value.constant.value = new_val;
+      if (!rd)
+	dst->value.constant.rdesc = src->value.constant.rdesc;
+      else
+	ipa_zap_jf_refdesc (dst);
+    }
+  else
+    ipa_set_jf_unknown (dst);
+}
+
 /* Set JFUNC to be a constant jmp function.  */
 
 static void
@@ -3863,13 +3893,9 @@  update_jump_functions_after_inlining (struct cgraph_edge *cs,
 		  ipa_set_jf_unknown (dst);
 		  break;
 		case IPA_JF_CONST:
-		  {
-		    bool rd = ipa_get_jf_pass_through_refdesc_decremented (dst);
-		    ipa_set_jf_cst_copy (dst, src);
-		    if (rd)
-		      ipa_zap_jf_refdesc (dst);
-		  }
-
+		  ipa_convert_prop_cst_jf (dst, src,
+					   ipa_get_type (old_inline_root_info,
+							 dst_fid));
 		  break;
 
 		case IPA_JF_PASS_THROUGH:
diff --git a/gcc/testsuite/gcc.dg/ipa/pr124777.c b/gcc/testsuite/gcc.dg/ipa/pr124777.c
new file mode 100644
index 00000000000..210eb7c36b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr124777.c
@@ -0,0 +1,38 @@ 
+/* { dg-do run } */
+/* { dg-options "-O2 -fno-early-inlining" } */
+
+int a;
+char b;
+void c() {
+    __builtin_exit(0);
+}
+
+typedef short (*t_d)(unsigned);
+
+static short __attribute__((noclone))
+d(unsigned f)
+{
+  if (f == (unsigned)(unsigned short)-1)
+    c ();
+  for (; a; a++)
+    ;
+}
+
+typedef short (*t_g)(unsigned, unsigned, unsigned short, t_d);
+
+static short  __attribute__((noclone))
+g(unsigned f, unsigned h, unsigned short i, t_d p_d) {
+  if (f || h)
+    p_d(i);
+}
+
+static unsigned  __attribute__((noclone))
+j(unsigned f, signed char h, t_d p_d, t_g p_g) {
+  p_g(b, 1, h, p_d);
+}
+
+int main() {
+  signed char e = -1;
+  j(0, e, d, g);
+  return 0;
+}