re PR target/87532 (bad results from vec_extract(unsigned char, foo) dependent upon...
[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 source->add_to_same_comdat_group (inode);
162 }
163 else
164 gcc_unreachable ();
165 }
166 }
167
168 symtab->change_decl_assembler_name (node->decl,
169 clone_function_name_numbered (
170 node->decl, "default"));
171
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;
184
185 DECL_ARTIFICIAL (node->decl) = 1;
186 node->force_output = true;
187 }
188
189 /* Return length of attribute names string,
190 if arglist chain > 1, -1 otherwise. */
191
192 static int
193 get_attr_len (tree arglist)
194 {
195 tree arg;
196 int str_len_sum = 0;
197 int argnum = 0;
198
199 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
200 {
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++;
207 }
208 if (argnum <= 1)
209 return -1;
210 return str_len_sum;
211 }
212
213 /* Create string with attributes separated by comma.
214 Return number of attributes. */
215
216 static int
217 get_attr_str (tree arglist, char *attr_str)
218 {
219 tree arg;
220 size_t str_len_sum = 0;
221 int argnum = 0;
222
223 for (arg = arglist; arg; arg = TREE_CHAIN (arg))
224 {
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++;
233 }
234 return argnum;
235 }
236
237 /* Return number of attributes separated by comma and put them into ARGS.
238 If there is no DEFAULT attribute return -1. If there is an empty
239 string in attribute return -2. */
240
241 static int
242 separate_attrs (char *attr_str, char **attrs, int attrnum)
243 {
244 int i = 0;
245 int default_count = 0;
246
247 for (char *attr = strtok (attr_str, ",");
248 attr != NULL; attr = strtok (NULL, ","))
249 {
250 if (strcmp (attr, "default") == 0)
251 {
252 default_count++;
253 continue;
254 }
255 attrs[i++] = attr;
256 }
257 if (default_count == 0)
258 return -1;
259 else if (i + default_count < attrnum)
260 return -2;
261
262 return i;
263 }
264
265 /* Return true if symbol is valid in assembler name. */
266
267 static bool
268 is_valid_asm_symbol (char c)
269 {
270 if ('a' <= c && c <= 'z')
271 return true;
272 if ('A' <= c && c <= 'Z')
273 return true;
274 if ('0' <= c && c <= '9')
275 return true;
276 if (c == '_')
277 return true;
278 return false;
279 }
280
281 /* Replace all not valid assembler symbols with '_'. */
282
283 static void
284 create_new_asm_name (char *old_asm_name, char *new_asm_name)
285 {
286 int i;
287 int old_name_len = strlen (old_asm_name);
288
289 /* Replace all not valid assembler symbols with '_'. */
290 for (i = 0; i < old_name_len; i++)
291 if (!is_valid_asm_symbol (old_asm_name[i]))
292 new_asm_name[i] = '_';
293 else
294 new_asm_name[i] = old_asm_name[i];
295 new_asm_name[old_name_len] = '\0';
296 }
297
298 /* Creates target clone of NODE. */
299
300 static cgraph_node *
301 create_target_clone (cgraph_node *node, bool definition, char *name,
302 tree attributes)
303 {
304 cgraph_node *new_node;
305
306 if (definition)
307 {
308 new_node = node->create_version_clone_with_body (vNULL, NULL,
309 NULL, false,
310 NULL, NULL,
311 name, attributes);
312 if (new_node == NULL)
313 return NULL;
314 new_node->force_output = true;
315 }
316 else
317 {
318 tree new_decl = copy_node (node->decl);
319 new_node = cgraph_node::get_create (new_decl);
320 DECL_ATTRIBUTES (new_decl) = attributes;
321 /* Generate a new name for the new version. */
322 symtab->change_decl_assembler_name (new_node->decl,
323 clone_function_name_numbered (
324 node->decl, name));
325 }
326 return new_node;
327 }
328
329 /* If the function in NODE has multiple target attributes
330 create the appropriate clone for each valid target attribute. */
331
332 static bool
333 expand_target_clones (struct cgraph_node *node, bool definition)
334 {
335 int i;
336 /* Parsing target attributes separated by comma. */
337 tree attr_target = lookup_attribute ("target_clones",
338 DECL_ATTRIBUTES (node->decl));
339 /* No targets specified. */
340 if (!attr_target)
341 return false;
342
343 tree arglist = TREE_VALUE (attr_target);
344 int attr_len = get_attr_len (arglist);
345
346 /* No need to clone for 1 target attribute. */
347 if (attr_len == -1)
348 {
349 warning_at (DECL_SOURCE_LOCATION (node->decl),
350 0,
351 "single %<target_clones%> attribute is ignored");
352 return false;
353 }
354
355 if (node->definition
356 && !tree_versionable_function_p (node->decl))
357 {
358 auto_diagnostic_group d;
359 error_at (DECL_SOURCE_LOCATION (node->decl),
360 "clones for %<target_clones%> attribute cannot be created");
361 const char *reason = NULL;
362 if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
363 reason = G_("function %q+F can never be copied "
364 "because it has %<noclone%> attribute");
365 else
366 reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
367 if (reason)
368 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
369 return false;
370 }
371
372 char *attr_str = XNEWVEC (char, attr_len);
373 int attrnum = get_attr_str (arglist, attr_str);
374 char **attrs = XNEWVEC (char *, attrnum);
375
376 attrnum = separate_attrs (attr_str, attrs, attrnum);
377 if (attrnum == -1)
378 {
379 error_at (DECL_SOURCE_LOCATION (node->decl),
380 "default target was not set");
381 XDELETEVEC (attrs);
382 XDELETEVEC (attr_str);
383 return false;
384 }
385 else if (attrnum == -2)
386 {
387 error_at (DECL_SOURCE_LOCATION (node->decl),
388 "an empty string cannot be in %<target_clones%> attribute");
389 XDELETEVEC (attrs);
390 XDELETEVEC (attr_str);
391 return false;
392 }
393
394 cgraph_function_version_info *decl1_v = NULL;
395 cgraph_function_version_info *decl2_v = NULL;
396 cgraph_function_version_info *before = NULL;
397 cgraph_function_version_info *after = NULL;
398 decl1_v = node->function_version ();
399 if (decl1_v == NULL)
400 decl1_v = node->insert_new_function_version ();
401 before = decl1_v;
402 DECL_FUNCTION_VERSIONED (node->decl) = 1;
403
404 for (i = 0; i < attrnum; i++)
405 {
406 char *attr = attrs[i];
407 char *suffix = XNEWVEC (char, strlen (attr) + 1);
408
409 create_new_asm_name (attr, suffix);
410 /* Create new target clone. */
411 tree attributes = make_attribute ("target", attr,
412 DECL_ATTRIBUTES (node->decl));
413
414 cgraph_node *new_node = create_target_clone (node, definition, suffix,
415 attributes);
416 if (new_node == NULL)
417 return false;
418 new_node->local.local = false;
419 XDELETEVEC (suffix);
420
421 decl2_v = new_node->function_version ();
422 if (decl2_v != NULL)
423 continue;
424 decl2_v = new_node->insert_new_function_version ();
425
426 /* Chain decl2_v and decl1_v. All semantically identical versions
427 will be chained together. */
428 after = decl2_v;
429 while (before->next != NULL)
430 before = before->next;
431 while (after->prev != NULL)
432 after = after->prev;
433
434 before->next = after;
435 after->prev = before;
436 DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
437 }
438
439 XDELETEVEC (attrs);
440 XDELETEVEC (attr_str);
441
442 /* Setting new attribute to initial function. */
443 tree attributes = make_attribute ("target", "default",
444 DECL_ATTRIBUTES (node->decl));
445 DECL_ATTRIBUTES (node->decl) = attributes;
446 node->local.local = false;
447 return true;
448 }
449
450 /* When NODE is a target clone, consider all callees and redirect
451 to a clone with equal target attributes. That prevents multiple
452 multi-versioning dispatches and a call-chain can be optimized. */
453
454 static void
455 redirect_to_specific_clone (cgraph_node *node)
456 {
457 cgraph_function_version_info *fv = node->function_version ();
458 if (fv == NULL)
459 return;
460
461 tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
462 if (attr_target == NULL_TREE)
463 return;
464
465 /* We need to remember NEXT_CALLER as it could be modified in the loop. */
466 for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
467 {
468 cgraph_function_version_info *fv2 = e->callee->function_version ();
469 if (!fv2)
470 continue;
471
472 tree attr_target2 = lookup_attribute ("target",
473 DECL_ATTRIBUTES (e->callee->decl));
474
475 /* Function is not calling proper target clone. */
476 if (!attribute_list_equal (attr_target, attr_target2))
477 {
478 while (fv2->prev != NULL)
479 fv2 = fv2->prev;
480
481 /* Try to find a clone with equal target attribute. */
482 for (; fv2 != NULL; fv2 = fv2->next)
483 {
484 cgraph_node *callee = fv2->this_node;
485 attr_target2 = lookup_attribute ("target",
486 DECL_ATTRIBUTES (callee->decl));
487 if (attribute_list_equal (attr_target, attr_target2))
488 {
489 e->redirect_callee (callee);
490 e->redirect_call_stmt_to_callee ();
491 break;
492 }
493 }
494 }
495 }
496 }
497
498 static unsigned int
499 ipa_target_clone (void)
500 {
501 struct cgraph_node *node;
502 auto_vec<cgraph_node *> to_dispatch;
503
504 FOR_EACH_FUNCTION (node)
505 if (expand_target_clones (node, node->definition))
506 to_dispatch.safe_push (node);
507
508 for (unsigned i = 0; i < to_dispatch.length (); i++)
509 create_dispatcher_calls (to_dispatch[i]);
510
511 FOR_EACH_FUNCTION (node)
512 redirect_to_specific_clone (node);
513
514 return 0;
515 }
516
517 namespace {
518
519 const pass_data pass_data_target_clone =
520 {
521 SIMPLE_IPA_PASS, /* type */
522 "targetclone", /* name */
523 OPTGROUP_NONE, /* optinfo_flags */
524 TV_NONE, /* tv_id */
525 ( PROP_ssa | PROP_cfg ), /* properties_required */
526 0, /* properties_provided */
527 0, /* properties_destroyed */
528 0, /* todo_flags_start */
529 TODO_update_ssa /* todo_flags_finish */
530 };
531
532 class pass_target_clone : public simple_ipa_opt_pass
533 {
534 public:
535 pass_target_clone (gcc::context *ctxt)
536 : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
537 {}
538
539 /* opt_pass methods: */
540 virtual bool gate (function *);
541 virtual unsigned int execute (function *) { return ipa_target_clone (); }
542 };
543
544 bool
545 pass_target_clone::gate (function *)
546 {
547 return true;
548 }
549
550 } // anon namespace
551
552 simple_ipa_opt_pass *
553 make_pass_target_clone (gcc::context *ctxt)
554 {
555 return new pass_target_clone (ctxt);
556 }