On 10-01-14 09:47, Richard Sandiford wrote:
Tom de Vries <tom_devr...@mentor.com> writes:
Why not just collect the usage information at
the end of final rather than at the beginning, so that all splits during
final have been done?
If we have a call to a leaf function, the final rtl representation does not
contain calls. The problem does not lie in the final pass where the callee is
analyzed, but in the caller, where information is used, and where the unsplit
call is missing the clobber of r6.
Ah, so when you're using this hook in final, you're actually adding in
the set of registers that will be clobbered by a future caller's CALL_INSN,
as well as the registers that are clobbered by the callee itself?
Right. The first part is not the intended usage of the hook, but it was the
simplest fix.
That seems a bit error-prone, since we don't know at this stage what
the future caller will look like. (Things like the target attribute
make this harder to predict.)
I think it would be cleaner to just calculate the callee-clobbered
registers during final and leave the caller to say what it clobbers.
Agree. I've rewritten the patch as such.
FWIW, I still think it'd be better to collect the set at the end of final
(after any final splits) rather than at the beginning.
Hmm. I was not aware that splits can happen during final. I'll try to update
that patch as well.
For other cases (where the usage isn't explicit
at the rtl level), why not record the usage in CALL_INSN_FUNCTION_USAGE
instead?
Right, we could add the r6 clobber that way. But to keep things simple, I've
used the hook instead.
Why's it simpler though? That's the kind of thing CALL_INSN_FUNCTION_USAGE
is there for.
It was simpler to implement. But you're right, using CALL_INSN_FUNCTION_USAGE
was simple as well.
build and reg-tested on MIPS. OK for stage1? (You've alread OK-ed the test-case
part).
Thanks,
- Tom
Thanks,
Richard
2014-01-12 Radovan Obradovic <robrado...@mips.com>
Tom de Vries <t...@codesourcery.com>
* 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