--- gcc/config/m68k/m68k.c 2018/04/24 18:21:09 1.1.1.3 +++ 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, 1994 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. */ @@ -62,7 +63,11 @@ 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); + } } @@ -694,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; @@ -766,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 @@ -859,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. */ @@ -871,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])) @@ -1874,7 +2157,12 @@ print_operand (file, op, letter) 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) @@ -2297,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)); +}