From patchwork Wed Oct 3 21:31:08 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Oleg Endo X-Patchwork-Id: 188933 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id E08832C031D for ; Thu, 4 Oct 2012 07:31:41 +1000 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1349904702; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Message-ID:Subject:From:To:Date:In-Reply-To:References: Content-Type:Mime-Version:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=K0LfRpuw6y1Q3v+9xQYQ3yjrIOY=; b=flSHyaCEpSCLIn4 mGkT+atYxlGVY8HHQa5Wb1mdebJAYUMwBvgfM7VuPg+DuLLzSVjWYsditx2qyoTZ pVfX21f7KdabTrDs8Knwfm9uHf5Kbhc3jUlGBu3rGVd7ND6IrResYpWTKgMf/sBk 33qs6yiRG/yHlKQ6hhf5Ny+AWWHo= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:Received:Message-ID:Subject:From:To:Date:In-Reply-To:References:Content-Type:Mime-Version:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=Ghll9atrw+ZVuN2nGPdqT4GidKp3oBIOtU/g67px1rtHRSPyQuJhm59DsnLvKN eyJSLswpUhnCj4pEZrtkK9sl9XYstovqChpEPMlmB300tB+fkmq5UOVJ6FfSYye3 kXeAh3ImJz6j7fLul7sqMGzfeOqIup/QT9fV8jW8zwmaI=; Received: (qmail 11649 invoked by alias); 3 Oct 2012 21:31:35 -0000 Received: (qmail 11628 invoked by uid 22791); 3 Oct 2012 21:31:31 -0000 X-SWARE-Spam-Status: No, hits=-4.0 required=5.0 tests=AWL, BAYES_00, KHOP_THREADED, RCVD_IN_DNSWL_NONE, RCVD_IN_HOSTKARMA_NO, RCVD_IN_HOSTKARMA_YE, RP_MATCHES_RCVD, UNPARSEABLE_RELAY X-Spam-Check-By: sourceware.org Received: from mailout02.t-online.de (HELO mailout02.t-online.de) (194.25.134.17) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Wed, 03 Oct 2012 21:31:21 +0000 Received: from fwd04.aul.t-online.de (fwd04.aul.t-online.de ) by mailout02.t-online.de with smtp id 1TJWXG-0006WU-AZ; Wed, 03 Oct 2012 23:31:18 +0200 Received: from [192.168.0.100] (rSiCr4ZYrhryCvgQBO5Vj4iVB6wWAqxwlzkBgeOewMuDs0HF14HrG9tXpgDgcm8g7w@[87.157.32.59]) by fwd04.t-online.de with esmtp id 1TJWX8-0oXyOe0; Wed, 3 Oct 2012 23:31:10 +0200 Message-ID: <1349299868.9306.128.camel@yam-132-YW-E178-FTW> Subject: Re: [SH] PR 54760 - Add thread pointer built-ins and GBR displacement addressing From: Oleg Endo To: gcc-patches Date: Wed, 03 Oct 2012 23:31:08 +0200 In-Reply-To: <1349299299.9306.124.camel@yam-132-YW-E178-FTW> References: <1349299299.9306.124.camel@yam-132-YW-E178-FTW> Mime-Version: 1.0 X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org On Wed, 2012-10-03 at 23:21 +0200, Oleg Endo wrote: > testsuite/ChangeLog: > > PR target/54760 > * gcc.target/sh/pr54706-1.c: New. > * gcc.target/sh/pr54706-2.c: New. > * gcc.target/sh/pr54706-3.c: New. Obviously there is a typo in the file names for the test cases. Attached is the corrected patch + changelog. Cheers, Oleg gcc/ChangeLog: PR target/54760 * config/sh/sh.md (define_constants): Add UNSPECV_GBR. (get_thread_pointer, set_thread_pointer): New expanders. (load_gbr): Rename to store_gbr. Remove GBR_REG use. (store_gbr): New insn. (*mov_gbr_load, *mov_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 (prepare_move_operands): Use gen_store_gbr instead of gen_load_gbr in TLS_MODEL_LOCAL_EXEC case. (sh_address_cost, sh_legitimate_address_p, sh_secondary_reload): Handle GBR addresses. (builtin_description): Add is_enabled member. (shmedia_builtin, sh1_builtin): New functions. (signature_args): Add SH_BLTIN_VP. (bdesc): Use shmedia_builtin for existing built-ins. Add __builtin_thread_pointer and __builtin_set_thread_pointer as sh1_builtin. (sh_media_init_builtins, sh_init_builtins): Merge into single function sh_init_builtins. Add is_enabled checking. (sh_media_builtin_decl, sh_builtin_decl): Merge into single function sh_builtin_decl. Add is_enabled checking. (base_reg_disp): New class. (sh_find_base_reg_disp, sh_find_equiv_gbr_addr): New functions. testsuite/ChangeLog: PR target/54760 * gcc.target/sh/pr54760-1.c: New. * gcc.target/sh/pr54760-2.c: New. * gcc.target/sh/pr54760-3.c: New. Index: gcc/config/sh/sh.md =================================================================== --- gcc/config/sh/sh.md (revision 191894) +++ gcc/config/sh/sh.md (working copy) @@ -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_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. @(%O1,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov_gbr_load" + [(set (match_operand:QIHISI 0 "register_operand" "=z") + (mem:QIHISI (reg:SI GBR_REG)))] + "TARGET_SH1" + "mov. @(0,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov_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. @(%O1,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov_gbr_load" + [(set (match_operand:SI 0 "register_operand" "=z") + (sign_extend:SI (mem:QIHI (reg:SI GBR_REG))))] + "TARGET_SH1" + "mov. @(0,gbr),%0" + [(set_attr "type" "load")]) + +(define_insn "*mov_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. %1,@(%O0,gbr)" + [(set_attr "type" "store")]) + +(define_insn "*mov_gbr_store" + [(set (mem:QIHISI (reg:SI GBR_REG)) + (match_operand:QIHISI 0 "register_operand" "z"))] + "TARGET_SH1" + "mov. %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 Index: gcc/config/sh/predicates.md =================================================================== --- gcc/config/sh/predicates.md (revision 191899) +++ gcc/config/sh/predicates.md (working copy) @@ -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; Index: gcc/config/sh/sh-protos.h =================================================================== --- gcc/config/sh/sh-protos.h (revision 191899) +++ gcc/config/sh/sh-protos.h (working copy) @@ -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); Index: gcc/config/sh/sh.c =================================================================== --- gcc/config/sh/sh.c (revision 191899) +++ gcc/config/sh/sh.c (working copy) @@ -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" Index: gcc/testsuite/gcc.target/sh/pr54760-1.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54760-1.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54760-1.c (revision 0) @@ -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); +} Index: gcc/testsuite/gcc.target/sh/pr54760-3.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54760-3.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54760-3.c (revision 0) @@ -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; +} Index: gcc/testsuite/gcc.target/sh/pr54760-2.c =================================================================== --- gcc/testsuite/gcc.target/sh/pr54760-2.c (revision 0) +++ gcc/testsuite/gcc.target/sh/pr54760-2.c (revision 0) @@ -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)