diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2012-10-15 22:04:37 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2012-10-15 22:04:37 +0000 |
commit | 14df3f361e5aaa4145ab242886e3a857d4ae078c (patch) | |
tree | 0e4d00759d8ddfb538c6aca0b82c0bfa1c6bbde8 /gcc/config | |
parent | 845f4111764265237c4554fae4219691b976cb7a (diff) | |
download | gcc-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.md | 1 | ||||
-rw-r--r-- | gcc/config/sh/predicates.md | 17 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 4 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 58 |
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; }) |