aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKaz Kojima <kkojima@gcc.gnu.org>2014-12-19 04:56:26 +0000
committerKaz Kojima <kkojima@gcc.gnu.org>2014-12-19 04:56:26 +0000
commit1e3e92b51382cf14e198a6d9bb11ba7de8e798e0 (patch)
tree500eab9e57b28df315fca2ac7efd0c39b5966f45
parent74bd0da1fd3bdffc036f0449c4d3ea7c95129585 (diff)
downloadgcc-1e3e92b51382cf14e198a6d9bb11ba7de8e798e0.zip
gcc-1e3e92b51382cf14e198a6d9bb11ba7de8e798e0.tar.gz
gcc-1e3e92b51382cf14e198a6d9bb11ba7de8e798e0.tar.bz2
* [SH] Split QI/HImode load/store via r0 when LRA is enabled.
From-SVN: r218892
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/config/sh/sh.c32
2 files changed, 37 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a974136..e67e97c 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,10 @@
2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org>
+ * config/sh/sh.c (prepare_move_operands): Split HI/QImode load/store
+ to two move insns via r0.
+
+2014-12-19 Kaz Kojima <kkojima@gcc.gnu.org>
+
* config/sh/predicates.md (arith_or_int_operand): New predicate.
* config/sh/sh.md (addsi3): Use arith_or_int_operand for operand 2.
Return fail if operands[0] and operands[1] are overlap when
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index 7851fe8..8ad8afa5 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -1778,6 +1778,38 @@ prepare_move_operands (rtx operands[], machine_mode mode)
&& GET_CODE (XEXP (operands[0], 0)) == PLUS
&& REG_P (XEXP (XEXP (operands[0], 0), 1)))
operands[1] = copy_to_mode_reg (mode, operands[1]);
+
+ /* When the displacement addressing is used, RA will assign r0 to
+ the pseudo register operand for the QI/HImode load/store.
+ This tends to make a long live range for R0 and might cause
+ anomalous register spills in some case with LRA. See PR
+ target/55212.
+ We split possible load/store to two move insns via r0 so as to
+ shorten R0 live range. It will make some codes worse but will
+ win on avarage for LRA. */
+ else if (sh_lra_p ()
+ && TARGET_SH1 && ! TARGET_SH2A
+ && (mode == QImode || mode == HImode)
+ && ((REG_P (operands[0]) && MEM_P (operands[1]))
+ || (REG_P (operands[1]) && MEM_P (operands[0]))))
+ {
+ bool load_p = REG_P (operands[0]);
+ rtx reg = operands[load_p ? 0 : 1];
+ rtx adr = XEXP (operands[load_p ? 1 : 0], 0);
+
+ if (REGNO (reg) >= FIRST_PSEUDO_REGISTER
+ && GET_CODE (adr) == PLUS
+ && REG_P (XEXP (adr, 0))
+ && (REGNO (XEXP (adr, 0)) >= FIRST_PSEUDO_REGISTER)
+ && CONST_INT_P (XEXP (adr, 1))
+ && INTVAL (XEXP (adr, 1)) != 0
+ && sh_legitimate_index_p (mode, XEXP (adr, 1), false, true))
+ {
+ rtx r0_rtx = gen_rtx_REG (mode, R0_REG);
+ emit_move_insn (r0_rtx, operands[1]);
+ operands[1] = r0_rtx;
+ }
+ }
}
if (mode == Pmode || mode == ptr_mode)