@@ -2010,6 +2010,7 @@ enum global_rtl_index
GR_VIRTUAL_STACK_DYNAMIC,
GR_VIRTUAL_OUTGOING_ARGS,
GR_VIRTUAL_CFA,
+ GR_VIRTUAL_PREFERRED_STACK_BOUNDARY,
GR_MAX
};
@@ -2157,7 +2158,18 @@ extern rtx gen_rtx_MEM (enum machine_mod
#define VIRTUAL_CFA_REGNUM ((FIRST_VIRTUAL_REGISTER) + 4)
-#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 4)
+#define LAST_VIRTUAL_POINTER_REGISTER ((FIRST_VIRTUAL_REGISTER) + 4)
+
+/* This is replaced by crtl->preferred_stack_boundary / BITS_PER_UNIT
+ when finalized. */
+
+#define virtual_preferred_stack_boundary_rtx \
+ (global_rtl[GR_VIRTUAL_PREFERRED_STACK_BOUNDARY])
+
+#define VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM \
+ ((FIRST_VIRTUAL_REGISTER) + 5)
+
+#define LAST_VIRTUAL_REGISTER ((FIRST_VIRTUAL_REGISTER) + 5)
/* Nonzero if REGNUM is a pointer into the stack frame. */
#define REGNO_PTR_FRAME_P(REGNUM) \
@@ -2166,7 +2178,7 @@ extern rtx gen_rtx_MEM (enum machine_mod
|| (REGNUM) == HARD_FRAME_POINTER_REGNUM \
|| (REGNUM) == ARG_POINTER_REGNUM \
|| ((REGNUM) >= FIRST_VIRTUAL_REGISTER \
- && (REGNUM) <= LAST_VIRTUAL_REGISTER))
+ && (REGNUM) <= LAST_VIRTUAL_POINTER_REGISTER))
/* REGNUM never really appearing in the INSN stream. */
#define INVALID_REGNUM (~(unsigned int) 0)
@@ -1405,6 +1405,11 @@ instantiate_new_reg (rtx x, HOST_WIDE_IN
#endif
offset = cfa_offset;
}
+ else if (x == virtual_preferred_stack_boundary_rtx)
+ {
+ new_rtx = GEN_INT (crtl->preferred_stack_boundary / BITS_PER_UNIT);
+ offset = 0;
+ }
else
return NULL_RTX;
@@ -5376,6 +5376,8 @@ init_virtual_regs (void)
regno_reg_rtx[VIRTUAL_STACK_DYNAMIC_REGNUM] = virtual_stack_dynamic_rtx;
regno_reg_rtx[VIRTUAL_OUTGOING_ARGS_REGNUM] = virtual_outgoing_args_rtx;
regno_reg_rtx[VIRTUAL_CFA_REGNUM] = virtual_cfa_rtx;
+ regno_reg_rtx[VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM]
+ = virtual_preferred_stack_boundary_rtx;
}
@@ -5698,6 +5700,8 @@ init_emit_regs (void)
virtual_outgoing_args_rtx =
gen_raw_REG (Pmode, VIRTUAL_OUTGOING_ARGS_REGNUM);
virtual_cfa_rtx = gen_raw_REG (Pmode, VIRTUAL_CFA_REGNUM);
+ virtual_preferred_stack_boundary_rtx =
+ gen_raw_REG (Pmode, VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM);
/* Initialize RTL for commonly used hard registers. These are
copied into regno_reg_rtx as we begin to compile each function. */
@@ -915,29 +915,46 @@ anti_adjust_stack (rtx adjust)
static rtx
round_push (rtx size)
{
- int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+ rtx align_rtx, alignm1_rtx;
- if (align == 1)
- return size;
-
- if (CONST_INT_P (size))
+ if (!SUPPORTS_STACK_ALIGNMENT
+ || crtl->preferred_stack_boundary == MAX_SUPPORTED_STACK_ALIGNMENT)
{
- HOST_WIDE_INT new_size = (INTVAL (size) + align - 1) / align * align;
+ int align = crtl->preferred_stack_boundary / BITS_PER_UNIT;
+
+ if (align == 1)
+ return size;
+
+ if (CONST_INT_P (size))
+ {
+ HOST_WIDE_INT new_size = (INTVAL (size) + align - 1) / align * align;
- if (INTVAL (size) != new_size)
- size = GEN_INT (new_size);
+ if (INTVAL (size) != new_size)
+ size = GEN_INT (new_size);
+ return size;
+ }
+
+ align_rtx = GEN_INT (align);
+ alignm1_rtx = GEN_INT (align - 1);
}
else
{
- /* 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. */
- size = expand_binop (Pmode, add_optab, size, GEN_INT (align - 1),
- NULL_RTX, 1, OPTAB_LIB_WIDEN);
- size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, GEN_INT (align),
- NULL_RTX, 1);
- size = expand_mult (Pmode, size, GEN_INT (align), NULL_RTX, 1);
- }
+ /* If crtl->preferred_stack_boundary might still grow, use
+ virtual_preferred_stack_boundary_rtx instead. This will be
+ substituted by the right value in vregs pass and optimized
+ during combine. */
+ align_rtx = virtual_preferred_stack_boundary_rtx;
+ alignm1_rtx = force_operand (plus_constant (align_rtx, -1), NULL_RTX);
+ }
+
+ /* 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. */
+ size = expand_binop (Pmode, add_optab, size, alignm1_rtx,
+ NULL_RTX, 1, OPTAB_LIB_WIDEN);
+ size = expand_divmod (0, TRUNC_DIV_EXPR, Pmode, size, align_rtx,
+ NULL_RTX, 1);
+ size = expand_mult (Pmode, size, align_rtx, NULL_RTX, 1);
return size;
}
@@ -1144,9 +1161,9 @@ allocate_dynamic_stack_space (rtx size,
introduced later by the various alignment operations. */
if (flag_stack_usage)
{
- if (GET_CODE (size) == CONST_INT)
+ if (CONST_INT_P (size))
stack_usage_size = INTVAL (size);
- else if (GET_CODE (size) == REG)
+ else if (REG_P (size))
{
/* Look into the last emitted insn and see if we can deduce
something for the register. */
@@ -1154,10 +1171,10 @@ allocate_dynamic_stack_space (rtx size,
insn = get_last_insn ();
if ((set = single_set (insn)) && rtx_equal_p (SET_DEST (set), size))
{
- if (GET_CODE (SET_SRC (set)) == CONST_INT)
+ if (CONST_INT_P (SET_SRC (set)))
stack_usage_size = INTVAL (SET_SRC (set));
else if ((note = find_reg_equal_equiv_note (insn))
- && GET_CODE (XEXP (note, 0)) == CONST_INT)
+ && CONST_INT_P (XEXP (note, 0)))
stack_usage_size = INTVAL (XEXP (note, 0));
}
}
@@ -1177,7 +1194,8 @@ allocate_dynamic_stack_space (rtx size,
/* We can't attempt to minimize alignment necessary, because we don't
know the final value of preferred_stack_boundary yet while executing
this code. */
- crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
+ if (crtl->preferred_stack_boundary < PREFERRED_STACK_BOUNDARY)
+ crtl->preferred_stack_boundary = PREFERRED_STACK_BOUNDARY;
/* We will need to ensure that the address we return is aligned to
BIGGEST_ALIGNMENT. If STACK_DYNAMIC_OFFSET is defined, we don't
@@ -1195,7 +1213,7 @@ allocate_dynamic_stack_space (rtx size,
#if defined (STACK_DYNAMIC_OFFSET) || defined (STACK_POINTER_OFFSET)
#define MUST_ALIGN 1
#else
-#define MUST_ALIGN (PREFERRED_STACK_BOUNDARY < BIGGEST_ALIGNMENT)
+#define MUST_ALIGN (crtl->preferred_stack_boundary < BIGGEST_ALIGNMENT)
#endif
if (MUST_ALIGN)
@@ -1255,13 +1273,13 @@ allocate_dynamic_stack_space (rtx size,
insns. Since this is an extremely rare event, we have no reliable
way of knowing which systems have this problem. So we avoid even
momentarily mis-aligning the stack. */
- if (!known_align_valid || known_align % PREFERRED_STACK_BOUNDARY != 0)
+ if (!known_align_valid || known_align % MAX_SUPPORTED_STACK_ALIGNMENT != 0)
{
size = round_push (size);
if (flag_stack_usage)
{
- int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+ int align = crtl->preferred_stack_boundary / BITS_PER_UNIT;
stack_usage_size = (stack_usage_size + align - 1) / align * align;
}
}
@@ -1328,6 +1346,8 @@ allocate_dynamic_stack_space (rtx size,
else
#endif
{
+ int saved_stack_pointer_delta;
+
#ifndef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
#endif
@@ -1358,10 +1378,15 @@ allocate_dynamic_stack_space (rtx size,
emit_label (space_available);
}
+ saved_stack_pointer_delta = stack_pointer_delta;
if (flag_stack_check && STACK_CHECK_MOVING_SP)
anti_adjust_stack_and_probe (size, false);
else
anti_adjust_stack (size);
+ /* Even if size is constant, don't modify stack_pointer_delta.
+ The constant size alloca should preserve
+ crtl->preferred_stack_boundary alignment. */
+ stack_pointer_delta = saved_stack_pointer_delta;
#ifdef STACK_GROWS_DOWNWARD
emit_move_insn (target, virtual_stack_dynamic_rtx);
@@ -1572,7 +1597,7 @@ probe_stack_range (HOST_WIDE_INT first,
{
rtx addr;
- if (GET_CODE (temp) == CONST_INT)
+ if (CONST_INT_P (temp))
{
/* Use [base + disp} addressing mode if supported. */
HOST_WIDE_INT offset = INTVAL (temp);
@@ -1613,7 +1638,7 @@ anti_adjust_stack_and_probe (rtx size, b
/* If we have a constant small number of probes to generate, that's the
easy case. */
- if (GET_CODE (size) == CONST_INT && INTVAL (size) < 7 * PROBE_INTERVAL)
+ if (CONST_INT_P (size) && INTVAL (size) < 7 * PROBE_INTERVAL)
{
HOST_WIDE_INT isize = INTVAL (size), i;
bool first_probe = true;
@@ -2385,19 +2385,6 @@ expand_call (tree exp, rtx target, int i
preferred_unit_stack_boundary = preferred_stack_boundary / BITS_PER_UNIT;
- if (SUPPORTS_STACK_ALIGNMENT)
- {
- /* All variable sized adjustments must be multiple of preferred
- stack boundary. Stack alignment may change preferred stack
- boundary after variable sized adjustments have been made. We
- need to compensate it here. */
- unsigned HOST_WIDE_INT delta
- = ((stack_pointer_delta - pending_stack_adjust)
- % preferred_unit_stack_boundary);
- if (delta)
- anti_adjust_stack (GEN_INT (preferred_unit_stack_boundary - delta));
- }
-
/* We want to make two insn chains; one for a sibling call, the other
for a normal call. We will select one of the two chains after
initial RTL generation is complete. */
@@ -457,6 +457,9 @@ print_rtx (const_rtx in_rtx)
fprintf (outfile, " %d virtual-outgoing-args", value);
else if (value == VIRTUAL_CFA_REGNUM)
fprintf (outfile, " %d virtual-cfa", value);
+ else if (value == VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM)
+ fprintf (outfile, " %d virtual-preferred-stack-boundary",
+ value);
else
fprintf (outfile, " %d virtual-reg-%d", value,
value-FIRST_VIRTUAL_REGISTER);
@@ -916,7 +916,7 @@ extern int alpha_memory_latency;
#define NONSTRICT_REG_OK_FP_BASE_P(X) \
(REGNO (X) == 31 || REGNO (X) == 63 \
|| (REGNO (X) >= FIRST_PSEUDO_REGISTER \
- && REGNO (X) < LAST_VIRTUAL_REGISTER))
+ && REGNO (X) < LAST_VIRTUAL_POINTER_REGISTER))
/* Nonzero if X is a hard reg that can be used as a base reg. */
#define STRICT_REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
@@ -4067,7 +4067,7 @@ frv_emit_movsi (rtx dest, rtx src)
|| (GET_CODE (src) == REG
&& IN_RANGE_P (REGNO (src),
FIRST_VIRTUAL_REGISTER,
- LAST_VIRTUAL_REGISTER))))
+ LAST_VIRTUAL_POINTER_REGISTER))))
{
emit_insn (gen_rtx_SET (VOIDmode, dest, copy_to_mode_reg (SImode, src)));
return TRUE;
@@ -5851,7 +5851,8 @@ thumb1_legitimate_address_p (enum machin
&& (REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
|| REGNO (XEXP (x, 0)) == ARG_POINTER_REGNUM
|| (REGNO (XEXP (x, 0)) >= FIRST_VIRTUAL_REGISTER
- && REGNO (XEXP (x, 0)) <= LAST_VIRTUAL_REGISTER))
+ && REGNO (XEXP (x, 0))
+ <= LAST_VIRTUAL_POINTER_REGISTER))
&& GET_MODE_SIZE (mode) >= 4
&& GET_CODE (XEXP (x, 1)) == CONST_INT
&& (INTVAL (XEXP (x, 1)) & 3) == 0)
@@ -5489,7 +5489,7 @@ virtual_stack_registers_memory_p (rtx op
return false;
return (regnum >= FIRST_VIRTUAL_REGISTER
- && regnum <= LAST_VIRTUAL_REGISTER);
+ && regnum <= LAST_VIRTUAL_POINTER_REGISTER);
}
static bool
@@ -0,0 +1,34 @@
+/* PR middle-end/45234 */
+/* { dg-do run { target { { i?86-*-* x86_64-*-* } && ilp32 } } } */
+/* { dg-options "-mincoming-stack-boundary=2 -mpreferred-stack-boundary=2" } */
+
+#include "check.h"
+
+void
+__attribute__ ((noinline))
+bar (__float128 f)
+{
+ check (&f, __alignof__(f));
+}
+
+volatile int z = 6;
+
+int
+main (void)
+{
+ char *p = __builtin_alloca (z);
+
+ bar (0);
+
+ __builtin_strncpy (p, "good", 5);
+ if (__builtin_strncmp (p, "good", 5) != 0)
+ {
+#ifdef DEBUG
+ p[z - 1] = '\0';
+ printf ("Failed: %s != good\n", p);
+#endif
+ abort ();
+ }
+
+ return 0;
+}
@@ -0,0 +1,18 @@
+/* PR middle-end/45234 */
+/* { dg-do compile } */
+/* { dg-options "-march=i586" { target ilp32 } } */
+
+struct S { union { double b[4]; } a[18]; } s, a[5];
+void foo (struct S);
+struct S bar (struct S, struct S *, struct S);
+
+void
+foo (struct S arg)
+{
+}
+
+void
+baz (void)
+{
+ foo (bar (s, &a[1], a[2]));
+}