static bool mark_load (gimple stmt, tree t, tree, void *data) { t = get_base_address (t); if (t && TREE_CODE (t) == FUNCTION_DECL) { /* ??? This can happen on platforms with descriptors when these are directly manipulated in the code. Pretend that it's an address. */ struct cgraph_node *node = cgraph_get_create_node (t); cgraph_mark_address_taken_node (node); ipa_record_reference ((symtab_node *)data, node, IPA_REF_ADDR, stmt); } else if (t && TREE_CODE (t) == VAR_DECL && (TREE_STATIC (t) || DECL_EXTERNAL (t))) { varpool_node *vnode = varpool_node_for_decl (t); ipa_record_reference ((symtab_node *)data, vnode, IPA_REF_LOAD, stmt); } return false; }
static tree record_reference (tree *tp, int *walk_subtrees, void *data) { tree t = *tp; tree decl; struct record_reference_ctx *ctx = (struct record_reference_ctx *)data; t = canonicalize_constructor_val (t, NULL); if (!t) t = *tp; else if (t != *tp) *tp = t; switch (TREE_CODE (t)) { case VAR_DECL: case FUNCTION_DECL: gcc_unreachable (); break; case FDESC_EXPR: case ADDR_EXPR: /* Record dereferences to the functions. This makes the functions reachable unconditionally. */ decl = get_base_var (*tp); if (TREE_CODE (decl) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_get_create_node (decl); if (!ctx->only_vars) cgraph_mark_address_taken_node (node); ipa_record_reference (ctx->varpool_node, node, IPA_REF_ADDR, NULL); } if (TREE_CODE (decl) == VAR_DECL) { varpool_node *vnode = varpool_node_for_decl (decl); ipa_record_reference (ctx->varpool_node, vnode, IPA_REF_ADDR, NULL); } *walk_subtrees = 0; break; default: /* Save some cycles by not walking types and declaration as we won't find anything useful there anyway. */ if (IS_TYPE_OR_DECL_P (*tp)) { *walk_subtrees = 0; break; } break; } return NULL_TREE; }
/* Add the variable DECL to the varpool. Unlike varpool_finalize_decl function is intended to be used by middle end and allows insertion of new variable at arbitrary point of compilation. */ void varpool_add_new_variable (tree decl) { struct varpool_node *node; varpool_finalize_decl (decl); node = varpool_node_for_decl (decl); if (varpool_externally_visible_p (node, false)) node->symbol.externally_visible = true; }
/* Add the variable DECL to the varpool. Unlike varpool_finalize_decl function is intended to be used by middle end and allows insertion of new variable at arbitrary point of compilation. */ void varpool_add_new_variable (tree decl) { varpool_node *node; varpool_finalize_decl (decl); node = varpool_node_for_decl (decl); varpool_call_variable_insertion_hooks (node); if (varpool_externally_visible_p (node)) node->externally_visible = true; }
void record_references_in_initializer (tree decl, bool only_vars) { struct pointer_set_t *visited_nodes = pointer_set_create (); varpool_node *node = varpool_node_for_decl (decl); struct record_reference_ctx ctx = {false, NULL}; ctx.varpool_node = node; ctx.only_vars = only_vars; walk_tree (&DECL_INITIAL (decl), record_reference, &ctx, visited_nodes); pointer_set_destroy (visited_nodes); }
static bool mark_store (gimple stmt, tree t, tree, void *data) { t = get_base_address (t); if (t && TREE_CODE (t) == VAR_DECL && (TREE_STATIC (t) || DECL_EXTERNAL (t))) { varpool_node *vnode = varpool_node_for_decl (t); ((symtab_node *)data)->add_reference (vnode, IPA_REF_STORE, stmt); } return false; }
varpool_node * varpool_create_variable_alias (tree alias, tree decl) { varpool_node *alias_node; gcc_assert (TREE_CODE (decl) == VAR_DECL); gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node_for_decl (alias); alias_node->alias = true; alias_node->definition = true; alias_node->alias_target = decl; if (lookup_attribute ("weakref", DECL_ATTRIBUTES (alias)) != NULL) alias_node->weakref = true; return alias_node; }
/* Create a new global variable of type TYPE. */ tree add_new_static_var (tree type) { tree new_decl; varpool_node *new_node; new_decl = create_tmp_var_raw (type, NULL); DECL_NAME (new_decl) = create_tmp_var_name (NULL); TREE_READONLY (new_decl) = 0; TREE_STATIC (new_decl) = 1; TREE_USED (new_decl) = 1; DECL_CONTEXT (new_decl) = NULL_TREE; DECL_ABSTRACT (new_decl) = 0; lang_hooks.dup_lang_specific_decl (new_decl); new_node = varpool_node_for_decl (new_decl); varpool_finalize_decl (new_decl); return new_node->decl; }
void varpool_analyze_node (struct varpool_node *node) { tree decl = node->symbol.decl; /* When reading back varpool at LTO time, we re-construct the queue in order to have "needed" list right by inserting all needed nodes into varpool. We however don't want to re-analyze already analyzed nodes. */ if (!node->analyzed) { gcc_assert (!in_lto_p || cgraph_function_flags_ready); /* Compute the alignment early so function body expanders are already informed about increased alignment. */ align_variable (decl, 0); } if (node->alias && node->alias_of) { struct varpool_node *tgt = varpool_node_for_decl (node->alias_of); struct varpool_node *n; for (n = tgt; n && n->alias; n = n->analyzed ? varpool_alias_aliased_node (n) : NULL) if (n == node) { error ("variable %q+D part of alias cycle", node->symbol.decl); node->alias = false; continue; } if (!vec_safe_length (node->symbol.ref_list.references)) ipa_record_reference ((symtab_node)node, (symtab_node)tgt, IPA_REF_ALIAS, NULL); if (node->extra_name_alias) { DECL_WEAK (node->symbol.decl) = DECL_WEAK (node->alias_of); DECL_EXTERNAL (node->symbol.decl) = DECL_EXTERNAL (node->alias_of); DECL_VISIBILITY (node->symbol.decl) = DECL_VISIBILITY (node->alias_of); fixup_same_cpp_alias_visibility ((symtab_node) node, (symtab_node) tgt, node->alias_of); } } else if (DECL_INITIAL (decl)) record_references_in_initializer (decl, node->analyzed); node->analyzed = true; }
static bool mark_address (gimple stmt, tree addr, tree, void *data) { addr = get_base_address (addr); if (TREE_CODE (addr) == FUNCTION_DECL) { struct cgraph_node *node = cgraph_get_create_node (addr); cgraph_mark_address_taken_node (node); ((symtab_node *)data)->add_reference (node, IPA_REF_ADDR, stmt); } else if (addr && TREE_CODE (addr) == VAR_DECL && (TREE_STATIC (addr) || DECL_EXTERNAL (addr))) { varpool_node *vnode = varpool_node_for_decl (addr); ((symtab_node *)data)->add_reference (vnode, IPA_REF_ADDR, stmt); } return false; }
varpool_node * varpool_extra_name_alias (tree alias, tree decl) { varpool_node *alias_node; #ifndef ASM_OUTPUT_DEF /* If aliases aren't supported by the assembler, fail. */ return NULL; #endif alias_node = varpool_create_variable_alias (alias, decl); alias_node->cpp_implicit_alias = true; /* Extra name alias mechanizm creates aliases really late via DECL_ASSEMBLER_NAME mechanizm. This is unfortunate because they are not going through the standard channels. Ensure they get output. */ if (cpp_implicit_aliases_done) symtab_resolve_alias (alias_node, varpool_node_for_decl (decl)); return alias_node; }
static void record_type_list (struct cgraph_node *node, tree list) { for (; list; list = TREE_CHAIN (list)) { tree type = TREE_VALUE (list); if (TYPE_P (type)) type = lookup_type_for_runtime (type); STRIP_NOPS (type); if (TREE_CODE (type) == ADDR_EXPR) { type = TREE_OPERAND (type, 0); if (TREE_CODE (type) == VAR_DECL) { varpool_node *vnode = varpool_node_for_decl (type); node->add_reference (vnode, IPA_REF_ADDR); } } } }
struct varpool_node * varpool_create_variable_alias (tree alias, tree decl) { struct varpool_node *alias_node; gcc_assert (TREE_CODE (decl) == VAR_DECL); gcc_assert (TREE_CODE (alias) == VAR_DECL); alias_node = varpool_node_for_decl (alias); alias_node->alias = 1; alias_node->finalized = 1; alias_node->alias_of = decl; /* Extra name alias mechanizm creates aliases really late via DECL_ASSEMBLER_NAME mechanizm. This is unfortunate because they are not going through the standard channels. Ensure they get output. */ if (cgraph_state >= CGRAPH_STATE_IPA) { varpool_analyze_node (alias_node); if (TREE_PUBLIC (alias)) alias_node->symbol.externally_visible = true; } return alias_node; }