static void unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { DECL_DEFER_OUTPUT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2); DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) == VAR_DECL) { DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_TEXT_SECTION (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_TLS_MODEL (expr) = (enum tls_model) bp_unpack_value (bp, 3); } if (VAR_OR_FUNCTION_DECL_P (expr)) { priority_type p; p = (priority_type) bp_unpack_var_len_unsigned (bp); SET_DECL_INIT_PRIORITY (expr, p); } }
static void pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { bp_pack_value (bp, DECL_COMMON (expr), 1); bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1); bp_pack_value (bp, DECL_WEAK (expr), 1); bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1); bp_pack_value (bp, DECL_COMDAT (expr), 1); bp_pack_value (bp, DECL_VISIBILITY (expr), 2); bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1); if (TREE_CODE (expr) == VAR_DECL) { bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1); /* DECL_IN_TEXT_SECTION is set during final asm output only. */ bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1); } if (TREE_CODE (expr) == FUNCTION_DECL) { bp_pack_value (bp, DECL_FINAL_P (expr), 1); bp_pack_value (bp, DECL_CXX_CONSTRUCTOR_P (expr), 1); bp_pack_value (bp, DECL_CXX_DESTRUCTOR_P (expr), 1); } }
void symtab_node::unregister (void) { remove_all_references (); remove_all_referring (); /* Remove reference to section. */ set_section_for_node (NULL); remove_from_same_comdat_group (); symtab->unregister (this); /* During LTO symtab merging we temporarily corrupt decl to symtab node hash. */ gcc_assert (decl->decl_with_vis.symtab_node || in_lto_p); if (decl->decl_with_vis.symtab_node == this) { symtab_node *replacement_node = NULL; if (cgraph_node *cnode = dyn_cast <cgraph_node *> (this)) replacement_node = cnode->find_replacement (); decl->decl_with_vis.symtab_node = replacement_node; } if (!is_a <varpool_node *> (this) || !DECL_HARD_REGISTER (decl)) symtab->unlink_from_assembler_name_hash (this, false); if (in_init_priority_hash) symtab->init_priority_hash->remove (this); }
static void insert_to_assembler_name_hash (symtab_node node, bool with_clones) { if (is_a <varpool_node> (node) && DECL_HARD_REGISTER (node->symbol.decl)) return; gcc_checking_assert (!node->symbol.previous_sharing_asm_name && !node->symbol.next_sharing_asm_name); if (assembler_name_hash) { void **aslot; struct cgraph_node *cnode; tree decl = node->symbol.decl; tree name = DECL_ASSEMBLER_NAME (node->symbol.decl); aslot = htab_find_slot_with_hash (assembler_name_hash, name, decl_assembler_name_hash (name), INSERT); gcc_assert (*aslot != node); node->symbol.next_sharing_asm_name = (symtab_node)*aslot; if (*aslot != NULL) ((symtab_node)*aslot)->symbol.previous_sharing_asm_name = node; *aslot = node; /* Update also possible inline clones sharing a decl. */ cnode = dyn_cast <cgraph_node> (node); if (cnode && cnode->clones && with_clones) for (cnode = cnode->clones; cnode; cnode = cnode->next_sibling_clone) if (cnode->symbol.decl == decl) insert_to_assembler_name_hash ((symtab_node) cnode, true); } }
bool may_propagate_copy_into_asm (tree dest) { /* Hard register operands of asms are special. Do not bypass. */ return !(TREE_CODE (dest) == SSA_NAME && TREE_CODE (SSA_NAME_VAR (dest)) == VAR_DECL && DECL_HARD_REGISTER (SSA_NAME_VAR (dest))); }
bool is_gimple_asm_val (tree t) { if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) return true; return is_gimple_val (t); }
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); } }
bool is_gimple_reg (tree t) { var_ann_t ann; if (TREE_CODE (t) == SSA_NAME) t = SSA_NAME_VAR (t); if (!is_gimple_variable (t)) return false; if (!is_gimple_reg_type (TREE_TYPE (t))) return false; /* A volatile decl is not acceptable because we can't reuse it as needed. We need to copy it into a temp first. */ if (TREE_THIS_VOLATILE (t)) return false; /* We define "registers" as things that can be renamed as needed, which with our infrastructure does not apply to memory. */ if (needs_to_live_in_memory (t)) return false; /* Hard register variables are an interesting case. For those that are call-clobbered, we don't know where all the calls are, since we don't (want to) take into account which operations will turn into libcalls at the rtl level. For those that are call-saved, we don't currently model the fact that calls may in fact change global hard registers, nor do we examine ASM_CLOBBERS at the tree level, and so miss variable changes that might imply. All around, it seems safest to not do too much optimization with these at the tree level at all. We'll have to rely on the rtl optimizers to clean this up, as there we've got all the appropriate bits exposed. */ if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) return false; /* Complex values must have been put into ssa form. That is, no assignments to the individual components. */ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE) return DECL_COMPLEX_GIMPLE_REG_P (t); /* Some compiler temporaries are created to be used exclusively in virtual operands (currently memory tags and sub-variables). These variables should never be considered GIMPLE registers. */ if (DECL_ARTIFICIAL (t) && (ann = var_ann (t)) != NULL) return ann->mem_tag_kind == NOT_A_TAG; return true; }
void symtab_unregister_node (symtab_node *node) { void **slot; ipa_remove_all_references (&node->ref_list); ipa_remove_all_referring (&node->ref_list); if (node->same_comdat_group) { symtab_node *prev; for (prev = node->same_comdat_group; prev->same_comdat_group != node; prev = prev->same_comdat_group) ; if (node->same_comdat_group == prev) prev->same_comdat_group = NULL; else prev->same_comdat_group = node->same_comdat_group; node->same_comdat_group = NULL; } if (node->previous) node->previous->next = node->next; else symtab_nodes = node->next; if (node->next) node->next->previous = node->previous; node->next = NULL; node->previous = NULL; slot = htab_find_slot (symtab_hash, node, NO_INSERT); /* During LTO symtab merging we temporarily corrupt decl to symtab node hash. */ gcc_assert ((slot && *slot) || in_lto_p); if (slot && *slot && *slot == node) { symtab_node *replacement_node = NULL; if (cgraph_node *cnode = dyn_cast <cgraph_node> (node)) replacement_node = cgraph_find_replacement_node (cnode); if (!replacement_node) htab_clear_slot (symtab_hash, slot); else *slot = replacement_node; } if (!is_a <varpool_node> (node) || !DECL_HARD_REGISTER (node->decl)) unlink_from_assembler_name_hash (node, false); }
bool is_gimple_reg (tree t) { if (virtual_operand_p (t)) return false; if (TREE_CODE (t) == SSA_NAME) return true; if (!is_gimple_variable (t)) return false; if (!is_gimple_reg_type (TREE_TYPE (t))) return false; /* A volatile decl is not acceptable because we can't reuse it as needed. We need to copy it into a temp first. */ if (TREE_THIS_VOLATILE (t)) return false; /* We define "registers" as things that can be renamed as needed, which with our infrastructure does not apply to memory. */ if (needs_to_live_in_memory (t)) return false; /* Hard register variables are an interesting case. For those that are call-clobbered, we don't know where all the calls are, since we don't (want to) take into account which operations will turn into libcalls at the rtl level. For those that are call-saved, we don't currently model the fact that calls may in fact change global hard registers, nor do we examine ASM_CLOBBERS at the tree level, and so miss variable changes that might imply. All around, it seems safest to not do too much optimization with these at the tree level at all. We'll have to rely on the rtl optimizers to clean this up, as there we've got all the appropriate bits exposed. */ if (TREE_CODE (t) == VAR_DECL && DECL_HARD_REGISTER (t)) return false; /* Complex and vector values must have been put into SSA-like form. That is, no assignments to the individual components. */ if (TREE_CODE (TREE_TYPE (t)) == COMPLEX_TYPE || TREE_CODE (TREE_TYPE (t)) == VECTOR_TYPE) return DECL_GIMPLE_REG_P (t); return true; }
bool varpool_assemble_decl (varpool_node *node) { tree decl = node->decl; /* Aliases are outout when their target is produced or by output_weakrefs. */ if (node->alias) return false; /* Constant pool is output from RTL land when the reference survive till this level. */ if (DECL_IN_CONSTANT_POOL (decl) && TREE_ASM_WRITTEN (decl)) return false; /* Decls with VALUE_EXPR should not be in the varpool at all. They are not real variables, but just info for debugging and codegen. Unfortunately at the moment emutls is not updating varpool correctly after turning real vars into value_expr vars. */ if (DECL_HAS_VALUE_EXPR_P (decl) && !targetm.have_tls) return false; /* Hard register vars do not need to be output. */ if (DECL_HARD_REGISTER (decl)) return false; gcc_checking_assert (!TREE_ASM_WRITTEN (decl) && TREE_CODE (decl) == VAR_DECL && !DECL_HAS_VALUE_EXPR_P (decl)); if (!node->in_other_partition && !DECL_EXTERNAL (decl)) { assemble_variable (decl, 0, 1, 0); gcc_assert (TREE_ASM_WRITTEN (decl)); node->definition = true; assemble_aliases (node); return true; } return false; }
static bool wrapper_parm_cb (const void *key0, void **val0, void *data) { struct wrapper_data *wd = (struct wrapper_data *) data; tree arg = * (tree *)&key0; tree val = (tree)*val0; tree parm; if (val == error_mark_node || val == arg) return true; if (TREE_CODE (val) == PAREN_EXPR) { /* We should not reach here with a register receiver. We may see a register variable modified in the argument list. Because register variables are worker-local we don't need to work hard to support them in code that spawns. */ if ((TREE_CODE (arg) == VAR_DECL) && DECL_HARD_REGISTER (arg)) { error_at (EXPR_LOCATION (arg), "explicit register variable %qD may not be modified in " "spawn", arg); arg = null_pointer_node; } else arg = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (arg)), arg); val = TREE_OPERAND (val, 0); *val0 = val; gcc_assert (TREE_CODE (val) == INDIRECT_REF); parm = TREE_OPERAND (val, 0); STRIP_NOPS (parm); } else parm = val; TREE_CHAIN (parm) = wd->parms; wd->parms = parm; wd->argtypes = tree_cons (NULL_TREE, TREE_TYPE (parm), wd->argtypes); wd->arglist = tree_cons (NULL_TREE, arg, wd->arglist); return true; }
static void pack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { bp_pack_value (bp, DECL_DEFER_OUTPUT (expr), 1); bp_pack_value (bp, DECL_COMMON (expr), 1); bp_pack_value (bp, DECL_DLLIMPORT_P (expr), 1); bp_pack_value (bp, DECL_WEAK (expr), 1); bp_pack_value (bp, DECL_SEEN_IN_BIND_EXPR_P (expr), 1); bp_pack_value (bp, DECL_COMDAT (expr), 1); bp_pack_value (bp, DECL_VISIBILITY (expr), 2); bp_pack_value (bp, DECL_VISIBILITY_SPECIFIED (expr), 1); if (TREE_CODE (expr) == VAR_DECL) { bp_pack_value (bp, DECL_HARD_REGISTER (expr), 1); bp_pack_value (bp, DECL_IN_TEXT_SECTION (expr), 1); bp_pack_value (bp, DECL_IN_CONSTANT_POOL (expr), 1); bp_pack_value (bp, DECL_TLS_MODEL (expr), 3); } if (VAR_OR_FUNCTION_DECL_P (expr)) bp_pack_var_len_unsigned (bp, DECL_INIT_PRIORITY (expr)); }
static void unpack_ts_decl_with_vis_value_fields (struct bitpack_d *bp, tree expr) { DECL_COMMON (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_DLLIMPORT_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_WEAK (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_SEEN_IN_BIND_EXPR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_COMDAT (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_VISIBILITY (expr) = (enum symbol_visibility) bp_unpack_value (bp, 2); DECL_VISIBILITY_SPECIFIED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) == VAR_DECL) { DECL_HARD_REGISTER (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_IN_CONSTANT_POOL (expr) = (unsigned) bp_unpack_value (bp, 1); } if (TREE_CODE (expr) == FUNCTION_DECL) { DECL_FINAL_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_CXX_CONSTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1); DECL_CXX_DESTRUCTOR_P (expr) = (unsigned) bp_unpack_value (bp, 1); } }
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); }
static void instrument_bool_enum_load (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); tree rhs = gimple_assign_rhs1 (stmt); tree type = TREE_TYPE (rhs); tree minv = NULL_TREE, maxv = NULL_TREE; if (TREE_CODE (type) == BOOLEAN_TYPE && (flag_sanitize & SANITIZE_BOOL)) { minv = boolean_false_node; maxv = boolean_true_node; } else if (TREE_CODE (type) == ENUMERAL_TYPE && (flag_sanitize & SANITIZE_ENUM) && TREE_TYPE (type) != NULL_TREE && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE && (TYPE_PRECISION (TREE_TYPE (type)) < GET_MODE_PRECISION (TYPE_MODE (type)))) { minv = TYPE_MIN_VALUE (TREE_TYPE (type)); maxv = TYPE_MAX_VALUE (TREE_TYPE (type)); } else return; int modebitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); HOST_WIDE_INT bitsize, bitpos; tree offset; enum machine_mode mode; int volatilep = 0, unsignedp = 0; tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode, &unsignedp, &volatilep, false); tree utype = build_nonstandard_integer_type (modebitsize, 1); if ((TREE_CODE (base) == VAR_DECL && DECL_HARD_REGISTER (base)) || (bitpos % modebitsize) != 0 || bitsize != modebitsize || GET_MODE_BITSIZE (TYPE_MODE (utype)) != modebitsize || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME) return; location_t loc = gimple_location (stmt); tree ptype = build_pointer_type (TREE_TYPE (rhs)); tree atype = reference_alias_ptr_type (rhs); gimple g = gimple_build_assign (make_ssa_name (ptype, NULL), build_fold_addr_expr (rhs)); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g), build_int_cst (atype, 0)); tree urhs = make_ssa_name (utype, NULL); g = gimple_build_assign (urhs, mem); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); minv = fold_convert (utype, minv); maxv = fold_convert (utype, maxv); if (!integer_zerop (minv)) { g = gimple_build_assign_with_ops (MINUS_EXPR, make_ssa_name (utype, NULL), urhs, minv); gimple_set_location (g, loc); gsi_insert_before (gsi, g, GSI_SAME_STMT); } gimple_stmt_iterator gsi2 = *gsi; basic_block then_bb, fallthru_bb; *gsi = create_cond_insert_point (gsi, true, false, true, &then_bb, &fallthru_bb); g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g), int_const_binop (MINUS_EXPR, maxv, minv), NULL_TREE, NULL_TREE); gimple_set_location (g, loc); gsi_insert_after (gsi, g, GSI_NEW_STMT); gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs, NULL_TREE); update_stmt (stmt); gsi2 = gsi_after_labels (then_bb); if (flag_sanitize_undefined_trap_on_error) g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0); else { tree data = ubsan_create_data ("__ubsan_invalid_value_data", &loc, NULL, ubsan_type_descriptor (type), NULL_TREE); data = build_fold_addr_expr_loc (loc, data); enum built_in_function bcode = flag_sanitize_recover ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT; tree fn = builtin_decl_explicit (bcode); tree val = force_gimple_operand_gsi (&gsi2, ubsan_encode_value (urhs), true, NULL_TREE, true, GSI_SAME_STMT); g = gimple_build_call (fn, 2, data, val); } gimple_set_location (g, loc); gsi_insert_before (&gsi2, g, GSI_SAME_STMT); }
DEBUG_FUNCTION bool symtab_node::verify_base (void) { bool error_found = false; symtab_node *hashed_node; if (is_a <cgraph_node *> (this)) { if (TREE_CODE (decl) != FUNCTION_DECL) { error ("function symbol is not function"); error_found = true; } } else if (is_a <varpool_node *> (this)) { if (TREE_CODE (decl) != VAR_DECL) { error ("variable symbol is not variable"); error_found = true; } } else { error ("node has unknown type"); error_found = true; } if (symtab->state != LTO_STREAMING) { hashed_node = symtab_node::get (decl); if (!hashed_node) { error ("node not found node->decl->decl_with_vis.symtab_node"); error_found = true; } if (hashed_node != this && (!is_a <cgraph_node *> (this) || !dyn_cast <cgraph_node *> (this)->clone_of || dyn_cast <cgraph_node *> (this)->clone_of->decl != decl)) { error ("node differs from node->decl->decl_with_vis.symtab_node"); error_found = true; } } if (symtab->assembler_name_hash) { hashed_node = symtab_node::get_for_asmname (DECL_ASSEMBLER_NAME (decl)); if (hashed_node && hashed_node->previous_sharing_asm_name) { error ("assembler name hash list corrupted"); error_found = true; } while (hashed_node) { if (hashed_node == this) break; hashed_node = hashed_node->next_sharing_asm_name; } if (!hashed_node && !(is_a <varpool_node *> (this) || DECL_HARD_REGISTER (decl))) { error ("node not found in symtab assembler name hash"); error_found = true; } } if (previous_sharing_asm_name && previous_sharing_asm_name->next_sharing_asm_name != this) { error ("double linked list of assembler names corrupted"); error_found = true; } if (analyzed && !definition) { error ("node is analyzed byt it is not a definition"); error_found = true; } if (cpp_implicit_alias && !alias) { error ("node is alias but not implicit alias"); error_found = true; } if (alias && !definition && !weakref) { error ("node is alias but not definition"); error_found = true; } if (weakref && !alias) { error ("node is weakref but not an alias"); error_found = true; } if (same_comdat_group) { symtab_node *n = same_comdat_group; if (!n->get_comdat_group ()) { error ("node is in same_comdat_group list but has no comdat_group"); error_found = true; } if (n->get_comdat_group () != get_comdat_group ()) { error ("same_comdat_group list across different groups"); error_found = true; } if (!n->definition) { error ("Node has same_comdat_group but it is not a definition"); error_found = true; } if (n->type != type) { error ("mixing different types of symbol in same comdat groups is not supported"); error_found = true; } if (n == this) { error ("node is alone in a comdat group"); error_found = true; } do { if (!n->same_comdat_group) { error ("same_comdat_group is not a circular list"); error_found = true; break; } n = n->same_comdat_group; } while (n != this); if (comdat_local_p ()) { ipa_ref *ref = NULL; for (int i = 0; iterate_referring (i, ref); ++i) { if (!in_same_comdat_group_p (ref->referring)) { error ("comdat-local symbol referred to by %s outside its " "comdat", identifier_to_locale (ref->referring->name())); error_found = true; } } } } if (implicit_section && !get_section ()) { error ("implicit_section flag is set but section isn't"); error_found = true; } if (get_section () && get_comdat_group () && !implicit_section) { error ("Both section and comdat group is set"); error_found = true; } /* TODO: Add string table for sections, so we do not keep holding duplicated strings. */ if (alias && definition && get_section () != get_alias_target ()->get_section () && (!get_section() || !get_alias_target ()->get_section () || strcmp (get_section(), get_alias_target ()->get_section ()))) { error ("Alias and target's section differs"); get_alias_target ()->dump (stderr); error_found = true; } if (alias && definition && get_comdat_group () != get_alias_target ()->get_comdat_group ()) { error ("Alias and target's comdat groups differs"); get_alias_target ()->dump (stderr); error_found = true; } return error_found; }
void lto_symtab_merge_symbols (void) { symtab_node *node; if (!flag_ltrans) { symtab->symtab_initialize_asm_name_hash (); /* Do the actual merging. At this point we invalidate hash translating decls into symtab nodes because after removing one of duplicate decls the hash is not correcly updated to the ohter dupliate. */ FOR_EACH_SYMBOL (node) if (lto_symtab_symbol_p (node) && node->next_sharing_asm_name && !node->previous_sharing_asm_name) lto_symtab_merge_symbols_1 (node); /* Resolve weakref aliases whose target are now in the compilation unit. also re-populate the hash translating decls into symtab nodes*/ FOR_EACH_SYMBOL (node) { cgraph_node *cnode, *cnode2; varpool_node *vnode; symtab_node *node2; if (!node->analyzed && node->alias_target) { symtab_node *tgt = symtab_node::get_for_asmname (node->alias_target); gcc_assert (node->weakref); if (tgt) node->resolve_alias (tgt, true); } /* If the symbol was preempted outside IR, see if we want to get rid of the definition. */ if (node->analyzed && !DECL_EXTERNAL (node->decl) && (node->resolution == LDPR_PREEMPTED_REG || node->resolution == LDPR_RESOLVED_IR || node->resolution == LDPR_RESOLVED_EXEC || node->resolution == LDPR_RESOLVED_DYN)) { DECL_EXTERNAL (node->decl) = 1; /* If alias to local symbol was preempted by external definition, we know it is not pointing to the local symbol. Remove it. */ if (node->alias && !node->weakref && !node->transparent_alias && node->get_alias_target ()->binds_to_current_def_p ()) { node->alias = false; node->remove_all_references (); node->definition = false; node->analyzed = false; node->cpp_implicit_alias = false; } else if (!node->alias && node->definition && node->get_availability () <= AVAIL_INTERPOSABLE) { if ((cnode = dyn_cast <cgraph_node *> (node)) != NULL) cnode->reset (); else { node->analyzed = node->definition = false; node->remove_all_references (); } } } if (!(cnode = dyn_cast <cgraph_node *> (node)) || !cnode->clone_of || cnode->clone_of->decl != cnode->decl) { /* Builtins are not merged via decl merging. It is however possible that tree merging unified the declaration. We do not want duplicate entries in symbol table. */ if (cnode && DECL_BUILT_IN (node->decl) && (cnode2 = cgraph_node::get (node->decl)) && cnode2 != cnode) lto_cgraph_replace_node (cnode2, cnode); /* The user defined assembler variables are also not unified by their symbol name (since it is irrelevant), but we need to unify symbol nodes if tree merging occurred. */ if ((vnode = dyn_cast <varpool_node *> (node)) && DECL_HARD_REGISTER (vnode->decl) && (node2 = symtab_node::get (vnode->decl)) && node2 != node) lto_varpool_replace_node (dyn_cast <varpool_node *> (node2), vnode); /* Abstract functions may have duplicated cgraph nodes attached; remove them. */ else if (cnode && DECL_ABSTRACT_P (cnode->decl) && (cnode2 = cgraph_node::get (node->decl)) && cnode2 != cnode) cnode2->remove (); node->decl->decl_with_vis.symtab_node = node; } } }
DEBUG_FUNCTION bool verify_symtab_base (symtab_node node) { bool error_found = false; symtab_node hashed_node; if (is_a <cgraph_node> (node)) { if (TREE_CODE (node->symbol.decl) != FUNCTION_DECL) { error ("function symbol is not function"); error_found = true; } } else if (is_a <varpool_node> (node)) { if (TREE_CODE (node->symbol.decl) != VAR_DECL) { error ("variable symbol is not variable"); error_found = true; } } else { error ("node has unknown type"); error_found = true; } if (cgraph_state != CGRAPH_LTO_STREAMING) { hashed_node = symtab_get_node (node->symbol.decl); if (!hashed_node) { error ("node not found in symtab decl hashtable"); error_found = true; } if (hashed_node != node && (!is_a <cgraph_node> (node) || !dyn_cast <cgraph_node> (node)->clone_of || dyn_cast <cgraph_node> (node)->clone_of->symbol.decl != node->symbol.decl)) { error ("node differs from symtab decl hashtable"); error_found = true; } } if (assembler_name_hash) { hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->symbol.decl)); if (hashed_node && hashed_node->symbol.previous_sharing_asm_name) { error ("assembler name hash list corrupted"); error_found = true; } while (hashed_node) { if (hashed_node == node) break; hashed_node = hashed_node->symbol.next_sharing_asm_name; } if (!hashed_node && !(is_a <varpool_node> (node) || DECL_HARD_REGISTER (node->symbol.decl))) { error ("node not found in symtab assembler name hash"); error_found = true; } } if (node->symbol.previous_sharing_asm_name && node->symbol.previous_sharing_asm_name->symbol.next_sharing_asm_name != node) { error ("double linked list of assembler names corrupted"); error_found = true; } if (node->symbol.analyzed && !node->symbol.definition) { error ("node is analyzed byt it is not a definition"); error_found = true; } if (node->symbol.cpp_implicit_alias && !node->symbol.alias) { error ("node is alias but not implicit alias"); error_found = true; } if (node->symbol.alias && !node->symbol.definition && !node->symbol.weakref) { error ("node is alias but not definition"); error_found = true; } if (node->symbol.weakref && !node->symbol.alias) { error ("node is weakref but not an alias"); error_found = true; } if (node->symbol.same_comdat_group) { symtab_node n = node->symbol.same_comdat_group; if (!DECL_ONE_ONLY (n->symbol.decl)) { error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); error_found = true; } if (n->symbol.type != node->symbol.type) { error ("mixing different types of symbol in same comdat groups is not supported"); error_found = true; } if (n == node) { error ("node is alone in a comdat group"); error_found = true; } do { if (!n->symbol.same_comdat_group) { error ("same_comdat_group is not a circular list"); error_found = true; break; } n = n->symbol.same_comdat_group; } while (n != node); } return error_found; }
static inline bool is_replaceable_p (gimple stmt) { use_operand_p use_p; tree def; gimple use_stmt; location_t locus1, locus2; tree block1, block2; /* Only consider modify stmts. */ if (!is_gimple_assign (stmt)) return false; /* If the statement may throw an exception, it cannot be replaced. */ if (stmt_could_throw_p (stmt)) return false; /* Punt if there is more than 1 def. */ def = SINGLE_SSA_TREE_OPERAND (stmt, SSA_OP_DEF); if (!def) return false; /* Only consider definitions which have a single use. */ if (!single_imm_use (def, &use_p, &use_stmt)) return false; /* If the use isn't in this block, it wont be replaced either. */ if (gimple_bb (use_stmt) != gimple_bb (stmt)) return false; locus1 = gimple_location (stmt); block1 = gimple_block (stmt); if (gimple_code (use_stmt) == GIMPLE_PHI) { locus2 = 0; block2 = NULL_TREE; } else { locus2 = gimple_location (use_stmt); block2 = gimple_block (use_stmt); } if (!optimize && ((locus1 && locus1 != locus2) || (block1 && block1 != block2))) return false; /* Used in this block, but at the TOP of the block, not the end. */ if (gimple_code (use_stmt) == GIMPLE_PHI) return false; /* There must be no VDEFs. */ if (!(ZERO_SSA_OPERANDS (stmt, SSA_OP_VDEF))) return false; /* Without alias info we can't move around loads. */ if (gimple_references_memory_p (stmt) && !optimize) return false; /* Float expressions must go through memory if float-store is on. */ if (flag_float_store && FLOAT_TYPE_P (gimple_expr_type (stmt))) return false; /* An assignment with a register variable on the RHS is not replaceable. */ if (gimple_assign_rhs_code (stmt) == VAR_DECL && DECL_HARD_REGISTER (gimple_assign_rhs1 (stmt))) return false; /* No function calls can be replaced. */ if (is_gimple_call (stmt)) return false; /* Leave any stmt with volatile operands alone as well. */ if (gimple_has_volatile_ops (stmt)) return false; return true; }
DEBUG_FUNCTION bool verify_symtab_base (symtab_node *node) { bool error_found = false; symtab_node *hashed_node; if (is_a <cgraph_node> (node)) { if (TREE_CODE (node->decl) != FUNCTION_DECL) { error ("function symbol is not function"); error_found = true; } } else if (is_a <varpool_node> (node)) { if (TREE_CODE (node->decl) != VAR_DECL) { error ("variable symbol is not variable"); error_found = true; } } else { error ("node has unknown type"); error_found = true; } if (cgraph_state != CGRAPH_LTO_STREAMING) { hashed_node = symtab_get_node (node->decl); if (!hashed_node) { error ("node not found in symtab decl hashtable"); error_found = true; } if (hashed_node != node && (!is_a <cgraph_node> (node) || !dyn_cast <cgraph_node> (node)->clone_of || dyn_cast <cgraph_node> (node)->clone_of->decl != node->decl)) { error ("node differs from symtab decl hashtable"); error_found = true; } } if (assembler_name_hash) { hashed_node = symtab_node_for_asm (DECL_ASSEMBLER_NAME (node->decl)); if (hashed_node && hashed_node->previous_sharing_asm_name) { error ("assembler name hash list corrupted"); error_found = true; } while (hashed_node) { if (hashed_node == node) break; hashed_node = hashed_node->next_sharing_asm_name; } if (!hashed_node && !(is_a <varpool_node> (node) || DECL_HARD_REGISTER (node->decl))) { error ("node not found in symtab assembler name hash"); error_found = true; } } if (node->previous_sharing_asm_name && node->previous_sharing_asm_name->next_sharing_asm_name != node) { error ("double linked list of assembler names corrupted"); error_found = true; } if (node->analyzed && !node->definition) { error ("node is analyzed byt it is not a definition"); error_found = true; } if (node->cpp_implicit_alias && !node->alias) { error ("node is alias but not implicit alias"); error_found = true; } if (node->alias && !node->definition && !node->weakref) { error ("node is alias but not definition"); error_found = true; } if (node->weakref && !node->alias) { error ("node is weakref but not an alias"); error_found = true; } if (node->same_comdat_group) { symtab_node *n = node->same_comdat_group; if (!DECL_ONE_ONLY (n->decl)) { error ("non-DECL_ONE_ONLY node in a same_comdat_group list"); error_found = true; } if (n->type != node->type) { error ("mixing different types of symbol in same comdat groups is not supported"); error_found = true; } if (n == node) { error ("node is alone in a comdat group"); error_found = true; } do { if (!n->same_comdat_group) { error ("same_comdat_group is not a circular list"); error_found = true; break; } n = n->same_comdat_group; } while (n != node); if (symtab_comdat_local_p (node)) { struct ipa_ref_list *refs = &node->ref_list; struct ipa_ref *ref; for (int i = 0; ipa_ref_list_referring_iterate (refs, i, ref); ++i) { if (!symtab_in_same_comdat_p (ref->referring, node)) { error ("comdat-local symbol referred to by %s outside its " "comdat", identifier_to_locale (ref->referring->name())); error_found = true; } } } } return error_found; }