aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorRichard Henderson <rth@redhat.com>2011-01-19 10:50:52 -0800
committerRichard Henderson <rth@gcc.gnu.org>2011-01-19 10:50:52 -0800
commit37a185d79e630fd3ad5acd7ac5a29ac07a5be4d6 (patch)
tree066424705d9da85f89031dc6070862c03f1f11cb /gcc/config
parent040c57570147b0a05c29339dd778378b8cf15a56 (diff)
downloadgcc-37a185d79e630fd3ad5acd7ac5a29ac07a5be4d6.zip
gcc-37a185d79e630fd3ad5acd7ac5a29ac07a5be4d6.tar.gz
gcc-37a185d79e630fd3ad5acd7ac5a29ac07a5be4d6.tar.bz2
mn10300: Emit retf instruction
Now that we properly track the life of MDR, we can emit the RETF instruction if MDR has not been modified. This insn is 3-4 cycles faster since the return address is already loaded. From-SVN: r169013
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/mn10300/mn10300-protos.h3
-rw-r--r--gcc/config/mn10300/mn10300.c65
-rw-r--r--gcc/config/mn10300/mn10300.md42
3 files changed, 61 insertions, 49 deletions
diff --git a/gcc/config/mn10300/mn10300-protos.h b/gcc/config/mn10300/mn10300-protos.h
index c25ba9b..058f5df 100644
--- a/gcc/config/mn10300/mn10300-protos.h
+++ b/gcc/config/mn10300/mn10300-protos.h
@@ -45,7 +45,8 @@ extern bool mn10300_match_ccmode (rtx, Mmode);
#endif /* RTX_CODE */
extern bool mn10300_regno_in_class_p (unsigned, int, bool);
-extern int mn10300_can_use_return_insn (void);
+extern bool mn10300_can_use_rets_insn (void);
+extern bool mn10300_can_use_retf_insn (void);
extern void mn10300_expand_prologue (void);
extern void mn10300_expand_epilogue (void);
extern int mn10300_initial_offset (int, int);
diff --git a/gcc/config/mn10300/mn10300.c b/gcc/config/mn10300/mn10300.c
index b2c2460..8a042f6 100644
--- a/gcc/config/mn10300/mn10300.c
+++ b/gcc/config/mn10300/mn10300.c
@@ -623,8 +623,33 @@ mn10300_print_reg_list (FILE *file, int mask)
fputc (']', file);
}
-int
-mn10300_can_use_return_insn (void)
+/* If the MDR register is never clobbered, we can use the RETF instruction
+ which takes the address from the MDR register. This is 3 cycles faster
+ than having to load the address from the stack. */
+
+bool
+mn10300_can_use_retf_insn (void)
+{
+ /* Don't bother if we're not optimizing. In this case we won't
+ have proper access to df_regs_ever_live_p. */
+ if (!optimize)
+ return false;
+
+ /* EH returns alter the saved return address; MDR is not current. */
+ if (crtl->calls_eh_return)
+ return false;
+
+ /* Obviously not if MDR is ever clobbered. */
+ if (df_regs_ever_live_p (MDR_REG))
+ return false;
+
+ /* ??? Careful not to use this during expand_epilogue etc. */
+ gcc_assert (!in_sequence_p ());
+ return leaf_function_p ();
+}
+
+bool
+mn10300_can_use_rets_insn (void)
{
return !mn10300_initial_offset (ARG_POINTER_REGNUM, STACK_POINTER_REGNUM);
}
@@ -995,6 +1020,7 @@ void
mn10300_expand_epilogue (void)
{
HOST_WIDE_INT size = mn10300_frame_size ();
+ int reg_save_bytes = REG_SAVE_BYTES;
if (TARGET_AM33_2 && fp_regs_to_save ())
{
@@ -1026,14 +1052,14 @@ mn10300_expand_epilogue (void)
this_strategy_size = SIZE_FMOV_SP (size, num_regs_to_save);
/* If size is too large, we'll have to adjust SP with an
add. */
- if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
{
/* Insn: add size + 4 * num_regs_to_save, sp. */
this_strategy_size += SIZE_ADD_SP (size + 4 * num_regs_to_save);
}
/* If we don't have to restore any non-FP registers,
we'll be able to save one byte by using rets. */
- if (! REG_SAVE_BYTES)
+ if (! reg_save_bytes)
this_strategy_size--;
if (this_strategy_size < strategy_size)
@@ -1060,14 +1086,14 @@ mn10300_expand_epilogue (void)
When size is close to 32Kb, we may be able to adjust SP
with an imm16 add instruction while still using fmov
(d8,sp). */
- if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
{
/* Insn: add size + 4 * num_regs_to_save
- + REG_SAVE_BYTES - 252,sp. */
+ + reg_save_bytes - 252,sp. */
this_strategy_size = SIZE_ADD_SP (size + 4 * num_regs_to_save
- + REG_SAVE_BYTES - 252);
+ + reg_save_bytes - 252);
/* Insn: fmov (##,sp),fs#, fo each fs# to be restored. */
- this_strategy_size += SIZE_FMOV_SP (252 - REG_SAVE_BYTES
+ this_strategy_size += SIZE_FMOV_SP (252 - reg_save_bytes
- 4 * num_regs_to_save,
num_regs_to_save);
/* We're going to use ret to release the FP registers
@@ -1096,14 +1122,14 @@ mn10300_expand_epilogue (void)
this_strategy_size += 3 * num_regs_to_save;
/* If size is large enough, we may be able to save a
couple of bytes. */
- if (size + 4 * num_regs_to_save + REG_SAVE_BYTES > 255)
+ if (size + 4 * num_regs_to_save + reg_save_bytes > 255)
{
/* Insn: mov a1,sp. */
this_strategy_size += 2;
}
/* If we don't have to restore any non-FP registers,
we'll be able to save one byte by using rets. */
- if (! REG_SAVE_BYTES)
+ if (! reg_save_bytes)
this_strategy_size--;
if (this_strategy_size < strategy_size)
@@ -1129,8 +1155,8 @@ mn10300_expand_epilogue (void)
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
GEN_INT (size + 4 * num_regs_to_save
- + REG_SAVE_BYTES - 252)));
- size = 252 - REG_SAVE_BYTES - 4 * num_regs_to_save;
+ + reg_save_bytes - 252)));
+ size = 252 - reg_save_bytes - 4 * num_regs_to_save;
break;
case restore_a1:
@@ -1176,7 +1202,7 @@ mn10300_expand_epilogue (void)
/* If we were using the restore_a1 strategy and the number of
bytes to be released won't fit in the `ret' byte, copy `a1'
to `sp', to avoid having to use `add' to adjust it. */
- if (! frame_pointer_needed && reg && size + REG_SAVE_BYTES > 255)
+ if (! frame_pointer_needed && reg && size + reg_save_bytes > 255)
{
emit_move_insn (stack_pointer_rtx, XEXP (reg, 0));
size = 0;
@@ -1203,7 +1229,7 @@ mn10300_expand_epilogue (void)
emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
size = 0;
}
- else if (size + REG_SAVE_BYTES > 255)
+ else if (size + reg_save_bytes > 255)
{
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx,
@@ -1212,15 +1238,10 @@ mn10300_expand_epilogue (void)
}
/* Adjust the stack and restore callee-saved registers, if any. */
- if (size || df_regs_ever_live_p (2) || df_regs_ever_live_p (3)
- || df_regs_ever_live_p (6) || df_regs_ever_live_p (7)
- || df_regs_ever_live_p (14) || df_regs_ever_live_p (15)
- || df_regs_ever_live_p (16) || df_regs_ever_live_p (17)
- || frame_pointer_needed)
- emit_jump_insn (gen_return_internal_regs
- (GEN_INT (size + REG_SAVE_BYTES)));
+ if (mn10300_can_use_rets_insn ())
+ emit_jump_insn (gen_rtx_RETURN (VOIDmode));
else
- emit_jump_insn (gen_return_internal ());
+ emit_jump_insn (gen_return_ret (GEN_INT (size + REG_SAVE_BYTES)));
}
/* Recognize the PARALLEL rtx generated by mn10300_gen_multiple_store().
diff --git a/gcc/config/mn10300/mn10300.md b/gcc/config/mn10300/mn10300.md
index 2477cb3..f3f6baf 100644
--- a/gcc/config/mn10300/mn10300.md
+++ b/gcc/config/mn10300/mn10300.md
@@ -1607,31 +1607,28 @@
{ mn10300_expand_epilogue (); DONE; }
)
-(define_insn "return_internal"
- [(const_int 2)
- (return)]
- ""
- "rets"
- [(set_attr "timings" "66")]
-)
+(define_insn "return"
+ [(return)]
+ "mn10300_can_use_rets_insn ()"
+{
+ /* The RETF insn is 4 cycles faster than RETS, though 1 byte larger. */
+ if (optimize_insn_for_speed_p () && mn10300_can_use_retf_insn ())
+ return "retf [],0";
+ else
+ return "rets";
+})
-;; This insn restores the callee saved registers and does a return, it
-;; can also deallocate stack space.
-(define_insn "return_internal_regs"
- [(const_int 0)
- (match_operand:SI 0 "const_int_operand" "i")
- (return)]
+(define_insn "return_ret"
+ [(return)
+ (use (match_operand:SI 0 "const_int_operand" ""))]
""
{
- fputs ("\tret ", asm_out_file);
+ /* The RETF insn is up to 3 cycles faster than RET. */
+ fputs ((mn10300_can_use_retf_insn () ? "\tretf " : "\tret "), asm_out_file);
mn10300_print_reg_list (asm_out_file, mn10300_get_live_callee_saved_regs ());
fprintf (asm_out_file, ",%d\n", (int) INTVAL (operands[0]));
return "";
-}
- ;; Assumes that there will be no more than 8 regs to pop
- [(set (attr "timings") (if_then_else (eq_attr "cpu" "am34")
- (const_int 1414) (const_int 1313)))]
-)
+})
;; This instruction matches one generated by mn10300_gen_multiple_store()
(define_insn "store_movm"
@@ -1651,13 +1648,6 @@
(const_int 99) (const_int 88)))]
)
-(define_insn "return"
- [(return)]
- "mn10300_can_use_return_insn ()"
- "rets"
- [(set_attr "timings" "66")]
-)
-
(define_expand "load_pic"
[(const_int 0)]
"flag_pic"