Commit 58db834b by Bob Wilson Committed by Bob Wilson

xtensa-protos.h (xtensa_copy_incoming_a7): Declare.

        * config/xtensa/xtensa-protos.h (xtensa_copy_incoming_a7): Declare.
        * config/xtensa/xtensa.c (struct machine_function): Add
        incoming_a7_copied flag.
        (xtensa_copy_incoming_a7): Define.
        (xtensa_emit_move_sequence): Use xtensa_copy_incoming_a7.
        * config/xtensa/xtensa.md (movdi, movsf, movdf): Ditto.

From-SVN: r59364
parent c05dbe81
2002-11-21 Bob Wilson <bob.wilson@acm.org>
* config/xtensa/xtensa-protos.h (xtensa_copy_incoming_a7): Declare.
* config/xtensa/xtensa.c (struct machine_function): Add
incoming_a7_copied flag.
(xtensa_copy_incoming_a7): Define.
(xtensa_emit_move_sequence): Use xtensa_copy_incoming_a7.
* config/xtensa/xtensa.md (movdi, movsf, movdf): Ditto.
Thu Nov 21 23:52:04 CET 2002 Jan Hubicka <jH@suse.cz> Thu Nov 21 23:52:04 CET 2002 Jan Hubicka <jH@suse.cz>
* i386-protos.h (x86_64_sign_extended_value): Fix prototype. * i386-protos.h (x86_64_sign_extended_value): Fix prototype.
......
...@@ -70,6 +70,7 @@ extern int xtensa_expand_conditional_move PARAMS ((rtx *, int)); ...@@ -70,6 +70,7 @@ extern int xtensa_expand_conditional_move PARAMS ((rtx *, int));
extern int xtensa_expand_scc PARAMS ((rtx *)); extern int xtensa_expand_scc PARAMS ((rtx *));
extern int xtensa_expand_block_move PARAMS ((rtx *)); extern int xtensa_expand_block_move PARAMS ((rtx *));
extern int xtensa_emit_move_sequence PARAMS ((rtx *, enum machine_mode)); extern int xtensa_emit_move_sequence PARAMS ((rtx *, enum machine_mode));
extern bool xtensa_copy_incoming_a7 PARAMS ((rtx *, enum machine_mode));
extern void xtensa_emit_block_move PARAMS ((rtx *, rtx *, int)); extern void xtensa_emit_block_move PARAMS ((rtx *, rtx *, int));
extern void xtensa_expand_nonlocal_goto PARAMS ((rtx *)); extern void xtensa_expand_nonlocal_goto PARAMS ((rtx *));
extern void xtensa_emit_loop_end PARAMS ((rtx, rtx *)); extern void xtensa_emit_loop_end PARAMS ((rtx, rtx *));
......
...@@ -90,6 +90,7 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE]; ...@@ -90,6 +90,7 @@ const char *xtensa_st_opcodes[(int) MAX_MACHINE_MODE];
struct machine_function GTY(()) struct machine_function GTY(())
{ {
int accesses_prev_frame; int accesses_prev_frame;
bool incoming_a7_copied;
}; };
/* Vector, indexed by hard register number, which contains 1 for a /* Vector, indexed by hard register number, which contains 1 for a
...@@ -1275,22 +1276,69 @@ xtensa_emit_move_sequence (operands, mode) ...@@ -1275,22 +1276,69 @@ xtensa_emit_move_sequence (operands, mode)
if (!xtensa_valid_move (mode, operands)) if (!xtensa_valid_move (mode, operands))
operands[1] = force_reg (mode, operands[1]); operands[1] = force_reg (mode, operands[1]);
/* Check if this move is copying an incoming argument in a7. If if (xtensa_copy_incoming_a7 (operands, mode))
so, emit the move, followed by the special "set_frame_ptr" return 1;
unspec_volatile insn, at the very beginning of the function. }
This is necessary because the register allocator will ignore
conflicts with a7 and may assign some other pseudo to a7. If /* During reload we don't want to emit (subreg:X (mem:Y)) since that
that pseudo was assigned prior to this move, it would clobber instruction won't be recognized after reload. So we remove the
the incoming argument in a7. By copying the argument out of subreg and adjust mem accordingly. */
a7 as the very first thing, and then immediately following if (reload_in_progress)
that with an unspec_volatile to keep the scheduler away, we {
should avoid any problems. */ operands[0] = fixup_subreg_mem (operands[0]);
operands[1] = fixup_subreg_mem (operands[1]);
}
return 0;
}
static rtx
fixup_subreg_mem (x)
rtx x;
{
if (GET_CODE (x) == SUBREG
&& GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
{
rtx temp =
gen_rtx_SUBREG (GET_MODE (x),
reg_equiv_mem [REGNO (SUBREG_REG (x))],
SUBREG_BYTE (x));
x = alter_subreg (&temp);
}
return x;
}
if (a7_overlap_mentioned_p (operands[1]))
/* Check if this move is copying an incoming argument in a7. If so,
emit the move, followed by the special "set_frame_ptr"
unspec_volatile insn, at the very beginning of the function. This
is necessary because the register allocator will ignore conflicts
with a7 and may assign some other pseudo to a7. If that pseudo was
assigned prior to this move, it would clobber the incoming argument
in a7. By copying the argument out of a7 as the very first thing,
and then immediately following that with an unspec_volatile to keep
the scheduler away, we should avoid any problems. */
bool
xtensa_copy_incoming_a7 (operands, mode)
rtx *operands;
enum machine_mode mode;
{
if (a7_overlap_mentioned_p (operands[1])
&& !cfun->machine->incoming_a7_copied)
{ {
rtx mov; rtx mov;
switch (mode) switch (mode)
{ {
case DFmode:
mov = gen_movdf_internal (operands[0], operands[1]);
break;
case SFmode:
mov = gen_movsf_internal (operands[0], operands[1]);
break;
case DImode:
mov = gen_movdi_internal (operands[0], operands[1]);
break;
case SImode: case SImode:
mov = gen_movsi_internal (operands[0], operands[1]); mov = gen_movsi_internal (operands[0], operands[1]);
break; break;
...@@ -1312,38 +1360,22 @@ xtensa_emit_move_sequence (operands, mode) ...@@ -1312,38 +1360,22 @@ xtensa_emit_move_sequence (operands, mode)
emit_insn_after (mov, get_insns ()); emit_insn_after (mov, get_insns ());
pop_topmost_sequence (); pop_topmost_sequence ();
/* Ideally the incoming argument in a7 would only be copied
once, since propagating a7 into the body of a function
will almost certainly lead to errors. However, there is
at least one harmless case (in GCSE) where the original
copy from a7 is changed to copy into a new pseudo. Thus,
we use a flag to only do this special treatment for the
first copy of a7. */
cfun->machine->incoming_a7_copied = true;
return 1; return 1;
} }
}
/* During reload we don't want to emit (subreg:X (mem:Y)) since that
instruction won't be recognized after reload. So we remove the
subreg and adjust mem accordingly. */
if (reload_in_progress)
{
operands[0] = fixup_subreg_mem (operands[0]);
operands[1] = fixup_subreg_mem (operands[1]);
}
return 0; return 0;
} }
static rtx
fixup_subreg_mem (x)
rtx x;
{
if (GET_CODE (x) == SUBREG
&& GET_CODE (SUBREG_REG (x)) == REG
&& REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
{
rtx temp =
gen_rtx_SUBREG (GET_MODE (x),
reg_equiv_mem [REGNO (SUBREG_REG (x))],
SUBREG_BYTE (x));
x = alter_subreg (&temp);
}
return x;
}
/* Try to expand a block move operation to an RTL block move instruction. /* Try to expand a block move operation to an RTL block move instruction.
If not optimizing or if the block size is not a constant or if the If not optimizing or if the block size is not a constant or if the
......
...@@ -929,13 +929,9 @@ ...@@ -929,13 +929,9 @@
&& !register_operand (operands[1], DImode)) && !register_operand (operands[1], DImode))
operands[1] = force_reg (DImode, operands[1]); operands[1] = force_reg (DImode, operands[1]);
if (a7_overlap_mentioned_p (operands[1])) if (xtensa_copy_incoming_a7 (operands, DImode))
{
emit_insn (gen_movdi_internal (operands[0], operands[1]));
emit_insn (gen_set_frame_ptr ());
DONE; DONE;
} }
}
}") }")
(define_insn "movdi_internal" (define_insn "movdi_internal"
...@@ -1107,13 +1103,9 @@ ...@@ -1107,13 +1103,9 @@
&& constantpool_mem_p (operands[1])))) && constantpool_mem_p (operands[1]))))
operands[1] = force_reg (SFmode, operands[1]); operands[1] = force_reg (SFmode, operands[1]);
if (a7_overlap_mentioned_p (operands[1])) if (xtensa_copy_incoming_a7 (operands, SFmode))
{
emit_insn (gen_movsf_internal (operands[0], operands[1]));
emit_insn (gen_set_frame_ptr ());
DONE; DONE;
} }
}
}") }")
(define_insn "movsf_internal" (define_insn "movsf_internal"
...@@ -1193,13 +1185,9 @@ ...@@ -1193,13 +1185,9 @@
&& !register_operand (operands[1], DFmode)) && !register_operand (operands[1], DFmode))
operands[1] = force_reg (DFmode, operands[1]); operands[1] = force_reg (DFmode, operands[1]);
if (a7_overlap_mentioned_p (operands[1])) if (xtensa_copy_incoming_a7 (operands, DFmode))
{
emit_insn (gen_movdf_internal (operands[0], operands[1]));
emit_insn (gen_set_frame_ptr ());
DONE; DONE;
} }
}
}") }")
(define_insn "movdf_internal" (define_insn "movdf_internal"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment