From caa2bd916db1b2b49248ae52a799e164ae7d30af Mon Sep 17 00:00:00 2001 From: Maxim Kuvyrkov Date: Tue, 11 Sep 2007 13:56:30 +0000 Subject: * 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: https://gcc.gnu.org/svn/gcc/trunk@128377 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/config/m68k/m68k.c | 753 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 680 insertions(+), 73 deletions(-) (limited to 'gcc/config/m68k/m68k.c') diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 8f7aa34f228..654add3d197 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; +} -- cgit v1.2.3