Commit 2cc21497 by Stephane Carrez Committed by Stephane Carrez

m68hc11.c (autoinc_mode): New function.

	* config/m68hc11/m68hc11.c (autoinc_mode): New function.
	(m68hc11_make_autoinc_notes): New function.
	(m68hc11_split_move): Be very cautious when spliting a move with
	auto increment/decrement modes because this may result in incompatible
	directions; add REG_INC notes to the resulting insn for CSE reg.

From-SVN: r55076
parent ba18d6d3
2002-06-28 Stephane Carrez <stcarrez@nerim.fr>
* config/m68hc11/m68hc11.c (autoinc_mode): New function.
(m68hc11_make_autoinc_notes): New function.
(m68hc11_split_move): Be very cautious when spliting a move with
auto increment/decrement modes because this may result in incompatible
directions; add REG_INC notes to the resulting insn for CSE reg.
2002-06-28 Stephane Carrez <Stephane.Carrez@nerim.fr> 2002-06-28 Stephane Carrez <Stephane.Carrez@nerim.fr>
* config/m68hc11/m68hc11.c (register_indirect_p): For 68HC12 a constant * config/m68hc11/m68hc11.c (register_indirect_p): For 68HC12 a constant
......
...@@ -2670,38 +2670,46 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label) ...@@ -2670,38 +2670,46 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label)
return 0; return 0;
} }
/* Return 1 if the TO and FROM operands contain compatible address /* Return the increment/decrement mode of a MEM if it is such.
increment and decrement modes for a split_move. One of the two Return CONST if it is anything else. */
operands must not use an autoinc mode or both must go in the
same direction. */
static int static int
m68hc11_autoinc_compatible_p (to, from) autoinc_mode (x)
rtx to, from; rtx x;
{ {
enum { INCOP, DECOP } type_to, type_from; if (GET_CODE (x) != MEM)
return CONST;
/* If one of them is not a MEM, it is ok. */ x = XEXP (x, 0);
if (GET_CODE (to) != MEM || GET_CODE (from) != MEM) if (GET_CODE (x) == PRE_INC
return 1; || GET_CODE (x) == PRE_DEC
|| GET_CODE (x) == POST_INC
|| GET_CODE (x) == POST_DEC)
return GET_CODE (x);
to = XEXP (to, 0); return CONST;
from = XEXP (from, 0); }
if (GET_CODE (to) == PRE_INC || GET_CODE (to) == POST_INC) static int
type_to = INCOP; m68hc11_make_autoinc_notes (x, data)
else if (GET_CODE (to) == PRE_DEC || GET_CODE (to) == POST_DEC) rtx *x;
type_to = DECOP; void *data;
else {
return 1; rtx insn;
if (GET_CODE (from) == PRE_INC || GET_CODE (from) == POST_INC) switch (GET_CODE (*x))
type_from = INCOP; {
else if (GET_CODE (from) == PRE_DEC || GET_CODE (from) == POST_DEC) case PRE_DEC:
type_from = DECOP; case PRE_INC:
else case POST_DEC:
return 1; case POST_INC:
insn = (rtx) data;
REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
REG_NOTES (insn));
return -1;
return type_to == type_from; default:
return 0;
}
} }
/* Split a DI, SI or HI move into several smaller move operations. /* Split a DI, SI or HI move into several smaller move operations.
...@@ -2713,41 +2721,116 @@ m68hc11_split_move (to, from, scratch) ...@@ -2713,41 +2721,116 @@ m68hc11_split_move (to, from, scratch)
{ {
rtx low_to, low_from; rtx low_to, low_from;
rtx high_to, high_from; rtx high_to, high_from;
rtx insn;
enum machine_mode mode; enum machine_mode mode;
int offset = 0; int offset = 0;
int autoinc_from = autoinc_mode (from);
int autoinc_to = autoinc_mode (to);
mode = GET_MODE (to); mode = GET_MODE (to);
if (GET_MODE_SIZE (mode) == 8)
mode = SImode;
else if (GET_MODE_SIZE (mode) == 4)
mode = HImode;
else
mode = QImode;
/* If the TO and FROM contain autoinc modes that are not compatible /* If the TO and FROM contain autoinc modes that are not compatible
together (one pop and the other a push), we must change one to together (one pop and the other a push), we must change one to
an offsetable operand and generate an appropriate add at the end. */ an offsetable operand and generate an appropriate add at the end. */
if (TARGET_M6812 && m68hc11_autoinc_compatible_p (to, from) == 0) if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
{ {
rtx reg; rtx reg;
int code; int code;
/* Decide to change the source. */ /* The source uses an autoinc mode which is not compatible with
code = GET_CODE (XEXP (from, 0)); a split (this would result in a word swap). */
reg = XEXP (XEXP (from, 0), 0); if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
offset = GET_MODE_SIZE (GET_MODE (from)); {
if (code == PRE_DEC || code == POST_DEC) code = GET_CODE (XEXP (from, 0));
offset = -offset; reg = XEXP (XEXP (from, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (from));
if (code == POST_DEC)
offset = -offset;
if (code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
if (code == POST_DEC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
/* Likewise for destination. */
if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
{
code = GET_CODE (XEXP (to, 0));
reg = XEXP (XEXP (to, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (to));
if (code == POST_DEC)
offset = -offset;
if (code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
if (code == POST_DEC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
if (code == PRE_DEC || code == PRE_INC) /* The source and destination auto increment modes must be compatible
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); with each other: same direction. */
m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch); if ((autoinc_to != autoinc_from
if (code == POST_DEC || code == POST_INC) && autoinc_to != CONST && autoinc_from != CONST)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset))); /* The destination address register must not be used within
the source operand because the source address would change
while doing the copy. */
|| (autoinc_to != CONST
&& reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
&& !IS_STACK_PUSH (to)))
{
/* Must change the destination. */
code = GET_CODE (XEXP (to, 0));
reg = XEXP (XEXP (to, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (to));
if (code == PRE_DEC || code == POST_DEC)
offset = -offset;
if (code == PRE_DEC || code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
if (code == POST_DEC || code == POST_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
return; /* Likewise, the source address register must not be used within
the destination operand. */
if (autoinc_from != CONST
&& reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
&& !IS_STACK_PUSH (to))
{
/* Must change the source. */
code = GET_CODE (XEXP (from, 0));
reg = XEXP (XEXP (from, 0), 0);
offset = GET_MODE_SIZE (GET_MODE (from));
if (code == PRE_DEC || code == POST_DEC)
offset = -offset;
if (code == PRE_DEC || code == PRE_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
if (code == POST_DEC || code == POST_INC)
emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
return;
}
} }
if (GET_MODE_SIZE (mode) == 8)
mode = SImode;
else if (GET_MODE_SIZE (mode) == 4)
mode = HImode;
else
mode = QImode;
if (TARGET_M6812 if (TARGET_M6812
&& IS_STACK_PUSH (to) && IS_STACK_PUSH (to)
&& reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from)) && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
...@@ -2783,6 +2866,25 @@ m68hc11_split_move (to, from, scratch) ...@@ -2783,6 +2866,25 @@ m68hc11_split_move (to, from, scratch)
high_from = adjust_address (high_from, mode, offset); high_from = adjust_address (high_from, mode, offset);
low_from = high_from; low_from = high_from;
} }
/* When copying with a POST_INC mode, we must copy the
high part and then the low part to guarantee a correct
32/64-bit copy. */
if (TARGET_M6812
&& GET_MODE_SIZE (mode) >= 2
&& autoinc_from != autoinc_to
&& (autoinc_from == POST_INC || autoinc_to == POST_INC))
{
rtx swap;
swap = low_to;
low_to = high_to;
high_to = swap;
swap = low_from;
low_from = high_from;
high_from = swap;
}
if (mode == SImode) if (mode == SImode)
{ {
m68hc11_split_move (low_to, low_from, scratch); m68hc11_split_move (low_to, low_from, scratch);
...@@ -2800,18 +2902,23 @@ m68hc11_split_move (to, from, scratch) ...@@ -2800,18 +2902,23 @@ m68hc11_split_move (to, from, scratch)
&& (!m68hc11_register_indirect_p (to, GET_MODE (to)) && (!m68hc11_register_indirect_p (to, GET_MODE (to))
|| m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))) || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
{ {
emit_move_insn (low_to, low_from); insn = emit_move_insn (low_to, low_from);
emit_move_insn (high_to, high_from); for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (high_to, high_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
} }
else else
{ {
rtx insn; insn = emit_move_insn (scratch, low_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
emit_move_insn (scratch, low_from);
insn = emit_move_insn (low_to, scratch); insn = emit_move_insn (low_to, scratch);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
emit_move_insn (scratch, high_from); insn = emit_move_insn (scratch, high_from);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
insn = emit_move_insn (high_to, scratch); insn = emit_move_insn (high_to, scratch);
for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
} }
} }
......
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