From patchwork Fri Jan 6 14:48:19 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chung-Lin Tang X-Patchwork-Id: 134649 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 5F7771007D8 for ; Sat, 7 Jan 2012 01:48:56 +1100 (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=1326466137; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC: Subject:Content-Type:Mailing-List:Precedence:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:Sender: Delivered-To; bh=dfJG+UVPid1zTnatujgZffZhdmM=; b=Ukbpt+HiOxBq2Lr 8BlrF6tKETT1d4cvRQHhI5OQoq6QH3oYQhM7BnD3CKnxY8kRehpCeKpvUh1PqRnD AplG1IFTP5fFzGCktkEuwEWrdLHn3BvrR8VvJrtEJkFuESWsw/Gz1vBtpJp6raq3 ehZVc4HCxj50+/EyEVAB7ldH99iA= 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:Received:Message-ID:Date:From:User-Agent:MIME-Version:To:CC:Subject:Content-Type:X-IsSubscribed:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=hT+X+QnBFlF7Xbvx6YJtStV7cZq2Zjy9mi9G+BlbsAxgbnc5Mihq93eeFdRgqr cgOw45UOqYhqDmgmvgySXVqpCVUsqWq8XdIeQJCn9tTbHGSKUC49sM+4jF4eiQBL X0SDWnSpCvSX9zZiUNupaup3l5wpZulP+qKzq+Volwko0=; Received: (qmail 21380 invoked by alias); 6 Jan 2012 14:48:51 -0000 Received: (qmail 21361 invoked by uid 22791); 6 Jan 2012 14:48:48 -0000 X-SWARE-Spam-Status: No, hits=1.0 required=5.0 tests=AWL, BAYES_20, FROM_12LTRDOM, KAM_STOCKGEN, TW_DH, TW_FN, TW_LG, TW_TP X-Spam-Check-By: sourceware.org Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 06 Jan 2012 14:48:31 +0000 Received: from svr-orw-fem-01.mgc.mentorg.com ([147.34.98.93]) by relay1.mentorg.com with esmtp id 1RjB5p-00017D-EU from ChungLin_Tang@mentor.com ; Fri, 06 Jan 2012 06:48:29 -0800 Received: from SVR-ORW-FEM-03.mgc.mentorg.com ([147.34.97.39]) by svr-orw-fem-01.mgc.mentorg.com over TLS secured channel with Microsoft SMTPSVC(6.0.3790.4675); Fri, 6 Jan 2012 06:48:29 -0800 Received: from [0.0.0.0] (147.34.91.1) by svr-orw-fem-03.mgc.mentorg.com (147.34.97.39) with Microsoft SMTP Server id 14.1.289.1; Fri, 6 Jan 2012 06:48:27 -0800 Message-ID: <4F0709B3.8060202@codesourcery.com> Date: Fri, 6 Jan 2012 22:48:19 +0800 From: Chung-Lin Tang User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:8.0) Gecko/20111105 Thunderbird/8.0 MIME-Version: 1.0 To: gcc-patches CC: Richard Sandiford Subject: [PATCH] MIPS16 TLS support for GCC 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 Hi Richard, here are the patches for MIPS16 TLS. Some highlights of the implementation: 1) For the common -mcode-readable=yes case, TP/DTP offset constants are loaded pc-relative (this saves insn count and size). HI16/LO16 constructing is used only as a fall-back when text is not readable. 2) To support the Initial/Local-Exec TLS access models, direct access to the TP is needed. However, MIPS16 mode cannot access the 'rdhwr $3,$29' instruction used to do that, thus a new __mips16_rdhwr() helper routine is added to libgcc.a 3) Uses of this __mips16_rdhwr() routine are only generated by by (a) IE/LE accesses, and (b) calls to the (new added) __builtin_thread_pointer() builtin function. To facilitate lower overhead, such calls are represented as UNSPECs instead of actual function calls, and doesn't really follow the standard ABI (e.g. value returned in $3). The __mips16_rdhwr() function is not intended for general use, just tightly coupled compiler runtime support; therefore, it is only linked statically from libgcc.a, not exported from shared libgcc. 4) Due to containing such a static only support routine, mips*-linux* targets have been adjusted to use config/t-slibgcc-libgcc in libgcc/config.host (or else static -lgcc would not be included when linking with -shared -shared-libgcc) 5) The libgomp MIPS futex.h header has been adjusted; sys_futex0() has been modified to be static, non-inlined, nomips16 under MIPS16 mode (for sake of using 'syscall'). The inline assembly has also been fixed, as Maciej noticed a possible violation of the MIPS syscall restart convention; the 'li $2, #syscall_number' must be right before the syscall insn. Only O32 support has been attempted right now, though the code should not have anything really old-ABI specific. We were able to build glibc as MIPS16 code with this TLS implementation, so I believe things should be fairly stable. Anyways, I believe this will be going in only after 4.8-stage1 opens, so you should have plenty time to review it :) Thanks, and Happy New Year Chung-Lin 2012-01-06 Chung-Lin Tang gcc/ * config/mips/mips.h (CRT_CALL_STATIC_FUNCTION): Define versions for MIPS16 O32. * config/mips/mips-protos.h (mips_symbol_type): Add SYMBOL_DTPREL_HI,SYMBOL_TPREL_HI. Update in comments. (mips_output_tls_reloc_directive): New prototype. * config/mips/mips-ftypes.def: Add (0, (POINTER)) entry. * config/mips/predicates.md (tls_reloc_operand): New predicate. * config/mips/mips.md (V0_REGNUM,PIC_JUMP_REGNUM): New constant. (MIPS16 %dtprel_hi,%tprel_hi split pattern): New. (consttable_tls_reloc): New. (tls_get_tp__mips16): New insn and split pattern. (*tls_get_tp__mips16_rdhwr): New insn pattern. libgcc/ * config.host (mips64*-*-linux*,mipsisa64*-*-linux*,mips*-*-linux*): Use config/t-slibgcc-libgcc. * config/mips/t-mips16 (LIB1ASMFUNCS): Add _m16rdhwr. * config/mips/crtfastmath.c (set_fast_math): Add 'nomips16' attribute. * config/mips/mips16.S (__mips16_rdhwr): New. libgomp/ * config/linux/mips/futex.h (sys_futex0): Change to static function with noinline, nomips16 attributes under MIPS16. Adjust asm statement to place 'li v0,SYS_futex' immediately before syscall insn. Index: libgcc/config.host =================================================================== --- libgcc/config.host (revision 182952) +++ libgcc/config.host (working copy) @@ -740,12 +740,12 @@ mips*-*-netbsd*) # NetBSD/mips, either endian. ;; mips64*-*-linux* | mipsisa64*-*-linux*) extra_parts="$extra_parts crtfastmath.o" - tmake_file="${tmake_file} t-crtfm mips/t-mips16 mips/t-tpbit" + tmake_file="${tmake_file} t-crtfm mips/t-mips16 mips/t-tpbit t-slibgcc-libgcc" md_unwind_header=mips/linux-unwind.h ;; mips*-*-linux*) # Linux MIPS, either endian. extra_parts="$extra_parts crtfastmath.o" - tmake_file="${tmake_file} t-crtfm mips/t-mips16" + tmake_file="${tmake_file} t-crtfm mips/t-mips16 t-slibgcc-libgcc" md_unwind_header=mips/linux-unwind.h ;; mips*-*-openbsd*) Index: libgcc/config/mips/t-mips16 =================================================================== --- libgcc/config/mips/t-mips16 (revision 182952) +++ libgcc/config/mips/t-mips16 (working copy) @@ -36,7 +36,8 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \ _m16stubsc9 _m16stubsc10 \ _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \ - _m16stubdc9 _m16stubdc10 + _m16stubdc9 _m16stubdc10 \ + _m16rdhwr SYNC = yes SYNC_CFLAGS = -mno-mips16 Index: libgcc/config/mips/mips16.S =================================================================== --- libgcc/config/mips/mips16.S (revision 182952) +++ libgcc/config/mips/mips16.S (working copy) @@ -709,4 +709,18 @@ CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC) CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC) #endif #endif /* !__mips_single_float */ + +#ifdef L_m16rdhwr +STARTFN (__mips16_rdhwr) + /* Forced always hidden, to avoid exporting from shared libgcc. */ + .hidden __mips16_rdhwr + .set push + .set mips32r2 + .set noreorder + rdhwr $3,$29 + .set pop + j $31 + ENDFN (__mips16_rdhwr) #endif + +#endif Index: libgcc/config/mips/crtfastmath.c =================================================================== --- libgcc/config/mips/crtfastmath.c (revision 182952) +++ libgcc/config/mips/crtfastmath.c (working copy) @@ -39,7 +39,7 @@ #define _FPU_GETCW(cw) __asm__ ("cfc1 %0,$31" : "=r" (cw)) #define _FPU_SETCW(cw) __asm__ ("ctc1 %0,$31" : : "r" (cw)) -static void __attribute__((constructor)) +static void __attribute__ ((constructor,nomips16)) set_fast_math (void) { unsigned int fcr; Index: libgomp/config/linux/mips/futex.h =================================================================== --- libgomp/config/linux/mips/futex.h (revision 182952) +++ libgomp/config/linux/mips/futex.h (working copy) @@ -28,20 +28,26 @@ #define FUTEX_WAIT 0 #define FUTEX_WAKE 1 +#ifdef __mips16 +static void __attribute__((noinline,nomips16)) +#else static inline void +#endif sys_futex0 (int *addr, int op, int val) { - register unsigned long __v0 asm("$2") = (unsigned long) SYS_futex; + register unsigned long __v0 asm("$2"); register unsigned long __a0 asm("$4") = (unsigned long) addr; register unsigned long __a1 asm("$5") = (unsigned long) op; register unsigned long __a2 asm("$6") = (unsigned long) val; register unsigned long __a3 asm("$7") = 0; - __asm volatile ("syscall" + __asm volatile ("li $2, %6\n\t" + "syscall" /* returns $a3 (errno), $v0 (return value) */ : "=r" (__v0), "=r" (__a3) - /* arguments in v0 (syscall) a0-a3 */ - : "r" (__v0), "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a3) + /* arguments in a0-a3, and syscall number */ + : "r" (__a0), "r" (__a1), "r" (__a2), "r" (__a3), + "IK" (SYS_futex) /* clobbers at, v1, t0-t9, memory */ : "$1", "$3", "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$24", "$25", "memory"); Index: gcc/config/mips/mips-ftypes.def =================================================================== --- gcc/config/mips/mips-ftypes.def (revision 182952) +++ gcc/config/mips/mips-ftypes.def (working copy) @@ -51,6 +51,8 @@ DEF_MIPS_FTYPE (2, (INT, SF, SF)) DEF_MIPS_FTYPE (2, (INT, V2SF, V2SF)) DEF_MIPS_FTYPE (4, (INT, V2SF, V2SF, V2SF, V2SF)) +DEF_MIPS_FTYPE (0, (POINTER)) + DEF_MIPS_FTYPE (2, (SI, DI, SI)) DEF_MIPS_FTYPE (2, (SI, POINTER, SI)) DEF_MIPS_FTYPE (2, (DI, POINTER, SI)) Index: gcc/config/mips/predicates.md =================================================================== --- gcc/config/mips/predicates.md (revision 182952) +++ gcc/config/mips/predicates.md (working copy) @@ -312,6 +312,14 @@ && type == SYMBOL_GOT_PAGE_OFST); }) +(define_predicate "tls_reloc_operand" + (match_code "const,symbol_ref,label_ref") +{ + enum mips_symbol_type type; + return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &type) + && (type == SYMBOL_DTPREL || type == SYMBOL_TPREL)); +}) + (define_predicate "symbol_ref_operand" (match_code "symbol_ref")) Index: gcc/config/mips/mips.md =================================================================== --- gcc/config/mips/mips.md (revision 182952) +++ gcc/config/mips/mips.md (working copy) @@ -134,7 +134,9 @@ ]) (define_constants - [(TLS_GET_TP_REGNUM 3) + [(V0_REGNUM 2) + (TLS_GET_TP_REGNUM 3) + (PIC_JUMP_REGNUM 25) (RETURN_ADDR_REGNUM 31) (CPRESTORE_SLOT_REGNUM 76) (GOT_VERSION_REGNUM 79) @@ -3933,6 +3935,23 @@ operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH); }) +;; MIPS16 %dtprel_hi,%tprel_hi split pattern. Similar transform +;; as above, for supporting MIPS16 TLS. +(define_split + [(set (match_operand:SI 0 "d_operand") + (high:SI (match_operand:SI 1 "tls_reloc_operand")))] + "TARGET_MIPS16 && reload_completed" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))] +{ + /* SYMBOL_DTPREL_HI/TPREL_HI are ordered immediately after + SYMBOL_DTPREL/TPREL respectively, so use unspec_type + 1. */ + rtx unspec = XEXP (operands[1], 0); + int unspec_type = XINT (unspec, 1); + operands[2] = mips_unspec_address (XVECEXP (unspec, 0, 0), + unspec_type + 1 - UNSPEC_ADDRESS_FIRST); +}) + ;; Insns to fetch a symbol from a big GOT. (define_insn_and_split "*xgot_hi" @@ -6492,6 +6511,17 @@ ;; .................... ;; +(define_insn "consttable_tls_reloc" + [(unspec_volatile [(match_operand 0 "tls_reloc_operand" "") + (match_operand 1 "const_int_operand" "")] + UNSPEC_CONSTTABLE_INT)] + "TARGET_MIPS16_PCREL_LOADS" +{ + mips_output_tls_reloc_directive (operands[0], operands[1]); + return ""; +} + [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))]) + (define_insn "consttable_int" [(unspec_volatile [(match_operand 0 "consttable_operand" "") (match_operand 1 "const_int_operand" "")] @@ -6593,6 +6623,60 @@ ; See tls_get_tp_ (set_attr "can_delay" "no") (set_attr "mode" "")]) + +;; In MIPS16 mode, the TLS base pointer is accessed by a +;; libgcc helper function __mips16_rdhwr(), as 'rdhwr' is not +;; accessible in MIPS16. +;; +;; This is not represented as a call insn, to avoid the +;; unnecesarry clobbering of caller-save registers by a +;; function consisting only of: "rdhwr $3,$29; j $31; nop;" +;; +;; A $25 clobber is added to cater for a $25 load stub added by the +;; linker to __mips16_rdhwr when the call is made from non-PIC code. + +(define_insn_and_split "tls_get_tp__mips16" + [(set (match_operand:P 0 "register_operand" "=d") + (unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP)) + (clobber (reg:P TLS_GET_TP_REGNUM)) + (clobber (reg:P PIC_JUMP_REGNUM)) + (clobber (reg:P RETURN_ADDR_REGNUM))] + "HAVE_AS_TLS && TARGET_MIPS16" + "#" + "&& reload_completed" + [(parallel [(set (reg:P TLS_GET_TP_REGNUM) + (unspec:P [(match_dup 1)] UNSPEC_TLS_GET_TP)) + (clobber (reg:P PIC_JUMP_REGNUM)) + (clobber (reg:P RETURN_ADDR_REGNUM))]) + (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM)) ] + { + /* UNSPEC operand decides on direct/indirect pattern below. */ + rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__mips16_rdhwr"); + if (TARGET_ABSOLUTE_JUMPS) + operands[1] = sym; + else + { + operands[1] = gen_rtx_REG (Pmode, TLS_GET_TP_REGNUM); + mips_emit_move (operands[1], sym); + } + } + [(set_attr "type" "unknown") + (set_attr "can_delay" "no") + (set_attr "mode" "")]) + +(define_insn "*tls_get_tp__mips16_rdhwr" + [(set (reg:P TLS_GET_TP_REGNUM) + (unspec:P [(match_operand:P 0 "")] UNSPEC_TLS_GET_TP)) + (clobber (reg:P PIC_JUMP_REGNUM)) + (clobber (reg:P RETURN_ADDR_REGNUM))] + "HAVE_AS_TLS && TARGET_MIPS16" + { + return MIPS_CALL ("jal", operands, 0, -1); + } + [(set_attr "type" "call") + (set_attr "can_delay" "no") + (set_attr "mode" "")]) + ;; Synchronization instructions. Index: gcc/config/mips/mips-protos.h =================================================================== --- gcc/config/mips/mips-protos.h (revision 182952) +++ gcc/config/mips/mips-protos.h (working copy) @@ -89,8 +89,10 @@ enum mips_symbol_context { SYMBOL_TLSGD SYMBOL_TLSLDM SYMBOL_DTPREL + SYMBOL_DTPREL_HI SYMBOL_GOTTPREL SYMBOL_TPREL + SYMBOL_TPREL_HI UNSPEC wrappers around SYMBOL_TLS, corresponding to the thread-local storage relocation operators. @@ -127,8 +129,10 @@ enum mips_symbol_type { SYMBOL_TLSGD, SYMBOL_TLSLDM, SYMBOL_DTPREL, + SYMBOL_DTPREL_HI, SYMBOL_GOTTPREL, SYMBOL_TPREL, + SYMBOL_TPREL_HI, SYMBOL_32_HIGH, SYMBOL_64_HIGH, SYMBOL_64_MID, @@ -341,6 +345,7 @@ extern bool mips_epilogue_uses (unsigned int); extern void mips_final_prescan_insn (rtx, rtx *, int); extern int mips_trampoline_code_size (void); extern void mips_function_profiler (FILE *); +extern void mips_output_tls_reloc_directive (rtx, rtx); typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx); #ifdef RTX_CODE Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c (revision 182952) +++ gcc/config/mips/mips.c (working copy) @@ -183,6 +183,7 @@ enum mips_address_type { }; /* Macros to create an enumeration identifier for a function prototype. */ +#define MIPS_FTYPE_NAME0(A) MIPS_##A##_FTYPE_VOID #define MIPS_FTYPE_NAME1(A, B) MIPS_##A##_FTYPE_##B #define MIPS_FTYPE_NAME2(A, B, C) MIPS_##A##_FTYPE_##B##_##C #define MIPS_FTYPE_NAME3(A, B, C, D) MIPS_##A##_FTYPE_##B##_##C##_##D @@ -233,7 +234,10 @@ enum mips_builtin_type { MIPS_BUILTIN_CMP_SINGLE, /* For generating bposge32 branch instructions in MIPS32 DSP ASE. */ - MIPS_BUILTIN_BPOSGE32 + MIPS_BUILTIN_BPOSGE32, + + /* For generating accesses to the TLS thread pointer. */ + MIPS_BUILTIN_THREAD_POINTER }; /* Invoke MACRO (COND) for each C.cond.fmt condition. */ @@ -1763,6 +1767,8 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_ case SYMBOL_GOTTPREL: case SYMBOL_TLS: case SYMBOL_HALF: + case SYMBOL_TPREL_HI: + case SYMBOL_DTPREL_HI: return false; } gcc_unreachable (); @@ -1857,8 +1863,10 @@ mips_symbol_insns_1 (enum mips_symbol_type type, e case SYMBOL_TLSGD: case SYMBOL_TLSLDM: case SYMBOL_DTPREL: + case SYMBOL_DTPREL_HI: case SYMBOL_GOTTPREL: case SYMBOL_TPREL: + case SYMBOL_TPREL_HI: case SYMBOL_HALF: /* A 16-bit constant formed by a single relocation, or a 32-bit constant formed from a high 16-bit relocation and a low 16-bit @@ -1928,14 +1936,23 @@ mips_cannot_force_const_mem (enum machine_mode mod if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type) && type != SYMBOL_FORCE_TO_MEM) { + if (TARGET_MIPS16_PCREL_LOADS) + { + /* Under MIPS16, TLS DTP/TP-relative offsets are loaded from the + constant pool, as this saves some code size compared to hi/lo + constructing. */ + if (type == SYMBOL_DTPREL || type == SYMBOL_TPREL) + return false; + + /* If MIPS16 constant pools live in the text section, they should + not refer to anything that might need run-time relocation. */ + if (mips_got_symbol_type_p (type)) + return true; + } + /* The same optimization as for CONST_INT. */ if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0) return true; - - /* If MIPS16 constant pools live in the text section, they should - not refer to anything that might need run-time relocation. */ - if (TARGET_MIPS16_PCREL_LOADS && mips_got_symbol_type_p (type)) - return true; } /* TLS symbols must be computed by mips_legitimize_move. */ @@ -2820,11 +2837,20 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_ /* Return a pseudo register that contains the current thread pointer. */ static rtx -mips_get_tp (void) +mips_get_tp (rtx target) { - rtx tp; + rtx tp = (target != NULL_RTX && REG_P (target) + ? target : gen_reg_rtx (Pmode)); - tp = gen_reg_rtx (Pmode); + if (TARGET_MIPS16) + { + if (Pmode == DImode) + emit_insn (gen_tls_get_tp_di_mips16 (tp)); + else + emit_insn (gen_tls_get_tp_si_mips16 (tp)); + return tp; + } + if (Pmode == DImode) emit_insn (gen_tls_get_tp_di (tp)); else @@ -2842,12 +2868,6 @@ mips_legitimize_tls_address (rtx loc) rtx dest, insn, v0, tp, tmp1, tmp2, eqv; enum tls_model model; - if (TARGET_MIPS16) - { - sorry ("MIPS16 TLS"); - return gen_reg_rtx (Pmode); - } - model = SYMBOL_REF_TLS_MODEL (loc); /* Only TARGET_ABICALLS code can have more than one module; other code must be be static and should not use a GOT. All TLS models @@ -2875,13 +2895,23 @@ mips_legitimize_tls_address (rtx loc) UNSPEC_TLS_LDM); emit_libcall_block (insn, tmp1, v0, eqv); - tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL); - dest = gen_rtx_LO_SUM (Pmode, tmp2, - mips_unspec_address (loc, SYMBOL_DTPREL)); + if (TARGET_MIPS16_PCREL_LOADS) + { + tmp2 = mips_force_temporary (NULL, + mips_unspec_address (loc, + SYMBOL_DTPREL)); + dest = gen_rtx_PLUS (Pmode, tmp1, tmp2); + } + else + { + tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL); + dest = gen_rtx_LO_SUM (Pmode, tmp2, + mips_unspec_address (loc, SYMBOL_DTPREL)); + } break; case TLS_MODEL_INITIAL_EXEC: - tp = mips_get_tp (); + tp = mips_get_tp (NULL_RTX); tmp1 = gen_reg_rtx (Pmode); tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL); if (Pmode == DImode) @@ -2893,10 +2923,20 @@ mips_legitimize_tls_address (rtx loc) break; case TLS_MODEL_LOCAL_EXEC: - tp = mips_get_tp (); - tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL); - dest = gen_rtx_LO_SUM (Pmode, tmp1, - mips_unspec_address (loc, SYMBOL_TPREL)); + tp = mips_get_tp (NULL_RTX); + if (TARGET_MIPS16_PCREL_LOADS) + { + tmp1 = mips_force_temporary (NULL, + mips_unspec_address (loc, + SYMBOL_TPREL)); + dest = gen_rtx_PLUS (Pmode, tp, tmp1); + } + else + { + tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL); + dest = gen_rtx_LO_SUM (Pmode, tmp1, + mips_unspec_address (loc, SYMBOL_TPREL)); + } break; default: @@ -7291,16 +7331,24 @@ mips_init_relocs (void) mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd("; mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm("; - mips_split_p[SYMBOL_DTPREL] = true; - mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi("; - mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo("; + if (! TARGET_MIPS16_PCREL_LOADS) + { + mips_split_p[SYMBOL_DTPREL] = true; + mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi("; + mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo("; - mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel("; + mips_split_p[SYMBOL_TPREL] = true; + mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi("; + mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo("; - mips_split_p[SYMBOL_TPREL] = true; - mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi("; - mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo("; + if (TARGET_MIPS16) + { + mips_lo_relocs[SYMBOL_TPREL_HI] = "%tprel_hi("; + mips_lo_relocs[SYMBOL_DTPREL_HI] = "%dtprel_hi("; + } + } + mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel("; mips_lo_relocs[SYMBOL_HALF] = "%half("; } @@ -12734,7 +12782,8 @@ struct mips_builtin_description { /* The function's prototype. */ enum mips_function_type function_type; - /* Whether the function is available. */ + /* Whether the function is available. A NULL pointer value here + means the builtin is always available. */ unsigned int (*avail) (void); }; @@ -12904,6 +12953,12 @@ AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN) #define CODE_FOR_loongson_psubush CODE_FOR_ussubv4hi3 #define CODE_FOR_loongson_psubusb CODE_FOR_ussubv8qi3 +/* Define a MIPS_BUILTIN_THREAD_POINTER builtin. The parameters are fixed, + but we allow both __builtin* and __builtin_mips* prefixes below. */ +#define THREAD_POINTER_BUILTIN(NAME) \ + { CODE_FOR_nothing, MIPS_FP_COND_f, #NAME, \ + MIPS_BUILTIN_THREAD_POINTER, MIPS_POINTER_FTYPE_VOID, NULL } + static const struct mips_builtin_description mips_builtins[] = { DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single), DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single), @@ -13187,7 +13242,11 @@ static const struct mips_builtin_description mips_ LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI), /* Sundry other built-in functions. */ - DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache) + DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache), + + /* TLS thread pointer built-in functions. */ + THREAD_POINTER_BUILTIN (__builtin_mips_thread_pointer), + THREAD_POINTER_BUILTIN (__builtin_thread_pointer) }; /* Index I is the function declaration for mips_builtins[I], or null if the @@ -13258,6 +13317,8 @@ mips_build_cvpointer_type (void) /* MIPS_FTYPE_ATYPESN takes N MIPS_FTYPES-like type codes and lists their associated MIPS_ATYPEs. */ +#define MIPS_FTYPE_ATYPES0(A) MIPS_ATYPE_##A + #define MIPS_FTYPE_ATYPES1(A, B) \ MIPS_ATYPE_##A, MIPS_ATYPE_##B @@ -13309,11 +13370,19 @@ mips_init_builtins (void) for (i = 0; i < ARRAY_SIZE (mips_builtins); i++) { d = &mips_builtins[i]; - if (d->avail ()) - mips_builtin_decls[i] - = add_builtin_function (d->name, - mips_build_function_type (d->function_type), - i, BUILT_IN_MD, NULL, NULL); + if (d->avail && !d->avail ()) + continue; + + mips_builtin_decls[i] + = add_builtin_function (d->name, + mips_build_function_type (d->function_type), + i, BUILT_IN_MD, NULL, NULL); + + if (d->builtin_type == MIPS_BUILTIN_THREAD_POINTER) + { + TREE_NOTHROW (mips_builtin_decls[i]) = 1; + TREE_READONLY (mips_builtin_decls[i]) = 1; + } } } @@ -13544,20 +13613,21 @@ mips_expand_builtin (tree exp, rtx target, rtx sub enum machine_mode mode, int ignore) { tree fndecl; - unsigned int fcode, avail; + unsigned int fcode; const struct mips_builtin_description *d; fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); fcode = DECL_FUNCTION_CODE (fndecl); gcc_assert (fcode < ARRAY_SIZE (mips_builtins)); d = &mips_builtins[fcode]; - avail = d->avail (); - gcc_assert (avail != 0); - if (TARGET_MIPS16) + if (d->avail && !d->avail ()) { - error ("built-in function %qE not supported for MIPS16", - DECL_NAME (fndecl)); - return ignore ? const0_rtx : CONST0_RTX (mode); + if (TARGET_MIPS16) + { + error ("built-in function %qE not supported for MIPS16", + DECL_NAME (fndecl)); + return ignore ? const0_rtx : CONST0_RTX (mode); + } } switch (d->builtin_type) { @@ -13582,6 +13652,9 @@ mips_expand_builtin (tree exp, rtx target, rtx sub case MIPS_BUILTIN_BPOSGE32: return mips_expand_builtin_bposge (d->builtin_type, target); + + case MIPS_BUILTIN_THREAD_POINTER: + return mips_get_tp (target); } gcc_unreachable (); } @@ -13771,7 +13844,7 @@ mips16_rewrite_pool_refs (rtx *x, void *data) struct mips16_rewrite_pool_refs_info *info = (struct mips16_rewrite_pool_refs_info *) data; - if (force_to_mem_operand (*x, Pmode)) + if (force_to_mem_operand (*x, Pmode) || tls_reloc_operand (*x, Pmode)) { rtx mem = force_const_mem (GET_MODE (*x), *x); validate_change (info->insn, x, mem, false); @@ -13783,6 +13856,11 @@ mips16_rewrite_pool_refs (rtx *x, void *data) return -1; } + if (GET_CODE (*x) == UNSPEC + && XINT (*x, 1) == UNSPEC_TLS_GET_TP + && GET_CODE (XVECEXP (*x, 0, 0)) == SYMBOL_REF) + return -1; + if (TARGET_MIPS16_TEXT_LOADS) mips16_rewrite_pool_constant (info->pool, x); @@ -17108,6 +17186,28 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx o x = gen_rtx_IOR (vmode, t0, t1); emit_insn (gen_rtx_SET (VOIDmode, target, x)); } + +/* Output a DTP/TP-relative relocation, used in MIPS16 TLS. */ + +void +mips_output_tls_reloc_directive (rtx x, rtx size) +{ + const char *dir = NULL; + if (GET_CODE (x) == CONST) + x = XEXP (x, 0); + switch (UNSPEC_ADDRESS_TYPE (x)) + { + case SYMBOL_DTPREL: + dir = INTVAL (size) == 4 ? ".dtprelword" : ".dtpreldword"; + break; + case SYMBOL_TPREL: + dir = INTVAL (size) == 4 ? ".tprelword" : ".tpreldword"; + break; + default: + gcc_unreachable (); + } + fprintf (asm_out_file, "\t%s\t%s\n", dir, XSTR (UNSPEC_ADDRESS (x), 0)); +} /* Initialize the GCC target structure. */ #undef TARGET_ASM_ALIGNED_HI_OP Index: gcc/config/mips/mips.h =================================================================== --- gcc/config/mips/mips.h (revision 182952) +++ gcc/config/mips/mips.h (working copy) @@ -2841,8 +2841,32 @@ while (0) jal " USER_LABEL_PREFIX #FUNC "\n\ " TEXT_SECTION_ASM_OP); #endif + +#else +#if (defined _ABIO32 && _MIPS_SIM == _ABIO32) +#ifdef __PIC__ +/* For MIPS16 PIC, construct the GP-value in $2 using PC-relative insns. */ +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ + asm (SECTION_OP "\n\ + li $2,%hi(_gp_disp)\n\ + addiu $3,$pc,%lo(_gp_disp)\n\ + sll $2,16\n\ + addu $2,$3\n\ + lw $2,%got(" USER_LABEL_PREFIX #FUNC ")($2)\n\ + addiu $2,%lo(" USER_LABEL_PREFIX #FUNC ")\n\ + move $25,$2\n\ + jalr $2\n\ + " TEXT_SECTION_ASM_OP); +#else +#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC) \ + asm (SECTION_OP "\n\ + jal " USER_LABEL_PREFIX #FUNC "\n\ + " TEXT_SECTION_ASM_OP); #endif +#endif +#endif /* __mips16 */ + #ifndef HAVE_AS_TLS #define HAVE_AS_TLS 0 #endif