update_sjlj_context ();
}
\f
-/* Return an rtx representing the address of an area of memory dynamically
- pushed on the stack.
+/* Return an rtx doing runtime alignment to REQUIRED_ALIGN on TARGET. */
+static rtx
+align_dynamic_address (rtx target, unsigned required_align)
+{
+ /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
+ but we know it can't. So add ourselves and then do
+ TRUNC_DIV_EXPR. */
+ target = expand_binop (Pmode, add_optab, target,
+ gen_int_mode (required_align / BITS_PER_UNIT - 1,
+ Pmode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
+ gen_int_mode (required_align / BITS_PER_UNIT,
+ Pmode),
+ NULL_RTX, 1);
+ target = expand_mult (Pmode, target,
+ gen_int_mode (required_align / BITS_PER_UNIT,
+ Pmode),
+ NULL_RTX, 1);
- Any required stack pointer alignment is preserved.
+ return target;
+}
- SIZE is an rtx representing the size of the area.
+/* Return an rtx through *PSIZE, representing the size of an area of memory to
+ be dynamically pushed on the stack.
+
+ *PSIZE is an rtx representing the size of the area.
SIZE_ALIGN is the alignment (in bits) that we know SIZE has. This
- parameter may be zero. If so, a proper value will be extracted
+ parameter may be zero. If so, a proper value will be extracted
from SIZE if it is constant, otherwise BITS_PER_UNIT will be assumed.
REQUIRED_ALIGN is the alignment (in bits) required for the region
of memory.
- If CANNOT_ACCUMULATE is set to TRUE, the caller guarantees that the
- stack space allocated by the generated code cannot be added with itself
- in the course of the execution of the function. It is always safe to
- pass FALSE here and the following criterion is sufficient in order to
- pass TRUE: every path in the CFG that starts at the allocation point and
- loops to it executes the associated deallocation code. */
-
-rtx
-allocate_dynamic_stack_space (rtx size, unsigned size_align,
- unsigned required_align, bool cannot_accumulate)
+ If PSTACK_USAGE_SIZE is not NULL it points to a value that is increased for
+ the additional size returned. */
+void
+get_dynamic_stack_size (rtx *psize, unsigned size_align,
+ unsigned required_align,
+ HOST_WIDE_INT *pstack_usage_size)
{
- HOST_WIDE_INT stack_usage_size = -1;
- rtx_code_label *final_label;
- rtx final_target, target;
- unsigned extra;
-
- /* If we're asking for zero bytes, it doesn't matter what we point
- to since we can't dereference it. But return a reasonable
- address anyway. */
- if (size == const0_rtx)
- return virtual_stack_dynamic_rtx;
-
- /* Otherwise, show we're calling alloca or equivalent. */
- cfun->calls_alloca = 1;
-
- /* If stack usage info is requested, look into the size we are passed.
- We need to do so this early to avoid the obfuscation that may be
- introduced later by the various alignment operations. */
- if (flag_stack_usage_info)
- {
- if (CONST_INT_P (size))
- stack_usage_size = INTVAL (size);
- else if (REG_P (size))
- {
- /* Look into the last emitted insn and see if we can deduce
- something for the register. */
- rtx_insn *insn;
- rtx set, note;
- insn = get_last_insn ();
- if ((set = single_set (insn)) && rtx_equal_p (SET_DEST (set), size))
- {
- if (CONST_INT_P (SET_SRC (set)))
- stack_usage_size = INTVAL (SET_SRC (set));
- else if ((note = find_reg_equal_equiv_note (insn))
- && CONST_INT_P (XEXP (note, 0)))
- stack_usage_size = INTVAL (XEXP (note, 0));
- }
- }
-
- /* If the size is not constant, we can't say anything. */
- if (stack_usage_size == -1)
- {
- current_function_has_unbounded_dynamic_stack_size = 1;
- stack_usage_size = 0;
- }
- }
+ unsigned extra = 0;
+ rtx size = *psize;
/* Ensure the size is in the proper mode. */
if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
size = convert_to_mode (Pmode, size, 1);
- /* Adjust SIZE_ALIGN, if needed. */
if (CONST_INT_P (size))
{
unsigned HOST_WIDE_INT lsb;
size = plus_constant (Pmode, size, extra);
size = force_operand (size, NULL_RTX);
- if (flag_stack_usage_info)
- stack_usage_size += extra;
+ if (flag_stack_usage_info && pstack_usage_size)
+ *pstack_usage_size += extra;
if (extra && size_align > BITS_PER_UNIT)
size_align = BITS_PER_UNIT;
{
size = round_push (size);
- if (flag_stack_usage_info)
+ if (flag_stack_usage_info && pstack_usage_size)
{
int align = crtl->preferred_stack_boundary / BITS_PER_UNIT;
- stack_usage_size = (stack_usage_size + align - 1) / align * align;
+ *pstack_usage_size =
+ (*pstack_usage_size + align - 1) / align * align;
}
}
+ *psize = size;
+}
+
+/* Return an rtx representing the address of an area of memory dynamically
+ pushed on the stack.
+
+ Any required stack pointer alignment is preserved.
+
+ SIZE is an rtx representing the size of the area.
+
+ SIZE_ALIGN is the alignment (in bits) that we know SIZE has. This
+ parameter may be zero. If so, a proper value will be extracted
+ from SIZE if it is constant, otherwise BITS_PER_UNIT will be assumed.
+
+ REQUIRED_ALIGN is the alignment (in bits) required for the region
+ of memory.
+
+ If CANNOT_ACCUMULATE is set to TRUE, the caller guarantees that the
+ stack space allocated by the generated code cannot be added with itself
+ in the course of the execution of the function. It is always safe to
+ pass FALSE here and the following criterion is sufficient in order to
+ pass TRUE: every path in the CFG that starts at the allocation point and
+ loops to it executes the associated deallocation code. */
+
+rtx
+allocate_dynamic_stack_space (rtx size, unsigned size_align,
+ unsigned required_align, bool cannot_accumulate)
+{
+ HOST_WIDE_INT stack_usage_size = -1;
+ rtx_code_label *final_label;
+ rtx final_target, target;
+
+ /* If we're asking for zero bytes, it doesn't matter what we point
+ to since we can't dereference it. But return a reasonable
+ address anyway. */
+ if (size == const0_rtx)
+ return virtual_stack_dynamic_rtx;
+
+ /* Otherwise, show we're calling alloca or equivalent. */
+ cfun->calls_alloca = 1;
+
+ /* If stack usage info is requested, look into the size we are passed.
+ We need to do so this early to avoid the obfuscation that may be
+ introduced later by the various alignment operations. */
+ if (flag_stack_usage_info)
+ {
+ if (CONST_INT_P (size))
+ stack_usage_size = INTVAL (size);
+ else if (REG_P (size))
+ {
+ /* Look into the last emitted insn and see if we can deduce
+ something for the register. */
+ rtx_insn *insn;
+ rtx set, note;
+ insn = get_last_insn ();
+ if ((set = single_set (insn)) && rtx_equal_p (SET_DEST (set), size))
+ {
+ if (CONST_INT_P (SET_SRC (set)))
+ stack_usage_size = INTVAL (SET_SRC (set));
+ else if ((note = find_reg_equal_equiv_note (insn))
+ && CONST_INT_P (XEXP (note, 0)))
+ stack_usage_size = INTVAL (XEXP (note, 0));
+ }
+ }
+
+ /* If the size is not constant, we can't say anything. */
+ if (stack_usage_size == -1)
+ {
+ current_function_has_unbounded_dynamic_stack_size = 1;
+ stack_usage_size = 0;
+ }
+ }
+
+ get_dynamic_stack_size (&size, size_align, required_align, &stack_usage_size);
+
target = gen_reg_rtx (Pmode);
/* The size is supposed to be fully adjusted at this point so record it
target = final_target;
}
- /* CEIL_DIV_EXPR needs to worry about the addition overflowing,
- but we know it can't. So add ourselves and then do
- TRUNC_DIV_EXPR. */
- target = expand_binop (Pmode, add_optab, target,
- gen_int_mode (required_align / BITS_PER_UNIT - 1,
- Pmode),
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- target = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, target,
- gen_int_mode (required_align / BITS_PER_UNIT, Pmode),
- NULL_RTX, 1);
- target = expand_mult (Pmode, target,
- gen_int_mode (required_align / BITS_PER_UNIT, Pmode),
- NULL_RTX, 1);
+ target = align_dynamic_address (target, required_align);
/* Now that we've committed to a return value, mark its alignment. */
mark_reg_pointer (target, required_align);
return target;
}
+
+/* Return an rtx representing the address of an area of memory already
+ statically pushed onto the stack in the virtual stack vars area. (It is
+ assumed that the area is allocated in the function prologue.)
+
+ Any required stack pointer alignment is preserved.
+
+ OFFSET is the offset of the area into the virtual stack vars area.
+
+ REQUIRED_ALIGN is the alignment (in bits) required for the region
+ of memory. */
+
+rtx
+get_dynamic_stack_base (HOST_WIDE_INT offset, unsigned required_align)
+{
+ rtx target;
+
+ if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
+ crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+
+ target = gen_reg_rtx (Pmode);
+ emit_move_insn (target, virtual_stack_vars_rtx);
+ target = expand_binop (Pmode, add_optab, target,
+ gen_int_mode (offset, Pmode),
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ target = align_dynamic_address (target, required_align);
+
+ /* Now that we've committed to a return value, mark its alignment. */
+ mark_reg_pointer (target, required_align);
+
+ return target;
+}
\f
/* A front end may want to override GCC's stack checking by providing a
run-time routine to call to check the stack, so provide a mechanism for