void mark_addressable (tree x) { while (handled_component_p (x)) x = TREE_OPERAND (x, 0); if (TREE_CODE (x) == MEM_REF && TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); if (TREE_CODE (x) != VAR_DECL && TREE_CODE (x) != PARM_DECL && TREE_CODE (x) != RESULT_DECL) return; TREE_ADDRESSABLE (x) = 1; /* Also mark the artificial SSA_NAME that points to the partition of X. */ if (TREE_CODE (x) == VAR_DECL && !DECL_EXTERNAL (x) && !TREE_STATIC (x) && cfun->gimple_df != NULL && cfun->gimple_df->decls_to_pointers != NULL) { tree *namep = cfun->gimple_df->decls_to_pointers->get (x); if (namep) TREE_ADDRESSABLE (*namep) = 1; } }
bool java_mark_addressable (tree exp) { tree x = exp; while (1) switch (TREE_CODE (x)) { case ADDR_EXPR: case COMPONENT_REF: case ARRAY_REF: case REALPART_EXPR: case IMAGPART_EXPR: x = TREE_OPERAND (x, 0); break; case TRUTH_ANDIF_EXPR: case TRUTH_ORIF_EXPR: case COMPOUND_EXPR: x = TREE_OPERAND (x, 1); break; case COND_EXPR: return java_mark_addressable (TREE_OPERAND (x, 1)) && java_mark_addressable (TREE_OPERAND (x, 2)); case CONSTRUCTOR: TREE_ADDRESSABLE (x) = 1; return true; case INDIRECT_REF: /* We sometimes add a cast *(TYPE*)&FOO to handle type and mode incompatibility problems. Handle this case by marking FOO. */ if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR && TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR) { x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); break; } if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) { x = TREE_OPERAND (x, 0); break; } return true; case VAR_DECL: case CONST_DECL: case PARM_DECL: case RESULT_DECL: case FUNCTION_DECL: TREE_ADDRESSABLE (x) = 1; #if 0 /* poplevel deals with this now. */ if (DECL_CONTEXT (x) == 0) TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; #endif /* drops through */ default: return true; } }
void cp_genericize (tree fndecl) { tree t; struct pointer_set_t *p_set; /* Fix up the types of parms passed by invisible reference. */ for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t)) if (TREE_ADDRESSABLE (TREE_TYPE (t))) { /* If a function's arguments are copied to create a thunk, then DECL_BY_REFERENCE will be set -- but the type of the argument will be a pointer type, so we will never get here. */ gcc_assert (!DECL_BY_REFERENCE (t)); gcc_assert (DECL_ARG_TYPE (t) != TREE_TYPE (t)); TREE_TYPE (t) = DECL_ARG_TYPE (t); DECL_BY_REFERENCE (t) = 1; TREE_ADDRESSABLE (t) = 0; relayout_decl (t); } /* Do the same for the return value. */ if (TREE_ADDRESSABLE (TREE_TYPE (DECL_RESULT (fndecl)))) { t = DECL_RESULT (fndecl); TREE_TYPE (t) = build_reference_type (TREE_TYPE (t)); DECL_BY_REFERENCE (t) = 1; TREE_ADDRESSABLE (t) = 0; relayout_decl (t); } /* If we're a clone, the body is already GIMPLE. */ if (DECL_CLONED_FUNCTION_P (fndecl)) return; /* We do want to see every occurrence of the parms, so we can't just use walk_tree's hash functionality. */ p_set = pointer_set_create (); cp_walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, p_set, NULL); pointer_set_destroy (p_set); /* Do everything else. */ c_genericize (fndecl); gcc_assert (bc_label[bc_break] == NULL); gcc_assert (bc_label[bc_continue] == NULL); }
tree make_alias_for (tree function, tree newid) { tree alias = build_decl (FUNCTION_DECL, newid, TREE_TYPE (function)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); cxx_dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL; TREE_READONLY (alias) = TREE_READONLY (function); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); TREE_PUBLIC (alias) = 0; DECL_INTERFACE_KNOWN (alias) = 1; DECL_NOT_REALLY_EXTERN (alias) = 1; DECL_THIS_STATIC (alias) = 1; DECL_SAVED_FUNCTION_DATA (alias) = NULL; DECL_DESTRUCTOR_P (alias) = 0; DECL_CONSTRUCTOR_P (alias) = 0; DECL_CLONED_FUNCTION (alias) = NULL_TREE; DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_NO_STATIC_CHAIN (alias) = 1; DECL_PENDING_INLINE_P (alias) = 0; DECL_INLINE (alias) = 0; DECL_DECLARED_INLINE_P (alias) = 0; DECL_DEFERRED_FN (alias) = 0; DECL_USE_TEMPLATE (alias) = 0; DECL_TEMPLATE_INSTANTIATED (alias) = 0; DECL_TEMPLATE_INFO (alias) = NULL; DECL_INITIAL (alias) = error_mark_node; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; return alias; }
static bool suitable_for_tail_call_opt_p (void) { tree param; /* alloca (until we have stack slot life analysis) inhibits sibling call optimizations, but not tail recursion. */ if (cfun->calls_alloca) return false; /* If we are using sjlj exceptions, we may need to add a call to _Unwind_SjLj_Unregister at exit of the function. Which means that we cannot do any sibcall transformations. */ if (targetm_common.except_unwind_info (&global_options) == UI_SJLJ && current_function_has_exception_handlers ()) return false; /* Any function that calls setjmp might have longjmp called from any called function. ??? We really should represent this properly in the CFG so that this needn't be special cased. */ if (cfun->calls_setjmp) return false; /* ??? It is OK if the argument of a function is taken in some cases, but not in all cases. See PR15387 and PR19616. Revisit for 4.1. */ for (param = DECL_ARGUMENTS (current_function_decl); param; param = DECL_CHAIN (param)) if (TREE_ADDRESSABLE (param)) return false; return true; }
static inline void unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr) { /* Note that the code for EXPR has already been unpacked to create EXPR in streamer_alloc_tree. */ if (!TYPE_P (expr)) { TREE_SIDE_EFFECTS (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_CONSTANT (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_READONLY (expr) = (unsigned) bp_unpack_value (bp, 1); /* TREE_PUBLIC is used on types to indicate that the type has a TYPE_CACHED_VALUES vector. This is not streamed out, so we skip it here. */ TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1); } else bp_unpack_value (bp, 4); TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1); if (DECL_P (expr)) DECL_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); else if (TYPE_P (expr)) TYPE_UNSIGNED (expr) = (unsigned) bp_unpack_value (bp, 1); else bp_unpack_value (bp, 1); TREE_ASM_WRITTEN (expr) = (unsigned) bp_unpack_value (bp, 1); if (TYPE_P (expr)) TYPE_ARTIFICIAL (expr) = (unsigned) bp_unpack_value (bp, 1); else TREE_NO_WARNING (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_NOTHROW (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_STATIC (expr) = (unsigned) bp_unpack_value (bp, 1); if (TREE_CODE (expr) != TREE_BINFO) TREE_PRIVATE (expr) = (unsigned) bp_unpack_value (bp, 1); else bp_unpack_value (bp, 1); TREE_PROTECTED (expr) = (unsigned) bp_unpack_value (bp, 1); TREE_DEPRECATED (expr) = (unsigned) bp_unpack_value (bp, 1); if (TYPE_P (expr)) { if (AGGREGATE_TYPE_P (expr)) TYPE_REVERSE_STORAGE_ORDER (expr) = (unsigned) bp_unpack_value (bp, 1); else TYPE_SATURATING (expr) = (unsigned) bp_unpack_value (bp, 1); TYPE_ADDR_SPACE (expr) = (unsigned) bp_unpack_value (bp, 8); } else if (TREE_CODE (expr) == BIT_FIELD_REF || TREE_CODE (expr) == MEM_REF) { REF_REVERSE_STORAGE_ORDER (expr) = (unsigned) bp_unpack_value (bp, 1); bp_unpack_value (bp, 8); } else if (TREE_CODE (expr) == SSA_NAME) { SSA_NAME_IS_DEFAULT_DEF (expr) = (unsigned) bp_unpack_value (bp, 1); bp_unpack_value (bp, 8); } else bp_unpack_value (bp, 9); }
static tree build_equiv_decl (tree union_type, bool is_init) { tree decl; if (is_init) { decl = gfc_create_var (union_type, "equiv"); TREE_STATIC (decl) = 1; return decl; } decl = build_decl (VAR_DECL, NULL, union_type); DECL_ARTIFICIAL (decl) = 1; DECL_COMMON (decl) = 1; TREE_ADDRESSABLE (decl) = 1; TREE_USED (decl) = 1; /* The source location has been lost, and doesn't really matter. We need to set it to something though. */ gfc_set_decl_location (decl, &gfc_current_locus); gfc_add_decl_to_function (decl); return decl; }
tree gfc_build_addr_expr (tree type, tree t) { tree base_type = TREE_TYPE (t); tree natural_type; if (type && POINTER_TYPE_P (type) && TREE_CODE (base_type) == ARRAY_TYPE && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == TYPE_MAIN_VARIANT (TREE_TYPE (base_type))) natural_type = type; else natural_type = build_pointer_type (base_type); if (TREE_CODE (t) == INDIRECT_REF) { if (!type) type = natural_type; t = TREE_OPERAND (t, 0); natural_type = TREE_TYPE (t); } else { if (DECL_P (t)) TREE_ADDRESSABLE (t) = 1; t = build1 (ADDR_EXPR, natural_type, t); } if (type && natural_type != type) t = convert (type, t); return t; }
static tree make_fname_decl () { const char *name = lang_hooks.decl_printable_name (current_function_decl, 0); tree decl, type, init; size_t length = strlen (name); type = build_array_type (build_type_variant (char_type_node, true, false), build_index_type (size_int (length))); decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier ("__function_name__"), type); TREE_STATIC (decl) = 1; TREE_READONLY (decl) = 1; DECL_ARTIFICIAL (decl) = 1; init = build_string (length + 1, name); TREE_TYPE (init) = type; TREE_READONLY (init) = 1; DECL_READ_P (decl) = 1; DECL_INITIAL (decl) = init; TREE_USED (decl) = 1; TREE_ADDRESSABLE (decl) = 1; DECL_CONTEXT (decl) = current_function_decl; return decl; }
static tree build_equiv_decl (tree union_type, bool is_init) { tree decl; char name[15]; static int serial = 0; if (is_init) { decl = gfc_create_var (union_type, "equiv"); TREE_STATIC (decl) = 1; return decl; } snprintf (name, sizeof (name), "equiv.%d", serial++); decl = build_decl (VAR_DECL, get_identifier (name), union_type); DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; if (!gfc_can_put_var_on_stack (DECL_SIZE_UNIT (decl))) TREE_STATIC (decl) = 1; TREE_ADDRESSABLE (decl) = 1; TREE_USED (decl) = 1; /* The source location has been lost, and doesn't really matter. We need to set it to something though. */ gfc_set_decl_location (decl, &gfc_current_locus); gfc_add_decl_to_function (decl); return decl; }
static void update_cloned_parm (tree parm, tree cloned_parm, bool first) { DECL_ABSTRACT_ORIGIN (cloned_parm) = parm; /* We may have taken its address. */ TREE_ADDRESSABLE (cloned_parm) = TREE_ADDRESSABLE (parm); /* The definition might have different constness. */ TREE_READONLY (cloned_parm) = TREE_READONLY (parm); TREE_USED (cloned_parm) = !first || TREE_USED (parm); /* The name may have changed from the declaration. */ DECL_NAME (cloned_parm) = DECL_NAME (parm); DECL_SOURCE_LOCATION (cloned_parm) = DECL_SOURCE_LOCATION (parm); TREE_TYPE (cloned_parm) = TREE_TYPE (parm); }
tree copy_var_decl (tree var, tree name, tree type) { tree copy = build_decl (DECL_SOURCE_LOCATION (var), VAR_DECL, name, type); TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var); TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var); DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var); DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var); DECL_IGNORED_P (copy) = DECL_IGNORED_P (var); DECL_CONTEXT (copy) = DECL_CONTEXT (var); TREE_NO_WARNING (copy) = TREE_NO_WARNING (var); TREE_USED (copy) = 1; DECL_SEEN_IN_BIND_EXPR_P (copy) = 1; DECL_ATTRIBUTES (copy) = DECL_ATTRIBUTES (var); return copy; }
tree gfc_build_array_ref (tree base, tree offset) { tree type = TREE_TYPE (base); gcc_assert (TREE_CODE (type) == ARRAY_TYPE); type = TREE_TYPE (type); if (DECL_P (base)) TREE_ADDRESSABLE (base) = 1; return build4 (ARRAY_REF, type, base, offset, NULL_TREE, NULL_TREE); }
static void mark_address_taken (tree ref) { tree var; /* Note that it is *NOT OKAY* to use the target of a COMPONENT_REF as the only thing we take the address of. If VAR is a structure, taking the address of a field means that the whole structure may be referenced using pointer arithmetic. See PR 21407 and the ensuing mailing list discussion. */ var = get_base_address (ref); if (var) { if (DECL_P (var)) TREE_ADDRESSABLE (var) = 1; else if (TREE_CODE (var) == MEM_REF && TREE_CODE (TREE_OPERAND (var, 0)) == ADDR_EXPR && DECL_P (TREE_OPERAND (TREE_OPERAND (var, 0), 0))) TREE_ADDRESSABLE (TREE_OPERAND (TREE_OPERAND (var, 0), 0)) = 1; } }
static void mark_addressable_1 (tree x) { if (!currently_expanding_to_rtl) { TREE_ADDRESSABLE (x) = 1; return; } if (!mark_addressable_queue) mark_addressable_queue = new hash_set<tree>(); mark_addressable_queue->add (x); }
/* Check whether the given decl, generally a VAR_DECL or PARM_DECL, is eligible for instrumentation. For the mudflap1 pass, this implies that it should be registered with the libmudflap runtime. For the mudflap2 pass this means instrumenting an indirection operation with respect to the object. */ static int mf_decl_eligible_p (tree decl) { return ((TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) /* The decl must have its address taken. In the case of arrays, this flag is also set if the indexes are not compile-time known valid constants. */ && TREE_ADDRESSABLE (decl) /* XXX: not sufficient: return-by-value structs! */ /* The type of the variable must be complete. */ && COMPLETE_OR_VOID_TYPE_P (TREE_TYPE (decl)) /* The decl hasn't been decomposed somehow. */ && !DECL_HAS_VALUE_EXPR_P (decl)); }
static void pack_ts_base_value_fields (struct bitpack_d *bp, tree expr) { bp_pack_value (bp, TREE_CODE (expr), 16); if (!TYPE_P (expr)) { bp_pack_value (bp, TREE_SIDE_EFFECTS (expr), 1); bp_pack_value (bp, TREE_CONSTANT (expr), 1); bp_pack_value (bp, TREE_READONLY (expr), 1); /* TREE_PUBLIC is used on types to indicate that the type has a TYPE_CACHED_VALUES vector. This is not streamed out, so we skip it here. */ bp_pack_value (bp, TREE_PUBLIC (expr), 1); } else bp_pack_value (bp, 0, 4); bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1); bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1); if (DECL_P (expr)) bp_pack_value (bp, DECL_UNSIGNED (expr), 1); else if (TYPE_P (expr)) bp_pack_value (bp, TYPE_UNSIGNED (expr), 1); else bp_pack_value (bp, 0, 1); /* We write debug info two times, do not confuse the second one. The only relevant TREE_ASM_WRITTEN use is on SSA names. */ bp_pack_value (bp, (TREE_CODE (expr) != SSA_NAME ? 0 : TREE_ASM_WRITTEN (expr)), 1); if (TYPE_P (expr)) bp_pack_value (bp, TYPE_ARTIFICIAL (expr), 1); else bp_pack_value (bp, TREE_NO_WARNING (expr), 1); bp_pack_value (bp, TREE_NOTHROW (expr), 1); bp_pack_value (bp, TREE_STATIC (expr), 1); if (TREE_CODE (expr) != TREE_BINFO) bp_pack_value (bp, TREE_PRIVATE (expr), 1); bp_pack_value (bp, TREE_PROTECTED (expr), 1); bp_pack_value (bp, TREE_DEPRECATED (expr), 1); if (TYPE_P (expr)) { bp_pack_value (bp, TYPE_SATURATING (expr), 1); bp_pack_value (bp, TYPE_ADDR_SPACE (expr), 8); } else if (TREE_CODE (expr) == SSA_NAME) bp_pack_value (bp, SSA_NAME_IS_DEFAULT_DEF (expr), 1); else bp_pack_value (bp, 0, 1); }
static tree make_alias_for_thunk (tree function) { tree alias; char buf[256]; #if defined (TARGET_IS_PE_COFF) if (DECL_ONE_ONLY (function)) return function; #endif ASM_GENERATE_INTERNAL_LABEL (buf, "LTHUNK", thunk_labelno); thunk_labelno++; alias = build_decl (FUNCTION_DECL, get_identifier (buf), TREE_TYPE (function)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (function); cxx_dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL; TREE_READONLY (alias) = TREE_READONLY (function); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (function); TREE_PUBLIC (alias) = 0; DECL_INTERFACE_KNOWN (alias) = 1; DECL_NOT_REALLY_EXTERN (alias) = 1; DECL_THIS_STATIC (alias) = 1; DECL_SAVED_FUNCTION_DATA (alias) = NULL; DECL_DESTRUCTOR_P (alias) = 0; DECL_CONSTRUCTOR_P (alias) = 0; DECL_CLONED_FUNCTION (alias) = NULL_TREE; DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_NO_STATIC_CHAIN (alias) = 1; DECL_PENDING_INLINE_P (alias) = 0; DECL_INLINE (alias) = 0; DECL_DECLARED_INLINE_P (alias) = 0; DECL_DEFERRED_FN (alias) = 0; DECL_USE_TEMPLATE (alias) = 0; DECL_TEMPLATE_INSTANTIATED (alias) = 0; DECL_TEMPLATE_INFO (alias) = NULL; DECL_INITIAL (alias) = error_mark_node; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; if (!flag_syntax_only) assemble_alias (alias, DECL_ASSEMBLER_NAME (function)); return alias; }
tree ubsan_encode_value (tree t, bool in_expand_p) { tree type = TREE_TYPE (t); const unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); if (bitsize <= POINTER_SIZE) switch (TREE_CODE (type)) { case BOOLEAN_TYPE: case ENUMERAL_TYPE: case INTEGER_TYPE: return fold_build1 (NOP_EXPR, pointer_sized_int_node, t); case REAL_TYPE: { tree itype = build_nonstandard_integer_type (bitsize, true); t = fold_build1 (VIEW_CONVERT_EXPR, itype, t); return fold_convert (pointer_sized_int_node, t); } default: gcc_unreachable (); } else { if (!DECL_P (t) || !TREE_ADDRESSABLE (t)) { /* The reason for this is that we don't want to pessimize code by making vars unnecessarily addressable. */ tree var = create_tmp_var (type, NULL); tree tem = build2 (MODIFY_EXPR, void_type_node, var, t); if (in_expand_p) { rtx mem = assign_stack_temp_for_type (TYPE_MODE (type), GET_MODE_SIZE (TYPE_MODE (type)), type); SET_DECL_RTL (var, mem); expand_assignment (var, t, false); return build_fold_addr_expr (var); } t = build_fold_addr_expr (var); return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t); } else return build_fold_addr_expr (t); } }
tree create_tmp_var (tree type, const char *prefix) { tree tmp_var; /* We don't allow types that are addressable (meaning we can't make copies), or incomplete. We also used to reject every variable size objects here, but now support those for which a constant upper bound can be obtained. The processing for variable sizes is performed in gimple_add_tmp_var, point at which it really matters and possibly reached via paths not going through this function, e.g. after direct calls to create_tmp_var_raw. */ gcc_assert (!TREE_ADDRESSABLE (type) && COMPLETE_TYPE_P (type)); tmp_var = create_tmp_var_raw (type, prefix); gimple_add_tmp_var (tmp_var); return tmp_var; }
static bool slang_mark_addressable (tree exp) { switch (TREE_CODE (exp)){ case STRING_CST: break; case FUNCTION_DECL: TREE_ADDRESSABLE (exp) = 1; break; case ARRAY_REF: return slang_mark_addressable (TREE_OPERAND (exp, 0)); break; default: gcc_unreachable(); break; } return true; }
tree gfc_build_addr_expr (tree type, tree t) { tree base_type = TREE_TYPE (t); tree natural_type; if (type && POINTER_TYPE_P (type) && TREE_CODE (base_type) == ARRAY_TYPE && TYPE_MAIN_VARIANT (TREE_TYPE (type)) == TYPE_MAIN_VARIANT (TREE_TYPE (base_type))) { tree min_val = size_zero_node; tree type_domain = TYPE_DOMAIN (base_type); if (type_domain && TYPE_MIN_VALUE (type_domain)) min_val = TYPE_MIN_VALUE (type_domain); t = fold (build4_loc (input_location, ARRAY_REF, TREE_TYPE (type), t, min_val, NULL_TREE, NULL_TREE)); natural_type = type; } else natural_type = build_pointer_type (base_type); if (TREE_CODE (t) == INDIRECT_REF) { if (!type) type = natural_type; t = TREE_OPERAND (t, 0); natural_type = TREE_TYPE (t); } else { tree base = get_base_address (t); if (base && DECL_P (base)) TREE_ADDRESSABLE (base) = 1; t = fold_build1_loc (input_location, ADDR_EXPR, natural_type, t); } if (type && natural_type != type) t = convert (type, t); return t; }
tree gfc_build_array_ref (tree base, tree offset, tree decl) { tree type = TREE_TYPE (base); tree tmp; gcc_assert (TREE_CODE (type) == ARRAY_TYPE); type = TREE_TYPE (type); if (DECL_P (base)) TREE_ADDRESSABLE (base) = 1; /* Strip NON_LVALUE_EXPR nodes. */ STRIP_TYPE_NOPS (offset); /* If the array reference is to a pointer, whose target contains a subreference, use the span that is stored with the backend decl and reference the element with pointer arithmetic. */ if (decl && (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == PARM_DECL) && GFC_DECL_SUBREF_ARRAY_P (decl) && !integer_zerop (GFC_DECL_SPAN(decl))) { offset = fold_build2_loc (input_location, MULT_EXPR, gfc_array_index_type, offset, GFC_DECL_SPAN(decl)); tmp = gfc_build_addr_expr (pvoid_type_node, base); tmp = fold_build2_loc (input_location, POINTER_PLUS_EXPR, pvoid_type_node, tmp, fold_convert (sizetype, offset)); tmp = fold_convert (build_pointer_type (type), tmp); if (!TYPE_STRING_FLAG (type)) tmp = build_fold_indirect_ref_loc (input_location, tmp); return tmp; } else /* Otherwise use a straightforward array reference. */ return build4_loc (input_location, ARRAY_REF, type, base, offset, NULL_TREE, NULL_TREE); }
void genrtl_scope_stmt (tree t) { tree block = SCOPE_STMT_BLOCK (t); if (!SCOPE_NO_CLEANUPS_P (t)) { if (SCOPE_BEGIN_P (t)) expand_start_bindings_and_block (2 * SCOPE_NULLIFIED_P (t), block); else if (SCOPE_END_P (t)) expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0); } else if (!SCOPE_NULLIFIED_P (t)) { rtx note = emit_note (SCOPE_BEGIN_P (t) ? NOTE_INSN_BLOCK_BEG : NOTE_INSN_BLOCK_END); NOTE_BLOCK (note) = block; } /* If we're at the end of a scope that contains inlined nested functions, we have to decide whether or not to write them out. */ if (block && SCOPE_END_P (t)) { tree fn; for (fn = BLOCK_VARS (block); fn; fn = TREE_CHAIN (fn)) { if (TREE_CODE (fn) == FUNCTION_DECL && DECL_CONTEXT (fn) == current_function_decl && DECL_SAVED_INSNS (fn) && DECL_SAVED_INSNS (fn)->saved_for_inline && !TREE_ASM_WRITTEN (fn) && TREE_ADDRESSABLE (fn)) { push_function_context (); output_inline_function (fn); pop_function_context (); } } } }
static void lower_builtin_posix_memalign (gimple_stmt_iterator *gsi) { gimple stmt, call = gsi_stmt (*gsi); tree pptr = gimple_call_arg (call, 0); tree align = gimple_call_arg (call, 1); tree res = gimple_call_lhs (call); tree ptr = create_tmp_reg (ptr_type_node, NULL); if (TREE_CODE (pptr) == ADDR_EXPR) { tree tem = create_tmp_var (ptr_type_node, NULL); TREE_ADDRESSABLE (tem) = 1; gimple_call_set_arg (call, 0, build_fold_addr_expr (tem)); stmt = gimple_build_assign (ptr, tem); } else stmt = gimple_build_assign (ptr, fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0))); if (res == NULL_TREE) { res = create_tmp_reg (integer_type_node, NULL); gimple_call_set_lhs (call, res); } tree align_label = create_artificial_label (UNKNOWN_LOCATION); tree noalign_label = create_artificial_label (UNKNOWN_LOCATION); gimple cond = gimple_build_cond (EQ_EXPR, res, integer_zero_node, align_label, noalign_label); gsi_insert_after (gsi, cond, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (align_label), GSI_NEW_STMT); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_ASSUME_ALIGNED), 2, ptr, align); gimple_call_set_lhs (stmt, ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); stmt = gimple_build_assign (fold_build2 (MEM_REF, ptr_type_node, pptr, build_int_cst (ptr_type_node, 0)), ptr); gsi_insert_after (gsi, stmt, GSI_NEW_STMT); gsi_insert_after (gsi, gimple_build_label (noalign_label), GSI_NEW_STMT); }
tree ubsan_encode_value (tree t) { tree type = TREE_TYPE (t); switch (TREE_CODE (type)) { case INTEGER_TYPE: if (TYPE_PRECISION (type) <= POINTER_SIZE) return fold_build1 (NOP_EXPR, pointer_sized_int_node, t); else return build_fold_addr_expr (t); case REAL_TYPE: { unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type)); if (bitsize <= POINTER_SIZE) { tree itype = build_nonstandard_integer_type (bitsize, true); t = fold_build1 (VIEW_CONVERT_EXPR, itype, t); return fold_convert (pointer_sized_int_node, t); } else { if (!TREE_ADDRESSABLE (t)) { /* The reason for this is that we don't want to pessimize code by making vars unnecessarily addressable. */ tree var = create_tmp_var (TREE_TYPE (t), NULL); tree tem = build2 (MODIFY_EXPR, void_type_node, var, t); t = build_fold_addr_expr (var); return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t); } else return build_fold_addr_expr (t); } } default: gcc_unreachable (); } }
tree make_alias_for (tree target, tree newid) { tree alias = build_decl (DECL_SOURCE_LOCATION (target), TREE_CODE (target), newid, TREE_TYPE (target)); DECL_LANG_SPECIFIC (alias) = DECL_LANG_SPECIFIC (target); cxx_dup_lang_specific_decl (alias); DECL_CONTEXT (alias) = NULL; TREE_READONLY (alias) = TREE_READONLY (target); TREE_THIS_VOLATILE (alias) = TREE_THIS_VOLATILE (target); TREE_PUBLIC (alias) = 0; DECL_INTERFACE_KNOWN (alias) = 1; if (DECL_LANG_SPECIFIC (alias)) { DECL_NOT_REALLY_EXTERN (alias) = 1; DECL_USE_TEMPLATE (alias) = 0; DECL_TEMPLATE_INFO (alias) = NULL; } DECL_EXTERNAL (alias) = 0; DECL_ARTIFICIAL (alias) = 1; DECL_TEMPLATE_INSTANTIATED (alias) = 0; if (TREE_CODE (alias) == FUNCTION_DECL) { DECL_SAVED_FUNCTION_DATA (alias) = NULL; DECL_DESTRUCTOR_P (alias) = 0; DECL_CONSTRUCTOR_P (alias) = 0; DECL_PENDING_INLINE_P (alias) = 0; DECL_DECLARED_INLINE_P (alias) = 0; DECL_INITIAL (alias) = error_mark_node; DECL_ARGUMENTS (alias) = copy_list (DECL_ARGUMENTS (target)); } else TREE_STATIC (alias) = 1; TREE_ADDRESSABLE (alias) = 1; TREE_USED (alias) = 1; SET_DECL_ASSEMBLER_NAME (alias, DECL_NAME (alias)); TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (alias)) = 1; return alias; }
static void create_vop_var (struct function *fn) { tree global_var; gcc_assert (fn->gimple_df->vop == NULL_TREE); global_var = build_decl (BUILTINS_LOCATION, VAR_DECL, get_identifier (".MEM"), void_type_node); DECL_ARTIFICIAL (global_var) = 1; DECL_IGNORED_P (global_var) = 1; TREE_READONLY (global_var) = 0; DECL_EXTERNAL (global_var) = 1; TREE_STATIC (global_var) = 1; TREE_USED (global_var) = 1; DECL_CONTEXT (global_var) = NULL_TREE; TREE_THIS_VOLATILE (global_var) = 0; TREE_ADDRESSABLE (global_var) = 0; VAR_DECL_IS_VIRTUAL_OPERAND (global_var) = 1; fn->gimple_df->vop = global_var; }
static void create_vop_var (void) { tree global_var; gcc_assert (cfun->gimple_df->vop == NULL_TREE); global_var = build_decl (BUILTINS_LOCATION, VAR_DECL, get_identifier (".MEM"), void_type_node); DECL_ARTIFICIAL (global_var) = 1; TREE_READONLY (global_var) = 0; DECL_EXTERNAL (global_var) = 1; TREE_STATIC (global_var) = 1; TREE_USED (global_var) = 1; DECL_CONTEXT (global_var) = NULL_TREE; TREE_THIS_VOLATILE (global_var) = 0; TREE_ADDRESSABLE (global_var) = 0; create_var_ann (global_var); add_referenced_var (global_var); cfun->gimple_df->vop = global_var; }
static void create_common (gfc_common_head *com, segment_info *head, bool saw_equiv) { segment_info *s, *next_s; tree union_type; tree *field_link; tree field; tree field_init = NULL_TREE; record_layout_info rli; tree decl; bool is_init = false; bool is_saved = false; /* Declare the variables inside the common block. If the current common block contains any equivalence object, then make a UNION_TYPE node, otherwise RECORD_TYPE. This will let the alias analyzer work well when there is no address overlapping for common variables in the current common block. */ if (saw_equiv) union_type = make_node (UNION_TYPE); else union_type = make_node (RECORD_TYPE); rli = start_record_layout (union_type); field_link = &TYPE_FIELDS (union_type); /* Check for overlapping initializers and replace them with a single, artificial field that contains all the data. */ if (saw_equiv) field = get_init_field (head, union_type, &field_init, rli); else field = NULL_TREE; if (field != NULL_TREE) { is_init = true; *field_link = field; field_link = &DECL_CHAIN (field); } for (s = head; s; s = s->next) { build_field (s, union_type, rli); /* Link the field into the type. */ *field_link = s->field; field_link = &DECL_CHAIN (s->field); /* Has initial value. */ if (s->sym->value) is_init = true; /* Has SAVE attribute. */ if (s->sym->attr.save) is_saved = true; } finish_record_layout (rli, true); if (com) decl = build_common_decl (com, union_type, is_init); else decl = build_equiv_decl (union_type, is_init, is_saved); if (is_init) { tree ctor, tmp; VEC(constructor_elt,gc) *v = NULL; if (field != NULL_TREE && field_init != NULL_TREE) CONSTRUCTOR_APPEND_ELT (v, field, field_init); else for (s = head; s; s = s->next) { if (s->sym->value) { /* Add the initializer for this field. */ tmp = gfc_conv_initializer (s->sym->value, &s->sym->ts, TREE_TYPE (s->field), s->sym->attr.dimension, s->sym->attr.pointer || s->sym->attr.allocatable, false); CONSTRUCTOR_APPEND_ELT (v, s->field, tmp); } } gcc_assert (!VEC_empty (constructor_elt, v)); ctor = build_constructor (union_type, v); TREE_CONSTANT (ctor) = 1; TREE_STATIC (ctor) = 1; DECL_INITIAL (decl) = ctor; #ifdef ENABLE_CHECKING { tree field, value; unsigned HOST_WIDE_INT idx; FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (ctor), idx, field, value) gcc_assert (TREE_CODE (field) == FIELD_DECL); } #endif } /* Build component reference for each variable. */ for (s = head; s; s = next_s) { tree var_decl; var_decl = build_decl (s->sym->declared_at.lb->location, VAR_DECL, DECL_NAME (s->field), TREE_TYPE (s->field)); TREE_STATIC (var_decl) = TREE_STATIC (decl); /* Mark the variable as used in order to avoid warnings about unused variables. */ TREE_USED (var_decl) = 1; if (s->sym->attr.use_assoc) DECL_IGNORED_P (var_decl) = 1; if (s->sym->attr.target) TREE_ADDRESSABLE (var_decl) = 1; /* Fake variables are not visible from other translation units. */ TREE_PUBLIC (var_decl) = 0; /* To preserve identifier names in COMMON, chain to procedure scope unless at top level in a module definition. */ if (com && s->sym->ns->proc_name && s->sym->ns->proc_name->attr.flavor == FL_MODULE) var_decl = pushdecl_top_level (var_decl); else gfc_add_decl_to_function (var_decl); SET_DECL_VALUE_EXPR (var_decl, fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (s->field), decl, s->field, NULL_TREE)); DECL_HAS_VALUE_EXPR_P (var_decl) = 1; GFC_DECL_COMMON_OR_EQUIV (var_decl) = 1; if (s->sym->attr.assign) { gfc_allocate_lang_decl (var_decl); GFC_DECL_ASSIGN (var_decl) = 1; GFC_DECL_STRING_LEN (var_decl) = GFC_DECL_STRING_LEN (s->field); GFC_DECL_ASSIGN_ADDR (var_decl) = GFC_DECL_ASSIGN_ADDR (s->field); } s->sym->backend_decl = var_decl; next_s = s->next; free (s); } }