void symtab_node::make_decl_local (void) { rtx rtl, symbol; /* Avoid clearing comdat_groups on comdat-local decls. */ if (TREE_PUBLIC (decl) == 0) return; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); DECL_COMDAT (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; DECL_VISIBILITY_SPECIFIED (decl) = 0; DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; TREE_PUBLIC (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
/* Optimization of function bodies might've rendered some variables as unnecessary so we want to avoid these from being compiled. This is done by pruning the queue and keeping only the variables that really appear needed (ie they are either externally visible or referenced by compiled function). Re-doing the reachability analysis on variables brings back the remaining variables referenced by these. */ void varpool_remove_unreferenced_decls (void) { struct varpool_node *next, *node = varpool_nodes_queue; varpool_reset_queue (); if (seen_error ()) return; while (node) { next = node->next_needed; node->needed = 0; if (node->analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ || DECL_RTL_SET_P (node->decl))) varpool_mark_needed_node (node); node = next; } /* Make sure we mark alias targets as used targets. */ finish_aliases_1 (); varpool_analyze_pending_decls (); }
void change_decl_assembler_name (tree decl, tree name) { symtab_node node = NULL; /* We can have user ASM names on things, like global register variables, that are not in the symbol table. */ if ((TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) || TREE_CODE (decl) == FUNCTION_DECL) node = symtab_get_node (decl); if (!DECL_ASSEMBLER_NAME_SET_P (decl)) { SET_DECL_ASSEMBLER_NAME (decl, name); if (node) insert_to_assembler_name_hash (node); } else { if (name == DECL_ASSEMBLER_NAME (decl)) return; if (node) unlink_from_assembler_name_hash (node); if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) && DECL_RTL_SET_P (decl)) warning (0, "%D renamed after being referenced in assembly", decl); SET_DECL_ASSEMBLER_NAME (decl, name); if (node) insert_to_assembler_name_hash (node); } }
/* Optimization of function bodies might've rendered some variables as unnecessary so we want to avoid these from being compiled. This is done by pruning the queue and keeping only the variables that really appear needed (ie they are either externally visible or referenced by compiled function). Re-doing the reachability analysis on variables brings back the remaining variables referenced by these. */ void varpool_remove_unreferenced_decls (void) { struct varpool_node *next, *node = varpool_nodes_queue; varpool_reset_queue (); if (errorcount || sorrycount) return; while (node) { tree decl = node->decl; next = node->next_needed; node->needed = 0; if (node->finalized && (decide_is_variable_needed (node, decl) /* ??? Cgraph does not yet rule the world with an iron hand, and does not control the emission of debug information. After a variable has its DECL_RTL set, we must assume that it may be referenced by the debug information, and we can no longer elide it. */ || DECL_RTL_SET_P (decl))) varpool_mark_needed_node (node); node = next; } /* Make sure we mark alias targets as used targets. */ finish_aliases_1 (); varpool_analyze_pending_decls (); }
void emit_local_var (tree decl) { /* Create RTL for this variable. */ if (!DECL_RTL_SET_P (decl)) { if (DECL_C_HARD_REGISTER (decl)) /* The user specified an assembler name for this variable. Set that up now. */ rest_of_decl_compilation (decl, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)), /*top_level=*/0, /*at_end=*/0); else expand_decl (decl); } if (DECL_INITIAL (decl)) { /* Actually do the initialization. */ if (stmts_are_full_exprs_p ()) expand_start_target_temps (); expand_decl_init (decl); if (stmts_are_full_exprs_p ()) expand_end_target_temps (); } }
void make_rtl_for_local_static (tree decl) { const char *asmspec = NULL; /* If we inlined this variable, we could see it's declaration again. */ if (TREE_ASM_WRITTEN (decl)) return; /* If the DECL_ASSEMBLER_NAME is not the same as the DECL_NAME, then either we already created RTL for this DECL (and since it was a local variable, its DECL_ASSEMBLER_NAME got hacked up to prevent clashes with other local statics with the same name by a previous call to make_decl_rtl), or the user explicitly requested a particular assembly name for this variable, using the GNU extension for this purpose: int i asm ("j"); There's no way to know which case we're in, here. But, it turns out we're safe. If there's already RTL, then rest_of_decl_compilation ignores the ASMSPEC parameter, so we may as well not pass it in. If there isn't RTL, then we didn't already create RTL, which means that the modification to DECL_ASSEMBLER_NAME came only via the explicit extension. */ if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl) && !DECL_RTL_SET_P (decl)) asmspec = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); rest_of_decl_compilation (decl, asmspec, /*top_level=*/0, /*at_end=*/0); }
/* Make DECL local. FIXME: We shouldn't need to mess with rtl this early, but other code such as notice_global_symbol generates rtl. */ void symtab_make_decl_local (tree decl) { rtx rtl, symbol; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl)) { /* It is possible that we are linking against library defining same COMDAT function. To avoid conflict we need to rename our local name of the function just in the case WHOPR partitioning decide to make it hidden to avoid cross partition references. */ if (flag_wpa) { const char *old_name; symtab_node node = symtab_get_node (decl); old_name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); change_decl_assembler_name (decl, clone_function_name (decl, "local")); if (node->symbol.lto_file_data) lto_record_renamed_decl (node->symbol.lto_file_data, old_name, IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); } DECL_SECTION_NAME (decl) = 0; DECL_COMDAT (decl) = 0; } DECL_COMDAT_GROUP (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; TREE_PUBLIC (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
void emit_local_var (tree decl) { /* Create RTL for this variable. */ if (!DECL_RTL_SET_P (decl)) { if (DECL_HARD_REGISTER (decl)) /* The user specified an assembler name for this variable. Set that up now. */ rest_of_decl_compilation (decl, 0, 0); else expand_decl (decl); } }
void symbol_table::change_decl_assembler_name (tree decl, tree name) { symtab_node *node = NULL; /* We can have user ASM names on things, like global register variables, that are not in the symbol table. */ if ((TREE_CODE (decl) == VAR_DECL && (TREE_STATIC (decl) || DECL_EXTERNAL (decl))) || TREE_CODE (decl) == FUNCTION_DECL) node = symtab_node::get (decl); if (!DECL_ASSEMBLER_NAME_SET_P (decl)) { SET_DECL_ASSEMBLER_NAME (decl, name); if (node) insert_to_assembler_name_hash (node, true); } else { if (name == DECL_ASSEMBLER_NAME (decl)) return; tree alias = (IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (decl)) ? TREE_CHAIN (DECL_ASSEMBLER_NAME (decl)) : NULL); if (node) unlink_from_assembler_name_hash (node, true); if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)) && DECL_RTL_SET_P (decl)) warning (0, "%D renamed after being referenced in assembly", decl); SET_DECL_ASSEMBLER_NAME (decl, name); if (alias) { IDENTIFIER_TRANSPARENT_ALIAS (name) = 1; TREE_CHAIN (name) = alias; } if (node) insert_to_assembler_name_hash (node, true); } }
void symtab_make_decl_local (tree decl) { rtx rtl, symbol; /* Avoid clearing DECL_COMDAT_GROUP on comdat-local decls. */ if (TREE_PUBLIC (decl) == 0) return; if (TREE_CODE (decl) == VAR_DECL) DECL_COMMON (decl) = 0; else gcc_assert (TREE_CODE (decl) == FUNCTION_DECL); if (DECL_ONE_ONLY (decl) || DECL_COMDAT (decl)) { DECL_SECTION_NAME (decl) = 0; DECL_COMDAT (decl) = 0; } DECL_COMDAT_GROUP (decl) = 0; DECL_WEAK (decl) = 0; DECL_EXTERNAL (decl) = 0; DECL_VISIBILITY_SPECIFIED (decl) = 0; DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT; TREE_PUBLIC (decl) = 0; DECL_DLLIMPORT_P (decl) = 0; if (!DECL_RTL_SET_P (decl)) return; /* Update rtl flags. */ make_decl_rtl (decl); rtl = DECL_RTL (decl); if (!MEM_P (rtl)) return; symbol = XEXP (rtl, 0); if (GET_CODE (symbol) != SYMBOL_REF) return; SYMBOL_REF_WEAK (symbol) = DECL_WEAK (decl); }
static void expand_one_var (tree var, bool toplevel) { if (TREE_CODE (var) != VAR_DECL) lang_hooks.expand_decl (var); else if (DECL_EXTERNAL (var)) ; else if (DECL_VALUE_EXPR (var)) ; else if (TREE_STATIC (var)) expand_one_static_var (var); else if (DECL_RTL_SET_P (var)) ; else if (TREE_TYPE (var) == error_mark_node) expand_one_error_var (var); else if (DECL_HARD_REGISTER (var)) expand_one_hard_reg_var (var); else if (use_register_for_decl (var)) expand_one_register_var (var); else if (defer_stack_allocation (var, toplevel)) add_stack_var (var); else expand_one_stack_var (var); }
void print_node (FILE *file, const char *prefix, tree node, int indent) { int hash; struct bucket *b; machine_mode mode; enum tree_code_class tclass; int len; int i; expanded_location xloc; enum tree_code code; if (node == 0) return; code = TREE_CODE (node); tclass = TREE_CODE_CLASS (code); /* Don't get too deep in nesting. If the user wants to see deeper, it is easy to use the address of a lowest-level node as an argument in another call to debug_tree. */ if (indent > 24) { print_node_brief (file, prefix, node, indent); return; } if (indent > 8 && (tclass == tcc_type || tclass == tcc_declaration)) { print_node_brief (file, prefix, node, indent); return; } /* It is unsafe to look at any other fields of an ERROR_MARK node. */ if (code == ERROR_MARK) { print_node_brief (file, prefix, node, indent); return; } /* Allow this function to be called if the table is not there. */ if (table) { hash = ((uintptr_t) node) % HASH_SIZE; /* If node is in the table, just mention its address. */ for (b = table[hash]; b; b = b->next) if (b->node == node) { print_node_brief (file, prefix, node, indent); return; } /* Add this node to the table. */ b = XNEW (struct bucket); b->node = node; b->next = table[hash]; table[hash] = b; } /* Indent to the specified column, since this is the long form. */ indent_to (file, indent); /* Print the slot this node is in, and its code, and address. */ fprintf (file, "%s <%s", prefix, get_tree_code_name (code)); dump_addr (file, " ", node); /* Print the name, if any. */ if (tclass == tcc_declaration) { if (DECL_NAME (node)) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (node))); else if (code == LABEL_DECL && LABEL_DECL_UID (node) != -1) { if (dump_flags & TDF_NOUID) fprintf (file, " L.xxxx"); else fprintf (file, " L.%d", (int) LABEL_DECL_UID (node)); } else { if (dump_flags & TDF_NOUID) fprintf (file, " %c.xxxx", code == CONST_DECL ? 'C' : 'D'); else fprintf (file, " %c.%u", code == CONST_DECL ? 'C' : 'D', DECL_UID (node)); } } else if (tclass == tcc_type) { if (TYPE_NAME (node)) { if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (TYPE_NAME (node))); else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL && DECL_NAME (TYPE_NAME (node))) fprintf (file, " %s", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (node)))); } } if (code == IDENTIFIER_NODE) fprintf (file, " %s", IDENTIFIER_POINTER (node)); if (code == INTEGER_CST) { if (indent <= 4) print_node_brief (file, "type", TREE_TYPE (node), indent + 4); } else if (CODE_CONTAINS_STRUCT (code, TS_TYPED)) { print_node (file, "type", TREE_TYPE (node), indent + 4); if (TREE_TYPE (node)) indent_to (file, indent + 3); } if (!TYPE_P (node) && TREE_SIDE_EFFECTS (node)) fputs (" side-effects", file); if (TYPE_P (node) ? TYPE_READONLY (node) : TREE_READONLY (node)) fputs (" readonly", file); if (TYPE_P (node) && TYPE_ATOMIC (node)) fputs (" atomic", file); if (!TYPE_P (node) && TREE_CONSTANT (node)) fputs (" constant", file); else if (TYPE_P (node) && TYPE_SIZES_GIMPLIFIED (node)) fputs (" sizes-gimplified", file); if (TYPE_P (node) && !ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (node))) fprintf (file, " address-space-%d", TYPE_ADDR_SPACE (node)); if (TREE_ADDRESSABLE (node)) fputs (" addressable", file); if (TREE_THIS_VOLATILE (node)) fputs (" volatile", file); if (TREE_ASM_WRITTEN (node)) fputs (" asm_written", file); if (TREE_USED (node)) fputs (" used", file); if (TREE_NOTHROW (node)) fputs (" nothrow", file); if (TREE_PUBLIC (node)) fputs (" public", file); if (TREE_PRIVATE (node)) fputs (" private", file); if (TREE_PROTECTED (node)) fputs (" protected", file); if (TREE_STATIC (node)) fputs (code == CALL_EXPR ? " must-tail-call" : " static", file); if (TREE_DEPRECATED (node)) fputs (" deprecated", file); if (TREE_VISITED (node)) fputs (" visited", file); if (code != TREE_VEC && code != INTEGER_CST && code != SSA_NAME) { if (TREE_LANG_FLAG_0 (node)) fputs (" tree_0", file); if (TREE_LANG_FLAG_1 (node)) fputs (" tree_1", file); if (TREE_LANG_FLAG_2 (node)) fputs (" tree_2", file); if (TREE_LANG_FLAG_3 (node)) fputs (" tree_3", file); if (TREE_LANG_FLAG_4 (node)) fputs (" tree_4", file); if (TREE_LANG_FLAG_5 (node)) fputs (" tree_5", file); if (TREE_LANG_FLAG_6 (node)) fputs (" tree_6", file); } /* DECL_ nodes have additional attributes. */ switch (TREE_CODE_CLASS (code)) { case tcc_declaration: if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_UNSIGNED (node)) fputs (" unsigned", file); if (DECL_IGNORED_P (node)) fputs (" ignored", file); if (DECL_ABSTRACT_P (node)) fputs (" abstract", file); if (DECL_EXTERNAL (node)) fputs (" external", file); if (DECL_NONLOCAL (node)) fputs (" nonlocal", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS)) { if (DECL_WEAK (node)) fputs (" weak", file); if (DECL_IN_SYSTEM_HEADER (node)) fputs (" in_system_header", file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL) && code != LABEL_DECL && code != FUNCTION_DECL && DECL_REGISTER (node)) fputs (" regdecl", file); if (code == TYPE_DECL && TYPE_DECL_SUPPRESS_DEBUG (node)) fputs (" suppress-debug", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_TARGET (node)) fputs (" function-specific-target", file); if (code == FUNCTION_DECL && DECL_FUNCTION_SPECIFIC_OPTIMIZATION (node)) fputs (" function-specific-opt", file); if (code == FUNCTION_DECL && DECL_DECLARED_INLINE_P (node)) fputs (" autoinline", file); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) fputs (" built-in", file); if (code == FUNCTION_DECL && DECL_STATIC_CHAIN (node)) fputs (" static-chain", file); if (TREE_CODE (node) == FUNCTION_DECL && decl_is_tm_clone (node)) fputs (" tm-clone", file); if (code == FIELD_DECL && DECL_PACKED (node)) fputs (" packed", file); if (code == FIELD_DECL && DECL_BIT_FIELD (node)) fputs (" bit-field", file); if (code == FIELD_DECL && DECL_NONADDRESSABLE_P (node)) fputs (" nonaddressable", file); if (code == LABEL_DECL && EH_LANDING_PAD_NR (node)) fprintf (file, " landing-pad:%d", EH_LANDING_PAD_NR (node)); if (code == VAR_DECL && DECL_IN_TEXT_SECTION (node)) fputs (" in-text-section", file); if (code == VAR_DECL && DECL_IN_CONSTANT_POOL (node)) fputs (" in-constant-pool", file); if (code == VAR_DECL && DECL_COMMON (node)) fputs (" common", file); if (code == VAR_DECL && DECL_THREAD_LOCAL_P (node)) { fputs (" ", file); fputs (tls_model_names[DECL_TLS_MODEL (node)], file); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { if (DECL_VIRTUAL_P (node)) fputs (" virtual", file); if (DECL_PRESERVE_P (node)) fputs (" preserve", file); if (DECL_LANG_FLAG_0 (node)) fputs (" decl_0", file); if (DECL_LANG_FLAG_1 (node)) fputs (" decl_1", file); if (DECL_LANG_FLAG_2 (node)) fputs (" decl_2", file); if (DECL_LANG_FLAG_3 (node)) fputs (" decl_3", file); if (DECL_LANG_FLAG_4 (node)) fputs (" decl_4", file); if (DECL_LANG_FLAG_5 (node)) fputs (" decl_5", file); if (DECL_LANG_FLAG_6 (node)) fputs (" decl_6", file); if (DECL_LANG_FLAG_7 (node)) fputs (" decl_7", file); mode = DECL_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); } if ((code == VAR_DECL || code == PARM_DECL || code == RESULT_DECL) && DECL_BY_REFERENCE (node)) fputs (" passed-by-reference", file); if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS) && DECL_DEFER_OUTPUT (node)) fputs (" defer-output", file); xloc = expand_location (DECL_SOURCE_LOCATION (node)); fprintf (file, " file %s line %d col %d", xloc.file, xloc.line, xloc.column); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node (file, "size", DECL_SIZE (node), indent + 4); print_node (file, "unit size", DECL_SIZE_UNIT (node), indent + 4); if (code != FUNCTION_DECL || DECL_BUILT_IN (node)) indent_to (file, indent + 3); if (DECL_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d", DECL_ALIGN (node)); if (code == FIELD_DECL) fprintf (file, " offset_align " HOST_WIDE_INT_PRINT_UNSIGNED, DECL_OFFSET_ALIGN (node)); if (code == FUNCTION_DECL && DECL_BUILT_IN (node)) { if (DECL_BUILT_IN_CLASS (node) == BUILT_IN_MD) fprintf (file, " built-in BUILT_IN_MD %d", DECL_FUNCTION_CODE (node)); else fprintf (file, " built-in %s:%s", built_in_class_names[(int) DECL_BUILT_IN_CLASS (node)], built_in_names[(int) DECL_FUNCTION_CODE (node)]); } } if (code == FIELD_DECL) { print_node (file, "offset", DECL_FIELD_OFFSET (node), indent + 4); print_node (file, "bit offset", DECL_FIELD_BIT_OFFSET (node), indent + 4); if (DECL_BIT_FIELD_TYPE (node)) print_node (file, "bit_field_type", DECL_BIT_FIELD_TYPE (node), indent + 4); } print_node_brief (file, "context", DECL_CONTEXT (node), indent + 4); if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON)) { print_node_brief (file, "attributes", DECL_ATTRIBUTES (node), indent + 4); if (code != PARM_DECL) print_node_brief (file, "initial", DECL_INITIAL (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_WRTL)) { print_node_brief (file, "abstract_origin", DECL_ABSTRACT_ORIGIN (node), indent + 4); } if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON)) { print_node (file, "result", DECL_RESULT_FLD (node), indent + 4); } lang_hooks.print_decl (file, node, indent); if (DECL_RTL_SET_P (node)) { indent_to (file, indent + 4); print_rtl (file, DECL_RTL (node)); } if (code == PARM_DECL) { print_node (file, "arg-type", DECL_ARG_TYPE (node), indent + 4); if (DECL_INCOMING_RTL (node) != 0) { indent_to (file, indent + 4); fprintf (file, "incoming-rtl "); print_rtl (file, DECL_INCOMING_RTL (node)); } } else if (code == FUNCTION_DECL && DECL_STRUCT_FUNCTION (node) != 0) { print_node (file, "arguments", DECL_ARGUMENTS (node), indent + 4); indent_to (file, indent + 4); dump_addr (file, "struct-function ", DECL_STRUCT_FUNCTION (node)); } if ((code == VAR_DECL || code == PARM_DECL) && DECL_HAS_VALUE_EXPR_P (node)) print_node (file, "value-expr", DECL_VALUE_EXPR (node), indent + 4); /* Print the decl chain only if decl is at second level. */ if (indent == 4) print_node (file, "chain", TREE_CHAIN (node), indent + 4); else print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_type: if (TYPE_UNSIGNED (node)) fputs (" unsigned", file); if (TYPE_NO_FORCE_BLK (node)) fputs (" no-force-blk", file); if (TYPE_STRING_FLAG (node)) fputs (" string-flag", file); if (TYPE_NEEDS_CONSTRUCTING (node)) fputs (" needs-constructing", file); if ((code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE || code == ARRAY_TYPE) && TYPE_REVERSE_STORAGE_ORDER (node)) fputs (" reverse-storage-order", file); /* The transparent-union flag is used for different things in different nodes. */ if ((code == UNION_TYPE || code == RECORD_TYPE) && TYPE_TRANSPARENT_AGGR (node)) fputs (" transparent-aggr", file); else if (code == ARRAY_TYPE && TYPE_NONALIASED_COMPONENT (node)) fputs (" nonaliased-component", file); if (TYPE_PACKED (node)) fputs (" packed", file); if (TYPE_RESTRICT (node)) fputs (" restrict", file); if (TYPE_LANG_FLAG_0 (node)) fputs (" type_0", file); if (TYPE_LANG_FLAG_1 (node)) fputs (" type_1", file); if (TYPE_LANG_FLAG_2 (node)) fputs (" type_2", file); if (TYPE_LANG_FLAG_3 (node)) fputs (" type_3", file); if (TYPE_LANG_FLAG_4 (node)) fputs (" type_4", file); if (TYPE_LANG_FLAG_5 (node)) fputs (" type_5", file); if (TYPE_LANG_FLAG_6 (node)) fputs (" type_6", file); if (TYPE_LANG_FLAG_7 (node)) fputs (" type_7", file); mode = TYPE_MODE (node); fprintf (file, " %s", GET_MODE_NAME (mode)); print_node (file, "size", TYPE_SIZE (node), indent + 4); print_node (file, "unit size", TYPE_SIZE_UNIT (node), indent + 4); indent_to (file, indent + 3); if (TYPE_USER_ALIGN (node)) fprintf (file, " user"); fprintf (file, " align %d symtab %d alias set " HOST_WIDE_INT_PRINT_DEC, TYPE_ALIGN (node), TYPE_SYMTAB_ADDRESS (node), (HOST_WIDE_INT) TYPE_ALIAS_SET (node)); if (TYPE_STRUCTURAL_EQUALITY_P (node)) fprintf (file, " structural equality"); else dump_addr (file, " canonical type ", TYPE_CANONICAL (node)); print_node (file, "attributes", TYPE_ATTRIBUTES (node), indent + 4); if (INTEGRAL_TYPE_P (node) || code == REAL_TYPE || code == FIXED_POINT_TYPE) { fprintf (file, " precision %d", TYPE_PRECISION (node)); print_node_brief (file, "min", TYPE_MIN_VALUE (node), indent + 4); print_node_brief (file, "max", TYPE_MAX_VALUE (node), indent + 4); } if (code == ENUMERAL_TYPE) print_node (file, "values", TYPE_VALUES (node), indent + 4); else if (code == ARRAY_TYPE) print_node (file, "domain", TYPE_DOMAIN (node), indent + 4); else if (code == VECTOR_TYPE) fprintf (file, " nunits %d", (int) TYPE_VECTOR_SUBPARTS (node)); else if (code == RECORD_TYPE || code == UNION_TYPE || code == QUAL_UNION_TYPE) print_node (file, "fields", TYPE_FIELDS (node), indent + 4); else if (code == FUNCTION_TYPE || code == METHOD_TYPE) { if (TYPE_METHOD_BASETYPE (node)) print_node_brief (file, "method basetype", TYPE_METHOD_BASETYPE (node), indent + 4); print_node (file, "arg-types", TYPE_ARG_TYPES (node), indent + 4); } else if (code == OFFSET_TYPE) print_node_brief (file, "basetype", TYPE_OFFSET_BASETYPE (node), indent + 4); if (TYPE_CONTEXT (node)) print_node_brief (file, "context", TYPE_CONTEXT (node), indent + 4); lang_hooks.print_type (file, node, indent); if (TYPE_POINTER_TO (node) || TREE_CHAIN (node)) indent_to (file, indent + 3); print_node_brief (file, "pointer_to_this", TYPE_POINTER_TO (node), indent + 4); print_node_brief (file, "reference_to_this", TYPE_REFERENCE_TO (node), indent + 4); print_node_brief (file, "chain", TREE_CHAIN (node), indent + 4); break; case tcc_expression: case tcc_comparison: case tcc_unary: case tcc_binary: case tcc_reference: case tcc_statement: case tcc_vl_exp: if (code == BIND_EXPR) { print_node (file, "vars", TREE_OPERAND (node, 0), indent + 4); print_node (file, "body", TREE_OPERAND (node, 1), indent + 4); print_node (file, "block", TREE_OPERAND (node, 2), indent + 4); break; } if (code == CALL_EXPR) { call_expr_arg_iterator iter; tree arg; print_node (file, "fn", CALL_EXPR_FN (node), indent + 4); print_node (file, "static_chain", CALL_EXPR_STATIC_CHAIN (node), indent + 4); i = 0; FOR_EACH_CALL_EXPR_ARG (arg, iter, node) { char temp[10]; sprintf (temp, "arg %d", i); print_node (file, temp, arg, indent + 4); i++; } }
static void varpool_remove_unreferenced_decls (void) { varpool_node *next, *node; varpool_node *first = (varpool_node *)(void *)1; int i; struct ipa_ref *ref; struct pointer_set_t *referenced = pointer_set_create (); if (seen_error ()) return; if (cgraph_dump_file) fprintf (cgraph_dump_file, "Trivially needed variables:"); FOR_EACH_DEFINED_VARIABLE (node) { if (node->analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ || DECL_RTL_SET_P (node->decl))) { enqueue_node (node, &first); if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", node->asm_name ()); } } while (first != (varpool_node *)(void *)1) { node = first; first = (varpool_node *)first->aux; if (node->same_comdat_group) { symtab_node *next; for (next = node->same_comdat_group; next != node; next = next->same_comdat_group) { varpool_node *vnext = dyn_cast <varpool_node *> (next); if (vnext && vnext->analyzed && !symtab_comdat_local_p (next)) enqueue_node (vnext, &first); } } for (i = 0; ipa_ref_list_reference_iterate (&node->ref_list, i, ref); i++) { varpool_node *vnode = dyn_cast <varpool_node *> (ref->referred); if (vnode && !vnode->in_other_partition && (!DECL_EXTERNAL (ref->referred->decl) || vnode->alias) && vnode->analyzed) enqueue_node (vnode, &first); else pointer_set_insert (referenced, node); } } if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nRemoving variables:"); for (node = varpool_first_defined_variable (); node; node = next) { next = varpool_next_defined_variable (node); if (!node->aux) { if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", node->asm_name ()); if (pointer_set_contains (referenced, node)) varpool_remove_initializer (node); else varpool_remove_node (node); } } pointer_set_destroy (referenced); if (cgraph_dump_file) fprintf (cgraph_dump_file, "\n"); }
void sdbout_symbol (tree decl, int local) { tree type = TREE_TYPE (decl); tree context = NULL_TREE; rtx value; int regno = -1; const char *name; /* If we are called before sdbout_init is run, just save the symbol for later. */ if (!sdbout_initialized) { preinit_symbols = tree_cons (0, decl, preinit_symbols); return; } sdbout_one_type (type); switch (TREE_CODE (decl)) { case CONST_DECL: /* Enum values are defined by defining the enum type. */ return; case FUNCTION_DECL: /* Don't mention a nested function under its parent. */ context = decl_function_context (decl); if (context == current_function_decl) return; /* Check DECL_INITIAL to distinguish declarations from definitions. Don't output debug info here for declarations; they will have a DECL_INITIAL value of 0. */ if (! DECL_INITIAL (decl)) return; if (!MEM_P (DECL_RTL (decl)) || GET_CODE (XEXP (DECL_RTL (decl), 0)) != SYMBOL_REF) return; PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); PUT_SDB_VAL (XEXP (DECL_RTL (decl), 0)); PUT_SDB_SCL (TREE_PUBLIC (decl) ? C_EXT : C_STAT); break; case TYPE_DECL: /* Done with tagged types. */ if (DECL_NAME (decl) == 0) return; if (DECL_IGNORED_P (decl)) return; /* Don't output intrinsic types. GAS chokes on SDB .def statements that contain identifiers with embedded spaces (eg "unsigned long"). */ if (DECL_IS_BUILTIN (decl)) return; /* Output typedef name. */ if (template_name_p (DECL_NAME (decl))) PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl))); else PUT_SDB_DEF (IDENTIFIER_POINTER (DECL_NAME (decl))); PUT_SDB_SCL (C_TPDEF); break; case PARM_DECL: /* Parm decls go in their own separate chains and are output by sdbout_reg_parms and sdbout_parms. */ gcc_unreachable (); case VAR_DECL: /* Don't mention a variable that is external. Let the file that defines it describe it. */ if (DECL_EXTERNAL (decl)) return; /* Ignore __FUNCTION__, etc. */ if (DECL_IGNORED_P (decl)) return; /* If there was an error in the declaration, don't dump core if there is no RTL associated with the variable doesn't exist. */ if (!DECL_RTL_SET_P (decl)) return; SET_DECL_RTL (decl, eliminate_regs (DECL_RTL (decl), VOIDmode, NULL_RTX)); #ifdef LEAF_REG_REMAP if (crtl->uses_only_leaf_regs) leaf_renumber_regs_insn (DECL_RTL (decl)); #endif value = DECL_RTL (decl); /* Don't mention a variable at all if it was completely optimized into nothingness. If DECL was from an inline function, then its rtl is not identically the rtl that was used in this particular compilation. */ if (REG_P (value)) { regno = REGNO (value); if (regno >= FIRST_PSEUDO_REGISTER) return; } else if (GET_CODE (value) == SUBREG) { while (GET_CODE (value) == SUBREG) value = SUBREG_REG (value); if (REG_P (value)) { if (REGNO (value) >= FIRST_PSEUDO_REGISTER) return; } regno = REGNO (alter_subreg (&value)); SET_DECL_RTL (decl, value); } /* Don't output anything if an auto variable gets RTL that is static. GAS version 2.2 can't handle such output. */ else if (MEM_P (value) && CONSTANT_P (XEXP (value, 0)) && ! TREE_STATIC (decl)) return; /* Emit any structure, union, or enum type that has not been output. This occurs for tag-less structs (et al) used to declare variables within functions. */ if (TREE_CODE (type) == ENUMERAL_TYPE || TREE_CODE (type) == RECORD_TYPE || TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == QUAL_UNION_TYPE) { if (COMPLETE_TYPE_P (type) /* not a forward reference */ && KNOWN_TYPE_TAG (type) == 0) /* not yet declared */ sdbout_one_type (type); } /* Defer SDB information for top-level initialized variables! */ if (! local && MEM_P (value) && DECL_INITIAL (decl)) return; /* C++ in 2.3 makes nameless symbols. That will be fixed later. For now, avoid crashing. */ if (DECL_NAME (decl) == NULL_TREE) return; /* Record the name for, starting a symtab entry. */ if (local) name = IDENTIFIER_POINTER (DECL_NAME (decl)); else name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)); if (MEM_P (value) && GET_CODE (XEXP (value, 0)) == SYMBOL_REF) { PUT_SDB_DEF (name); if (TREE_PUBLIC (decl)) { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_EXT); } else { PUT_SDB_VAL (XEXP (value, 0)); PUT_SDB_SCL (C_STAT); } } else if (regno >= 0) { PUT_SDB_DEF (name); PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (regno)); PUT_SDB_SCL (C_REG); } else if (MEM_P (value) && (MEM_P (XEXP (value, 0)) || (REG_P (XEXP (value, 0)) && REGNO (XEXP (value, 0)) != HARD_FRAME_POINTER_REGNUM && REGNO (XEXP (value, 0)) != STACK_POINTER_REGNUM))) /* If the value is indirect by memory or by a register that isn't the frame pointer then it means the object is variable-sized and address through that register or stack slot. COFF has no way to represent this so all we can do is output the variable as a pointer. */ { PUT_SDB_DEF (name); if (REG_P (XEXP (value, 0))) { PUT_SDB_INT_VAL (DBX_REGISTER_NUMBER (REGNO (XEXP (value, 0)))); PUT_SDB_SCL (C_REG); } else { /* DECL_RTL looks like (MEM (MEM (PLUS (REG...) (CONST_INT...)))). We want the value of that CONST_INT. */ /* Encore compiler hates a newline in a macro arg, it seems. */ PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET (XEXP (XEXP (value, 0), 0))); PUT_SDB_SCL (C_AUTO); } /* Effectively do build_pointer_type, but don't cache this type, since it might be temporary whereas the type it points to might have been saved for inlining. */ /* Don't use REFERENCE_TYPE because dbx can't handle that. */ type = make_node (POINTER_TYPE); TREE_TYPE (type) = TREE_TYPE (decl); } else if (MEM_P (value) && ((GET_CODE (XEXP (value, 0)) == PLUS && REG_P (XEXP (XEXP (value, 0), 0)) && CONST_INT_P (XEXP (XEXP (value, 0), 1))) /* This is for variables which are at offset zero from the frame pointer. This happens on the Alpha. Non-frame pointer registers are excluded above. */ || (REG_P (XEXP (value, 0))))) { /* DECL_RTL looks like (MEM (PLUS (REG...) (CONST_INT...))) or (MEM (REG...)). We want the value of that CONST_INT or zero. */ PUT_SDB_DEF (name); PUT_SDB_INT_VAL (DEBUGGER_AUTO_OFFSET (XEXP (value, 0))); PUT_SDB_SCL (C_AUTO); } else { /* It is something we don't know how to represent for SDB. */ return; } break; default: break; } PUT_SDB_TYPE (plain_type (type)); PUT_SDB_ENDEF; }
static void varpool_remove_unreferenced_decls (void) { struct varpool_node *next, *node; struct varpool_node *first = (struct varpool_node *)(void *)1; int i; struct ipa_ref *ref; if (seen_error ()) return; if (cgraph_dump_file) fprintf (cgraph_dump_file, "Trivially needed variables:"); FOR_EACH_DEFINED_VARIABLE (node) { if (node->analyzed && (!varpool_can_remove_if_no_refs (node) /* We just expanded all function bodies. See if any of them needed the variable. */ || (!DECL_EXTERNAL (node->symbol.decl) && DECL_RTL_SET_P (node->symbol.decl)))) { enqueue_node (node, &first); if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); } } while (first != (struct varpool_node *)(void *)1) { node = first; first = (struct varpool_node *)first->symbol.aux; if (node->symbol.same_comdat_group) { symtab_node next; for (next = node->symbol.same_comdat_group; next != (symtab_node)node; next = next->symbol.same_comdat_group) { varpool_node *vnext = dyn_cast <varpool_node> (next); if (vnext && vnext->analyzed) enqueue_node (vnext, &first); } } for (i = 0; ipa_ref_list_reference_iterate (&node->symbol.ref_list, i, ref); i++) { varpool_node *vnode = dyn_cast <varpool_node> (ref->referred); if (vnode && (!DECL_EXTERNAL (ref->referred->symbol.decl) || vnode->alias) && vnode->analyzed) enqueue_node (vnode, &first); } } if (cgraph_dump_file) fprintf (cgraph_dump_file, "\nRemoving variables:"); for (node = varpool_first_defined_variable (); node; node = next) { next = varpool_next_defined_variable (node); if (!node->symbol.aux) { if (cgraph_dump_file) fprintf (cgraph_dump_file, " %s", varpool_node_asm_name (node)); varpool_remove_node (node); } } if (cgraph_dump_file) fprintf (cgraph_dump_file, "\n"); }