--- gcc/config/m68k/m68k.c 2018/04/24 18:10:24 1.1 +++ gcc/config/m68k/m68k.c 2018/04/24 18:28:27 1.1.1.4 @@ -1,5 +1,5 @@ /* Subroutines for insn-output.c for Motorola 68000 family. - Copyright (C) 1987, 1993 Free Software Foundation, Inc. + Copyright (C) 1987, 1993, 1994, 1995 Free Software Foundation, Inc. This file is part of GNU CC. @@ -15,7 +15,8 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Some output-actions in m68k.md need these. */ @@ -58,10 +59,15 @@ 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) - emit_insn (gen_rtx (USE, VOIDmode, pic_offset_table_rtx)); + { + rtx insn = gen_rtx (USE, VOIDmode, pic_offset_table_rtx); + emit_insn_after (insn, get_insns ()); + emit_insn (insn); + } } @@ -92,8 +98,20 @@ output_function_prologue (stream, size) if (frame_pointer_needed) { - /* Adding negative number is faster on the 68040. */ - if (fsize < 0x8000 && !TARGET_68040) + if (fsize == 0 && TARGET_68040) + { + /* on the 68040, pea + move is faster than link.w 0 */ +#ifdef MOTOROLA + asm_fprintf (stream, "\tpea (%s)\n\tmove.l %s,%s\n", + reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], + reg_names[FRAME_POINTER_REGNUM]); +#else + asm_fprintf (stream, "\tpea %s@\n\tmovel %s,%s\n", + reg_names[FRAME_POINTER_REGNUM], reg_names[STACK_POINTER_REGNUM], + reg_names[FRAME_POINTER_REGNUM]); +#endif + } + else if (fsize < 0x8000) { #ifdef MOTOROLA asm_fprintf (stream, "\tlink.w %s,%0I%d\n", @@ -115,6 +133,7 @@ output_function_prologue (stream, size) } else { + /* Adding negative number is faster on the 68040. */ #ifdef MOTOROLA asm_fprintf (stream, "\tlink.w %s,%0I0\n\tadd.l %0I%d,%Rsp\n", reg_names[FRAME_POINTER_REGNUM], -fsize); @@ -129,6 +148,7 @@ output_function_prologue (stream, size) /* Adding negative number is faster on the 68040. */ if (fsize + 4 < 0x8000) { + /* asm_fprintf() cannot handle %. */ #ifdef MOTOROLA asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", - (fsize + 4)); #else @@ -137,6 +157,7 @@ output_function_prologue (stream, size) } else { + /* asm_fprintf() cannot handle %. */ #ifdef MOTOROLA asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", - (fsize + 4)); #else @@ -314,9 +335,9 @@ output_function_epilogue (stream, size) && (mask || fmask || fpoffset)) { #ifdef MOTOROLA - asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra0\n", -fsize); + asm_fprintf (stream, "\t%Omove.l %0I%d,%Ra1\n", -fsize); #else - asm_fprintf (stream, "\tmovel %0I%d,%Ra0\n", -fsize); + asm_fprintf (stream, "\tmovel %0I%d,%Ra1\n", -fsize); #endif fsize = 0, big = 1; } @@ -336,12 +357,12 @@ output_function_epilogue (stream, size) if (big) { #ifdef MOTOROLA - asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra0.l),%s\n", + asm_fprintf (stream, "\t%Omove.l -%d(%s,%Ra1.l),%s\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], reg_names[i]); #else - asm_fprintf (stream, "\tmovel %s@(-%d,%Ra0:l),%s\n", + asm_fprintf (stream, "\tmovel %s@(-%d,%Ra1:l),%s\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, reg_names[i]); #endif @@ -377,12 +398,12 @@ output_function_epilogue (stream, size) if (big) { #ifdef MOTOROLA - asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra0.l),%0I0x%x\n", + asm_fprintf (stream, "\tmovm.l -%d(%s,%Ra1.l),%0I0x%x\n", offset + fsize, reg_names[FRAME_POINTER_REGNUM], mask); #else - asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra0:l),%0I0x%x\n", + asm_fprintf (stream, "\tmoveml %s@(-%d,%Ra1:l),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], offset + fsize, mask); #endif @@ -414,12 +435,12 @@ output_function_epilogue (stream, size) if (big) { #ifdef MOTOROLA - asm_fprintf (stream, "\tfmovm -%d(%s,%Ra0.l),%0I0x%x\n", + asm_fprintf (stream, "\tfmovm -%d(%s,%Ra1.l),%0I0x%x\n", foffset + fsize, reg_names[FRAME_POINTER_REGNUM], fmask); #else - asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra0:l),%0I0x%x\n", + asm_fprintf (stream, "\tfmovem %s@(-%d,%Ra1:l),%0I0x%x\n", reg_names[FRAME_POINTER_REGNUM], foffset + fsize, fmask); #endif @@ -453,12 +474,12 @@ output_function_epilogue (stream, size) if (big) { #ifdef MOTOROLA - asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra0.l), %s\n", + asm_fprintf (stream, "\tfpmovd -%d(%s,%Ra1.l), %s\n", fpoffset + fsize, reg_names[FRAME_POINTER_REGNUM], reg_names[regno]); #else - asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra0:l), %s\n", + asm_fprintf (stream, "\tfpmoved %s@(-%d,%Ra1:l), %s\n", reg_names[FRAME_POINTER_REGNUM], fpoffset + fsize, reg_names[regno]); #endif @@ -495,6 +516,7 @@ output_function_epilogue (stream, size) { if (fsize + 4 < 0x8000) { + /* asm_fprintf() cannot handle %. */ #ifdef MOTOROLA asm_fprintf (stream, "\tadd.w %0I%d,%Rsp\n", fsize + 4); #else @@ -503,6 +525,7 @@ output_function_epilogue (stream, size) } else { + /* asm_fprintf() cannot handle %. */ #ifdef MOTOROLA asm_fprintf (stream, "\tadd.l %0I%d,%Rsp\n", fsize + 4); #else @@ -676,6 +699,163 @@ output_dbcc_and_branch (operands) } char * +output_scc_di(op, operand1, operand2, dest) + rtx op; + rtx operand1; + rtx operand2; + rtx dest; +{ + rtx loperands[7]; + enum rtx_code op_code = GET_CODE (op); + + /* The m68k cmp.l instruction requires operand1 to be a reg as used + below. Swap the operands and change the op if these requirements + are not fulfilled. */ + if (GET_CODE (operand2) == REG && GET_CODE (operand1) != REG) + { + rtx tmp = operand1; + + operand1 = operand2; + operand2 = tmp; + op_code = swap_condition (op_code); + } + loperands[0] = operand1; + if (GET_CODE (operand1) == REG) + loperands[1] = gen_rtx (REG, SImode, REGNO (operand1) + 1); + else + loperands[1] = adj_offsettable_operand (operand1, 4); + if (operand2 != const0_rtx) + { + loperands[2] = operand2; + if (GET_CODE (operand2) == REG) + loperands[3] = gen_rtx (REG, SImode, REGNO (operand2) + 1); + else + loperands[3] = adj_offsettable_operand (operand2, 4); + } + loperands[4] = gen_label_rtx(); + if (operand2 != const0_rtx) +#ifdef MOTOROLA +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.l %0,%2\n\tjbne %l4\n\tcmp%.l %1,%3", loperands); +#else + output_asm_insn ("cmp%.l %2,%0\n\tjbne %l4\n\tcmp%.l %3,%1", loperands); +#endif +#else +#ifdef SGS_CMP_ORDER + output_asm_insn ("cmp%.l %0,%2\n\tjne %l4\n\tcmp%.l %1,%3", loperands); +#else + output_asm_insn ("cmp%.l %2,%0\n\tjne %l4\n\tcmp%.l %3,%1", loperands); +#endif +#endif + else +#ifdef MOTOROLA + output_asm_insn ("tst%.l %0\n\tjbne %l4\n\ttst%.l %1", loperands); +#else + output_asm_insn ("tst%.l %0\n\tjne %l4\n\ttst%.l %1", loperands); +#endif + loperands[5] = dest; + + switch (op_code) + { + case EQ: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("seq %5", loperands); + break; + + case NE: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sne %5", loperands); + break; + + case GT: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("shi %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("shi %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sgt %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case GTU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("shi %5", loperands); + break; + + case LT: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("scs %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("scs %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("slt %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case LTU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("scs %5", loperands); + break; + + case GE: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("scc %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("scc %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sge %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case GEU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("scc %5", loperands); + break; + + case LE: + loperands[6] = gen_label_rtx(); +#ifdef MOTOROLA + output_asm_insn ("sls %5\n\tjbra %l6", loperands); +#else + output_asm_insn ("sls %5\n\tjra %l6", loperands); +#endif + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sle %5", loperands); + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[6])); + break; + + case LEU: + ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", + CODE_LABEL_NUMBER (loperands[4])); + output_asm_insn ("sls %5", loperands); + break; + + default: + abort (); + } + return ""; +} + +char * output_btst (operands, countop, dataop, insn, signpos) rtx *operands; rtx countop, dataop; @@ -748,6 +928,25 @@ symbolic_operand (op, mode) return 0; } } + +/* Check for sign_extend or zero_extend. Used for bit-count operands. */ + +int +extend_operator(x, mode) + rtx x; + enum machine_mode mode; +{ + if (mode != VOIDmode && GET_MODE(x) != mode) + return 0; + switch (GET_CODE(x)) + { + case SIGN_EXTEND : + case ZERO_EXTEND : + return 1; + default : + return 0; + } +} /* Legitimize PIC addresses. If the address is already @@ -841,6 +1040,116 @@ legitimize_pic_address (orig, mode, reg) } +typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ } CONST_METHOD; + +use_movq (i) + int i; +{ + return (i >= -128 && i <= 127); +} + +CONST_METHOD +const_method (constant) + rtx constant; +{ + int i; + unsigned u; + + i = INTVAL (constant); + if (use_movq (i)) + return MOVQ; + /* if -256 < N < 256 but N is not in range for a moveq + N^ff will be, so use moveq #N^ff, dreg; not.b dreg. */ + if (use_movq (i ^ 0xff)) + return NOTB; + /* Likewise, try with not.w */ + if (use_movq (i ^ 0xffff)) + return NOTW; + /* This is the only value where neg.w is useful */ + if (i == -65408) + return NEGW; + /* Try also with swap */ + u = i; + if (use_movq ((u >> 16) | (u << 16))) + return SWAP; + /* Otherwise, use move.l */ + return MOVL; +} + +const_int_cost (constant) + rtx constant; +{ + switch (const_method (constant)) + { + case MOVQ : + /* Constants between -128 and 127 are cheap due to moveq */ + return 0; + case NOTB : + case NOTW : + case NEGW : + case SWAP : + /* Constants easily generated by moveq + not.b/not.w/neg.w/swap */ + return 1; + case MOVL : + return 2; + default : + abort (); + } +} + +char * +output_move_const_into_data_reg (operands) + rtx *operands; +{ + int i; + + i = INTVAL (operands[1]); + switch (const_method (operands[1])) + { + case MOVQ : +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0"; +#else + return "moveq %1,%0"; +#endif + case NOTB : + operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xff); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tnot%.b %0"; +#else + return "moveq %1,%0\n\tnot%.b %0"; +#endif + case NOTW : + operands[1] = gen_rtx (CONST_INT, VOIDmode, i ^ 0xffff); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tnot%.w %0"; +#else + return "moveq %1,%0\n\tnot%.w %0"; +#endif + case NEGW : +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %#-128,%0\n\tneg%.w %0"; +#else + return "moveq %#-128,%0\n\tneg%.w %0"; +#endif + case SWAP : + { + unsigned u = i; + + operands[1] = gen_rtx (CONST_INT, VOIDmode, (u << 16) | (u >> 16)); +#if defined (MOTOROLA) && !defined (CRDS) + return "moveq%.l %1,%0\n\tswap %0"; +#else + return "moveq %1,%0\n\tswap %0"; +#endif + } + case MOVL : + return "move%.l %1,%0"; + default : + abort (); + } +} + /* Return the best assembler insn template for moving operands[1] into operands[0] as a fullword. */ @@ -853,16 +1162,8 @@ singlemove_string (operands) return "fpmoves %1,%0"; #endif if (DATA_REG_P (operands[0]) - && GET_CODE (operands[1]) == CONST_INT - && INTVAL (operands[1]) < 128 - && INTVAL (operands[1]) >= -128) - { -#if defined (MOTOROLA) && !defined (CRDS) - return "moveq%.l %1,%0"; -#else - return "moveq %1,%0"; -#endif - } + && GET_CODE (operands[1]) == CONST_INT) + return output_move_const_into_data_reg (operands); if (operands[1] != const0_rtx) return "move%.l %1,%0"; if (! ADDRESS_REG_P (operands[0])) @@ -884,7 +1185,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 +1367,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,22 +1442,23 @@ 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) { if (size == 12) - output_asm_insn ("addql %#8,%0", &addreg0); + output_asm_insn ("addq%.l %#8,%0", &addreg0); else - output_asm_insn ("addql %#4,%0", &addreg0); + output_asm_insn ("addq%.l %#4,%0", &addreg0); } if (addreg1) { if (size == 12) - output_asm_insn ("addql %#8,%0", &addreg1); + output_asm_insn ("addq%.l %#8,%0", &addreg1); else - output_asm_insn ("addql %#4,%0", &addreg1); + output_asm_insn ("addq%.l %#4,%0", &addreg1); } /* Do that word. */ @@ -1100,17 +1466,17 @@ output_move_double (operands) /* Undo the adds we just did. */ if (addreg0) - output_asm_insn ("subql %#4,%0", &addreg0); + output_asm_insn ("subq%.l %#4,%0", &addreg0); if (addreg1) - output_asm_insn ("subql %#4,%0", &addreg1); + output_asm_insn ("subq%.l %#4,%0", &addreg1); if (size == 12) { output_asm_insn (singlemove_string (middlehalf), middlehalf); if (addreg0) - output_asm_insn ("subql %#4,%0", &addreg0); + output_asm_insn ("subq%.l %#4,%0", &addreg0); if (addreg1) - output_asm_insn ("subql %#4,%0", &addreg1); + output_asm_insn ("subq%.l %#4,%0", &addreg1); } /* Do low-numbered word. */ @@ -1125,18 +1491,18 @@ output_move_double (operands) if (size == 12) { if (addreg0) - output_asm_insn ("addql %#4,%0", &addreg0); + output_asm_insn ("addq%.l %#4,%0", &addreg0); if (addreg1) - output_asm_insn ("addql %#4,%0", &addreg1); + output_asm_insn ("addq%.l %#4,%0", &addreg1); output_asm_insn (singlemove_string (middlehalf), middlehalf); } /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) - output_asm_insn ("addql %#4,%0", &addreg0); + output_asm_insn ("addq%.l %#4,%0", &addreg0); if (addreg1) - output_asm_insn ("addql %#4,%0", &addreg1); + output_asm_insn ("addq%.l %#4,%0", &addreg1); /* Do that word. */ output_asm_insn (singlemove_string (latehalf), latehalf); @@ -1145,16 +1511,16 @@ output_move_double (operands) if (addreg0) { if (size == 12) - output_asm_insn ("subql %#8,%0", &addreg0); + output_asm_insn ("subq%.l %#8,%0", &addreg0); else - output_asm_insn ("subql %#4,%0", &addreg0); + output_asm_insn ("subq%.l %#4,%0", &addreg0); } if (addreg1) { if (size == 12) - output_asm_insn ("subql %#8,%0", &addreg1); + output_asm_insn ("subq%.l %#8,%0", &addreg1); else - output_asm_insn ("subql %#4,%0", &addreg1); + output_asm_insn ("subq%.l %#4,%0", &addreg1); } return ""; @@ -1278,7 +1644,7 @@ notice_update_cc (exp, insn) { case PLUS: case MINUS: case MULT: case DIV: case UDIV: case MOD: case UMOD: case NEG: - case ASHIFT: case LSHIFT: case ASHIFTRT: case LSHIFTRT: + case ASHIFT: case ASHIFTRT: case LSHIFTRT: case ROTATE: case ROTATERT: if (GET_MODE (cc_status.value2) != VOIDmode) cc_status.flags |= CC_NO_OVERFLOW; @@ -1429,6 +1795,10 @@ standard_68881_constant_p (x) int i; enum machine_mode mode; +#ifdef NO_ASM_FMOVECR + return 0; +#endif + /* fmovecr must be emulated on the 68040, so it shouldn't be used at all. */ if (TARGET_68040) return 0; @@ -1776,6 +2146,7 @@ print_operand (file, op, letter) } else if (GET_CODE (op) == REG) { +#ifdef SUPPORT_SUN_FPA if (REGNO (op) < 16 && (letter == 'y' || letter == 'x') && GET_MODE (op) == DFmode) @@ -1784,8 +2155,14 @@ print_operand (file, op, letter) reg_names[REGNO (op)+1]); } else +#endif { - fprintf (file, "%s", reg_names[REGNO (op)]); + if (letter == 'R') + /* Print out the second register name of a register pair. + I.e., R (6) => 7. */ + fputs (reg_names[REGNO (op) + 1], file); + else + fputs (reg_names[REGNO (op)], file); } } else if (GET_CODE (op) == MEM) @@ -1851,6 +2228,9 @@ print_operand (file, op, letter) define such "LDnnn" to be either "Lnnn-LInnn-2.b", "Lnnn", or any other string, as necessary. This is accomplished via the ASM_OUTPUT_CASE_END macro. See m68k/sgs.h for an example; for versions without the bug. + Some assemblers refuse all the above solutions. The workaround is to + emit "K(pc,d0.l*2)" with K being a small constant known to give the + right behaviour. They also do not like things like "pea 1.w", so we simple leave off the .w on small constants. @@ -1860,6 +2240,21 @@ print_operand (file, op, letter) offset is output in word mode (eg movel a5@(_foo:w), a0). When generating -fPIC code the offset is output in long mode (eg movel a5@(_foo:l), a0) */ +#ifndef ASM_OUTPUT_CASE_FETCH +#ifdef MOTOROLA +#ifdef SGS +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%LLD%d(%Rpc,%s.", labelno, regname) +#else +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.", labelno, labelno, regname) +#endif +#else +#define ASM_OUTPUT_CASE_FETCH(file, labelno, regname)\ + asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:", labelno, labelno, regname) +#endif +#endif /* ASM_OUTPUT_CASE_FETCH */ + void print_operand_address (file, addr) FILE *file; @@ -1996,43 +2391,17 @@ print_operand_address (file, addr) } if (GET_CODE (ireg) == SIGN_EXTEND) { -#ifdef MOTOROLA -#ifdef SGS - asm_fprintf (file, "%LLD%d(%Rpc,%s.w", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (XEXP (ireg, 0))]); -#else - asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.w", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (XEXP (ireg, 0))]); -#endif -#else - asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:w", - CODE_LABEL_NUMBER (XEXP (addr, 0)), + ASM_OUTPUT_CASE_FETCH (file, CODE_LABEL_NUMBER (XEXP (addr, 0)), reg_names[REGNO (XEXP (ireg, 0))]); -#endif + fprintf (file, "w"); } else { -#ifdef MOTOROLA -#ifdef SGS - asm_fprintf (file, "%LLD%d(%Rpc,%s.l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (ireg)]); -#else - asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (ireg)]); -#endif -#else - asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), + ASM_OUTPUT_CASE_FETCH (file, CODE_LABEL_NUMBER (XEXP (addr, 0)), reg_names[REGNO (ireg)]); -#endif + fprintf (file, "l"); } if (scale != 1) { @@ -2048,24 +2417,10 @@ print_operand_address (file, addr) if (breg != 0 && ireg == 0 && GET_CODE (addr) == LABEL_REF && ! (flag_pic && breg == pic_offset_table_rtx)) { -#ifdef MOTOROLA -#ifdef SGS - asm_fprintf (file, "%LLD%d(%Rpc,%s.l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (breg)]); -#else - asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (breg)]); -#endif -#else - asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l", - CODE_LABEL_NUMBER (XEXP (addr, 0)), + ASM_OUTPUT_CASE_FETCH (file, CODE_LABEL_NUMBER (XEXP (addr, 0)), reg_names[REGNO (breg)]); -#endif - putc (')', file); + fprintf (file, "l)"); break; } if (ireg != 0 || breg != 0) @@ -2141,23 +2496,10 @@ print_operand_address (file, addr) else if (reg1 != 0 && GET_CODE (addr) == LABEL_REF && ! (flag_pic && reg1 == pic_offset_table_rtx)) { -#ifdef MOTOROLA -#ifdef SGS - asm_fprintf (file, "%LLD%d(%Rpc,%s.l)", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (reg1)]); -#else - asm_fprintf (file, "%LL%d-%LLI%d.b(%Rpc,%s.l)", - CODE_LABEL_NUMBER (XEXP (addr, 0)), + ASM_OUTPUT_CASE_FETCH (file, CODE_LABEL_NUMBER (XEXP (addr, 0)), reg_names[REGNO (reg1)]); -#endif -#else - asm_fprintf (file, "%Rpc@(%LL%d-%LLI%d-2:b,%s:l)", - CODE_LABEL_NUMBER (XEXP (addr, 0)), - CODE_LABEL_NUMBER (XEXP (addr, 0)), - reg_names[REGNO (reg1)]); -#endif + fprintf (file, "l)"); break; } /* FALL-THROUGH (is this really what we want? */ @@ -2243,3 +2585,36 @@ strict_low_part_peephole_ok (mode, first return 0; } + +/* Accept integer operands in the range 0..0xffffffff. We have to check the + range carefully since this predicate is used in DImode contexts. Also, we + need some extra crud to make it work when hosted on 64-bit machines. */ + +int +const_uint32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ +#if HOST_BITS_PER_WIDE_INT > 32 + /* All allowed constants will fit a CONST_INT. */ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) >= 0 && INTVAL (op) <= 0xffffffffL)); +#else + return ((GET_CODE (op) == CONST_INT && INTVAL (op) >= 0) + || (GET_CODE (op) == CONST_DOUBLE && CONST_DOUBLE_HIGH (op) == 0)); +#endif +} + +/* Accept integer operands in the range -0x80000000..0x7fffffff. We have + to check the range carefully since this predicate is used in DImode + contexts. */ + +int +const_sint32_operand (op, mode) + rtx op; + enum machine_mode mode; +{ + /* All allowed constants will fit a CONST_INT. */ + return (GET_CODE (op) == CONST_INT + && (INTVAL (op) >= (-0x7fffffff - 1) && INTVAL (op) <= 0x7fffffff)); +}