Hi,
push/pop in x86 only works on word_mode registers. This patch properly
handles push/pop on registers in x86. Tested on Linux/x86-64. OK for
trunk?
Thanks.
H.J.
---
2012-03-06 H.J. Lu
* config/i386/i386.c (setup_incoming_varargs_64): Use word_mode
with integer parameters in registers.
(gen_push): Push register in word_mode instead of Pmode.
(ix86_emit_save_regs): Likewise.
(ix86_emit_save_regs_using_mov): Save integer registers in
word_mode.
(gen_pop): Pop register in word_mode instead of Pmode.
(ix86_emit_restore_regs_using_pop): Likewise.
(ix86_expand_prologue): Replace Pmode with word_mode for push
immediate. Use ix86_gen_pro_epilogue_adjust_stack. Save and
restore RAX and R10 in word_mode.
(ix86_emit_restore_regs_using_mov): Restore integer registers
in word_mode.
(ix86_expand_split_stack_prologue): Save R10_REG and restore in
word_mode.
(ix86_split_to_parts): Use word_mode with PUT_MODE for push.
(ix86_split_long_move): Likewise.
* config/i386/i386.md (W): New.
(*push2_prologue): Replace :P with :W.
(*pop1): Likewise.
(*pop1_epilogue): Likewise.
(push/pop peephole2): Use word_mode scratch registers.
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 973bbeb..eb4aaa8 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -7600,12 +7600,13 @@ setup_incoming_varargs_64 (CUMULATIVE_ARGS *cum)
for (i = cum->regno; i < max; i++)
{
- mem = gen_rtx_MEM (Pmode,
+ mem = gen_rtx_MEM (word_mode,
plus_constant (save_area, i * UNITS_PER_WORD));
MEM_NOTRAP_P (mem) = 1;
set_mem_alias_set (mem, set);
- emit_move_insn (mem, gen_rtx_REG (Pmode,
- x86_64_int_parameter_registers[i]));
+ emit_move_insn (mem,
+ gen_rtx_REG (word_mode,
+ x86_64_int_parameter_registers[i]));
}
if (ix86_varargs_fpr_size)
@@ -8660,8 +8661,11 @@ gen_push (rtx arg)
m->fs.cfa_offset += UNITS_PER_WORD;
m->fs.sp_offset += UNITS_PER_WORD;
+ if (REG_P (arg) && GET_MODE (arg) != word_mode)
+arg = gen_rtx_REG (word_mode, REGNO (arg));
+
return gen_rtx_SET (VOIDmode,
- gen_rtx_MEM (Pmode,
+ gen_rtx_MEM (word_mode,
gen_rtx_PRE_DEC (Pmode,
stack_pointer_rtx)),
arg);
@@ -8672,9 +8676,12 @@ gen_push (rtx arg)
static rtx
gen_pop (rtx arg)
{
+ if (REG_P (arg) && GET_MODE (arg) != word_mode)
+arg = gen_rtx_REG (word_mode, REGNO (arg));
+
return gen_rtx_SET (VOIDmode,
arg,
- gen_rtx_MEM (Pmode,
+ gen_rtx_MEM (word_mode,
gen_rtx_POST_INC (Pmode,
stack_pointer_rtx)));
}
@@ -9141,7 +9148,7 @@ ix86_emit_save_regs (void)
for (regno = FIRST_PSEUDO_REGISTER - 1; regno-- > 0; )
if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
{
- insn = emit_insn (gen_push (gen_rtx_REG (Pmode, regno)));
+ insn = emit_insn (gen_push (gen_rtx_REG (word_mode, regno)));
RTX_FRAME_RELATED_P (insn) = 1;
}
}
@@ -9221,7 +9228,7 @@ ix86_emit_save_regs_using_mov (HOST_WIDE_INT cfa_offset)
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
if (!SSE_REGNO_P (regno) && ix86_save_reg (regno, true))
{
-ix86_emit_save_reg_using_mov (Pmode, regno, cfa_offset);
+ix86_emit_save_reg_using_mov (word_mode, regno, cfa_offset);
cfa_offset -= UNITS_PER_WORD;
}
}
@@ -10158,7 +10165,7 @@ ix86_expand_prologue (void)
to implement macro RETURN_ADDR_RTX and intrinsic function
expand_builtin_return_addr etc. */
t = plus_constant (crtl->drap_reg, -UNITS_PER_WORD);
- t = gen_frame_mem (Pmode, t);
+ t = gen_frame_mem (word_mode, t);
insn = emit_insn (gen_push (t));
RTX_FRAME_RELATED_P (insn) = 1;
@@ -10355,14 +10362,18 @@ ix86_expand_prologue (void)
if (r10_live && eax_live)
{
t = choose_baseaddr (m->fs.sp_offset - allocate);
- emit_move_insn (r10, gen_frame_mem (Pmode, t));
+ emit_move_insn (gen_rtx_REG (word_mode, R10_REG),
+ gen_frame_mem (word_mode, t));
t = choose_baseaddr (m->fs.sp_offset - allocate - UNITS_PER_WORD);
- emit_move_insn (eax, gen_frame_mem (Pmode, t));
+ emit_move_insn (gen_rtx_REG (word_mode, AX_REG),
+ gen_frame_mem (word_mode, t));
}
else if (eax_live || r10_live)
{
t = choose_baseaddr (m->fs.sp_offset - allocate);
- emit_move_insn ((eax_live ? eax : r10), gen_frame_mem (Pmode, t));