Hi!

Here is my attempt at the PR119614 LTO fix.
Of course, if Martin can come up with something cleaner, let's go with that
instead.

This patch just remembers when ipa_record_return_value_range was set
to a singleton range with CONSTANT_CLASS_P value and propagates that value
through LTO to ltrans where ipa_return_value_range used by tailc pass can
consume it.
Initially I wanted to store it in cgraph_node as a tree, but haven't figured
out how to stream that tree out/in, so this patch stores it as an attribute
instead, which is streamed automatically.

Bootstrapped/regtested on x86_64-linux and i686-linux.

2025-04-14  Jakub Jelinek  <ja...@redhat.com>

        PR tree-optimization/119614
        * ipa-prop.cc: Include attribs.h.
        (ipa_record_return_value_range): Set "singleton retval" attribute if
        the recorded range is singleton with CONSTANT_CLASS_P value, or
        remove it otherwise.
        (ipa_return_value_range): Use "singleton retval" attribute and create
        singleton range from it as fallback.

        * g++.dg/lto/pr119614_0.C: New test.

--- gcc/ipa-prop.cc.jj  2025-04-10 17:14:31.689344793 +0200
+++ gcc/ipa-prop.cc     2025-04-14 08:02:15.083339571 +0200
@@ -60,6 +60,7 @@ along with GCC; see the file COPYING3.
 #include "gimple-range.h"
 #include "value-range-storage.h"
 #include "vr-values.h"
+#include "attribs.h"
 
 /* Function summary where the parameter infos are actually stored. */
 ipa_node_params_t *ipa_node_params_sum = NULL;
@@ -6158,6 +6159,21 @@ ipa_record_return_value_range (value_ran
       ipa_return_value_sum->disable_insertion_hook ();
     }
   ipa_return_value_sum->get_create (n)->vr = ipa_get_value_range (val);
+  tree valr;
+  if (flag_lto || flag_wpa)
+    {
+      if (val.singleton_p (&valr)
+         && CONSTANT_CLASS_P (valr)
+         && !tree_expr_nan_p (valr))
+       DECL_ATTRIBUTES (current_function_decl)
+         = tree_cons (get_identifier ("singleton retval"), valr,
+                      DECL_ATTRIBUTES (current_function_decl));
+      else
+       DECL_ATTRIBUTES (current_function_decl)
+         = remove_attribute ("singleton retval",
+                             DECL_ATTRIBUTES (current_function_decl));
+    }
+
   if (dump_file && (dump_flags & TDF_DETAILS))
     {
       fprintf (dump_file, "Recording return range ");
@@ -6172,7 +6188,7 @@ bool
 ipa_return_value_range (value_range &range, tree decl)
 {
   cgraph_node *n = cgraph_node::get (decl);
-  if (!n || !ipa_return_value_sum)
+  if (!n || (!ipa_return_value_sum && !flag_ltrans))
     return false;
   enum availability avail;
   n = n->ultimate_alias_target (&avail);
@@ -6180,11 +6196,21 @@ ipa_return_value_range (value_range &ran
     return false;
   if (n->decl != decl && !useless_type_conversion_p (TREE_TYPE (decl), 
TREE_TYPE (n->decl)))
     return false;
-  ipa_return_value_summary *v = ipa_return_value_sum->get (n);
-  if (!v)
-    return false;
-  v->vr->get_vrange (range);
-  return true;
+  if (ipa_return_value_sum)
+    if (ipa_return_value_summary *v = ipa_return_value_sum->get (n))
+      {
+       v->vr->get_vrange (range);
+       return true;
+      }
+  if (tree attr = lookup_attribute ("singleton retval", DECL_ATTRIBUTES 
(n->decl)))
+    {
+      value_range vr (TREE_VALUE (attr), TREE_VALUE (attr));
+      if (is_a <frange> (vr))
+       (as_a <frange> (vr)).clear_nan ();
+      range = vr;
+      return true;
+    }
+  return false;
 }
 
 /* Reset all state within ipa-prop.cc so that we can rerun the compiler
--- gcc/testsuite/g++.dg/lto/pr119614_0.C.jj    2025-04-14 08:06:08.774121960 
+0200
+++ gcc/testsuite/g++.dg/lto/pr119614_0.C       2025-04-07 08:42:35.629686614 
+0200
@@ -0,0 +1,34 @@
+// PR tree-optimization/119614
+// { dg-lto-do link }
+// { dg-lto-options { { -O2 -fPIC -flto -flto-partition=max } } }
+// { dg-require-effective-target shared }
+// { dg-require-effective-target fpic }
+// { dg-require-effective-target musttail }
+// { dg-extra-ld-options "-shared" }
+
+struct S {} b;
+char *foo ();
+int e, g;
+void bar ();
+void corge (S);
+
+[[gnu::noinline]] static char *
+baz ()
+{
+  bar ();
+  return 0;
+}
+
+const char *
+qux ()
+{
+  if (e)
+    {
+      S a = b;
+      corge (a);
+      if (g)
+        return 0;
+      [[gnu::musttail]] return baz ();
+    }
+  return foo ();
+}

        Jakub

Reply via email to