diff options
author | Stephane Carrez <stcarrez@nerim.fr> | 2002-06-28 22:26:16 +0200 |
---|---|---|
committer | Stephane Carrez <ciceron@gcc.gnu.org> | 2002-06-28 22:26:16 +0200 |
commit | 2cc21497379c4b3fc3884c7e224c5c5a00d61c28 (patch) | |
tree | 26aa611941231af13655b753b6775cf0a700ed8f /gcc | |
parent | ba18d6d38bdad235a43eb8bdefa417031d5f042b (diff) | |
download | gcc-2cc21497379c4b3fc3884c7e224c5c5a00d61c28.zip gcc-2cc21497379c4b3fc3884c7e224c5c5a00d61c28.tar.gz gcc-2cc21497379c4b3fc3884c7e224c5c5a00d61c28.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/config/m68hc11/m68hc11.c | 207 |
2 files changed, 165 insertions, 50 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e3f267d..502b645 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +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> * config/m68hc11/m68hc11.c (register_indirect_p): For 68HC12 a constant diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index 50b831e..4fb054d3 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -2670,38 +2670,46 @@ m68hc11_expand_compare_and_branch (code, op0, op1, label) return 0; } -/* Return 1 if the TO and FROM operands contain compatible address - increment and decrement modes for a split_move. One of the two - operands must not use an autoinc mode or both must go in the - same direction. */ +/* Return the increment/decrement mode of a MEM if it is such. + Return CONST if it is anything else. */ static int -m68hc11_autoinc_compatible_p (to, from) - rtx to, from; +autoinc_mode (x) + 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. */ - if (GET_CODE (to) != MEM || GET_CODE (from) != MEM) - return 1; + x = XEXP (x, 0); + if (GET_CODE (x) == PRE_INC + || GET_CODE (x) == PRE_DEC + || GET_CODE (x) == POST_INC + || GET_CODE (x) == POST_DEC) + return GET_CODE (x); - to = XEXP (to, 0); - from = XEXP (from, 0); + return CONST; +} - if (GET_CODE (to) == PRE_INC || GET_CODE (to) == POST_INC) - type_to = INCOP; - else if (GET_CODE (to) == PRE_DEC || GET_CODE (to) == POST_DEC) - type_to = DECOP; - else - return 1; +static int +m68hc11_make_autoinc_notes (x, data) + rtx *x; + void *data; +{ + rtx insn; - if (GET_CODE (from) == PRE_INC || GET_CODE (from) == POST_INC) - type_from = INCOP; - else if (GET_CODE (from) == PRE_DEC || GET_CODE (from) == POST_DEC) - type_from = DECOP; - else - return 1; + switch (GET_CODE (*x)) + { + case PRE_DEC: + case PRE_INC: + case POST_DEC: + 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. @@ -2713,41 +2721,116 @@ m68hc11_split_move (to, from, scratch) { rtx low_to, low_from; rtx high_to, high_from; + rtx insn; enum machine_mode mode; int offset = 0; + int autoinc_from = autoinc_mode (from); + int autoinc_to = autoinc_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 together (one pop and the other a push), we must change one to 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; int code; - /* Decide to 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; + /* The source uses an autoinc mode which is not compatible with + a split (this would result in a word swap). */ + if (autoinc_from == PRE_INC || autoinc_from == POST_DEC) + { + code = GET_CODE (XEXP (from, 0)); + 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) - 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))); + /* The source and destination auto increment modes must be compatible + with each other: same direction. */ + if ((autoinc_to != autoinc_from + && autoinc_to != CONST && autoinc_from != CONST) + /* 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 && IS_STACK_PUSH (to) && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from)) @@ -2783,6 +2866,25 @@ m68hc11_split_move (to, from, scratch) high_from = adjust_address (high_from, mode, offset); 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) { m68hc11_split_move (low_to, low_from, scratch); @@ -2800,18 +2902,23 @@ m68hc11_split_move (to, from, scratch) && (!m68hc11_register_indirect_p (to, GET_MODE (to)) || m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))) { - emit_move_insn (low_to, low_from); - emit_move_insn (high_to, high_from); + insn = emit_move_insn (low_to, low_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 { - rtx insn; - - emit_move_insn (scratch, low_from); + insn = emit_move_insn (scratch, low_from); + for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); 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); + for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn); } } |