If we put static chain on the stack, we need to replicate it on the stack so that static chain can be reached via (argp - 2) slot. This is needed for nested function with stack realignment.
OK for trunk if there are no regressions? H.J. --- gcc/ PR target/66906 * config/i386/i386.c (ix86_expand_prologue): Replicate static chain on the stack. gcc/testsuite/ PR target/66906 * gcc.target/i386/pr66906.c: New test. --- gcc/config/i386/i386.c | 18 ++++++++++++- gcc/testsuite/gcc.target/i386/pr66906.c | 45 +++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gcc.target/i386/pr66906.c diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 0551a75..3803dde 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -11495,6 +11495,7 @@ ix86_expand_prologue (void) HOST_WIDE_INT allocate; bool int_registers_saved; bool sse_registers_saved; + rtx static_chain = NULL_RTX; ix86_finalize_stack_realign_flags (); @@ -11593,7 +11594,8 @@ ix86_expand_prologue (void) call. This insn will be skipped by the trampoline. */ else if (ix86_static_chain_on_stack) { - insn = emit_insn (gen_push (ix86_static_chain (cfun->decl, false))); + static_chain = ix86_static_chain (cfun->decl, false); + insn = emit_insn (gen_push (static_chain)); emit_insn (gen_blockage ()); /* We don't want to interpret this push insn as a register save, @@ -11645,6 +11647,20 @@ ix86_expand_prologue (void) we've started over with a new frame. */ m->fs.sp_offset = INCOMING_FRAME_SP_OFFSET; m->fs.realigned = true; + + if (static_chain) + { + /* Replicate static chain on the stack so that static chain + can be reached via (argp - 2) slot. This is needed for + nested function with stack realignment. */ + t = plus_constant (Pmode, stack_pointer_rtx, -UNITS_PER_WORD); + t = gen_rtx_SET (stack_pointer_rtx, t); + insn = emit_insn (t); + RTX_FRAME_RELATED_P (insn) = 1; + emit_move_insn (gen_rtx_MEM (Pmode, stack_pointer_rtx), + static_chain); + m->fs.sp_offset += UNITS_PER_WORD; + } } int_registers_saved = (frame.nregs == 0); diff --git a/gcc/testsuite/gcc.target/i386/pr66906.c b/gcc/testsuite/gcc.target/i386/pr66906.c new file mode 100644 index 0000000..969e183 --- /dev/null +++ b/gcc/testsuite/gcc.target/i386/pr66906.c @@ -0,0 +1,45 @@ +/* { dg-do run { target ia32 } } */ +/* { dg-options "-O0 -mregparm=3" } */ + +typedef int ptrdiff_t; +extern void abort (void); +int +check_int (int *i, int align) +{ + *i = 20; + if ((((ptrdiff_t) i) & (align - 1)) != 0) + abort (); + return *i; +} +void +check (void *p, int align) +{ + if ((((ptrdiff_t) p) & (align - 1)) != 0) + abort (); +} +typedef int aligned __attribute__((aligned(64))); +void +foo (void) +{ + aligned j; + void bar () + { + aligned i; + if (check_int (&i, __alignof__(i)) != i) + abort (); + if (check_int (&j, __alignof__(j)) != j) + abort (); + j = -20; + } + bar (); + if (j != -20) + abort (); + if (check_int (&j, __alignof__(j)) != j) + abort (); +} +int +main() +{ + foo (); + return 0; +} -- 2.4.3