2014-01-12 Radovan Obradovic Tom de Vries * config/mips/mips.c (POST_CALL_TMP_REG): Define. (mips_split_call): Use POST_CALL_TMP_REG. (mips_fn_other_hard_reg_usage): New function. (TARGET_FN_OTHER_HARD_REG_USAGE): Define targhook using new function. (mips_expand_call): Add POST_CALL_TMP_REG clobber. * gcc.target/mips/mips.exp: Add use-caller-save to -ffoo/-fno-foo options. * gcc.target/mips/fuse-caller-save.c: New test. --- gcc/config/mips/mips.c | 41 +++++++++++++++++++++--- gcc/testsuite/gcc.target/mips/fuse-caller-save.c | 30 +++++++++++++++++ gcc/testsuite/gcc.target/mips/mips.exp | 1 + 3 files changed, 67 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/mips/fuse-caller-save.c diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 617391c..ef7a3f9 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -175,6 +175,11 @@ along with GCC; see the file COPYING3. If not see /* Return the usual opcode for a nop. */ #define MIPS_NOP 0 +/* Temporary register that is used after a call, and suitable for both + MIPS16 and non-MIPS16 code. $4 and $5 are used for returning complex double + values in soft-float code, so $6 is the first suitable candidate. */ +#define POST_CALL_TMP_REG (GP_ARG_FIRST + 2) + /* Classifies an address. ADDRESS_REG @@ -6906,11 +6911,19 @@ mips_expand_call (enum mips_call_type type, rtx result, rtx addr, { rtx orig_addr, pattern, insn; int fp_code; + rtx post_call_tmp_reg = gen_rtx_REG (word_mode, POST_CALL_TMP_REG); fp_code = aux == 0 ? 0 : (int) GET_MODE (aux); insn = mips16_build_call_stub (result, &addr, args_size, fp_code); if (insn) { + if (TARGET_EXPLICIT_RELOCS + && TARGET_CALL_CLOBBERED_GP + && !find_reg_note (insn, REG_NORETURN, 0)) + CALL_INSN_FUNCTION_USAGE (insn) + = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_CLOBBER (VOIDmode, post_call_tmp_reg), + CALL_INSN_FUNCTION_USAGE (insn)); gcc_assert (!lazy_p && type == MIPS_CALL_NORMAL); return insn; } @@ -6966,7 +6979,16 @@ mips_expand_call (enum mips_call_type type, rtx result, rtx addr, pattern = fn (result, addr, args_size); } - return mips_emit_call_insn (pattern, orig_addr, addr, lazy_p); + insn = mips_emit_call_insn (pattern, orig_addr, addr, lazy_p); + if (TARGET_EXPLICIT_RELOCS + && TARGET_CALL_CLOBBERED_GP + && !find_reg_note (insn, REG_NORETURN, 0)) + CALL_INSN_FUNCTION_USAGE (insn) + = gen_rtx_EXPR_LIST (VOIDmode, + gen_rtx_CLOBBER (VOIDmode, post_call_tmp_reg), + CALL_INSN_FUNCTION_USAGE (insn)); + + return insn; } /* Split call instruction INSN into a $gp-clobbering call and @@ -6978,10 +7000,8 @@ mips_split_call (rtx insn, rtx call_pattern) { emit_call_insn (call_pattern); if (!find_reg_note (insn, REG_NORETURN, 0)) - /* Pick a temporary register that is suitable for both MIPS16 and - non-MIPS16 code. $4 and $5 are used for returning complex double - values in soft-float code, so $6 is the first suitable candidate. */ - mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2)); + mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, + POST_CALL_TMP_REG)); } /* Return true if a call to DECL may need to use JALX. */ @@ -18687,6 +18707,14 @@ mips_case_values_threshold (void) else return default_case_values_threshold (); } + +/* Implement TARGET_FN_OTHER_HARD_REG_USAGE. */ + +static bool +mips_fn_other_hard_reg_usage (struct hard_reg_set_container *fn_used_regs) +{ + return true; +} /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP @@ -18921,6 +18949,9 @@ mips_case_values_threshold (void) #undef TARGET_CASE_VALUES_THRESHOLD #define TARGET_CASE_VALUES_THRESHOLD mips_case_values_threshold +#undef TARGET_FN_OTHER_HARD_REG_USAGE +#define TARGET_FN_OTHER_HARD_REG_USAGE mips_fn_other_hard_reg_usage + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-mips.h" diff --git a/gcc/testsuite/gcc.target/mips/fuse-caller-save.c b/gcc/testsuite/gcc.target/mips/fuse-caller-save.c new file mode 100644 index 0000000..1fd6c7d --- /dev/null +++ b/gcc/testsuite/gcc.target/mips/fuse-caller-save.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-fuse-caller-save" } */ +/* { dg-skip-if "" { *-*-* } { "*" } { "-Os" } } */ +/* Testing -fuse-caller-save optimization option. */ + +static int __attribute__((noinline)) NOCOMPRESSION +bar (int x) +{ + return x + 3; +} + +int __attribute__((noinline)) NOCOMPRESSION +foo (int y) +{ + return y + bar (y); +} + +int NOCOMPRESSION +main (void) +{ + return !(foo (5) == 13); +} + +/* Check that there are only 2 stack-saves: r31 in main and foo. */ + +/* Check that there only 2 sw/sd. */ +/* { dg-final { scan-assembler-times "(?n)s\[wd\]\t\\\$.*,.*\\(\\\$sp\\)" 2 } } */ + +/* Check that the first caller-save register is unused. */ +/* { dg-final { scan-assembler-not "\\\$16" } } */ diff --git a/gcc/testsuite/gcc.target/mips/mips.exp b/gcc/testsuite/gcc.target/mips/mips.exp index 8c72cff..6ad8160 100644 --- a/gcc/testsuite/gcc.target/mips/mips.exp +++ b/gcc/testsuite/gcc.target/mips/mips.exp @@ -305,6 +305,7 @@ foreach option { tree-vectorize unroll-all-loops unroll-loops + use-caller-save } { lappend mips_option_groups $option "-f(no-|)$option" } -- 1.8.3.2