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