1*38fd1498Szrj /* Pass for parsing functions with multiple target attributes. 2*38fd1498Szrj 3*38fd1498Szrj Contributed by Evgeny Stupachenko <evstupac@gmail.com> 4*38fd1498Szrj 5*38fd1498Szrj Copyright (C) 2015-2018 Free Software Foundation, Inc. 6*38fd1498Szrj 7*38fd1498Szrj This file is part of GCC. 8*38fd1498Szrj 9*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under 10*38fd1498Szrj the terms of the GNU General Public License as published by the Free 11*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later 12*38fd1498Szrj version. 13*38fd1498Szrj 14*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY 15*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or 16*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 17*38fd1498Szrj for more details. 18*38fd1498Szrj 19*38fd1498Szrj You should have received a copy of the GNU General Public License 20*38fd1498Szrj along with GCC; see the file COPYING3. If not see 21*38fd1498Szrj <http://www.gnu.org/licenses/>. */ 22*38fd1498Szrj 23*38fd1498Szrj #include "config.h" 24*38fd1498Szrj #include "system.h" 25*38fd1498Szrj #include "coretypes.h" 26*38fd1498Szrj #include "backend.h" 27*38fd1498Szrj #include "tree.h" 28*38fd1498Szrj #include "stringpool.h" 29*38fd1498Szrj #include "gimple.h" 30*38fd1498Szrj #include "diagnostic-core.h" 31*38fd1498Szrj #include "gimple-ssa.h" 32*38fd1498Szrj #include "cgraph.h" 33*38fd1498Szrj #include "tree-pass.h" 34*38fd1498Szrj #include "target.h" 35*38fd1498Szrj #include "attribs.h" 36*38fd1498Szrj #include "pretty-print.h" 37*38fd1498Szrj #include "gimple-iterator.h" 38*38fd1498Szrj #include "gimple-walk.h" 39*38fd1498Szrj #include "tree-inline.h" 40*38fd1498Szrj #include "intl.h" 41*38fd1498Szrj 42*38fd1498Szrj /* Walker callback that replaces all FUNCTION_DECL of a function that's 43*38fd1498Szrj going to be versioned. */ 44*38fd1498Szrj 45*38fd1498Szrj static tree 46*38fd1498Szrj replace_function_decl (tree *op, int *walk_subtrees, void *data) 47*38fd1498Szrj { 48*38fd1498Szrj struct walk_stmt_info *wi = (struct walk_stmt_info *) data; 49*38fd1498Szrj cgraph_function_version_info *info = (cgraph_function_version_info *)wi->info; 50*38fd1498Szrj 51*38fd1498Szrj if (TREE_CODE (*op) == FUNCTION_DECL 52*38fd1498Szrj && info->this_node->decl == *op) 53*38fd1498Szrj { 54*38fd1498Szrj *op = info->dispatcher_resolver; 55*38fd1498Szrj *walk_subtrees = 0; 56*38fd1498Szrj } 57*38fd1498Szrj 58*38fd1498Szrj return NULL; 59*38fd1498Szrj } 60*38fd1498Szrj 61*38fd1498Szrj /* If the call in NODE has multiple target attribute with multiple fields, 62*38fd1498Szrj replace it with dispatcher call and create dispatcher (once). */ 63*38fd1498Szrj 64*38fd1498Szrj static void 65*38fd1498Szrj create_dispatcher_calls (struct cgraph_node *node) 66*38fd1498Szrj { 67*38fd1498Szrj ipa_ref *ref; 68*38fd1498Szrj 69*38fd1498Szrj if (!DECL_FUNCTION_VERSIONED (node->decl) 70*38fd1498Szrj || !is_function_default_version (node->decl)) 71*38fd1498Szrj return; 72*38fd1498Szrj 73*38fd1498Szrj if (!targetm.has_ifunc_p ()) 74*38fd1498Szrj { 75*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 76*38fd1498Szrj "the call requires ifunc, which is not" 77*38fd1498Szrj " supported by this target"); 78*38fd1498Szrj return; 79*38fd1498Szrj } 80*38fd1498Szrj else if (!targetm.get_function_versions_dispatcher) 81*38fd1498Szrj { 82*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 83*38fd1498Szrj "target does not support function version dispatcher"); 84*38fd1498Szrj return; 85*38fd1498Szrj } 86*38fd1498Szrj 87*38fd1498Szrj tree idecl = targetm.get_function_versions_dispatcher (node->decl); 88*38fd1498Szrj if (!idecl) 89*38fd1498Szrj { 90*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 91*38fd1498Szrj "default %<target_clones%> attribute was not set"); 92*38fd1498Szrj return; 93*38fd1498Szrj } 94*38fd1498Szrj 95*38fd1498Szrj cgraph_node *inode = cgraph_node::get (idecl); 96*38fd1498Szrj gcc_assert (inode); 97*38fd1498Szrj tree resolver_decl = targetm.generate_version_dispatcher_body (inode); 98*38fd1498Szrj 99*38fd1498Szrj /* Update aliases. */ 100*38fd1498Szrj inode->alias = true; 101*38fd1498Szrj inode->alias_target = resolver_decl; 102*38fd1498Szrj if (!inode->analyzed) 103*38fd1498Szrj inode->resolve_alias (cgraph_node::get (resolver_decl)); 104*38fd1498Szrj 105*38fd1498Szrj auto_vec<cgraph_edge *> edges_to_redirect; 106*38fd1498Szrj auto_vec<ipa_ref *> references_to_redirect; 107*38fd1498Szrj 108*38fd1498Szrj for (unsigned i = 0; node->iterate_referring (i, ref); i++) 109*38fd1498Szrj references_to_redirect.safe_push (ref); 110*38fd1498Szrj 111*38fd1498Szrj /* We need to remember NEXT_CALLER as it could be modified in the loop. */ 112*38fd1498Szrj for (cgraph_edge *e = node->callers; e ; e = e->next_caller) 113*38fd1498Szrj edges_to_redirect.safe_push (e); 114*38fd1498Szrj 115*38fd1498Szrj if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ()) 116*38fd1498Szrj { 117*38fd1498Szrj /* Redirect edges. */ 118*38fd1498Szrj unsigned i; 119*38fd1498Szrj cgraph_edge *e; 120*38fd1498Szrj FOR_EACH_VEC_ELT (edges_to_redirect, i, e) 121*38fd1498Szrj { 122*38fd1498Szrj e->redirect_callee (inode); 123*38fd1498Szrj e->redirect_call_stmt_to_callee (); 124*38fd1498Szrj } 125*38fd1498Szrj 126*38fd1498Szrj /* Redirect references. */ 127*38fd1498Szrj FOR_EACH_VEC_ELT (references_to_redirect, i, ref) 128*38fd1498Szrj { 129*38fd1498Szrj if (ref->use == IPA_REF_ADDR) 130*38fd1498Szrj { 131*38fd1498Szrj struct walk_stmt_info wi; 132*38fd1498Szrj memset (&wi, 0, sizeof (wi)); 133*38fd1498Szrj wi.info = (void *)node->function_version (); 134*38fd1498Szrj 135*38fd1498Szrj if (dyn_cast<varpool_node *> (ref->referring)) 136*38fd1498Szrj { 137*38fd1498Szrj hash_set<tree> visited_nodes; 138*38fd1498Szrj walk_tree (&DECL_INITIAL (ref->referring->decl), 139*38fd1498Szrj replace_function_decl, &wi, &visited_nodes); 140*38fd1498Szrj } 141*38fd1498Szrj else 142*38fd1498Szrj { 143*38fd1498Szrj gimple_stmt_iterator it = gsi_for_stmt (ref->stmt); 144*38fd1498Szrj if (ref->referring->decl != resolver_decl) 145*38fd1498Szrj walk_gimple_stmt (&it, NULL, replace_function_decl, &wi); 146*38fd1498Szrj } 147*38fd1498Szrj 148*38fd1498Szrj symtab_node *source = ref->referring; 149*38fd1498Szrj ref->remove_reference (); 150*38fd1498Szrj source->create_reference (inode, IPA_REF_ADDR); 151*38fd1498Szrj } 152*38fd1498Szrj else if (ref->use == IPA_REF_ALIAS) 153*38fd1498Szrj { 154*38fd1498Szrj symtab_node *source = ref->referring; 155*38fd1498Szrj ref->remove_reference (); 156*38fd1498Szrj source->create_reference (inode, IPA_REF_ALIAS); 157*38fd1498Szrj source->add_to_same_comdat_group (inode); 158*38fd1498Szrj } 159*38fd1498Szrj else 160*38fd1498Szrj gcc_unreachable (); 161*38fd1498Szrj } 162*38fd1498Szrj } 163*38fd1498Szrj 164*38fd1498Szrj symtab->change_decl_assembler_name (node->decl, 165*38fd1498Szrj clone_function_name (node->decl, 166*38fd1498Szrj "default")); 167*38fd1498Szrj 168*38fd1498Szrj /* FIXME: copy of cgraph_node::make_local that should be cleaned up 169*38fd1498Szrj in next stage1. */ 170*38fd1498Szrj node->make_decl_local (); 171*38fd1498Szrj node->set_section (NULL); 172*38fd1498Szrj node->set_comdat_group (NULL); 173*38fd1498Szrj node->externally_visible = false; 174*38fd1498Szrj node->forced_by_abi = false; 175*38fd1498Szrj node->set_section (NULL); 176*38fd1498Szrj node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY 177*38fd1498Szrj || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) 178*38fd1498Szrj && !flag_incremental_link); 179*38fd1498Szrj node->resolution = LDPR_PREVAILING_DEF_IRONLY; 180*38fd1498Szrj 181*38fd1498Szrj DECL_ARTIFICIAL (node->decl) = 1; 182*38fd1498Szrj node->force_output = true; 183*38fd1498Szrj } 184*38fd1498Szrj 185*38fd1498Szrj /* Return length of attribute names string, 186*38fd1498Szrj if arglist chain > 1, -1 otherwise. */ 187*38fd1498Szrj 188*38fd1498Szrj static int 189*38fd1498Szrj get_attr_len (tree arglist) 190*38fd1498Szrj { 191*38fd1498Szrj tree arg; 192*38fd1498Szrj int str_len_sum = 0; 193*38fd1498Szrj int argnum = 0; 194*38fd1498Szrj 195*38fd1498Szrj for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 196*38fd1498Szrj { 197*38fd1498Szrj const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 198*38fd1498Szrj size_t len = strlen (str); 199*38fd1498Szrj str_len_sum += len + 1; 200*38fd1498Szrj for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ',')) 201*38fd1498Szrj argnum++; 202*38fd1498Szrj argnum++; 203*38fd1498Szrj } 204*38fd1498Szrj if (argnum <= 1) 205*38fd1498Szrj return -1; 206*38fd1498Szrj return str_len_sum; 207*38fd1498Szrj } 208*38fd1498Szrj 209*38fd1498Szrj /* Create string with attributes separated by comma. 210*38fd1498Szrj Return number of attributes. */ 211*38fd1498Szrj 212*38fd1498Szrj static int 213*38fd1498Szrj get_attr_str (tree arglist, char *attr_str) 214*38fd1498Szrj { 215*38fd1498Szrj tree arg; 216*38fd1498Szrj size_t str_len_sum = 0; 217*38fd1498Szrj int argnum = 0; 218*38fd1498Szrj 219*38fd1498Szrj for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 220*38fd1498Szrj { 221*38fd1498Szrj const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 222*38fd1498Szrj size_t len = strlen (str); 223*38fd1498Szrj for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ',')) 224*38fd1498Szrj argnum++; 225*38fd1498Szrj memcpy (attr_str + str_len_sum, str, len); 226*38fd1498Szrj attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0'; 227*38fd1498Szrj str_len_sum += len + 1; 228*38fd1498Szrj argnum++; 229*38fd1498Szrj } 230*38fd1498Szrj return argnum; 231*38fd1498Szrj } 232*38fd1498Szrj 233*38fd1498Szrj /* Return number of attributes separated by comma and put them into ARGS. 234*38fd1498Szrj If there is no DEFAULT attribute return -1. If there is an empty 235*38fd1498Szrj string in attribute return -2. */ 236*38fd1498Szrj 237*38fd1498Szrj static int 238*38fd1498Szrj separate_attrs (char *attr_str, char **attrs, int attrnum) 239*38fd1498Szrj { 240*38fd1498Szrj int i = 0; 241*38fd1498Szrj int default_count = 0; 242*38fd1498Szrj 243*38fd1498Szrj for (char *attr = strtok (attr_str, ","); 244*38fd1498Szrj attr != NULL; attr = strtok (NULL, ",")) 245*38fd1498Szrj { 246*38fd1498Szrj if (strcmp (attr, "default") == 0) 247*38fd1498Szrj { 248*38fd1498Szrj default_count++; 249*38fd1498Szrj continue; 250*38fd1498Szrj } 251*38fd1498Szrj attrs[i++] = attr; 252*38fd1498Szrj } 253*38fd1498Szrj if (default_count == 0) 254*38fd1498Szrj return -1; 255*38fd1498Szrj else if (i + default_count < attrnum) 256*38fd1498Szrj return -2; 257*38fd1498Szrj 258*38fd1498Szrj return i; 259*38fd1498Szrj } 260*38fd1498Szrj 261*38fd1498Szrj /* Return true if symbol is valid in assembler name. */ 262*38fd1498Szrj 263*38fd1498Szrj static bool 264*38fd1498Szrj is_valid_asm_symbol (char c) 265*38fd1498Szrj { 266*38fd1498Szrj if ('a' <= c && c <= 'z') 267*38fd1498Szrj return true; 268*38fd1498Szrj if ('A' <= c && c <= 'Z') 269*38fd1498Szrj return true; 270*38fd1498Szrj if ('0' <= c && c <= '9') 271*38fd1498Szrj return true; 272*38fd1498Szrj if (c == '_') 273*38fd1498Szrj return true; 274*38fd1498Szrj return false; 275*38fd1498Szrj } 276*38fd1498Szrj 277*38fd1498Szrj /* Replace all not valid assembler symbols with '_'. */ 278*38fd1498Szrj 279*38fd1498Szrj static void 280*38fd1498Szrj create_new_asm_name (char *old_asm_name, char *new_asm_name) 281*38fd1498Szrj { 282*38fd1498Szrj int i; 283*38fd1498Szrj int old_name_len = strlen (old_asm_name); 284*38fd1498Szrj 285*38fd1498Szrj /* Replace all not valid assembler symbols with '_'. */ 286*38fd1498Szrj for (i = 0; i < old_name_len; i++) 287*38fd1498Szrj if (!is_valid_asm_symbol (old_asm_name[i])) 288*38fd1498Szrj new_asm_name[i] = '_'; 289*38fd1498Szrj else 290*38fd1498Szrj new_asm_name[i] = old_asm_name[i]; 291*38fd1498Szrj new_asm_name[old_name_len] = '\0'; 292*38fd1498Szrj } 293*38fd1498Szrj 294*38fd1498Szrj /* Creates target clone of NODE. */ 295*38fd1498Szrj 296*38fd1498Szrj static cgraph_node * 297*38fd1498Szrj create_target_clone (cgraph_node *node, bool definition, char *name) 298*38fd1498Szrj { 299*38fd1498Szrj cgraph_node *new_node; 300*38fd1498Szrj 301*38fd1498Szrj if (definition) 302*38fd1498Szrj { 303*38fd1498Szrj new_node = node->create_version_clone_with_body (vNULL, NULL, 304*38fd1498Szrj NULL, false, 305*38fd1498Szrj NULL, NULL, 306*38fd1498Szrj name); 307*38fd1498Szrj new_node->force_output = true; 308*38fd1498Szrj } 309*38fd1498Szrj else 310*38fd1498Szrj { 311*38fd1498Szrj tree new_decl = copy_node (node->decl); 312*38fd1498Szrj new_node = cgraph_node::get_create (new_decl); 313*38fd1498Szrj /* Generate a new name for the new version. */ 314*38fd1498Szrj symtab->change_decl_assembler_name (new_node->decl, 315*38fd1498Szrj clone_function_name (node->decl, 316*38fd1498Szrj name)); 317*38fd1498Szrj } 318*38fd1498Szrj return new_node; 319*38fd1498Szrj } 320*38fd1498Szrj 321*38fd1498Szrj /* If the function in NODE has multiple target attributes 322*38fd1498Szrj create the appropriate clone for each valid target attribute. */ 323*38fd1498Szrj 324*38fd1498Szrj static bool 325*38fd1498Szrj expand_target_clones (struct cgraph_node *node, bool definition) 326*38fd1498Szrj { 327*38fd1498Szrj int i; 328*38fd1498Szrj /* Parsing target attributes separated by comma. */ 329*38fd1498Szrj tree attr_target = lookup_attribute ("target_clones", 330*38fd1498Szrj DECL_ATTRIBUTES (node->decl)); 331*38fd1498Szrj /* No targets specified. */ 332*38fd1498Szrj if (!attr_target) 333*38fd1498Szrj return false; 334*38fd1498Szrj 335*38fd1498Szrj tree arglist = TREE_VALUE (attr_target); 336*38fd1498Szrj int attr_len = get_attr_len (arglist); 337*38fd1498Szrj 338*38fd1498Szrj /* No need to clone for 1 target attribute. */ 339*38fd1498Szrj if (attr_len == -1) 340*38fd1498Szrj { 341*38fd1498Szrj warning_at (DECL_SOURCE_LOCATION (node->decl), 342*38fd1498Szrj 0, 343*38fd1498Szrj "single %<target_clones%> attribute is ignored"); 344*38fd1498Szrj return false; 345*38fd1498Szrj } 346*38fd1498Szrj 347*38fd1498Szrj if (node->definition 348*38fd1498Szrj && !tree_versionable_function_p (node->decl)) 349*38fd1498Szrj { 350*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 351*38fd1498Szrj "clones for %<target_clones%> attribute cannot be created"); 352*38fd1498Szrj const char *reason = NULL; 353*38fd1498Szrj if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl))) 354*38fd1498Szrj reason = G_("function %q+F can never be copied " 355*38fd1498Szrj "because it has %<noclone%> attribute"); 356*38fd1498Szrj else 357*38fd1498Szrj reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl)); 358*38fd1498Szrj if (reason) 359*38fd1498Szrj inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl); 360*38fd1498Szrj return false; 361*38fd1498Szrj } 362*38fd1498Szrj 363*38fd1498Szrj char *attr_str = XNEWVEC (char, attr_len); 364*38fd1498Szrj int attrnum = get_attr_str (arglist, attr_str); 365*38fd1498Szrj char **attrs = XNEWVEC (char *, attrnum); 366*38fd1498Szrj 367*38fd1498Szrj attrnum = separate_attrs (attr_str, attrs, attrnum); 368*38fd1498Szrj if (attrnum == -1) 369*38fd1498Szrj { 370*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 371*38fd1498Szrj "default target was not set"); 372*38fd1498Szrj XDELETEVEC (attrs); 373*38fd1498Szrj XDELETEVEC (attr_str); 374*38fd1498Szrj return false; 375*38fd1498Szrj } 376*38fd1498Szrj else if (attrnum == -2) 377*38fd1498Szrj { 378*38fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 379*38fd1498Szrj "an empty string cannot be in %<target_clones%> attribute"); 380*38fd1498Szrj XDELETEVEC (attrs); 381*38fd1498Szrj XDELETEVEC (attr_str); 382*38fd1498Szrj return false; 383*38fd1498Szrj } 384*38fd1498Szrj 385*38fd1498Szrj cgraph_function_version_info *decl1_v = NULL; 386*38fd1498Szrj cgraph_function_version_info *decl2_v = NULL; 387*38fd1498Szrj cgraph_function_version_info *before = NULL; 388*38fd1498Szrj cgraph_function_version_info *after = NULL; 389*38fd1498Szrj decl1_v = node->function_version (); 390*38fd1498Szrj if (decl1_v == NULL) 391*38fd1498Szrj decl1_v = node->insert_new_function_version (); 392*38fd1498Szrj before = decl1_v; 393*38fd1498Szrj DECL_FUNCTION_VERSIONED (node->decl) = 1; 394*38fd1498Szrj 395*38fd1498Szrj for (i = 0; i < attrnum; i++) 396*38fd1498Szrj { 397*38fd1498Szrj char *attr = attrs[i]; 398*38fd1498Szrj char *suffix = XNEWVEC (char, strlen (attr) + 1); 399*38fd1498Szrj 400*38fd1498Szrj create_new_asm_name (attr, suffix); 401*38fd1498Szrj /* Create new target clone. */ 402*38fd1498Szrj cgraph_node *new_node = create_target_clone (node, definition, suffix); 403*38fd1498Szrj new_node->local.local = false; 404*38fd1498Szrj XDELETEVEC (suffix); 405*38fd1498Szrj 406*38fd1498Szrj /* Set new attribute for the clone. */ 407*38fd1498Szrj tree attributes = make_attribute ("target", attr, 408*38fd1498Szrj DECL_ATTRIBUTES (new_node->decl)); 409*38fd1498Szrj DECL_ATTRIBUTES (new_node->decl) = attributes; 410*38fd1498Szrj location_t saved_loc = input_location; 411*38fd1498Szrj input_location = DECL_SOURCE_LOCATION (node->decl); 412*38fd1498Szrj if (!targetm.target_option.valid_attribute_p (new_node->decl, NULL, 413*38fd1498Szrj TREE_VALUE (attributes), 414*38fd1498Szrj 0)) 415*38fd1498Szrj return false; 416*38fd1498Szrj 417*38fd1498Szrj input_location = saved_loc; 418*38fd1498Szrj decl2_v = new_node->function_version (); 419*38fd1498Szrj if (decl2_v != NULL) 420*38fd1498Szrj continue; 421*38fd1498Szrj decl2_v = new_node->insert_new_function_version (); 422*38fd1498Szrj 423*38fd1498Szrj /* Chain decl2_v and decl1_v. All semantically identical versions 424*38fd1498Szrj will be chained together. */ 425*38fd1498Szrj after = decl2_v; 426*38fd1498Szrj while (before->next != NULL) 427*38fd1498Szrj before = before->next; 428*38fd1498Szrj while (after->prev != NULL) 429*38fd1498Szrj after = after->prev; 430*38fd1498Szrj 431*38fd1498Szrj before->next = after; 432*38fd1498Szrj after->prev = before; 433*38fd1498Szrj DECL_FUNCTION_VERSIONED (new_node->decl) = 1; 434*38fd1498Szrj } 435*38fd1498Szrj 436*38fd1498Szrj XDELETEVEC (attrs); 437*38fd1498Szrj XDELETEVEC (attr_str); 438*38fd1498Szrj 439*38fd1498Szrj /* Setting new attribute to initial function. */ 440*38fd1498Szrj tree attributes = make_attribute ("target", "default", 441*38fd1498Szrj DECL_ATTRIBUTES (node->decl)); 442*38fd1498Szrj DECL_ATTRIBUTES (node->decl) = attributes; 443*38fd1498Szrj node->local.local = false; 444*38fd1498Szrj location_t saved_loc = input_location; 445*38fd1498Szrj input_location = DECL_SOURCE_LOCATION (node->decl); 446*38fd1498Szrj bool ret 447*38fd1498Szrj = targetm.target_option.valid_attribute_p (node->decl, NULL, 448*38fd1498Szrj TREE_VALUE (attributes), 0); 449*38fd1498Szrj input_location = saved_loc; 450*38fd1498Szrj return ret; 451*38fd1498Szrj } 452*38fd1498Szrj 453*38fd1498Szrj static unsigned int 454*38fd1498Szrj ipa_target_clone (void) 455*38fd1498Szrj { 456*38fd1498Szrj struct cgraph_node *node; 457*38fd1498Szrj auto_vec<cgraph_node *> to_dispatch; 458*38fd1498Szrj 459*38fd1498Szrj FOR_EACH_FUNCTION (node) 460*38fd1498Szrj if (expand_target_clones (node, node->definition)) 461*38fd1498Szrj to_dispatch.safe_push (node); 462*38fd1498Szrj 463*38fd1498Szrj for (unsigned i = 0; i < to_dispatch.length (); i++) 464*38fd1498Szrj create_dispatcher_calls (to_dispatch[i]); 465*38fd1498Szrj 466*38fd1498Szrj return 0; 467*38fd1498Szrj } 468*38fd1498Szrj 469*38fd1498Szrj namespace { 470*38fd1498Szrj 471*38fd1498Szrj const pass_data pass_data_target_clone = 472*38fd1498Szrj { 473*38fd1498Szrj SIMPLE_IPA_PASS, /* type */ 474*38fd1498Szrj "targetclone", /* name */ 475*38fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 476*38fd1498Szrj TV_NONE, /* tv_id */ 477*38fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */ 478*38fd1498Szrj 0, /* properties_provided */ 479*38fd1498Szrj 0, /* properties_destroyed */ 480*38fd1498Szrj 0, /* todo_flags_start */ 481*38fd1498Szrj TODO_update_ssa /* todo_flags_finish */ 482*38fd1498Szrj }; 483*38fd1498Szrj 484*38fd1498Szrj class pass_target_clone : public simple_ipa_opt_pass 485*38fd1498Szrj { 486*38fd1498Szrj public: 487*38fd1498Szrj pass_target_clone (gcc::context *ctxt) 488*38fd1498Szrj : simple_ipa_opt_pass (pass_data_target_clone, ctxt) 489*38fd1498Szrj {} 490*38fd1498Szrj 491*38fd1498Szrj /* opt_pass methods: */ 492*38fd1498Szrj virtual bool gate (function *); 493*38fd1498Szrj virtual unsigned int execute (function *) { return ipa_target_clone (); } 494*38fd1498Szrj }; 495*38fd1498Szrj 496*38fd1498Szrj bool 497*38fd1498Szrj pass_target_clone::gate (function *) 498*38fd1498Szrj { 499*38fd1498Szrj return true; 500*38fd1498Szrj } 501*38fd1498Szrj 502*38fd1498Szrj } // anon namespace 503*38fd1498Szrj 504*38fd1498Szrj simple_ipa_opt_pass * 505*38fd1498Szrj make_pass_target_clone (gcc::context *ctxt) 506*38fd1498Szrj { 507*38fd1498Szrj return new pass_target_clone (ctxt); 508*38fd1498Szrj } 509