Branch data Line data Source code
1 : : /* Pass for parsing functions with multiple target attributes.
2 : :
3 : : Contributed by Evgeny Stupachenko <evstupac@gmail.com>
4 : :
5 : : Copyright (C) 2015-2025 Free Software Foundation, Inc.
6 : :
7 : : This file is part of GCC.
8 : :
9 : : GCC is free software; you can redistribute it and/or modify it under
10 : : the terms of the GNU General Public License as published by the Free
11 : : Software Foundation; either version 3, or (at your option) any later
12 : : version.
13 : :
14 : : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
15 : : WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 : : FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 : : for more details.
18 : :
19 : : You should have received a copy of the GNU General Public License
20 : : along with GCC; see the file COPYING3. If not see
21 : : <http://www.gnu.org/licenses/>. */
22 : :
23 : : #include "config.h"
24 : : #include "system.h"
25 : : #include "coretypes.h"
26 : : #include "backend.h"
27 : : #include "tree.h"
28 : : #include "stringpool.h"
29 : : #include "gimple.h"
30 : : #include "diagnostic-core.h"
31 : : #include "gimple-ssa.h"
32 : : #include "cgraph.h"
33 : : #include "tree-pass.h"
34 : : #include "target.h"
35 : : #include "attribs.h"
36 : : #include "pretty-print.h"
37 : : #include "gimple-iterator.h"
38 : : #include "gimple-walk.h"
39 : : #include "tree-inline.h"
40 : : #include "intl.h"
41 : :
42 : : /* Walker callback that replaces all FUNCTION_DECL of a function that's
43 : : going to be versioned. */
44 : :
45 : : static tree
46 : 127 : replace_function_decl (tree *op, int *walk_subtrees, void *data)
47 : : {
48 : 127 : struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
49 : 127 : cgraph_function_version_info *info = (cgraph_function_version_info *)wi->info;
50 : :
51 : 127 : if (TREE_CODE (*op) == FUNCTION_DECL
52 : 50 : && info->this_node->decl == *op)
53 : : {
54 : 26 : *op = info->dispatcher_resolver;
55 : 26 : *walk_subtrees = 0;
56 : : }
57 : :
58 : 127 : return NULL;
59 : : }
60 : :
61 : : /* In target FMV attributes, if the call in NODE has multiple target attribute
62 : : with multiple fields, replace it with calls to the dispatched symbol and
63 : : create the dispatcher body (once).
64 : :
65 : : In target_version semantics, if it is a lone annotated default, then
66 : : the dispatched symbol is changed to be an alias and no resolver is
67 : : required. Otherwise, redirect all calls and references to the dispatched
68 : : symbol, but only create the resolver body if the default version is
69 : : implemented. */
70 : :
71 : : static void
72 : 84 : create_dispatcher_calls (struct cgraph_node *node)
73 : : {
74 : 84 : ipa_ref *ref;
75 : :
76 : 84 : if (!targetm.has_ifunc_p ())
77 : : {
78 : 0 : error_at (DECL_SOURCE_LOCATION (node->decl),
79 : : "the call requires %<ifunc%>, which is not"
80 : : " supported by this target");
81 : 0 : return;
82 : : }
83 : 84 : else if (!targetm.get_function_versions_dispatcher)
84 : : {
85 : 0 : error_at (DECL_SOURCE_LOCATION (node->decl),
86 : : "target does not support function version dispatcher");
87 : 0 : return;
88 : : }
89 : :
90 : 84 : tree idecl = targetm.get_function_versions_dispatcher (node->decl);
91 : 84 : if (!idecl)
92 : : {
93 : 0 : error_at (DECL_SOURCE_LOCATION (node->decl),
94 : : "default %<target_clones%> attribute was not set");
95 : 0 : return;
96 : : }
97 : :
98 : 84 : cgraph_node *inode = cgraph_node::get (idecl);
99 : 84 : gcc_assert (inode);
100 : 84 : cgraph_function_version_info *inode_info = inode->function_version ();
101 : 84 : gcc_assert (inode_info);
102 : :
103 : 84 : tree resolver_decl = NULL;
104 : :
105 : : /* For target_version semantics, if there is a lone default declaration
106 : : it needs to be mangled, with an alias from the dispatched symbol to the
107 : : default version. */
108 : 84 : if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
109 : : && TREE_STATIC (node->decl)
110 : : && inode_info->next
111 : : && !inode_info->next->next)
112 : : {
113 : : inode->alias = true;
114 : : inode->alias_target = inode_info->next->this_node->decl;
115 : : inode->externally_visible = true;
116 : : if (!inode->analyzed)
117 : : inode->resolve_alias
118 : : (cgraph_node::get (inode_info->next->this_node->decl));
119 : :
120 : : DECL_ATTRIBUTES (idecl)
121 : : = make_attribute ("alias",
122 : : IDENTIFIER_POINTER
123 : : (DECL_ASSEMBLER_NAME
124 : : (inode_info->next->this_node->decl)),
125 : : DECL_ATTRIBUTES (node->decl));
126 : : TREE_USED (idecl) = true;
127 : : DECL_EXTERNAL (idecl) = false;
128 : : TREE_STATIC (idecl) = true;
129 : : return;
130 : : }
131 : : /* In target_version semantics, only create the resolver if the
132 : : default node is implemented. */
133 : 84 : else if (TARGET_HAS_FMV_TARGET_ATTRIBUTE || TREE_STATIC (node->decl))
134 : : {
135 : 84 : resolver_decl = targetm.generate_version_dispatcher_body (inode);
136 : : /* Update aliases. */
137 : 84 : inode->alias = true;
138 : 84 : inode->alias_target = resolver_decl;
139 : 84 : if (!inode->analyzed)
140 : 0 : inode->resolve_alias (cgraph_node::get (resolver_decl));
141 : : }
142 : :
143 : 84 : auto_vec<cgraph_edge *> edges_to_redirect;
144 : : /* We need to capture the references by value rather than just pointers to them
145 : : and remove them right away, as removing them later would invalidate what
146 : : some other reference pointers point to. */
147 : 84 : auto_vec<ipa_ref> references_to_redirect;
148 : :
149 : 198 : while (node->iterate_referring (0, ref))
150 : : {
151 : 114 : references_to_redirect.safe_push (*ref);
152 : 114 : ref->remove_reference ();
153 : : }
154 : :
155 : : /* We need to remember NEXT_CALLER as it could be modified in the loop. */
156 : 147 : for (cgraph_edge *e = node->callers; e ; e = e->next_caller)
157 : 63 : edges_to_redirect.safe_push (e);
158 : :
159 : 84 : if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ())
160 : : {
161 : : /* Redirect edges. */
162 : : unsigned i;
163 : : cgraph_edge *e;
164 : 147 : FOR_EACH_VEC_ELT (edges_to_redirect, i, e)
165 : : {
166 : 63 : e->redirect_callee (inode);
167 : 63 : cgraph_edge::redirect_call_stmt_to_callee (e);
168 : : }
169 : :
170 : : /* Redirect references. */
171 : 198 : FOR_EACH_VEC_ELT (references_to_redirect, i, ref)
172 : : {
173 : 114 : if (ref->use == IPA_REF_ADDR)
174 : : {
175 : 110 : struct walk_stmt_info wi;
176 : 110 : memset (&wi, 0, sizeof (wi));
177 : 110 : wi.info = (void *)node->function_version ();
178 : :
179 : 110 : if (dyn_cast<varpool_node *> (ref->referring))
180 : : {
181 : 1 : hash_set<tree> visited_nodes;
182 : 1 : walk_tree (&DECL_INITIAL (ref->referring->decl),
183 : : replace_function_decl, &wi, &visited_nodes);
184 : 1 : }
185 : : else
186 : : {
187 : 109 : gimple_stmt_iterator it = gsi_for_stmt (ref->stmt);
188 : 109 : if (ref->referring->decl != resolver_decl)
189 : 25 : walk_gimple_stmt (&it, NULL, replace_function_decl, &wi);
190 : : }
191 : :
192 : 110 : symtab_node *source = ref->referring;
193 : 110 : source->create_reference (inode, IPA_REF_ADDR);
194 : : }
195 : 4 : else if (ref->use == IPA_REF_ALIAS)
196 : : {
197 : 4 : symtab_node *source = ref->referring;
198 : 4 : source->create_reference (inode, IPA_REF_ALIAS);
199 : 4 : if (inode->get_comdat_group ())
200 : : {
201 : 3 : if (source->same_comdat_group)
202 : 0 : source->remove_from_same_comdat_group ();
203 : 3 : source->add_to_same_comdat_group (inode);
204 : : }
205 : : }
206 : : else
207 : 0 : gcc_unreachable ();
208 : : }
209 : : }
210 : :
211 : 84 : if (node->definition)
212 : : {
213 : : /* FIXME: copy of cgraph_node::make_local that should be cleaned up
214 : : in next stage1. */
215 : 76 : node->make_decl_local ();
216 : 76 : node->set_section (NULL);
217 : 76 : node->set_comdat_group (NULL);
218 : 76 : node->externally_visible = false;
219 : 76 : node->forced_by_abi = false;
220 : :
221 : 76 : DECL_ARTIFICIAL (node->decl) = 1;
222 : 76 : node->force_output = true;
223 : : }
224 : 84 : }
225 : :
226 : : /* Creates target clone of NODE. */
227 : :
228 : : static cgraph_node *
229 : 155 : create_target_clone (cgraph_node *node, bool definition, char *name,
230 : : tree attributes)
231 : : {
232 : 155 : cgraph_node *new_node;
233 : :
234 : 155 : if (definition)
235 : : {
236 : 124 : new_node
237 : 124 : = node->create_version_clone_with_body (vNULL, NULL, NULL, NULL, NULL,
238 : : name, attributes, false);
239 : 124 : if (new_node == NULL)
240 : : return NULL;
241 : 123 : new_node->force_output = true;
242 : : }
243 : : else
244 : : {
245 : 31 : tree new_decl = copy_node (node->decl);
246 : 31 : new_node = cgraph_node::get_create (new_decl);
247 : 31 : DECL_ATTRIBUTES (new_decl) = attributes;
248 : : /* Generate a new name for the new version. */
249 : 31 : tree fname = clone_function_name (node->decl, name);
250 : 31 : symtab->change_decl_assembler_name (new_node->decl, fname);
251 : : }
252 : : return new_node;
253 : : }
254 : :
255 : : /* If the function in NODE has multiple target attributes
256 : : create the appropriate clone for each valid target attribute. */
257 : :
258 : : static bool
259 : 3587005 : expand_target_clones (struct cgraph_node *node, bool definition)
260 : : {
261 : : /* Parsing target attributes separated by TARGET_CLONES_ATTR_SEPARATOR. */
262 : 3587005 : tree attr_target = lookup_attribute ("target_clones",
263 : 3587005 : DECL_ATTRIBUTES (node->decl));
264 : : /* No targets specified. */
265 : 3587005 : if (!attr_target)
266 : : return false;
267 : :
268 : 94 : int num_defaults = 0;
269 : 94 : auto_vec<string_slice> attr_list = get_clone_versions (node->decl,
270 : 94 : &num_defaults);
271 : :
272 : : /* If the target clones list is empty after filtering, remove this node. */
273 : 94 : if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE && attr_list.is_empty ())
274 : : {
275 : : node->remove ();
276 : : return false;
277 : : }
278 : :
279 : : /* No need to clone for 1 target attribute. */
280 : 94 : if (attr_list.length () == 1 && TARGET_HAS_FMV_TARGET_ATTRIBUTE)
281 : : {
282 : 0 : warning_at (DECL_SOURCE_LOCATION (node->decl),
283 : 0 : 0, "single %<target_clones%> attribute is ignored");
284 : 0 : return false;
285 : : }
286 : :
287 : : /* For target_version semantics, a target clone with just a default version
288 : : is the same as an unannotated decl, so can ignore. */
289 : 94 : if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
290 : : && attr_list.length () == 1
291 : : && num_defaults == 1)
292 : : return false;
293 : :
294 : 94 : if (node->definition
295 : 94 : && (node->alias || !tree_versionable_function_p (node->decl)))
296 : : {
297 : 6 : auto_diagnostic_group d;
298 : 6 : error_at (DECL_SOURCE_LOCATION (node->decl),
299 : : "clones for %<target_clones%> attribute cannot be created");
300 : 6 : const char *reason = NULL;
301 : 6 : if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
302 : : reason = G_("function %q+F can never be copied "
303 : : "because it has %<noclone%> attribute");
304 : 3 : else if (node->alias)
305 : : reason
306 : : = "%<target_clones%> cannot be combined with %<alias%> attribute";
307 : : else
308 : 2 : reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
309 : 2 : if (reason)
310 : 6 : inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
311 : 6 : return false;
312 : 6 : }
313 : :
314 : : /* Disallow multiple defaults. */
315 : 88 : if (num_defaults > 1)
316 : : {
317 : 1 : error_at (DECL_SOURCE_LOCATION (node->decl),
318 : : "multiple %<default%> targets were set");
319 : 1 : return false;
320 : : }
321 : :
322 : : /* For target FMV semantics, where target and target_clone mixing
323 : : is not supported, disallow target clones with no defaults. */
324 : 87 : if (TARGET_HAS_FMV_TARGET_ATTRIBUTE && num_defaults == 0)
325 : : {
326 : 1 : error_at (DECL_SOURCE_LOCATION (node->decl),
327 : : "%<default%> target was not set");
328 : 1 : return false;
329 : : }
330 : :
331 : : /* Disallow any empty values in the clone attr. */
332 : 500 : for (string_slice attr : attr_list)
333 : 485 : if (attr.empty () || !attr.is_valid ())
334 : : {
335 : 1 : error_at (DECL_SOURCE_LOCATION (node->decl),
336 : : "an empty string cannot be in %<target_clones%> attribute");
337 : 1 : return false;
338 : : }
339 : :
340 : 85 : string_slice new_attr_name = TARGET_HAS_FMV_TARGET_ATTRIBUTE
341 : : ? "target"
342 : 85 : : "target_version";
343 : :
344 : 85 : cgraph_function_version_info *node_v = node->function_version ();
345 : :
346 : 85 : if (!node_v)
347 : 85 : node_v = node->insert_new_function_version ();
348 : :
349 : : /* If this target_clones contains a default, then convert this node to the
350 : : default. If this node does not contain default (this is only possible
351 : : in target_version semantics) then remove the node. This is safe at this
352 : : point as only target_clones declarations containing default version is
353 : : resolvable so this decl will have no calls/references. */
354 : :
355 : 85 : tree attrs = remove_attribute ("target_clones",
356 : 85 : DECL_ATTRIBUTES (node->decl));
357 : 85 : tree assembler_name = node_v->assembler_name;
358 : :
359 : : /* Change the current node into the default node. */
360 : 85 : if (num_defaults == 1)
361 : : {
362 : : /* Setting new attribute to initial function. */
363 : 85 : tree attributes = make_attribute (new_attr_name, "default", attrs);
364 : 85 : DECL_ATTRIBUTES (node->decl) = attributes;
365 : 85 : DECL_FUNCTION_VERSIONED (node->decl) = true;
366 : :
367 : 85 : node->is_target_clone = true;
368 : 85 : node->local = false;
369 : :
370 : : /* Remangle base node after new target version string set. */
371 : 85 : tree id = targetm.mangle_decl_assembler_name (node->decl, assembler_name);
372 : 85 : symtab->change_decl_assembler_name (node->decl, id);
373 : : }
374 : : else
375 : : {
376 : : /* Target clones without a default are only allowed for target_version
377 : : semantics where we can have target_clones/target_version mixing. */
378 : 0 : gcc_assert (!TARGET_HAS_FMV_TARGET_ATTRIBUTE);
379 : :
380 : : /* If there isn't a default version, can safely remove this version.
381 : : The node itself gets removed after the other versions are created. */
382 : : cgraph_function_version_info *temp = node_v;
383 : : node_v = node_v->next ? node_v->next : node_v->prev;
384 : : cgraph_node::delete_function_version (temp);
385 : : }
386 : :
387 : 493 : for (string_slice attr : attr_list)
388 : : {
389 : : /* Skip default nodes. */
390 : 239 : if (attr == "default")
391 : 84 : continue;
392 : :
393 : : /* Create new target clone. */
394 : 155 : tree attributes = make_attribute (new_attr_name, attr, attrs);
395 : :
396 : 155 : cgraph_node *new_node
397 : 155 : = create_target_clone (node, definition, NULL, attributes);
398 : 155 : if (new_node == NULL)
399 : 1 : return false;
400 : 154 : new_node->local = false;
401 : :
402 : 154 : DECL_FUNCTION_VERSIONED (new_node->decl) = true;
403 : 154 : if (!node_v)
404 : 0 : node_v = new_node->insert_new_function_version ();
405 : : else
406 : 154 : cgraph_node::add_function_version (node_v, new_node->decl);
407 : :
408 : : /* Use the base node's assembler name for all created nodes. */
409 : 154 : new_node->function_version ()->assembler_name = assembler_name;
410 : 154 : new_node->is_target_clone = true;
411 : :
412 : : /* Mangle all new nodes. */
413 : 154 : tree id = targetm.mangle_decl_assembler_name
414 : 154 : (new_node->decl, new_node->function_version ()->assembler_name);
415 : 154 : symtab->change_decl_assembler_name (new_node->decl, id);
416 : : }
417 : :
418 : : /* If there are no default versions in the target_clones, this node is not
419 : : reused, so can delete this node. */
420 : 84 : if (num_defaults == 0)
421 : 0 : node->remove ();
422 : :
423 : : return true;
424 : 94 : }
425 : :
426 : : /* When NODE is part of an FMV function set, consider all callees and check if
427 : : any can provably always resolve a certain version and then call that version
428 : : directly. */
429 : :
430 : : static void
431 : 3587474 : redirect_to_specific_clone (cgraph_node *node)
432 : : {
433 : 3587474 : if (!targetm.compare_version_priority || !optimize)
434 : : return;
435 : :
436 : : /* We need to remember NEXT_CALLER as it could be modified in the loop. */
437 : 8122389 : for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
438 : : {
439 : : /* Only if this is a call to a dispatched symbol. */
440 : 5350783 : if (!e->callee->dispatcher_function)
441 : 5350697 : continue;
442 : :
443 : 86 : cgraph_function_version_info *callee_v
444 : 86 : = e->callee->function_version ();
445 : 86 : cgraph_function_version_info *caller_v
446 : 86 : = e->caller->function_version ();
447 : :
448 : 86 : gcc_assert (callee_v);
449 : :
450 : : /* Find the default nodes for both callee and caller (if present). */
451 : 86 : cgraph_function_version_info *callee_default_v = callee_v->next;
452 : 86 : cgraph_function_version_info *caller_default_v = caller_v;
453 : 86 : if (caller_v)
454 : : {
455 : 9 : while (caller_default_v->prev)
456 : : caller_default_v = caller_default_v->prev;
457 : 7 : if (!is_function_default_version (caller_default_v->this_node->decl))
458 : 79 : caller_default_v = NULL;
459 : : }
460 : :
461 : : /* If this is not the TU that contains the definition of the default
462 : : version we are not guaranteed to have visibility of all versions
463 : : so cannot reason about them. */
464 : 101 : if (!callee_default_v
465 : 86 : || !callee_default_v->this_node->binds_to_current_def_p ())
466 : 15 : continue;
467 : :
468 : 71 : cgraph_function_version_info *highest_callable_fn = NULL;
469 : 71 : for (cgraph_function_version_info *ver = callee_v->next;
470 : 438 : ver;
471 : 367 : ver = ver->next)
472 : 367 : if (targetm.target_option.functions_b_resolvable_from_a
473 : 367 : (node->decl, ver->this_node->decl, node->decl))
474 : 7 : highest_callable_fn = ver;
475 : :
476 : 71 : if (!highest_callable_fn)
477 : 64 : continue;
478 : :
479 : 7 : bool inlinable = true;
480 : :
481 : : /* If there are higher priority versions of callee and caller has no
482 : : more version information, then not callable. */
483 : 7 : if (highest_callable_fn->next)
484 : : {
485 : : /* If this is not the TU where the callee default is defined then
486 : : cannot reason about the caller versions. */
487 : 5 : if (!caller_default_v
488 : 5 : || !caller_default_v->this_node->binds_to_current_def_p ())
489 : 0 : continue;
490 : :
491 : : /* If every higher priority version would imply a higher priority
492 : : version of caller would have been selected, then this is
493 : : callable. */
494 : 5 : for (cgraph_function_version_info *callee_ver
495 : : = highest_callable_fn->next;
496 : 10 : callee_ver; callee_ver = callee_ver->next)
497 : : {
498 : 5 : bool is_possible = true;
499 : 5 : for (cgraph_function_version_info *caller_ver = caller_v->next;
500 : 5 : caller_ver; caller_ver = caller_ver->next)
501 : 5 : if (targetm.target_option.functions_b_resolvable_from_a
502 : 5 : (callee_ver->this_node->decl, caller_ver->this_node->decl,
503 : : node->decl))
504 : : {
505 : : is_possible = false;
506 : : break;
507 : : }
508 : 5 : if (is_possible)
509 : : {
510 : : inlinable = false;
511 : : break;
512 : : }
513 : : }
514 : : }
515 : 5 : if (inlinable)
516 : : {
517 : 7 : e->redirect_callee (highest_callable_fn->this_node);
518 : 7 : cgraph_edge::redirect_call_stmt_to_callee (e);
519 : : }
520 : : }
521 : : }
522 : :
523 : : /* Checks if NODE is in the 'simple' target_clones case, which is where NODE
524 : : is a declaration annotated with target_clones containing the default, and it
525 : : is the sole function declaration in the FMV function set. */
526 : :
527 : : static bool
528 : 0 : is_simple_target_clones_case (cgraph_node *node)
529 : : {
530 : : /* target attribute semantics doesnt support the complex case,
531 : : so this is always true. */
532 : 0 : if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
533 : 0 : return true;
534 : :
535 : : int num_defaults = 0;
536 : : auto versions = get_clone_versions (node->decl, &num_defaults);
537 : : if (versions.is_empty () || num_defaults != 1)
538 : : return false;
539 : :
540 : : cgraph_function_version_info *fv = node->function_version ();
541 : :
542 : : if (fv && (fv->next || fv->prev))
543 : : return false;
544 : :
545 : : return true;
546 : : }
547 : :
548 : : static unsigned int
549 : 462331 : ipa_target_clone (bool early)
550 : : {
551 : 462331 : struct cgraph_node *node;
552 : 462331 : auto_vec<cgraph_node *> to_dispatch;
553 : :
554 : : /* Don't need to do anything early for target attribute semantics. */
555 : 462331 : if (early && TARGET_HAS_FMV_TARGET_ATTRIBUTE)
556 : : return 0;
557 : :
558 : : /* For target attribute semantics, this pass skips the early phase, and in
559 : : the later stage is only responsible for expanding and dispatching
560 : : target_clone declarations, as target annotated functions are dispatched
561 : : in the front end.
562 : :
563 : : The expanding and dispatching can be done at the late stage as the
564 : : target_clone functions aren't allowed to be part of a larger FMV set, so
565 : : all versions will all have the same body, so early optimisations are safe
566 : : to treat a call to a target_clones set as a call to one function.
567 : :
568 : : For target_version semantics, this pass is responsible for expanding
569 : : target_clones and dispatching all FMV function sets, including ones only
570 : : made up of target_version declarations.
571 : :
572 : : Cases where there is more than one declaration must be expanded and
573 : : dispatched at the early stage, as the declarations may have different
574 : : bodies, and so the early optimisation passes would not be valid.
575 : :
576 : : The late stage is only used for the expansion and dispatching of the simple
577 : : case where the FMV set is defined by a single target_clone attribute. */
578 : :
579 : 7867466 : FOR_EACH_FUNCTION_REMOVABLE (node)
580 : : {
581 : : /* In the early stage, we need to expand any target clone that is not
582 : : the simple case. Simple cases are dispatched in the later stage. */
583 : :
584 : 3587005 : if (early == !is_simple_target_clones_case (node))
585 : 3587005 : if (expand_target_clones (node, node->definition)
586 : 3587005 : && TARGET_HAS_FMV_TARGET_ATTRIBUTE)
587 : : /* In non target_version semantics, dispatch all target clones. */
588 : 84 : to_dispatch.safe_push (node);
589 : : }
590 : :
591 : : /* In target_version semantics dispatch all FMV function sets with a default
592 : : implementation in the early stage.
593 : : Also dispatch any default versions generated by expanding target_clones
594 : : in the late stage. */
595 : :
596 : : if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE)
597 : : FOR_EACH_FUNCTION (node)
598 : : if (is_function_default_version (node->decl)
599 : : && DECL_FUNCTION_VERSIONED (node->decl)
600 : : /* Don't dispatch target clones, as they haven't been expanded so
601 : : are simple. */
602 : : && !lookup_attribute ("target_clones", DECL_ATTRIBUTES (node->decl)))
603 : : to_dispatch.safe_push (node);
604 : :
605 : 231236 : for (unsigned i = 0; i < to_dispatch.length (); i++)
606 : 84 : create_dispatcher_calls (to_dispatch[i]);
607 : :
608 : 7637252 : FOR_EACH_FUNCTION (node)
609 : 3587474 : redirect_to_specific_clone (node);
610 : :
611 : : return 0;
612 : 462331 : }
613 : :
614 : : namespace {
615 : :
616 : : const pass_data pass_data_target_clone =
617 : : {
618 : : SIMPLE_IPA_PASS, /* type */
619 : : "targetclone", /* name */
620 : : OPTGROUP_NONE, /* optinfo_flags */
621 : : TV_NONE, /* tv_id */
622 : : ( PROP_ssa | PROP_cfg ), /* properties_required */
623 : : 0, /* properties_provided */
624 : : 0, /* properties_destroyed */
625 : : 0, /* todo_flags_start */
626 : : TODO_update_ssa /* todo_flags_finish */
627 : : };
628 : :
629 : : class pass_target_clone : public simple_ipa_opt_pass
630 : : {
631 : : public:
632 : 578160 : pass_target_clone (gcc::context *ctxt)
633 : 1156320 : : simple_ipa_opt_pass (pass_data_target_clone, ctxt), early_p (false)
634 : : {}
635 : : bool early_p;
636 : :
637 : 578160 : void set_pass_param (unsigned int n, bool param) final override
638 : : {
639 : 578160 : gcc_assert (n == 0);
640 : 578160 : early_p = param;
641 : 578160 : }
642 : : /* opt_pass methods: */
643 : : bool gate (function *) final override;
644 : 289080 : opt_pass * clone () final override { return new pass_target_clone (m_ctxt); }
645 : 462331 : unsigned int execute (function *) final override
646 : : {
647 : 462331 : return ipa_target_clone (early_p);
648 : : }
649 : : };
650 : :
651 : : bool
652 : 462542 : pass_target_clone::gate (function *)
653 : : {
654 : : /* If there were any errors avoid pass property verification errors. */
655 : 462542 : return !seen_error ();
656 : : }
657 : :
658 : : } // anon namespace
659 : :
660 : : simple_ipa_opt_pass *
661 : 289080 : make_pass_target_clone (gcc::context *ctxt)
662 : : {
663 : 289080 : return new pass_target_clone (ctxt);
664 : : }
|