From 1d86aeab250b3c69bf826385bd6875cf0b9ea459 Mon Sep 17 00:00:00 2001 From: mkuvyrkov Date: Tue, 11 Sep 2007 13:56:30 +0000 Subject: [PATCH] * config/m68k/predicates.md (movsi_const0_operand, non_symbolic_call_operand): New predicates. * config/m68k/constraints.md: (Cs, Ci, C0, Cj, CQ, CW, CZ, CS, Ap, Ac): New constraints. * doc/md.texi (Constraints for Particular Machines: Motorola 680x0): Document constraints N, O, P, R, S, T, Q, U, W, Cs, Ci, C0, Cj, CQ, CW, CZ, CS, Ap and Ac. * config/m68k/m68k.md (UNSPEC_IB): New constant. (constraints.md): New include. (cpu, type, type1, opx, opy, opx_type, opy_type, size, opx_access, opx_mem, opy_mem, op_mem, guess, split): New attributes. (movdf_internal): Name pattern. Fix to use alternatives. Add split. Specify attributes. (pushdi): Add split. (tstsi_internal): Name pattern. Fix to use alternatives. Specify attributes. Split tstsi_internal_68020_cf from it. (tstsi_internal_68020_cf): New pattern. (tsthi_internal, tstqi_internal): Name pattern. Specify attributes. (tst_cf): Specify attributea. (cmpsi_cf): Name pattern. Specify attributes. (cmp_68881, cmp_cf): Specify type attribute. (pushexthisi_const): Fix to use alternatives. Specify attributes. (movsi_const0): Split movsi_const0_68000_10 and movsi_const0_68040_60 from it. Fix to use alternatives. Specify attributes. (movsi_const0_68040_10, movsi_const0_68040_60): New patterns. (movsi_cf, movstrictqi_cf): Fix to use alternatives. Specify attributes. (movsf_cf_soft): Specify attributes. (movdf_cf_soft): Add split. (pushasi, zero_extendhisi2_cf, zero_extendqisi2_cfv4, cfv4_extendhisi2, 68k_extendhisi2, extendqihi2, cfv4_extendqisi2, 68k_extendqisi2, truncdfsf2_cf): Specify attributes. (truncdfsf2_68881): Name pattern. Specify attributes. (floatsi2_cf, floathi2_68881, floathi2_cf, floatqi2_68881, floatqi2_cf, ftrunc2_cf, fixqi2_cf, fixhi2_cf, fixsi2_cf, adddi_dishl32): Specify attributes. (addsi3_5200): Fix to use alternatives. Specify attributes. Add splits. (add3_cf, subdi_dishl32): Specify attributes. (subsi3): Add alternative for subq.l. Specify attributes. (sub3_cf, mulhi3, mulhisi3): Specify attributes. (mulhisisi3_s, mulsi3_68020, mulsi3_cf): Name pattern. Specify attributes. (umulhisi3): Specify attributes. (mulhisisi3_z): Name pattern. Specify attributes. (fmul3_cf, div3_cf, negsi2_internal, negsi2_5200, sqrt2_68881, clzsi2, one_cmplsi2_5200, subreghi1ashrdi_const32, subregsi1ashrdi_const32, ashrsi3, subreg1lshrdi_const32, lshrsi3, bsetmemqi): Specify attributes. (bsetmemqi_ext): Name pattern. Specify attributes. (bclrmemqi): Specify attributes. (bclrmemqi_ext, scc, sls): Name pattern. Specify attributes. (beq, bne, bgt, bgtu, blt, bltu, bge, bgeu, ble, bleu): Specify attributes. (beq2, bne2, bgt2, bgtu2, blt2, bltu2, bge2, bgeu2, ble2, bleu2): Name pattern. Specify attributes. (jump): Specify attributes. (tablejump_internal): Name pattern. Specify attributes. (call_value): Split into non_symbolic_call_value, symbolic_call_value_jsr, symbolic_call_value_bsr. Fix to use alternatives. Specify attributes. (non_symbolic_call_value, symbolic_call_value_jsr, symbolic_call_value_bsr): New patterns. (nop, return, unlink, indirect_jump): Specify attributes. (trap): Fix condition. Specify attributes. (ib): New pattern. * config/m68k/m68k.c (m68k_symbolic_call_var): New variable. (override_options): Initialize it. Initialize m68k_sched_cpu. (CONST_METHOD): Rename to M68K_CONST_METHOD, move to m68k.h. (const_method): Make global, rename to m68k_const_method. (const_int_cost, output_move_const_into_data_reg): Update. (output_move_double): Parametrize to emit rtl code, rename to handle_move_double. (output_reg_adjust, emit_reg_adjust, output_compadr, output_movsi, emit_movsi): New static functions. (output_move_double): New function with semantics of old output_move_double. (m68k_emit_move_double): New function. (m68k_sched_cpu): New variable. (attr_op_type): New enum. (sched_guess_p): New variable. (sched_address_type, sched_operand_type, sched_attr_op_type): New static functions. (m68k_sched_attr_opx_type, m68k_sched_attr_opy_type, m68k_sched_attr_size, m68k_sched_attr_op_mem): New functions. (sched_branch_type): New static variable. (m68k_sched_branch_type): New function. * config/m68k/m68k.h (M68K_SYMBOLIC_CALL): New enum. (m68k_symbolic_call_var): Declare. (M68K_CONST_METHOD): Rename from CONST_METHOD. Move here from m68k.c. (m68k_const_method, m68k_emit_move_double, m68k_sched_cpu, m68k_sched_attr_opx_type, m68k_sched_attr_opy_type, m68k_sched_attr_size, m68k_sched_attr_op_mem, m68k_sched_branch_type): Declare. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@128377 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/ChangeLog | 102 +++++ gcc/config/m68k/constraints.md | 48 +++ gcc/config/m68k/m68k.c | 753 ++++++++++++++++++++++++++++++++---- gcc/config/m68k/m68k.h | 24 ++ gcc/config/m68k/m68k.md | 855 ++++++++++++++++++++++++++++++++--------- gcc/config/m68k/predicates.md | 14 + gcc/doc/md.texi | 60 ++- 7 files changed, 1591 insertions(+), 265 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 3e45698..add5753 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,105 @@ +2007-09-11 Maxim Kuvyrkov + + * config/m68k/predicates.md (movsi_const0_operand, + non_symbolic_call_operand): New predicates. + + * config/m68k/constraints.md: (Cs, Ci, C0, Cj, CQ, CW, CZ, CS, Ap, Ac): + New constraints. + * doc/md.texi (Constraints for Particular Machines: Motorola 680x0): + Document constraints N, O, P, R, S, T, Q, U, W, Cs, Ci, C0, Cj, CQ, + CW, CZ, CS, Ap and Ac. + + * config/m68k/m68k.md (UNSPEC_IB): New constant. + (constraints.md): New include. + (cpu, type, type1, opx, opy, opx_type, opy_type, size, opx_access, + opx_mem, opy_mem, op_mem, guess, split): New attributes. + (movdf_internal): Name pattern. Fix to use alternatives. Add split. + Specify attributes. + (pushdi): Add split. + (tstsi_internal): Name pattern. Fix to use alternatives. Specify + attributes. Split tstsi_internal_68020_cf from it. + (tstsi_internal_68020_cf): New pattern. + (tsthi_internal, tstqi_internal): Name pattern. Specify attributes. + (tst_cf): Specify attributea. + (cmpsi_cf): Name pattern. Specify attributes. + (cmp_68881, cmp_cf): Specify type attribute. + (pushexthisi_const): Fix to use alternatives. Specify + attributes. + (movsi_const0): Split movsi_const0_68000_10 and movsi_const0_68040_60 + from it. Fix to use alternatives. Specify attributes. + (movsi_const0_68040_10, movsi_const0_68040_60): New patterns. + (movsi_cf, movstrictqi_cf): Fix to use alternatives. Specify + attributes. + (movsf_cf_soft): Specify attributes. + (movdf_cf_soft): Add split. + (pushasi, zero_extendhisi2_cf, zero_extendqisi2_cfv4, + cfv4_extendhisi2, 68k_extendhisi2, extendqihi2, cfv4_extendqisi2, + 68k_extendqisi2, truncdfsf2_cf): Specify attributes. + (truncdfsf2_68881): Name pattern. Specify attributes. + (floatsi2_cf, floathi2_68881, floathi2_cf, + floatqi2_68881, floatqi2_cf, ftrunc2_cf, + fixqi2_cf, fixhi2_cf, fixsi2_cf, adddi_dishl32): + Specify attributes. + (addsi3_5200): Fix to use alternatives. Specify attributes. + Add splits. + (add3_cf, subdi_dishl32): Specify attributes. + (subsi3): Add alternative for subq.l. Specify attributes. + (sub3_cf, mulhi3, mulhisi3): Specify attributes. + (mulhisisi3_s, mulsi3_68020, mulsi3_cf): Name pattern. Specify + attributes. + (umulhisi3): Specify attributes. + (mulhisisi3_z): Name pattern. Specify attributes. + (fmul3_cf, div3_cf, negsi2_internal, negsi2_5200, + sqrt2_68881, clzsi2, one_cmplsi2_5200, subreghi1ashrdi_const32, + subregsi1ashrdi_const32, ashrsi3, subreg1lshrdi_const32, lshrsi3, + bsetmemqi): Specify attributes. + (bsetmemqi_ext): Name pattern. Specify attributes. + (bclrmemqi): Specify attributes. + (bclrmemqi_ext, scc, sls): Name pattern. Specify attributes. + (beq, bne, bgt, bgtu, blt, bltu, bge, bgeu, ble, bleu): Specify + attributes. + (beq2, bne2, bgt2, bgtu2, blt2, bltu2, bge2, bgeu2, ble2, bleu2): Name + pattern. Specify attributes. + (jump): Specify attributes. + (tablejump_internal): Name pattern. Specify attributes. + (call_value): Split into non_symbolic_call_value, + symbolic_call_value_jsr, symbolic_call_value_bsr. Fix to use + alternatives. Specify attributes. + (non_symbolic_call_value, symbolic_call_value_jsr, + symbolic_call_value_bsr): New patterns. + (nop, return, unlink, indirect_jump): Specify attributes. + (trap): Fix condition. Specify attributes. + (ib): New pattern. + + * config/m68k/m68k.c (m68k_symbolic_call_var): New variable. + (override_options): Initialize it. Initialize m68k_sched_cpu. + (CONST_METHOD): Rename to M68K_CONST_METHOD, move to m68k.h. + (const_method): Make global, rename to m68k_const_method. + (const_int_cost, output_move_const_into_data_reg): Update. + (output_move_double): Parametrize to emit rtl code, rename to + handle_move_double. + (output_reg_adjust, emit_reg_adjust, output_compadr, output_movsi, + emit_movsi): New static functions. + (output_move_double): New function with semantics of old + output_move_double. + (m68k_emit_move_double): New function. + (m68k_sched_cpu): New variable. + (attr_op_type): New enum. + (sched_guess_p): New variable. + (sched_address_type, sched_operand_type, sched_attr_op_type): + New static functions. + (m68k_sched_attr_opx_type, m68k_sched_attr_opy_type, + m68k_sched_attr_size, m68k_sched_attr_op_mem): New functions. + (sched_branch_type): New static variable. + (m68k_sched_branch_type): New function. + * config/m68k/m68k.h (M68K_SYMBOLIC_CALL): New enum. + (m68k_symbolic_call_var): Declare. + (M68K_CONST_METHOD): Rename from CONST_METHOD. Move here from m68k.c. + (m68k_const_method, m68k_emit_move_double, m68k_sched_cpu, + m68k_sched_attr_opx_type, m68k_sched_attr_opy_type, + m68k_sched_attr_size, m68k_sched_attr_op_mem, m68k_sched_branch_type): + Declare. + 2007-09-11 Jakub Jelinek * builtins.def (BUILT_IN_VA_ARG_PACK_LEN): New builtin. diff --git a/gcc/config/m68k/constraints.md b/gcc/config/m68k/constraints.md index 9cd9c29..592112a 100644 --- a/gcc/config/m68k/constraints.md +++ b/gcc/config/m68k/constraints.md @@ -104,3 +104,51 @@ (define_constraint "W" "Used for const_call_operands." (match_operand 0 "const_call_operand")) + +(define_constraint "Cs" + "symbol_ref or const." + (match_code "symbol_ref,const")) + +(define_constraint "Ci" + "const_int." + (and (match_code "const_int") + (match_test "true"))) + +(define_constraint "C0" + "const_int 0." + (and (match_code "const_int") + (match_test "ival == 0"))) + +(define_constraint "Cj" + "Range of signed numbers that don't fit in 16 bits." + (and (match_code "const_int") + (match_test "ival < -0x8000 || ival > 0x7FFF"))) + +(define_constraint "CQ" + "Integers valid for mvq." + (and (match_code "const_int") + (match_test "m68k_const_method (ival) == MOVQ"))) + +(define_constraint "CW" + "Integers valid for a moveq followed by a swap." + (and (match_code "const_int") + (match_test "m68k_const_method (ival) == SWAP"))) + +(define_constraint "CZ" + "Integers valid for mvz." + (and (match_code "const_int") + (match_test "m68k_const_method (ival) == MVZ"))) + +(define_constraint "CS" + "Integers valid for mvs." + (and (match_code "const_int") + (match_test "m68k_const_method (ival) == MVS"))) + +(define_constraint "Ap" + "push_operand." + (match_operand 0 "push_operand")) + +(define_constraint "Ac" + "Non-register operands allowed in clr." + (and (match_operand 0 "movsi_const0_operand") + (match_test "!REG_P (op)"))) diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 8f7aa34..654add3 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -353,6 +353,10 @@ unsigned int m68k_cpu_flags; in operand 0. */ const char *m68k_symbolic_call; const char *m68k_symbolic_jump; + +/* Enum variable that corresponds to m68k_symbolic_call values. */ +enum M68K_SYMBOLIC_CALL m68k_symbolic_call_var; + /* See whether TABLE has an entry with name NAME. Return true and store the entry in *ENTRY if so, otherwise return false and @@ -563,11 +567,11 @@ override_options (void) if (!flag_pic) { + m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_JSR; + #if MOTOROLA && !defined (USE_GAS) - m68k_symbolic_call = "jsr %a0"; m68k_symbolic_jump = "jmp %a0"; #else - m68k_symbolic_call = "jbsr %a0"; m68k_symbolic_jump = "jra %a0"; #endif } @@ -577,15 +581,10 @@ override_options (void) else if (TARGET_68020 || TARGET_ISAB || TARGET_ISAC) { if (TARGET_PCREL) - m68k_symbolic_call = "bsr.l %c0"; + m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_BSR_C; else - { -#if defined(USE_GAS) - m68k_symbolic_call = "bsr.l %p0"; -#else - m68k_symbolic_call = "bsr %p0"; -#endif - } + m68k_symbolic_call_var = M68K_SYMBOLIC_CALL_BSR_P; + if (TARGET_ISAC) /* No unconditional long branch */; else if (TARGET_PCREL) @@ -605,7 +604,48 @@ override_options (void) flag_no_function_cse = 1; } + switch (m68k_symbolic_call_var) + { + case M68K_SYMBOLIC_CALL_JSR: +#if MOTOROLA && !defined (USE_GAS) + m68k_symbolic_call = "jsr %a0"; +#else + m68k_symbolic_call = "jbsr %a0"; +#endif + break; + + case M68K_SYMBOLIC_CALL_BSR_C: + m68k_symbolic_call = "bsr.l %c0"; + break; + + case M68K_SYMBOLIC_CALL_BSR_P: +#if defined(USE_GAS) + m68k_symbolic_call = "bsr.l %p0"; +#else + m68k_symbolic_call = "bsr %p0"; +#endif + break; + + case M68K_SYMBOLIC_CALL_NONE: + gcc_assert (m68k_symbolic_call == NULL); + break; + + default: + gcc_unreachable (); + } + SUBTARGET_OVERRIDE_OPTIONS; + + /* Setup scheduling options. */ + if (TUNE_CFV2) + m68k_sched_cpu = CPU_CF_V2; + else + { + m68k_sched_cpu = CPU_UNKNOWN; + flag_schedule_insns = 0; + flag_schedule_insns_after_reload = 0; + flag_modulo_sched = 0; + } } /* Generate a macro of the form __mPREFIX_cpu_NAME, where PREFIX is the @@ -2037,14 +2077,13 @@ legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED, } -typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ, MVS, MVZ } CONST_METHOD; #define USE_MOVQ(i) ((unsigned) ((i) + 128) <= 255) /* Return the type of move that should be used for integer I. */ -static CONST_METHOD -const_method (HOST_WIDE_INT i) +M68K_CONST_METHOD +m68k_const_method (HOST_WIDE_INT i) { unsigned u; @@ -2090,7 +2129,7 @@ const_method (HOST_WIDE_INT i) static int const_int_cost (HOST_WIDE_INT i) { - switch (const_method (i)) + switch (m68k_const_method (i)) { case MOVQ: /* Constants between -128 and 127 are cheap due to moveq. */ @@ -2254,7 +2293,7 @@ output_move_const_into_data_reg (rtx *operands) HOST_WIDE_INT i; i = INTVAL (operands[1]); - switch (const_method (i)) + switch (m68k_const_method (i)) { case MVZ: return "mvzw %1,%0"; @@ -2478,11 +2517,18 @@ singlemove_string (rtx *operands) } -/* Output assembler code to perform a doubleword move insn - with operands OPERANDS. */ +/* Output assembler or rtl code to perform a doubleword move insn + with operands OPERANDS. + Pointers to 3 helper functions should be specified: + HANDLE_REG_ADJUST to adjust a register by a small value, + HANDLE_COMPADR to compute an address and + HANDLE_MOVSI to move 4 bytes. */ -const char * -output_move_double (rtx *operands) +static void +handle_move_double (rtx operands[2], + void (*handle_reg_adjust) (rtx, int), + void (*handle_compadr) (rtx [2]), + void (*handle_movsi) (rtx [2])) { enum { @@ -2540,10 +2586,9 @@ output_move_double (rtx *operands) if (optype0 == PUSHOP && optype1 == POPOP) { operands[0] = XEXP (XEXP (operands[0], 0), 0); - if (size == 12) - output_asm_insn ("sub%.l #12,%0", operands); - else - output_asm_insn ("subq%.l #8,%0", operands); + + handle_reg_adjust (operands[0], -size); + if (GET_MODE (operands[1]) == XFmode) operands[0] = gen_rtx_MEM (XFmode, operands[0]); else if (GET_MODE (operands[0]) == DFmode) @@ -2555,10 +2600,9 @@ output_move_double (rtx *operands) if (optype0 == POPOP && optype1 == PUSHOP) { operands[1] = XEXP (XEXP (operands[1], 0), 0); - if (size == 12) - output_asm_insn ("sub%.l #12,%1", operands); - else - output_asm_insn ("subq%.l #8,%1", operands); + + handle_reg_adjust (operands[1], -size); + if (GET_MODE (operands[1]) == XFmode) operands[1] = gen_rtx_MEM (XFmode, operands[1]); else if (GET_MODE (operands[1]) == DFmode) @@ -2600,8 +2644,8 @@ output_move_double (rtx *operands) } else { - middlehalf[0] = operands[0]; - latehalf[0] = operands[0]; + middlehalf[0] = adjust_address (operands[0], SImode, 0); + latehalf[0] = adjust_address (operands[0], SImode, 0); } if (optype1 == REGOP) @@ -2636,8 +2680,8 @@ output_move_double (rtx *operands) } else { - middlehalf[1] = operands[1]; - latehalf[1] = operands[1]; + middlehalf[1] = adjust_address (operands[1], SImode, 0); + latehalf[1] = adjust_address (operands[1], SImode, 0); } } else @@ -2648,7 +2692,7 @@ output_move_double (rtx *operands) else if (optype0 == OFFSOP) latehalf[0] = adjust_address (operands[0], SImode, size - 4); else - latehalf[0] = operands[0]; + latehalf[0] = adjust_address (operands[0], SImode, 0); if (optype1 == REGOP) latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1); @@ -2657,7 +2701,7 @@ output_move_double (rtx *operands) else if (optype1 == CNSTOP) split_double (operands[1], &operands[1], &latehalf[1]); else - latehalf[1] = operands[1]; + latehalf[1] = adjust_address (operands[1], SImode, 0); } /* If insn is effectively movd N(sp),-(sp) then we will do the @@ -2687,8 +2731,9 @@ output_move_double (rtx *operands) compadr: xops[0] = latehalf[0]; xops[1] = XEXP (operands[1], 0); - output_asm_insn ("lea %a1,%0", xops); - if (GET_MODE (operands[1]) == XFmode ) + + handle_compadr (xops); + if (GET_MODE (operands[1]) == XFmode) { operands[1] = gen_rtx_MEM (XFmode, latehalf[0]); middlehalf[1] = adjust_address (operands[1], DImode, size - 8); @@ -2718,10 +2763,11 @@ output_move_double (rtx *operands) gcc_assert (!addreg0 && !addreg1); /* 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 ""; + handle_movsi (operands); + handle_movsi (latehalf); + handle_movsi (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 @@ -2745,85 +2791,194 @@ output_move_double (rtx *operands) { /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) - { - if (size == 12) - output_asm_insn ("addq%.l #8,%0", &addreg0); - else - output_asm_insn ("addq%.l #4,%0", &addreg0); - } + handle_reg_adjust (addreg0, size - 4); if (addreg1) - { - if (size == 12) - output_asm_insn ("addq%.l #8,%0", &addreg1); - else - output_asm_insn ("addq%.l #4,%0", &addreg1); - } + handle_reg_adjust (addreg1, size - 4); /* Do that word. */ - output_asm_insn (singlemove_string (latehalf), latehalf); + handle_movsi (latehalf); /* Undo the adds we just did. */ if (addreg0) - output_asm_insn ("subq%.l #4,%0", &addreg0); + handle_reg_adjust (addreg0, -4); if (addreg1) - output_asm_insn ("subq%.l #4,%0", &addreg1); + handle_reg_adjust (addreg1, -4); if (size == 12) { - output_asm_insn (singlemove_string (middlehalf), middlehalf); + handle_movsi (middlehalf); + if (addreg0) - output_asm_insn ("subq%.l #4,%0", &addreg0); + handle_reg_adjust (addreg0, -4); if (addreg1) - output_asm_insn ("subq%.l #4,%0", &addreg1); + handle_reg_adjust (addreg1, -4); } /* Do low-numbered word. */ - return singlemove_string (operands); + + handle_movsi (operands); + return; } /* Normal case: do the two words, low-numbered first. */ - output_asm_insn (singlemove_string (operands), operands); + handle_movsi (operands); /* Do the middle one of the three words for long double */ if (size == 12) { if (addreg0) - output_asm_insn ("addq%.l #4,%0", &addreg0); + handle_reg_adjust (addreg0, 4); if (addreg1) - output_asm_insn ("addq%.l #4,%0", &addreg1); + handle_reg_adjust (addreg1, 4); - output_asm_insn (singlemove_string (middlehalf), middlehalf); + handle_movsi (middlehalf); } /* Make any unoffsettable addresses point at high-numbered word. */ if (addreg0) - output_asm_insn ("addq%.l #4,%0", &addreg0); + handle_reg_adjust (addreg0, 4); if (addreg1) - output_asm_insn ("addq%.l #4,%0", &addreg1); + handle_reg_adjust (addreg1, 4); /* Do that word. */ - output_asm_insn (singlemove_string (latehalf), latehalf); + handle_movsi (latehalf); /* Undo the adds we just did. */ if (addreg0) + handle_reg_adjust (addreg0, -(size - 4)); + if (addreg1) + handle_reg_adjust (addreg1, -(size - 4)); + + return; +} + +/* Output assembler code to adjust REG by N. */ +static void +output_reg_adjust (rtx reg, int n) +{ + const char *s; + + gcc_assert (GET_MODE (reg) == SImode + && -12 <= n && n != 0 && n <= 12); + + switch (n) { - if (size == 12) - output_asm_insn ("subq%.l #8,%0", &addreg0); - else - output_asm_insn ("subq%.l #4,%0", &addreg0); + case 12: + s = "add%.l #12,%0"; + break; + + case 8: + s = "addq%.l #8,%0"; + break; + + case 4: + s = "addq%.l #4,%0"; + break; + + case -12: + s = "sub%.l #12,%0"; + break; + + case -8: + s = "subq%.l #8,%0"; + break; + + case -4: + s = "subq%.l #4,%0"; + break; + + default: + gcc_unreachable (); + s = NULL; } - if (addreg1) + + output_asm_insn (s, ®); +} + +/* Emit rtl code to adjust REG by N. */ +static void +emit_reg_adjust (rtx reg1, int n) +{ + rtx reg2; + + gcc_assert (GET_MODE (reg1) == SImode + && -12 <= n && n != 0 && n <= 12); + + reg1 = copy_rtx (reg1); + reg2 = copy_rtx (reg1); + + if (n < 0) + emit_insn (gen_subsi3 (reg1, reg2, GEN_INT (-n))); + else if (n > 0) + emit_insn (gen_addsi3 (reg1, reg2, GEN_INT (n))); + else + gcc_unreachable (); +} + +/* Output assembler to load address OPERANDS[0] to register OPERANDS[1]. */ +static void +output_compadr (rtx operands[2]) +{ + output_asm_insn ("lea %a1,%0", operands); +} + +/* Output the best assembler insn for moving operands[1] into operands[0] + as a fullword. */ +static void +output_movsi (rtx operands[2]) +{ + output_asm_insn (singlemove_string (operands), operands); +} + +/* Copy OP and change its mode to MODE. */ +static rtx +copy_operand (rtx op, enum machine_mode mode) +{ + /* ??? This looks really ugly. There must be a better way + to change a mode on the operand. */ + if (GET_MODE (op) != VOIDmode) { - if (size == 12) - output_asm_insn ("subq%.l #8,%0", &addreg1); + if (REG_P (op)) + op = gen_rtx_REG (mode, REGNO (op)); else - output_asm_insn ("subq%.l #4,%0", &addreg1); + { + op = copy_rtx (op); + PUT_MODE (op, mode); + } } + return op; +} + +/* Emit rtl code for moving operands[1] into operands[0] as a fullword. */ +static void +emit_movsi (rtx operands[2]) +{ + operands[0] = copy_operand (operands[0], SImode); + operands[1] = copy_operand (operands[1], SImode); + + emit_insn (gen_movsi (operands[0], operands[1])); +} + +/* Output assembler code to perform a doubleword move insn + with operands OPERANDS. */ +const char * +output_move_double (rtx *operands) +{ + handle_move_double (operands, + output_reg_adjust, output_compadr, output_movsi); + return ""; } +/* Output rtl code to perform a doubleword move insn + with operands OPERANDS. */ +void +m68k_emit_move_double (rtx operands[2]) +{ + handle_move_double (operands, emit_reg_adjust, emit_movsi, emit_movsi); +} /* Ensure mode of ORIG, a REG rtx, is MODE. Returns either ORIG or a new rtx with the correct mode. */ @@ -4432,3 +4587,455 @@ m68k_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED) return false; } #endif + +/* CPU to schedule the program for. */ +enum attr_cpu m68k_sched_cpu; + +/* Operand type. */ +enum attr_op_type + { + /* No operand. */ + OP_TYPE_NONE, + + /* Register. */ + OP_TYPE_REG, + + /* Implicit mem reference (e.g. stack). */ + OP_TYPE_MEM1, + + /* Memory without offset or indexing. EA modes 2, 3 and 4. */ + OP_TYPE_MEM234, + + /* Memory with offset but without indexing. EA mode 5. */ + OP_TYPE_MEM5, + + /* Memory with indexing. EA mode 6. */ + OP_TYPE_MEM6, + + /* Memory referenced by absolute address. EA mode 7. */ + OP_TYPE_MEM7, + + /* Immediate operand that doesn't require extension word. */ + OP_TYPE_IMM_Q, + + /* Immediate 16 bit operand. */ + OP_TYPE_IMM_W, + + /* Immediate 32 bit operand. */ + OP_TYPE_IMM_L + }; + +/* True if current insn doesn't have complete pipeline description. */ +static bool sched_guess_p; + +/* Return type of memory ADDR_RTX refers to. */ +static enum attr_op_type +sched_address_type (enum machine_mode mode, rtx addr_rtx) +{ + struct m68k_address address; + + if (!m68k_decompose_address (mode, addr_rtx, + reload_completed, &address)) + { + gcc_assert (sched_guess_p); + /* Reload will likely fix the address to be in the register. */ + return OP_TYPE_MEM234; + } + + if (address.scale != 0) + return OP_TYPE_MEM6; + + if (address.base != NULL_RTX) + { + if (address.offset == NULL_RTX) + return OP_TYPE_MEM234; + + return OP_TYPE_MEM5; + } + + gcc_assert (address.offset != NULL_RTX); + + return OP_TYPE_MEM7; +} + +/* Return type of the operand OP. + If ADDRESS_P is true, return type of memory location OP refers to. */ +static enum attr_op_type +sched_operand_type (rtx op, bool address_p) +{ + gcc_assert (op != NULL_RTX); + + if (address_p) + return sched_address_type (QImode, op); + + if (memory_operand (op, VOIDmode)) + return sched_address_type (GET_MODE (op), XEXP (op, 0)); + + if (register_operand (op, VOIDmode)) + return OP_TYPE_REG; + + if (GET_CODE (op) == CONST_INT) + { + /* ??? Below condition should probably check if the operation is + signed or unsigned. */ + if (IN_RANGE (INTVAL (op), -0x8000, 0x7fff)) + return OP_TYPE_IMM_W; + + return OP_TYPE_IMM_L; + } + + if (GET_CODE (op) == CONST_DOUBLE) + { + switch (GET_MODE (op)) + { + case SFmode: + return OP_TYPE_IMM_W; + + case VOIDmode: + case DFmode: + return OP_TYPE_IMM_L; + + default: + gcc_unreachable (); + } + } + + if (symbolic_operand (op, VOIDmode) + || LABEL_P (op)) + { + switch (GET_MODE (op)) + { + case QImode: + return OP_TYPE_IMM_Q; + + case HImode: + return OP_TYPE_IMM_W; + + case SImode: + return OP_TYPE_IMM_L; + + default: + if (GET_CODE (op) == SYMBOL_REF) + /* ??? Just a guess. Probably we can guess better using length + attribute of the instructions. */ + return OP_TYPE_IMM_W; + + return OP_TYPE_IMM_L; + } + } + + gcc_assert (sched_guess_p); + + return OP_TYPE_REG; +} + +/* Return type of INSN's operand X (if OPX_P) or operand Y (if !OPX_P). + If ADDRESS_P is true, return type of memory location operand refers to. */ +static enum attr_op_type +sched_attr_op_type (rtx insn, bool opx_p, bool address_p) +{ + int i; + + extract_constrain_insn_cached (insn); + + if (opx_p) + i = get_attr_opx (insn); + else + i = get_attr_opy (insn); + + if (i >= recog_data.n_operands) + { + gcc_assert (sched_guess_p); + return OP_TYPE_REG; + } + + return sched_operand_type (recog_data.operand[i], address_p); +} + +/* Implement opx_type attribute. + Return type of INSN's operand X. + If ADDRESS_P is true, return type of memory location operand refers to. */ +enum attr_opx_type +m68k_sched_attr_opx_type (rtx insn, int address_p) +{ + sched_guess_p = (get_attr_guess (insn) == GUESS_YES); + + switch (sched_attr_op_type (insn, true, address_p != 0)) + { + case OP_TYPE_REG: + return OPX_TYPE_REG; + + case OP_TYPE_MEM1: + return OPX_TYPE_MEM1; + + case OP_TYPE_MEM234: + return OPX_TYPE_MEM234; + + case OP_TYPE_MEM5: + return OPX_TYPE_MEM5; + + case OP_TYPE_MEM6: + return OPX_TYPE_MEM6; + + case OP_TYPE_MEM7: + return OPX_TYPE_MEM7; + + case OP_TYPE_IMM_Q: + return OPX_TYPE_IMM_Q; + + case OP_TYPE_IMM_W: + return OPX_TYPE_IMM_W; + + case OP_TYPE_IMM_L: + return OPX_TYPE_IMM_L; + + default: + gcc_unreachable (); + return 0; + } +} + +/* Implement opy_type attribute. + Return type of INSN's operand Y. + If ADDRESS_P is true, return type of memory location operand refers to. */ +enum attr_opy_type +m68k_sched_attr_opy_type (rtx insn, int address_p) +{ + sched_guess_p = (get_attr_guess (insn) == GUESS_YES); + + switch (sched_attr_op_type (insn, false, address_p != 0)) + { + case OP_TYPE_REG: + return OPY_TYPE_REG; + + case OP_TYPE_MEM1: + return OPY_TYPE_MEM1; + + case OP_TYPE_MEM234: + return OPY_TYPE_MEM234; + + case OP_TYPE_MEM5: + return OPY_TYPE_MEM5; + + case OP_TYPE_MEM6: + return OPY_TYPE_MEM6; + + case OP_TYPE_MEM7: + return OPY_TYPE_MEM7; + + case OP_TYPE_IMM_Q: + return OPY_TYPE_IMM_Q; + + case OP_TYPE_IMM_W: + return OPY_TYPE_IMM_W; + + case OP_TYPE_IMM_L: + return OPY_TYPE_IMM_L; + + default: + gcc_unreachable (); + return 0; + } +} + +/* Return the size of INSN. */ +int +m68k_sched_attr_size (rtx insn) +{ + int size; + + sched_guess_p = (get_attr_guess (insn) == GUESS_YES); + + switch (get_attr_type1 (insn)) + { + case TYPE1_MUL_L: + size = 2; + break; + + default: + size = 1; + break; + } + + switch (get_attr_opx_type (insn)) + { + case OPX_TYPE_NONE: + case OPX_TYPE_REG: + case OPX_TYPE_MEM1: + case OPX_TYPE_MEM234: + case OPY_TYPE_IMM_Q: + break; + + case OPX_TYPE_MEM5: + case OPX_TYPE_MEM6: + /* Here we assume that most absolute references are short. */ + case OPX_TYPE_MEM7: + case OPY_TYPE_IMM_W: + ++size; + break; + + case OPY_TYPE_IMM_L: + size += 2; + break; + + default: + gcc_unreachable (); + } + + switch (get_attr_opy_type (insn)) + { + case OPY_TYPE_NONE: + case OPY_TYPE_REG: + case OPY_TYPE_MEM1: + case OPY_TYPE_MEM234: + case OPY_TYPE_IMM_Q: + break; + + case OPY_TYPE_MEM5: + case OPY_TYPE_MEM6: + /* Here we assume that most absolute references are short. */ + case OPY_TYPE_MEM7: + case OPY_TYPE_IMM_W: + ++size; + break; + + case OPY_TYPE_IMM_L: + size += 2; + break; + + default: + gcc_unreachable (); + } + + if (size > 3) + { + gcc_assert (sched_guess_p); + + size = 3; + } + + return size; +} + +/* Implement op_mem attribute. */ +enum attr_op_mem +m68k_sched_attr_op_mem (rtx insn) +{ + enum attr_opy_mem opy; + enum attr_opx_mem opx; + + sched_guess_p = (get_attr_guess (insn) == GUESS_YES); + + opy = get_attr_opy_mem (insn); + opx = get_attr_opx_mem (insn); + + if (opy == OPY_MEM_R && opx == OPX_MEM_R) + return OP_MEM_00; + + if (opy == OPY_MEM_R && opx == OPX_MEM_M) + { + switch (get_attr_opx_access (insn)) + { + case OPX_ACCESS_R: + return OP_MEM_10; + + case OPX_ACCESS_W: + return OP_MEM_01; + + case OPX_ACCESS_RW: + return OP_MEM_11; + + default: + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; + } + } + + if (opy == OPY_MEM_R && opx == OPX_MEM_I) + { + switch (get_attr_opx_access (insn)) + { + case OPX_ACCESS_R: + return OP_MEM_I0; + + case OPX_ACCESS_W: + return OP_MEM_0I; + + case OPX_ACCESS_RW: + return OP_MEM_I1; + + default: + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; + } + } + + if (opy == OPY_MEM_M && opx == OPX_MEM_R) + return OP_MEM_10; + + if (opy == OPY_MEM_M && opx == OPX_MEM_M) + { + switch (get_attr_opx_access (insn)) + { + case OPX_ACCESS_W: + return OP_MEM_11; + + default: + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; + } + } + + if (opy == OPY_MEM_M && opx == OPX_MEM_I) + { + switch (get_attr_opx_access (insn)) + { + case OPX_ACCESS_W: + return OP_MEM_1I; + + default: + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; + } + } + + if (opy == OPY_MEM_I && opx == OPX_MEM_R) + return OP_MEM_I0; + + + if (opy == OPY_MEM_I && opx == OPX_MEM_M) + { + switch (get_attr_opx_access (insn)) + { + case OPX_ACCESS_W: + return OP_MEM_I1; + + default: + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; + } + } + + gcc_assert (sched_guess_p); + return OP_MEM_UNKNOWN; +} + +/* Jump instructions types. Indexed by INSN_UID. + The same rtl insn can be expanded into different asm instructions + depending on the cc0_status. To properly determine type of jump + instructions we scan instruction stream and map jumps types to this + array. */ +static enum attr_type *sched_branch_type; + +/* Return the type of the jump insn. */ +enum attr_type +m68k_sched_branch_type (rtx insn) +{ + enum attr_type type; + + type = sched_branch_type[INSN_UID (insn)]; + + gcc_assert (type != 0); + + return type; +} diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index 96756f3..3767413 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -1125,3 +1125,27 @@ extern enum fpu_type m68k_fpu; extern unsigned int m68k_cpu_flags; extern const char *m68k_symbolic_call; extern const char *m68k_symbolic_jump; + +enum M68K_SYMBOLIC_CALL { M68K_SYMBOLIC_CALL_NONE, M68K_SYMBOLIC_CALL_JSR, + M68K_SYMBOLIC_CALL_BSR_C, M68K_SYMBOLIC_CALL_BSR_P }; + +extern enum M68K_SYMBOLIC_CALL m68k_symbolic_call_var; + +/* ??? HOST_WIDE_INT is not being defined for auto-generated files. + Workaround that. */ +#ifdef HOST_WIDE_INT +typedef enum { MOVL, SWAP, NEGW, NOTW, NOTB, MOVQ, MVS, MVZ } + M68K_CONST_METHOD; + +extern M68K_CONST_METHOD m68k_const_method (HOST_WIDE_INT); +#endif + +extern void m68k_emit_move_double (rtx [2]); + +extern enum attr_cpu m68k_sched_cpu; + +extern enum attr_opx_type m68k_sched_attr_opx_type (rtx, int); +extern enum attr_opy_type m68k_sched_attr_opy_type (rtx, int); +extern int m68k_sched_attr_size (rtx); +extern enum attr_op_mem m68k_sched_attr_op_mem (rtx); +extern enum attr_type m68k_sched_branch_type (rtx); diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index 99ee142..63c0a0e 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -114,6 +114,7 @@ [(UNSPEC_SIN 1) (UNSPEC_COS 2) (UNSPEC_GOT 3) + (UNSPEC_IB 4) ]) ;; UNSPEC_VOLATILE usage: @@ -136,6 +137,205 @@ (include "predicates.md") (include "constraints.md") +;; :::::::::::::::::::: +;; :: +;; :: Attributes +;; :: +;; :::::::::::::::::::: + +;; Processor type. +(define_attr "cpu" "cf_v2, unknown" (const (symbol_ref "m68k_sched_cpu"))) + +;; Instruction type. +;; Basically, an asm pattern. +(define_attr "type" + "add_l, addq_l, asr_l, bcc, bclr, bra, bset, bsr, + clr_b, clr_w, clr_l, cmp_l, + ext_w, extb_l, ext_l, + fadd, fcmp, fdiv, ff1, fintrz, fmove, fmul, fsqrt, fsub, ftst, jmp, jsr, + ib, + lea, lsr_l, + move_b, move_w, move_l, moveq_l, mov3q_l, mvs_b, mvs_w, mvz_b, mvz_w, + muls_w, muls_l, mulu_w, mulu_l, + neg_l, nop, not_l, + pea, rts, + scc, sub_l, subq_l, + trap, tst_b, tst_l, tst_w, + unlk, unknown" + (const_string "unknown")) + +;; Instruction type for use in scheduling description. +;; _l and _w suffixes indicate size of the operands of instruction. +;; alu - usual arithmetic or logic instruction. +;; alu_reg1 - arithmetic or logic instruction with one operand that is +;; a register. +;; alu_regx - arithmetic or logic instruction which has a register for its +;; X operand. +;; aluq - arithmetic or logic instruction which has a quick immediate (the one +;; that is encoded in the instruction word) for its Y operand. +;; - corresponding asm instructions. +(define_attr "type1" + "alu_l, alu_reg1, alu_regx, aluq_l, bcc, bra, bsr, clr, cmp_l, jmp, jsr, lea, + mov3q_l, move, move_l, moveq_l, mul_l, mul_w, pea, rts, tst, tst_l, unlk, + unknown" + (cond [(eq_attr "type" "add_l,sub_l") (const_string "alu_l") + (eq_attr "type" "ext_w,extb_l,ext_l,neg_l,not_l") + (const_string "alu_reg1") + (eq_attr "type" "asr_l,lsr_l") (const_string "alu_regx") + (eq_attr "type" "addq_l,subq_l") (const_string "aluq_l") + (eq_attr "type" "bcc") (const_string "bcc") + (eq_attr "type" "bra") (const_string "bra") + (eq_attr "type" "bsr") (const_string "bsr") + (eq_attr "type" "clr_b,clr_l,clr_w") (const_string "clr") + (eq_attr "type" "cmp_l") (const_string "cmp_l") + (eq_attr "type" "jmp") (const_string "jmp") + (eq_attr "type" "jsr") (const_string "jsr") + (eq_attr "type" "lea") (const_string "lea") + (eq_attr "type" "mov3q_l") (const_string "mov3q_l") + (eq_attr "type" "move_b,move_w") (const_string "move") + (eq_attr "type" "move_l") (const_string "move_l") + (eq_attr "type" "moveq_l") (const_string "moveq_l") + (eq_attr "type" "muls_l,mulu_l") (const_string "mul_l") + (eq_attr "type" "muls_w,mulu_w") (const_string "mul_w") + (eq_attr "type" "pea") (const_string "pea") + (eq_attr "type" "rts") (const_string "rts") + (eq_attr "type" "tst_b,tst_w") (const_string "tst") + (eq_attr "type" "tst_l") (const_string "tst_l") + (eq_attr "type" "unlk") (const_string "unlk")] + (const_string "unknown"))) + +;; Index of the X or Y operand in recog_data.operand[]. +;; Should be used only within opx_type and opy_type. +(define_attr "opx" "" (const_int 0)) +(define_attr "opy" "" (const_int 1)) + +;; Type of the X operand. +;; See m68k.c: enum attr_op_type. +(define_attr "opx_type" + "none, reg, mem1, mem234, mem5, mem6, mem7, imm_q, imm_w, imm_l" + (cond [(eq_attr "type1" "rts,unlk") (const_string "none") + (eq_attr "type1" "alu_reg1,alu_regx,lea,moveq_l,mul_l,mul_w") + (const_string "reg") + (eq_attr "type1" "pea") (const_string "mem1") + (eq_attr "type1" "bcc") (const_string "imm_q") + (eq_attr "type1" "bra,bsr") (const_string "imm_w") + (eq_attr "type1" "jmp,jsr") + (symbol_ref "m68k_sched_attr_opx_type (insn, 1)")] + (symbol_ref "m68k_sched_attr_opx_type (insn, 0)"))) + +;; Type of the Y operand. +;; See m68k.c: enum attr_op_type. +(define_attr "opy_type" + "none, reg, mem1, mem234, mem5, mem6, mem7, imm_q, imm_w, imm_l" + (cond [(eq_attr "type1" "alu_reg1,bcc,bra,bsr,clr,jmp,jsr,rts,tst,tst_l, + unlk") (const_string "none") + (eq_attr "type1" "mov3q_l,moveq_l,aluq_l") (const_string "imm_q") + (eq_attr "type1" "lea,pea") + (symbol_ref "m68k_sched_attr_opy_type (insn, 1)")] + (symbol_ref "m68k_sched_attr_opy_type (insn, 0)"))) + +;; Instruction size in words. +(define_attr "size" "" + (cond [(eq_attr "type1" "alu_reg1,moveq_l,rts,unlk") (const_int 1)] + (symbol_ref "m68k_sched_attr_size (insn)"))) + +;; Access to the X operand: none, read, write, read/write, unknown. +;; Access to the Y operand is either none (if opy_type is none) +;; or read otherwise. +(define_attr "opx_access" "none, r, w, rw, unknown" + (cond [(eq_attr "type1" "rts,unlk") (const_string "none") + (eq_attr "type1" "bcc,bra,bsr,cmp_l,jmp,jsr,tst,tst_l") + (const_string "r") + (eq_attr "type1" "clr,lea,mov3q_l,move,move_l,moveq_l,pea") + (const_string "w") + (eq_attr "type1" "alu_l,alu_reg1,alu_regx,aluq_l") + (const_string "rw")] + (const_string "unknown"))) + +;; Memory relation of operands: +;; r - register or immediate operand +;; m - non-indexed memory location +;; i - indexed memory location + +(define_attr "opx_mem" "r, m, i, unknown" + (cond [(eq_attr "opx_type" "none,reg,imm_q,imm_w,imm_l") (const_string "r") + (eq_attr "opx_type" "mem1,mem234,mem5,mem7") (const_string "m") + (eq_attr "opx_type" "mem6") (const_string "i")] + (const_string "unknown"))) + +(define_attr "opy_mem" "r, m, i, unknown" + (cond [(eq_attr "opy_type" "none,reg,imm_q,imm_w,imm_l") (const_string "r") + (eq_attr "opy_type" "mem1,mem234,mem5,mem7") (const_string "m") + (eq_attr "opy_type" "mem6") (const_string "i")] + (const_string "unknown"))) + +;; Memory accesses of the insn. +;; 00 - no memory references +;; 10 - memory is read +;; i10 - indexed memory is read +;; 01 - memory is written +;; 0i1 - indexed memory is written +;; 11 - memory is read, memory is written +;; i11 - indexed memory is read, memory is written +;; 1i1 - memory is read, indexed memory is written +;; +;; unknown - should now occur on normal insn. +;; ??? This attribute is implemented in C to spare genattrtab from +;; ??? optimizing it. +(define_attr "op_mem" "00, 10, i0, 01, 0i, 11, i1, 1i, unknown" +; (cond [(and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "r")) +; (const_string "00") +; +; (and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "m")) +; (cond [(eq_attr "opx_access" "r") (const_string "10") +; (eq_attr "opx_access" "w") (const_string "01") +; (eq_attr "opx_access" "rw") (const_string "11")] +; (const_string "unknown")) +; +; (and (eq_attr "opy_mem" "r") (eq_attr "opx_mem" "i")) +; (cond [(eq_attr "opx_access" "r") (const_string "i0") +; (eq_attr "opx_access" "w") (const_string "0i") +; (eq_attr "opx_access" "rw") (const_string "i1")] +; (const_string "unknown")) +; +; (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "r")) +; (const_string "10") +; +; (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "m")) +; (cond [(eq_attr "opx_access" "w") (const_string "11")] +; (const_string "unknown")) +; +; (and (eq_attr "opy_mem" "m") (eq_attr "opx_mem" "i")) +; (cond [(eq_attr "opx_access" "w") (const_string "1i")] +; (const_string "unknown")) +; +; (and (eq_attr "opy_mem" "i") (eq_attr "opx_mem" "r")) +; (const_string "i0") +; +; (and (eq_attr "opy_mem" "i") (eq_attr "opx_mem" "m")) +; (cond [(eq_attr "opx_access" "w") (const_string "i1")] +; (const_string "unknown"))] +; (const_string "unknown")) + (symbol_ref "m68k_sched_attr_op_mem (insn)")) + +;; Attribute to support partial automata description. +;; This attribute has value 'yes' for instructions that are not +;; fully handled yet. +(define_attr "guess" "yes, no" + (cond [(ior (eq (symbol_ref "reload_completed") (const_int 0)) + (eq_attr "type1" "unknown")) + (const_string "yes")] + (const_string "no"))) + +;; Attribute to support statistics gathering. +;; Todo means that insn lacks something to get pipeline description. +;; Done means that insn was transformed to suit pipeline description. +;; Nothing means that insn was originally good enough for scheduling. +(define_attr "split" "todo, done, nothing" + (if_then_else (eq_attr "type" "unknown") + (const_string "todo") + (const_string "nothing"))) + ;; Mode macros for floating point operations. ;; Valid floating point modes (define_mode_iterator FP [SF DF (XF "TARGET_68881")]) @@ -150,22 +350,33 @@ ;; Allowable 68881 constant constraints (define_mode_attr const [(SF "F") (DF "G") (XF "")]) -(define_insn "" - [(set (match_operand:DF 0 "push_operand" "=m") - (match_operand:DF 1 "general_operand" "ro<>fE"))] + +(define_insn_and_split "*movdf_internal" + [(set (match_operand:DF 0 "push_operand" "=m, m") + (match_operand:DF 1 "general_operand" "f, ro<>E"))] "" + "@ + fmove%.d %f1,%0 + #" + "&& reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 1)" + [(const_int 0)] { - if (FP_REG_P (operands[1])) - return "fmove%.d %f1,%0"; - return output_move_double (operands); -}) + m68k_emit_move_double (operands); + DONE; +} + [(set_attr "type" "fmove,*") + (set_attr "split" "done,*")]) -(define_insn "pushdi" +(define_insn_and_split "pushdi" [(set (match_operand:DI 0 "push_operand" "=m") (match_operand:DI 1 "general_operand" "ro<>Fi"))] "" + "#" + "&& reload_completed" + [(const_int 0)] { - return output_move_double (operands); + m68k_emit_move_double (operands); + DONE; }) ;; We don't want to allow a constant operand for test insns because @@ -194,12 +405,12 @@ xoperands[0] = operands[2]; xoperands[1] = operands[0]; output_move_double (xoperands); - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "neg%.l %R2\;negx%.l %2"; } if (find_reg_note (insn, REG_DEAD, operands[0])) { - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "neg%.l %R0\;negx%.l %0"; } else @@ -217,18 +428,24 @@ "" "m68k_last_compare_had_fp_operands = 0;") -(define_insn "" +;; If you think that the 68020 does not support tstl a0, +;; reread page B-167 of the 68020 manual more carefully. +(define_insn "*tstsi_internal_68020_cf" [(set (cc0) (match_operand:SI 0 "nonimmediate_operand" "rm"))] - "" -{ - if (TARGET_68020 || TARGET_COLDFIRE || ! ADDRESS_REG_P (operands[0])) - return "tst%.l %0"; - /* If you think that the 68020 does not support tstl a0, - reread page B-167 of the 68020 manual more carefully. */ - /* On an address reg, cmpw may replace cmpl. */ - return "cmp%.w #0,%0"; -}) + "TARGET_68020 || TARGET_COLDFIRE" + "tst%.l %0" + [(set_attr "type" "tst_l")]) + +;; On an address reg, cmpw may replace cmpl. +(define_insn "*tstsi_internal" + [(set (cc0) + (match_operand:SI 0 "nonimmediate_operand" "dm,r"))] + "!(TARGET_68020 || TARGET_COLDFIRE)" + "@ + tst%.l %0 + cmp%.w #0,%0" + [(set_attr "type" "tst_l,*")]) ;; This can't use an address register, because comparisons ;; with address registers as second operand always test the whole word. @@ -238,11 +455,12 @@ "" "m68k_last_compare_had_fp_operands = 0;") -(define_insn "" +(define_insn "*tsthi_internal" [(set (cc0) (match_operand:HI 0 "nonimmediate_operand" "dm"))] "" - "tst%.w %0") + "tst%.w %0" + [(set_attr "type" "tst_w")]) (define_expand "tstqi" [(set (cc0) @@ -250,11 +468,12 @@ "" "m68k_last_compare_had_fp_operands = 0;") -(define_insn "" +(define_insn "*tstqi_internal" [(set (cc0) (match_operand:QI 0 "nonimmediate_operand" "dm"))] "" - "tst%.b %0") + "tst%.b %0" + [(set_attr "type" "tst_b")]) (define_expand "tst" [(set (cc0) @@ -284,7 +503,8 @@ if (FP_REG_P (operands[0])) return "ftst%.d %0"; return "ftst%. %0"; -}) +} + [(set_attr "type" "ftst")]) ;; compare instructions. @@ -309,7 +529,7 @@ return "sub%.l %R2,%R0\;subx%.l %2,%0"; else { - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "sub%.l %R1,%R0\;subx%.l %1,%0"; } }) @@ -335,7 +555,7 @@ if (REG_P (operands[1]) || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) { - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "cmp%.l %d0,%d1"; } if (ADDRESS_REG_P (operands[0]) @@ -346,7 +566,7 @@ return "cmp%.l %d1,%d0"; }) -(define_insn "" +(define_insn "*cmpsi_cf" [(set (cc0) (compare (match_operand:SI 0 "nonimmediate_operand" "mrKs,r") (match_operand:SI 1 "general_operand" "r,mrKs")))] @@ -355,11 +575,12 @@ if (REG_P (operands[1]) || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) { - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "cmp%.l %d0,%d1"; } return "cmp%.l %d1,%d0"; -}) +} + [(set_attr "type" "cmp_l")]) (define_expand "cmphi" [(set (cc0) @@ -403,7 +624,7 @@ if (REG_P (operands[1]) || (!REG_P (operands[0]) && GET_CODE (operands[0]) != MEM)) { - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "cmp%.b %d0,%d1"; } return "cmp%.b %d1,%d0"; @@ -434,9 +655,10 @@ else return "fcmp%. %f1,%0"; } - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "fcmp%. %f0,%1"; -}) +} + [(set_attr "type" "fcmp")]) (define_insn "cmp_cf" [(set (cc0) @@ -452,9 +674,10 @@ else return "fcmp%. %f1,%0"; } - cc_status.flags |= CC_REVERSED; + cc_status.flags |= CC_REVERSED; /*|*/ return "fcmp%. %f0,%1"; -}) +} + [(set_attr "type" "fcmp")]) ;; Recognizers for btst instructions. @@ -578,16 +801,15 @@ ;; A special case in which it is not desirable ;; to reload the constant into a data register. (define_insn "pushexthisi_const" - [(set (match_operand:SI 0 "push_operand" "=m") - (match_operand:SI 1 "const_int_operand" "J"))] + [(set (match_operand:SI 0 "push_operand" "=m,m,m") + (match_operand:SI 1 "const_int_operand" "C0,R,J"))] "INTVAL (operands[1]) >= -0x8000 && INTVAL (operands[1]) < 0x8000" -{ - if (operands[1] == const0_rtx) - return "clr%.l %0"; - if (valid_mov3q_const (INTVAL (operands[1]))) - return "mov3q%.l %1,%-"; - return "pea %a1"; -}) + "@ + clr%.l %0 + mov3q%.l %1,%- + pea %a1" + [(set_attr "type" "clr_l,mov3q_l,pea") + (set_attr "split" "done")]) ;This is never used. ;(define_insn "swapsi" @@ -597,30 +819,52 @@ ; "" ; "exg %1,%0") -;; Special case of fullword move when source is zero. -;; The reason this is special is to avoid loading a zero -;; into a data reg with moveq in order to store it elsewhere. - -(define_insn "movsi_const0" - [(set (match_operand:SI 0 "nonimmediate_operand" "=g") +;; Special case of fullword move when source is zero for 68000_10. +;; moveq is faster on the 68000. +(define_insn "*movsi_const0_68000_10" + [(set (match_operand:SI 0 "movsi_const0_operand" "=d,a,g") + (const_int 0))] + "TUNE_68000_10" + "@ + moveq #0,%0 + sub%.l %0,%0 + clr%.l %0" + [(set_attr "type" "moveq_l,sub_l,clr_l") + (set_attr "opy_type" "imm_q,reg,*") + (set_attr "split" "done")]) + +;; Special case of fullword move when source is zero for 68040_60. +;; On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 +(define_insn "*movsi_const0_68040_60" + [(set (match_operand:SI 0 "movsi_const0_operand" "=a,g") (const_int 0))] - ;; clr insns on 68000 read before writing. - "((TARGET_68010 || TARGET_COLDFIRE) - || !(GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))" + "TUNE_68040_60" { - if (ADDRESS_REG_P (operands[0])) + if (which_alternative == 0) + return MOTOROLA ? "lea 0.w,%0" : "lea 0:w,%0"; + else if (which_alternative == 1) + return "clr%.l %0"; + else { - /* On the '040, 'subl an,an' takes 2 clocks while lea takes only 1 */ - if (TUNE_68040_60) - return MOTOROLA ? "lea 0.w,%0" : "lea 0:w,%0"; - else - return "sub%.l %0,%0"; + gcc_unreachable (); + return ""; } - /* moveq is faster on the 68000. */ - if (DATA_REG_P (operands[0]) && TUNE_68000_10) - return "moveq #0,%0"; - return "clr%.l %0"; -}) +} + [(set_attr "type" "lea,clr_l") + (set_attr "opy_type" "imm_w,*") + (set_attr "split" "done")]) + +;; Special case of fullword move when source is zero. +(define_insn "*movsi_const0" + [(set (match_operand:SI 0 "movsi_const0_operand" "=a,g") + (const_int 0))] + "!(TUNE_68000_10 || TUNE_68040_60)" + "@ + sub%.l %0,%0 + clr%.l %0" + [(set_attr "type" "sub_l,clr_l") + (set_attr "opy_type" "reg,*") + (set_attr "split" "done")]) ;; General case of fullword move. ;; @@ -688,10 +932,59 @@ ;; ColdFire move instructions can have at most one operand of mode >= 6. (define_insn "*movsi_cf" - [(set (match_operand:SI 0 "nonimmediate_operand" "=r,g,U") - (match_operand:SI 1 "general_operand" "g,Rr,U"))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=g,d, d, d, d, d, a,Ap, a, r,g, U") + (match_operand:SI 1 "general_operand" " R,CQ,CW,CZ,CS,Ci,J,J Cs,Cs, g, Rr,U"))] "TARGET_COLDFIRE" - "* return output_move_simode (operands);") +{ + switch (which_alternative) + { + case 0: + return "mov3q%.l %1,%0"; + + case 1: + return "moveq %1,%0"; + + case 2: + { + unsigned u = INTVAL (operands[1]); + + operands[1] = GEN_INT ((u << 16) | (u >> 16)); /*|*/ + return "moveq %1,%0\n\tswap %0"; + } + + case 3: + return "mvz%.w %1,%0"; + + case 4: + return "mvs%.w %1,%0"; + + case 5: + return "move%.l %1,%0"; + + case 6: + return "move%.w %1,%0"; + + case 7: + return "pea %a1"; + + case 8: + return "lea %a1,%0"; + + case 9: + case 10: + case 11: + return "move%.l %1,%0"; + + default: + gcc_unreachable (); + return ""; + } +} + [(set_attr "type" "mov3q_l, moveq_l,*, mvz_w, mvs_w, move_l, move_w, pea, lea, move_l, move_l, move_l") + (set (attr "split") + (if_then_else (eq_attr "alternative" "2") + (const_string "*") + (const_string "done")))]) ;; Special case of fullword move, where we need to get a non-GOT PIC ;; reference into an address register. @@ -771,11 +1064,17 @@ "!TARGET_COLDFIRE" "* return output_move_strictqi (operands);") -(define_insn "" - [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+d,m")) - (match_operand:QI 1 "general_src_operand" "dmn,d"))] +(define_insn "*movstrictqi_cf" + [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+d, Ac, d,m")) + (match_operand:QI 1 "general_src_operand" "C0,C0, dmn,d"))] "TARGET_COLDFIRE" - "* return output_move_strictqi (operands);") + "@ + clr%.b %0 + clr%.b %0 + move%.b %1,%0 + move%.b %1,%0" + [(set_attr "type" "clr_b,clr_b,move_b,move_b") + (set_attr "split" "done")]) (define_expand "pushqi1" [(set (reg:SI SP_REG) (plus:SI (reg:SI SP_REG) (const_int -2))) @@ -864,9 +1163,8 @@ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,g,U") (match_operand:SF 1 "general_operand" "g,r,U"))] "TARGET_COLDFIRE && !TARGET_COLDFIRE_FPU" -{ - return "move%.l %1,%0"; -}) + "move%.l %1,%0" + [(set_attr "type" "move_l")]) ;; SFmode MEMs are restricted to modes 2-4 if TARGET_COLDFIRE_FPU. ;; The move instructions can handle all combinations. @@ -1003,12 +1301,16 @@ return output_move_double (operands); }) -(define_insn "movdf_cf_soft" +(define_insn_and_split "movdf_cf_soft" [(set (match_operand:DF 0 "nonimmediate_operand" "=r,g") (match_operand:DF 1 "general_operand" "g,r"))] "TARGET_COLDFIRE && !TARGET_COLDFIRE_FPU" + "#" + "&& reload_completed" + [(const_int 0)] { - return output_move_double (operands); + m68k_emit_move_double (operands); + DONE; }) (define_insn "movdf_cf_hard" @@ -1230,7 +1532,8 @@ [(set (match_operand:SI 0 "push_operand" "=m") (match_operand:SI 1 "address_operand" "p"))] "" - "pea %a1") + "pea %a1" + [(set_attr "type" "pea")]) ;; truncation instructions (define_insn "truncsiqi2" @@ -1391,7 +1694,8 @@ [(set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:HI 1 "nonimmediate_src_operand" "rmS")))] "ISA_HAS_MVS_MVZ" - "mvz%.w %1,%0") + "mvz%.w %1,%0" + [(set_attr "type" "mvz_w")]) (define_insn "zero_extendhisi2" [(set (match_operand:SI 0 "register_operand" "=d") @@ -1415,7 +1719,8 @@ [(set (match_operand:SI 0 "register_operand" "=d") (zero_extend:SI (match_operand:QI 1 "nonimmediate_src_operand" "dmS")))] "ISA_HAS_MVS_MVZ" - "mvz%.b %1,%0") + "mvz%.b %1,%0" + [(set_attr "type" "mvz_b")]) (define_insn "zero_extendqisi2" [(set (match_operand:SI 0 "register_operand" "=d") @@ -1567,24 +1872,25 @@ (sign_extend:SI (match_operand:HI 1 "nonimmediate_src_operand" "rmS")))] "ISA_HAS_MVS_MVZ" - "mvs%.w %1,%0") + "mvs%.w %1,%0" + [(set_attr "type" "mvs_w")]) (define_insn "*68k_extendhisi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,a") (sign_extend:SI (match_operand:HI 1 "nonimmediate_src_operand" "0,rmS")))] "!ISA_HAS_MVS_MVZ" -{ - if (ADDRESS_REG_P (operands[0])) - return "move%.w %1,%0"; - return "ext%.l %0"; -}) + "@ + ext%.l %0 + move%.w %1,%0" + [(set_attr "type" "ext_l,move_w")]) (define_insn "extendqihi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=d") (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0")))] "" - "ext%.w %0") + "ext%.w %0" + [(set_attr "type" "ext_w")]) (define_expand "extendqisi2" [(set (match_operand:SI 0 "nonimmediate_operand" "") @@ -1596,13 +1902,15 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "rms")))] "ISA_HAS_MVS_MVZ" - "mvs%.b %1,%0") + "mvs%.b %1,%0" + [(set_attr "type" "mvs_b")]) (define_insn "*68k_extendqisi2" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0")))] "TARGET_68020 || (TARGET_COLDFIRE && !ISA_HAS_MVS_MVZ)" - "extb%.l %0") + "extb%.l %0" + [(set_attr "type" "extb_l")]) ;; Conversions between float and double. @@ -1691,14 +1999,16 @@ "TARGET_COLDFIRE_FPU" "@ fsmove%.d %1,%0 - fmove%.s %1,%0") + fmove%.s %1,%0" + [(set_attr "type" "fmove")]) -(define_insn "" +(define_insn "*truncdfsf2_68881" [(set (match_operand:SF 0 "nonimmediate_operand" "=dm") (float_truncate:SF (match_operand:DF 1 "general_operand" "f")))] "TARGET_68881" - "fmove%.s %f1,%0") + "fmove%.s %f1,%0" + [(set_attr "type" "fmove")]) ;; Conversion between fixed point and floating point. ;; Note that among the fix-to-float insns @@ -1724,7 +2034,8 @@ [(set (match_operand:FP 0 "nonimmediate_operand" "=f") (float:FP (match_operand:SI 1 "general_operand" "dU")))] "TARGET_COLDFIRE_FPU" - "fmove%.l %1,%0") + "fmove%.l %1,%0" + [(set_attr "type" "fmove")]) (define_expand "floathi2" @@ -1737,13 +2048,15 @@ [(set (match_operand:FP 0 "nonimmediate_operand" "=f") (float:FP (match_operand:HI 1 "general_operand" "dmn")))] "TARGET_68881" - "fmove%.w %1,%0") + "fmove%.w %1,%0" + [(set_attr "type" "fmove")]) (define_insn "floathi2_cf" [(set (match_operand:FP 0 "nonimmediate_operand" "=f") (float:FP (match_operand:HI 1 "general_operand" "dU")))] "TARGET_COLDFIRE_FPU" - "fmove%.w %1,%0") + "fmove%.w %1,%0" + [(set_attr "type" "fmove")]) (define_expand "floatqi2" @@ -1756,13 +2069,15 @@ [(set (match_operand:FP 0 "nonimmediate_operand" "=f") (float:FP (match_operand:QI 1 "general_operand" "dmn")))] "TARGET_68881" - "fmove%.b %1,%0") + "fmove%.b %1,%0" + [(set_attr "type" "fmove")]) (define_insn "floatqi2_cf" [(set (match_operand:FP 0 "nonimmediate_operand" "=f") (float:FP (match_operand:QI 1 "general_operand" "dU")))] "TARGET_COLDFIRE_FPU" - "fmove%.b %1,%0") + "fmove%.b %1,%0" + [(set_attr "type" "fmove")]) ;; New routines to convert floating-point values to integers @@ -1830,7 +2145,8 @@ if (FP_REG_P (operands[1])) return "fintrz%.d %f1,%0"; return "fintrz%. %f1,%0"; -}) +} + [(set_attr "type" "fintrz")]) ;; Convert a float whose value is an integer ;; to an actual integer. Second stage of converting float to integer type. @@ -1850,7 +2166,8 @@ [(set (match_operand:QI 0 "nonimmediate_operand" "=dU") (fix:QI (match_operand:FP 1 "general_operand" "f")))] "TARGET_COLDFIRE_FPU" - "fmove%.b %1,%0") + "fmove%.b %1,%0" + [(set_attr "type" "fmove")]) (define_expand "fixhi2" [(set (match_operand:HI 0 "nonimmediate_operand" "") @@ -1868,7 +2185,8 @@ [(set (match_operand:HI 0 "nonimmediate_operand" "=dU") (fix:HI (match_operand:FP 1 "general_operand" "f")))] "TARGET_COLDFIRE_FPU" - "fmove%.w %1,%0") + "fmove%.w %1,%0" + [(set_attr "type" "fmove")]) (define_expand "fixsi2" [(set (match_operand:SI 0 "nonimmediate_operand" "") @@ -1886,7 +2204,8 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=dU") (fix:SI (match_operand:FP 1 "general_operand" "f")))] "TARGET_COLDFIRE_FPU" - "fmove%.l %1,%0") + "fmove%.l %1,%0" + [(set_attr "type" "fmove")]) ;; add instructions @@ -1984,7 +2303,8 @@ else operands[1] = adjust_address (operands[1], SImode, 4); return "add%.l %1,%0"; -}) +} + [(set_attr "type" "add_l")]) (define_insn "adddi3" [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,d,d,d") @@ -2107,12 +2427,54 @@ "! TARGET_COLDFIRE" "* return output_addsi3 (operands);") -(define_insn "*addsi3_5200" - [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?a,?a,r") - (plus:SI (match_operand:SI 1 "general_operand" "%0,a,rJK,0") - (match_operand:SI 2 "general_src_operand" "dIL,rJK,a,mrIKLi")))] +(define_insn_and_split "*addsi3_5200" + [(set (match_operand:SI 0 "nonimmediate_operand" "=mr,mr,m,r, ?a,?a,?a,?a") + (plus:SI (match_operand:SI 1 "general_operand" "%0, 0, 0,0, a, a, r, a") + (match_operand:SI 2 "general_src_operand" " I, L, d,mrKi,Cj,r, a, J")))] "TARGET_COLDFIRE" - "* return output_addsi3 (operands);") +{ + switch (which_alternative) + { + case 0: + return "addq%.l %2,%0"; + + case 1: + operands[2] = GEN_INT (- INTVAL (operands[2])); + return "subq%.l %2,%0"; + + case 2: + case 3: + return "add%.l %2,%0"; + + case 4: + /* move%.l %2,%0\n\tadd%.l %1,%0 */ + return "#"; + + case 5: + return MOTOROLA ? "lea (%1,%2.l),%0" : "lea %1@(0,%2:l),%0"; + + case 6: + return MOTOROLA ? "lea (%2,%1.l),%0" : "lea %2@(0,%1:l),%0"; + + case 7: + return MOTOROLA ? "lea (%c2,%1),%0" : "lea %1@(%c2),%0"; + + default: + gcc_unreachable (); + return ""; + } +} + "&& reload_completed && (extract_constrain_insn_cached (insn), which_alternative == 4) && !operands_match_p (operands[0], operands[1])" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (plus:SI (match_dup 0) + (match_dup 1)))] + "" + [(set_attr "type" "addq_l,subq_l,add_l,add_l,*,lea,lea,lea") + (set_attr "opy" "2,2,2,2,*,*,*,*") + (set_attr "opy_type" "*,*,*,*,*,mem6,mem6,mem5") + (set_attr "split" "done,done,done,done,*,done,done,done")]) (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=a") @@ -2392,7 +2754,8 @@ if (FP_REG_P (operands[2])) return "fadd%.d %2,%0"; return "fadd%. %2,%0"; -}) +} + [(set_attr "type" "fadd")]) ;; subtract instructions @@ -2426,7 +2789,8 @@ else operands[1] = adjust_address (operands[1], SImode, 4); return "sub%.l %1,%0"; -}) +} + [(set_attr "type" "sub_l")]) (define_insn "subdi3" [(set (match_operand:DI 0 "nonimmediate_operand" "=o<>,d,d,d") @@ -2508,11 +2872,17 @@ }) (define_insn "subsi3" - [(set (match_operand:SI 0 "nonimmediate_operand" "=m,d,a") - (minus:SI (match_operand:SI 1 "general_operand" "0,0,0") - (match_operand:SI 2 "general_src_operand" "dT,mSrT,mSrs")))] + [(set (match_operand:SI 0 "nonimmediate_operand" "=mda,m,d,a") + (minus:SI (match_operand:SI 1 "general_operand" "0,0,0,0") + (match_operand:SI 2 "general_src_operand" "I,dT,mSrT,mSrs")))] "" - "sub%.l %2,%0") + "@ + subq%.l %2, %0 + sub%.l %2,%0 + sub%.l %2,%0 + sub%.l %2,%0" + [(set_attr "type" "subq_l,sub_l,sub_l,sub_l") + (set_attr "opy" "2")]) (define_insn "" [(set (match_operand:SI 0 "nonimmediate_operand" "=a") @@ -2598,7 +2968,8 @@ if (FP_REG_P (operands[2])) return "fsub%.d %2,%0"; return "fsub%. %2,%0"; -}) +} + [(set_attr "type" "fsub")]) ;; multiply instructions @@ -2609,7 +2980,9 @@ "" { return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0"; -}) +} + [(set_attr "type" "muls_w") + (set_attr "opy" "2")]) (define_insn "mulhisi3" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") @@ -2620,9 +2993,11 @@ "" { return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0"; -}) +} + [(set_attr "type" "muls_w") + (set_attr "opy" "2")]) -(define_insn "" +(define_insn "*mulhisisi3_s" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (mult:SI (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%0")) @@ -2630,7 +3005,9 @@ "INTVAL (operands[2]) >= -0x8000 && INTVAL (operands[2]) <= 0x7fff" { return MOTOROLA ? "muls%.w %2,%0" : "muls %2,%0"; -}) +} + [(set_attr "type" "muls_w") + (set_attr "opy" "2")]) (define_expand "mulsi3" [(set (match_operand:SI 0 "nonimmediate_operand" "") @@ -2639,20 +3016,24 @@ "TARGET_68020 || TARGET_COLDFIRE" "") -(define_insn "" +(define_insn "*mulsi3_68020" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (mult:SI (match_operand:SI 1 "general_operand" "%0") (match_operand:SI 2 "general_src_operand" "dmSTK")))] "TARGET_68020" - "muls%.l %2,%0") + "muls%.l %2,%0" + [(set_attr "type" "muls_l") + (set_attr "opy" "2")]) -(define_insn "" +(define_insn "*mulsi3_cf" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (mult:SI (match_operand:SI 1 "general_operand" "%0") (match_operand:SI 2 "general_operand" "d")))] "TARGET_COLDFIRE" - "muls%.l %2,%0") + "muls%.l %2,%0" + [(set_attr "type" "muls_l") + (set_attr "opy" "2")]) (define_insn "umulhisi3" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") @@ -2663,9 +3044,11 @@ "" { return MOTOROLA ? "mulu%.w %2,%0" : "mulu %2,%0"; -}) +} + [(set_attr "type" "mulu_w") + (set_attr "opy" "2")]) -(define_insn "" +(define_insn "*mulhisisi3_z" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (mult:SI (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "%0")) @@ -2673,7 +3056,9 @@ "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 0xffff" { return MOTOROLA ? "mulu%.w %2,%0" : "mulu %2,%0"; -}) +} + [(set_attr "type" "mulu_w") + (set_attr "opy" "2")]) ;; We need a separate DEFINE_EXPAND for u?mulsidi3 to be able to use the ;; proper matching constraint. This is because the matching is between @@ -2932,7 +3317,8 @@ if (FP_REG_P (operands[2])) return "fmul%.d %2,%0"; return "fmul%. %2,%0"; -}) +} + [(set_attr "type" "fmul")]) ;; divide instructions @@ -3000,7 +3386,8 @@ if (FP_REG_P (operands[2])) return "fdiv%.d %2,%0"; return "fdiv%. %2,%0"; -}) +} + [(set_attr "type" "fdiv")]) ;; Remainder instructions. @@ -3692,13 +4079,15 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=dm") (neg:SI (match_operand:SI 1 "general_operand" "0")))] "!TARGET_COLDFIRE" - "neg%.l %0") + "neg%.l %0" + [(set_attr "type" "neg_l")]) (define_insn "negsi2_5200" [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (neg:SI (match_operand:SI 1 "general_operand" "0")))] "TARGET_COLDFIRE" - "neg%.l %0") + "neg%.l %0" + [(set_attr "type" "neg_l")]) (define_insn "neghi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") @@ -3863,7 +4252,8 @@ if (FP_REG_P (operands[1])) return "fsqrt%.x %1,%0"; return "fsqrt%. %1,%0"; -}) +} + [(set_attr "type" "fsqrt")]) (define_insn "sqrt2_cf" [(set (match_operand:FP 0 "nonimmediate_operand" "=f") @@ -4005,7 +4395,8 @@ [(set (match_operand:SI 0 "register_operand" "=d") (clz:SI (match_operand:SI 1 "register_operand" "0")))] "ISA_HAS_FF1" - "ff1 %0") + "ff1 %0" + [(set_attr "type" "ff1")]) ;; one complement instructions @@ -4048,7 +4439,8 @@ [(set (match_operand:SI 0 "nonimmediate_operand" "=d") (not:SI (match_operand:SI 1 "general_operand" "0")))] "TARGET_COLDFIRE" - "not%.l %0") + "not%.l %0" + [(set_attr "type" "not_l")]) (define_insn "one_cmplhi2" [(set (match_operand:HI 0 "nonimmediate_operand" "=dm") @@ -4399,7 +4791,8 @@ if (GET_CODE (operands[1]) != REG) operands[1] = adjust_address (operands[1], HImode, 2); return "move%.w %1,%0"; -}) +} + [(set_attr "type" "move_w")]) (define_insn "subregsi1ashrdi_const32" [(set (match_operand:SI 0 "nonimmediate_operand" "=rm") @@ -4408,7 +4801,8 @@ "" { return "move%.l %1,%0"; -}) +} + [(set_attr "type" "move_l")]) (define_insn "*ashrdi3_const1" [(set (match_operand:DI 0 "register_operand" "=d") @@ -4577,7 +4971,9 @@ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "dI")))] "" - "asr%.l %2,%0") + "asr%.l %2,%0" + [(set_attr "type" "asr_l") + (set_attr "opy" "2")]) (define_insn "ashrhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -4643,9 +5039,8 @@ (subreg:SI (lshiftrt:DI (match_operand:DI 1 "general_operand" "ro") (const_int 32)) 4))] "" -{ - return "move%.l %1,%0"; -}) + "move%.l %1,%0" + [(set_attr "type" "move_l")]) (define_insn "*lshrdi3_const1" [(set (match_operand:DI 0 "register_operand" "=d") @@ -4872,7 +5267,9 @@ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0") (match_operand:SI 2 "general_operand" "dI")))] "" - "lsr%.l %2,%0") + "lsr%.l %2,%0" + [(set_attr "type" "lsr_l") + (set_attr "opy" "2")]) (define_insn "lshrhi3" [(set (match_operand:HI 0 "register_operand" "=d") @@ -5029,10 +5426,11 @@ { CC_STATUS_INIT; return "bset %1,%0"; -}) +} + [(set_attr "type" "bset")]) ;; set bit, bit number is (sign/zero)_extended from HImode/QImode -(define_insn "" +(define_insn "*bsetmemqi_ext" [(set (match_operand:QI 0 "memory_operand" "+m") (ior:QI (subreg:QI (ashift:SI (const_int 1) (match_operator:SI 2 "extend_operator" @@ -5042,7 +5440,8 @@ { CC_STATUS_INIT; return "bset %1,%0"; -}) +} + [(set_attr "type" "bset")]) ;; clear bit, bit number is int (define_insn "bclrmemqi" @@ -5055,10 +5454,11 @@ { CC_STATUS_INIT; return "bclr %1,%0"; -}) +} + [(set_attr "type" "bclr")]) ;; clear bit, bit number is (sign/zero)_extended from HImode/QImode -(define_insn "" +(define_insn "*bclrmemqi_ext" [(set (zero_extract:SI (match_operand:QI 0 "memory_operand" "+m") (const_int 1) (minus:SI (const_int 7) @@ -5069,7 +5469,8 @@ { CC_STATUS_INIT; return "bclr %1,%0"; -}) +} + [(set_attr "type" "bclr")]) ;; Special cases of bit-field insns which we should ;; recognize in preference to the general case. @@ -5641,14 +6042,15 @@ "" "") -(define_insn "" +(define_insn "*scc" [(set (match_operand:QI 0 "register_operand" "=d") (geu:QI (cc0) (const_int 0)))] "" { cc_status = cc_prev_status; return "scc %0"; -}) +} + [(set_attr "type" "scc")]) (define_expand "sle" [(set (match_operand:QI 0 "register_operand" "") @@ -5678,14 +6080,15 @@ "" "") -(define_insn "" +(define_insn "*sls" [(set (match_operand:QI 0 "register_operand" "=d") (leu:QI (cc0) (const_int 0)))] "" { cc_status = cc_prev_status; return "sls %0"; -}) +} + [(set_attr "type" "scc")]) (define_expand "sordered" [(set (match_operand:QI 0 "register_operand" "") @@ -6085,7 +6488,9 @@ OUTPUT_JUMP ("jbeq %l0", "fbeq %l0", "jbeq %l0"); else OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0"); -}) +} + [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)")) + (set_attr "split" "done")]) (define_insn "bne" [(set (pc) @@ -6099,7 +6504,9 @@ OUTPUT_JUMP ("jbne %l0", "fbne %l0", "jbne %l0"); else OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0"); -}) +} + [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)")) + (set_attr "split" "done")]) (define_insn "bgt" [(set (pc) @@ -6113,7 +6520,9 @@ OUTPUT_JUMP ("jbgt %l0", "fbgt %l0", 0); else OUTPUT_JUMP ("jgt %l0", "fjgt %l0", 0); -}) +} + [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)")) + (set_attr "split" "done")]) (define_insn "bgtu" [(set (pc) @@ -6124,7 +6533,8 @@ "" { return MOTOROLA ? "jbhi %l0" : "jhi %l0"; -}) +} + [(set_attr "type" "bcc")]) (define_insn "blt" [(set (pc) @@ -6138,7 +6548,9 @@ OUTPUT_JUMP ("jblt %l0", "fblt %l0", "jbmi %l0"); else OUTPUT_JUMP ("jlt %l0", "fjlt %l0", "jmi %l0"); -}) +} + [(set (attr "type") (symbol_ref "m68k_sched_branch_type (insn)")) + (set_attr "split" "done")]) (define_insn "bltu" [(set (pc) @@ -6149,7 +6561,8 @@ "" { return MOTOROLA ? "jbcs %l0" : "jcs %l0"; -}) +} + [(set_attr "type" "bcc")]) (define_insn "bge" [(set (pc) @@ -6174,7 +6587,8 @@ "" { return MOTOROLA ? "jbcc %l0" : "jcc %l0"; -}) +} + [(set_attr "type" "bcc")]) (define_insn "ble" [(set (pc) @@ -6188,7 +6602,8 @@ OUTPUT_JUMP ("jble %l0", "fble %l0", 0); else OUTPUT_JUMP ("jle %l0", "fjle %l0", 0); -}) +} + [(set_attr "type" "bcc")]) (define_insn "bleu" [(set (pc) @@ -6199,7 +6614,8 @@ "" { return MOTOROLA ? "jbls %l0" : "jls %l0"; -}) +} + [(set_attr "type" "bcc")]) (define_insn "bordered" [(set (pc) @@ -6291,7 +6707,7 @@ ;; Negated conditional jump instructions. -(define_insn "" +(define_insn "*beq2" [(set (pc) (if_then_else (eq (cc0) (const_int 0)) @@ -6303,9 +6719,10 @@ OUTPUT_JUMP ("jbne %l0", "fbne %l0", "jbne %l0"); else OUTPUT_JUMP ("jne %l0", "fjne %l0", "jne %l0"); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bne2" [(set (pc) (if_then_else (ne (cc0) (const_int 0)) @@ -6317,9 +6734,10 @@ OUTPUT_JUMP ("jbeq %l0", "fbeq %l0", "jbeq %l0"); else OUTPUT_JUMP ("jeq %l0", "fjeq %l0", "jeq %l0"); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bgt2" [(set (pc) (if_then_else (gt (cc0) (const_int 0)) @@ -6331,9 +6749,10 @@ OUTPUT_JUMP ("jble %l0", "fbngt %l0", 0); else OUTPUT_JUMP ("jle %l0", "fjngt %l0", 0); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bgtu2" [(set (pc) (if_then_else (gtu (cc0) (const_int 0)) @@ -6342,9 +6761,10 @@ "" { return MOTOROLA ? "jbls %l0" : "jls %l0"; -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*blt2" [(set (pc) (if_then_else (lt (cc0) (const_int 0)) @@ -6356,9 +6776,10 @@ OUTPUT_JUMP ("jbge %l0", "fbnlt %l0", "jbpl %l0"); else OUTPUT_JUMP ("jge %l0", "fjnlt %l0", "jpl %l0"); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bltu2" [(set (pc) (if_then_else (ltu (cc0) (const_int 0)) @@ -6367,9 +6788,10 @@ "" { return MOTOROLA ? "jbcc %l0" : "jcc %l0"; -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bge2" [(set (pc) (if_then_else (ge (cc0) (const_int 0)) @@ -6381,9 +6803,10 @@ OUTPUT_JUMP ("jblt %l0", "fbnge %l0", "jbmi %l0"); else OUTPUT_JUMP ("jlt %l0", "fjnge %l0", "jmi %l0"); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bgeu2" [(set (pc) (if_then_else (geu (cc0) (const_int 0)) @@ -6392,9 +6815,10 @@ "" { return MOTOROLA ? "jbcs %l0" : "jcs %l0"; -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*ble2" [(set (pc) (if_then_else (le (cc0) (const_int 0)) @@ -6406,9 +6830,10 @@ OUTPUT_JUMP ("jbgt %l0", "fbnle %l0", 0); else OUTPUT_JUMP ("jgt %l0", "fjnle %l0", 0); -}) +} + [(set_attr "type" "bcc")]) -(define_insn "" +(define_insn "*bleu2" [(set (pc) (if_then_else (leu (cc0) (const_int 0)) @@ -6417,7 +6842,8 @@ "" { return MOTOROLA ? "jbhi %l0" : "jhi %l0"; -}) +} + [(set_attr "type" "bcc")]) (define_insn "*bordered_rev" [(set (pc) @@ -6514,7 +6940,8 @@ "" { return MOTOROLA ? "jbra %l0" : "jra %l0"; -}) +} + [(set_attr "type" "bra")]) (define_expand "tablejump" [(parallel [(set (pc) (match_operand 0 "" "")) @@ -6528,13 +6955,14 @@ }) ;; Jump to variable address from dispatch table of absolute addresses. -(define_insn "" +(define_insn "*tablejump_internal" [(set (pc) (match_operand:SI 0 "register_operand" "a")) (use (label_ref (match_operand 1 "" "")))] "" { return MOTOROLA ? "jmp (%0)" : "jmp %0@"; -}) +} + [(set_attr "type" "bra")]) ;; Jump to variable address from dispatch table of relative addresses. (define_insn "" @@ -6746,16 +7174,46 @@ operands[1] = m68k_legitimize_call_address (operands[1]); }) -(define_insn "*call_value" +(define_insn "*non_symbolic_call_value" [(set (match_operand 0 "" "=rf,rf") - (call (mem:QI (match_operand:SI 1 "call_operand" "a,W")) + (call (mem:QI (match_operand:SI 1 "non_symbolic_call_operand" "a,W")) (match_operand:SI 2 "general_operand" "g,g")))] ;; Operand 2 not really used on the m68000. "!SIBLING_CALL_P (insn)" + "jsr %a1" + [(set_attr "type" "jsr") + (set_attr "split" "done") + (set_attr "opx" "1")]) + +(define_insn "*symbolic_call_value_jsr" + [(set (match_operand 0 "" "=rf,rf") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "a,W")) + (match_operand:SI 2 "general_operand" "g,g")))] + ;; Operand 2 not really used on the m68000. + "!SIBLING_CALL_P (insn) && m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_JSR" { operands[0] = operands[1]; - return output_call (operands[0]); -}) + return m68k_symbolic_call; +} + [(set_attr "type" "jsr") + (set_attr "split" "done") + (set_attr "opx" "1")]) + +(define_insn "*symbolic_call_value_bsr" + [(set (match_operand 0 "" "=rf,rf") + (call (mem:QI (match_operand:SI 1 "symbolic_operand" "a,W")) + (match_operand:SI 2 "general_operand" "g,g")))] + ;; Operand 2 not really used on the m68000. + "!SIBLING_CALL_P (insn) + && (m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_BSR_C + || m68k_symbolic_call_var == M68K_SYMBOLIC_CALL_BSR_P)" +{ + operands[0] = operands[1]; + return m68k_symbolic_call; +} + [(set_attr "type" "bsr") + (set_attr "split" "done") + (set_attr "opx" "1")]) ;; Call subroutine returning any type. @@ -6796,7 +7254,8 @@ (define_insn "nop" [(const_int 0)] "" - "nop") + "nop" + [(set_attr "type" "nop")]) (define_expand "prologue" [(const_int 0)] @@ -6849,7 +7308,8 @@ else return "rts"; } -}) +} + [(set_attr "type" "rts")]) (define_insn "*m68k_store_multiple" [(match_parallel 0 "" [(match_operand 1 "")])] @@ -6939,7 +7399,8 @@ (plus:SI (match_dup 0) (const_int 4)))] "" - "unlk %0") + "unlk %0" + [(set_attr "type" "unlk")]) (define_insn "load_got" [(set (match_operand:SI 0 "register_operand" "=a") @@ -6971,7 +7432,8 @@ (define_insn "indirect_jump" [(set (pc) (match_operand:SI 0 "address_operand" "p"))] "" - "jmp %a0") + "jmp %a0" + [(set_attr "type" "jmp")]) ;; This should not be used unless the add/sub insns can't be. @@ -7373,10 +7835,12 @@ return "fcos%. %1,%0"; }) +;; Unconditional traps are assumed to have (const_int 1) for the condition. (define_insn "trap" - [(trap_if (const_int -1) (const_int 7))] + [(trap_if (const_int 1) (const_int 7))] "" - "trap #7") + "trap #7" + [(set_attr "type" "trap")]) (define_insn "conditional_trap" [(trap_if (match_operator 0 "valid_dbcc_comparison_p" @@ -7399,3 +7863,12 @@ default: gcc_unreachable (); } }) + +;; Instruction that subscribes one word in ColdFire instruction buffer. +;; This instruction is used within scheduler only and should not appear +;; in the instruction stream. +(define_insn "ib" + [(unspec [(const_int 0)] UNSPEC_IB)] + "" + "#" + [(set_attr "type" "ib")]) diff --git a/gcc/config/m68k/predicates.md b/gcc/config/m68k/predicates.md index 939e869..bf96863 100644 --- a/gcc/config/m68k/predicates.md +++ b/gcc/config/m68k/predicates.md @@ -192,3 +192,17 @@ (define_predicate "pre_dec_operand" (and (match_code "mem") (match_test "GET_CODE (XEXP (op, 0)) == PRE_DEC"))) + +;; An operand for movsi_const0 pattern. +(define_predicate "movsi_const0_operand" + (and (match_operand 0 "nonimmediate_operand") + (match_test "(TARGET_68010 || TARGET_COLDFIRE) + || !(MEM_P (op) && MEM_VOLATILE_P (op))"))) + +;; A non-symbolic call operand. +;; We need to special case 'const_int' to ignore its mode while matching. +(define_predicate "non_symbolic_call_operand" + (and (match_operand 0 "call_operand") + (ior (and (match_code "const_int") + (match_test "!symbolic_operand (op, mode)")) + (match_test "!symbolic_operand (op,mode)")))) diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi index c75b983..553c58d 100644 --- a/gcc/doc/md.texi +++ b/gcc/doc/md.texi @@ -2542,7 +2542,7 @@ Floating-point zero. An address that can be used in a non-macro load or store. @end table -@item Motorola 680x0---@file{config/m68k/m68k.h} +@item Motorola 680x0---@file{config/m68k/constraints.md} @table @code @item a Address register @@ -2568,8 +2568,66 @@ Integer in the range @minus{}8 to @minus{}1 @item M Signed number whose magnitude is greater than 0x100 +@item N +Range 24 to 31, rotatert:SI 8 to 1 expressed as rotate + +@item O +16 (for rotate using swap) + +@item P +Range 8 to 15, rotatert:HI 8 to 1 expressed as rotate + +@item R +Numbers that mov3q can handle + @item G Floating point constant that is not a 68881 constant + +@item S +Operands that satisfy 'm' when -mpcrel is in effect + +@item T +Operands that satisfy 's' when -mpcrel is not in effect + +@item Q +Address register indirect addressing mode + +@item U +Register offset addressing + +@item W +const_call_operand + +@item Cs +symbol_ref or const + +@item Ci +const_int + +@item C0 +const_int 0 + +@item Cj +Range of signed numbers that don't fit in 16 bits + +@item Cmvq +Integers valid for mvq + +@item Capsw +Integers valid for a moveq followed by a swap + +@item Cmvz +Integers valid for mvz + +@item Cmvs +Integers valid for mvs + +@item Ap +push_operand + +@item Ac +Non-register operands allowed in clr + @end table @item Motorola 68HC11 & 68HC12 families---@file{config/m68hc11/m68hc11.h} -- 2.7.4