static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
htab_t epilogue_insn_hash;
\f
+
+htab_t types_used_by_vars_hash = NULL;
+tree types_used_by_cur_var_decl = NULL;
+
/* Forward declarations. */
static struct temp_slot *find_temp_slot_from_address (rtx);
/* Leave room for the fixed part of the frame. */
- 64 * UNITS_PER_WORD)
{
- error ("%Jtotal size of local objects too large", func);
+ error_at (DECL_SOURCE_LOCATION (func),
+ "total size of local objects too large");
return TRUE;
}
#ifdef PROMOTE_MODE
if (! dont_promote)
- mode = promote_mode (type, mode, &unsignedp, 0);
+ mode = promote_mode (type, mode, &unsignedp);
#endif
return gen_reg_rtx (mode);
|| GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
|| GET_CODE (PATTERN (insn)) == ASM_INPUT)
continue;
-
- instantiate_virtual_regs_in_insn (insn);
+ else if (DEBUG_INSN_P (insn))
+ for_each_rtx (&INSN_VAR_LOCATION (insn),
+ instantiate_virtual_regs_in_rtx, NULL);
+ else
+ instantiate_virtual_regs_in_insn (insn);
if (INSN_DELETED_P (insn))
continue;
{
tree nominal_type, passed_type;
enum machine_mode nominal_mode, passed_mode, promoted_mode;
+ int unsignedp;
memset (data, 0, sizeof (*data));
}
/* Find mode as it is passed by the ABI. */
- promoted_mode = passed_mode;
- if (targetm.calls.promote_function_args (TREE_TYPE (current_function_decl)))
- {
- int unsignedp = TYPE_UNSIGNED (passed_type);
- promoted_mode = promote_mode (passed_type, promoted_mode,
- &unsignedp, 1);
- }
+ unsignedp = TYPE_UNSIGNED (passed_type);
+ promoted_mode = promote_function_mode (passed_type, passed_mode, &unsignedp,
+ TREE_TYPE (current_function_decl), 0);
egress:
data->nominal_type = nominal_type;
stack_parm = gen_rtx_PLUS (Pmode, stack_parm, offset_rtx);
stack_parm = gen_rtx_MEM (data->promoted_mode, stack_parm);
- set_mem_attributes (stack_parm, parm, 1);
- /* set_mem_attributes could set MEM_SIZE to the passed mode's size,
- while promoted mode's size is needed. */
- if (data->promoted_mode != BLKmode
- && data->promoted_mode != DECL_MODE (parm))
+ if (!data->passed_pointer)
{
- set_mem_size (stack_parm, GEN_INT (GET_MODE_SIZE (data->promoted_mode)));
- if (MEM_EXPR (stack_parm) && MEM_OFFSET (stack_parm))
+ set_mem_attributes (stack_parm, parm, 1);
+ /* set_mem_attributes could set MEM_SIZE to the passed mode's size,
+ while promoted mode's size is needed. */
+ if (data->promoted_mode != BLKmode
+ && data->promoted_mode != DECL_MODE (parm))
{
- int offset = subreg_lowpart_offset (DECL_MODE (parm),
- data->promoted_mode);
- if (offset)
- set_mem_offset (stack_parm,
- plus_constant (MEM_OFFSET (stack_parm), -offset));
+ set_mem_size (stack_parm,
+ GEN_INT (GET_MODE_SIZE (data->promoted_mode)));
+ if (MEM_EXPR (stack_parm) && MEM_OFFSET (stack_parm))
+ {
+ int offset = subreg_lowpart_offset (DECL_MODE (parm),
+ data->promoted_mode);
+ if (offset)
+ set_mem_offset (stack_parm,
+ plus_constant (MEM_OFFSET (stack_parm),
+ -offset));
+ }
}
}
bool did_conversion = false;
/* Store the parm in a pseudoregister during the function, but we may
- need to do it in a wider mode. */
-
- /* This is not really promoting for a call. However we need to be
- consistent with assign_parm_find_data_types and expand_expr_real_1. */
+ need to do it in a wider mode. Using 2 here makes the result
+ consistent with promote_decl_mode and thus expand_expr_real_1. */
promoted_nominal_mode
- = promote_mode (data->nominal_type, data->nominal_mode, &unsignedp, 1);
+ = promote_function_mode (data->nominal_type, data->nominal_mode, &unsignedp,
+ TREE_TYPE (current_function_decl), 2);
parmreg = gen_reg_rtx (promoted_nominal_mode);
assign_parm_remove_parallels (data);
- /* Copy the value into the register. */
+ /* Copy the value into the register, thus bridging between
+ assign_parm_find_data_types and expand_expr_real_1. */
if (data->nominal_mode != data->passed_mode
|| promoted_nominal_mode != data->promoted_mode)
{
TYPE_UNSIGNED (TREE_TYPE (parm)));
if (data->stack_parm)
- /* ??? This may need a big-endian conversion on sparc64. */
- data->stack_parm
- = adjust_address (data->stack_parm, data->nominal_mode, 0);
+ {
+ int offset = subreg_lowpart_offset (data->nominal_mode,
+ GET_MODE (data->stack_parm));
+ /* ??? This may need a big-endian conversion on sparc64. */
+ data->stack_parm
+ = adjust_address (data->stack_parm, data->nominal_mode, 0);
+ if (offset && MEM_OFFSET (data->stack_parm))
+ set_mem_offset (data->stack_parm,
+ plus_constant (MEM_OFFSET (data->stack_parm),
+ offset));
+ }
}
if (data->entry_parm != data->stack_parm)
{
unsigned int align = FUNCTION_ARG_BOUNDARY (data.promoted_mode,
data.passed_type);
+ align = MINIMUM_ALIGNMENT (data.passed_type, data.promoted_mode,
+ align);
if (TYPE_ALIGN (data.nominal_type) > align)
- align = TYPE_ALIGN (data.passed_type);
+ align = MINIMUM_ALIGNMENT (data.nominal_type,
+ TYPE_MODE (data.nominal_type),
+ TYPE_ALIGN (data.nominal_type));
if (crtl->stack_alignment_estimated < align)
{
gcc_assert (!crtl->stack_realign_processed);
{
{
RTL_PASS,
- NULL, /* name */
+ "*init_function", /* name */
NULL, /* gate */
init_function_for_compilation, /* execute */
NULL, /* sub */
tree guard_decl = targetm.stack_protect_guard ();
rtx x, y;
- /* Avoid expand_expr here, because we don't want guard_decl pulled
- into registers unless absolutely necessary. And we know that
- crtl->stack_protect_guard is a local stack slot, so this skips
- all the fluff. */
- x = validize_mem (DECL_RTL (crtl->stack_protect_guard));
- y = validize_mem (DECL_RTL (guard_decl));
+ x = expand_normal (crtl->stack_protect_guard);
+ y = expand_normal (guard_decl);
/* Allow the target to copy from Y to X without leaking Y into a
register. */
rtx label = gen_label_rtx ();
rtx x, y, tmp;
- /* Avoid expand_expr here, because we don't want guard_decl pulled
- into registers unless absolutely necessary. And we know that
- crtl->stack_protect_guard is a local stack slot, so this skips
- all the fluff. */
- x = validize_mem (DECL_RTL (crtl->stack_protect_guard));
- y = validize_mem (DECL_RTL (guard_decl));
+ x = expand_normal (crtl->stack_protect_guard);
+ y = expand_normal (guard_decl);
/* Allow the target to compare Y with X without leaking either into
a register. */
if (cfun->static_chain_decl)
{
tree parm = cfun->static_chain_decl;
- rtx local = gen_reg_rtx (Pmode);
+ rtx local, chain, insn;
- set_decl_incoming_rtl (parm, static_chain_incoming_rtx, false);
+ local = gen_reg_rtx (Pmode);
+ chain = targetm.calls.static_chain (current_function_decl, true);
+
+ set_decl_incoming_rtl (parm, chain, false);
SET_DECL_RTL (parm, local);
mark_reg_pointer (local, TYPE_ALIGN (TREE_TYPE (TREE_TYPE (parm))));
- emit_move_insn (local, static_chain_incoming_rtx);
+ insn = emit_move_insn (local, chain);
+
+ /* Mark the register as eliminable, similar to parameters. */
+ if (MEM_P (chain)
+ && reg_mentioned_p (arg_pointer_rtx, XEXP (chain, 0)))
+ set_unique_reg_note (insn, REG_EQUIV, chain);
}
/* If the function receives a non-local goto, then store the
for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
if (CALL_P (insn))
{
+ rtx max_frame_size = GEN_INT (STACK_CHECK_MAX_FRAME_SIZE);
start_sequence ();
- probe_stack_range (STACK_OLD_CHECK_PROTECT,
- GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
+ if (STACK_CHECK_MOVING_SP)
+ anti_adjust_stack_and_probe (max_frame_size, true);
+ else
+ probe_stack_range (STACK_OLD_CHECK_PROTECT, max_frame_size);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, stack_check_probe_note);
else if (GET_MODE (real_decl_rtl) != GET_MODE (decl_rtl))
{
int unsignedp = TYPE_UNSIGNED (TREE_TYPE (decl_result));
-
- if (targetm.calls.promote_function_return (TREE_TYPE (current_function_decl)))
- promote_mode (TREE_TYPE (decl_result), GET_MODE (decl_rtl),
- &unsignedp, 1);
+ promote_function_mode (TREE_TYPE (decl_result),
+ GET_MODE (decl_rtl), &unsignedp,
+ TREE_TYPE (current_function_decl), 1);
convert_move (real_decl_rtl, decl_rtl, unsignedp);
}
{
#if defined (HAVE_prologue) || defined (HAVE_epilogue) \
|| defined (HAVE_sibcall_epilogue)
- rtx insn, last, note;
- basic_block bb;
-
/* Since the hash table is created on demand, the fact that it is
non-null is a signal that it is non-empty. */
if (prologue_insn_hash != NULL)
{
size_t len = htab_elements (prologue_insn_hash);
- last = 0, note = 0;
+ rtx insn, last = NULL, note = NULL;
/* Scan from the beginning until we reach the last prologue insn. */
/* ??? While we do have the CFG intact, there are two problems:
FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR->preds)
{
- last = 0, note = 0;
- bb = e->src;
+ rtx insn, first = NULL, note = NULL;
+ basic_block bb = e->src;
- /* Scan from the beginning until we reach the first epilogue insn.
- Take the cue for whether this is a plain or sibcall epilogue
- from the kind of note we find first. */
+ /* Scan from the beginning until we reach the first epilogue insn. */
FOR_BB_INSNS (bb, insn)
{
if (NOTE_P (insn))
if (NOTE_KIND (insn) == NOTE_INSN_EPILOGUE_BEG)
{
note = insn;
- if (last)
+ if (first != NULL)
break;
}
}
- else if (contains (insn, epilogue_insn_hash))
+ else if (first == NULL && contains (insn, epilogue_insn_hash))
{
- last = insn;
+ first = insn;
if (note != NULL)
break;
}
}
-
- if (last && note && PREV_INSN (last) != note)
- reorder_insns (note, note, PREV_INSN (last));
+
+ if (note)
+ {
+ /* If the function has a single basic block, and no real
+ epilogue insns (e.g. sibcall with no cleanup), the
+ epilogue note can get scheduled before the prologue
+ note. If we have frame related prologue insns, having
+ them scanned during the epilogue will result in a crash.
+ In this case re-order the epilogue note to just before
+ the last insn in the block. */
+ if (first == NULL)
+ first = BB_END (bb);
+
+ if (PREV_INSN (first) != note)
+ reorder_insns (note, note, PREV_INSN (first));
+ }
}
}
#endif /* HAVE_prologue or HAVE_epilogue */
const char *
current_function_name (void)
{
+ if (cfun == NULL)
+ return "<none>";
return lang_hooks.decl_printable_name (cfun->decl, 2);
}
\f
}
/* Insert a TYPE into the used types hash table of CFUN. */
+
static void
used_types_insert_helper (tree type, struct function *func)
{
t = TREE_TYPE (t);
t = TYPE_MAIN_VARIANT (t);
if (debug_info_level > DINFO_LEVEL_NONE)
- used_types_insert_helper (t, cfun);
+ {
+ if (cfun)
+ used_types_insert_helper (t, cfun);
+ else
+ /* So this might be a type referenced by a global variable.
+ Record that type so that we can later decide to emit its debug
+ information. */
+ types_used_by_cur_var_decl =
+ tree_cons (t, NULL, types_used_by_cur_var_decl);
+
+ }
+}
+
+/* Helper to Hash a struct types_used_by_vars_entry. */
+
+static hashval_t
+hash_types_used_by_vars_entry (const struct types_used_by_vars_entry *entry)
+{
+ gcc_assert (entry && entry->var_decl && entry->type);
+
+ return iterative_hash_object (entry->type,
+ iterative_hash_object (entry->var_decl, 0));
+}
+
+/* Hash function of the types_used_by_vars_entry hash table. */
+
+hashval_t
+types_used_by_vars_do_hash (const void *x)
+{
+ const struct types_used_by_vars_entry *entry =
+ (const struct types_used_by_vars_entry *) x;
+
+ return hash_types_used_by_vars_entry (entry);
+}
+
+/*Equality function of the types_used_by_vars_entry hash table. */
+
+int
+types_used_by_vars_eq (const void *x1, const void *x2)
+{
+ const struct types_used_by_vars_entry *e1 =
+ (const struct types_used_by_vars_entry *) x1;
+ const struct types_used_by_vars_entry *e2 =
+ (const struct types_used_by_vars_entry *)x2;
+
+ return (e1->var_decl == e2->var_decl && e1->type == e2->type);
+}
+
+/* Inserts an entry into the types_used_by_vars_hash hash table. */
+
+void
+types_used_by_var_decl_insert (tree type, tree var_decl)
+{
+ if (type != NULL && var_decl != NULL)
+ {
+ void **slot;
+ struct types_used_by_vars_entry e;
+ e.var_decl = var_decl;
+ e.type = type;
+ if (types_used_by_vars_hash == NULL)
+ types_used_by_vars_hash =
+ htab_create_ggc (37, types_used_by_vars_do_hash,
+ types_used_by_vars_eq, NULL);
+ slot = htab_find_slot_with_hash (types_used_by_vars_hash, &e,
+ hash_types_used_by_vars_entry (&e), INSERT);
+ if (*slot == NULL)
+ {
+ struct types_used_by_vars_entry *entry;
+ entry = (struct types_used_by_vars_entry*) ggc_alloc
+ (sizeof (struct types_used_by_vars_entry));
+ entry->type = type;
+ entry->var_decl = var_decl;
+ *slot = entry;
+ }
+ }
}
struct rtl_opt_pass pass_leaf_regs =
{
{
RTL_PASS,
- NULL, /* name */
+ "*leaf_regs", /* name */
NULL, /* gate */
rest_of_handle_check_leaf_regs, /* execute */
NULL, /* sub */