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 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; }
static int avm2_function_regparm (tree type, tree decl) { tree attr; /* APPLE LOCAL begin MERGE FIXME audit to ensure that it's ok We had local_regparm but the FSF didn't and there didn't seem to be a merge conflict some something is strange. These seem to be just normal apple local changes. I asked Stuart about them in email. */ int regparm = avm2_regparm; bool user_convention = false; if (1) { attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (type)); if (attr) { regparm = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr))); user_convention = true; } /* APPLE LOCAL begin regparmandstackparm */ if (lookup_attribute ("fastcall", TYPE_ATTRIBUTES (type)) || lookup_attribute ("regparmandstackparmee", TYPE_ATTRIBUTES (type))) /* APPLE LOCAL end regparmandstackparm */ { regparm = 2; user_convention = true; } /* Use register calling convention for local functions when possible. */ if (!user_convention && decl && flag_unit_at_a_time && !profile_flag) { struct cgraph_local_info *i = cgraph_local_info (decl); if (i && i->local) { int local_regparm, globals = 0, regno; /* Make sure no regparm register is taken by a global register variable. */ for (local_regparm = 0; local_regparm < 3; local_regparm++) if (global_regs[local_regparm]) break; /* We can't use regparm(3) for nested functions as these use static chain pointer in third argument. */ if (local_regparm == 3 /* APPLE LOCAL begin mainline */ && (decl_function_context (decl)) /* APPLE LOCAL end mainline */ && !DECL_NO_STATIC_CHAIN (decl)) local_regparm = 2; /* If the function realigns its stackpointer, the prologue will clobber %ecx. If we've already generated code for the callee, the callee DECL_STRUCT_FUNCTION is gone, so we fall back to scanning the attributes for the self-realigning property. */ if (false) local_regparm = 2; /* Each global register variable increases register preassure, so the more global reg vars there are, the smaller regparm optimization use, unless requested by the user explicitly. */ for (regno = 0; regno < 6; regno++) if (global_regs[regno]) globals++; local_regparm = globals < local_regparm ? local_regparm - globals : 0; if (local_regparm > regparm) regparm = local_regparm; } } } /* APPLE LOCAL end MERGE FIXME audit to ensure that it's ok */ return regparm; }
tree make_thunk (tree function, bool this_adjusting, tree fixed_offset, tree virtual_offset) { HOST_WIDE_INT d; tree thunk; gcc_assert (TREE_CODE (function) == FUNCTION_DECL); /* We can have this thunks to covariant thunks, but not vice versa. */ gcc_assert (!DECL_THIS_THUNK_P (function)); gcc_assert (!DECL_RESULT_THUNK_P (function) || this_adjusting); /* Scale the VIRTUAL_OFFSET to be in terms of bytes. */ if (this_adjusting && virtual_offset) virtual_offset = size_binop (MULT_EXPR, virtual_offset, convert (ssizetype, TYPE_SIZE_UNIT (vtable_entry_type))); d = tree_low_cst (fixed_offset, 0); /* See if we already have the thunk in question. For this_adjusting thunks VIRTUAL_OFFSET will be an INTEGER_CST, for covariant thunks it will be a BINFO. */ for (thunk = DECL_THUNKS (function); thunk; thunk = TREE_CHAIN (thunk)) if (DECL_THIS_THUNK_P (thunk) == this_adjusting && THUNK_FIXED_OFFSET (thunk) == d && !virtual_offset == !THUNK_VIRTUAL_OFFSET (thunk) && (!virtual_offset || (this_adjusting ? tree_int_cst_equal (THUNK_VIRTUAL_OFFSET (thunk), virtual_offset) : THUNK_VIRTUAL_OFFSET (thunk) == virtual_offset))) return thunk; /* All thunks must be created before FUNCTION is actually emitted; the ABI requires that all thunks be emitted together with the function to which they transfer control. */ gcc_assert (!TREE_ASM_WRITTEN (function)); /* Likewise, we can only be adding thunks to a function declared in the class currently being laid out. */ gcc_assert (TYPE_SIZE (DECL_CONTEXT (function)) && TYPE_BEING_DEFINED (DECL_CONTEXT (function))); thunk = build_decl (FUNCTION_DECL, NULL_TREE, TREE_TYPE (function)); DECL_LANG_SPECIFIC (thunk) = DECL_LANG_SPECIFIC (function); cxx_dup_lang_specific_decl (thunk); DECL_THUNKS (thunk) = NULL_TREE; DECL_CONTEXT (thunk) = DECL_CONTEXT (function); TREE_READONLY (thunk) = TREE_READONLY (function); TREE_THIS_VOLATILE (thunk) = TREE_THIS_VOLATILE (function); TREE_PUBLIC (thunk) = TREE_PUBLIC (function); SET_DECL_THUNK_P (thunk, this_adjusting); THUNK_TARGET (thunk) = function; THUNK_FIXED_OFFSET (thunk) = d; THUNK_VIRTUAL_OFFSET (thunk) = virtual_offset; THUNK_ALIAS (thunk) = NULL_TREE; /* The thunk itself is not a constructor or destructor, even if the thing it is thunking to is. */ DECL_INTERFACE_KNOWN (thunk) = 1; DECL_NOT_REALLY_EXTERN (thunk) = 1; DECL_SAVED_FUNCTION_DATA (thunk) = NULL; DECL_DESTRUCTOR_P (thunk) = 0; DECL_CONSTRUCTOR_P (thunk) = 0; DECL_EXTERNAL (thunk) = 1; DECL_ARTIFICIAL (thunk) = 1; /* Even if this thunk is a member of a local class, we don't need a static chain. */ DECL_NO_STATIC_CHAIN (thunk) = 1; /* The THUNK is not a pending inline, even if the FUNCTION is. */ DECL_PENDING_INLINE_P (thunk) = 0; DECL_INLINE (thunk) = 0; DECL_DECLARED_INLINE_P (thunk) = 0; /* Nor has it been deferred. */ DECL_DEFERRED_FN (thunk) = 0; /* Nor is it a template instantiation. */ DECL_USE_TEMPLATE (thunk) = 0; DECL_TEMPLATE_INFO (thunk) = NULL; /* Add it to the list of thunks associated with FUNCTION. */ TREE_CHAIN (thunk) = DECL_THUNKS (function); DECL_THUNKS (function) = thunk; return thunk; }