138fd1498Szrj /* Pass for parsing functions with multiple target attributes. 238fd1498Szrj 338fd1498Szrj Contributed by Evgeny Stupachenko <evstupac@gmail.com> 438fd1498Szrj 538fd1498Szrj Copyright (C) 2015-2018 Free Software Foundation, Inc. 638fd1498Szrj 738fd1498Szrj This file is part of GCC. 838fd1498Szrj 938fd1498Szrj GCC is free software; you can redistribute it and/or modify it under 1038fd1498Szrj the terms of the GNU General Public License as published by the Free 1138fd1498Szrj Software Foundation; either version 3, or (at your option) any later 1238fd1498Szrj version. 1338fd1498Szrj 1438fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY 1538fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or 1638fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1738fd1498Szrj for more details. 1838fd1498Szrj 1938fd1498Szrj You should have received a copy of the GNU General Public License 2038fd1498Szrj along with GCC; see the file COPYING3. If not see 2138fd1498Szrj <http://www.gnu.org/licenses/>. */ 2238fd1498Szrj 2338fd1498Szrj #include "config.h" 2438fd1498Szrj #include "system.h" 2538fd1498Szrj #include "coretypes.h" 2638fd1498Szrj #include "backend.h" 2738fd1498Szrj #include "tree.h" 2838fd1498Szrj #include "stringpool.h" 2938fd1498Szrj #include "gimple.h" 3038fd1498Szrj #include "diagnostic-core.h" 3138fd1498Szrj #include "gimple-ssa.h" 3238fd1498Szrj #include "cgraph.h" 3338fd1498Szrj #include "tree-pass.h" 3438fd1498Szrj #include "target.h" 3538fd1498Szrj #include "attribs.h" 3638fd1498Szrj #include "pretty-print.h" 3738fd1498Szrj #include "gimple-iterator.h" 3838fd1498Szrj #include "gimple-walk.h" 3938fd1498Szrj #include "tree-inline.h" 4038fd1498Szrj #include "intl.h" 4138fd1498Szrj 4238fd1498Szrj /* Walker callback that replaces all FUNCTION_DECL of a function that's 4338fd1498Szrj going to be versioned. */ 4438fd1498Szrj 4538fd1498Szrj static tree 4638fd1498Szrj replace_function_decl (tree *op, int *walk_subtrees, void *data) 4738fd1498Szrj { 4838fd1498Szrj struct walk_stmt_info *wi = (struct walk_stmt_info *) data; 4938fd1498Szrj cgraph_function_version_info *info = (cgraph_function_version_info *)wi->info; 5038fd1498Szrj 5138fd1498Szrj if (TREE_CODE (*op) == FUNCTION_DECL 5238fd1498Szrj && info->this_node->decl == *op) 5338fd1498Szrj { 5438fd1498Szrj *op = info->dispatcher_resolver; 5538fd1498Szrj *walk_subtrees = 0; 5638fd1498Szrj } 5738fd1498Szrj 5838fd1498Szrj return NULL; 5938fd1498Szrj } 6038fd1498Szrj 6138fd1498Szrj /* If the call in NODE has multiple target attribute with multiple fields, 6238fd1498Szrj replace it with dispatcher call and create dispatcher (once). */ 6338fd1498Szrj 6438fd1498Szrj static void 6538fd1498Szrj create_dispatcher_calls (struct cgraph_node *node) 6638fd1498Szrj { 6738fd1498Szrj ipa_ref *ref; 6838fd1498Szrj 6938fd1498Szrj if (!DECL_FUNCTION_VERSIONED (node->decl) 7038fd1498Szrj || !is_function_default_version (node->decl)) 7138fd1498Szrj return; 7238fd1498Szrj 7338fd1498Szrj if (!targetm.has_ifunc_p ()) 7438fd1498Szrj { 7538fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 7638fd1498Szrj "the call requires ifunc, which is not" 7738fd1498Szrj " supported by this target"); 7838fd1498Szrj return; 7938fd1498Szrj } 8038fd1498Szrj else if (!targetm.get_function_versions_dispatcher) 8138fd1498Szrj { 8238fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 8338fd1498Szrj "target does not support function version dispatcher"); 8438fd1498Szrj return; 8538fd1498Szrj } 8638fd1498Szrj 8738fd1498Szrj tree idecl = targetm.get_function_versions_dispatcher (node->decl); 8838fd1498Szrj if (!idecl) 8938fd1498Szrj { 9038fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 9138fd1498Szrj "default %<target_clones%> attribute was not set"); 9238fd1498Szrj return; 9338fd1498Szrj } 9438fd1498Szrj 9538fd1498Szrj cgraph_node *inode = cgraph_node::get (idecl); 9638fd1498Szrj gcc_assert (inode); 9738fd1498Szrj tree resolver_decl = targetm.generate_version_dispatcher_body (inode); 9838fd1498Szrj 9938fd1498Szrj /* Update aliases. */ 10038fd1498Szrj inode->alias = true; 10138fd1498Szrj inode->alias_target = resolver_decl; 10238fd1498Szrj if (!inode->analyzed) 10338fd1498Szrj inode->resolve_alias (cgraph_node::get (resolver_decl)); 10438fd1498Szrj 10538fd1498Szrj auto_vec<cgraph_edge *> edges_to_redirect; 10638fd1498Szrj auto_vec<ipa_ref *> references_to_redirect; 10738fd1498Szrj 10838fd1498Szrj for (unsigned i = 0; node->iterate_referring (i, ref); i++) 10938fd1498Szrj references_to_redirect.safe_push (ref); 11038fd1498Szrj 11138fd1498Szrj /* We need to remember NEXT_CALLER as it could be modified in the loop. */ 11238fd1498Szrj for (cgraph_edge *e = node->callers; e ; e = e->next_caller) 11338fd1498Szrj edges_to_redirect.safe_push (e); 11438fd1498Szrj 11538fd1498Szrj if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ()) 11638fd1498Szrj { 11738fd1498Szrj /* Redirect edges. */ 11838fd1498Szrj unsigned i; 11938fd1498Szrj cgraph_edge *e; 12038fd1498Szrj FOR_EACH_VEC_ELT (edges_to_redirect, i, e) 12138fd1498Szrj { 12238fd1498Szrj e->redirect_callee (inode); 12338fd1498Szrj e->redirect_call_stmt_to_callee (); 12438fd1498Szrj } 12538fd1498Szrj 12638fd1498Szrj /* Redirect references. */ 12738fd1498Szrj FOR_EACH_VEC_ELT (references_to_redirect, i, ref) 12838fd1498Szrj { 12938fd1498Szrj if (ref->use == IPA_REF_ADDR) 13038fd1498Szrj { 13138fd1498Szrj struct walk_stmt_info wi; 13238fd1498Szrj memset (&wi, 0, sizeof (wi)); 13338fd1498Szrj wi.info = (void *)node->function_version (); 13438fd1498Szrj 13538fd1498Szrj if (dyn_cast<varpool_node *> (ref->referring)) 13638fd1498Szrj { 13738fd1498Szrj hash_set<tree> visited_nodes; 13838fd1498Szrj walk_tree (&DECL_INITIAL (ref->referring->decl), 13938fd1498Szrj replace_function_decl, &wi, &visited_nodes); 14038fd1498Szrj } 14138fd1498Szrj else 14238fd1498Szrj { 14338fd1498Szrj gimple_stmt_iterator it = gsi_for_stmt (ref->stmt); 14438fd1498Szrj if (ref->referring->decl != resolver_decl) 14538fd1498Szrj walk_gimple_stmt (&it, NULL, replace_function_decl, &wi); 14638fd1498Szrj } 14738fd1498Szrj 14838fd1498Szrj symtab_node *source = ref->referring; 14938fd1498Szrj ref->remove_reference (); 15038fd1498Szrj source->create_reference (inode, IPA_REF_ADDR); 15138fd1498Szrj } 15238fd1498Szrj else if (ref->use == IPA_REF_ALIAS) 15338fd1498Szrj { 15438fd1498Szrj symtab_node *source = ref->referring; 15538fd1498Szrj ref->remove_reference (); 15638fd1498Szrj source->create_reference (inode, IPA_REF_ALIAS); 15738fd1498Szrj source->add_to_same_comdat_group (inode); 15838fd1498Szrj } 15938fd1498Szrj else 16038fd1498Szrj gcc_unreachable (); 16138fd1498Szrj } 16238fd1498Szrj } 16338fd1498Szrj 16438fd1498Szrj symtab->change_decl_assembler_name (node->decl, 16538fd1498Szrj clone_function_name (node->decl, 16638fd1498Szrj "default")); 16738fd1498Szrj 16838fd1498Szrj /* FIXME: copy of cgraph_node::make_local that should be cleaned up 16938fd1498Szrj in next stage1. */ 17038fd1498Szrj node->make_decl_local (); 17138fd1498Szrj node->set_section (NULL); 17238fd1498Szrj node->set_comdat_group (NULL); 17338fd1498Szrj node->externally_visible = false; 17438fd1498Szrj node->forced_by_abi = false; 17538fd1498Szrj node->set_section (NULL); 17638fd1498Szrj node->unique_name = ((node->resolution == LDPR_PREVAILING_DEF_IRONLY 17738fd1498Szrj || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP) 17838fd1498Szrj && !flag_incremental_link); 17938fd1498Szrj node->resolution = LDPR_PREVAILING_DEF_IRONLY; 18038fd1498Szrj 18138fd1498Szrj DECL_ARTIFICIAL (node->decl) = 1; 18238fd1498Szrj node->force_output = true; 18338fd1498Szrj } 18438fd1498Szrj 18538fd1498Szrj /* Return length of attribute names string, 18638fd1498Szrj if arglist chain > 1, -1 otherwise. */ 18738fd1498Szrj 18838fd1498Szrj static int 18938fd1498Szrj get_attr_len (tree arglist) 19038fd1498Szrj { 19138fd1498Szrj tree arg; 19238fd1498Szrj int str_len_sum = 0; 19338fd1498Szrj int argnum = 0; 19438fd1498Szrj 19538fd1498Szrj for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 19638fd1498Szrj { 19738fd1498Szrj const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 19838fd1498Szrj size_t len = strlen (str); 19938fd1498Szrj str_len_sum += len + 1; 20038fd1498Szrj for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ',')) 20138fd1498Szrj argnum++; 20238fd1498Szrj argnum++; 20338fd1498Szrj } 20438fd1498Szrj if (argnum <= 1) 20538fd1498Szrj return -1; 20638fd1498Szrj return str_len_sum; 20738fd1498Szrj } 20838fd1498Szrj 20938fd1498Szrj /* Create string with attributes separated by comma. 21038fd1498Szrj Return number of attributes. */ 21138fd1498Szrj 21238fd1498Szrj static int 21338fd1498Szrj get_attr_str (tree arglist, char *attr_str) 21438fd1498Szrj { 21538fd1498Szrj tree arg; 21638fd1498Szrj size_t str_len_sum = 0; 21738fd1498Szrj int argnum = 0; 21838fd1498Szrj 21938fd1498Szrj for (arg = arglist; arg; arg = TREE_CHAIN (arg)) 22038fd1498Szrj { 22138fd1498Szrj const char *str = TREE_STRING_POINTER (TREE_VALUE (arg)); 22238fd1498Szrj size_t len = strlen (str); 22338fd1498Szrj for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ',')) 22438fd1498Szrj argnum++; 22538fd1498Szrj memcpy (attr_str + str_len_sum, str, len); 22638fd1498Szrj attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0'; 22738fd1498Szrj str_len_sum += len + 1; 22838fd1498Szrj argnum++; 22938fd1498Szrj } 23038fd1498Szrj return argnum; 23138fd1498Szrj } 23238fd1498Szrj 23338fd1498Szrj /* Return number of attributes separated by comma and put them into ARGS. 23438fd1498Szrj If there is no DEFAULT attribute return -1. If there is an empty 23538fd1498Szrj string in attribute return -2. */ 23638fd1498Szrj 23738fd1498Szrj static int 23838fd1498Szrj separate_attrs (char *attr_str, char **attrs, int attrnum) 23938fd1498Szrj { 24038fd1498Szrj int i = 0; 24138fd1498Szrj int default_count = 0; 24238fd1498Szrj 24338fd1498Szrj for (char *attr = strtok (attr_str, ","); 24438fd1498Szrj attr != NULL; attr = strtok (NULL, ",")) 24538fd1498Szrj { 24638fd1498Szrj if (strcmp (attr, "default") == 0) 24738fd1498Szrj { 24838fd1498Szrj default_count++; 24938fd1498Szrj continue; 25038fd1498Szrj } 25138fd1498Szrj attrs[i++] = attr; 25238fd1498Szrj } 25338fd1498Szrj if (default_count == 0) 25438fd1498Szrj return -1; 25538fd1498Szrj else if (i + default_count < attrnum) 25638fd1498Szrj return -2; 25738fd1498Szrj 25838fd1498Szrj return i; 25938fd1498Szrj } 26038fd1498Szrj 26138fd1498Szrj /* Return true if symbol is valid in assembler name. */ 26238fd1498Szrj 26338fd1498Szrj static bool 26438fd1498Szrj is_valid_asm_symbol (char c) 26538fd1498Szrj { 26638fd1498Szrj if ('a' <= c && c <= 'z') 26738fd1498Szrj return true; 26838fd1498Szrj if ('A' <= c && c <= 'Z') 26938fd1498Szrj return true; 27038fd1498Szrj if ('0' <= c && c <= '9') 27138fd1498Szrj return true; 27238fd1498Szrj if (c == '_') 27338fd1498Szrj return true; 27438fd1498Szrj return false; 27538fd1498Szrj } 27638fd1498Szrj 27738fd1498Szrj /* Replace all not valid assembler symbols with '_'. */ 27838fd1498Szrj 27938fd1498Szrj static void 28038fd1498Szrj create_new_asm_name (char *old_asm_name, char *new_asm_name) 28138fd1498Szrj { 28238fd1498Szrj int i; 28338fd1498Szrj int old_name_len = strlen (old_asm_name); 28438fd1498Szrj 28538fd1498Szrj /* Replace all not valid assembler symbols with '_'. */ 28638fd1498Szrj for (i = 0; i < old_name_len; i++) 28738fd1498Szrj if (!is_valid_asm_symbol (old_asm_name[i])) 28838fd1498Szrj new_asm_name[i] = '_'; 28938fd1498Szrj else 29038fd1498Szrj new_asm_name[i] = old_asm_name[i]; 29138fd1498Szrj new_asm_name[old_name_len] = '\0'; 29238fd1498Szrj } 29338fd1498Szrj 29438fd1498Szrj /* Creates target clone of NODE. */ 29538fd1498Szrj 29638fd1498Szrj static cgraph_node * 297*e215fc28Szrj create_target_clone (cgraph_node *node, bool definition, char *name, 298*e215fc28Szrj tree attributes) 29938fd1498Szrj { 30038fd1498Szrj cgraph_node *new_node; 30138fd1498Szrj 30238fd1498Szrj if (definition) 30338fd1498Szrj { 30438fd1498Szrj new_node = node->create_version_clone_with_body (vNULL, NULL, 30538fd1498Szrj NULL, false, 30638fd1498Szrj NULL, NULL, 307*e215fc28Szrj name, attributes); 308*e215fc28Szrj if (new_node == NULL) 309*e215fc28Szrj return NULL; 31038fd1498Szrj new_node->force_output = true; 31138fd1498Szrj } 31238fd1498Szrj else 31338fd1498Szrj { 31438fd1498Szrj tree new_decl = copy_node (node->decl); 31538fd1498Szrj new_node = cgraph_node::get_create (new_decl); 316*e215fc28Szrj DECL_ATTRIBUTES (new_decl) = attributes; 31738fd1498Szrj /* Generate a new name for the new version. */ 31838fd1498Szrj symtab->change_decl_assembler_name (new_node->decl, 31938fd1498Szrj clone_function_name (node->decl, 32038fd1498Szrj name)); 32138fd1498Szrj } 32238fd1498Szrj return new_node; 32338fd1498Szrj } 32438fd1498Szrj 32538fd1498Szrj /* If the function in NODE has multiple target attributes 32638fd1498Szrj create the appropriate clone for each valid target attribute. */ 32738fd1498Szrj 32838fd1498Szrj static bool 32938fd1498Szrj expand_target_clones (struct cgraph_node *node, bool definition) 33038fd1498Szrj { 33138fd1498Szrj int i; 33238fd1498Szrj /* Parsing target attributes separated by comma. */ 33338fd1498Szrj tree attr_target = lookup_attribute ("target_clones", 33438fd1498Szrj DECL_ATTRIBUTES (node->decl)); 33538fd1498Szrj /* No targets specified. */ 33638fd1498Szrj if (!attr_target) 33738fd1498Szrj return false; 33838fd1498Szrj 33938fd1498Szrj tree arglist = TREE_VALUE (attr_target); 34038fd1498Szrj int attr_len = get_attr_len (arglist); 34138fd1498Szrj 34238fd1498Szrj /* No need to clone for 1 target attribute. */ 34338fd1498Szrj if (attr_len == -1) 34438fd1498Szrj { 34538fd1498Szrj warning_at (DECL_SOURCE_LOCATION (node->decl), 34638fd1498Szrj 0, 34738fd1498Szrj "single %<target_clones%> attribute is ignored"); 34838fd1498Szrj return false; 34938fd1498Szrj } 35038fd1498Szrj 35138fd1498Szrj if (node->definition 35238fd1498Szrj && !tree_versionable_function_p (node->decl)) 35338fd1498Szrj { 35438fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 35538fd1498Szrj "clones for %<target_clones%> attribute cannot be created"); 35638fd1498Szrj const char *reason = NULL; 35738fd1498Szrj if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl))) 35838fd1498Szrj reason = G_("function %q+F can never be copied " 35938fd1498Szrj "because it has %<noclone%> attribute"); 36038fd1498Szrj else 36138fd1498Szrj reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl)); 36238fd1498Szrj if (reason) 36338fd1498Szrj inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl); 36438fd1498Szrj return false; 36538fd1498Szrj } 36638fd1498Szrj 36738fd1498Szrj char *attr_str = XNEWVEC (char, attr_len); 36838fd1498Szrj int attrnum = get_attr_str (arglist, attr_str); 36938fd1498Szrj char **attrs = XNEWVEC (char *, attrnum); 37038fd1498Szrj 37138fd1498Szrj attrnum = separate_attrs (attr_str, attrs, attrnum); 37238fd1498Szrj if (attrnum == -1) 37338fd1498Szrj { 37438fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 37538fd1498Szrj "default target was not set"); 37638fd1498Szrj XDELETEVEC (attrs); 37738fd1498Szrj XDELETEVEC (attr_str); 37838fd1498Szrj return false; 37938fd1498Szrj } 38038fd1498Szrj else if (attrnum == -2) 38138fd1498Szrj { 38238fd1498Szrj error_at (DECL_SOURCE_LOCATION (node->decl), 38338fd1498Szrj "an empty string cannot be in %<target_clones%> attribute"); 38438fd1498Szrj XDELETEVEC (attrs); 38538fd1498Szrj XDELETEVEC (attr_str); 38638fd1498Szrj return false; 38738fd1498Szrj } 38838fd1498Szrj 38938fd1498Szrj cgraph_function_version_info *decl1_v = NULL; 39038fd1498Szrj cgraph_function_version_info *decl2_v = NULL; 39138fd1498Szrj cgraph_function_version_info *before = NULL; 39238fd1498Szrj cgraph_function_version_info *after = NULL; 39338fd1498Szrj decl1_v = node->function_version (); 39438fd1498Szrj if (decl1_v == NULL) 39538fd1498Szrj decl1_v = node->insert_new_function_version (); 39638fd1498Szrj before = decl1_v; 39738fd1498Szrj DECL_FUNCTION_VERSIONED (node->decl) = 1; 39838fd1498Szrj 39938fd1498Szrj for (i = 0; i < attrnum; i++) 40038fd1498Szrj { 40138fd1498Szrj char *attr = attrs[i]; 40238fd1498Szrj char *suffix = XNEWVEC (char, strlen (attr) + 1); 40338fd1498Szrj 40438fd1498Szrj create_new_asm_name (attr, suffix); 40538fd1498Szrj /* Create new target clone. */ 406*e215fc28Szrj tree attributes = make_attribute ("target", attr, 407*e215fc28Szrj DECL_ATTRIBUTES (node->decl)); 408*e215fc28Szrj 409*e215fc28Szrj cgraph_node *new_node = create_target_clone (node, definition, suffix, 410*e215fc28Szrj attributes); 411*e215fc28Szrj if (new_node == NULL) 412*e215fc28Szrj return false; 41338fd1498Szrj new_node->local.local = false; 41438fd1498Szrj XDELETEVEC (suffix); 41538fd1498Szrj 41638fd1498Szrj decl2_v = new_node->function_version (); 41738fd1498Szrj if (decl2_v != NULL) 41838fd1498Szrj continue; 41938fd1498Szrj decl2_v = new_node->insert_new_function_version (); 42038fd1498Szrj 42138fd1498Szrj /* Chain decl2_v and decl1_v. All semantically identical versions 42238fd1498Szrj will be chained together. */ 42338fd1498Szrj after = decl2_v; 42438fd1498Szrj while (before->next != NULL) 42538fd1498Szrj before = before->next; 42638fd1498Szrj while (after->prev != NULL) 42738fd1498Szrj after = after->prev; 42838fd1498Szrj 42938fd1498Szrj before->next = after; 43038fd1498Szrj after->prev = before; 43138fd1498Szrj DECL_FUNCTION_VERSIONED (new_node->decl) = 1; 43238fd1498Szrj } 43338fd1498Szrj 43438fd1498Szrj XDELETEVEC (attrs); 43538fd1498Szrj XDELETEVEC (attr_str); 43638fd1498Szrj 43738fd1498Szrj /* Setting new attribute to initial function. */ 43838fd1498Szrj tree attributes = make_attribute ("target", "default", 43938fd1498Szrj DECL_ATTRIBUTES (node->decl)); 44038fd1498Szrj DECL_ATTRIBUTES (node->decl) = attributes; 44138fd1498Szrj node->local.local = false; 442*e215fc28Szrj return true; 44338fd1498Szrj } 44438fd1498Szrj 44538fd1498Szrj static unsigned int 44638fd1498Szrj ipa_target_clone (void) 44738fd1498Szrj { 44838fd1498Szrj struct cgraph_node *node; 44938fd1498Szrj auto_vec<cgraph_node *> to_dispatch; 45038fd1498Szrj 45138fd1498Szrj FOR_EACH_FUNCTION (node) 45238fd1498Szrj if (expand_target_clones (node, node->definition)) 45338fd1498Szrj to_dispatch.safe_push (node); 45438fd1498Szrj 45538fd1498Szrj for (unsigned i = 0; i < to_dispatch.length (); i++) 45638fd1498Szrj create_dispatcher_calls (to_dispatch[i]); 45738fd1498Szrj 45838fd1498Szrj return 0; 45938fd1498Szrj } 46038fd1498Szrj 46138fd1498Szrj namespace { 46238fd1498Szrj 46338fd1498Szrj const pass_data pass_data_target_clone = 46438fd1498Szrj { 46538fd1498Szrj SIMPLE_IPA_PASS, /* type */ 46638fd1498Szrj "targetclone", /* name */ 46738fd1498Szrj OPTGROUP_NONE, /* optinfo_flags */ 46838fd1498Szrj TV_NONE, /* tv_id */ 46938fd1498Szrj ( PROP_ssa | PROP_cfg ), /* properties_required */ 47038fd1498Szrj 0, /* properties_provided */ 47138fd1498Szrj 0, /* properties_destroyed */ 47238fd1498Szrj 0, /* todo_flags_start */ 47338fd1498Szrj TODO_update_ssa /* todo_flags_finish */ 47438fd1498Szrj }; 47538fd1498Szrj 47638fd1498Szrj class pass_target_clone : public simple_ipa_opt_pass 47738fd1498Szrj { 47838fd1498Szrj public: 47938fd1498Szrj pass_target_clone (gcc::context *ctxt) 48038fd1498Szrj : simple_ipa_opt_pass (pass_data_target_clone, ctxt) 48138fd1498Szrj {} 48238fd1498Szrj 48338fd1498Szrj /* opt_pass methods: */ 48438fd1498Szrj virtual bool gate (function *); 48538fd1498Szrj virtual unsigned int execute (function *) { return ipa_target_clone (); } 48638fd1498Szrj }; 48738fd1498Szrj 48838fd1498Szrj bool 48938fd1498Szrj pass_target_clone::gate (function *) 49038fd1498Szrj { 49138fd1498Szrj return true; 49238fd1498Szrj } 49338fd1498Szrj 49438fd1498Szrj } // anon namespace 49538fd1498Szrj 49638fd1498Szrj simple_ipa_opt_pass * 49738fd1498Szrj make_pass_target_clone (gcc::context *ctxt) 49838fd1498Szrj { 49938fd1498Szrj return new pass_target_clone (ctxt); 50038fd1498Szrj } 501