Commit 14df3f36 by Oleg Endo

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
parent 845f4111
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
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.
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
* config/sh/sh.c: Update function attribute comments.
* doc/extend.texi (function_vector): Rephrase SH2A specific part.
(nosave_low_regs, renesas, trapa_handler): Document SH specific
......@@ -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])
......
......@@ -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;
})
......@@ -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;
......
......@@ -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;
})
......
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
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.
2012-10-15 Oleg Endo <olegendo@gcc.gnu.org>
PR target/34777
* gcc.target/sh/torture/sh-torture.exp: New.
* gcc.target/sh/torture/pr34777.c: New.
......
/* Check that the GBR address optimization does not combine a gbr store
and its use when a function call is inbetween, when GBR is a call used
register, i.e. it is invalidated by function calls. */
/* { dg-do compile { target "sh*-*-*" } } */
/* { dg-options "-O1 -fcall-used-gbr" } */
/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
/* { dg-final { scan-assembler "stc\tgbr" } } */
extern int test00 (void);
int
test01 (int x)
{
/* We must see a stc gbr,rn before the function call, because
a function call could modify the gbr. In this case the user requests
the old gbr value, before the function call. */
int* p = (int*)__builtin_thread_pointer ();
p[5] = test00 ();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment