1 /* Pass for parsing functions with multiple target attributes.
3 Contributed by Evgeny Stupachenko <evstupac@gmail.com>
5 Copyright (C) 2015-2019 Free Software Foundation, Inc.
7 This file is part of GCC.
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
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
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/>. */
25 #include "coretypes.h"
28 #include "stringpool.h"
30 #include "diagnostic-core.h"
31 #include "gimple-ssa.h"
33 #include "tree-pass.h"
36 #include "pretty-print.h"
37 #include "gimple-iterator.h"
38 #include "gimple-walk.h"
39 #include "tree-inline.h"
42 /* Walker callback that replaces all FUNCTION_DECL of a function that's
43 going to be versioned. */
46 replace_function_decl (tree
*op
, int *walk_subtrees
, void *data
)
48 struct walk_stmt_info
*wi
= (struct walk_stmt_info
*) data
;
49 cgraph_function_version_info
*info
= (cgraph_function_version_info
*)wi
->info
;
51 if (TREE_CODE (*op
) == FUNCTION_DECL
52 && info
->this_node
->decl
== *op
)
54 *op
= info
->dispatcher_resolver
;
61 /* If the call in NODE has multiple target attribute with multiple fields,
62 replace it with dispatcher call and create dispatcher (once). */
65 create_dispatcher_calls (struct cgraph_node
*node
)
69 if (!DECL_FUNCTION_VERSIONED (node
->decl
)
70 || !is_function_default_version (node
->decl
))
73 if (!targetm
.has_ifunc_p ())
75 error_at (DECL_SOURCE_LOCATION (node
->decl
),
76 "the call requires %<ifunc%>, which is not"
77 " supported by this target");
80 else if (!targetm
.get_function_versions_dispatcher
)
82 error_at (DECL_SOURCE_LOCATION (node
->decl
),
83 "target does not support function version dispatcher");
87 tree idecl
= targetm
.get_function_versions_dispatcher (node
->decl
);
90 error_at (DECL_SOURCE_LOCATION (node
->decl
),
91 "default %<target_clones%> attribute was not set");
95 cgraph_node
*inode
= cgraph_node::get (idecl
);
97 tree resolver_decl
= targetm
.generate_version_dispatcher_body (inode
);
101 inode
->alias_target
= resolver_decl
;
102 if (!inode
->analyzed
)
103 inode
->resolve_alias (cgraph_node::get (resolver_decl
));
105 auto_vec
<cgraph_edge
*> edges_to_redirect
;
106 /* We need to capture the references by value rather than just pointers to them
107 and remove them right away, as removing them later would invalidate what
108 some other reference pointers point to. */
109 auto_vec
<ipa_ref
> references_to_redirect
;
111 while (node
->iterate_referring (0, ref
))
113 references_to_redirect
.safe_push (*ref
);
114 ref
->remove_reference ();
117 /* We need to remember NEXT_CALLER as it could be modified in the loop. */
118 for (cgraph_edge
*e
= node
->callers
; e
; e
= e
->next_caller
)
119 edges_to_redirect
.safe_push (e
);
121 if (!edges_to_redirect
.is_empty () || !references_to_redirect
.is_empty ())
123 /* Redirect edges. */
126 FOR_EACH_VEC_ELT (edges_to_redirect
, i
, e
)
128 e
->redirect_callee (inode
);
129 e
->redirect_call_stmt_to_callee ();
132 /* Redirect references. */
133 FOR_EACH_VEC_ELT (references_to_redirect
, i
, ref
)
135 if (ref
->use
== IPA_REF_ADDR
)
137 struct walk_stmt_info wi
;
138 memset (&wi
, 0, sizeof (wi
));
139 wi
.info
= (void *)node
->function_version ();
141 if (dyn_cast
<varpool_node
*> (ref
->referring
))
143 hash_set
<tree
> visited_nodes
;
144 walk_tree (&DECL_INITIAL (ref
->referring
->decl
),
145 replace_function_decl
, &wi
, &visited_nodes
);
149 gimple_stmt_iterator it
= gsi_for_stmt (ref
->stmt
);
150 if (ref
->referring
->decl
!= resolver_decl
)
151 walk_gimple_stmt (&it
, NULL
, replace_function_decl
, &wi
);
154 symtab_node
*source
= ref
->referring
;
155 source
->create_reference (inode
, IPA_REF_ADDR
);
157 else if (ref
->use
== IPA_REF_ALIAS
)
159 symtab_node
*source
= ref
->referring
;
160 source
->create_reference (inode
, IPA_REF_ALIAS
);
161 source
->add_to_same_comdat_group (inode
);
168 symtab
->change_decl_assembler_name (node
->decl
,
169 clone_function_name_numbered (
170 node
->decl
, "default"));
172 /* FIXME: copy of cgraph_node::make_local that should be cleaned up
174 node
->make_decl_local ();
175 node
->set_section (NULL
);
176 node
->set_comdat_group (NULL
);
177 node
->externally_visible
= false;
178 node
->forced_by_abi
= false;
179 node
->set_section (NULL
);
180 node
->unique_name
= ((node
->resolution
== LDPR_PREVAILING_DEF_IRONLY
181 || node
->resolution
== LDPR_PREVAILING_DEF_IRONLY_EXP
)
182 && !flag_incremental_link
);
183 node
->resolution
= LDPR_PREVAILING_DEF_IRONLY
;
185 DECL_ARTIFICIAL (node
->decl
) = 1;
186 node
->force_output
= true;
189 /* Return length of attribute names string,
190 if arglist chain > 1, -1 otherwise. */
193 get_attr_len (tree arglist
)
199 for (arg
= arglist
; arg
; arg
= TREE_CHAIN (arg
))
201 const char *str
= TREE_STRING_POINTER (TREE_VALUE (arg
));
202 size_t len
= strlen (str
);
203 str_len_sum
+= len
+ 1;
204 for (const char *p
= strchr (str
, ','); p
; p
= strchr (p
+ 1, ','))
213 /* Create string with attributes separated by comma.
214 Return number of attributes. */
217 get_attr_str (tree arglist
, char *attr_str
)
220 size_t str_len_sum
= 0;
223 for (arg
= arglist
; arg
; arg
= TREE_CHAIN (arg
))
225 const char *str
= TREE_STRING_POINTER (TREE_VALUE (arg
));
226 size_t len
= strlen (str
);
227 for (const char *p
= strchr (str
, ','); p
; p
= strchr (p
+ 1, ','))
229 memcpy (attr_str
+ str_len_sum
, str
, len
);
230 attr_str
[str_len_sum
+ len
] = TREE_CHAIN (arg
) ? ',' : '\0';
231 str_len_sum
+= len
+ 1;
237 /* Return number of attributes separated by comma and put them into ARGS.
238 If there is no DEFAULT attribute return -1.
239 If there is an empty string in attribute return -2.
240 If there are multiple DEFAULT attributes return -3.
244 separate_attrs (char *attr_str
, char **attrs
, int attrnum
)
247 int default_count
= 0;
249 for (char *attr
= strtok (attr_str
, ",");
250 attr
!= NULL
; attr
= strtok (NULL
, ","))
252 if (strcmp (attr
, "default") == 0)
259 if (default_count
== 0)
261 else if (default_count
> 1)
263 else if (i
+ default_count
< attrnum
)
269 /* Return true if symbol is valid in assembler name. */
272 is_valid_asm_symbol (char c
)
274 if ('a' <= c
&& c
<= 'z')
276 if ('A' <= c
&& c
<= 'Z')
278 if ('0' <= c
&& c
<= '9')
285 /* Replace all not valid assembler symbols with '_'. */
288 create_new_asm_name (char *old_asm_name
, char *new_asm_name
)
291 int old_name_len
= strlen (old_asm_name
);
293 /* Replace all not valid assembler symbols with '_'. */
294 for (i
= 0; i
< old_name_len
; i
++)
295 if (!is_valid_asm_symbol (old_asm_name
[i
]))
296 new_asm_name
[i
] = '_';
298 new_asm_name
[i
] = old_asm_name
[i
];
299 new_asm_name
[old_name_len
] = '\0';
302 /* Creates target clone of NODE. */
305 create_target_clone (cgraph_node
*node
, bool definition
, char *name
,
308 cgraph_node
*new_node
;
312 new_node
= node
->create_version_clone_with_body (vNULL
, NULL
,
316 if (new_node
== NULL
)
318 new_node
->force_output
= true;
322 tree new_decl
= copy_node (node
->decl
);
323 new_node
= cgraph_node::get_create (new_decl
);
324 DECL_ATTRIBUTES (new_decl
) = attributes
;
325 /* Generate a new name for the new version. */
326 symtab
->change_decl_assembler_name (new_node
->decl
,
327 clone_function_name_numbered (
333 /* If the function in NODE has multiple target attributes
334 create the appropriate clone for each valid target attribute. */
337 expand_target_clones (struct cgraph_node
*node
, bool definition
)
340 /* Parsing target attributes separated by comma. */
341 tree attr_target
= lookup_attribute ("target_clones",
342 DECL_ATTRIBUTES (node
->decl
));
343 /* No targets specified. */
347 tree arglist
= TREE_VALUE (attr_target
);
348 int attr_len
= get_attr_len (arglist
);
350 /* No need to clone for 1 target attribute. */
353 warning_at (DECL_SOURCE_LOCATION (node
->decl
),
354 0, "single %<target_clones%> attribute is ignored");
359 && (node
->alias
|| !tree_versionable_function_p (node
->decl
)))
361 auto_diagnostic_group d
;
362 error_at (DECL_SOURCE_LOCATION (node
->decl
),
363 "clones for %<target_clones%> attribute cannot be created");
364 const char *reason
= NULL
;
365 if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node
->decl
)))
366 reason
= G_("function %q+F can never be copied "
367 "because it has %<noclone%> attribute");
368 else if (node
->alias
)
370 = "%<target_clones%> cannot be combined with %<alias%> attribute";
372 reason
= copy_forbidden (DECL_STRUCT_FUNCTION (node
->decl
));
374 inform (DECL_SOURCE_LOCATION (node
->decl
), reason
, node
->decl
);
378 char *attr_str
= XNEWVEC (char, attr_len
);
379 int attrnum
= get_attr_str (arglist
, attr_str
);
380 char **attrs
= XNEWVEC (char *, attrnum
);
382 attrnum
= separate_attrs (attr_str
, attrs
, attrnum
);
386 error_at (DECL_SOURCE_LOCATION (node
->decl
),
387 "%<default%> target was not set");
390 error_at (DECL_SOURCE_LOCATION (node
->decl
),
391 "an empty string cannot be in %<target_clones%> attribute");
394 error_at (DECL_SOURCE_LOCATION (node
->decl
),
395 "multiple %<default%> targets were set");
404 XDELETEVEC (attr_str
);
408 cgraph_function_version_info
*decl1_v
= NULL
;
409 cgraph_function_version_info
*decl2_v
= NULL
;
410 cgraph_function_version_info
*before
= NULL
;
411 cgraph_function_version_info
*after
= NULL
;
412 decl1_v
= node
->function_version ();
414 decl1_v
= node
->insert_new_function_version ();
416 DECL_FUNCTION_VERSIONED (node
->decl
) = 1;
418 for (i
= 0; i
< attrnum
; i
++)
420 char *attr
= attrs
[i
];
421 char *suffix
= XNEWVEC (char, strlen (attr
) + 1);
423 create_new_asm_name (attr
, suffix
);
424 /* Create new target clone. */
425 tree attributes
= make_attribute ("target", attr
,
426 DECL_ATTRIBUTES (node
->decl
));
428 cgraph_node
*new_node
= create_target_clone (node
, definition
, suffix
,
430 if (new_node
== NULL
)
432 new_node
->local
.local
= false;
435 decl2_v
= new_node
->function_version ();
438 decl2_v
= new_node
->insert_new_function_version ();
440 /* Chain decl2_v and decl1_v. All semantically identical versions
441 will be chained together. */
443 while (before
->next
!= NULL
)
444 before
= before
->next
;
445 while (after
->prev
!= NULL
)
448 before
->next
= after
;
449 after
->prev
= before
;
450 DECL_FUNCTION_VERSIONED (new_node
->decl
) = 1;
454 XDELETEVEC (attr_str
);
456 /* Setting new attribute to initial function. */
457 tree attributes
= make_attribute ("target", "default",
458 DECL_ATTRIBUTES (node
->decl
));
459 DECL_ATTRIBUTES (node
->decl
) = attributes
;
460 node
->local
.local
= false;
464 /* When NODE is a target clone, consider all callees and redirect
465 to a clone with equal target attributes. That prevents multiple
466 multi-versioning dispatches and a call-chain can be optimized. */
469 redirect_to_specific_clone (cgraph_node
*node
)
471 cgraph_function_version_info
*fv
= node
->function_version ();
475 tree attr_target
= lookup_attribute ("target", DECL_ATTRIBUTES (node
->decl
));
476 if (attr_target
== NULL_TREE
)
479 /* We need to remember NEXT_CALLER as it could be modified in the loop. */
480 for (cgraph_edge
*e
= node
->callees
; e
; e
= e
->next_callee
)
482 cgraph_function_version_info
*fv2
= e
->callee
->function_version ();
486 tree attr_target2
= lookup_attribute ("target",
487 DECL_ATTRIBUTES (e
->callee
->decl
));
489 /* Function is not calling proper target clone. */
490 if (!attribute_list_equal (attr_target
, attr_target2
))
492 while (fv2
->prev
!= NULL
)
495 /* Try to find a clone with equal target attribute. */
496 for (; fv2
!= NULL
; fv2
= fv2
->next
)
498 cgraph_node
*callee
= fv2
->this_node
;
499 attr_target2
= lookup_attribute ("target",
500 DECL_ATTRIBUTES (callee
->decl
));
501 if (attribute_list_equal (attr_target
, attr_target2
))
503 e
->redirect_callee (callee
);
504 e
->redirect_call_stmt_to_callee ();
513 ipa_target_clone (void)
515 struct cgraph_node
*node
;
516 auto_vec
<cgraph_node
*> to_dispatch
;
518 FOR_EACH_FUNCTION (node
)
519 if (expand_target_clones (node
, node
->definition
))
520 to_dispatch
.safe_push (node
);
522 for (unsigned i
= 0; i
< to_dispatch
.length (); i
++)
523 create_dispatcher_calls (to_dispatch
[i
]);
525 FOR_EACH_FUNCTION (node
)
526 redirect_to_specific_clone (node
);
533 const pass_data pass_data_target_clone
=
535 SIMPLE_IPA_PASS
, /* type */
536 "targetclone", /* name */
537 OPTGROUP_NONE
, /* optinfo_flags */
539 ( PROP_ssa
| PROP_cfg
), /* properties_required */
540 0, /* properties_provided */
541 0, /* properties_destroyed */
542 0, /* todo_flags_start */
543 TODO_update_ssa
/* todo_flags_finish */
546 class pass_target_clone
: public simple_ipa_opt_pass
549 pass_target_clone (gcc::context
*ctxt
)
550 : simple_ipa_opt_pass (pass_data_target_clone
, ctxt
)
553 /* opt_pass methods: */
554 virtual bool gate (function
*);
555 virtual unsigned int execute (function
*) { return ipa_target_clone (); }
559 pass_target_clone::gate (function
*)
566 simple_ipa_opt_pass
*
567 make_pass_target_clone (gcc::context
*ctxt
)
569 return new pass_target_clone (ctxt
);