aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorOleg Endo <olegendo@gcc.gnu.org>2012-10-15 22:04:37 +0000
committerOleg Endo <olegendo@gcc.gnu.org>2012-10-15 22:04:37 +0000
commit14df3f361e5aaa4145ab242886e3a857d4ae078c (patch)
tree0e4d00759d8ddfb538c6aca0b82c0bfa1c6bbde8 /gcc/config
parent845f4111764265237c4554fae4219691b976cb7a (diff)
downloadgcc-14df3f361e5aaa4145ab242886e3a857d4ae078c.zip
gcc-14df3f361e5aaa4145ab242886e3a857d4ae078c.tar.gz
gcc-14df3f361e5aaa4145ab242886e3a857d4ae078c.tar.bz2
re PR target/54760 ([SH] Add __builtin_thread_pointer, __builtin_set_thread_pointer)
PR target/54760 * config/sh/sh.c (sh_find_base_reg_disp): Stop searching insns when hitting a call insn if GBR is marked as call used. * config/sh/iterators.md (QIHISIDI): New mode iterator. * config/sh/predicates.md (gbr_address_mem): New predicate. * config/sh/sh.md (*movdi_gbr_load, *movdi_gbr_store): New insn_and_split. Use QIHISIDI instead of QIHISI in unnamed GBR addressing splits. PR target/54760 * gcc.target/sh/pr54760-2.c: Add long long and unsigned long long test functions. * gcc.target/sh/pr54760-4.c: New. From-SVN: r192480
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/sh/iterators.md1
-rw-r--r--gcc/config/sh/predicates.md17
-rw-r--r--gcc/config/sh/sh.c4
-rw-r--r--gcc/config/sh/sh.md58
4 files changed, 71 insertions, 9 deletions
diff --git a/gcc/config/sh/iterators.md b/gcc/config/sh/iterators.md
index ec95013..e118c3e 100644
--- a/gcc/config/sh/iterators.md
+++ b/gcc/config/sh/iterators.md
@@ -18,6 +18,7 @@
;; along with GCC; see the file COPYING3. If not see
;; <http://www.gnu.org/licenses/>.
+(define_mode_iterator QIHISIDI [QI HI SI DI])
(define_mode_iterator QIHISI [QI HI SI])
(define_mode_iterator QIHI [QI HI])
(define_mode_iterator HISI [HI SI])
diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md
index cd98055..83508e8 100644
--- a/gcc/config/sh/predicates.md
+++ b/gcc/config/sh/predicates.md
@@ -1139,3 +1139,20 @@
return INTVAL (op) >= 0 && INTVAL (op) <= max_disp;
})
+
+;; A predicate that determines whether OP is a valid GBR addressing mode
+;; memory reference.
+(define_predicate "gbr_address_mem"
+ (match_code "mem")
+{
+ rtx addr = XEXP (op, 0);
+
+ if (REG_P (addr) && REGNO (addr) == GBR_REG)
+ return true;
+ if (GET_CODE (addr) == PLUS
+ && REG_P (XEXP (addr, 0)) && REGNO (XEXP (addr, 0)) == GBR_REG
+ && gbr_displacement (XEXP (addr, 1), mode))
+ return true;
+
+ return false;
+})
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index bc4eb8b..763ee9d 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -13395,6 +13395,10 @@ sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL)
for (rtx i = prev_nonnote_insn (insn); i != NULL;
i = prev_nonnote_insn (i))
{
+ if (REGNO_REG_SET_P (regs_invalidated_by_call_regset, GBR_REG)
+ && CALL_P (i))
+ break;
+
if (!NONJUMP_INSN_P (i))
continue;
diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md
index 1b6c284..95afd9b 100644
--- a/gcc/config/sh/sh.md
+++ b/gcc/config/sh/sh.md
@@ -10277,6 +10277,47 @@ label:
"mov.<bwl> %0,@(0,gbr)"
[(set_attr "type" "store")])
+;; DImode memory accesses have to be split in two SImode accesses.
+;; Split them before reload, so that it gets a better chance to figure out
+;; how to deal with the R0 restriction for the individual SImode accesses.
+;; Do not match this insn during or after reload because it can't be split
+;; afterwards.
+(define_insn_and_split "*movdi_gbr_load"
+ [(set (match_operand:DI 0 "register_operand")
+ (match_operand:DI 1 "gbr_address_mem"))]
+ "TARGET_SH1 && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (match_dup 3) (match_dup 5))
+ (set (match_dup 4) (match_dup 6))]
+{
+ /* Swap low/high part load order on little endian, so that the result reg
+ of the second load can be used better. */
+ int off = TARGET_LITTLE_ENDIAN ? 1 : 0;
+ operands[3 + off] = gen_lowpart (SImode, operands[0]);
+ operands[5 + off] = gen_lowpart (SImode, operands[1]);
+ operands[4 - off] = gen_highpart (SImode, operands[0]);
+ operands[6 - off] = gen_highpart (SImode, operands[1]);
+})
+
+(define_insn_and_split "*movdi_gbr_store"
+ [(set (match_operand:DI 0 "gbr_address_mem")
+ (match_operand:DI 1 "register_operand"))]
+ "TARGET_SH1 && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(set (match_dup 3) (match_dup 5))
+ (set (match_dup 4) (match_dup 6))]
+{
+ /* Swap low/high part store order on big endian, so that stores of function
+ call results can save a reg copy. */
+ int off = TARGET_LITTLE_ENDIAN ? 0 : 1;
+ operands[3 + off] = gen_lowpart (SImode, operands[0]);
+ operands[5 + off] = gen_lowpart (SImode, operands[1]);
+ operands[4 - off] = gen_highpart (SImode, operands[0]);
+ operands[6 - off] = gen_highpart (SImode, operands[1]);
+})
+
;; Sometimes memory accesses do not get combined with the store_gbr insn,
;; in particular when the displacements are in the range of the regular move
;; insns. Thus, in the first split pass after the combine pass we search
@@ -10287,15 +10328,15 @@ label:
;; other operand) and there's no point of doing it if the GBR is not
;; referenced in a function at all.
(define_split
- [(set (match_operand:QIHISI 0 "register_operand")
- (match_operand:QIHISI 1 "memory_operand"))]
+ [(set (match_operand:QIHISIDI 0 "register_operand")
+ (match_operand:QIHISIDI 1 "memory_operand"))]
"TARGET_SH1 && !reload_in_progress && !reload_completed
&& df_regs_ever_live_p (GBR_REG)"
[(set (match_dup 0) (match_dup 1))]
{
rtx gbr_mem = sh_find_equiv_gbr_addr (curr_insn, operands[1]);
if (gbr_mem != NULL_RTX)
- operands[1] = change_address (operands[1], GET_MODE (operands[1]), gbr_mem);
+ operands[1] = replace_equiv_address (operands[1], gbr_mem);
else
FAIL;
})
@@ -10309,7 +10350,7 @@ label:
{
rtx gbr_mem = sh_find_equiv_gbr_addr (curr_insn, operands[1]);
if (gbr_mem != NULL_RTX)
- operands[1] = change_address (operands[1], GET_MODE (operands[1]), gbr_mem);
+ operands[1] = replace_equiv_address (operands[1], gbr_mem);
else
FAIL;
})
@@ -10328,23 +10369,22 @@ label:
if (gbr_mem != NULL_RTX)
{
operands[2] = gen_reg_rtx (GET_MODE (operands[1]));
- operands[1] = change_address (operands[1], GET_MODE (operands[1]),
- gbr_mem);
+ operands[1] = replace_equiv_address (operands[1], gbr_mem);
}
else
FAIL;
})
(define_split
- [(set (match_operand:QIHISI 0 "memory_operand")
- (match_operand:QIHISI 1 "register_operand"))]
+ [(set (match_operand:QIHISIDI 0 "memory_operand")
+ (match_operand:QIHISIDI 1 "register_operand"))]
"TARGET_SH1 && !reload_in_progress && !reload_completed
&& df_regs_ever_live_p (GBR_REG)"
[(set (match_dup 0) (match_dup 1))]
{
rtx gbr_mem = sh_find_equiv_gbr_addr (curr_insn, operands[0]);
if (gbr_mem != NULL_RTX)
- operands[0] = change_address (operands[0], GET_MODE (operands[0]), gbr_mem);
+ operands[0] = replace_equiv_address (operands[0], gbr_mem);
else
FAIL;
})