re PR middle-end/45234 (ICE in expand_call, at calls.c:2845 when passing aligned function argument from unaligned stack after alloca)

PR middle-end/45234
	* rtl.h (enum global_rtl_index): Add
	GR_VIRTUAL_PREFERRED_STACK_BOUNDARY.
	(LAST_VIRTUAL_POINTER_REGISTER): Define.
	(virtual_preferred_stack_boundary_rtx,
	VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM): Define.
	(LAST_VIRTUAL_REGISTER): Increase by one.
	(REGNO_PTR_FRAME_P): Use LAST_VIRTUAL_POINTER_REGISTER
	instead of LAST_VIRTUAL_REGISTER.
	* function.c (instantiate_new_reg): Handle
	virtual_preferred_stack_boundary_rtx.
	* emit-rtl.c (init_virtual_regs): Handle
	VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM.
	(init_emit_regs): Initialize virtual_preferred_stack_boundary_rtx.
	* explow.c (round_push): If crtl->preferred_stack_boundary
	is smaller than MAX_SUPPORTED_STACK_ALIGNMENT, use
	virtual_preferred_stack_boundary_rtx alignment instead of
	crtl->preferred_stack_boundary alignment.
	(allocate_dynamic_stack_space): Use CONST_INT_P and REG_P
	macros.  Never decrease crtl->preferred_stack_boundary,
	use crtl->preferred_stack_boundary or MAX_SUPPORTED_STACK_ALIGNMENT
	instead of PREFERRED_STACK_BOUNDARY.  Don't modify
	stack_pointer_delta in dynamic allocation, even when size
	is constant.
	(probe_stack_range, anti_adjust_stack_and_probe): Use CONST_INT_P
	macro.
	* print-rtl.c (print_rtx): Handle
	VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM.
	* config/alpha/alpha.h (NONSTRICT_REG_OK_FP_BASE_P): Use
	LAST_VIRTUAL_POINTER_REGISTER instead of LAST_VIRTUAL_REGISTER.
	* config/frv/frv.c (frv_emit_movsi): Likewise.
	* config/arm/arm.c (thumb1_legitimate_address_p): Likewise.
	* config/rs6000/rs6000.c (virtual_stack_registers_memory_p):
	Likewise.

	* gcc.dg/torture/stackalign/alloca-6.c: New test.
	* gcc.target/i386/pr45234.c: New test.

	Revert:
	2010-09-17  H.J. Lu  <hongjiu.lu@intel.com>

	PR middle-end/45234
	* calls.c (expand_call): Make sure that all variable sized
	adjustments are multiple of preferred stack boundary after
	stack alignment.

From-SVN: r164593
This commit is contained in:
Jakub Jelinek 2010-09-24 16:37:02 +02:00 committed by Jakub Jelinek
parent 3d1b7f135d
commit 32990d5bc2
14 changed files with 185 additions and 45 deletions

View File

@ -1,3 +1,48 @@
2010-09-24 Jakub Jelinek <jakub@redhat.com>
PR middle-end/45234
* rtl.h (enum global_rtl_index): Add
GR_VIRTUAL_PREFERRED_STACK_BOUNDARY.
(LAST_VIRTUAL_POINTER_REGISTER): Define.
(virtual_preferred_stack_boundary_rtx,
VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM): Define.
(LAST_VIRTUAL_REGISTER): Increase by one.
(REGNO_PTR_FRAME_P): Use LAST_VIRTUAL_POINTER_REGISTER
instead of LAST_VIRTUAL_REGISTER.
* function.c (instantiate_new_reg): Handle
virtual_preferred_stack_boundary_rtx.
* emit-rtl.c (init_virtual_regs): Handle
VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM.
(init_emit_regs): Initialize virtual_preferred_stack_boundary_rtx.
* explow.c (round_push): If crtl->preferred_stack_boundary
is smaller than MAX_SUPPORTED_STACK_ALIGNMENT, use
virtual_preferred_stack_boundary_rtx alignment instead of
crtl->preferred_stack_boundary alignment.
(allocate_dynamic_stack_space): Use CONST_INT_P and REG_P
macros. Never decrease crtl->preferred_stack_boundary,
use crtl->preferred_stack_boundary or MAX_SUPPORTED_STACK_ALIGNMENT
instead of PREFERRED_STACK_BOUNDARY. Don't modify
stack_pointer_delta in dynamic allocation, even when size
is constant.
(probe_stack_range, anti_adjust_stack_and_probe): Use CONST_INT_P
macro.
* print-rtl.c (print_rtx): Handle
VIRTUAL_PREFERRED_STACK_BOUNDARY_REGNUM.
* config/alpha/alpha.h (NONSTRICT_REG_OK_FP_BASE_P): Use
LAST_VIRTUAL_POINTER_REGISTER instead of LAST_VIRTUAL_REGISTER.
* config/frv/frv.c (frv_emit_movsi): Likewise.
* config/arm/arm.c (thumb1_legitimate_address_p): Likewise.
* config/rs6000/rs6000.c (virtual_stack_registers_memory_p):
Likewise.
Revert:
2010-09-17 H.J. Lu <hongjiu.lu@intel.com>
PR middle-end/45234
* calls.c (expand_call): Make sure that all variable sized
adjustments are multiple of preferred stack boundary after
stack alignment.
2010-09-24 Iain Sandoe <iains@gcc.gnu.org>
Dominique Dhumieres <dominiq@lps.ens.fr>

View File

@ -2385,19 +2385,6 @@ expand_call (tree exp, rtx target, int ignore)
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. */

View File

@ -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))

View File

@ -5855,7 +5855,8 @@ thumb1_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
&& (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)

View File

@ -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;

View File

@ -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

View File

@ -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. */

View File

@ -915,30 +915,47 @@ 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 (INTVAL (size) != new_size)
size = GEN_INT (new_size);
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);
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, rtx target, int known_align,
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, rtx target, int known_align,
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, rtx target, int known_align,
/* 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, rtx target, int known_align,
#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, rtx target, int known_align,
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, rtx target, int known_align,
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, rtx target, int known_align,
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 size)
{
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, bool adjust_back)
/* 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;

View File

@ -1405,6 +1405,11 @@ instantiate_new_reg (rtx x, HOST_WIDE_INT *poffset)
#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;

View File

@ -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);

View File

@ -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_mode, rtx);
#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_mode, rtx);
|| (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)

View File

@ -1,3 +1,9 @@
2010-09-24 Jakub Jelinek <jakub@redhat.com>
PR middle-end/45234
* gcc.dg/torture/stackalign/alloca-6.c: New test.
* gcc.target/i386/pr45234.c: New test.
2010-09-24 Richard Guenther <rguenther@suse.de>
* gcc.dg/lto/20091006-2_0.c: Prune warnings.

View File

@ -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;
}

View File

@ -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]));
}