Commit 4670abb0 by Richard Sandiford Committed by Richard Sandiford

mips-protos.h (mips_split_type): New enum.

gcc/
	* config/mips/mips-protos.h (mips_split_type): New enum.
	(mips_split_64bit_move_p, mips_split_doubleword_move): Delete.
	(mips_split_move_p, mips_split_move, mips_split_move_insn_p)
	(mips_split_move_insn): Declare.
	* config/mips/mips.c (mips_tuning_info): New variable.
	(mips_load_store_insns): Use mips_split_move_insn_p instead of
	mips_split_64bit_move_p.
	(mips_emit_move_or_split, mips_mult_move_p): New functions.
	(mips_split_64bit_move_p): Rename to...
	(mips_split_move_p): ...this and take a mips_split_type argument.
	Generalize to all moves.  Call mips_mult_move_p.
	(mips_split_doubleword_move): Rename to...
	(mips_split_move): ...this and take a mips_split_type argument.
	Assert that mips_split_move_p holds.
	(mips_insn_split_type, mips_split_move_insn_p, mips_split_move_insn):
	New functions.
	(mips_output_move): Use mips_split_move_p instead of
	mips_split_64bit_move_p.  Handle MULT $0, $0 moves.
	(mips_save_reg): Use mips_emit_move_or_split.
	(mips_sim_reset): Assign to curr_state.  Call targetm.sched.init
	and advance_state.
	(mips_sim_init): Call targetm.sched.init_dfa_pre_cycle_insn and
	targetm.sched.init_dfa_post_cycle_insn, if defined.
	(mips_sim_next_cycle): Assign to curr_state.  Use advance_state
	instead of state_transition.
	(mips_sim_issue_insn): Assign to curr_state.  Use
	targetm.sched.variable_issue to see how many more insns
	can be issued.
	(mips_seq_time, mips_mult_zero_zero_cost)
	(mips_set_fast_mult_zero_zero_p, mips_set_tuning_info)
	(mips_expand_to_rtl_hook): New functions.
	(TARGET_EXPAND_TO_RTL_HOOK): Define.
	* config/mips/mips.md (move_type): Add imul.
	(type): Map imul move_types to imul.
	(*movdi_32bit, *movti): Add imul alternatives.
	Use mips_split_move_insn_p and mips_split_move_insn instead of
	mips_split_64bit_move_p and mips_split_doubleword_move in move
	splitters.

gcc/testsuite/
2012-10-07  Richard Sandiford  <rdsandiford@googlemail.com>
	    Sandra Loosemore  <sandra@codesourcery.com>

	* gcc.target/mips/madd-9.c: Force code to be tuned for the 4kc
	and test that the accumulator is initialized using MULT.
	* gcc.target/mips/mips32-dsp-accinit-1.c: New test.
	* gcc.target/mips/mips32-dsp-accinit-2.c: Likewise.

Co-Authored-By: Sandra Loosemore <sandra@codesourcery.com>

