aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/mips/mips.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mips/mips.c')
-rw-r--r--gcc/config/mips/mips.c335
1 files changed, 335 insertions, 0 deletions
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index b1408f1..4dcf524 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -155,6 +155,8 @@ static void mips_select_rtx_section PARAMS ((enum machine_mode, rtx,
unsigned HOST_WIDE_INT));
static int mips_use_dfa_pipeline_interface PARAMS ((void));
static void mips_encode_section_info PARAMS ((tree, int));
+static bool mips_rtx_costs PARAMS ((rtx, int, int, int *));
+
/* Structure to be filled in by compute_frame_size with register
save masks, and offsets for the current function. */
@@ -670,6 +672,8 @@ const struct mips_cpu_info mips_cpu_info_table[] = {
#undef TARGET_VALID_POINTER_MODE
#define TARGET_VALID_POINTER_MODE mips_valid_pointer_mode
+#undef TARGET_RTX_COSTS
+#define TARGET_RTX_COSTS mips_rtx_costs
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -2986,6 +2990,337 @@ mips_move_2words (operands, insn)
return ret;
}
+static bool
+mips_rtx_costs (x, code, outer_code, total)
+ rtx x;
+ int code, outer_code;
+ int *total;
+{
+ enum machine_mode mode = GET_MODE (x);
+
+ switch (code)
+ {
+ case CONST_INT:
+ if (! TARGET_MIPS16)
+ {
+ /* Always return 0, since we don't have different sized insns,
+ hence different costs according to Richard Kenner. */
+ *total = 0;
+ return true;
+ }
+
+ if (outer_code == SET)
+ {
+ if (INTVAL (x) >= 0 && INTVAL (x) < 0x100)
+ *total = 0;
+ else if ((INTVAL (x) >= 0 && INTVAL (x) < 0x10000)
+ || (INTVAL (x) < 0 && INTVAL (x) > -0x100))
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ return true;
+ }
+
+ /* A PLUS could be an address. We don't want to force an address
+ to use a register, so accept any signed 16 bit value without
+ complaint. */
+ if (outer_code == PLUS
+ && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000)
+ {
+ *total = 0;
+ return true;
+ }
+
+ /* A number between 1 and 8 inclusive is efficient for a shift.
+ Otherwise, we will need an extended instruction. */
+ if (outer_code == ASHIFT || outer_code == ASHIFTRT
+ || outer_code == LSHIFTRT)
+ {
+ if (INTVAL (x) >= 1 && INTVAL (x) <= 8)
+ *total = 0;
+ else
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+
+ /* We can use cmpi for an xor with an unsigned 16 bit value. */
+ if (outer_code == XOR
+ && INTVAL (x) >= 0 && INTVAL (x) < 0x10000)
+ {
+ *total = 0;
+ return true;
+ }
+
+ /* We may be able to use slt or sltu for a comparison with a
+ signed 16 bit value. (The boundary conditions aren't quite
+ right, but this is just a heuristic anyhow.) */
+ if ((outer_code == LT || outer_code == LE
+ || outer_code == GE || outer_code == GT
+ || outer_code == LTU || outer_code == LEU
+ || outer_code == GEU || outer_code == GTU)
+ && INTVAL (x) >= -0x8000 && INTVAL (x) < 0x8000)
+ {
+ *total = 0;
+ return true;
+ }
+
+ /* Equality comparisons with 0 are cheap. */
+ if ((outer_code == EQ || outer_code == NE)
+ && INTVAL (x) == 0)
+ return 0;
+
+ /* Otherwise, work out the cost to load the value into a
+ register. */
+ if (INTVAL (x) >= 0 && INTVAL (x) < 0x100)
+ *total = COSTS_N_INSNS (1);
+ else if ((INTVAL (x) >= 0 && INTVAL (x) < 0x10000)
+ || (INTVAL (x) < 0 && INTVAL (x) > -0x100))
+ *total = COSTS_N_INSNS (2);
+ else
+ *total = COSTS_N_INSNS (3);
+ return true;
+
+ case LABEL_REF:
+ *total = COSTS_N_INSNS (2);
+ return true;
+
+ case CONST:
+ {
+ rtx offset = const0_rtx;
+ rtx symref = eliminate_constant_term (XEXP (x, 0), &offset);
+
+ if (TARGET_MIPS16 && mips16_gp_offset_p (x))
+ {
+ /* Treat this like a signed 16 bit CONST_INT. */
+ if (outer_code == PLUS)
+ *total = 0;
+ else if (outer_code == SET)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ return true;
+ }
+
+ if (GET_CODE (symref) == LABEL_REF)
+ *total = COSTS_N_INSNS (2);
+ else if (GET_CODE (symref) != SYMBOL_REF)
+ *total = COSTS_N_INSNS (4);
+ else if (INTVAL (offset) < -32768 || INTVAL (offset) > 32767)
+ *total = COSTS_N_INSNS (2);
+ else
+ *total = COSTS_N_INSNS (SYMBOL_REF_FLAG (symref) ? 1 : 2);
+
+ return true;
+ }
+
+ case SYMBOL_REF:
+ *total = COSTS_N_INSNS (SYMBOL_REF_FLAG (x) ? 1 : 2);
+ return true;
+
+ case CONST_DOUBLE:
+ {
+ rtx high, low;
+ if (TARGET_MIPS16)
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+
+ split_double (x, &high, &low);
+ *total = COSTS_N_INSNS ((high == CONST0_RTX (GET_MODE (high))
+ || low == CONST0_RTX (GET_MODE (low)))
+ ? 2 : 4);
+ return true;
+ }
+
+ case MEM:
+ {
+ int num_words = (GET_MODE_SIZE (mode) > UNITS_PER_WORD) ? 2 : 1;
+ if (simple_memory_operand (x, mode))
+ *total = COSTS_N_INSNS (num_words);
+ else
+ *total = COSTS_N_INSNS (2*num_words);
+ return true;
+ }
+
+ case FFS:
+ *total = COSTS_N_INSNS (6);
+ return true;
+
+ case NOT:
+ *total = COSTS_N_INSNS ((mode == DImode && !TARGET_64BIT) ? 2 : 1);
+ return true;
+
+ case AND:
+ case IOR:
+ case XOR:
+ if (mode == DImode && !TARGET_64BIT)
+ {
+ *total = COSTS_N_INSNS (2);
+ return true;
+ }
+ return false;
+
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ if (mode == DImode && !TARGET_64BIT)
+ {
+ *total = COSTS_N_INSNS ((GET_CODE (XEXP (x, 1)) == CONST_INT)
+ ? 4 : 12);
+ return true;
+ }
+ return false;
+
+ case ABS:
+ if (mode == SFmode || mode == DFmode)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (4);
+ return true;
+
+ case PLUS:
+ case MINUS:
+ if (mode == SFmode || mode == DFmode)
+ {
+ if (TUNE_MIPS3000 || TUNE_MIPS3900)
+ *total = COSTS_N_INSNS (2);
+ else if (TUNE_MIPS6000)
+ *total = COSTS_N_INSNS (3);
+ else
+ *total = COSTS_N_INSNS (6);
+ return true;
+ }
+ if (mode == DImode && !TARGET_64BIT)
+ {
+ *total = COSTS_N_INSNS (4);
+ return true;
+ }
+ return false;
+
+ case NEG:
+ if (mode == DImode && !TARGET_64BIT)
+ {
+ *total = 4;
+ return true;
+ }
+ return false;
+
+ case MULT:
+ if (mode == SFmode)
+ {
+ if (TUNE_MIPS3000
+ || TUNE_MIPS3900
+ || TUNE_MIPS5000)
+ *total = COSTS_N_INSNS (4);
+ else if (TUNE_MIPS6000
+ || TUNE_MIPS5400
+ || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS (5);
+ else
+ *total = COSTS_N_INSNS (7);
+ return true;
+ }
+
+ if (mode == DFmode)
+ {
+ if (TUNE_MIPS3000
+ || TUNE_MIPS3900
+ || TUNE_MIPS5000)
+ *total = COSTS_N_INSNS (5);
+ else if (TUNE_MIPS6000
+ || TUNE_MIPS5400
+ || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS (6);
+ else
+ *total = COSTS_N_INSNS (8);
+ return true;
+ }
+
+ if (TUNE_MIPS3000)
+ *total = COSTS_N_INSNS (12);
+ else if (TUNE_MIPS3900)
+ *total = COSTS_N_INSNS (2);
+ else if (TUNE_MIPS5400 || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS ((mode == DImode) ? 4 : 3);
+ else if (TUNE_MIPS6000)
+ *total = COSTS_N_INSNS (17);
+ else if (TUNE_MIPS5000)
+ *total = COSTS_N_INSNS (5);
+ else
+ *total = COSTS_N_INSNS (10);
+ return true;
+
+ case DIV:
+ case MOD:
+ if (mode == SFmode)
+ {
+ if (TUNE_MIPS3000
+ || TUNE_MIPS3900)
+ *total = COSTS_N_INSNS (12);
+ else if (TUNE_MIPS6000)
+ *total = COSTS_N_INSNS (15);
+ else if (TUNE_MIPS5400 || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS (30);
+ else
+ *total = COSTS_N_INSNS (23);
+ return true;
+ }
+
+ if (mode == DFmode)
+ {
+ if (TUNE_MIPS3000
+ || TUNE_MIPS3900)
+ *total = COSTS_N_INSNS (19);
+ else if (TUNE_MIPS5400 || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS (59);
+ else if (TUNE_MIPS6000)
+ *total = COSTS_N_INSNS (16);
+ else
+ *total = COSTS_N_INSNS (36);
+ return true;
+ }
+ /* FALLTHRU */
+
+ case UDIV:
+ case UMOD:
+ if (TUNE_MIPS3000
+ || TUNE_MIPS3900)
+ *total = COSTS_N_INSNS (35);
+ else if (TUNE_MIPS6000)
+ *total = COSTS_N_INSNS (38);
+ else if (TUNE_MIPS5000)
+ *total = COSTS_N_INSNS (36);
+ else if (TUNE_MIPS5400 || TUNE_MIPS5500)
+ *total = COSTS_N_INSNS ((mode == SImode) ? 42 : 74);
+ else
+ *total = COSTS_N_INSNS (69);
+ return true;
+
+ case SIGN_EXTEND:
+ /* A sign extend from SImode to DImode in 64 bit mode is often
+ zero instructions, because the result can often be used
+ directly by another instruction; we'll call it one. */
+ if (TARGET_64BIT && mode == DImode
+ && GET_MODE (XEXP (x, 0)) == SImode)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2);
+ return true;
+
+ case ZERO_EXTEND:
+ if (TARGET_64BIT && mode == DImode
+ && GET_MODE (XEXP (x, 0)) == SImode)
+ *total = COSTS_N_INSNS (2);
+ else
+ *total = COSTS_N_INSNS (1);
+ return true;
+
+ default:
+ return false;
+ }
+}
+
/* Provide the costs of an addressing mode that contains ADDR.
If ADDR is not a valid address, its cost is irrelevant. */