diff options
author | Oleg Endo <olegendo@gcc.gnu.org> | 2012-10-08 02:00:46 +0000 |
---|---|---|
committer | Oleg Endo <olegendo@gcc.gnu.org> | 2012-10-08 02:00:46 +0000 |
commit | fce1e5fb8f22c020935ab99b9a05e55ed4a89c78 (patch) | |
tree | a07109dc211baaa3ed5080642628c9d5d4ceba88 | |
parent | 7f7b06c14f2c60b092cf254c94490cfb35211135 (diff) | |
download | gcc-fce1e5fb8f22c020935ab99b9a05e55ed4a89c78.zip gcc-fce1e5fb8f22c020935ab99b9a05e55ed4a89c78.tar.gz gcc-fce1e5fb8f22c020935ab99b9a05e55ed4a89c78.tar.bz2 |
re PR target/54760 ([SH] Add __builtin_thread_pointer, __builtin_set_thread_pointer)
PR target/54760
* config/sh/sh.md (*mov<mode>_gbr_load, *mov<mode>_gbr_store): New
insns and accompanying unnamed splits.
* config/sh/predicates.md (general_movsrc_operand,
general_movdst_operand): Reject GBR addresses.
* config/sh/sh-protos.h (sh_find_equiv_gbr_addr): New declaration.
* config/sh/sh.c (sh_address_cost, sh_legitimate_address_p,
sh_secondary_reload): Handle GBR addresses.
(base_reg_disp): New class.
(sh_find_base_reg_disp, sh_find_equiv_gbr_addr): New functions.
PR target/54760
* gcc.target/sh/pr54760-2.c: New.
* gcc.target/sh/pr54760-3.c: New.
From-SVN: r192193
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/config/sh/predicates.md | 19 | ||||
-rw-r--r-- | gcc/config/sh/sh-protos.h | 2 | ||||
-rw-r--r-- | gcc/config/sh/sh.c | 176 | ||||
-rw-r--r-- | gcc/config/sh/sh.md | 129 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr54760-2.c | 223 | ||||
-rw-r--r-- | gcc/testsuite/gcc.target/sh/pr54760-3.c | 69 |
8 files changed, 635 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 8f944d7..7fcb167 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,16 @@ +2012-10-08 Oleg Endo <olegendo@gcc.gnu.org> + + PR target/54760 + * config/sh/sh.md (*mov<mode>_gbr_load, *mov<mode>_gbr_store): New + insns and accompanying unnamed splits. + * config/sh/predicates.md (general_movsrc_operand, + general_movdst_operand): Reject GBR addresses. + * config/sh/sh-protos.h (sh_find_equiv_gbr_addr): New declaration. + * config/sh/sh.c (sh_address_cost, sh_legitimate_address_p, + sh_secondary_reload): Handle GBR addresses. + (base_reg_disp): New class. + (sh_find_base_reg_disp, sh_find_equiv_gbr_addr): New functions. + 2012-10-08 Hans-Peter Nilsson <hp@bitrange.com> * config/mmix/mmix.c (mmix_output_octa): Don't assume diff --git a/gcc/config/sh/predicates.md b/gcc/config/sh/predicates.md index 05ad858..89b4d0f 100644 --- a/gcc/config/sh/predicates.md +++ b/gcc/config/sh/predicates.md @@ -409,6 +409,14 @@ if (MEM_P (op)) { rtx inside = XEXP (op, 0); + + /* Disallow mems with GBR address here. They have to go through + separate special patterns. */ + if ((REG_P (inside) && REGNO (inside) == GBR_REG) + || (GET_CODE (inside) == PLUS && REG_P (XEXP (inside, 0)) + && REGNO (XEXP (inside, 0)) == GBR_REG)) + return 0; + if (GET_CODE (inside) == CONST) inside = XEXP (inside, 0); @@ -466,6 +474,17 @@ if (t_reg_operand (op, mode)) return 0; + if (MEM_P (op)) + { + rtx inside = XEXP (op, 0); + /* Disallow mems with GBR address here. They have to go through + separate special patterns. */ + if ((REG_P (inside) && REGNO (inside) == GBR_REG) + || (GET_CODE (inside) == PLUS && REG_P (XEXP (inside, 0)) + && REGNO (XEXP (inside, 0)) == GBR_REG)) + return 0; + } + /* Only pre dec allowed. */ if (MEM_P (op) && GET_CODE (XEXP (op, 0)) == POST_INC) return 0; diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index d908110..61d4eab 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -161,7 +161,7 @@ extern bool sh_vector_mode_supported_p (enum machine_mode); extern bool sh_cfun_trap_exit_p (void); extern void sh_canonicalize_comparison (enum rtx_code&, rtx&, rtx&, enum machine_mode mode = VOIDmode); - +extern rtx sh_find_equiv_gbr_addr (rtx cur_insn, rtx mem); #endif /* RTX_CODE */ extern void sh_cpu_cpp_builtins (cpp_reader* pfile); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 3a0689d..d1ab28a 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -3610,6 +3610,10 @@ static int sh_address_cost (rtx x, enum machine_mode mode, addr_space_t as ATTRIBUTE_UNUSED, bool speed ATTRIBUTE_UNUSED) { + /* 'GBR + 0'. Account one more because of R0 restriction. */ + if (REG_P (x) && REGNO (x) == GBR_REG) + return 2; + /* Simple reg, post-inc, pre-dec addressing. */ if (REG_P (x) || GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) return 1; @@ -3618,6 +3622,11 @@ sh_address_cost (rtx x, enum machine_mode mode, if (GET_CODE (x) == PLUS && REG_P (XEXP (x, 0)) && CONST_INT_P (XEXP (x, 1))) { + /* 'GBR + disp'. Account one more because of R0 restriction. */ + if (REGNO (XEXP (x, 0)) == GBR_REG + && gbr_displacement (XEXP (x, 1), mode)) + return 2; + const HOST_WIDE_INT offset = INTVAL (XEXP (x, 1)); if (offset == 0) @@ -10185,11 +10194,16 @@ sh_legitimate_index_p (enum machine_mode mode, rtx op, bool consider_sh2a, REG+disp REG+r0 REG++ - --REG */ + --REG + GBR + GBR+disp */ static bool sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) { + if (REG_P (x) && REGNO (x) == GBR_REG) + return true; + if (MAYBE_BASE_REGISTER_RTX_P (x, strict)) return true; else if ((GET_CODE (x) == POST_INC || GET_CODE (x) == PRE_DEC) @@ -10202,6 +10216,9 @@ sh_legitimate_address_p (enum machine_mode mode, rtx x, bool strict) rtx xop0 = XEXP (x, 0); rtx xop1 = XEXP (x, 1); + if (REG_P (xop0) && REGNO (xop0) == GBR_REG) + return gbr_displacement (xop1, mode); + if (GET_MODE_SIZE (mode) <= 8 && MAYBE_BASE_REGISTER_RTX_P (xop0, strict) && sh_legitimate_index_p (mode, xop1, TARGET_SH2A, false)) @@ -13014,6 +13031,17 @@ sh_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i, { enum reg_class rclass = (enum reg_class) rclass_i; + if (MEM_P (x) && GET_CODE (XEXP (x, 0)) == PLUS + && REG_P (XEXP (XEXP (x, 0), 0)) + && REGNO (XEXP (XEXP (x, 0), 0)) == GBR_REG) + return rclass == R0_REGS ? NO_REGS : R0_REGS; + + if (MEM_P (x) && REG_P (XEXP (x, 0)) && REGNO (XEXP (x, 0)) == GBR_REG) + return rclass == R0_REGS ? NO_REGS : R0_REGS; + + if (REG_P (x) && REGNO (x) == GBR_REG) + return NO_REGS; + if (in_p) { if (REGCLASS_HAS_FP_REG (rclass) @@ -13248,4 +13276,150 @@ sh_can_use_simple_return_p (void) return true; } +/*------------------------------------------------------------------------------ + Address mode optimization support code +*/ + +typedef HOST_WIDE_INT disp_t; +static const disp_t MIN_DISP = HOST_WIDE_INT_MIN; +static const disp_t MAX_DISP = HOST_WIDE_INT_MAX; +static const disp_t INVALID_DISP = MAX_DISP; + +/* A memory reference which is described by a base register and a + displacement. */ +class base_reg_disp +{ +public: + base_reg_disp (rtx br, disp_t d); + + bool is_reg (void) const; + bool is_disp (void) const; + rtx reg (void) const; + disp_t disp (void) const; + +private: + rtx reg_; + disp_t disp_; +}; + +inline +base_reg_disp::base_reg_disp (rtx br, disp_t d) +: reg_ (br), disp_ (d) +{ +} + +inline bool +base_reg_disp::is_reg (void) const +{ + return reg_ != NULL_RTX && disp_ != INVALID_DISP; +} + +inline bool +base_reg_disp::is_disp (void) const +{ + return reg_ == NULL_RTX && disp_ != INVALID_DISP; +} + +inline rtx +base_reg_disp::reg (void) const +{ + return reg_; +} + +inline disp_t +base_reg_disp::disp (void) const +{ + return disp_; +} + +/* Find the base register and calculate the displacement for a given + address rtx 'x'. + This is done by walking the insn list backwards and following SET insns + that set the value of the specified reg 'x'. */ +static base_reg_disp +sh_find_base_reg_disp (rtx insn, rtx x, disp_t disp = 0, rtx base_reg = NULL) +{ + if (REG_P (x)) + { + if (REGNO (x) == GBR_REG) + return base_reg_disp (x, disp); + + /* We've reached a hard-reg. This is probably the point where + function args are copied to pseudos. Do not go any further and + stick to the pseudo. If the original mem addr was in a hard reg + from the beginning, it will become the base reg. */ + if (REGNO (x) < FIRST_PSEUDO_REGISTER) + return base_reg_disp (base_reg != NULL ? base_reg : x, disp); + + /* Try to find the previous insn that sets the reg. */ + for (rtx i = prev_nonnote_insn (insn); i != NULL; + i = prev_nonnote_insn (i)) + { + if (!NONJUMP_INSN_P (i)) + continue; + + rtx p = PATTERN (i); + if (p != NULL && GET_CODE (p) == SET && REG_P (XEXP (p, 0)) + && REGNO (XEXP (p, 0)) == REGNO (x)) + { + /* If the recursion can't find out any more details about the + source of the set, then this reg becomes our new base reg. */ + return sh_find_base_reg_disp (i, XEXP (p, 1), disp, XEXP (p, 0)); + } + } + + /* When here, no previous insn was found that sets the reg. + The input reg is already the base reg. */ + return base_reg_disp (x, disp); + } + + else if (GET_CODE (x) == PLUS) + { + base_reg_disp left_val = sh_find_base_reg_disp (insn, XEXP (x, 0)); + base_reg_disp right_val = sh_find_base_reg_disp (insn, XEXP (x, 1)); + + /* Either left or right val must be a reg. + We don't handle the case of 'reg + reg' here. */ + if (left_val.is_reg () && right_val.is_disp ()) + return base_reg_disp (left_val.reg (), left_val.disp () + + right_val.disp () + disp); + else if (right_val.is_reg () && left_val.is_disp ()) + return base_reg_disp (right_val.reg (), right_val.disp () + + left_val.disp () + disp); + else + return base_reg_disp (base_reg, disp); + } + + else if (CONST_INT_P (x)) + return base_reg_disp (NULL, disp + INTVAL (x)); + + /* Didn't find anything useful. */ + return base_reg_disp (base_reg, disp); +} + +/* Given an insn and a memory operand, try to find an equivalent GBR + based memory address and return the corresponding new memory address. + Return NULL_RTX if not found. */ +rtx +sh_find_equiv_gbr_addr (rtx insn, rtx mem) +{ + if (!MEM_P (mem)) + return NULL_RTX; + + /* Leave post/pre inc/dec or any other side effect addresses alone. */ + if (side_effects_p (XEXP (mem, 0))) + return NULL_RTX; + + base_reg_disp gbr_disp = sh_find_base_reg_disp (insn, XEXP (mem, 0)); + + if (gbr_disp.is_reg () && REGNO (gbr_disp.reg ()) == GBR_REG) + { + rtx disp = GEN_INT (gbr_disp.disp ()); + if (gbr_displacement (disp, GET_MODE (mem))) + return gen_rtx_PLUS (SImode, gen_rtx_REG (SImode, GBR_REG), disp); + } + + return NULL_RTX; +} + #include "gt-sh.h" diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index eeed561..989d52e 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -10061,6 +10061,135 @@ label: [(set_attr "type" "move")]) ;;------------------------------------------------------------------------------ +;; Thread pointer relative memory loads and stores. +;; +;; On SH there are GBR displacement address modes which can be utilized to +;; access memory behind the thread pointer. +;; Since we do not allow using GBR for general purpose memory accesses, these +;; GBR addressing modes are formed by the combine pass. +;; This could be done with fewer patterns than below by using a mem predicate +;; for the GBR mem, but then reload would try to reload addresses with a +;; zero displacement for some strange reason. + +(define_insn "*mov<mode>_gbr_load" + [(set (match_operand:QIHISI 0 "register_operand" "=z") + (mem:QIHISI (plus:SI (reg:SI GBR_REG) + (match_operand:QIHISI 1 "gbr_displacement"))))] + "TARGET_SH1" + "mov.<bwl> @(%O1,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov<mode>_gbr_load" + [(set (match_operand:QIHISI 0 "register_operand" "=z") + (mem:QIHISI (reg:SI GBR_REG)))] + "TARGET_SH1" + "mov.<bwl> @(0,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov<mode>_gbr_load" + [(set (match_operand:SI 0 "register_operand" "=z") + (sign_extend:SI + (mem:QIHI (plus:SI (reg:SI GBR_REG) + (match_operand:QIHI 1 "gbr_displacement")))))] + "TARGET_SH1" + "mov.<bw> @(%O1,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov<mode>_gbr_load" + [(set (match_operand:SI 0 "register_operand" "=z") + (sign_extend:SI (mem:QIHI (reg:SI GBR_REG))))] + "TARGET_SH1" + "mov.<bw> @(0,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov<mode>_gbr_store" + [(set (mem:QIHISI (plus:SI (reg:SI GBR_REG) + (match_operand:QIHISI 0 "gbr_displacement"))) + (match_operand:QIHISI 1 "register_operand" "z"))] + "TARGET_SH1" + "mov.<bwl> %1,@(%O0,gbr)" + [(set_attr "type" "store")]) + +(define_insn "*mov<mode>_gbr_store" + [(set (mem:QIHISI (reg:SI GBR_REG)) + (match_operand:QIHISI 0 "register_operand" "z"))] + "TARGET_SH1" + "mov.<bwl> %0,@(0,gbr)" + [(set_attr "type" "store")]) + +;; 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 +;; for missed opportunities and try to fix them up ourselves. +;; If an equivalent GBR address can be determined the load / store is split +;; into one of the GBR load / store patterns. +;; All of that must happen before reload (GBR address modes use R0 as the +;; 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"))] + "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); + else + FAIL; +}) + +(define_split + [(set (match_operand:SI 0 "register_operand") + (sign_extend:SI (match_operand:QIHI 1 "memory_operand")))] + "TARGET_SH1 && !reload_in_progress && !reload_completed + && df_regs_ever_live_p (GBR_REG)" + [(set (match_dup 0) (sign_extend:SI (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); + else + FAIL; +}) + +;; On SH2A we've got movu.b and movu.w for doing zero-extending mem loads. +;; Split those so that a GBR load can be used. +(define_split + [(set (match_operand:SI 0 "register_operand") + (zero_extend:SI (match_operand:QIHI 1 "memory_operand")))] + "TARGET_SH2A && !reload_in_progress && !reload_completed + && df_regs_ever_live_p (GBR_REG)" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (zero_extend:SI (match_dup 2)))] +{ + rtx gbr_mem = sh_find_equiv_gbr_addr (curr_insn, operands[1]); + 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); + } + else + FAIL; +}) + +(define_split + [(set (match_operand:QIHISI 0 "memory_operand") + (match_operand:QIHISI 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); + else + FAIL; +}) + +;;------------------------------------------------------------------------------ ;; case instruction for switch statements. ;; Operand 0 is index diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index a1c4a32..5eb6c6d 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2012-10-08 Oleg Endo <olegendo@gcc.gnu.org> + + PR target/54760 + * gcc.target/sh/pr54760-2.c: New. + * gcc.target/sh/pr54760-3.c: New. + 2012-10-07 Paolo Carlini <paolo.carlini@oracle.com> PR c++/51422 diff --git a/gcc/testsuite/gcc.target/sh/pr54760-2.c b/gcc/testsuite/gcc.target/sh/pr54760-2.c new file mode 100644 index 0000000..b8a5018 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54760-2.c @@ -0,0 +1,223 @@ +/* Check that thread pointer relative memory accesses are converted to + gbr displacement address modes. If we see a gbr register store + instruction something is not working properly. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ +/* { dg-final { scan-assembler-times "stc\tgbr" 0 } } */ + +/* --------------------------------------------------------------------------- + Simple GBR load. +*/ +#define func(name, type, disp)\ + int \ + name ## _tp_load (void) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + return tp[disp]; \ + } + +func (test00, int, 0) +func (test01, int, 5) +func (test02, int, 255) + +func (test03, short, 0) +func (test04, short, 5) +func (test05, short, 255) + +func (test06, char, 0) +func (test07, char, 5) +func (test08, char, 255) + +func (test09, unsigned int, 0) +func (test10, unsigned int, 5) +func (test11, unsigned int, 255) + +func (test12, unsigned short, 0) +func (test13, unsigned short, 5) +func (test14, unsigned short, 255) + +func (test15, unsigned char, 0) +func (test16, unsigned char, 5) +func (test17, unsigned char, 255) + +#undef func + +/* --------------------------------------------------------------------------- + Simple GBR store. +*/ +#define func(name, type, disp)\ + void \ + name ## _tp_store (int a) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + tp[disp] = (type)a; \ + } + +func (test00, int, 0) +func (test01, int, 5) +func (test02, int, 255) + +func (test03, short, 0) +func (test04, short, 5) +func (test05, short, 255) + +func (test06, char, 0) +func (test07, char, 5) +func (test08, char, 255) + +func (test09, unsigned int, 0) +func (test10, unsigned int, 5) +func (test11, unsigned int, 255) + +func (test12, unsigned short, 0) +func (test13, unsigned short, 5) +func (test14, unsigned short, 255) + +func (test15, unsigned char, 0) +func (test16, unsigned char, 5) +func (test17, unsigned char, 255) + +#undef func + +/* --------------------------------------------------------------------------- + Arithmetic on the result of a GBR load. +*/ +#define func(name, type, disp, op, opname)\ + int \ + name ## _tp_load_arith_ ##opname (int a) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + return tp[disp] op a; \ + } + +#define funcs(op, opname) \ + func (test00, int, 0, op, opname) \ + func (test01, int, 5, op, opname) \ + func (test02, int, 255, op, opname) \ + func (test03, short, 0, op, opname) \ + func (test04, short, 5, op, opname) \ + func (test05, short, 255, op, opname) \ + func (test06, char, 0, op, opname) \ + func (test07, char, 5, op, opname) \ + func (test08, char, 255, op, opname) \ + func (test09, unsigned int, 0, op, opname) \ + func (test10, unsigned int, 5, op, opname) \ + func (test11, unsigned int, 255, op, opname) \ + func (test12, unsigned short, 0, op, opname) \ + func (test13, unsigned short, 5, op, opname) \ + func (test14, unsigned short, 255, op, opname) \ + func (test15, unsigned char, 0, op, opname) \ + func (test16, unsigned char, 5, op, opname) \ + func (test17, unsigned char, 255, op, opname) \ + +funcs (+, plus) +funcs (-, minus) +funcs (*, mul) +funcs (&, and) +funcs (|, or) +funcs (^, xor) + +#undef funcs +#undef func + +/* --------------------------------------------------------------------------- + Arithmetic of the result of two GBR loads. +*/ +#define func(name, type, disp0, disp1, op, opname)\ + int \ + name ## _tp_load_load_arith_ ##opname (void) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + return tp[disp0] op tp[disp1]; \ + } + +#define funcs(op, opname) \ + func (test00, int, 0, 5, op, opname) \ + func (test02, int, 1, 255, op, opname) \ + func (test03, short, 0, 5, op, opname) \ + func (test05, short, 1, 255, op, opname) \ + func (test06, char, 0, 5, op, opname) \ + func (test08, char, 1, 255, op, opname) \ + func (test09, unsigned int, 0, 5, op, opname) \ + func (test11, unsigned int, 1, 255, op, opname) \ + func (test12, unsigned short, 0, 5, op, opname) \ + func (test14, unsigned short, 1, 255, op, opname) \ + func (test15, unsigned char, 0, 5, op, opname) \ + func (test17, unsigned char, 1, 255, op, opname) \ + +funcs (+, plus) +funcs (-, minus) +funcs (*, mul) +funcs (&, and) +funcs (|, or) +funcs (^, xor) + +#undef funcs +#undef func + +/* --------------------------------------------------------------------------- + GBR load GBR store copy. +*/ + +#define func(name, type, disp0, disp1)\ + void \ + name ## _tp_copy (void) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + tp[disp0] = tp[disp1]; \ + } + +func (test00, int, 0, 5) +func (test02, int, 1, 255) +func (test03, short, 0, 5) +func (test05, short, 1, 255) +func (test06, char, 0, 5) +func (test08, char, 1, 255) +func (test09, unsigned int, 0, 5) +func (test11, unsigned int, 1, 255) +func (test12, unsigned short, 0, 5) +func (test14, unsigned short, 1, 255) +func (test15, unsigned char, 0, 5) +func (test17, unsigned char, 1, 255) + +#undef func + +/* --------------------------------------------------------------------------- + GBR load, arithmetic, GBR store +*/ + +#define func(name, type, disp, op, opname)\ + void \ + name ## _tp_load_arith_store_ ##opname (int a) \ + { \ + type* tp = (type*)__builtin_thread_pointer (); \ + tp[disp] op a; \ + } + +#define funcs(op, opname) \ + func (test00, int, 0, op, opname) \ + func (test01, int, 5, op, opname) \ + func (test02, int, 255, op, opname) \ + func (test03, short, 0, op, opname) \ + func (test04, short, 5, op, opname) \ + func (test05, short, 255, op, opname) \ + func (test06, char, 0, op, opname) \ + func (test07, char, 5, op, opname) \ + func (test08, char, 255, op, opname) \ + func (test09, unsigned int, 0, op, opname) \ + func (test10, unsigned int, 5, op, opname) \ + func (test11, unsigned int, 255, op, opname) \ + func (test12, unsigned short, 0, op, opname) \ + func (test13, unsigned short, 5, op, opname) \ + func (test14, unsigned short, 255, op, opname) \ + func (test15, unsigned char, 0, op, opname) \ + func (test16, unsigned char, 5, op, opname) \ + func (test17, unsigned char, 255, op, opname) \ + +funcs (+=, plus) +funcs (-=, minus) +funcs (*=, mul) +funcs (&=, and) +funcs (|=, or) +funcs (^=, xor) diff --git a/gcc/testsuite/gcc.target/sh/pr54760-3.c b/gcc/testsuite/gcc.target/sh/pr54760-3.c new file mode 100644 index 0000000..2b6f186 --- /dev/null +++ b/gcc/testsuite/gcc.target/sh/pr54760-3.c @@ -0,0 +1,69 @@ +/* Check that these thread relative memory accesses play along with + surrounding code. + These should be moved to C torture tests once there are target + independent thread_pointer built-in functions available. */ +/* { dg-do compile { target "sh*-*-*" } } */ +/* { dg-options "-O1" } */ +/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */ + +int +test00 (void* p, int x) +{ + int* tcb = (int*)__builtin_thread_pointer (); + int r = tcb[4]; + + __builtin_set_thread_pointer (p); + + tcb = (int*)__builtin_thread_pointer (); + return tcb[255] + r; +} + +int +test01 (void) +{ + unsigned short* tcb = (unsigned short*)__builtin_thread_pointer (); + return tcb[500]; +} + +void +test02 (int* x, int a, int b) +{ + int* tcb = (int*)__builtin_thread_pointer (); + tcb[50] = a; + + __builtin_set_thread_pointer (x); + + tcb = (int*)__builtin_thread_pointer (); + tcb[40] = b; +} + +int +test03 (const int* x, int c) +{ + volatile int* tcb = (volatile int*)__builtin_thread_pointer (); + + int s = 0; + int i; + for (i = 0; i < c; ++i) + s ^= x[i] + tcb[40]; + + return s; +} + +int +test04 (const int* x, int c, int** xx, int d) +{ + int s = 0; + int i; + for (i = 0; i < c; ++i) + { + volatile int* tcb = (volatile int*)__builtin_thread_pointer (); + tcb[20] = s; + + __builtin_set_thread_pointer (xx[i]); + + tcb = (volatile int*)__builtin_thread_pointer (); + s ^= x[i] + tcb[40] + d; + } + return s; +} |