So, here is the asked more complex variant regarding displacement-value-range of amd64-instruction and taking care that we use constant-offsets instead of register-based displacement addressing if possible.
ChangeLog 2014-02-14 Kai Tietz <kti...@redhat.com> PR target/60193 * config/i386/i386.c (ix86_expand_prologue): Use rax register as displacement for restoring %r10, %eax. Regression-tested for x86_64-unknown-linux-gnu, and x86_64-w64-mingw32, and i686-w64-mingw32. Ok for apply? Regards, Kai Index: i386.c =================================================================== --- i386.c (Revision 207686) +++ i386.c (Arbeitskopie) @@ -11084,17 +11084,34 @@ ix86_expand_prologue (void) works for realigned stack, too. */ if (r10_live && eax_live) { - t = plus_constant (Pmode, stack_pointer_rtx, allocate); + /* Don't exceed displacement-range for 64-bit. */ + if (!TARGET_64BIT || allocate <= (1 << 31)) + t = plus_constant (Pmode, stack_pointer_rtx, allocate); + else + t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, eax); emit_move_insn (gen_rtx_REG (word_mode, R10_REG), gen_frame_mem (word_mode, t)); - t = plus_constant (Pmode, stack_pointer_rtx, - allocate - UNITS_PER_WORD); + + /* Don't exceed displacement-range for 64-bit. */ + if (!TARGET_64BIT || (allocate + UNITS_PER_WORD) <= (1 << 31)) + t = plus_constant (Pmode, stack_pointer_rtx, + allocate + UNITS_PER_WORD); + else + { + t = plus_constant (Pmode, eax, UNITS_PER_WORD); + emit_move_insn (eax, t); + t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, eax); + } emit_move_insn (gen_rtx_REG (word_mode, AX_REG), gen_frame_mem (word_mode, t)); } else if (eax_live || r10_live) { - t = plus_constant (Pmode, stack_pointer_rtx, allocate); + /* Don't exceed displacement-range for 64-bit. */ + if (!TARGET_64BIT || allocate <= (1 << 31)) + t = plus_constant (Pmode, stack_pointer_rtx, allocate); + else + t = gen_rtx_PLUS (Pmode, stack_pointer_rtx, eax); emit_move_insn (gen_rtx_REG (word_mode, (eax_live ? AX_REG : R10_REG)), gen_frame_mem (word_mode, t));