--- gcc/config/m68k/m68k.c 2018/04/24 18:10:24 1.1 +++ gcc/config/m68k/m68k.c 2018/04/24 18:14:44 1.1.1.2 @@ -58,6 +58,7 @@ rtx legitimize_pic_address (); all PIC references were deleted from the current function. That would save an address register */ +void finalize_pic () { if (flag_pic && current_function_uses_pic_offset_table) @@ -884,7 +885,9 @@ output_move_double (operands) } optype0, optype1; rtx latehalf[2]; rtx middlehalf[2]; + rtx xops[2]; rtx addreg0 = 0, addreg1 = 0; + int dest_overlapped_low = 0; int size = GET_MODE_SIZE (GET_MODE (operands[0])); middlehalf[0] = 0; @@ -1064,7 +1067,69 @@ output_move_double (operands) if (optype0 == PUSHOP && REGNO (XEXP (XEXP (operands[0], 0), 0)) == STACK_POINTER_REGNUM && reg_overlap_mentioned_p (stack_pointer_rtx, operands[1])) - operands[1] = latehalf[1]; + operands[1] = middlehalf[1] = latehalf[1]; + + /* For (set (reg:DI N) (mem:DI ... (reg:SI N) ...)), + if the upper part of reg N does not appear in the MEM, arrange to + emit the move late-half first. Otherwise, compute the MEM address + into the upper part of N and use that as a pointer to the memory + operand. */ + if (optype0 == REGOP + && (optype1 == OFFSOP || optype1 == MEMOP)) + { + rtx testlow = gen_rtx (REG, SImode, REGNO (operands[0])); + + if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) + && reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + compute the address into latehalf of dest. + Note that this can't happen if the dest is two data regs. */ +compadr: + xops[0] = latehalf[0]; + xops[1] = XEXP (operands[1], 0); + output_asm_insn ("lea %a1,%0", xops); + if( GET_MODE (operands[1]) == XFmode ) + { + operands[1] = gen_rtx (MEM, XFmode, latehalf[0]); + middlehalf[1] = adj_offsettable_operand (operands[1], size-8); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + else + { + operands[1] = gen_rtx (MEM, DImode, latehalf[0]); + latehalf[1] = adj_offsettable_operand (operands[1], size-4); + } + } + else if (size == 12 + && reg_overlap_mentioned_p (middlehalf[0], + XEXP (operands[1], 0))) + { + /* Check for two regs used by both source and dest. + Note that this can't happen if the dest is all data regs. + It can happen if the dest is d6, d7, a0. + But in that case, latehalf is an addr reg, so + the code at compadr does ok. */ + + if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0)) + || reg_overlap_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + goto compadr; + + /* JRV says this can't happen: */ + if (addreg0 || addreg1) + abort (); + + /* Only the middle reg conflicts; simply put it last. */ + output_asm_insn (singlemove_string (operands), operands); + output_asm_insn (singlemove_string (latehalf), latehalf); + output_asm_insn (singlemove_string (middlehalf), middlehalf); + return ""; + } + else if (reg_overlap_mentioned_p (testlow, XEXP (operands[1], 0))) + /* If the low half of dest is mentioned in the source memory + address, the arrange to emit the move late half first. */ + dest_overlapped_low = 1; + } /* If one or both operands autodecrementing, do the two words, high-numbered first. */ @@ -1077,7 +1142,8 @@ output_move_double (operands) if (optype0 == PUSHOP || optype1 == PUSHOP || (optype0 == REGOP && optype1 == REGOP && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1])) - || REGNO (operands[0]) == REGNO (latehalf[1])))) + || REGNO (operands[0]) == REGNO (latehalf[1]))) + || dest_overlapped_low) { /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0)