re PR bootstrap/92433 (r276645 breaks bootstrap on powerpc)
[gcc.git] / gcc / multiple_target.c
1 /* Pass for parsing functions with multiple target attributes.
2
3 Contributed by Evgeny Stupachenko <evstupac@gmail.com>
4
5 Copyright (C) 2015-2019 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 replace_function_decl (tree *op, int *walk_subtrees, void *data)
47 {
48 struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
49 cgraph_function_version_info *info = (cgraph_function_version_info *)wi->info;
50
51 if (TREE_CODE (*op) == FUNCTION_DECL
52 && info->this_node->decl == *op)
53 {
54 *op = info->dispatcher_resolver;
55 *walk_subtrees = 0;
56 }
57
58 return NULL;
59 }
60
61 /* If the call in NODE has multiple target attribute with multiple fields,
62 replace it with dispatcher call and create dispatcher (once). */
63
64 static void
65 create_dispatcher_calls (struct cgraph_node *node)
66 {
67 ipa_ref *ref;
68
69 if (!DECL_FUNCTION_VERSIONED (node->decl)
70 || !is_function_default_version (node->decl))
71 return;
72
73 if (!targetm.has_ifunc_p ())
74 {
75 error_at (DECL_SOURCE_LOCATION (node->decl),
76 "the call requires %<ifunc%>, which is not"
77 " supported by this target");
78 return;
79 }
80 else if (!targetm.get_function_versions_dispatcher)
81 {
82 error_at (DECL_SOURCE_LOCATION (node->decl),
83 "target does not support function version dispatcher");
84 return;
85 }
86
87 tree idecl = targetm.get_function_versions_dispatcher (node->decl);
88 if (!idecl)
89 {
90 error_at (DECL_SOURCE_LOCATION (node->decl),
91 "default %<target_clones%> attribute was not set");
92 return;
93 }
94
95 cgraph_node *inode = cgraph_node::get (idecl);
96 gcc_assert (inode);
97 tree resolver_decl = targetm.generate_version_dispatcher_body (inode);
98
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));
104
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;
110
111 while (node->iterate_referring (0, ref))
112 {
113 references_to_redirect.safe_push (*ref);
114 ref->remove_reference ();
115 }
116
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);
120
121 if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ())
122 {
123 /* Redirect edges. */
124 unsigned i;
125 cgraph_edge *e;
126 FOR_EACH_VEC_ELT (edges_to_redirect, i, e)
127 {
128 e->redirect_callee (inode);
129 e->redirect_call_stmt_to_callee ();
130 }
131
132 /* Redirect references. */
133 FOR_EACH_VEC_ELT (references_to_redirect, i, ref)
134 {
135 if (ref->use == IPA_REF_ADDR)
136 {
137 struct walk_stmt_info wi;
138 memset (&wi, 0, sizeof (wi));
139 wi.info = (void *)node->function_version ();
140
141 if (dyn_cast<varpool_node *> (ref->referring))
142 {
143 hash_set<tree> visited_nodes;
144 walk_tree (&DECL_INITIAL (ref->referring->decl),
145 replace_function_decl, &wi, &visited_nodes);
146 }
147 else
148 {
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);
152 }
153
154 symtab_node *source = ref->referring;
155 source->create_reference (inode, IPA_REF_ADDR);
156 }
157 else if (ref->use == IPA_REF_ALIAS)
158 {
159 symtab_node *source = ref->referring;
160 source->create_reference (inode, IPA_REF_ALIAS);
161 if (inode->get_comdat_group ())
162 source->add_to_same_comdat_group (inode);
163 }
164 else
165 gcc_unreachable ();
166 }
167 }
168
169 symtab->change_decl_assembler_name (node->decl,
170 clone_function_name_numbered (
171 node->decl, "default"));
172
173 /* FIXME: copy of cgraph_node::make_local that should be cleaned up
174 in next stage1. */
175 node->make_decl_local ();
176 node->set_section (NULL);
177 node->set_comdat_group (NULL);
178 node->externally_visible = false;
179 node->forced_by_abi = false;
180 node->set_section (NULL);
181 node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY
182 || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
183 && !flag_incremental_link);
184 node->resolution = LDPR_PREVAILING_DEF_IRONLY;
185
186 DECL_ARTIFICIAL (node->decl) = 1;
187 node->force_output = true;
188 }
189
190 /* Return length of attribute names string,
191 if arglist chain > 1, -1 otherwise. */
192
193 static int
194 get_attr_len (tree arglist)
195 {
196 tree arg;
197 int str_len_sum = 0;
198 int argnum = 0;
199
200 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
201 {
202 const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
203 size_t len = strlen (str);
204 str_len_sum += len + 1;
205 for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ','))
206 argnum++;
207 argnum++;
208 }
209 if (argnum <= 1)
210 return -1;
211 return str_len_sum;
212 }
213
214 /* Create string with attributes separated by comma.
215 Return number of attributes. */
216
217 static int
218 get_attr_str (tree arglist, char *attr_str)
219 {
220 tree arg;
221 size_t str_len_sum = 0;
222 int argnum = 0;
223
224 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
225 {
226 const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
227 size_t len = strlen (str);
228 for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ','))
229 argnum++;
230 memcpy (attr_str + str_len_sum, str, len);
231 attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
232 str_len_sum += len + 1;
233 argnum++;
234 }
235 return argnum;
236 }
237
238 /* Return number of attributes separated by comma and put them into ARGS.
239 If there is no DEFAULT attribute return -1.
240 If there is an empty string in attribute return -2.
241 If there are multiple DEFAULT attributes return -3.
242 */
243
244 static int
245 separate_attrs (char *attr_str, char **attrs, int attrnum)
246 {
247 int i = 0;
248 int default_count = 0;
249
250 for (char *attr = strtok (attr_str, ",");
251 attr != NULL; attr = strtok (NULL, ","))
252 {
253 if (strcmp (attr, "default") == 0)
254 {
255 default_count++;
256 continue;
257 }
258 attrs[i++] = attr;
259 }
260 if (default_count == 0)
261 return -1;
262 else if (default_count > 1)
263 return -3;
264 else if (i + default_count < attrnum)
265 return -2;
266
267 return i;
268 }
269
270 /* Return true if symbol is valid in assembler name. */
271
272 static bool
273 is_valid_asm_symbol (char c)
274 {
275 if ('a' <= c && c <= 'z')
276 return true;
277 if ('A' <= c && c <= 'Z')
278 return true;
279 if ('0' <= c && c <= '9')
280 return true;
281 if (c == '_')
282 return true;
283 return false;
284 }
285
286 /* Replace all not valid assembler symbols with '_'. */
287
288 static void
289 create_new_asm_name (char *old_asm_name, char *new_asm_name)
290 {
291 int i;
292 int old_name_len = strlen (old_asm_name);
293
294 /* Replace all not valid assembler symbols with '_'. */
295 for (i = 0; i < old_name_len; i++)
296 if (!is_valid_asm_symbol (old_asm_name[i]))
297 new_asm_name[i] = '_';
298 else
299 new_asm_name[i] = old_asm_name[i];
300 new_asm_name[old_name_len] = '\0';
301 }
302
303 /* Creates target clone of NODE. */
304
305 static cgraph_node *
306 create_target_clone (cgraph_node *node, bool definition, char *name,
307 tree attributes)
308 {
309 cgraph_node *new_node;
310
311 if (definition)
312 {
313 new_node = node->create_version_clone_with_body (vNULL, NULL,
314 NULL, NULL,
315 NULL, name, attributes);
316 if (new_node == NULL)
317 return NULL;
318 new_node->force_output = true;
319 }
320 else
321 {
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));
329 }
330 return new_node;
331 }
332
333 /* If the function in NODE has multiple target attributes
334 create the appropriate clone for each valid target attribute. */
335
336 static bool
337 expand_target_clones (struct cgraph_node *node, bool definition)
338 {
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;
346
347 tree arglist = TREE_VALUE (attr_target);
348 int attr_len = get_attr_len (arglist);
349
350 /* No need to clone for 1 target attribute. */
351 if (attr_len == -1)
352 {
353 warning_at (DECL_SOURCE_LOCATION (node->decl),
354 0, "single %<target_clones%> attribute is ignored");
355 return false;
356 }
357
358 if (node->definition
359 && (node->alias || !tree_versionable_function_p (node->decl)))
360 {
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)
369 reason
370 = "%<target_clones%> cannot be combined with %<alias%> attribute";
371 else
372 reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
373 if (reason)
374 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
375 return false;
376 }
377
378 char *attr_str = XNEWVEC (char, attr_len);
379 int attrnum = get_attr_str (arglist, attr_str);
380 char **attrs = XNEWVEC (char *, attrnum);
381
382 attrnum = separate_attrs (attr_str, attrs, attrnum);
383 switch (attrnum)
384 {
385 case -1:
386 error_at (DECL_SOURCE_LOCATION (node->decl),
387 "%<default%> target was not set");
388 break;
389 case -2:
390 error_at (DECL_SOURCE_LOCATION (node->decl),
391 "an empty string cannot be in %<target_clones%> attribute");
392 break;
393 case -3:
394 error_at (DECL_SOURCE_LOCATION (node->decl),
395 "multiple %<default%> targets were set");
396 break;
397 default:
398 break;
399 }
400
401 if (attrnum < 0)
402 {
403 XDELETEVEC (attrs);
404 XDELETEVEC (attr_str);
405 return false;
406 }
407
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 ();
413 if (decl1_v == NULL)
414 decl1_v = node->insert_new_function_version ();
415 before = decl1_v;
416 DECL_FUNCTION_VERSIONED (node->decl) = 1;
417
418 for (i = 0; i < attrnum; i++)
419 {
420 char *attr = attrs[i];
421 char *suffix = XNEWVEC (char, strlen (attr) + 1);
422
423 create_new_asm_name (attr, suffix);
424 /* Create new target clone. */
425 tree attributes = make_attribute ("target", attr,
426 DECL_ATTRIBUTES (node->decl));
427
428 cgraph_node *new_node = create_target_clone (node, definition, suffix,
429 attributes);
430 if (new_node == NULL)
431 return false;
432 new_node->local = false;
433 XDELETEVEC (suffix);
434
435 decl2_v = new_node->function_version ();
436 if (decl2_v != NULL)
437 continue;
438 decl2_v = new_node->insert_new_function_version ();
439
440 /* Chain decl2_v and decl1_v. All semantically identical versions
441 will be chained together. */
442 after = decl2_v;
443 while (before->next != NULL)
444 before = before->next;
445 while (after->prev != NULL)
446 after = after->prev;
447
448 before->next = after;
449 after->prev = before;
450 DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
451 }
452
453 XDELETEVEC (attrs);
454 XDELETEVEC (attr_str);
455
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 = false;
461 return true;
462 }
463
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. */
467
468 static void
469 redirect_to_specific_clone (cgraph_node *node)
470 {
471 cgraph_function_version_info *fv = node->function_version ();
472 if (fv == NULL)
473 return;
474
475 tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
476 if (attr_target == NULL_TREE)
477 return;
478
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)
481 {
482 cgraph_function_version_info *fv2 = e->callee->function_version ();
483 if (!fv2)
484 continue;
485
486 tree attr_target2 = lookup_attribute ("target",
487 DECL_ATTRIBUTES (e->callee->decl));
488
489 /* Function is not calling proper target clone. */
490 if (!attribute_list_equal (attr_target, attr_target2))
491 {
492 while (fv2->prev != NULL)
493 fv2 = fv2->prev;
494
495 /* Try to find a clone with equal target attribute. */
496 for (; fv2 != NULL; fv2 = fv2->next)
497 {
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))
502 {
503 e->redirect_callee (callee);
504 e->redirect_call_stmt_to_callee ();
505 break;
506 }
507 }
508 }
509 }
510 }
511
512 static unsigned int
513 ipa_target_clone (void)
514 {
515 struct cgraph_node *node;
516 auto_vec<cgraph_node *> to_dispatch;
517
518 FOR_EACH_FUNCTION (node)
519 if (expand_target_clones (node, node->definition))
520 to_dispatch.safe_push (node);
521
522 for (unsigned i = 0; i < to_dispatch.length (); i++)
523 create_dispatcher_calls (to_dispatch[i]);
524
525 FOR_EACH_FUNCTION (node)
526 redirect_to_specific_clone (node);
527
528 return 0;
529 }
530
531 namespace {
532
533 const pass_data pass_data_target_clone =
534 {
535 SIMPLE_IPA_PASS, /* type */
536 "targetclone", /* name */
537 OPTGROUP_NONE, /* optinfo_flags */
538 TV_NONE, /* tv_id */
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 */
544 };
545
546 class pass_target_clone : public simple_ipa_opt_pass
547 {
548 public:
549 pass_target_clone (gcc::context *ctxt)
550 : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
551 {}
552
553 /* opt_pass methods: */
554 virtual bool gate (function *);
555 virtual unsigned int execute (function *) { return ipa_target_clone (); }
556 };
557
558 bool
559 pass_target_clone::gate (function *)
560 {
561 return true;
562 }
563
564 } // anon namespace
565
566 simple_ipa_opt_pass *
567 make_pass_target_clone (gcc::context *ctxt)
568 {
569 return new pass_target_clone (ctxt);
570 }