1 | /* Utilities for ipa analysis. |
2 | Copyright (C) 2004-2024 Free Software Foundation, Inc. |
3 | Contributed by Kenneth Zadeck <zadeck@naturalbridge.com> |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #ifndef GCC_IPA_UTILS_H |
22 | #define GCC_IPA_UTILS_H |
23 | |
24 | struct ipa_dfs_info { |
25 | int dfn_number; |
26 | int low_link; |
27 | /* This field will have the samy value for any two nodes in the same strongly |
28 | connected component. */ |
29 | int scc_no; |
30 | bool new_node; |
31 | bool on_stack; |
32 | struct cgraph_node* next_cycle; |
33 | void *aux; |
34 | }; |
35 | |
36 | |
37 | /* In ipa-utils.cc */ |
38 | void ipa_print_order (FILE*, const char *, struct cgraph_node**, int); |
39 | int ipa_reduced_postorder (struct cgraph_node **, bool, |
40 | bool (*ignore_edge) (struct cgraph_edge *)); |
41 | void ipa_free_postorder_info (void); |
42 | vec<cgraph_node *> ipa_get_nodes_in_cycle (struct cgraph_node *); |
43 | bool ipa_edge_within_scc (struct cgraph_edge *); |
44 | int ipa_reverse_postorder (struct cgraph_node **); |
45 | tree get_base_var (tree); |
46 | void ipa_merge_profiles (struct cgraph_node *dst, |
47 | struct cgraph_node *src, bool preserve_body = false); |
48 | bool recursive_call_p (tree, tree); |
49 | bool stmt_may_terminate_function_p (function *fun, gimple *stmt, bool assume_return_or_eh); |
50 | bitmap find_always_executed_bbs (function *fun, bool assume_return_or_eh); |
51 | |
52 | /* In ipa-pure-const.cc */ |
53 | bool finite_function_p (); |
54 | bool builtin_safe_for_const_function_p (bool *, tree); |
55 | bool ipa_make_function_const (cgraph_node *, bool, bool); |
56 | bool ipa_make_function_pure (cgraph_node *, bool, bool); |
57 | |
58 | /* In ipa-profile.cc */ |
59 | bool ipa_propagate_frequency (struct cgraph_node *node); |
60 | void ipa_profile_cc_finalize (void); |
61 | |
62 | /* In ipa-icf.cc */ |
63 | void ipa_icf_cc_finalize (void); |
64 | |
65 | /* In ipa-sra.cc */ |
66 | void ipa_sra_cc_finalize (void); |
67 | |
68 | /* In ipa-devirt.cc */ |
69 | |
70 | struct odr_type_d; |
71 | typedef odr_type_d *odr_type; |
72 | extern bool thunk_expansion; |
73 | void build_type_inheritance_graph (void); |
74 | void rebuild_type_inheritance_graph (void); |
75 | void update_type_inheritance_graph (void); |
76 | vec <cgraph_node *> |
77 | possible_polymorphic_call_targets (tree, HOST_WIDE_INT, |
78 | ipa_polymorphic_call_context, |
79 | bool *copletep = NULL, |
80 | void **cache_token = NULL, |
81 | bool speuclative = false); |
82 | odr_type get_odr_type (tree, bool insert = false); |
83 | bool odr_type_p (const_tree); |
84 | bool possible_polymorphic_call_target_p (tree ref, gimple *stmt, struct cgraph_node *n); |
85 | void dump_possible_polymorphic_call_targets (FILE *, tree, HOST_WIDE_INT, |
86 | const ipa_polymorphic_call_context &, |
87 | bool verbose = true); |
88 | bool possible_polymorphic_call_target_p (tree, HOST_WIDE_INT, |
89 | const ipa_polymorphic_call_context &, |
90 | struct cgraph_node *); |
91 | tree polymorphic_ctor_dtor_p (tree, bool); |
92 | tree inlined_polymorphic_ctor_dtor_block_p (tree, bool); |
93 | bool decl_maybe_in_construction_p (tree, tree, gimple *, tree); |
94 | tree vtable_pointer_value_to_binfo (const_tree); |
95 | bool vtable_pointer_value_to_vtable (const_tree, tree *, unsigned HOST_WIDE_INT *); |
96 | tree subbinfo_with_vtable_at_offset (tree, unsigned HOST_WIDE_INT, tree); |
97 | void compare_virtual_tables (varpool_node *, varpool_node *); |
98 | bool type_all_derivations_known_p (const_tree); |
99 | bool type_known_to_have_no_derivations_p (tree); |
100 | bool contains_polymorphic_type_p (const_tree); |
101 | void register_odr_type (tree); |
102 | bool types_must_be_same_for_odr (tree, tree); |
103 | bool types_odr_comparable (tree, tree); |
104 | cgraph_node *try_speculative_devirtualization (tree, HOST_WIDE_INT, |
105 | ipa_polymorphic_call_context); |
106 | void warn_types_mismatch (tree t1, tree t2, location_t loc1 = UNKNOWN_LOCATION, |
107 | location_t loc2 = UNKNOWN_LOCATION); |
108 | bool odr_or_derived_type_p (const_tree t); |
109 | bool odr_types_equivalent_p (tree type1, tree type2); |
110 | bool odr_type_violation_reported_p (tree type); |
111 | tree prevailing_odr_type (tree type); |
112 | void enable_odr_based_tbaa (tree type); |
113 | bool odr_based_tbaa_p (const_tree type); |
114 | void set_type_canonical_for_odr_type (tree type, tree canonical); |
115 | void warn_function_returns_nonnull (tree); |
116 | |
117 | void register_odr_enum (tree type); |
118 | |
119 | /* Return vector containing possible targets of polymorphic call E. |
120 | If COMPLETEP is non-NULL, store true if the list is complete. |
121 | CACHE_TOKEN (if non-NULL) will get stored to an unique ID of entry |
122 | in the target cache. If user needs to visit every target list |
123 | just once, it can memoize them. |
124 | |
125 | Returned vector is placed into cache. It is NOT caller's responsibility |
126 | to free it. The vector can be freed on cgraph_remove_node call if |
127 | the particular node is a virtual function present in the cache. */ |
128 | |
129 | inline vec <cgraph_node *> |
130 | possible_polymorphic_call_targets (struct cgraph_edge *e, |
131 | bool *completep = NULL, |
132 | void **cache_token = NULL, |
133 | bool speculative = false) |
134 | { |
135 | ipa_polymorphic_call_context context(e); |
136 | |
137 | return possible_polymorphic_call_targets (e->indirect_info->otr_type, |
138 | e->indirect_info->otr_token, |
139 | context, |
140 | copletep: completep, cache_token, |
141 | speuclative: speculative); |
142 | } |
143 | |
144 | /* Same as above but taking OBJ_TYPE_REF as an parameter. */ |
145 | |
146 | inline vec <cgraph_node *> |
147 | possible_polymorphic_call_targets (tree ref, |
148 | gimple *call, |
149 | bool *completep = NULL, |
150 | void **cache_token = NULL) |
151 | { |
152 | ipa_polymorphic_call_context context (current_function_decl, ref, call); |
153 | |
154 | return possible_polymorphic_call_targets (obj_type_ref_class (ref), |
155 | tree_to_uhwi |
156 | (OBJ_TYPE_REF_TOKEN (ref)), |
157 | context, |
158 | copletep: completep, cache_token); |
159 | } |
160 | |
161 | /* Dump possible targets of a polymorphic call E into F. */ |
162 | |
163 | inline void |
164 | dump_possible_polymorphic_call_targets (FILE *f, struct cgraph_edge *e, |
165 | bool verbose = true) |
166 | { |
167 | ipa_polymorphic_call_context context(e); |
168 | |
169 | dump_possible_polymorphic_call_targets (f, e->indirect_info->otr_type, |
170 | e->indirect_info->otr_token, |
171 | context, verbose); |
172 | } |
173 | |
174 | /* Return true if N can be possibly target of a polymorphic call of |
175 | E. */ |
176 | |
177 | inline bool |
178 | possible_polymorphic_call_target_p (struct cgraph_edge *e, |
179 | struct cgraph_node *n) |
180 | { |
181 | ipa_polymorphic_call_context context(e); |
182 | |
183 | return possible_polymorphic_call_target_p (e->indirect_info->otr_type, |
184 | e->indirect_info->otr_token, |
185 | context, n); |
186 | } |
187 | |
188 | /* Return true if BINFO corresponds to a type with virtual methods. |
189 | |
190 | Every type has several BINFOs. One is the BINFO associated by the type |
191 | while other represents bases of derived types. The BINFOs representing |
192 | bases do not have BINFO_VTABLE pointer set when this is the single |
193 | inheritance (because vtables are shared). Look up the BINFO of type |
194 | and check presence of its vtable. */ |
195 | |
196 | inline bool |
197 | polymorphic_type_binfo_p (const_tree binfo) |
198 | { |
199 | return (BINFO_TYPE (binfo) && TYPE_BINFO (BINFO_TYPE (binfo)) |
200 | && BINFO_VTABLE (TYPE_BINFO (BINFO_TYPE (binfo)))); |
201 | } |
202 | |
203 | /* Return true if T is a type with linkage defined. */ |
204 | |
205 | inline bool |
206 | type_with_linkage_p (const_tree t) |
207 | { |
208 | gcc_checking_assert (TYPE_MAIN_VARIANT (t) == t); |
209 | if (!TYPE_NAME (t) || TREE_CODE (TYPE_NAME (t)) != TYPE_DECL) |
210 | return false; |
211 | |
212 | /* After free_lang_data was run we can recongize |
213 | types with linkage by presence of mangled name. */ |
214 | if (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))) |
215 | return true; |
216 | |
217 | if (in_lto_p) |
218 | return false; |
219 | |
220 | /* We used to check for TYPE_STUB_DECL but that is set to NULL for forward |
221 | declarations. */ |
222 | |
223 | if (!RECORD_OR_UNION_TYPE_P (t) && TREE_CODE (t) != ENUMERAL_TYPE) |
224 | return false; |
225 | |
226 | /* Builtin types do not define linkage, their TYPE_CONTEXT is NULL. */ |
227 | if (!TYPE_CONTEXT (t)) |
228 | return false; |
229 | |
230 | return true; |
231 | } |
232 | |
233 | /* Return true if T is in anonymous namespace. |
234 | This works only on those C++ types with linkage defined. */ |
235 | |
236 | inline bool |
237 | type_in_anonymous_namespace_p (const_tree t) |
238 | { |
239 | gcc_checking_assert (type_with_linkage_p (t)); |
240 | |
241 | /* free_lang_data clears TYPE_STUB_DECL but sets assembler name to |
242 | "<anon>" */ |
243 | if (DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))) |
244 | return !strcmp (s1: "<anon>" , |
245 | IDENTIFIER_POINTER |
246 | (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))); |
247 | else if (!TYPE_STUB_DECL (t)) |
248 | return false; |
249 | else |
250 | return !TREE_PUBLIC (TYPE_STUB_DECL (t)); |
251 | } |
252 | |
253 | /* Return true of T is type with One Definition Rule info attached. |
254 | It means that either it is anonymous type or it has assembler name |
255 | set. */ |
256 | |
257 | inline bool |
258 | odr_type_p (const_tree t) |
259 | { |
260 | /* We do not have this information when not in LTO, but we do not need |
261 | to care, since it is used only for type merging. */ |
262 | gcc_checking_assert (in_lto_p || flag_lto || flag_generate_offload); |
263 | return TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL |
264 | && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)); |
265 | } |
266 | |
267 | /* If TYPE has mangled ODR name, return it. Otherwise return NULL. |
268 | The function works only when free_lang_data is run. */ |
269 | |
270 | inline const char * |
271 | get_odr_name_for_type (tree type) |
272 | { |
273 | tree type_name = TYPE_NAME (type); |
274 | if (type_name == NULL_TREE |
275 | || TREE_CODE (type_name) != TYPE_DECL |
276 | || !DECL_ASSEMBLER_NAME_SET_P (type_name)) |
277 | return NULL; |
278 | |
279 | return IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (type_name)); |
280 | } |
281 | |
282 | /* Return true if we are going to do LTO streaming. */ |
283 | |
284 | inline bool |
285 | lto_streaming_expected_p () |
286 | { |
287 | /* Compilation before LTO stremaing. */ |
288 | if (flag_lto && !in_lto_p && symtab->state < IPA_SSA_AFTER_INLINING) |
289 | return true; |
290 | /* WPA or incremental link. */ |
291 | return (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO); |
292 | } |
293 | |
294 | #endif /* GCC_IPA_UTILS_H */ |
295 | |