diff options
Diffstat (limited to 'gcc/config/m68hc11/m68hc11.c')
-rw-r--r-- | gcc/config/m68hc11/m68hc11.c | 150 |
1 files changed, 90 insertions, 60 deletions
diff --git a/gcc/config/m68hc11/m68hc11.c b/gcc/config/m68hc11/m68hc11.c index ce057a387b3..383025d4ae1 100644 --- a/gcc/config/m68hc11/m68hc11.c +++ b/gcc/config/m68hc11/m68hc11.c @@ -1,5 +1,5 @@ /* Subroutines for code generation on Motorola 68HC11 and 68HC12. - Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. Contributed by Stephane Carrez (stcarrez@nerim.fr) @@ -1027,6 +1027,7 @@ reg_or_some_mem_operand (rtx operand, enum machine_mode mode) if (GET_CODE (operand) == MEM) { rtx op = XEXP (operand, 0); + int addr_mode; if (symbolic_memory_operand (op, mode)) return 1; @@ -1034,10 +1035,20 @@ reg_or_some_mem_operand (rtx operand, enum machine_mode mode) if (IS_STACK_PUSH (operand)) return 1; - if (m68hc11_register_indirect_p (operand, mode)) - return 1; + if (GET_CODE (operand) == REG && reload_in_progress + && REGNO (operand) >= FIRST_PSEUDO_REGISTER + && reg_equiv_memory_loc[REGNO (operand)]) + { + operand = reg_equiv_memory_loc[REGNO (operand)]; + operand = eliminate_regs (operand, 0, NULL_RTX); + } + if (GET_CODE (operand) != MEM) + return 0; - return 0; + operand = XEXP (operand, 0); + addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0); + addr_mode &= ~ADDR_INDIRECT; + return register_indirect_p (operand, mode, addr_mode); } return register_operand (operand, mode); @@ -2044,6 +2055,10 @@ m68hc11_gen_highpart (enum machine_mode mode, rtx x) { return gen_int_mode (val >> 16, HImode); } + else if (mode == SImode) + { + return gen_int_mode (val >> 32, SImode); + } } if (mode == QImode && D_REG_P (x)) return gen_rtx (REG, mode, HARD_A_REGNUM); @@ -2926,15 +2941,7 @@ m68hc11_split_move (rtx to, rtx from, rtx scratch) high_to = m68hc11_gen_highpart (mode, to); low_from = m68hc11_gen_lowpart (mode, from); - if (mode == SImode && GET_CODE (from) == CONST_INT) - { - if (INTVAL (from) >= 0) - high_from = const0_rtx; - else - high_from = constm1_rtx; - } - else - high_from = m68hc11_gen_highpart (mode, from); + high_from = m68hc11_gen_highpart (mode, from); if (offset) { @@ -3117,26 +3124,8 @@ m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands) low[2] = m68hc11_gen_lowpart (mode, operands[2]); high[0] = m68hc11_gen_highpart (mode, operands[0]); - - if (mode == SImode && GET_CODE (operands[1]) == CONST_INT) - { - if (INTVAL (operands[1]) >= 0) - high[1] = const0_rtx; - else - high[1] = constm1_rtx; - } - else - high[1] = m68hc11_gen_highpart (mode, operands[1]); - - if (mode == SImode && GET_CODE (operands[2]) == CONST_INT) - { - if (INTVAL (operands[2]) >= 0) - high[2] = const0_rtx; - else - high[2] = constm1_rtx; - } - else - high[2] = m68hc11_gen_highpart (mode, operands[2]); + high[1] = m68hc11_gen_highpart (mode, operands[1]); + high[2] = m68hc11_gen_highpart (mode, operands[2]); low[3] = operands[3]; high[3] = operands[3]; @@ -3243,10 +3232,13 @@ m68hc11_gen_movhi (rtx insn, rtx *operands) if (TARGET_M6812) { - if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1])) + rtx from = operands[1]; + rtx to = operands[0]; + + if (IS_STACK_PUSH (to) && H_REG_P (from)) { cc_status = cc_prev_status; - switch (REGNO (operands[1])) + switch (REGNO (from)) { case HARD_X_REGNUM: case HARD_Y_REGNUM: @@ -3261,10 +3253,10 @@ m68hc11_gen_movhi (rtx insn, rtx *operands) } return; } - if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0])) + if (IS_STACK_POP (from) && H_REG_P (to)) { cc_status = cc_prev_status; - switch (REGNO (operands[0])) + switch (REGNO (to)) { case HARD_X_REGNUM: case HARD_Y_REGNUM: @@ -3295,11 +3287,52 @@ m68hc11_gen_movhi (rtx insn, rtx *operands) else output_asm_insn ("st%1\t%0", operands); } + + /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw + instruction. We have to use a scratch register as temporary location. + Trying to use a specific pattern or constrain failed. */ + else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM) + { + rtx ops[4]; + + ops[0] = to; + ops[2] = from; + ops[3] = 0; + if (dead_register_here (insn, d_reg)) + ops[1] = d_reg; + else if (dead_register_here (insn, ix_reg)) + ops[1] = ix_reg; + else if (dead_register_here (insn, iy_reg)) + ops[1] = iy_reg; + else + { + ops[1] = d_reg; + ops[3] = d_reg; + output_asm_insn ("psh%3", ops); + } + + ops[0] = to; + ops[2] = from; + output_asm_insn ("ld%1\t%2", ops); + output_asm_insn ("st%1\t%0", ops); + if (ops[3]) + output_asm_insn ("pul%3", ops); + } + + /* Use movw for non-null constants or when we are clearing + a volatile memory reference. However, this is possible + only if the memory reference has a small offset or is an + absolute address. */ + else if (GET_CODE (from) == CONST_INT + && INTVAL (from) == 0 + && (MEM_VOLATILE_P (to) == 0 + || m68hc11_small_indexed_indirect_p (to, HImode) == 0)) + { + output_asm_insn ("clr\t%h0", operands); + output_asm_insn ("clr\t%b0", operands); + } else { - rtx from = operands[1]; - rtx to = operands[0]; - if ((m68hc11_register_indirect_p (from, GET_MODE (from)) && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from))) || (m68hc11_register_indirect_p (to, GET_MODE (to)) @@ -3316,6 +3349,7 @@ m68hc11_gen_movhi (rtx insn, rtx *operands) ops[0] = to; ops[1] = operands[2]; m68hc11_gen_movhi (insn, ops); + return; } else { @@ -3323,19 +3357,11 @@ m68hc11_gen_movhi (rtx insn, rtx *operands) fatal_insn ("move insn not handled", insn); } } - else - { - if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0) - { - output_asm_insn ("clr\t%h0", operands); - output_asm_insn ("clr\t%b0", operands); - } - else - { - m68hc11_notice_keep_cc (operands[0]); - output_asm_insn ("movw\t%1,%0", operands); - } - } + else + { + m68hc11_notice_keep_cc (operands[0]); + output_asm_insn ("movw\t%1,%0", operands); + } } return; } @@ -3663,8 +3689,10 @@ m68hc11_gen_movqi (rtx insn, rtx *operands) } else if (H_REG_P (operands[0])) { - if (Q_REG_P (operands[0])) - output_asm_insn ("lda%0\t%b1", operands); + if (IS_STACK_POP (operands[1])) + output_asm_insn ("pul%b0", operands); + else if (Q_REG_P (operands[0])) + output_asm_insn ("lda%0\t%b1", operands); else if (D_REG_P (operands[0])) output_asm_insn ("ldab\t%b1", operands); else @@ -5028,9 +5056,11 @@ m68hc11_z_replacement (rtx insn) if (info.save_before_last) save_pos_insn = PREV_INSN (save_pos_insn); - emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM), - gen_rtx (REG, HImode, info.regno)), - save_pos_insn); + /* Use emit_insn_after () to ensure the new insn is part of + the good basic block. */ + emit_insn_after (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM), + gen_rtx (REG, HImode, info.regno)), + PREV_INSN (save_pos_insn)); } if (info.must_push_reg && info.last) @@ -5069,8 +5099,8 @@ m68hc11_z_replacement (rtx insn) else dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM); - emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno), - dst), insn); + emit_insn_after (gen_movhi (gen_rtx (REG, HImode, info.regno), + dst), PREV_INSN (insn)); } } |