#include "langhooks.h"
#include "target.h"
#include "cfglayout.h"
-#include "tree-gimple.h"
+#include "gimple.h"
#include "tree-pass.h"
#include "predict.h"
#include "df.h"
/* So we can assign to cfun in this file. */
#undef cfun
-#ifndef LOCAL_ALIGNMENT
-#define LOCAL_ALIGNMENT(TYPE, ALIGNMENT) ALIGNMENT
-#endif
-
#ifndef STACK_ALIGNMENT_NEEDED
#define STACK_ALIGNMENT_NEEDED 1
#endif
static void do_use_return_reg (rtx, void *);
static void set_insn_locators (rtx, int) ATTRIBUTE_UNUSED;
\f
-/* Pointer to chain of `struct function' for containing functions. */
-struct function *outer_function_chain;
-
-/* Given a function decl for a containing function,
- return the `struct function' for it. */
-
-struct function *
-find_function_data (tree decl)
-{
- struct function *p;
+/* Stack of nested functions. */
+/* Keep track of the cfun stack. */
- for (p = outer_function_chain; p; p = p->outer)
- if (p->decl == decl)
- return p;
+typedef struct function *function_p;
- gcc_unreachable ();
-}
+DEF_VEC_P(function_p);
+DEF_VEC_ALLOC_P(function_p,heap);
+static VEC(function_p,heap) *function_context_stack;
/* Save the current context for compilation of a nested function.
This is called from language-specific code. */
if (cfun == 0)
allocate_struct_function (NULL, false);
- cfun->outer = outer_function_chain;
- outer_function_chain = cfun;
+ VEC_safe_push (function_p, heap, function_context_stack, cfun);
set_cfun (NULL);
}
void
pop_function_context (void)
{
- struct function *p = outer_function_chain;
-
+ struct function *p = VEC_pop (function_p, function_context_stack);
set_cfun (p);
- outer_function_chain = p->outer;
current_function_decl = p->decl;
/* Reset variables that have known state during rtx generation. */
f->machine = NULL;
f->cfg = NULL;
- f->epilogue_delay_list = NULL;
+ regno_reg_rtx = NULL;
+ insn_locators_free ();
}
\f
/* Return size needed for stack frame based on slots so far allocated.
return FALSE;
}
+/* Return stack slot alignment in bits for TYPE and MODE. */
+
+static unsigned int
+get_stack_local_alignment (tree type, enum machine_mode mode)
+{
+ unsigned int alignment;
+
+ if (mode == BLKmode)
+ alignment = BIGGEST_ALIGNMENT;
+ else
+ alignment = GET_MODE_ALIGNMENT (mode);
+
+ /* Allow the frond-end to (possibly) increase the alignment of this
+ stack slot. */
+ if (! type)
+ type = lang_hooks.types.type_for_mode (mode, 0);
+
+ return STACK_SLOT_ALIGNMENT (type, mode, alignment);
+}
+
/* Allocate a stack slot of SIZE bytes and return a MEM rtx for it
with machine mode MODE.
-2 means use BITS_PER_UNIT,
positive specifies alignment boundary in bits.
+ If REDUCE_ALIGNMENT_OK is true, it is OK to reduce alignment.
+
We do not round to stack_boundary here. */
rtx
-assign_stack_local (enum machine_mode mode, HOST_WIDE_INT size, int align)
+assign_stack_local_1 (enum machine_mode mode, HOST_WIDE_INT size,
+ int align,
+ bool reduce_alignment_ok ATTRIBUTE_UNUSED)
{
rtx x, addr;
int bigend_correction = 0;
- unsigned int alignment;
+ unsigned int alignment, alignment_in_bits;
int frame_off, frame_alignment, frame_phase;
if (align == 0)
{
- tree type;
-
- if (mode == BLKmode)
- alignment = BIGGEST_ALIGNMENT;
- else
- alignment = GET_MODE_ALIGNMENT (mode);
-
- /* Allow the target to (possibly) increase the alignment of this
- stack slot. */
- type = lang_hooks.types.type_for_mode (mode, 0);
- if (type)
- alignment = LOCAL_ALIGNMENT (type, alignment);
-
+ alignment = get_stack_local_alignment (NULL, mode);
alignment /= BITS_PER_UNIT;
}
else if (align == -1)
else
alignment = align / BITS_PER_UNIT;
+ alignment_in_bits = alignment * BITS_PER_UNIT;
+
if (FRAME_GROWS_DOWNWARD)
frame_offset -= size;
- /* Ignore alignment we can't do with expected alignment of the boundary. */
- if (alignment * BITS_PER_UNIT > PREFERRED_STACK_BOUNDARY)
- alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+ /* Ignore alignment if it exceeds MAX_SUPPORTED_STACK_ALIGNMENT. */
+ if (alignment_in_bits > MAX_SUPPORTED_STACK_ALIGNMENT)
+ {
+ alignment_in_bits = MAX_SUPPORTED_STACK_ALIGNMENT;
+ alignment = alignment_in_bits / BITS_PER_UNIT;
+ }
- if (cfun->stack_alignment_needed < alignment * BITS_PER_UNIT)
- cfun->stack_alignment_needed = alignment * BITS_PER_UNIT;
+ if (SUPPORTS_STACK_ALIGNMENT)
+ {
+ if (crtl->stack_alignment_estimated < alignment_in_bits)
+ {
+ if (!crtl->stack_realign_processed)
+ crtl->stack_alignment_estimated = alignment_in_bits;
+ else
+ {
+ /* If stack is realigned and stack alignment value
+ hasn't been finalized, it is OK not to increase
+ stack_alignment_estimated. The bigger alignment
+ requirement is recorded in stack_alignment_needed
+ below. */
+ gcc_assert (!crtl->stack_realign_finalized);
+ if (!crtl->stack_realign_needed)
+ {
+ /* It is OK to reduce the alignment as long as the
+ requested size is 0 or the estimated stack
+ alignment >= mode alignment. */
+ gcc_assert (reduce_alignment_ok
+ || size == 0
+ || (crtl->stack_alignment_estimated
+ >= GET_MODE_ALIGNMENT (mode)));
+ alignment_in_bits = crtl->stack_alignment_estimated;
+ alignment = alignment_in_bits / BITS_PER_UNIT;
+ }
+ }
+ }
+ }
+
+ if (crtl->stack_alignment_needed < alignment_in_bits)
+ crtl->stack_alignment_needed = alignment_in_bits;
+ if (crtl->max_used_stack_slot_alignment < crtl->stack_alignment_needed)
+ crtl->max_used_stack_slot_alignment = crtl->stack_alignment_needed;
/* Calculate how many bytes the start of local variables is off from
stack alignment. */
frame_offset += size;
x = gen_rtx_MEM (mode, addr);
+ set_mem_align (x, alignment_in_bits);
MEM_NOTRAP_P (x) = 1;
stack_slot_list
return x;
}
+
+/* Wrap up assign_stack_local_1 with last parameter as false. */
+
+rtx
+assign_stack_local (enum machine_mode mode, HOST_WIDE_INT size, int align)
+{
+ return assign_stack_local_1 (mode, size, align, false);
+}
\f
/* Removes temporary slot TEMP from LIST. */
/* These are now unused. */
gcc_assert (keep <= 1);
- if (mode == BLKmode)
- align = BIGGEST_ALIGNMENT;
- else
- align = GET_MODE_ALIGNMENT (mode);
-
- if (! type)
- type = lang_hooks.types.type_for_mode (mode, 0);
-
- if (type)
- align = LOCAL_ALIGNMENT (type, align);
+ align = get_stack_local_alignment (type, mode);
/* Try to find an available, already-allocated temporary of the proper
mode which meets the size and alignment requirements. Choose the
if (best_p->size - rounded_size >= alignment)
{
- p = ggc_alloc (sizeof (struct temp_slot));
+ p = GGC_NEW (struct temp_slot);
p->in_use = p->addr_taken = 0;
p->size = best_p->size - rounded_size;
p->base_offset = best_p->base_offset + rounded_size;
{
HOST_WIDE_INT frame_offset_old = frame_offset;
- p = ggc_alloc (sizeof (struct temp_slot));
+ p = GGC_NEW (struct temp_slot);
/* We are passing an explicit alignment request to assign_stack_local.
One side effect of that is assign_stack_local will not round SIZE
return 0;
}
-/* Indicate that NEW is an alternate way of referring to the temp slot
- that previously was known by OLD. */
+/* Indicate that NEW_RTX is an alternate way of referring to the temp
+ slot that previously was known by OLD_RTX. */
void
-update_temp_slot_address (rtx old, rtx new)
+update_temp_slot_address (rtx old_rtx, rtx new_rtx)
{
struct temp_slot *p;
- if (rtx_equal_p (old, new))
+ if (rtx_equal_p (old_rtx, new_rtx))
return;
- p = find_temp_slot_from_address (old);
+ p = find_temp_slot_from_address (old_rtx);
- /* If we didn't find one, see if both OLD is a PLUS. If so, and NEW
- is a register, see if one operand of the PLUS is a temporary
- location. If so, NEW points into it. Otherwise, if both OLD and
- NEW are a PLUS and if there is a register in common between them.
- If so, try a recursive call on those values. */
+ /* If we didn't find one, see if both OLD_RTX is a PLUS. If so, and
+ NEW_RTX is a register, see if one operand of the PLUS is a
+ temporary location. If so, NEW_RTX points into it. Otherwise,
+ if both OLD_RTX and NEW_RTX are a PLUS and if there is a register
+ in common between them. If so, try a recursive call on those
+ values. */
if (p == 0)
{
- if (GET_CODE (old) != PLUS)
+ if (GET_CODE (old_rtx) != PLUS)
return;
- if (REG_P (new))
+ if (REG_P (new_rtx))
{
- update_temp_slot_address (XEXP (old, 0), new);
- update_temp_slot_address (XEXP (old, 1), new);
+ update_temp_slot_address (XEXP (old_rtx, 0), new_rtx);
+ update_temp_slot_address (XEXP (old_rtx, 1), new_rtx);
return;
}
- else if (GET_CODE (new) != PLUS)
+ else if (GET_CODE (new_rtx) != PLUS)
return;
- if (rtx_equal_p (XEXP (old, 0), XEXP (new, 0)))
- update_temp_slot_address (XEXP (old, 1), XEXP (new, 1));
- else if (rtx_equal_p (XEXP (old, 1), XEXP (new, 0)))
- update_temp_slot_address (XEXP (old, 0), XEXP (new, 1));
- else if (rtx_equal_p (XEXP (old, 0), XEXP (new, 1)))
- update_temp_slot_address (XEXP (old, 1), XEXP (new, 0));
- else if (rtx_equal_p (XEXP (old, 1), XEXP (new, 1)))
- update_temp_slot_address (XEXP (old, 0), XEXP (new, 0));
+ if (rtx_equal_p (XEXP (old_rtx, 0), XEXP (new_rtx, 0)))
+ update_temp_slot_address (XEXP (old_rtx, 1), XEXP (new_rtx, 1));
+ else if (rtx_equal_p (XEXP (old_rtx, 1), XEXP (new_rtx, 0)))
+ update_temp_slot_address (XEXP (old_rtx, 0), XEXP (new_rtx, 1));
+ else if (rtx_equal_p (XEXP (old_rtx, 0), XEXP (new_rtx, 1)))
+ update_temp_slot_address (XEXP (old_rtx, 1), XEXP (new_rtx, 0));
+ else if (rtx_equal_p (XEXP (old_rtx, 1), XEXP (new_rtx, 1)))
+ update_temp_slot_address (XEXP (old_rtx, 0), XEXP (new_rtx, 0));
return;
}
/* Otherwise add an alias for the temp's address. */
else if (p->address == 0)
- p->address = new;
+ p->address = new_rtx;
else
{
if (GET_CODE (p->address) != EXPR_LIST)
p->address = gen_rtx_EXPR_LIST (VOIDmode, p->address, NULL_RTX);
- p->address = gen_rtx_EXPR_LIST (VOIDmode, new, p->address);
+ p->address = gen_rtx_EXPR_LIST (VOIDmode, new_rtx, p->address);
}
}
#define STACK_DYNAMIC_OFFSET(FNDECL) \
((ACCUMULATE_OUTGOING_ARGS \
? (crtl->outgoing_args_size \
- + (OUTGOING_REG_PARM_STACK_SPACE ? 0 : REG_PARM_STACK_SPACE (FNDECL))) \
+ + (OUTGOING_REG_PARM_STACK_SPACE ((!(FNDECL) ? NULL_TREE : TREE_TYPE (FNDECL))) ? 0 \
+ : REG_PARM_STACK_SPACE (FNDECL))) \
: 0) + (STACK_POINTER_OFFSET))
#else
#define STACK_DYNAMIC_OFFSET(FNDECL) \
static rtx
instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
{
- rtx new;
+ rtx new_rtx;
HOST_WIDE_INT offset;
if (x == virtual_incoming_args_rtx)
- new = arg_pointer_rtx, offset = in_arg_offset;
+ {
+ if (stack_realign_drap)
+ {
+ /* Replace virtual_incoming_args_rtx with internal arg
+ pointer if DRAP is used to realign stack. */
+ new_rtx = crtl->args.internal_arg_pointer;
+ offset = 0;
+ }
+ else
+ new_rtx = arg_pointer_rtx, offset = in_arg_offset;
+ }
else if (x == virtual_stack_vars_rtx)
- new = frame_pointer_rtx, offset = var_offset;
+ new_rtx = frame_pointer_rtx, offset = var_offset;
else if (x == virtual_stack_dynamic_rtx)
- new = stack_pointer_rtx, offset = dynamic_offset;
+ new_rtx = stack_pointer_rtx, offset = dynamic_offset;
else if (x == virtual_outgoing_args_rtx)
- new = stack_pointer_rtx, offset = out_arg_offset;
+ new_rtx = stack_pointer_rtx, offset = out_arg_offset;
else if (x == virtual_cfa_rtx)
{
#ifdef FRAME_POINTER_CFA_OFFSET
- new = frame_pointer_rtx;
+ new_rtx = frame_pointer_rtx;
#else
- new = arg_pointer_rtx;
+ new_rtx = arg_pointer_rtx;
#endif
offset = cfa_offset;
}
return NULL_RTX;
*poffset = offset;
- return new;
+ return new_rtx;
}
/* A subroutine of instantiate_virtual_regs, called via for_each_rtx.
{
HOST_WIDE_INT offset;
bool *changed = (bool *) data;
- rtx x, new;
+ rtx x, new_rtx;
x = *loc;
if (x == 0)
switch (GET_CODE (x))
{
case REG:
- new = instantiate_new_reg (x, &offset);
- if (new)
+ new_rtx = instantiate_new_reg (x, &offset);
+ if (new_rtx)
{
- *loc = plus_constant (new, offset);
+ *loc = plus_constant (new_rtx, offset);
if (changed)
*changed = true;
}
return -1;
case PLUS:
- new = instantiate_new_reg (XEXP (x, 0), &offset);
- if (new)
+ new_rtx = instantiate_new_reg (XEXP (x, 0), &offset);
+ if (new_rtx)
{
- new = plus_constant (new, offset);
- *loc = simplify_gen_binary (PLUS, GET_MODE (x), new, XEXP (x, 1));
+ new_rtx = plus_constant (new_rtx, offset);
+ *loc = simplify_gen_binary (PLUS, GET_MODE (x), new_rtx, XEXP (x, 1));
if (changed)
*changed = true;
return -1;
HOST_WIDE_INT offset;
int insn_code, i;
bool any_change = false;
- rtx set, new, x, seq;
+ rtx set, new_rtx, x, seq;
/* There are some special cases to be handled first. */
set = single_set (insn);
to mean that the underlying register gets assigned the inverse
transformation. This is used, for example, in the handling of
non-local gotos. */
- new = instantiate_new_reg (SET_DEST (set), &offset);
- if (new)
+ new_rtx = instantiate_new_reg (SET_DEST (set), &offset);
+ if (new_rtx)
{
start_sequence ();
for_each_rtx (&SET_SRC (set), instantiate_virtual_regs_in_rtx, NULL);
- x = simplify_gen_binary (PLUS, GET_MODE (new), SET_SRC (set),
+ x = simplify_gen_binary (PLUS, GET_MODE (new_rtx), SET_SRC (set),
GEN_INT (-offset));
- x = force_operand (x, new);
- if (x != new)
- emit_move_insn (new, x);
+ x = force_operand (x, new_rtx);
+ if (x != new_rtx)
+ emit_move_insn (new_rtx, x);
seq = get_insns ();
end_sequence ();
new add insn. The difference between this and falling through
to the generic case is avoiding a new pseudo and eliminating a
move insn in the initial rtl stream. */
- new = instantiate_new_reg (SET_SRC (set), &offset);
- if (new && offset != 0
+ new_rtx = instantiate_new_reg (SET_SRC (set), &offset);
+ if (new_rtx && offset != 0
&& REG_P (SET_DEST (set))
&& REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
{
start_sequence ();
x = expand_simple_binop (GET_MODE (SET_DEST (set)), PLUS,
- new, GEN_INT (offset), SET_DEST (set),
+ new_rtx, GEN_INT (offset), SET_DEST (set),
1, OPTAB_LIB_WIDEN);
if (x != SET_DEST (set))
emit_move_insn (SET_DEST (set), x);
&& recog_data.operand_loc[1] == &XEXP (SET_SRC (set), 0)
&& recog_data.operand_loc[2] == &XEXP (SET_SRC (set), 1)
&& GET_CODE (recog_data.operand[2]) == CONST_INT
- && (new = instantiate_new_reg (recog_data.operand[1], &offset)))
+ && (new_rtx = instantiate_new_reg (recog_data.operand[1], &offset)))
{
offset += INTVAL (recog_data.operand[2]);
&& REGNO (SET_DEST (set)) > LAST_VIRTUAL_REGISTER)
{
start_sequence ();
- emit_move_insn (SET_DEST (set), new);
+ emit_move_insn (SET_DEST (set), new_rtx);
seq = get_insns ();
end_sequence ();
/* Using validate_change and apply_change_group here leaves
recog_data in an invalid state. Since we know exactly what
we want to check, do those two by hand. */
- if (safe_insn_predicate (insn_code, 1, new)
+ if (safe_insn_predicate (insn_code, 1, new_rtx)
&& safe_insn_predicate (insn_code, 2, x))
{
- *recog_data.operand_loc[1] = recog_data.operand[1] = new;
+ *recog_data.operand_loc[1] = recog_data.operand[1] = new_rtx;
*recog_data.operand_loc[2] = recog_data.operand[2] = x;
any_change = true;
break;
case REG:
- new = instantiate_new_reg (x, &offset);
- if (new == NULL)
+ new_rtx = instantiate_new_reg (x, &offset);
+ if (new_rtx == NULL)
continue;
if (offset == 0)
- x = new;
+ x = new_rtx;
else
{
start_sequence ();
/* ??? Recognize address_operand and/or "p" constraints
to see if (plus new offset) is a valid before we put
this through expand_simple_binop. */
- x = expand_simple_binop (GET_MODE (x), PLUS, new,
+ x = expand_simple_binop (GET_MODE (x), PLUS, new_rtx,
GEN_INT (offset), NULL_RTX,
1, OPTAB_LIB_WIDEN);
seq = get_insns ();
break;
case SUBREG:
- new = instantiate_new_reg (SUBREG_REG (x), &offset);
- if (new == NULL)
+ new_rtx = instantiate_new_reg (SUBREG_REG (x), &offset);
+ if (new_rtx == NULL)
continue;
if (offset != 0)
{
start_sequence ();
- new = expand_simple_binop (GET_MODE (new), PLUS, new,
+ new_rtx = expand_simple_binop (GET_MODE (new_rtx), PLUS, new_rtx,
GEN_INT (offset), NULL_RTX,
1, OPTAB_LIB_WIDEN);
seq = get_insns ();
end_sequence ();
emit_insn_before (seq, insn);
}
- x = simplify_gen_subreg (recog_data.operand_mode[i], new,
- GET_MODE (new), SUBREG_BYTE (x));
+ x = simplify_gen_subreg (recog_data.operand_mode[i], new_rtx,
+ GET_MODE (new_rtx), SUBREG_BYTE (x));
+ gcc_assert (x);
break;
default:
instantiate_expr (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
{
tree t = *tp;
- if (! EXPR_P (t) && ! GIMPLE_STMT_P (t))
+ if (! EXPR_P (t))
{
*walk_subtrees = 0;
if (DECL_P (t) && DECL_RTL_SET_P (t))
static void
instantiate_decls (tree fndecl)
{
- tree decl;
+ tree decl, t, next;
/* Process all parameters of the function. */
for (decl = DECL_ARGUMENTS (fndecl); decl; decl = TREE_CHAIN (decl))
/* Now process all variables defined in the function or its subblocks. */
instantiate_decls_1 (DECL_INITIAL (fndecl));
+
+ t = cfun->local_decls;
+ cfun->local_decls = NULL_TREE;
+ for (; t; t = next)
+ {
+ next = TREE_CHAIN (t);
+ decl = TREE_VALUE (t);
+ if (DECL_RTL_SET_P (decl))
+ instantiate_decl_rtl (DECL_RTL (decl));
+ ggc_free (t);
+ }
}
/* Pass through the INSNS of function FNDECL and convert virtual register
bool
use_register_for_decl (const_tree decl)
{
+ if (!targetm.calls.allocate_stack_slots_for_args())
+ return true;
+
/* Honor volatile. */
if (TREE_SIDE_EFFECTS (decl))
return false;
/* If struct value address is treated as the first argument, make it so. */
if (aggregate_value_p (DECL_RESULT (fndecl), fndecl)
- && ! current_function_returns_pcc_struct
+ && ! cfun->returns_pcc_struct
&& targetm.calls.struct_value_rtx (TREE_TYPE (fndecl), 1) == 0)
{
tree type = build_pointer_type (TREE_TYPE (fntype));
memset (data, 0, sizeof (*data));
- /* NAMED_ARG is a mis-nomer. We really mean 'non-varadic'. */
- if (!current_function_stdarg)
- data->named_arg = 1; /* No varadic parms. */
+ /* NAMED_ARG is a misnomer. We really mean 'non-variadic'. */
+ if (!cfun->stdarg)
+ data->named_arg = 1; /* No variadic parms. */
else if (TREE_CHAIN (parm))
- data->named_arg = 1; /* Not the last non-varadic parm. */
+ data->named_arg = 1; /* Not the last non-variadic parm. */
else if (targetm.calls.strict_argument_naming (&all->args_so_far))
- data->named_arg = 1; /* Only varadic ones are unnamed. */
+ data->named_arg = 1; /* Only variadic ones are unnamed. */
else
- data->named_arg = 0; /* Treat as varadic. */
+ data->named_arg = 0; /* Treat as variadic. */
nominal_type = TREE_TYPE (parm);
passed_type = DECL_ARG_TYPE (parm);
entry_parm ? data->partial : 0, current_function_decl,
&all->stack_args_size, &data->locate);
+ /* Update parm_stack_boundary if this parameter is passed in the
+ stack. */
+ if (!in_regs && crtl->parm_stack_boundary < data->locate.boundary)
+ crtl->parm_stack_boundary = data->locate.boundary;
+
/* Adjust offsets to include the pretend args. */
pretend_bytes = all->extra_pretend_bytes - pretend_bytes;
data->locate.slot_offset.constant += pretend_bytes;
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))
+ set_mem_size (stack_parm, GEN_INT (GET_MODE_SIZE (data->promoted_mode)));
boundary = data->locate.boundary;
align = BITS_PER_UNIT;
data->entry_parm = entry_parm;
}
+/* A subroutine of assign_parms. Reconstitute any values which were
+ passed in multiple registers and would fit in a single register. */
+
+static void
+assign_parm_remove_parallels (struct assign_parm_data_one *data)
+{
+ rtx entry_parm = data->entry_parm;
+
+ /* Convert the PARALLEL to a REG of the same mode as the parallel.
+ This can be done with register operations rather than on the
+ stack, even if we will store the reconstituted parameter on the
+ stack later. */
+ if (GET_CODE (entry_parm) == PARALLEL && GET_MODE (entry_parm) != BLKmode)
+ {
+ rtx parmreg = gen_reg_rtx (GET_MODE (entry_parm));
+ emit_group_store (parmreg, entry_parm, NULL_TREE,
+ GET_MODE_SIZE (GET_MODE (entry_parm)));
+ entry_parm = parmreg;
+ }
+
+ data->entry_parm = entry_parm;
+}
+
/* A subroutine of assign_parms. Adjust DATA->STACK_RTL such that it's
always valid and properly aligned. */
/* If stack protection is in effect for this function, don't leave any
pointers in their passed stack slots. */
- else if (cfun->stack_protect_guard
+ else if (crtl->stack_protect_guard
&& (flag_stack_protect == 2
|| data->passed_pointer
|| POINTER_TYPE_P (data->nominal_type)))
{
if (data->nominal_mode == BLKmode)
return true;
- if (GET_CODE (data->entry_parm) == PARALLEL)
+ if (GET_MODE (data->entry_parm) == BLKmode)
return true;
#ifdef BLOCK_REG_PADDING
rtx stack_parm = data->stack_parm;
HOST_WIDE_INT size;
HOST_WIDE_INT size_stored;
- rtx orig_entry_parm = entry_parm;
if (GET_CODE (entry_parm) == PARALLEL)
entry_parm = emit_group_move_into_temps (entry_parm);
- /* If we've a non-block object that's nevertheless passed in parts,
- reconstitute it in register operations rather than on the stack. */
- if (GET_CODE (entry_parm) == PARALLEL
- && data->nominal_mode != BLKmode)
- {
- rtx elt0 = XEXP (XVECEXP (orig_entry_parm, 0, 0), 0);
-
- if ((XVECLEN (entry_parm, 0) > 1
- || hard_regno_nregs[REGNO (elt0)][GET_MODE (elt0)] > 1)
- && use_register_for_decl (parm))
- {
- rtx parmreg = gen_reg_rtx (data->nominal_mode);
-
- push_to_sequence2 (all->first_conversion_insn,
- all->last_conversion_insn);
-
- /* For values returned in multiple registers, handle possible
- incompatible calls to emit_group_store.
-
- For example, the following would be invalid, and would have to
- be fixed by the conditional below:
-
- emit_group_store ((reg:SF), (parallel:DF))
- emit_group_store ((reg:SI), (parallel:DI))
-
- An example of this are doubles in e500 v2:
- (parallel:DF (expr_list (reg:SI) (const_int 0))
- (expr_list (reg:SI) (const_int 4))). */
- if (data->nominal_mode != data->passed_mode)
- {
- rtx t = gen_reg_rtx (GET_MODE (entry_parm));
- emit_group_store (t, entry_parm, NULL_TREE,
- GET_MODE_SIZE (GET_MODE (entry_parm)));
- convert_move (parmreg, t, 0);
- }
- else
- emit_group_store (parmreg, entry_parm, data->nominal_type,
- int_size_in_bytes (data->nominal_type));
-
- all->first_conversion_insn = get_insns ();
- all->last_conversion_insn = get_last_insn ();
- end_sequence ();
-
- SET_DECL_RTL (parm, parmreg);
- return;
- }
- }
-
size = int_size_in_bytes (data->passed_type);
size_stored = CEIL_ROUND (size, UNITS_PER_WORD);
if (stack_parm == 0)
else
SET_DECL_RTL (parm, parmreg);
+ assign_parm_remove_parallels (data);
+
/* Copy the value into the register. */
if (data->nominal_mode != data->passed_mode
|| promoted_nominal_mode != data->promoted_mode)
execution. */
bool to_conversion = false;
+ assign_parm_remove_parallels (data);
+
if (data->promoted_mode != data->nominal_mode)
{
/* Conversion is required. */
continue;
}
- if (current_function_stdarg && !TREE_CHAIN (parm))
+ /* Estimate stack alignment from parameter alignment. */
+ if (SUPPORTS_STACK_ALIGNMENT)
+ {
+ unsigned int align = FUNCTION_ARG_BOUNDARY (data.promoted_mode,
+ data.passed_type);
+ if (TYPE_ALIGN (data.nominal_type) > align)
+ align = TYPE_ALIGN (data.passed_type);
+ if (crtl->stack_alignment_estimated < align)
+ {
+ gcc_assert (!crtl->stack_realign_processed);
+ crtl->stack_alignment_estimated = align;
+ }
+ }
+
+ if (cfun->stdarg && !TREE_CHAIN (parm))
assign_parms_setup_varargs (&all, &data, false);
/* Find out where the parameter arrives in this function. */
now that all parameters have been copied out of hard registers. */
emit_insn (all.first_conversion_insn);
+ /* Estimate reload stack alignment from scalar return mode. */
+ if (SUPPORTS_STACK_ALIGNMENT)
+ {
+ if (DECL_RESULT (fndecl))
+ {
+ tree type = TREE_TYPE (DECL_RESULT (fndecl));
+ enum machine_mode mode = TYPE_MODE (type);
+
+ if (mode != BLKmode
+ && mode != VOIDmode
+ && !AGGREGATE_TYPE_P (type))
+ {
+ unsigned int align = GET_MODE_ALIGNMENT (mode);
+ if (crtl->stack_alignment_estimated < align)
+ {
+ gcc_assert (!crtl->stack_realign_processed);
+ crtl->stack_alignment_estimated = align;
+ }
+ }
+ }
+ }
+
/* If we are receiving a struct value address as the first argument, set up
the RTL for the function result. As this might require code to convert
the transmitted address to Pmode, we do this here to ensure that possible
else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
&& !TYPE_SIZES_GIMPLIFIED (t))
{
- gimplify_type_sizes (t, (tree *) data);
+ gimplify_type_sizes (t, (gimple_seq *) data);
*walk_subtrees = 1;
}
}
/* Gimplify the parameter list for current_function_decl. This involves
evaluating SAVE_EXPRs of variable sized parameters and generating code
- to implement callee-copies reference parameters. Returns a list of
- statements to add to the beginning of the function, or NULL if nothing
- to do. */
+ to implement callee-copies reference parameters. Returns a sequence of
+ statements to add to the beginning of the function. */
-tree
+gimple_seq
gimplify_parameters (void)
{
struct assign_parm_data_all all;
- tree fnargs, parm, stmts = NULL;
+ tree fnargs, parm;
+ gimple_seq stmts = NULL;
assign_parms_initialize_all (&all);
fnargs = assign_parms_augmented_arg_list (&all);
walk_tree_without_duplicates (&data.passed_type,
gimplify_parm_type, &stmts);
- if (!TREE_CONSTANT (DECL_SIZE (parm)))
+ if (TREE_CODE (DECL_SIZE_UNIT (parm)) != INTEGER_CST)
{
gimplify_one_sizepos (&DECL_SIZE (parm), &stmts);
gimplify_one_sizepos (&DECL_SIZE_UNIT (parm), &stmts);
{
tree local, t;
- /* For constant sized objects, this is trivial; for
+ /* For constant-sized objects, this is trivial; for
variable-sized objects, we have to play games. */
- if (TREE_CONSTANT (DECL_SIZE (parm)))
+ if (TREE_CODE (DECL_SIZE_UNIT (parm)) == INTEGER_CST
+ && !(flag_stack_check == GENERIC_STACK_CHECK
+ && compare_tree_int (DECL_SIZE_UNIT (parm),
+ STACK_CHECK_MAX_VAR_SIZE) > 0))
{
local = create_tmp_var (type, get_name (parm));
DECL_IGNORED_P (local) = 0;
t = built_in_decls[BUILT_IN_ALLOCA];
t = build_call_expr (t, 1, DECL_SIZE_UNIT (parm));
t = fold_convert (ptr_type, t);
- t = build_gimple_modify_stmt (addr, t);
+ t = build2 (MODIFY_EXPR, TREE_TYPE (addr), addr, t);
gimplify_and_add (t, &stmts);
}
- t = build_gimple_modify_stmt (local, parm);
- gimplify_and_add (t, &stmts);
+ gimplify_assign (local, parm, &stmts);
SET_DECL_VALUE_EXPR (parm, local);
DECL_HAS_VALUE_EXPR_P (parm) = 1;
where_pad = FUNCTION_ARG_PADDING (passed_mode, type);
boundary = FUNCTION_ARG_BOUNDARY (passed_mode, type);
locate->where_pad = where_pad;
+
+ /* Alignment can't exceed MAX_SUPPORTED_STACK_ALIGNMENT. */
+ if (boundary > MAX_SUPPORTED_STACK_ALIGNMENT)
+ boundary = MAX_SUPPORTED_STACK_ALIGNMENT;
+
locate->boundary = boundary;
+ if (SUPPORTS_STACK_ALIGNMENT)
+ {
+ /* stack_alignment_estimated can't change after stack has been
+ realigned. */
+ if (crtl->stack_alignment_estimated < boundary)
+ {
+ if (!crtl->stack_realign_processed)
+ crtl->stack_alignment_estimated = boundary;
+ else
+ {
+ /* If stack is realigned and stack alignment value
+ hasn't been finalized, it is OK not to increase
+ stack_alignment_estimated. The bigger alignment
+ requirement is recorded in stack_alignment_needed
+ below. */
+ gcc_assert (!crtl->stack_realign_finalized
+ && crtl->stack_realign_needed);
+ }
+ }
+ }
+
/* Remember if the outgoing parameter requires extra alignment on the
calling function side. */
- if (boundary > PREFERRED_STACK_BOUNDARY)
- boundary = PREFERRED_STACK_BOUNDARY;
- if (cfun->stack_alignment_needed < boundary)
- cfun->stack_alignment_needed = boundary;
+ if (crtl->stack_alignment_needed < boundary)
+ crtl->stack_alignment_needed = boundary;
+ if (crtl->max_used_stack_slot_alignment < crtl->stack_alignment_needed)
+ crtl->max_used_stack_slot_alignment = crtl->stack_alignment_needed;
+ if (crtl->preferred_stack_boundary < boundary)
+ crtl->preferred_stack_boundary = boundary;
#ifdef ARGS_GROW_DOWNWARD
locate->slot_offset.constant = -initial_offset_ptr->constant;
static bool in_dummy_function;
-/* Invoke the target hook when setting cfun. */
+/* Invoke the target hook when setting cfun. Update the optimization options
+ if the function uses different options than the default. */
static void
invoke_set_current_function_hook (tree fndecl)
{
if (!in_dummy_function)
- targetm.set_current_function (fndecl);
+ {
+ tree opts = ((fndecl)
+ ? DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl)
+ : optimization_default_node);
+
+ if (!opts)
+ opts = optimization_default_node;
+
+ /* Change optimization options if needed. */
+ if (optimization_current_node != opts)
+ {
+ optimization_current_node = opts;
+ cl_optimization_restore (TREE_OPTIMIZATION (opts));
+ }
+
+ targetm.set_current_function (fndecl);
+ }
}
/* cfun should never be set directly; use this function. */
}
}
-/* Keep track of the cfun stack. */
-
-typedef struct function *function_p;
-
-DEF_VEC_P(function_p);
-DEF_VEC_ALLOC_P(function_p,heap);
-
/* Initialized with NOGC, making this poisonous to the garbage collector. */
static VEC(function_p,heap) *cfun_stack;
-/* We save the value of in_system_header here when pushing the first
- function on the cfun stack, and we restore it from here when
- popping the last function. */
-
-static bool saved_in_system_header;
-
/* Push the current cfun onto the stack, and set cfun to new_cfun. */
void
push_cfun (struct function *new_cfun)
{
- if (cfun == NULL)
- saved_in_system_header = in_system_header;
VEC_safe_push (function_p, heap, cfun_stack, cfun);
- if (new_cfun)
- in_system_header = DECL_IN_SYSTEM_HEADER (new_cfun->decl);
set_cfun (new_cfun);
}
pop_cfun (void)
{
struct function *new_cfun = VEC_pop (function_p, cfun_stack);
- in_system_header = ((new_cfun == NULL) ? saved_in_system_header
- : DECL_IN_SYSTEM_HEADER (new_cfun->decl));
set_cfun (new_cfun);
}
tree result;
tree fntype = fndecl ? TREE_TYPE (fndecl) : NULL_TREE;
- cfun = ggc_alloc_cleared (sizeof (struct function));
-
- cfun->stack_alignment_needed = STACK_BOUNDARY;
- cfun->preferred_stack_boundary = STACK_BOUNDARY;
-
- current_function_funcdef_no = get_next_funcdef_no ();
+ cfun = GGC_CNEW (struct function);
cfun->function_frequency = FUNCTION_FREQUENCY_NORMAL;
if (init_machine_status)
cfun->machine = (*init_machine_status) ();
- if (fndecl != NULL)
+#ifdef OVERRIDE_ABI_FORMAT
+ OVERRIDE_ABI_FORMAT (fndecl);
+#endif
+
+ if (fndecl != NULL_TREE)
{
DECL_STRUCT_FUNCTION (fndecl) = cfun;
cfun->decl = fndecl;
+ current_function_funcdef_no = get_next_funcdef_no ();
result = DECL_RESULT (fndecl);
if (!abstract_p && aggregate_value_p (result, fndecl))
{
#ifdef PCC_STATIC_STRUCT_RETURN
- current_function_returns_pcc_struct = 1;
+ cfun->returns_pcc_struct = 1;
#endif
- current_function_returns_struct = 1;
+ cfun->returns_struct = 1;
}
- current_function_stdarg
+ cfun->stdarg
= (fntype
&& TYPE_ARG_TYPES (fntype) != 0
&& (TREE_VALUE (tree_last (TYPE_ARG_TYPES (fntype)))
void
push_struct_function (tree fndecl)
{
- if (cfun == NULL)
- saved_in_system_header = in_system_header;
VEC_safe_push (function_p, heap, cfun_stack, cfun);
- if (fndecl)
- in_system_header = DECL_IN_SYSTEM_HEADER (fndecl);
allocate_struct_function (fndecl, false);
}
init_emit ();
init_varasm_status ();
init_expr ();
+ default_rtl_profile ();
cse_not_expected = ! optimize;
/* Avoid expand_expr here, because we don't want guard_decl pulled
into registers unless absolutely necessary. And we know that
- cfun->stack_protect_guard is a local stack slot, so this skips
+ crtl->stack_protect_guard is a local stack slot, so this skips
all the fluff. */
- x = validize_mem (DECL_RTL (cfun->stack_protect_guard));
+ x = validize_mem (DECL_RTL (crtl->stack_protect_guard));
y = validize_mem (DECL_RTL (guard_decl));
/* Allow the target to copy from Y to X without leaking Y into a
/* Avoid expand_expr here, because we don't want guard_decl pulled
into registers unless absolutely necessary. And we know that
- cfun->stack_protect_guard is a local stack slot, so this skips
+ crtl->stack_protect_guard is a local stack slot, so this skips
all the fluff. */
- x = validize_mem (DECL_RTL (cfun->stack_protect_guard));
+ x = validize_mem (DECL_RTL (crtl->stack_protect_guard));
y = validize_mem (DECL_RTL (guard_decl));
/* Allow the target to compare Y with X without leaking either into
valid operands of arithmetic insns. */
init_recog_no_volatile ();
- current_function_profile
+ crtl->profile
= (profile_flag
&& ! DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (subr));
- current_function_limit_stack
+ crtl->limit_stack
= (stack_limit_rtx != NULL_RTX && ! DECL_NO_LIMIT_STACK (subr));
/* Make the label for return statements to jump to. Do not special
rtx value_address = 0;
#ifdef PCC_STATIC_STRUCT_RETURN
- if (current_function_returns_pcc_struct)
+ if (cfun->returns_pcc_struct)
{
int size = int_size_in_bytes (TREE_TYPE (DECL_RESULT (subr)));
value_address = assemble_static_space (size);
r_save = expand_expr (t_save, NULL_RTX, VOIDmode, EXPAND_WRITE);
r_save = convert_memory_address (Pmode, r_save);
- emit_move_insn (r_save, virtual_stack_vars_rtx);
+ emit_move_insn (r_save, targetm.builtin_setjmp_frame_value ());
update_nonlocal_goto_save_area ();
}
parm_birth_insn = get_last_insn ();
- if (current_function_profile)
+ if (crtl->profile)
{
#ifdef PROFILE_HOOK
PROFILE_HOOK (current_function_funcdef_no);
static void
do_clobber_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
{
- emit_insn (gen_rtx_CLOBBER (VOIDmode, reg));
+ emit_clobber (reg);
}
void
static void
do_use_return_reg (rtx reg, void *arg ATTRIBUTE_UNUSED)
{
- emit_insn (gen_rtx_USE (VOIDmode, reg));
+ emit_use (reg);
}
static void
/* If arg_pointer_save_area was referenced only from a nested
function, we will not have initialized it yet. Do that now. */
- if (arg_pointer_save_area && ! cfun->arg_pointer_save_area_init)
+ if (arg_pointer_save_area && ! crtl->arg_pointer_save_area_init)
get_arg_pointer_save_area ();
- /* If we are doing stack checking and this function makes calls,
+ /* If we are doing generic stack checking and this function makes calls,
do a stack probe at the start of the function to ensure we have enough
space for another stack frame. */
- if (flag_stack_check && ! STACK_CHECK_BUILTIN)
+ if (flag_stack_check == GENERIC_STACK_CHECK)
{
rtx insn, seq;
if (CALL_P (insn))
{
start_sequence ();
- probe_stack_range (STACK_CHECK_PROTECT,
+ probe_stack_range (STACK_OLD_CHECK_PROTECT,
GEN_INT (STACK_CHECK_MAX_FRAME_SIZE));
seq = get_insns ();
end_sequence ();
If returning a structure PCC style,
the caller also depends on this value.
- And current_function_returns_pcc_struct is not necessarily set. */
- if (current_function_returns_struct
- || current_function_returns_pcc_struct)
+ And cfun->returns_pcc_struct is not necessarily set. */
+ if (cfun->returns_struct
+ || cfun->returns_pcc_struct)
{
rtx value_address = DECL_RTL (DECL_RESULT (current_function_decl));
tree type = TREE_TYPE (DECL_RESULT (current_function_decl));
emit_insn (gen_blockage ());
/* If stack protection is enabled for this function, check the guard. */
- if (cfun->stack_protect_guard)
+ if (crtl->stack_protect_guard)
stack_protect_epilogue ();
/* If we had calls to alloca, and this machine needs
an accurate stack pointer to exit the function,
insert some code to save and restore the stack pointer. */
if (! EXIT_IGNORE_STACK
- && current_function_calls_alloca)
+ && cfun->calls_alloca)
{
rtx tem = 0;
arg_pointer_save_area = ret;
}
- if (! cfun->arg_pointer_save_area_init)
+ if (! crtl->arg_pointer_save_area_init)
{
rtx seq;
generated stack slot may not be a valid memory address, so we
have to check it and fix it if necessary. */
start_sequence ();
- emit_move_insn (validize_mem (ret), virtual_incoming_args_rtx);
+ emit_move_insn (validize_mem (ret),
+ crtl->args.internal_arg_pointer);
seq = get_insns ();
end_sequence ();
#endif
edge_iterator ei;
+ rtl_profile_for_bb (ENTRY_BLOCK_PTR);
#ifdef HAVE_prologue
if (HAVE_prologue)
{
/* Insert an explicit USE for the frame pointer
if the profiling is on and the frame pointer is required. */
- if (current_function_profile && frame_pointer_needed)
- emit_insn (gen_rtx_USE (VOIDmode, hard_frame_pointer_rtx));
+ if (crtl->profile && frame_pointer_needed)
+ emit_use (hard_frame_pointer_rtx);
/* Retain a map of the prologue insns. */
record_insns (seq, &prologue);
/* Ensure that instructions are not moved into the prologue when
profiling is on. The call to the profiling routine can be
emitted within the live range of a call-clobbered register. */
- if (current_function_profile)
+ if (crtl->profile)
emit_insn (gen_blockage ());
#endif
if (e == NULL)
goto epilogue_done;
+ rtl_profile_for_bb (EXIT_BLOCK_PTR);
#ifdef HAVE_return
if (optimize && HAVE_return)
{
cfg_layout_finalize ();
}
epilogue_done:
+ default_rtl_profile ();
if (inserted)
{
rtx op = SET_SRC (p_sets[0]);
int ninputs = ASM_OPERANDS_INPUT_LENGTH (op);
rtvec inputs = ASM_OPERANDS_INPUT_VEC (op);
- bool *output_matched = alloca (noutputs * sizeof (bool));
+ bool *output_matched = XALLOCAVEC (bool, noutputs);
memset (output_matched, 0, noutputs * sizeof (bool));
for (i = 0; i < ninputs; i++)
emit_insn_before (insns, insn);
/* Now replace all mentions of the input with output. We can't
- just replace the occurence in inputs[i], as the register might
+ just replace the occurrence in inputs[i], as the register might
also be used in some other input (or even in an address of an
output), which would mean possibly increasing the number of
inputs by one (namely 'output' in addition), which might pose
Here 'input' is used in two occurrences as input (once for the
input operand, once for the address in the second output operand).
- If we would replace only the occurence of the input operand (to
+ If we would replace only the occurrence of the input operand (to
make the matching) we would be left with this:
output = input
rtx insn, pat, *p_sets;
int noutputs;
- if (!cfun->has_asm_statement)
+ if (!crtl->has_asm_statement)
return 0;
df_set_flags (DF_DEFER_INSN_RESCAN);