Mercurial > hg > CbC > CbC_gcc
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 { |