comparison gcc/multiple_target.c @ 131:84e7813d76e9

gcc-8.2
author mir3636
date Thu, 25 Oct 2018 07:37:49 +0900
parents 04ced10e8804
children 1830386684a0
comparison
equal deleted inserted replaced
111:04ced10e8804 131:84e7813d76e9
1 /* Pass for parsing functions with multiple target attributes. 1 /* Pass for parsing functions with multiple target attributes.
2 2
3 Contributed by Evgeny Stupachenko <evstupac@gmail.com> 3 Contributed by Evgeny Stupachenko <evstupac@gmail.com>
4 4
5 Copyright (C) 2015-2017 Free Software Foundation, Inc. 5 Copyright (C) 2015-2018 Free Software Foundation, Inc.
6 6
7 This file is part of GCC. 7 This file is part of GCC.
8 8
9 GCC is free software; you can redistribute it and/or modify it under 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 10 the terms of the GNU General Public License as published by the Free
34 #include "target.h" 34 #include "target.h"
35 #include "attribs.h" 35 #include "attribs.h"
36 #include "pretty-print.h" 36 #include "pretty-print.h"
37 #include "gimple-iterator.h" 37 #include "gimple-iterator.h"
38 #include "gimple-walk.h" 38 #include "gimple-walk.h"
39 #include "tree-inline.h"
40 #include "intl.h"
39 41
40 /* Walker callback that replaces all FUNCTION_DECL of a function that's 42 /* Walker callback that replaces all FUNCTION_DECL of a function that's
41 going to be versioned. */ 43 going to be versioned. */
42 44
43 static tree 45 static tree
84 86
85 tree idecl = targetm.get_function_versions_dispatcher (node->decl); 87 tree idecl = targetm.get_function_versions_dispatcher (node->decl);
86 if (!idecl) 88 if (!idecl)
87 { 89 {
88 error_at (DECL_SOURCE_LOCATION (node->decl), 90 error_at (DECL_SOURCE_LOCATION (node->decl),
89 "default target_clones attribute was not set"); 91 "default %<target_clones%> attribute was not set");
90 return; 92 return;
91 } 93 }
92 94
93 cgraph_node *inode = cgraph_node::get (idecl); 95 cgraph_node *inode = cgraph_node::get (idecl);
94 gcc_assert (inode); 96 gcc_assert (inode);
140 { 142 {
141 gimple_stmt_iterator it = gsi_for_stmt (ref->stmt); 143 gimple_stmt_iterator it = gsi_for_stmt (ref->stmt);
142 if (ref->referring->decl != resolver_decl) 144 if (ref->referring->decl != resolver_decl)
143 walk_gimple_stmt (&it, NULL, replace_function_decl, &wi); 145 walk_gimple_stmt (&it, NULL, replace_function_decl, &wi);
144 } 146 }
147
148 symtab_node *source = ref->referring;
149 ref->remove_reference ();
150 source->create_reference (inode, IPA_REF_ADDR);
151 }
152 else if (ref->use == IPA_REF_ALIAS)
153 {
154 symtab_node *source = ref->referring;
155 ref->remove_reference ();
156 source->create_reference (inode, IPA_REF_ALIAS);
157 source->add_to_same_comdat_group (inode);
145 } 158 }
146 else 159 else
147 gcc_unreachable (); 160 gcc_unreachable ();
148 } 161 }
149 } 162 }
150 163
151 TREE_PUBLIC (node->decl) = 0;
152 symtab->change_decl_assembler_name (node->decl, 164 symtab->change_decl_assembler_name (node->decl,
153 clone_function_name (node->decl, 165 clone_function_name (node->decl,
154 "default")); 166 "default"));
167
168 /* FIXME: copy of cgraph_node::make_local that should be cleaned up
169 in next stage1. */
170 node->make_decl_local ();
171 node->set_section (NULL);
172 node->set_comdat_group (NULL);
173 node->externally_visible = false;
174 node->forced_by_abi = false;
175 node->set_section (NULL);
176 node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY
177 || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
178 && !flag_incremental_link);
179 node->resolution = LDPR_PREVAILING_DEF_IRONLY;
180
181 DECL_ARTIFICIAL (node->decl) = 1;
182 node->force_output = true;
155 } 183 }
156 184
157 /* Return length of attribute names string, 185 /* Return length of attribute names string,
158 if arglist chain > 1, -1 otherwise. */ 186 if arglist chain > 1, -1 otherwise. */
159 187
201 } 229 }
202 return argnum; 230 return argnum;
203 } 231 }
204 232
205 /* Return number of attributes separated by comma and put them into ARGS. 233 /* Return number of attributes separated by comma and put them into ARGS.
206 If there is no DEFAULT attribute return -1. */ 234 If there is no DEFAULT attribute return -1. If there is an empty
235 string in attribute return -2. */
207 236
208 static int 237 static int
209 separate_attrs (char *attr_str, char **attrs) 238 separate_attrs (char *attr_str, char **attrs, int attrnum)
210 { 239 {
211 int i = 0; 240 int i = 0;
212 bool has_default = false; 241 int default_count = 0;
213 242
214 for (char *attr = strtok (attr_str, ","); 243 for (char *attr = strtok (attr_str, ",");
215 attr != NULL; attr = strtok (NULL, ",")) 244 attr != NULL; attr = strtok (NULL, ","))
216 { 245 {
217 if (strcmp (attr, "default") == 0) 246 if (strcmp (attr, "default") == 0)
218 { 247 {
219 has_default = true; 248 default_count++;
220 continue; 249 continue;
221 } 250 }
222 attrs[i++] = attr; 251 attrs[i++] = attr;
223 } 252 }
224 if (!has_default) 253 if (default_count == 0)
225 return -1; 254 return -1;
255 else if (i + default_count < attrnum)
256 return -2;
257
226 return i; 258 return i;
227 } 259 }
228 260
229 /* Return true if symbol is valid in assembler name. */ 261 /* Return true if symbol is valid in assembler name. */
230 262
306 /* No need to clone for 1 target attribute. */ 338 /* No need to clone for 1 target attribute. */
307 if (attr_len == -1) 339 if (attr_len == -1)
308 { 340 {
309 warning_at (DECL_SOURCE_LOCATION (node->decl), 341 warning_at (DECL_SOURCE_LOCATION (node->decl),
310 0, 342 0,
311 "single target_clones attribute is ignored"); 343 "single %<target_clones%> attribute is ignored");
344 return false;
345 }
346
347 if (node->definition
348 && !tree_versionable_function_p (node->decl))
349 {
350 auto_diagnostic_group d;
351 error_at (DECL_SOURCE_LOCATION (node->decl),
352 "clones for %<target_clones%> attribute cannot be created");
353 const char *reason = NULL;
354 if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
355 reason = G_("function %q+F can never be copied "
356 "because it has %<noclone%> attribute");
357 else
358 reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
359 if (reason)
360 inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
312 return false; 361 return false;
313 } 362 }
314 363
315 char *attr_str = XNEWVEC (char, attr_len); 364 char *attr_str = XNEWVEC (char, attr_len);
316 int attrnum = get_attr_str (arglist, attr_str); 365 int attrnum = get_attr_str (arglist, attr_str);
317 char **attrs = XNEWVEC (char *, attrnum); 366 char **attrs = XNEWVEC (char *, attrnum);
318 367
319 attrnum = separate_attrs (attr_str, attrs); 368 attrnum = separate_attrs (attr_str, attrs, attrnum);
320 if (attrnum == -1) 369 if (attrnum == -1)
321 { 370 {
322 error_at (DECL_SOURCE_LOCATION (node->decl), 371 error_at (DECL_SOURCE_LOCATION (node->decl),
323 "default target was not set"); 372 "default target was not set");
373 XDELETEVEC (attrs);
374 XDELETEVEC (attr_str);
375 return false;
376 }
377 else if (attrnum == -2)
378 {
379 error_at (DECL_SOURCE_LOCATION (node->decl),
380 "an empty string cannot be in %<target_clones%> attribute");
324 XDELETEVEC (attrs); 381 XDELETEVEC (attrs);
325 XDELETEVEC (attr_str); 382 XDELETEVEC (attr_str);
326 return false; 383 return false;
327 } 384 }
328 385
392 TREE_VALUE (attributes), 0); 449 TREE_VALUE (attributes), 0);
393 input_location = saved_loc; 450 input_location = saved_loc;
394 return ret; 451 return ret;
395 } 452 }
396 453
454 /* When NODE is a target clone, consider all callees and redirect
455 to a clone with equal target attributes. That prevents multiple
456 multi-versioning dispatches and a call-chain can be optimized. */
457
458 static void
459 redirect_to_specific_clone (cgraph_node *node)
460 {
461 cgraph_function_version_info *fv = node->function_version ();
462 if (fv == NULL)
463 return;
464
465 tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
466 if (attr_target == NULL_TREE)
467 return;
468
469 /* We need to remember NEXT_CALLER as it could be modified in the loop. */
470 for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
471 {
472 cgraph_function_version_info *fv2 = e->callee->function_version ();
473 if (!fv2)
474 continue;
475
476 tree attr_target2 = lookup_attribute ("target",
477 DECL_ATTRIBUTES (e->callee->decl));
478
479 /* Function is not calling proper target clone. */
480 if (!attribute_list_equal (attr_target, attr_target2))
481 {
482 while (fv2->prev != NULL)
483 fv2 = fv2->prev;
484
485 /* Try to find a clone with equal target attribute. */
486 for (; fv2 != NULL; fv2 = fv2->next)
487 {
488 cgraph_node *callee = fv2->this_node;
489 attr_target2 = lookup_attribute ("target",
490 DECL_ATTRIBUTES (callee->decl));
491 if (attribute_list_equal (attr_target, attr_target2))
492 {
493 e->redirect_callee (callee);
494 e->redirect_call_stmt_to_callee ();
495 break;
496 }
497 }
498 }
499 }
500 }
501
397 static unsigned int 502 static unsigned int
398 ipa_target_clone (void) 503 ipa_target_clone (void)
399 { 504 {
400 struct cgraph_node *node; 505 struct cgraph_node *node;
401 506 auto_vec<cgraph_node *> to_dispatch;
402 bool target_clone_pass = false; 507
403 FOR_EACH_FUNCTION (node) 508 FOR_EACH_FUNCTION (node)
404 target_clone_pass |= expand_target_clones (node, node->definition); 509 if (expand_target_clones (node, node->definition))
405 510 to_dispatch.safe_push (node);
406 if (target_clone_pass) 511
407 FOR_EACH_FUNCTION (node) 512 for (unsigned i = 0; i < to_dispatch.length (); i++)
408 create_dispatcher_calls (node); 513 create_dispatcher_calls (to_dispatch[i]);
514
515 FOR_EACH_FUNCTION (node)
516 redirect_to_specific_clone (node);
409 517
410 return 0; 518 return 0;
411 } 519 }
412 520
413 namespace { 521 namespace {