diff options
-rw-r--r-- | gcc/ChangeLog | 14 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.c | 420 | ||||
-rw-r--r-- | gcc/config/mn10300/mn10300.h | 13 |
4 files changed, 305 insertions, 143 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2785470..1f80f21 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,19 @@ 2011-01-11 Richard Henderson <rth@redhat.com> + * config/mn10300/mn10300.c (mn10300_address_cost): Remove forward + declaration. Rewrite for both speed and size. + (mn10300_address_cost_1): Remove. + (mn10300_register_move_cost): New. + (mn10300_memory_move_cost): New. + (mn10300_rtx_costs): Rewrite for both speed and size. Don't handle + ZERO_EXTRACT. Do handle UNSPEC, arithmetic, logicals, compare, + extensions, shifts, BSWAP, CLZ. + (mn10300_wide_const_load_uses_clr): Remove. + (TARGET_REGISTER_MOVE_COST): New. + (TARGET_MEMORY_MOVE_COST): New. + * config/mn10300/mn10300-protos.h: Update. + * config/mn10300/mn10300.h (REGISTER_MOVE_COST): Remove. + * config/mn10300/constraints.md ("R", "T"): Remove constraints. * config/mn10300/mn10300.c (mn10300_mask_ok_for_mem_btst): Remove. * config/mn10300/mn10300-protos.h: Update. diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h index 8979eb4..d6cf850 100644 --- a/gcc/config/mn10300/mn10300-protos.h +++ b/gcc/config/mn10300/mn10300-protos.h @@ -39,7 +39,6 @@ extern Rclas mn10300_secondary_reload_class (Rclas, Mmode, rtx); extern Mmode mn10300_select_cc_mode (rtx); extern int mn10300_store_multiple_operation (rtx, Mmode); extern int mn10300_symbolic_operand (rtx, Mmode); -extern bool mn10300_wide_const_load_uses_clr (rtx operands[2]); #endif /* RTX_CODE */ extern int mn10300_can_use_return_insn (void); diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c index e801c47..d39b427 100644 --- a/gcc/config/mn10300/mn10300.c +++ b/gcc/config/mn10300/mn10300.c @@ -75,8 +75,6 @@ enum processor_type mn10300_tune_cpu = PROCESSOR_DEFAULT; || df_regs_ever_live_p (16) \ || df_regs_ever_live_p (17))) -static int mn10300_address_cost (rtx, bool); - /* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ static const struct default_options mn10300_option_optimization_table[] = { @@ -2034,180 +2032,340 @@ mn10300_legitimate_constant_p (rtx x) return true; } +/* For addresses, costs are relative to "MOV (Rm),Rn". For AM33 this is + the 3-byte fully general instruction; for MN103 this is the 2-byte form + with an address register. */ + static int -mn10300_address_cost_1 (rtx x, int *unsig) +mn10300_address_cost (rtx x, bool speed) { + HOST_WIDE_INT i; + rtx base, index; + switch (GET_CODE (x)) { + case CONST: + case SYMBOL_REF: + case LABEL_REF: + /* We assume all of these require a 32-bit constant, even though + some symbol and label references can be relaxed. */ + return speed ? 1 : 4; + case REG: - switch (REGNO_REG_CLASS (REGNO (x))) + case SUBREG: + case POST_INC: + return 0; + + case POST_MODIFY: + /* Assume any symbolic offset is a 32-bit constant. */ + i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678); + if (IN_RANGE (i, -128, 127)) + return speed ? 0 : 1; + if (speed) + return 1; + if (IN_RANGE (i, -0x800000, 0x7fffff)) + return 3; + return 4; + + case PLUS: + base = XEXP (x, 0); + index = XEXP (x, 1); + if (register_operand (index, SImode)) { - case SP_REGS: - *unsig = 1; - return 0; + /* Attempt to minimize the number of registers in the address. + This is similar to what other ports do. */ + if (register_operand (base, SImode)) + return 1; - case ADDRESS_REGS: - return 1; + base = XEXP (x, 1); + index = XEXP (x, 0); + } - case DATA_REGS: - case EXTENDED_REGS: - case FP_REGS: - return 3; + /* Assume any symbolic offset is a 32-bit constant. */ + i = (CONST_INT_P (XEXP (x, 1)) ? INTVAL (XEXP (x, 1)) : 0x12345678); + if (IN_RANGE (i, -128, 127)) + return speed ? 0 : 1; + if (IN_RANGE (i, -32768, 32767)) + return speed ? 0 : 2; + return speed ? 2 : 6; - case NO_REGS: - return 5; + default: + return rtx_cost (x, MEM, speed); + } +} - default: - gcc_unreachable (); - } +/* Implement the TARGET_REGISTER_MOVE_COST hook. - case PLUS: - case MINUS: - case ASHIFT: - case AND: - case IOR: - return (mn10300_address_cost_1 (XEXP (x, 0), unsig) - + mn10300_address_cost_1 (XEXP (x, 1), unsig)); + Recall that the base value of 2 is required by assumptions elsewhere + in the body of the compiler, and that cost 2 is special-cased as an + early exit from reload meaning no work is required. */ - case EXPR_LIST: - case SUBREG: - case MEM: - return mn10300_address_cost (XEXP (x, 0), !optimize_size); +static int +mn10300_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, + reg_class_t ifrom, reg_class_t ito) +{ + enum reg_class from = (enum reg_class) ifrom; + enum reg_class to = (enum reg_class) ito; + enum reg_class scratch, test; + + /* Simplify the following code by unifying the fp register classes. */ + if (to == FP_ACC_REGS) + to = FP_REGS; + if (from == FP_ACC_REGS) + from = FP_REGS; + + /* Diagnose invalid moves by costing them as two moves. */ + + scratch = NO_REGS; + test = from; + if (to == SP_REGS) + scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS); + else if (to == FP_REGS && to != from) + scratch = GENERAL_REGS; + else + { + test = to; + if (from == SP_REGS) + scratch = (TARGET_AM33 ? GENERAL_REGS : ADDRESS_REGS); + else if (from == FP_REGS && to != from) + scratch = GENERAL_REGS; + } + if (scratch != NO_REGS && !reg_class_subset_p (test, scratch)) + return (mn10300_register_move_cost (VOIDmode, from, scratch) + + mn10300_register_move_cost (VOIDmode, scratch, to)); - case ZERO_EXTEND: - *unsig = 1; - return mn10300_address_cost_1 (XEXP (x, 0), unsig); + /* From here on, all we need consider are legal combinations. */ - case CONST_INT: - if (INTVAL (x) == 0) - return 0; - if (INTVAL (x) + (*unsig ? 0 : 0x80) < 0x100) - return 1; - if (INTVAL (x) + (*unsig ? 0 : 0x8000) < 0x10000) - return 3; - if (INTVAL (x) + (*unsig ? 0 : 0x800000) < 0x1000000) - return 5; - return 7; + if (optimize_size) + { + /* The scale here is bytes * 2. */ - case CONST: - case SYMBOL_REF: - case LABEL_REF: - return 8; + if (from == to && (to == ADDRESS_REGS || to == DATA_REGS)) + return 2; - default: - gcc_unreachable (); + if (from == SP_REGS) + return (to == ADDRESS_REGS ? 2 : 6); + + /* For MN103, all remaining legal moves are two bytes. */ + if (TARGET_AM33) + return 4; + + if (to == SP_REGS) + return (from == ADDRESS_REGS ? 4 : 6); + + if ((from == ADDRESS_REGS || from == DATA_REGS) + && (to == ADDRESS_REGS || to == DATA_REGS)) + return 4; + + if (to == EXTENDED_REGS) + return (to == from ? 6 : 4); + /* What's left are SP_REGS, FP_REGS, or combinations of the above. */ + return 6; + } + else + { + /* The scale here is cycles * 2. */ + + if (to == FP_REGS) + return 8; + if (from == FP_REGS) + return 4; + + /* All legal moves between integral registers are single cycle. */ + return 2; } } +/* Implement the TARGET_MEMORY_MOVE_COST hook. + + Given lack of the form of the address, this must be speed-relative, + though we should never be less expensive than a size-relative register + move cost above. This is not a problem. */ + static int -mn10300_address_cost (rtx x, bool speed ATTRIBUTE_UNUSED) +mn10300_memory_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED, + reg_class_t iclass, bool in ATTRIBUTE_UNUSED) { - int s = 0; - return mn10300_address_cost_1 (x, &s); + enum reg_class rclass = (enum reg_class) iclass; + + if (rclass == FP_REGS) + return 8; + return 6; } +/* Implement the TARGET_RTX_COSTS hook. + + Speed-relative costs are relative to COSTS_N_INSNS, which is intended + to represent cycles. Size-relative costs are in bytes. */ + static bool -mn10300_rtx_costs (rtx x, int code, int outer_code, int *total, - bool speed ATTRIBUTE_UNUSED) +mn10300_rtx_costs (rtx x, int code, int outer_code, int *ptotal, bool speed) { + /* This value is used for SYMBOL_REF etc where we want to pretend + we have a full 32-bit constant. */ + HOST_WIDE_INT i = 0x12345678; + int total; + switch (code) { case CONST_INT: - /* Zeros are extremely cheap. */ - if (INTVAL (x) == 0 && (outer_code == SET || outer_code == COMPARE)) - *total = 0; - /* If it fits in 8 bits, then it's still relatively cheap. */ - else if (INT_8_BITS (INTVAL (x))) - *total = 1; - /* This is the "base" cost, includes constants where either the - upper or lower 16bits are all zeros. */ - else if (INT_16_BITS (INTVAL (x)) - || (INTVAL (x) & 0xffff) == 0 - || (INTVAL (x) & 0xffff0000) == 0) - *total = 2; + i = INTVAL (x); + do_int_costs: + if (speed) + { + if (outer_code == SET) + { + /* 16-bit integer loads have latency 1, 32-bit loads 2. */ + if (IN_RANGE (i, -32768, 32767)) + total = COSTS_N_INSNS (1); + else + total = COSTS_N_INSNS (2); + } + else + { + /* 16-bit integer operands don't affect latency; + 24-bit and 32-bit operands add a cycle. */ + if (IN_RANGE (i, -32768, 32767)) + total = 0; + else + total = COSTS_N_INSNS (1); + } + } else - *total = 4; - return true; + { + if (outer_code == SET) + { + if (i == 0) + total = 1; + else if (IN_RANGE (i, -128, 127)) + total = 2; + else if (IN_RANGE (i, -32768, 32767)) + total = 3; + else + total = 6; + } + else + { + /* Reference here is ADD An,Dn, vs ADD imm,Dn. */ + if (IN_RANGE (i, -128, 127)) + total = 0; + else if (IN_RANGE (i, -32768, 32767)) + total = 2; + else if (TARGET_AM33 && IN_RANGE (i, -0x01000000, 0x00ffffff)) + total = 3; + else + total = 4; + } + } + goto alldone; case CONST: case LABEL_REF: case SYMBOL_REF: - /* These are more costly than a CONST_INT, but we can relax them, - so they're less costly than a CONST_DOUBLE. */ - *total = 6; - return true; - case CONST_DOUBLE: - /* We don't optimize CONST_DOUBLEs well nor do we relax them well, - so their cost is very high. */ - *total = 8; - return true; - - case ZERO_EXTRACT: - /* This is cheap, we can use btst. */ - if (outer_code == COMPARE) - *total = 0; - return false; + /* We assume all of these require a 32-bit constant, even though + some symbol and label references can be relaxed. */ + goto do_int_costs; - /* ??? This probably needs more work. */ - case MOD: - case DIV: - case MULT: - *total = 8; - return true; + case UNSPEC: + switch (XINT (x, 1)) + { + case UNSPEC_PIC: + case UNSPEC_GOT: + case UNSPEC_GOTOFF: + case UNSPEC_PLT: + case UNSPEC_GOTSYM_OFF: + /* The PIC unspecs also resolve to a 32-bit constant. */ + goto do_int_costs; - default: - return false; - } -} + default: + /* Assume any non-listed unspec is some sort of arithmetic. */ + goto do_arith_costs; + } -/* Check whether a constant used to initialize a DImode or DFmode can - use a clr instruction. The code here must be kept in sync with - movdf and movdi. */ + case PLUS: + /* Notice the size difference of INC and INC4. */ + if (!speed && outer_code == SET && CONST_INT_P (XEXP (x, 1))) + { + i = INTVAL (XEXP (x, 1)); + if (i == 1 || i == 4) + { + total = 1 + rtx_cost (XEXP (x, 0), PLUS, speed); + goto alldone; + } + } + goto do_arith_costs; + + case MINUS: + case AND: + case IOR: + case XOR: + case NOT: + case NEG: + case ZERO_EXTEND: + case SIGN_EXTEND: + case COMPARE: + case BSWAP: + case CLZ: + do_arith_costs: + total = (speed ? COSTS_N_INSNS (1) : 2); + break; -bool -mn10300_wide_const_load_uses_clr (rtx operands[2]) -{ - long val[2] = {0, 0}; + case ASHIFT: + /* Notice the size difference of ASL2 and variants. */ + if (!speed && CONST_INT_P (XEXP (x, 1))) + switch (INTVAL (XEXP (x, 1))) + { + case 1: + case 2: + total = 1; + goto alldone; + case 3: + case 4: + total = 2; + goto alldone; + } + /* FALLTHRU */ - if ((! REG_P (operands[0])) - || REGNO_REG_CLASS (REGNO (operands[0])) != DATA_REGS) - return false; + case ASHIFTRT: + case LSHIFTRT: + total = (speed ? COSTS_N_INSNS (1) : 3); + goto alldone; - switch (GET_CODE (operands[1])) - { - case CONST_INT: - { - rtx low, high; - split_double (operands[1], &low, &high); - val[0] = INTVAL (low); - val[1] = INTVAL (high); - } + case MULT: + total = (speed ? COSTS_N_INSNS (3) : 2); break; - case CONST_DOUBLE: - if (GET_MODE (operands[1]) == DFmode) - { - REAL_VALUE_TYPE rv; - - REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); - REAL_VALUE_TO_TARGET_DOUBLE (rv, val); - } - else if (GET_MODE (operands[1]) == VOIDmode - || GET_MODE (operands[1]) == DImode) - { - val[0] = CONST_DOUBLE_LOW (operands[1]); - val[1] = CONST_DOUBLE_HIGH (operands[1]); - } + case DIV: + case UDIV: + case MOD: + case UMOD: + total = (speed ? COSTS_N_INSNS (39) + /* Include space to load+retrieve MDR. */ + : code == MOD || code == UMOD ? 6 : 4); break; + case MEM: + total = mn10300_address_cost (XEXP (x, 0), speed); + if (speed) + total = COSTS_N_INSNS (2 + total); + goto alldone; + default: - return false; + /* Probably not implemented. Assume external call. */ + total = (speed ? COSTS_N_INSNS (10) : 7); + break; } - return val[0] == 0 || val[1] == 0; + *ptotal = total; + return false; + + alldone: + *ptotal = total; + return true; } + /* If using PIC, mark a SYMBOL_REF for a non-global symbol so that we may access it using GOTOFF instead of GOT. */ @@ -2502,10 +2660,14 @@ mn10300_conditional_register_usage (void) #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS mn10300_legitimize_address +#undef TARGET_ADDRESS_COST +#define TARGET_ADDRESS_COST mn10300_address_cost +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST mn10300_register_move_cost +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST mn10300_memory_move_cost #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS mn10300_rtx_costs -#undef TARGET_ADDRESS_COST -#define TARGET_ADDRESS_COST mn10300_address_cost #undef TARGET_ASM_FILE_START #define TARGET_ASM_FILE_START mn10300_file_start diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h index bdd6b6f..ef79245 100644 --- a/gcc/config/mn10300/mn10300.h +++ b/gcc/config/mn10300/mn10300.h @@ -600,19 +600,6 @@ struct cum_arg #define SELECT_CC_MODE(OP, X, Y) mn10300_select_cc_mode (X) #define REVERSIBLE_CC_MODE(MODE) 0 -#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) \ - ((CLASS1 == CLASS2 && (CLASS1 == ADDRESS_REGS || CLASS1 == DATA_REGS)) ? 2 :\ - ((CLASS1 == ADDRESS_REGS || CLASS1 == DATA_REGS) && \ - (CLASS2 == ADDRESS_REGS || CLASS2 == DATA_REGS)) ? 4 : \ - (CLASS1 == SP_REGS && CLASS2 == ADDRESS_REGS) ? 2 : \ - (CLASS1 == ADDRESS_REGS && CLASS2 == SP_REGS) ? 4 : \ - ! TARGET_AM33 ? 6 : \ - (CLASS1 == SP_REGS || CLASS2 == SP_REGS) ? 6 : \ - (CLASS1 == CLASS2 && CLASS1 == EXTENDED_REGS) ? 6 : \ - (CLASS1 == FP_REGS || CLASS2 == FP_REGS) ? 6 : \ - (CLASS1 == EXTENDED_REGS || CLASS2 == EXTENDED_REGS) ? 4 : \ - 4) - /* Nonzero if access to memory by bytes or half words is no faster than accessing full words. */ #define SLOW_BYTE_ACCESS 1 |