From-SVN: r192179
parent 03d15315
2012-10-07 Richard Sandiford <rdsandiford@googlemail.com>
* config/mips/mips-protos.h (mips_split_type): New enum.
(mips_split_64bit_move_p, mips_split_doubleword_move): Delete.
(mips_split_move_p, mips_split_move, mips_split_move_insn_p)
(mips_split_move_insn): Declare.
* config/mips/mips.c (mips_tuning_info): New variable.
(mips_load_store_insns): Use mips_split_move_insn_p instead of
mips_split_64bit_move_p.
(mips_emit_move_or_split, mips_mult_move_p): New functions.
(mips_split_64bit_move_p): Rename to...
(mips_split_move_p): ...this and take a mips_split_type argument.
Generalize to all moves. Call mips_mult_move_p.
(mips_split_doubleword_move): Rename to...
(mips_split_move): ...this and take a mips_split_type argument.
Assert that mips_split_move_p holds.
(mips_insn_split_type, mips_split_move_insn_p, mips_split_move_insn):
New functions.
(mips_output_move): Use mips_split_move_p instead of
mips_split_64bit_move_p. Handle MULT $0, $0 moves.
(mips_save_reg): Use mips_emit_move_or_split.
(mips_sim_reset): Assign to curr_state. Call targetm.sched.init
and advance_state.
(mips_sim_init): Call targetm.sched.init_dfa_pre_cycle_insn and
targetm.sched.init_dfa_post_cycle_insn, if defined.
(mips_sim_next_cycle): Assign to curr_state. Use advance_state
instead of state_transition.
(mips_sim_issue_insn): Assign to curr_state. Use
targetm.sched.variable_issue to see how many more insns
can be issued.
(mips_seq_time, mips_mult_zero_zero_cost)
(mips_set_fast_mult_zero_zero_p, mips_set_tuning_info)
(mips_expand_to_rtl_hook): New functions.
(TARGET_EXPAND_TO_RTL_HOOK): Define.
* config/mips/mips.md (move_type): Add imul.
(type): Map imul move_types to imul.
(*movdi_32bit, *movti): Add imul alternatives.
Use mips_split_move_insn_p and mips_split_move_insn instead of
mips_split_64bit_move_p and mips_split_doubleword_move in move
splitters.
2012-10-06 Segher Boessenkool <segher@kernel.crashing.org> 2012-10-06 Segher Boessenkool <segher@kernel.crashing.org>
* config/rs6000/rs6000.c (print_operand) ['A']: Delete. * config/rs6000/rs6000.c (print_operand) ['A']: Delete.
......
...@@ -173,6 +173,25 @@ enum mips_call_type { ...@@ -173,6 +173,25 @@ enum mips_call_type {
MIPS_CALL_EPILOGUE MIPS_CALL_EPILOGUE
}; };
/* Controls the conditions under which certain instructions are split.
SPLIT_IF_NECESSARY
Only perform splits that are necessary for correctness
(because no unsplit version exists).
SPLIT_FOR_SPEED
Perform splits that are necessary for correctness or
beneficial for code speed.
SPLIT_FOR_SIZE
Perform splits that are necessary for correctness or
beneficial for code size. */
enum mips_split_type {
SPLIT_IF_NECESSARY,
SPLIT_FOR_SPEED,
SPLIT_FOR_SIZE
};
extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_context, extern bool mips_symbolic_constant_p (rtx, enum mips_symbol_context,
enum mips_symbol_type *); enum mips_symbol_type *);
extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, bool); extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, bool);
...@@ -212,8 +231,10 @@ extern int m16_simm8_8 (rtx, enum machine_mode); ...@@ -212,8 +231,10 @@ extern int m16_simm8_8 (rtx, enum machine_mode);
extern int m16_nsimm8_8 (rtx, enum machine_mode); extern int m16_nsimm8_8 (rtx, enum machine_mode);
extern rtx mips_subword (rtx, bool); extern rtx mips_subword (rtx, bool);
extern bool mips_split_64bit_move_p (rtx, rtx); extern bool mips_split_move_p (rtx, rtx, enum mips_split_type);
extern void mips_split_doubleword_move (rtx, rtx); extern void mips_split_move (rtx, rtx, enum mips_split_type);
extern bool mips_split_move_insn_p (rtx, rtx, rtx);
extern void mips_split_move_insn (rtx, rtx, rtx);
extern const char *mips_output_move (rtx, rtx); extern const char *mips_output_move (rtx, rtx);
extern bool mips_cfun_has_cprestore_slot_p (void); extern bool mips_cfun_has_cprestore_slot_p (void);
extern bool mips_cprestore_address_p (rtx, bool); extern bool mips_cprestore_address_p (rtx, bool);
......
...@@ -265,6 +265,24 @@ static const char *const mips_fp_conditions[] = { ...@@ -265,6 +265,24 @@ static const char *const mips_fp_conditions[] = {
MIPS_FP_CONDITIONS (STRINGIFY) MIPS_FP_CONDITIONS (STRINGIFY)
}; };
/* Tuning information that is automatically derived from other sources
(such as the scheduler). */
static struct {
/* The architecture and tuning settings that this structure describes. */
enum processor arch;
enum processor tune;
/* True if this structure describes MIPS16 settings. */
bool mips16_p;
/* True if the structure has been initialized. */
bool initialized_p;
/* True if "MULT $0, $0" is preferable to "MTLO $0; MTHI $0"
when optimizing for speed. */
bool fast_mult_zero_zero_p;
} mips_tuning_info;
/* Information about a function's frame layout. */ /* Information about a function's frame layout. */
struct GTY(()) mips_frame_info { struct GTY(()) mips_frame_info {
/* The size of the frame in bytes. */ /* The size of the frame in bytes. */
...@@ -2395,11 +2413,11 @@ mips_load_store_insns (rtx mem, rtx insn) ...@@ -2395,11 +2413,11 @@ mips_load_store_insns (rtx mem, rtx insn)
mode = GET_MODE (mem); mode = GET_MODE (mem);
/* Try to prove that INSN does not need to be split. */ /* Try to prove that INSN does not need to be split. */
might_split_p = true; might_split_p = GET_MODE_SIZE (mode) > UNITS_PER_WORD;
if (GET_MODE_BITSIZE (mode) == 64) if (might_split_p)
{ {
set = single_set (insn); set = single_set (insn);
if (set && !mips_split_64bit_move_p (SET_DEST (set), SET_SRC (set))) if (set && !mips_split_move_insn_p (SET_DEST (set), SET_SRC (set), insn))
might_split_p = false; might_split_p = false;
} }
...@@ -2441,6 +2459,18 @@ mips_emit_move (rtx dest, rtx src) ...@@ -2441,6 +2459,18 @@ mips_emit_move (rtx dest, rtx src)
: emit_move_insn_1 (dest, src)); : emit_move_insn_1 (dest, src));
} }
/* Emit a move from SRC to DEST, splitting compound moves into individual
instructions. SPLIT_TYPE is the type of split to perform. */
static void
mips_emit_move_or_split (rtx dest, rtx src, enum mips_split_type split_type)
{
if (mips_split_move_p (dest, src, split_type))
mips_split_move (dest, src, split_type);
else
mips_emit_move (dest, src);
}
/* Emit an instruction of the form (set TARGET (CODE OP0)). */ /* Emit an instruction of the form (set TARGET (CODE OP0)). */
static void static void
...@@ -4107,39 +4137,60 @@ mips_subword (rtx op, bool high_p) ...@@ -4107,39 +4137,60 @@ mips_subword (rtx op, bool high_p)
return simplify_gen_subreg (word_mode, op, mode, byte); return simplify_gen_subreg (word_mode, op, mode, byte);
} }
/* Return true if a 64-bit move from SRC to DEST should be split into two. */ /* Return true if SRC should be moved into DEST using "MULT $0, $0".
SPLIT_TYPE is the condition under which moves should be split. */
static bool
mips_mult_move_p (rtx dest, rtx src, enum mips_split_type split_type)
{
return ((split_type != SPLIT_FOR_SPEED
|| mips_tuning_info.fast_mult_zero_zero_p)
&& src == const0_rtx
&& REG_P (dest)
&& GET_MODE_SIZE (GET_MODE (dest)) == 2 * UNITS_PER_WORD
&& (ISA_HAS_DSP_MULT
? ACC_REG_P (REGNO (dest))
: MD_REG_P (REGNO (dest))));
}
/* Return true if a move from SRC to DEST should be split into two.
SPLIT_TYPE describes the split condition. */
bool bool
mips_split_64bit_move_p (rtx dest, rtx src) mips_split_move_p (rtx dest, rtx src, enum mips_split_type split_type)
{ {
if (TARGET_64BIT) /* Check whether the move can be done using some variant of MULT $0,$0. */
if (mips_mult_move_p (dest, src, split_type))
return false; return false;
/* FPR-to-FPR moves can be done in a single instruction, if they're /* FPR-to-FPR moves can be done in a single instruction, if they're
allowed at all. */ allowed at all. */
if (FP_REG_RTX_P (src) && FP_REG_RTX_P (dest)) unsigned int size = GET_MODE_SIZE (GET_MODE (dest));
if (size == 8 && FP_REG_RTX_P (src) && FP_REG_RTX_P (dest))
return false; return false;
/* Check for floating-point loads and stores. */ /* Check for floating-point loads and stores. */
if (ISA_HAS_LDC1_SDC1) if (size == 8 && ISA_HAS_LDC1_SDC1)
{ {
if (FP_REG_RTX_P (dest) && MEM_P (src)) if (FP_REG_RTX_P (dest) && MEM_P (src))
return false; return false;
if (FP_REG_RTX_P (src) && MEM_P (dest)) if (FP_REG_RTX_P (src) && MEM_P (dest))
return false; return false;
} }
return true;
/* Otherwise split all multiword moves. */
return size > UNITS_PER_WORD;
} }
/* Split a doubleword move from SRC to DEST. On 32-bit targets, /* Split a move from SRC to DEST, given that mips_split_move_p holds.
this function handles 64-bit moves for which mips_split_64bit_move_p SPLIT_TYPE describes the split condition. */
holds. For 64-bit targets, this function handles 128-bit moves. */
void void
mips_split_doubleword_move (rtx dest, rtx src) mips_split_move (rtx dest, rtx src, enum mips_split_type split_type)
{ {
rtx low_dest; rtx low_dest;
gcc_checking_assert (mips_split_move_p (dest, src, split_type));
if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src)) if (FP_REG_RTX_P (dest) || FP_REG_RTX_P (src))
{ {
if (!TARGET_64BIT && GET_MODE (dest) == DImode) if (!TARGET_64BIT && GET_MODE (dest) == DImode)
...@@ -4195,6 +4246,41 @@ mips_split_doubleword_move (rtx dest, rtx src) ...@@ -4195,6 +4246,41 @@ mips_split_doubleword_move (rtx dest, rtx src)
} }
} }
/* Return the split type for instruction INSN. */
static enum mips_split_type
mips_insn_split_type (rtx insn)
{
basic_block bb = BLOCK_FOR_INSN (insn);
if (bb)
{
if (optimize_bb_for_speed_p (bb))
return SPLIT_FOR_SPEED;
else
return SPLIT_FOR_SIZE;
}
/* Once CFG information has been removed, we should trust the optimization
decisions made by previous passes and only split where necessary. */
return SPLIT_IF_NECESSARY;
}
/* Return true if a move from SRC to DEST in INSN should be split. */
bool
mips_split_move_insn_p (rtx dest, rtx src, rtx insn)
{
return mips_split_move_p (dest, src, mips_insn_split_type (insn));
}
/* Split a move from SRC to DEST in INSN, given that mips_split_move_insn_p
holds. */
void
mips_split_move_insn (rtx dest, rtx src, rtx insn)
{
mips_split_move (dest, src, mips_insn_split_type (insn));
}
/* Return the appropriate instructions to move SRC into DEST. Assume /* Return the appropriate instructions to move SRC into DEST. Assume
that SRC is operand 1 and DEST is operand 0. */ that SRC is operand 1 and DEST is operand 0. */
...@@ -4211,7 +4297,7 @@ mips_output_move (rtx dest, rtx src) ...@@ -4211,7 +4297,7 @@ mips_output_move (rtx dest, rtx src)
mode = GET_MODE (dest); mode = GET_MODE (dest);
dbl_p = (GET_MODE_SIZE (mode) == 8); dbl_p = (GET_MODE_SIZE (mode) == 8);
if (dbl_p && mips_split_64bit_move_p (dest, src)) if (mips_split_move_p (dest, src, SPLIT_IF_NECESSARY))
return "#"; return "#";
if ((src_code == REG && GP_REG_P (REGNO (src))) if ((src_code == REG && GP_REG_P (REGNO (src)))
...@@ -4222,6 +4308,14 @@ mips_output_move (rtx dest, rtx src) ...@@ -4222,6 +4308,14 @@ mips_output_move (rtx dest, rtx src)
if (GP_REG_P (REGNO (dest))) if (GP_REG_P (REGNO (dest)))
return "move\t%0,%z1"; return "move\t%0,%z1";
if (mips_mult_move_p (dest, src, SPLIT_IF_NECESSARY))
{
if (ISA_HAS_DSP_MULT)
return "mult\t%q0,%.,%.";
else
return "mult\t%.,%.";
}
/* Moves to HI are handled by special .md insns. */ /* Moves to HI are handled by special .md insns. */
if (REGNO (dest) == LO_REGNUM) if (REGNO (dest) == LO_REGNUM)
return "mtlo\t%z1"; return "mtlo\t%z1";
...@@ -10432,10 +10526,7 @@ mips_save_reg (rtx reg, rtx mem) ...@@ -10432,10 +10526,7 @@ mips_save_reg (rtx reg, rtx mem)
{ {
rtx x1, x2; rtx x1, x2;
if (mips_split_64bit_move_p (mem, reg)) mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
mips_split_doubleword_move (mem, reg);
else
mips_emit_move (mem, reg);
x1 = mips_frame_set (mips_subword (mem, false), x1 = mips_frame_set (mips_subword (mem, false),
mips_subword (reg, false)); mips_subword (reg, false));
...@@ -14895,10 +14986,15 @@ struct mips_sim { ...@@ -14895,10 +14986,15 @@ struct mips_sim {
static void static void
mips_sim_reset (struct mips_sim *state) mips_sim_reset (struct mips_sim *state)
{ {
curr_state = state->dfa_state;
state->time = 0; state->time = 0;
state->insns_left = state->issue_rate; state->insns_left = state->issue_rate;
memset (&state->last_set, 0, sizeof (state->last_set)); memset (&state->last_set, 0, sizeof (state->last_set));
state_reset (state->dfa_state); state_reset (curr_state);
targetm.sched.init (0, false, 0);
advance_state (curr_state);
} }
/* Initialize STATE before its first use. DFA_STATE points to an /* Initialize STATE before its first use. DFA_STATE points to an
...@@ -14907,6 +15003,12 @@ mips_sim_reset (struct mips_sim *state) ...@@ -14907,6 +15003,12 @@ mips_sim_reset (struct mips_sim *state)
static void static void
mips_sim_init (struct mips_sim *state, state_t dfa_state) mips_sim_init (struct mips_sim *state, state_t dfa_state)
{ {
if (targetm.sched.init_dfa_pre_cycle_insn)
targetm.sched.init_dfa_pre_cycle_insn ();
if (targetm.sched.init_dfa_post_cycle_insn)
targetm.sched.init_dfa_post_cycle_insn ();
state->issue_rate = mips_issue_rate (); state->issue_rate = mips_issue_rate ();
state->dfa_state = dfa_state; state->dfa_state = dfa_state;
mips_sim_reset (state); mips_sim_reset (state);
...@@ -14917,9 +15019,11 @@ mips_sim_init (struct mips_sim *state, state_t dfa_state) ...@@ -14917,9 +15019,11 @@ mips_sim_init (struct mips_sim *state, state_t dfa_state)
static void static void
mips_sim_next_cycle (struct mips_sim *state) mips_sim_next_cycle (struct mips_sim *state)
{ {
curr_state = state->dfa_state;
state->time++; state->time++;
state->insns_left = state->issue_rate; state->insns_left = state->issue_rate;
state_transition (state->dfa_state, 0); advance_state (curr_state);
} }
/* Advance simulation state STATE until instruction INSN can read /* Advance simulation state STATE until instruction INSN can read
...@@ -15025,8 +15129,11 @@ mips_sim_record_set (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data) ...@@ -15025,8 +15129,11 @@ mips_sim_record_set (rtx x, const_rtx pat ATTRIBUTE_UNUSED, void *data)
static void static void
mips_sim_issue_insn (struct mips_sim *state, rtx insn) mips_sim_issue_insn (struct mips_sim *state, rtx insn)
{ {
state_transition (state->dfa_state, insn); curr_state = state->dfa_state;
state->insns_left--;
state_transition (curr_state, insn);
state->insns_left = targetm.sched.variable_issue (0, false, insn,
state->insns_left);
mips_sim_insn = insn; mips_sim_insn = insn;
note_stores (PATTERN (insn), mips_sim_record_set, state); note_stores (PATTERN (insn), mips_sim_record_set, state);
...@@ -15078,6 +15185,109 @@ mips_sim_finish_insn (struct mips_sim *state, rtx insn) ...@@ -15078,6 +15185,109 @@ mips_sim_finish_insn (struct mips_sim *state, rtx insn)
} }
} }
/* Use simulator state STATE to calculate the execution time of
instruction sequence SEQ. */
static unsigned int
mips_seq_time (struct mips_sim *state, rtx seq)
{
mips_sim_reset (state);
for (rtx insn = seq; insn; insn = NEXT_INSN (insn))
{
mips_sim_wait_insn (state, insn);
mips_sim_issue_insn (state, insn);
}
return state->time;
}
/* Return the execution-time cost of mips_tuning_info.fast_mult_zero_zero_p
setting SETTING, using STATE to simulate instruction sequences. */
static unsigned int
mips_mult_zero_zero_cost (struct mips_sim *state, bool setting)
{
mips_tuning_info.fast_mult_zero_zero_p = setting;
start_sequence ();
enum machine_mode dword_mode = TARGET_64BIT ? TImode : DImode;
rtx hilo = gen_rtx_REG (dword_mode, MD_REG_FIRST);
mips_emit_move_or_split (hilo, const0_rtx, SPLIT_FOR_SPEED);
/* If the target provides mulsidi3_32bit then that's the most likely
consumer of the result. Test for bypasses. */
if (dword_mode == DImode && HAVE_maddsidi4)
{
rtx gpr = gen_rtx_REG (SImode, GP_REG_FIRST + 4);
emit_insn (gen_maddsidi4 (hilo, gpr, gpr, hilo));
}
unsigned int time = mips_seq_time (state, get_insns ());
end_sequence ();
return time;
}
/* Check the relative speeds of "MULT $0,$0" and "MTLO $0; MTHI $0"
and set up mips_tuning_info.fast_mult_zero_zero_p accordingly.
Prefer MULT -- which is shorter -- in the event of a tie. */
static void
mips_set_fast_mult_zero_zero_p (struct mips_sim *state)
{
if (TARGET_MIPS16)
/* No MTLO or MTHI available. */
mips_tuning_info.fast_mult_zero_zero_p = true;
else
{
unsigned int true_time = mips_mult_zero_zero_cost (state, true);
unsigned int false_time = mips_mult_zero_zero_cost (state, false);
mips_tuning_info.fast_mult_zero_zero_p = (true_time <= false_time);
}
}
/* Set up costs based on the current architecture and tuning settings. */
static void
mips_set_tuning_info (void)
{
if (mips_tuning_info.initialized_p
&& mips_tuning_info.arch == mips_arch
&& mips_tuning_info.tune == mips_tune
&& mips_tuning_info.mips16_p == TARGET_MIPS16)
return;
mips_tuning_info.arch = mips_arch;
mips_tuning_info.tune = mips_tune;
mips_tuning_info.mips16_p = TARGET_MIPS16;
mips_tuning_info.initialized_p = true;
dfa_start ();
struct mips_sim state;
mips_sim_init (&state, alloca (state_size ()));
mips_set_fast_mult_zero_zero_p (&state);
dfa_finish ();
}
/* Implement TARGET_EXPAND_TO_RTL_HOOK. */
static void
mips_expand_to_rtl_hook (void)
{
/* We need to call this at a point where we can safely create sequences
of instructions, so TARGET_OVERRIDE_OPTIONS is too early. We also
need to call it at a point where the DFA infrastructure is not
already in use, so we can't just call it lazily on demand.
At present, mips_tuning_info is only needed during post-expand
RTL passes such as split_insns, so this hook should be early enough.
We may need to move the call elsewhere if mips_tuning_info starts
to be used for other things (such as rtx_costs, or expanders that
could be called during gimple optimization). */
mips_set_tuning_info ();
}
/* The VR4130 pipeline issues aligned pairs of instructions together, /* The VR4130 pipeline issues aligned pairs of instructions together,
but it stalls the second instruction if it depends on the first. but it stalls the second instruction if it depends on the first.
In order to cut down the amount of logic required, this dependence In order to cut down the amount of logic required, this dependence
...@@ -17748,6 +17958,8 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx op1, ...@@ -17748,6 +17958,8 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx op1,
#undef TARGET_PREFERRED_RELOAD_CLASS #undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS mips_preferred_reload_class #define TARGET_PREFERRED_RELOAD_CLASS mips_preferred_reload_class
#undef TARGET_EXPAND_TO_RTL_HOOK
#define TARGET_EXPAND_TO_RTL_HOOK mips_expand_to_rtl_hook
#undef TARGET_ASM_FILE_START #undef TARGET_ASM_FILE_START
#define TARGET_ASM_FILE_START mips_file_start #define TARGET_ASM_FILE_START mips_file_start
#undef TARGET_ASM_FILE_START_FILE_DIRECTIVE #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
......
...@@ -204,7 +204,7 @@ ...@@ -204,7 +204,7 @@
;; the split instructions; in some cases, it is more appropriate for the ;; the split instructions; in some cases, it is more appropriate for the
;; scheduling type to be "multi" instead. ;; scheduling type to be "multi" instead.
(define_attr "move_type" (define_attr "move_type"
"unknown,load,fpload,store,fpstore,mtc,mfc,mtlo,mflo,move,fmove, "unknown,load,fpload,store,fpstore,mtc,mfc,mtlo,mflo,imul,move,fmove,
const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool, const,constN,signext,ext_ins,logical,arith,sll0,andi,loadpool,
shift_shift" shift_shift"
(const_string "unknown")) (const_string "unknown"))
...@@ -369,6 +369,7 @@ ...@@ -369,6 +369,7 @@
(eq_attr "move_type" "mflo") (const_string "mflo") (eq_attr "move_type" "mflo") (const_string "mflo")
;; These types of move are always single insns. ;; These types of move are always single insns.
(eq_attr "move_type" "imul") (const_string "imul")
(eq_attr "move_type" "fmove") (const_string "fmove") (eq_attr "move_type" "fmove") (const_string "fmove")
(eq_attr "move_type" "loadpool") (const_string "load") (eq_attr "move_type" "loadpool") (const_string "load")
(eq_attr "move_type" "signext") (const_string "signext") (eq_attr "move_type" "signext") (const_string "signext")
...@@ -4243,14 +4244,17 @@ ...@@ -4243,14 +4244,17 @@
(set_attr "mode" "<MODE>")]) (set_attr "mode" "<MODE>")])
(define_insn "*movdi_32bit" (define_insn "*movdi_32bit"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d,*f,*f,*d,*m,*B*C*D,*B*C*D,*d,*m") [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,d,m,*a,*a,*d,*f,*f,*d,*m,*B*C*D,*B*C*D,*d,*m")
(match_operand:DI 1 "move_operand" "d,i,m,d,*J*d,*a,*J*d,*m,*f,*f,*d,*m,*B*C*D,*B*C*D"))] (match_operand:DI 1 "move_operand" "d,i,m,d,*J,*d,*a,*J*d,*m,*f,*f,*d,*m,*B*C*D,*B*C*D"))]
"!TARGET_64BIT && !TARGET_MIPS16 "!TARGET_64BIT && !TARGET_MIPS16
&& (register_operand (operands[0], DImode) && (register_operand (operands[0], DImode)
|| reg_or_0_operand (operands[1], DImode))" || reg_or_0_operand (operands[1], DImode))"
{ return mips_output_move (operands[0], operands[1]); } { return mips_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "move,const,load,store,mtlo,mflo,mtc,fpload,mfc,fpstore,mtc,fpload,mfc,fpstore") [(set_attr "move_type" "move,const,load,store,imul,mtlo,mflo,mtc,fpload,mfc,fpstore,mtc,fpload,mfc,fpstore")
(set_attr "mode" "DI")]) (set (attr "mode")
(if_then_else (eq_attr "move_type" "imul")
(const_string "SI")
(const_string "DI")))])
(define_insn "*movdi_32bit_mips16" (define_insn "*movdi_32bit_mips16"
[(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
...@@ -4696,15 +4700,18 @@ ...@@ -4696,15 +4700,18 @@
}) })
(define_insn "*movti" (define_insn "*movti"
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,m,*a,*d") [(set (match_operand:TI 0 "nonimmediate_operand" "=d,d,d,m,*a,*a,*d")
(match_operand:TI 1 "move_operand" "d,i,m,dJ,*d*J,*a"))] (match_operand:TI 1 "move_operand" "d,i,m,dJ,*J,*d,*a"))]
"TARGET_64BIT "TARGET_64BIT
&& !TARGET_MIPS16 && !TARGET_MIPS16
&& (register_operand (operands[0], TImode) && (register_operand (operands[0], TImode)
|| reg_or_0_operand (operands[1], TImode))" || reg_or_0_operand (operands[1], TImode))"
"#" { return mips_output_move (operands[0], operands[1]); }
[(set_attr "move_type" "move,const,load,store,mtlo,mflo") [(set_attr "move_type" "move,const,load,store,imul,mtlo,mflo")
(set_attr "mode" "TI")]) (set (attr "mode")
(if_then_else (eq_attr "move_type" "imul")
(const_string "SI")
(const_string "TI")))])
(define_insn "*movti_mips16" (define_insn "*movti_mips16"
[(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d") [(set (match_operand:TI 0 "nonimmediate_operand" "=d,y,d,d,d,d,m,*d")
...@@ -4754,21 +4761,20 @@ ...@@ -4754,21 +4761,20 @@
(define_split (define_split
[(set (match_operand:MOVE64 0 "nonimmediate_operand") [(set (match_operand:MOVE64 0 "nonimmediate_operand")
(match_operand:MOVE64 1 "move_operand"))] (match_operand:MOVE64 1 "move_operand"))]
"reload_completed && !TARGET_64BIT "reload_completed && mips_split_move_insn_p (operands[0], operands[1], insn)"
&& mips_split_64bit_move_p (operands[0], operands[1])"
[(const_int 0)] [(const_int 0)]
{ {
mips_split_doubleword_move (operands[0], operands[1]); mips_split_move_insn (operands[0], operands[1], curr_insn);
DONE; DONE;
}) })
(define_split (define_split
[(set (match_operand:MOVE128 0 "nonimmediate_operand") [(set (match_operand:MOVE128 0 "nonimmediate_operand")
(match_operand:MOVE128 1 "move_operand"))] (match_operand:MOVE128 1 "move_operand"))]
"TARGET_64BIT && reload_completed" "reload_completed && mips_split_move_insn_p (operands[0], operands[1], insn)"
[(const_int 0)] [(const_int 0)]
{ {
mips_split_doubleword_move (operands[0], operands[1]); mips_split_move_insn (operands[0], operands[1], curr_insn);
DONE; DONE;
}) })
......
2012-10-07 Richard Sandiford <rdsandiford@googlemail.com>
Sandra Loosemore <sandra@codesourcery.com>
* gcc.target/mips/madd-9.c: Force code to be tuned for the 4kc
and test that the accumulator is initialized using MULT.
* gcc.target/mips/mips32-dsp-accinit-1.c: New test.
* gcc.target/mips/mips32-dsp-accinit-2.c: Likewise.
2012-10-06 Paolo Carlini <paolo.carlini@oracle.com> 2012-10-06 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/52764 PR c++/52764
......
/* { dg-do compile } */ /* { dg-do compile } */
/* { dg-options "isa_rev>=1 -mgp32" } */ /* { dg-options "isa_rev>=1 -mgp32 -mtune=4kc" } */
/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */ /* References to X within the loop need to have a higher frequency than
references to X outside the loop, otherwise there is no reason
to prefer multiply/accumulator registers over GPRs. */
/* { dg-skip-if "requires register frequencies" { *-*-* } { "-O0" "-Os" } { "" } } */
/* { dg-final { scan-assembler-not "\tmul\t" } } */ /* { dg-final { scan-assembler-not "\tmul\t" } } */
/* { dg-final { scan-assembler-not "\tmthi" } } */
/* { dg-final { scan-assembler-not "\tmtlo" } } */
/* { dg-final { scan-assembler "\tmult\t" } } */
/* { dg-final { scan-assembler "\tmadd\t" } } */ /* { dg-final { scan-assembler "\tmadd\t" } } */
NOMIPS16 long long NOMIPS16 long long
......
/* { dg-options "-mdspr2 -mgp32 -mtune=74kc" } */
/* References to RESULT within the loop need to have a higher frequency than
references to RESULT outside the loop, otherwise there is no reason
to prefer multiply/accumulator registers over GPRs. */
/* { dg-skip-if "requires register frequencies" { *-*-* } { "-O0" "-Os" } { "" } } */
/* Check that the zero-initialization of the accumulator feeding into
the madd is done by means of a mult instruction instead of mthi/mtlo. */
NOMIPS16 long long f (int n, int *v, int m)
{
long long result = 0;
int i;
for (i = 0; i < n; i++)
result = __builtin_mips_madd (result, v[i], m);
return result;
}
/* { dg-final { scan-assembler "\tmult\t\\\$ac.,\\\$0,\\\$0" } } */
/* { dg-final { scan-assembler-not "mthi\t" } } */
/* { dg-final { scan-assembler-not "mtlo\t" } } */
/* { dg-options "-mdspr2 -mgp32 -mtune=4kp" } */
/* References to RESULT within the loop need to have a higher frequency than
references to RESULT outside the loop, otherwise there is no reason
to prefer multiply/accumulator registers over GPRs. */
/* { dg-skip-if "requires register frequencies" { *-*-* } { "-O0" "-Os" } { "" } } */
/* Check that the zero-initialization of the accumulator feeding into
the madd is done by means of a mult instruction instead of mthi/mtlo. */
NOMIPS16 long long f (int n, int *v, int m)
{
long long result = 0;
int i;
for (i = 0; i < n; i++)
result = __builtin_mips_madd (result, v[i], m);
return result;
}
/* { dg-final { scan-assembler-not "mult\t\[^\n\]*\\\$0" } } */
/* { dg-final { scan-assembler "\tmthi\t" } } */
/* { dg-final { scan-assembler "\tmtlo\t" } } */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment