summaryrefslogtreecommitdiff
path: root/gcc/config/mn10300/mn10300.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/mn10300/mn10300.c')
-rw-r--r--gcc/config/mn10300/mn10300.c175
1 files changed, 163 insertions, 12 deletions
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index 2187463d083..c0f11805117 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -58,6 +58,12 @@ int mn10300_protect_label;
/* The selected processor. */
enum processor_type mn10300_processor = PROCESSOR_DEFAULT;
+/* Processor type to select for tuning. */
+static const char * mn10300_tune_string = NULL;
+
+/* Selected processor type for tuning. */
+enum processor_type mn10300_tune_cpu = PROCESSOR_DEFAULT;
+
/* The size of the callee register save area. Right now we save everything
on entry since it costs us nothing in code size. It does cost us from a
speed standpoint, so we want to optimize this sooner or later. */
@@ -91,11 +97,21 @@ mn10300_handle_option (size_t code,
case OPT_mam33:
mn10300_processor = value ? PROCESSOR_AM33 : PROCESSOR_MN10300;
return true;
+
case OPT_mam33_2:
mn10300_processor = (value
? PROCESSOR_AM33_2
: MIN (PROCESSOR_AM33, PROCESSOR_DEFAULT));
return true;
+
+ case OPT_mam34:
+ mn10300_processor = (value ? PROCESSOR_AM34 : PROCESSOR_DEFAULT);
+ return true;
+
+ case OPT_mtune_:
+ mn10300_tune_string = arg;
+ return true;
+
default:
return true;
}
@@ -108,6 +124,27 @@ mn10300_option_override (void)
{
if (TARGET_AM33)
target_flags &= ~MASK_MULT_BUG;
+ else
+ {
+ /* Disable scheduling for the MN10300 as we do
+ not have timing information available for it. */
+ flag_schedule_insns = 0;
+ flag_schedule_insns_after_reload = 0;
+ }
+
+ if (mn10300_tune_string)
+ {
+ if (strcasecmp (mn10300_tune_string, "mn10300") == 0)
+ mn10300_tune_cpu = PROCESSOR_MN10300;
+ else if (strcasecmp (mn10300_tune_string, "am33") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM33;
+ else if (strcasecmp (mn10300_tune_string, "am33-2") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM33_2;
+ else if (strcasecmp (mn10300_tune_string, "am34") == 0)
+ mn10300_tune_cpu = PROCESSOR_AM34;
+ else
+ error ("-mtune= expects mn10300, am33, am33-2, or am34");
+ }
}
static void
@@ -370,7 +407,7 @@ mn10300_print_operand (FILE *file, rtx x, int code)
case 'A':
fputc ('(', file);
- if (REG_P ((XEXP (x, 0))))
+ if (REG_P (XEXP (x, 0)))
output_address (gen_rtx_PLUS (SImode, XEXP (x, 0), const0_rtx));
else
output_address (XEXP (x, 0));
@@ -392,7 +429,7 @@ mn10300_print_operand (FILE *file, rtx x, int code)
shift count as an error. So we mask off the high bits
of the immediate here. */
case 'S':
- if (CONST_INT_P ((x)))
+ if (CONST_INT_P (x))
{
fprintf (file, "%d", (int)(INTVAL (x) & 0x1f));
break;
@@ -1250,8 +1287,8 @@ mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
/* Memory loads less than a full word wide can't have an
address or stack pointer destination. They must use
a data register as an intermediate register. */
- if ((MEM_P ((in))
- || (REG_P ((inner))
+ if ((MEM_P (in)
+ || (REG_P (inner)
&& REGNO (inner) >= FIRST_PSEUDO_REGISTER))
&& (mode == QImode || mode == HImode)
&& (rclass == ADDRESS_REGS || rclass == SP_REGS
@@ -1281,13 +1318,13 @@ mn10300_secondary_reload_class (enum reg_class rclass, enum machine_mode mode,
{
/* We can't load directly into an FP register from a
constant address. */
- if (MEM_P ((in))
+ if (MEM_P (in)
&& CONSTANT_ADDRESS_P (XEXP (in, 0)))
return DATA_OR_EXTENDED_REGS;
/* Handle case were a pseudo may not get a hard register
but has an equivalent memory location defined. */
- if (REG_P ((inner))
+ if (REG_P (inner)
&& REGNO (inner) >= FIRST_PSEUDO_REGISTER
&& reg_equiv_mem [REGNO (inner)]
&& CONSTANT_ADDRESS_P (XEXP (reg_equiv_mem [REGNO (inner)], 0)))
@@ -1417,9 +1454,9 @@ mn10300_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
/* Return an RTX to represent where a value with mode MODE will be returned
from a function. If the result is NULL_RTX, the argument is pushed. */
-rtx
+static rtx
mn10300_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
- tree type, int named ATTRIBUTE_UNUSED)
+ const_tree type, bool named ATTRIBUTE_UNUSED)
{
rtx result = NULL_RTX;
int size, align;
@@ -1464,6 +1501,19 @@ mn10300_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
return result;
}
+/* Update the data in CUM to advance over an argument
+ of mode MODE and data type TYPE.
+ (TYPE is null for libcalls where that information may not be available.) */
+
+static void
+mn10300_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ cum->nbytes += (mode != BLKmode
+ ? (GET_MODE_SIZE (mode) + 3) & ~3
+ : (int_size_in_bytes (type) + 3) & ~3);
+}
+
/* Return the number of bytes of registers to use for an argument passed
partially in registers and partially in memory. */
@@ -1683,7 +1733,7 @@ mn10300_symbolic_operand (rtx op,
op = XEXP (op, 0);
return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
|| GET_CODE (XEXP (op, 0)) == LABEL_REF)
- && CONST_INT_P ((XEXP (op, 1))));
+ && CONST_INT_P (XEXP (op, 1)));
default:
return 0;
}
@@ -1857,7 +1907,7 @@ mn10300_legitimate_address_p (enum machine_mode mode, rtx x, bool strict)
if (base != 0 && index != 0)
{
- if (CONST_INT_P ((index)))
+ if (CONST_INT_P (index))
return TRUE;
if (GET_CODE (index) == CONST
&& GET_CODE (XEXP (index, 0)) != PLUS
@@ -1894,7 +1944,6 @@ mn10300_legitimate_constant_p (rtx x)
/* Only some unspecs are valid as "constants". */
if (GET_CODE (x) == UNSPEC)
{
- rtx sym = XVECEXP (x, 0, 0);
switch (XINT (x, 1))
{
case UNSPEC_INT_LABEL:
@@ -2057,7 +2106,7 @@ mn10300_wide_const_load_uses_clr (rtx operands[2])
{
long val[2] = {0, 0};
- if (! REG_P (operands[0])
+ if ((! REG_P (operands[0]))
|| REGNO_REG_CLASS (REGNO (operands[0])) != DATA_REGS)
return false;
@@ -2259,6 +2308,101 @@ mn10300_select_cc_mode (rtx x)
{
return (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) ? CC_FLOATmode : CCmode;
}
+
+static inline bool
+is_load_insn (rtx insn)
+{
+ if (GET_CODE (PATTERN (insn)) != SET)
+ return false;
+
+ return MEM_P (SET_SRC (PATTERN (insn)));
+}
+
+static inline bool
+is_store_insn (rtx insn)
+{
+ if (GET_CODE (PATTERN (insn)) != SET)
+ return false;
+
+ return MEM_P (SET_DEST (PATTERN (insn)));
+}
+
+/* Update scheduling costs for situations that cannot be
+ described using the attributes and DFA machinery.
+ DEP is the insn being scheduled.
+ INSN is the previous insn.
+ COST is the current cycle cost for DEP. */
+
+static int
+mn10300_adjust_sched_cost (rtx insn, rtx link, rtx dep, int cost)
+{
+ int timings = get_attr_timings (insn);
+
+ if (!TARGET_AM33)
+ return 1;
+
+ if (GET_CODE (insn) == PARALLEL)
+ insn = XVECEXP (insn, 0, 0);
+
+ if (GET_CODE (dep) == PARALLEL)
+ dep = XVECEXP (dep, 0, 0);
+
+ /* For the AM34 a load instruction that follows a
+ store instruction incurs an extra cycle of delay. */
+ if (mn10300_tune_cpu == PROCESSOR_AM34
+ && is_load_insn (dep)
+ && is_store_insn (insn))
+ cost += 1;
+
+ /* For the AM34 a non-store, non-branch FPU insn that follows
+ another FPU insn incurs a one cycle throughput increase. */
+ else if (mn10300_tune_cpu == PROCESSOR_AM34
+ && ! is_store_insn (insn)
+ && ! JUMP_P (insn)
+ && GET_CODE (PATTERN (dep)) == SET
+ && GET_CODE (PATTERN (insn)) == SET
+ && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) == MODE_FLOAT
+ && GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) == MODE_FLOAT)
+ cost += 1;
+
+ /* Resolve the conflict described in section 1-7-4 of
+ Chapter 3 of the MN103E Series Instruction Manual
+ where it says:
+
+ "When the preceeding instruction is a CPU load or
+ store instruction, a following FPU instruction
+ cannot be executed until the CPU completes the
+ latency period even though there are no register
+ or flag dependencies between them." */
+
+ /* Only the AM33-2 (and later) CPUs have FPU instructions. */
+ if (! TARGET_AM33_2)
+ return cost;
+
+ /* If a data dependence already exists then the cost is correct. */
+ if (REG_NOTE_KIND (link) == 0)
+ return cost;
+
+ /* Check that the instruction about to scheduled is an FPU instruction. */
+ if (GET_CODE (PATTERN (dep)) != SET)
+ return cost;
+
+ if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (dep)))) != MODE_FLOAT)
+ return cost;
+
+ /* Now check to see if the previous instruction is a load or store. */
+ if (! is_load_insn (insn) && ! is_store_insn (insn))
+ return cost;
+
+ /* XXX: Verify: The text of 1-7-4 implies that the restriction
+ only applies when an INTEGER load/store preceeds an FPU
+ instruction, but is this true ? For now we assume that it is. */
+ if (GET_MODE_CLASS (GET_MODE (SET_SRC (PATTERN (insn)))) != MODE_INT)
+ return cost;
+
+ /* Extract the latency value from the timings attribute. */
+ return timings < 100 ? (timings % 10) : (timings % 100);
+}
/* Initialize the GCC target structure. */
@@ -2303,6 +2447,10 @@ mn10300_select_cc_mode (rtx x)
#define TARGET_CALLEE_COPIES hook_bool_CUMULATIVE_ARGS_mode_tree_bool_true
#undef TARGET_ARG_PARTIAL_BYTES
#define TARGET_ARG_PARTIAL_BYTES mn10300_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG mn10300_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE mn10300_function_arg_advance
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
#define TARGET_EXPAND_BUILTIN_SAVEREGS mn10300_builtin_saveregs
@@ -2330,4 +2478,7 @@ mn10300_select_cc_mode (rtx x)
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK mn10300_can_output_mi_thunk
+#undef TARGET_SCHED_ADJUST_COST
+#define TARGET_SCHED_ADJUST_COST mn10300_adjust_sched_cost
+
struct gcc_target targetm = TARGET_INITIALIZER;