===================================================================
@@ -175,6 +175,7 @@
(UNSPECV_WINDOW_END 10)
(UNSPECV_CONST_END 11)
(UNSPECV_EH_RETURN 12)
+ (UNSPECV_GBR 13)
])
;; -------------------------------------------------------------------------
@@ -10029,13 +10030,165 @@
DONE;
})
-(define_insn "load_gbr"
- [(set (match_operand:SI 0 "register_operand" "=r") (reg:SI GBR_REG))
- (use (reg:SI GBR_REG))]
+;;------------------------------------------------------------------------------
+;; Thread pointer getter and setter.
+;;
+;; On SH the thread pointer is kept in the GBR.
+;; These patterns are usually expanded from the respective built-in functions.
+(define_expand "get_thread_pointer"
+ [(set (match_operand:SI 0 "register_operand") (reg:SI GBR_REG))]
+ "TARGET_SH1")
+
+(define_insn "store_gbr"
+ [(set (match_operand:SI 0 "register_operand" "=r") (reg:SI GBR_REG))]
""
"stc gbr,%0"
[(set_attr "type" "tls_load")])
+(define_expand "set_thread_pointer"
+ [(set (reg:SI GBR_REG)
+ (unspec_volatile:SI [(match_operand:SI 0 "register_operand")]
+ UNSPECV_GBR))]
+ "TARGET_SH1")
+
+(define_insn "load_gbr"
+ [(set (reg:SI GBR_REG)
+ (unspec_volatile:SI [(match_operand:SI 0 "register_operand" "r")]
+ UNSPECV_GBR))]
+ "TARGET_SH1"
+ "ldc %0,gbr"
+ [(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
===================================================================
@@ -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;
===================================================================
@@ -153,7 +153,7 @@
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 const char *output_jump_label_table (void);
===================================================================
@@ -243,8 +243,6 @@
static void sh_init_builtins (void);
static tree sh_builtin_decl (unsigned, bool);
-static void sh_media_init_builtins (void);
-static tree sh_media_builtin_decl (unsigned, bool);
static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
static void sh_file_start (void);
@@ -1880,7 +1878,7 @@
case TLS_MODEL_LOCAL_EXEC:
tmp2 = gen_reg_rtx (Pmode);
- emit_insn (gen_load_gbr (tmp2));
+ emit_insn (gen_store_gbr (tmp2));
tmp = gen_reg_rtx (Pmode);
emit_insn (gen_symTPOFF2reg (tmp, op1));
@@ -3603,6 +3601,10 @@
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;
@@ -3611,6 +3613,11 @@
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)
@@ -10178,11 +10185,16 @@
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)
@@ -10195,6 +10207,9 @@
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))
@@ -11501,12 +11516,25 @@
struct builtin_description
{
+ bool (* const is_enabled) (void);
const enum insn_code icode;
const char *const name;
int signature;
tree fndecl;
};
+static bool
+shmedia_builtin (void)
+{
+ return TARGET_SHMEDIA;
+}
+
+static bool
+sh1_builtin (void)
+{
+ return TARGET_SH1;
+}
+
/* describe number and signedness of arguments; arg[0] == result
(1: unsigned, 2: signed, 4: don't care, 8: pointer 0: no argument */
/* 9: 64-bit pointer, 10: 32-bit pointer */
@@ -11564,6 +11592,8 @@
{ 1, 1, 1, 1 },
#define SH_BLTIN_PV 23
{ 0, 8 },
+#define SH_BLTIN_VP 24
+ { 8, 0 }
};
/* mcmv: operands considered unsigned. */
/* mmulsum_wq, msad_ubq: result considered unsigned long long. */
@@ -11573,103 +11603,195 @@
/* nsb: takes long long arg, returns unsigned char. */
static struct builtin_description bdesc[] =
{
- { CODE_FOR_absv2si2, "__builtin_absv2si2", SH_BLTIN_V2SI2, 0 },
- { CODE_FOR_absv4hi2, "__builtin_absv4hi2", SH_BLTIN_V4HI2, 0 },
- { CODE_FOR_addv2si3, "__builtin_addv2si3", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_addv4hi3, "__builtin_addv4hi3", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_ssaddv2si3,"__builtin_ssaddv2si3", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_usaddv8qi3,"__builtin_usaddv8qi3", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_ssaddv4hi3,"__builtin_ssaddv4hi3", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_alloco_i, "__builtin_sh_media_ALLOCO", SH_BLTIN_PV, 0 },
- { CODE_FOR_negcmpeqv8qi,"__builtin_sh_media_MCMPEQ_B", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_negcmpeqv2si,"__builtin_sh_media_MCMPEQ_L", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_negcmpeqv4hi,"__builtin_sh_media_MCMPEQ_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_negcmpgtuv8qi,"__builtin_sh_media_MCMPGT_UB", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_negcmpgtv2si,"__builtin_sh_media_MCMPGT_L", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_negcmpgtv4hi,"__builtin_sh_media_MCMPGT_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_mcmv, "__builtin_sh_media_MCMV", SH_BLTIN_UUUU, 0 },
- { CODE_FOR_mcnvs_lw, "__builtin_sh_media_MCNVS_LW", SH_BLTIN_3, 0 },
- { CODE_FOR_mcnvs_wb, "__builtin_sh_media_MCNVS_WB", SH_BLTIN_V4HI2V8QI, 0 },
- { CODE_FOR_mcnvs_wub, "__builtin_sh_media_MCNVS_WUB", SH_BLTIN_V4HI2V8QI, 0 },
- { CODE_FOR_mextr1, "__builtin_sh_media_MEXTR1", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr2, "__builtin_sh_media_MEXTR2", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr3, "__builtin_sh_media_MEXTR3", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr4, "__builtin_sh_media_MEXTR4", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr5, "__builtin_sh_media_MEXTR5", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr6, "__builtin_sh_media_MEXTR6", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mextr7, "__builtin_sh_media_MEXTR7", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mmacfx_wl, "__builtin_sh_media_MMACFX_WL", SH_BLTIN_MAC_HISI, 0 },
- { CODE_FOR_mmacnfx_wl,"__builtin_sh_media_MMACNFX_WL", SH_BLTIN_MAC_HISI, 0 },
- { CODE_FOR_mulv2si3, "__builtin_mulv2si3", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_mulv4hi3, "__builtin_mulv4hi3", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_mmulfx_l, "__builtin_sh_media_MMULFX_L", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_mmulfx_w, "__builtin_sh_media_MMULFX_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_mmulfxrp_w,"__builtin_sh_media_MMULFXRP_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_mmulhi_wl, "__builtin_sh_media_MMULHI_WL", SH_BLTIN_V4HI2V2SI, 0 },
- { CODE_FOR_mmullo_wl, "__builtin_sh_media_MMULLO_WL", SH_BLTIN_V4HI2V2SI, 0 },
- { CODE_FOR_mmulsum_wq,"__builtin_sh_media_MMULSUM_WQ", SH_BLTIN_XXUU, 0 },
- { CODE_FOR_mperm_w, "__builtin_sh_media_MPERM_W", SH_BLTIN_SH_HI, 0 },
- { CODE_FOR_msad_ubq, "__builtin_sh_media_MSAD_UBQ", SH_BLTIN_XXUU, 0 },
- { CODE_FOR_mshalds_l, "__builtin_sh_media_MSHALDS_L", SH_BLTIN_SH_SI, 0 },
- { CODE_FOR_mshalds_w, "__builtin_sh_media_MSHALDS_W", SH_BLTIN_SH_HI, 0 },
- { CODE_FOR_ashrv2si3, "__builtin_ashrv2si3", SH_BLTIN_SH_SI, 0 },
- { CODE_FOR_ashrv4hi3, "__builtin_ashrv4hi3", SH_BLTIN_SH_HI, 0 },
- { CODE_FOR_mshards_q, "__builtin_sh_media_MSHARDS_Q", SH_BLTIN_SUS, 0 },
- { CODE_FOR_mshfhi_b, "__builtin_sh_media_MSHFHI_B", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mshfhi_l, "__builtin_sh_media_MSHFHI_L", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_mshfhi_w, "__builtin_sh_media_MSHFHI_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_mshflo_b, "__builtin_sh_media_MSHFLO_B", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_mshflo_l, "__builtin_sh_media_MSHFLO_L", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_mshflo_w, "__builtin_sh_media_MSHFLO_W", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_ashlv2si3, "__builtin_ashlv2si3", SH_BLTIN_SH_SI, 0 },
- { CODE_FOR_ashlv4hi3, "__builtin_ashlv4hi3", SH_BLTIN_SH_HI, 0 },
- { CODE_FOR_lshrv2si3, "__builtin_lshrv2si3", SH_BLTIN_SH_SI, 0 },
- { CODE_FOR_lshrv4hi3, "__builtin_lshrv4hi3", SH_BLTIN_SH_HI, 0 },
- { CODE_FOR_subv2si3, "__builtin_subv2si3", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_subv4hi3, "__builtin_subv4hi3", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_sssubv2si3,"__builtin_sssubv2si3", SH_BLTIN_V2SI3, 0 },
- { CODE_FOR_ussubv8qi3,"__builtin_ussubv8qi3", SH_BLTIN_V8QI3, 0 },
- { CODE_FOR_sssubv4hi3,"__builtin_sssubv4hi3", SH_BLTIN_V4HI3, 0 },
- { CODE_FOR_fcosa_s, "__builtin_sh_media_FCOSA_S", SH_BLTIN_SISF, 0 },
- { CODE_FOR_fsina_s, "__builtin_sh_media_FSINA_S", SH_BLTIN_SISF, 0 },
- { CODE_FOR_fipr, "__builtin_sh_media_FIPR_S", SH_BLTIN_3, 0 },
- { CODE_FOR_ftrv, "__builtin_sh_media_FTRV_S", SH_BLTIN_3, 0 },
- { CODE_FOR_sqrtdf2, "__builtin_sh_media_FSQRT_D", SH_BLTIN_2, 0 },
- { CODE_FOR_sqrtsf2, "__builtin_sh_media_FSQRT_S", SH_BLTIN_2, 0 },
- { CODE_FOR_fsrra_s, "__builtin_sh_media_FSRRA_S", SH_BLTIN_2, 0 },
- { CODE_FOR_ldhi_l, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L, 0 },
- { CODE_FOR_ldhi_q, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q, 0 },
- { CODE_FOR_ldlo_l, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L, 0 },
- { CODE_FOR_ldlo_q, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q, 0 },
- { CODE_FOR_sthi_l, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L, 0 },
- { CODE_FOR_sthi_q, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q, 0 },
- { CODE_FOR_stlo_l, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L, 0 },
- { CODE_FOR_stlo_q, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q, 0 },
- { CODE_FOR_ldhi_l64, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L64, 0 },
- { CODE_FOR_ldhi_q64, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q64, 0 },
- { CODE_FOR_ldlo_l64, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L64, 0 },
- { CODE_FOR_ldlo_q64, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q64, 0 },
- { CODE_FOR_sthi_l64, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L64, 0 },
- { CODE_FOR_sthi_q64, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q64, 0 },
- { CODE_FOR_stlo_l64, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L64, 0 },
- { CODE_FOR_stlo_q64, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q64, 0 },
- { CODE_FOR_nsb, "__builtin_sh_media_NSB", SH_BLTIN_SU, 0 },
- { CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 },
- { CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 },
+ { shmedia_builtin,
+ CODE_FOR_absv2si2, "__builtin_absv2si2", SH_BLTIN_V2SI2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_absv4hi2, "__builtin_absv4hi2", SH_BLTIN_V4HI2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_addv2si3, "__builtin_addv2si3", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_addv4hi3, "__builtin_addv4hi3", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ssaddv2si3,"__builtin_ssaddv2si3", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_usaddv8qi3,"__builtin_usaddv8qi3", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ssaddv4hi3,"__builtin_ssaddv4hi3", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_alloco_i, "__builtin_sh_media_ALLOCO", SH_BLTIN_PV, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpeqv8qi,"__builtin_sh_media_MCMPEQ_B", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpeqv2si,"__builtin_sh_media_MCMPEQ_L", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpeqv4hi,"__builtin_sh_media_MCMPEQ_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpgtuv8qi,"__builtin_sh_media_MCMPGT_UB", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpgtv2si,"__builtin_sh_media_MCMPGT_L", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_negcmpgtv4hi,"__builtin_sh_media_MCMPGT_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mcmv, "__builtin_sh_media_MCMV", SH_BLTIN_UUUU, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mcnvs_lw, "__builtin_sh_media_MCNVS_LW", SH_BLTIN_3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mcnvs_wb, "__builtin_sh_media_MCNVS_WB", SH_BLTIN_V4HI2V8QI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mcnvs_wub, "__builtin_sh_media_MCNVS_WUB", SH_BLTIN_V4HI2V8QI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr1, "__builtin_sh_media_MEXTR1", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr2, "__builtin_sh_media_MEXTR2", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr3, "__builtin_sh_media_MEXTR3", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr4, "__builtin_sh_media_MEXTR4", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr5, "__builtin_sh_media_MEXTR5", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr6, "__builtin_sh_media_MEXTR6", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mextr7, "__builtin_sh_media_MEXTR7", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmacfx_wl, "__builtin_sh_media_MMACFX_WL", SH_BLTIN_MAC_HISI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmacnfx_wl,"__builtin_sh_media_MMACNFX_WL", SH_BLTIN_MAC_HISI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mulv2si3, "__builtin_mulv2si3", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mulv4hi3, "__builtin_mulv4hi3", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmulfx_l, "__builtin_sh_media_MMULFX_L", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmulfx_w, "__builtin_sh_media_MMULFX_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmulfxrp_w,"__builtin_sh_media_MMULFXRP_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmulhi_wl, "__builtin_sh_media_MMULHI_WL", SH_BLTIN_V4HI2V2SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmullo_wl, "__builtin_sh_media_MMULLO_WL", SH_BLTIN_V4HI2V2SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mmulsum_wq,"__builtin_sh_media_MMULSUM_WQ", SH_BLTIN_XXUU, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mperm_w, "__builtin_sh_media_MPERM_W", SH_BLTIN_SH_HI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_msad_ubq, "__builtin_sh_media_MSAD_UBQ", SH_BLTIN_XXUU, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshalds_l, "__builtin_sh_media_MSHALDS_L", SH_BLTIN_SH_SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshalds_w, "__builtin_sh_media_MSHALDS_W", SH_BLTIN_SH_HI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ashrv2si3, "__builtin_ashrv2si3", SH_BLTIN_SH_SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ashrv4hi3, "__builtin_ashrv4hi3", SH_BLTIN_SH_HI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshards_q, "__builtin_sh_media_MSHARDS_Q", SH_BLTIN_SUS, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshfhi_b, "__builtin_sh_media_MSHFHI_B", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshfhi_l, "__builtin_sh_media_MSHFHI_L", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshfhi_w, "__builtin_sh_media_MSHFHI_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshflo_b, "__builtin_sh_media_MSHFLO_B", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshflo_l, "__builtin_sh_media_MSHFLO_L", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_mshflo_w, "__builtin_sh_media_MSHFLO_W", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ashlv2si3, "__builtin_ashlv2si3", SH_BLTIN_SH_SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ashlv4hi3, "__builtin_ashlv4hi3", SH_BLTIN_SH_HI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_lshrv2si3, "__builtin_lshrv2si3", SH_BLTIN_SH_SI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_lshrv4hi3, "__builtin_lshrv4hi3", SH_BLTIN_SH_HI, 0 },
+ { shmedia_builtin,
+ CODE_FOR_subv2si3, "__builtin_subv2si3", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_subv4hi3, "__builtin_subv4hi3", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sssubv2si3,"__builtin_sssubv2si3", SH_BLTIN_V2SI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ussubv8qi3,"__builtin_ussubv8qi3", SH_BLTIN_V8QI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sssubv4hi3,"__builtin_sssubv4hi3", SH_BLTIN_V4HI3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_fcosa_s, "__builtin_sh_media_FCOSA_S", SH_BLTIN_SISF, 0 },
+ { shmedia_builtin,
+ CODE_FOR_fsina_s, "__builtin_sh_media_FSINA_S", SH_BLTIN_SISF, 0 },
+ { shmedia_builtin,
+ CODE_FOR_fipr, "__builtin_sh_media_FIPR_S", SH_BLTIN_3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ftrv, "__builtin_sh_media_FTRV_S", SH_BLTIN_3, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sqrtdf2, "__builtin_sh_media_FSQRT_D", SH_BLTIN_2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sqrtsf2, "__builtin_sh_media_FSQRT_S", SH_BLTIN_2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_fsrra_s, "__builtin_sh_media_FSRRA_S", SH_BLTIN_2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldhi_l, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldhi_q, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldlo_l, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldlo_q, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sthi_l, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sthi_q, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q, 0 },
+ { shmedia_builtin,
+ CODE_FOR_stlo_l, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L, 0 },
+ { shmedia_builtin,
+ CODE_FOR_stlo_q, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldhi_l64, "__builtin_sh_media_LDHI_L", SH_BLTIN_LDUA_L64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldhi_q64, "__builtin_sh_media_LDHI_Q", SH_BLTIN_LDUA_Q64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldlo_l64, "__builtin_sh_media_LDLO_L", SH_BLTIN_LDUA_L64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_ldlo_q64, "__builtin_sh_media_LDLO_Q", SH_BLTIN_LDUA_Q64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sthi_l64, "__builtin_sh_media_STHI_L", SH_BLTIN_STUA_L64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_sthi_q64, "__builtin_sh_media_STHI_Q", SH_BLTIN_STUA_Q64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_stlo_l64, "__builtin_sh_media_STLO_L", SH_BLTIN_STUA_L64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_stlo_q64, "__builtin_sh_media_STLO_Q", SH_BLTIN_STUA_Q64, 0 },
+ { shmedia_builtin,
+ CODE_FOR_nsb, "__builtin_sh_media_NSB", SH_BLTIN_SU, 0 },
+ { shmedia_builtin,
+ CODE_FOR_byterev, "__builtin_sh_media_BYTEREV", SH_BLTIN_2, 0 },
+ { shmedia_builtin,
+ CODE_FOR_prefetch, "__builtin_sh_media_PREFO", SH_BLTIN_PSSV, 0 },
+
+ { sh1_builtin,
+ CODE_FOR_get_thread_pointer, "__builtin_thread_pointer", SH_BLTIN_VP, 0 },
+ { sh1_builtin,
+ CODE_FOR_set_thread_pointer, "__builtin_set_thread_pointer",
+ SH_BLTIN_PV, 0 },
};
static void
-sh_media_init_builtins (void)
+sh_init_builtins (void)
{
tree shared[SH_BLTIN_NUM_SHARED_SIGNATURES];
- struct builtin_description *d;
+ memset (shared, 0, sizeof shared);
- memset (shared, 0, sizeof shared);
- for (d = bdesc; d - bdesc < (int) ARRAY_SIZE (bdesc); d++)
+ for (unsigned int di = 0; di < ARRAY_SIZE (bdesc); ++di)
{
- tree type, arg_type = 0;
+ builtin_description* d = &bdesc[di];
+
+ if (!d->is_enabled ())
+ continue;
+
+ tree type, arg_type = NULL_TREE;
int signature = d->signature;
- int i;
if (signature < SH_BLTIN_NUM_SHARED_SIGNATURES && shared[signature])
type = shared[signature];
@@ -11685,9 +11807,9 @@
if (! TARGET_FPU_ANY
&& FLOAT_MODE_P (insn_data[d->icode].operand[0].mode))
continue;
- for (i = 0; i < (int) ARRAY_SIZE (args); i++)
+ for (int i = 0; i < (int) ARRAY_SIZE (args); i++)
args[i] = NULL_TREE;
- for (i = 3; ; i--)
+ for (int i = 3; ; i--)
{
int arg = signature_args[signature][i];
int opno = i - 1 + has_result;
@@ -11696,8 +11818,7 @@
arg_type = ptr_type_node;
else if (arg)
arg_type = (*lang_hooks.types.type_for_mode)
- (insn_data[d->icode].operand[opno].mode,
- (arg & 1));
+ (insn_data[d->icode].operand[opno].mode, (arg & 1));
else if (i)
continue;
else
@@ -11717,17 +11838,6 @@
}
}
-/* Returns the shmedia builtin decl for CODE. */
-
-static tree
-sh_media_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
-{
- if (code >= ARRAY_SIZE (bdesc))
- return error_mark_node;
-
- return bdesc[code].fndecl;
-}
-
/* Implements target hook vector_mode_supported_p. */
bool
sh_vector_mode_supported_p (enum machine_mode mode)
@@ -11773,22 +11883,18 @@
return DW_CC_normal;
}
-static void
-sh_init_builtins (void)
-{
- if (TARGET_SHMEDIA)
- sh_media_init_builtins ();
-}
-
/* Returns the sh builtin decl for CODE. */
static tree
sh_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED)
-{
- if (TARGET_SHMEDIA)
- return sh_media_builtin_decl (code, initialize_p);
-
- return error_mark_node;
+{
+ if (code >= ARRAY_SIZE (bdesc))
+ return error_mark_node;
+
+ if (!bdesc[code].is_enabled ())
+ return error_mark_node;
+
+ return bdesc[code].fndecl;
}
/* Expand an expression EXP that calls a built-in function,
@@ -11806,27 +11912,24 @@
const struct builtin_description *d = &bdesc[fcode];
enum insn_code icode = d->icode;
int signature = d->signature;
- enum machine_mode tmode = VOIDmode;
- int nop = 0, i;
+ int nop = 0;
rtx op[4];
- rtx pat = NULL_RTX;
if (signature_args[signature][0])
{
if (ignore)
return NULL_RTX;
- tmode = insn_data[icode].operand[0].mode;
- if (! target
- || GET_MODE (target) != tmode
+ enum machine_mode tmode = insn_data[icode].operand[0].mode;
+ if (! target || GET_MODE (target) != tmode
|| ! (*insn_data[icode].operand[0].predicate) (target, tmode))
target = gen_reg_rtx (tmode);
op[nop++] = target;
}
else
- target = 0;
+ target = NULL_RTX;
- for (i = 1; i <= 3; i++, nop++)
+ for (int i = 1; i <= 3; i++, nop++)
{
tree arg;
enum machine_mode opmode, argmode;
@@ -11855,6 +11958,8 @@
op[nop] = copy_to_mode_reg (opmode, op[nop]);
}
+ rtx pat = NULL_RTX;
+
switch (nop)
{
case 1:
@@ -12917,6 +13022,17 @@
{
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)
@@ -13143,7 +13259,149 @@
return false;
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))
+ {
+ 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"
===================================================================
@@ -0,0 +1,20 @@
+/* Check that the __builtin_thread_pointer and __builtin_set_thread_pointer
+ built-in functions result in gbr store / load instructions. */
+/* { dg-do compile { target "sh*-*-*" } } */
+/* { dg-options "-O1" } */
+/* { dg-skip-if "" { "sh*-*-*" } { "-m5*"} { "" } } */
+/* { dg-final { scan-assembler-times "ldc" 1 } } */
+/* { dg-final { scan-assembler-times "stc" 1 } } */
+/* { dg-final { scan-assembler-times "gbr" 2 } } */
+
+void*
+test00 (void)
+{
+ return __builtin_thread_pointer ();
+}
+
+void
+test01 (void* p)
+{
+ __builtin_set_thread_pointer (p);
+}
===================================================================
@@ -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;
+}
===================================================================
@@ -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)