https://gcc.gnu.org/g:0b004c92f5ea239936a403a2a757e12ca82ce6d8

commit r16-960-g0b004c92f5ea239936a403a2a757e12ca82ce6d8
Author: Martin Jambor <mjam...@suse.cz>
Date:   Thu May 29 16:32:04 2025 +0200

    ipa: When inlining, don't combine PT JFs changing signedness (PR120295)
    
    In GCC 15 we allowed jump-function generation code to skip over a
    type-cast converting one integer to another as long as the latter can
    hold all the values of the former or has at least the same precision.
    This works well for IPA-CP where we do then evaluate each jump
    function as we propagate values and value-ranges.  However, the
    test-case in PR 120295 shows a problem with inlining, where we combine
    pass-through jump-functions so that they are always relative to the
    function which is the root of the inline tree.  Unfortunately, we are
    happy to combine also those with type-casts to a different signedness
    which makes us use sign zero extension for the expected value ranges
    where we should have used sign extension.  When the value-range which
    then leads to wrong insertion of a call to builtin_unreachable is
    being computed, the information about an existence of a intermediary
    signed type has already been lost during previous inlining.
    
    This patch simply blocks combining such jump-functions so that it is
    back-portable to GCC 15.  Once we switch pass-through jump functions
    to use a vector of operations rather than having room for just one, we
    will be able to address this situation with adding an extra conversion
    instead.
    
    gcc/ChangeLog:
    
    2025-05-19  Martin Jambor  <mjam...@suse.cz>
    
            PR ipa/120295
            * ipa-prop.cc (update_jump_functions_after_inlining): Do not
            combine pass-through jump functions with type-casts changing
            signedness.
    
    gcc/testsuite/ChangeLog:
    
    2025-05-19  Martin Jambor  <mjam...@suse.cz>
    
            PR ipa/120295
            * gcc.dg/ipa/pr120295.c: New test.

Diff:
---
 gcc/ipa-prop.cc                     | 28 ++++++++++++++++
 gcc/testsuite/gcc.dg/ipa/pr120295.c | 66 +++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+)

diff --git a/gcc/ipa-prop.cc b/gcc/ipa-prop.cc
index 24a538034e31..84d4fb5db674 100644
--- a/gcc/ipa-prop.cc
+++ b/gcc/ipa-prop.cc
@@ -3330,6 +3330,10 @@ update_jump_functions_after_inlining (struct cgraph_edge 
*cs,
   ipa_edge_args *args = ipa_edge_args_sum->get (e);
   if (!args)
     return;
+  ipa_node_params *old_inline_root_info = ipa_node_params_sum->get 
(cs->callee);
+  ipa_node_params *new_inline_root_info
+    = ipa_node_params_sum->get (cs->caller->inlined_to
+                               ? cs->caller->inlined_to : cs->caller);
   int count = ipa_get_cs_argument_count (args);
   int i;
 
@@ -3541,6 +3545,30 @@ update_jump_functions_after_inlining (struct cgraph_edge 
*cs,
                    enum tree_code operation;
                    operation = ipa_get_jf_pass_through_operation (src);
 
+                   tree old_ir_ptype = ipa_get_type (old_inline_root_info,
+                                                     dst_fid);
+                   tree new_ir_ptype = ipa_get_type (new_inline_root_info,
+                                                     formal_id);
+                   if (!useless_type_conversion_p (old_ir_ptype, new_ir_ptype))
+                     {
+                       /* Jump-function construction now permits type-casts
+                          from an integer to another if the latter can hold
+                          all values or has at least the same precision.
+                          However, as we're combining multiple pass-through
+                          functions together, we are losing information about
+                          signedness and thus if conversions should sign or
+                          zero extend.  Therefore we must prevent combining
+                          such jump-function if signednesses do not match.  */
+                       if (!INTEGRAL_TYPE_P (old_ir_ptype)
+                           || !INTEGRAL_TYPE_P (new_ir_ptype)
+                           || (TYPE_UNSIGNED (new_ir_ptype)
+                               != TYPE_UNSIGNED (old_ir_ptype)))
+                         {
+                           ipa_set_jf_unknown (dst);
+                           continue;
+                         }
+                     }
+
                    if (operation == NOP_EXPR)
                      {
                        bool agg_p;
diff --git a/gcc/testsuite/gcc.dg/ipa/pr120295.c 
b/gcc/testsuite/gcc.dg/ipa/pr120295.c
new file mode 100644
index 000000000000..2033ee9493d2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ipa/pr120295.c
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-options "-O3" } */
+
+struct {
+  signed a;
+} b;
+int a, f, j, l;
+char c, k, g, e;
+short d[2] = {0};
+int *i = &j;
+
+volatile int glob;
+void __attribute__((noipa)) sth (const char *, int a)
+{
+  glob = a;
+  return;
+}
+
+void marker_37() {
+  a++;
+  sth ("%d\n", a);
+}
+unsigned long long m(unsigned, char, unsigned, short);
+int n(int, unsigned char, long long);
+int o(long long, unsigned, unsigned);
+unsigned short p(void) {
+  int *r = &l;
+  *r |= ({
+    long long y = (m(c, c, 0, c), b.a);
+    y;
+  });
+  return 0;
+}
+unsigned long long m(unsigned q, char v, unsigned s, short u) {
+  unsigned short ab = 5;
+  if (n(q, ab, d[1]))
+    for (; g; g++)
+      ;
+  return c;
+}
+int n(int af, unsigned char e, long long ae) {
+  unsigned ag = 4;
+  int *ah = &f;
+  *ah = ({ short ad = o(af, f, ag); ad<0 || ad> e; });
+  return *i;
+}
+int o(long long aj, unsigned ai, unsigned ak) {
+  for (; e; e--) {
+    int *al = &f;
+    for (; k; k++)
+      *al = 0;
+  }
+  if (18446744073709551606UL != (unsigned long long) aj)
+    ;
+  else
+    marker_37();
+  return ak;
+}
+int f123() {
+  c = 0xf6;
+  p();
+  return 0;
+}
+int main() {
+  return f123();
+}

Reply via email to