--- gcc/config/ns32k/ns32k.c 2018/04/24 18:10:24 1.1.1.1 +++ gcc/config/ns32k/ns32k.c 2018/04/24 18:14:56 1.1.1.2 @@ -244,7 +244,7 @@ char * output_move_double (operands) rtx *operands; { - enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1; + enum anon1 { REGOP, OFFSOP, PUSHOP, CNSTOP, RNDOP } optype0, optype1; rtx latehalf[2]; /* First classify both operands. */ @@ -254,7 +254,7 @@ output_move_double (operands) else if (offsettable_memref_p (operands[0])) optype0 = OFFSOP; else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC) - optype0 = POPOP; + optype0 = PUSHOP; else optype0 = RNDOP; @@ -266,7 +266,7 @@ output_move_double (operands) else if (offsettable_memref_p (operands[1])) optype1 = OFFSOP; else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC) - optype1 = POPOP; + optype1 = PUSHOP; else optype1 = RNDOP; @@ -307,16 +307,66 @@ output_move_double (operands) else latehalf[1] = operands[1]; + /* If insn is effectively movd N(sp),tos then we will do the + high word first. We should use the adjusted operand 1 (which is N+4(sp)) + for the low word as well, to compensate for the first decrement of sp. + Given this, it doesn't matter which half we do "first". */ + 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]; + /* If one or both operands autodecrementing, do the two words, high-numbered first. */ + else if (optype0 == PUSHOP || optype1 == PUSHOP) + { + output_asm_insn (singlemove_string (latehalf), latehalf); + return singlemove_string (operands); + } + + /* If the first move would clobber the source of the second one, + do them in the other order. */ - if (optype0 == POPOP || optype1 == POPOP) + /* Overlapping registers. */ + if (optype0 == REGOP && optype1 == REGOP + && REGNO (operands[0]) == REGNO (latehalf[1])) { + /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); + /* Do low-numbered word. */ return singlemove_string (operands); } + /* Loading into a register which overlaps a register used in the address. */ + else if (optype0 == REGOP && optype1 != REGOP + && reg_overlap_mentioned_p (operands[0], operands[1])) + { + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)) + && reg_mentioned_p (latehalf[0], XEXP (operands[1], 0))) + { + /* If both halves of dest are used in the src memory address, + add the two regs and put them in the low reg (operands[0]). + Then it works to load latehalf first. */ + rtx xops[2]; + xops[0] = latehalf[0]; + xops[1] = operands[0]; + output_asm_insn ("addd %0,%1", xops); + operands[1] = gen_rtx (MEM, DImode, operands[0]); + latehalf[1] = adj_offsettable_operand (operands[1], 4); + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))) + { + /* The first half has the overlap, Do the late half first. */ + output_asm_insn (singlemove_string (latehalf), latehalf); + /* Then clobber. */ + return singlemove_string (operands); + } + } - /* Not autodecrementing. Do the two words, low-numbered first. */ + /* Normal case. Do the two words, low-numbered first. */ output_asm_insn (singlemove_string (operands), operands);