1 /* Pass for parsing functions with multiple target attributes.
2
3 Contributed by Evgeny Stupachenko <evstupac@gmail.com>
4
5 Copyright (C) 2015-2018 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
replace_function_decl(tree * op,int * walk_subtrees,void * data)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
create_dispatcher_calls(struct cgraph_node * node)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 (node->decl,
171 "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
get_attr_len(tree arglist)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
get_attr_str(tree arglist,char * attr_str)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. If there is an empty
240 string in attribute return -2. */
241
242 static int
separate_attrs(char * attr_str,char ** attrs,int attrnum)243 separate_attrs (char *attr_str, char **attrs, int attrnum)
244 {
245 int i = 0;
246 int default_count = 0;
247
248 for (char *attr = strtok (attr_str, ",");
249 attr != NULL; attr = strtok (NULL, ","))
250 {
251 if (strcmp (attr, "default") == 0)
252 {
253 default_count++;
254 continue;
255 }
256 attrs[i++] = attr;
257 }
258 if (default_count == 0)
259 return -1;
260 else if (i + default_count < attrnum)
261 return -2;
262
263 return i;
264 }
265
266 /* Return true if symbol is valid in assembler name. */
267
268 static bool
is_valid_asm_symbol(char c)269 is_valid_asm_symbol (char c)
270 {
271 if ('a' <= c && c <= 'z')
272 return true;
273 if ('A' <= c && c <= 'Z')
274 return true;
275 if ('0' <= c && c <= '9')
276 return true;
277 if (c == '_')
278 return true;
279 return false;
280 }
281
282 /* Replace all not valid assembler symbols with '_'. */
283
284 static void
create_new_asm_name(char * old_asm_name,char * new_asm_name)285 create_new_asm_name (char *old_asm_name, char *new_asm_name)
286 {
287 int i;
288 int old_name_len = strlen (old_asm_name);
289
290 /* Replace all not valid assembler symbols with '_'. */
291 for (i = 0; i < old_name_len; i++)
292 if (!is_valid_asm_symbol (old_asm_name[i]))
293 new_asm_name[i] = '_';
294 else
295 new_asm_name[i] = old_asm_name[i];
296 new_asm_name[old_name_len] = '\0';
297 }
298
299 /* Creates target clone of NODE. */
300
301 static cgraph_node *
create_target_clone(cgraph_node * node,bool definition,char * name,tree attributes)302 create_target_clone (cgraph_node *node, bool definition, char *name,
303 tree attributes)
304 {
305 cgraph_node *new_node;
306
307 if (definition)
308 {
309 new_node = node->create_version_clone_with_body (vNULL, NULL,
310 NULL, false,
311 NULL, NULL,
312 name, attributes);
313 if (new_node == NULL)
314 return NULL;
315 new_node->force_output = true;
316 }
317 else
318 {
319 tree new_decl = copy_node (node->decl);
320 new_node = cgraph_node::get_create (new_decl);
321 DECL_ATTRIBUTES (new_decl) = attributes;
322 /* Generate a new name for the new version. */
323 symtab->change_decl_assembler_name (new_node->decl,
324 clone_function_name (node->decl,
325 name));
326 }
327 return new_node;
328 }
329
330 /* If the function in NODE has multiple target attributes
331 create the appropriate clone for each valid target attribute. */
332
333 static bool
expand_target_clones(struct cgraph_node * node,bool definition)334 expand_target_clones (struct cgraph_node *node, bool definition)
335 {
336 int i;
337 /* Parsing target attributes separated by comma. */
338 tree attr_target = lookup_attribute ("target_clones",
339 DECL_ATTRIBUTES (node->decl));
340 /* No targets specified. */
341 if (!attr_target)
342 return false;
343
344 tree arglist = TREE_VALUE (attr_target);
345 int attr_len = get_attr_len (arglist);
346
347 /* No need to clone for 1 target attribute. */
348 if (attr_len == -1)
349 {
350 warning_at (DECL_SOURCE_LOCATION (node->decl),
351 0,
352 "single %<target_clones%> attribute is ignored");
353 return false;
354 }
355
356 if (node->definition
357 && !tree_versionable_function_p (node->decl))
358 {
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 static unsigned int
ipa_target_clone(void)451 ipa_target_clone (void)
452 {
453 struct cgraph_node *node;
454 auto_vec<cgraph_node *> to_dispatch;
455
456 FOR_EACH_FUNCTION (node)
457 if (expand_target_clones (node, node->definition))
458 to_dispatch.safe_push (node);
459
460 for (unsigned i = 0; i < to_dispatch.length (); i++)
461 create_dispatcher_calls (to_dispatch[i]);
462
463 return 0;
464 }
465
466 namespace {
467
468 const pass_data pass_data_target_clone =
469 {
470 SIMPLE_IPA_PASS, /* type */
471 "targetclone", /* name */
472 OPTGROUP_NONE, /* optinfo_flags */
473 TV_NONE, /* tv_id */
474 ( PROP_ssa | PROP_cfg ), /* properties_required */
475 0, /* properties_provided */
476 0, /* properties_destroyed */
477 0, /* todo_flags_start */
478 TODO_update_ssa /* todo_flags_finish */
479 };
480
481 class pass_target_clone : public simple_ipa_opt_pass
482 {
483 public:
pass_target_clone(gcc::context * ctxt)484 pass_target_clone (gcc::context *ctxt)
485 : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
486 {}
487
488 /* opt_pass methods: */
489 virtual bool gate (function *);
execute(function *)490 virtual unsigned int execute (function *) { return ipa_target_clone (); }
491 };
492
493 bool
gate(function *)494 pass_target_clone::gate (function *)
495 {
496 return true;
497 }
498
499 } // anon namespace
500
501 simple_ipa_opt_pass *
make_pass_target_clone(gcc::context * ctxt)502 make_pass_target_clone (gcc::context *ctxt)
503 {
504 return new pass_target_clone (ctxt);
505 }
506