bool symtab_semantically_equivalent_p (symtab_node *a, symtab_node *b) { enum availability avail; symtab_node *ba; symtab_node *bb; /* Equivalent functions are equivalent. */ if (a->decl == b->decl) return true; /* If symbol is not overwritable by different implementation, walk to the base object it defines. */ ba = symtab_alias_ultimate_target (a, &avail); if (avail >= AVAIL_AVAILABLE) { if (ba == b) return true; } else ba = a; bb = symtab_alias_ultimate_target (b, &avail); if (avail >= AVAIL_AVAILABLE) { if (a == bb) return true; } else bb = b; return bb == ba; }
symtab_node * symtab_nonoverwritable_alias (symtab_node *node) { tree new_decl; symtab_node *new_node = NULL; /* First try to look up existing alias or base object (if that is already non-overwritable). */ node = symtab_alias_ultimate_target (node, NULL); gcc_assert (!node->alias && !node->weakref); symtab_for_node_and_aliases (node, symtab_nonoverwritable_alias_1, (void *)&new_node, true); if (new_node) return new_node; #ifndef ASM_OUTPUT_DEF /* If aliases aren't supported by the assembler, fail. */ return NULL; #endif /* Otherwise create a new one. */ new_decl = copy_node (node->decl); DECL_DLLIMPORT_P (new_decl) = 0; DECL_NAME (new_decl) = clone_function_name (node->decl, "localalias"); if (TREE_CODE (new_decl) == FUNCTION_DECL) DECL_STRUCT_FUNCTION (new_decl) = NULL; DECL_INITIAL (new_decl) = NULL; SET_DECL_ASSEMBLER_NAME (new_decl, DECL_NAME (new_decl)); SET_DECL_RTL (new_decl, NULL); /* Update the properties. */ DECL_EXTERNAL (new_decl) = 0; if (DECL_ONE_ONLY (node->decl)) DECL_SECTION_NAME (new_decl) = NULL; DECL_COMDAT_GROUP (new_decl) = 0; TREE_PUBLIC (new_decl) = 0; DECL_COMDAT (new_decl) = 0; DECL_WEAK (new_decl) = 0; DECL_VIRTUAL_P (new_decl) = 0; if (TREE_CODE (new_decl) == FUNCTION_DECL) { DECL_STATIC_CONSTRUCTOR (new_decl) = 0; DECL_STATIC_DESTRUCTOR (new_decl) = 0; new_node = cgraph_create_function_alias (new_decl, node->decl); } else new_node = varpool_create_variable_alias (new_decl, node->decl); symtab_resolve_alias (new_node, node); gcc_assert (decl_binds_to_current_def_p (new_decl)); return new_node; }
void enqueue_references (symtab_node **first, symtab_node *symbol) { int i; struct ipa_ref *ref; for (i = 0; ipa_ref_list_reference_iterate (&symbol->ref_list, i, ref); i++) { symtab_node *node = symtab_alias_ultimate_target (ref->referred, NULL); if (!node->aux && node->definition) { node->aux = *first; *first = node; } } if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol)) { struct cgraph_edge *edge; for (edge = cnode->callees; edge; edge = edge->next_callee) if (!edge->inline_failed) enqueue_references (first, edge->callee); else { symtab_node *node = symtab_alias_ultimate_target (edge->callee, NULL); if (!node->aux && node->definition) { node->aux = *first; *first = node; } } } }
bool symtab_resolve_alias (symtab_node node, symtab_node target) { symtab_node n; gcc_assert (!node->symbol.analyzed && !vec_safe_length (node->symbol.ref_list.references)); /* Never let cycles to creep into the symbol table alias references; those will make alias walkers to be infinite. */ for (n = target; n && n->symbol.alias; n = n->symbol.analyzed ? symtab_alias_target (n) : NULL) if (n == node) { if (is_a <cgraph_node> (node)) error ("function %q+D part of alias cycle", node->symbol.decl); else if (is_a <varpool_node> (node)) error ("variable %q+D part of alias cycle", node->symbol.decl); else gcc_unreachable (); node->symbol.alias = false; return false; } /* "analyze" the node - i.e. mark the reference. */ node->symbol.definition = true; node->symbol.alias = true; node->symbol.analyzed = true; ipa_record_reference (node, target, IPA_REF_ALIAS, NULL); /* Alias targets become reudndant after alias is resolved into an reference. We do not want to keep it around or we would have to mind updating them when renaming symbols. */ node->symbol.alias_target = NULL; if (node->symbol.cpp_implicit_alias && cgraph_state >= CGRAPH_STATE_CONSTRUCTION) fixup_same_cpp_alias_visibility (node, target); /* If alias has address taken, so does the target. */ if (node->symbol.address_taken) symtab_alias_ultimate_target (target, NULL)->symbol.address_taken = true; return true; }
static unsigned int ipa_comdats (void) { pointer_map<tree> map; pointer_map<symtab_node *> comdat_head_map; symtab_node *symbol; bool comdat_group_seen = false; symtab_node *first = (symtab_node *) (void *) 1; tree group; /* Start the dataflow by assigning comdat group to symbols that are in comdat groups already. All other externally visible symbols must stay, we use ERROR_MARK_NODE as bottom for the propagation. */ FOR_EACH_DEFINED_SYMBOL (symbol) if (!symtab_real_symbol_p (symbol)) ; else if ((group = symbol->get_comdat_group ()) != NULL) { *map.insert (symbol) = group; *comdat_head_map.insert (group) = symbol; comdat_group_seen = true; /* Mark the symbol so we won't waste time visiting it for dataflow. */ symbol->aux = (symtab_node *) (void *) 1; } /* See symbols that can not be privatized to comdats; that is externally visible symbols or otherwise used ones. We also do not want to mangle user section names. */ else if (symbol->externally_visible || symbol->force_output || symbol->used_from_other_partition || TREE_THIS_VOLATILE (symbol->decl) || symbol->get_section () || (TREE_CODE (symbol->decl) == FUNCTION_DECL && (DECL_STATIC_CONSTRUCTOR (symbol->decl) || DECL_STATIC_DESTRUCTOR (symbol->decl)))) { *map.insert (symtab_alias_ultimate_target (symbol, NULL)) = error_mark_node; /* Mark the symbol so we won't waste time visiting it for dataflow. */ symbol->aux = (symtab_node *) (void *) 1; } else { /* Enqueue symbol for dataflow. */ symbol->aux = first; first = symbol; } if (!comdat_group_seen) { FOR_EACH_DEFINED_SYMBOL (symbol) symbol->aux = NULL; return 0; } /* The actual dataflow. */ while (first != (void *) 1) { tree group = NULL; tree newgroup, *val; symbol = first; first = (symtab_node *)first->aux; /* Get current lattice value of SYMBOL. */ val = map.contains (symbol); if (val) group = *val; /* If it is bottom, there is nothing to do; do not clear AUX so we won't re-queue the symbol. */ if (group == error_mark_node) continue; newgroup = propagate_comdat_group (symbol, group, map); /* If nothing changed, proceed to next symbol. */ if (newgroup == group) { symbol->aux = NULL; continue; } /* Update lattice value and enqueue all references for re-visiting. */ gcc_assert (newgroup); if (val) *val = newgroup; else *map.insert (symbol) = newgroup; enqueue_references (&first, symbol); /* We may need to revisit the symbol unless it is BOTTOM. */ if (newgroup != error_mark_node) symbol->aux = NULL; } /* Finally assign symbols to the sections. */ FOR_EACH_DEFINED_SYMBOL (symbol) { symbol->aux = NULL; if (!symbol->get_comdat_group () && !symbol->alias && symtab_real_symbol_p (symbol)) { tree group = *map.contains (symbol); if (group == error_mark_node) continue; if (dump_file) { fprintf (dump_file, "Localizing symbol\n"); dump_symtab_node (dump_file, symbol); fprintf (dump_file, "To group: %s\n", IDENTIFIER_POINTER (group)); } symtab_for_node_and_aliases (symbol, set_comdat_group, *comdat_head_map.contains (group), true); } } return 0; }