ipa-devirt: Add speculative direct calls based on stores to structures
This patch extends the ipa-devirt pass with the ability to add
speculative calls for indirect calls where the target was loaded from
a record_type data structure and we have seen writes of address of
only one particular function to the same offset of that record
type (including static initializers).
The idea is basically taken from Christoph Müllner's patch from 2022
(https://gcc.gnu.org/pipermail/gcc-patches/2022-November/605934.html)
but I have re-worked it so that it stores the required information in
GC memory (which I belive is necessary) and does not require an
additional pass through gimple statements of all functions because it
uses the analysis phase of ipa-cp/ipa-fnsummary (which was an approach
we agreed on with Honza).
It also performs simple verification that the collected types match
the type of the record field. We could verify that the function
determined as the likely target matches the call statement
expectations, but for that we would need to stream both types which is
something I decided not to do.
Co-authored by: Christoph Müllner <christoph.muellner@vrull.eu>
gcc/ChangeLog:
2025-11-28 Martin Jambor <mjambor@suse.cz>
PR ipa/107666
* common.opt (fspeculatively-call-stored-functions): New.
* cgraph.h (cgraph_simple_indirect_info): New fields rec_type and
fld_offset.
* ipa-prop.h (ipa_analyze_var_static_initializer): Declare.
(ipa_dump_noted_record_fnptrs): Likewise.
(ipa_debug_noted_record_fnptrs): Likewise.
(ipa_single_noted_fnptr_in_record): Likewise.
(ipa_free_noted_fnptr_calls): Likewise.
* ipa-cp.cc (ipcp_generate_summary): Call
ipa_analyze_var_static_initializer on each varbool node with a static
initializer.
* ipa-devirt.cc (struct devirt_stats): New type.
(devirt_target_ok_p): New function.
(ipa_devirt): Move statistics counters to the new structure. dump
noted function pointers stored in records. Check for edge hotness
first and for odr_types only for polymorphic edges. Moved a number of
checks to devirt_target_ok_p. Also add speculative direct calls for
non-polymorphic indirect ones when ipa_single_noted_fnptr_in_record
finds a likely target. Call ipa_free_noted_fnptr_calls.
(pass_ipa_devirt::gate): Also check the new flag.
* ipa-prop.cc (noted_fnptr_store): New type.
(struct noted_fnptr_hasher): Likewise.
(noted_fnptr_hasher::hash): New function.
(noted_fnptr_hasher::equal): Likewise.
(noted_fnptrs_in_records): New.
(is_func_ptr_from_record): New function.
(ipa_analyze_indirect_call_uses): Also simple create indirect info
structures with fnptr_loaded_from_record set.
(note_fnptr_in_record): New function.
(ipa_dump_noted_record_fnptrs): Likewise.
(ipa_debug_noted_record_fnptrs): Likewise.
(ipa_single_noted_fnptr_in_record): Likewise.
(ipa_free_noted_fnptr_calls): Likewise.
(ipa_analyze_stmt_uses): Also look for stroes of function pointers to
record structures.
(ipa_analyze_var_static_initializer): New function.
(ipa_write_indirect_edge_info): Also stream fnptr_loaded_from_record
indirec infos.
(ipa_read_indirect_edge_info): Likewise.
(ipa_prop_write_jump_functions): Also stream the contents of
noted_fnptrs_in_records.
(ipa_prop_read_section): Likewise.
* opts.cc (default_options_table): Also turn on
OPT_fspeculatively_call_stored_functions at -O2.
(common_handle_option): Turn flag_speculatively_call_stored_functions
when using profile feedback.
* doc/invoke.texi (-fspeculatively-call-stored-functions): New.