typeck.c (cp_build_function_call_vec): When mark_used fails unconditionally return...
[official-gcc.git] / gcc / multiple_target.c
blob0a87241b25191ae910289fc5fb3d296ae554ff19
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
12 version.
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.
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/>. */
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"
42 /* Walker callback that replaces all FUNCTION_DECL of a function that's
43 going to be versioned. */
45 static tree
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;
55 *walk_subtrees = 0;
58 return NULL;
61 /* If the call in NODE has multiple target attribute with multiple fields,
62 replace it with dispatcher call and create dispatcher (once). */
64 static void
65 create_dispatcher_calls (struct cgraph_node *node)
67 ipa_ref *ref;
69 if (!DECL_FUNCTION_VERSIONED (node->decl)
70 || !is_function_default_version (node->decl))
71 return;
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");
78 return;
80 else if (!targetm.get_function_versions_dispatcher)
82 error_at (DECL_SOURCE_LOCATION (node->decl),
83 "target does not support function version dispatcher");
84 return;
87 tree idecl = targetm.get_function_versions_dispatcher (node->decl);
88 if (!idecl)
90 error_at (DECL_SOURCE_LOCATION (node->decl),
91 "default %<target_clones%> attribute was not set");
92 return;
95 cgraph_node *inode = cgraph_node::get (idecl);
96 gcc_assert (inode);
97 tree resolver_decl = targetm.generate_version_dispatcher_body (inode);
99 /* Update aliases. */
100 inode->alias = true;
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. */
124 unsigned i;
125 cgraph_edge *e;
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);
147 else
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);
163 else
164 gcc_unreachable ();
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
173 in next stage1. */
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. */
192 static int
193 get_attr_len (tree arglist)
195 tree arg;
196 int str_len_sum = 0;
197 int argnum = 0;
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, ','))
205 argnum++;
206 argnum++;
208 if (argnum <= 1)
209 return -1;
210 return str_len_sum;
213 /* Create string with attributes separated by comma.
214 Return number of attributes. */
216 static int
217 get_attr_str (tree arglist, char *attr_str)
219 tree arg;
220 size_t str_len_sum = 0;
221 int argnum = 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, ','))
228 argnum++;
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;
232 argnum++;
234 return argnum;
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.
243 static int
244 separate_attrs (char *attr_str, char **attrs, int attrnum)
246 int i = 0;
247 int default_count = 0;
249 for (char *attr = strtok (attr_str, ",");
250 attr != NULL; attr = strtok (NULL, ","))
252 if (strcmp (attr, "default") == 0)
254 default_count++;
255 continue;
257 attrs[i++] = attr;
259 if (default_count == 0)
260 return -1;
261 else if (default_count > 1)
262 return -3;
263 else if (i + default_count < attrnum)
264 return -2;
266 return i;
269 /* Return true if symbol is valid in assembler name. */
271 static bool
272 is_valid_asm_symbol (char c)
274 if ('a' <= c && c <= 'z')
275 return true;
276 if ('A' <= c && c <= 'Z')
277 return true;
278 if ('0' <= c && c <= '9')
279 return true;
280 if (c == '_')
281 return true;
282 return false;
285 /* Replace all not valid assembler symbols with '_'. */
287 static void
288 create_new_asm_name (char *old_asm_name, char *new_asm_name)
290 int i;
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] = '_';
297 else
298 new_asm_name[i] = old_asm_name[i];
299 new_asm_name[old_name_len] = '\0';
302 /* Creates target clone of NODE. */
304 static cgraph_node *
305 create_target_clone (cgraph_node *node, bool definition, char *name,
306 tree attributes)
308 cgraph_node *new_node;
310 if (definition)
312 new_node = node->create_version_clone_with_body (vNULL, NULL,
313 NULL, false,
314 NULL, NULL,
315 name, attributes);
316 if (new_node == NULL)
317 return NULL;
318 new_node->force_output = true;
320 else
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 (
328 node->decl, name));
330 return new_node;
333 /* If the function in NODE has multiple target attributes
334 create the appropriate clone for each valid target attribute. */
336 static bool
337 expand_target_clones (struct cgraph_node *node, bool definition)
339 int i;
340 /* Parsing target attributes separated by comma. */
341 tree attr_target = lookup_attribute ("target_clones",
342 DECL_ATTRIBUTES (node->decl));
343 /* No targets specified. */
344 if (!attr_target)
345 return false;
347 tree arglist = TREE_VALUE (attr_target);
348 int attr_len = get_attr_len (arglist);
350 /* No need to clone for 1 target attribute. */
351 if (attr_len == -1)
353 warning_at (DECL_SOURCE_LOCATION (node->decl),
354 0, "single %<target_clones%> attribute is ignored");
355 return false;
358 if (node->definition
359 && !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
369 reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
370 if (reason)
371 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
372 return false;
375 char *attr_str = XNEWVEC (char, attr_len);
376 int attrnum = get_attr_str (arglist, attr_str);
377 char **attrs = XNEWVEC (char *, attrnum);
379 attrnum = separate_attrs (attr_str, attrs, attrnum);
380 switch (attrnum)
382 case -1:
383 error_at (DECL_SOURCE_LOCATION (node->decl),
384 "%<default%> target was not set");
385 break;
386 case -2:
387 error_at (DECL_SOURCE_LOCATION (node->decl),
388 "an empty string cannot be in %<target_clones%> attribute");
389 break;
390 case -3:
391 error_at (DECL_SOURCE_LOCATION (node->decl),
392 "multiple %<default%> targets were set");
393 break;
394 default:
395 break;
398 if (attrnum < 0)
400 XDELETEVEC (attrs);
401 XDELETEVEC (attr_str);
402 return false;
405 cgraph_function_version_info *decl1_v = NULL;
406 cgraph_function_version_info *decl2_v = NULL;
407 cgraph_function_version_info *before = NULL;
408 cgraph_function_version_info *after = NULL;
409 decl1_v = node->function_version ();
410 if (decl1_v == NULL)
411 decl1_v = node->insert_new_function_version ();
412 before = decl1_v;
413 DECL_FUNCTION_VERSIONED (node->decl) = 1;
415 for (i = 0; i < attrnum; i++)
417 char *attr = attrs[i];
418 char *suffix = XNEWVEC (char, strlen (attr) + 1);
420 create_new_asm_name (attr, suffix);
421 /* Create new target clone. */
422 tree attributes = make_attribute ("target", attr,
423 DECL_ATTRIBUTES (node->decl));
425 cgraph_node *new_node = create_target_clone (node, definition, suffix,
426 attributes);
427 if (new_node == NULL)
428 return false;
429 new_node->local.local = false;
430 XDELETEVEC (suffix);
432 decl2_v = new_node->function_version ();
433 if (decl2_v != NULL)
434 continue;
435 decl2_v = new_node->insert_new_function_version ();
437 /* Chain decl2_v and decl1_v. All semantically identical versions
438 will be chained together. */
439 after = decl2_v;
440 while (before->next != NULL)
441 before = before->next;
442 while (after->prev != NULL)
443 after = after->prev;
445 before->next = after;
446 after->prev = before;
447 DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
450 XDELETEVEC (attrs);
451 XDELETEVEC (attr_str);
453 /* Setting new attribute to initial function. */
454 tree attributes = make_attribute ("target", "default",
455 DECL_ATTRIBUTES (node->decl));
456 DECL_ATTRIBUTES (node->decl) = attributes;
457 node->local.local = false;
458 return true;
461 /* When NODE is a target clone, consider all callees and redirect
462 to a clone with equal target attributes. That prevents multiple
463 multi-versioning dispatches and a call-chain can be optimized. */
465 static void
466 redirect_to_specific_clone (cgraph_node *node)
468 cgraph_function_version_info *fv = node->function_version ();
469 if (fv == NULL)
470 return;
472 tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
473 if (attr_target == NULL_TREE)
474 return;
476 /* We need to remember NEXT_CALLER as it could be modified in the loop. */
477 for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
479 cgraph_function_version_info *fv2 = e->callee->function_version ();
480 if (!fv2)
481 continue;
483 tree attr_target2 = lookup_attribute ("target",
484 DECL_ATTRIBUTES (e->callee->decl));
486 /* Function is not calling proper target clone. */
487 if (!attribute_list_equal (attr_target, attr_target2))
489 while (fv2->prev != NULL)
490 fv2 = fv2->prev;
492 /* Try to find a clone with equal target attribute. */
493 for (; fv2 != NULL; fv2 = fv2->next)
495 cgraph_node *callee = fv2->this_node;
496 attr_target2 = lookup_attribute ("target",
497 DECL_ATTRIBUTES (callee->decl));
498 if (attribute_list_equal (attr_target, attr_target2))
500 e->redirect_callee (callee);
501 e->redirect_call_stmt_to_callee ();
502 break;
509 static unsigned int
510 ipa_target_clone (void)
512 struct cgraph_node *node;
513 auto_vec<cgraph_node *> to_dispatch;
515 FOR_EACH_FUNCTION (node)
516 if (expand_target_clones (node, node->definition))
517 to_dispatch.safe_push (node);
519 for (unsigned i = 0; i < to_dispatch.length (); i++)
520 create_dispatcher_calls (to_dispatch[i]);
522 FOR_EACH_FUNCTION (node)
523 redirect_to_specific_clone (node);
525 return 0;
528 namespace {
530 const pass_data pass_data_target_clone =
532 SIMPLE_IPA_PASS, /* type */
533 "targetclone", /* name */
534 OPTGROUP_NONE, /* optinfo_flags */
535 TV_NONE, /* tv_id */
536 ( PROP_ssa | PROP_cfg ), /* properties_required */
537 0, /* properties_provided */
538 0, /* properties_destroyed */
539 0, /* todo_flags_start */
540 TODO_update_ssa /* todo_flags_finish */
543 class pass_target_clone : public simple_ipa_opt_pass
545 public:
546 pass_target_clone (gcc::context *ctxt)
547 : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
550 /* opt_pass methods: */
551 virtual bool gate (function *);
552 virtual unsigned int execute (function *) { return ipa_target_clone (); }
555 bool
556 pass_target_clone::gate (function *)
558 return true;
561 } // anon namespace
563 simple_ipa_opt_pass *
564 make_pass_target_clone (gcc::context *ctxt)
566 return new pass_target_clone (ctxt);