From patchwork Sun Jan 8 11:20:53 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 134898 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 7BCB2B6F69 for ; Sun, 8 Jan 2012 22:21:33 +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=1326626494; h=Comment: DomainKey-Signature:Received:Received:Received:Received:Received: Received:From:To:Mail-Followup-To:Cc:Subject:References:Date: Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List: Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:Sender:Delivered-To; bh=NeG/SYUwmsn3TI7UB+Z9ybFoYvY=; b=htK5bNWSAEjBMyOeCIVdf/iel2Dl+JygeF9SUhWc18OnKy0Vonb0fnV1xXtTeK DdBIc/rDTsVWmwQxVExqULyT+ma9P6erm2DaVZIgroijGXcViO7l2WGSiukrja3r JdtvfdI1EO3dTl6e/AtNu/z4ERaTFWlSuSTd9t6CvPjlc= 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:From:To:Mail-Followup-To:Cc:Subject:References:Date:Message-ID:User-Agent:MIME-Version:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=fjG9qoZ/x941jW40l/+R19U2WUR0VOSOzZoJMHEk5zwL+t/6FdCrpK60YXTEK/ kfmfuPrk5hGo/pdhlEQ3K+MnSteQLP/miubvuAn7baQz7JieA0FEbB4w1OIbTwW8 bQkMeCDROypCCs/c1LOTEGNiXkCXCXXb4k9nIoMyH8jAE=; Received: (qmail 5050 invoked by alias); 8 Jan 2012 11:21:24 -0000 Received: (qmail 5036 invoked by uid 22791); 8 Jan 2012 11:21:20 -0000 X-SWARE-Spam-Status: No, hits=-0.2 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, TW_DH X-Spam-Check-By: sourceware.org Received: from mail-wi0-f175.google.com (HELO mail-wi0-f175.google.com) (209.85.212.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Sun, 08 Jan 2012 11:21:03 +0000 Received: by wibhq7 with SMTP id hq7so2407233wib.20 for ; Sun, 08 Jan 2012 03:21:01 -0800 (PST) Received: by 10.180.88.169 with SMTP id bh9mr7106858wib.20.1326021661199; Sun, 08 Jan 2012 03:21:01 -0800 (PST) Received: from localhost (rsandifo.gotadsl.co.uk. [82.133.89.107]) by mx.google.com with ESMTPS id q5sm26307519wbo.8.2012.01.08.03.20.57 (version=TLSv1/SSLv3 cipher=OTHER); Sun, 08 Jan 2012 03:20:58 -0800 (PST) From: Richard Sandiford To: Chung-Lin Tang Mail-Followup-To: Chung-Lin Tang , gcc-patches , rdsandiford@googlemail.com Cc: gcc-patches Subject: Re: [PATCH] MIPS16 TLS support for GCC References: <4F0709B3.8060202@codesourcery.com> Date: Sun, 08 Jan 2012 11:20:53 +0000 Message-ID: <87r4zaxwx6.fsf@firetop.home> User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.2 (gnu/linux) MIME-Version: 1.0 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 Chung-Lin Tang writes: > Hi Richard, > here are the patches for MIPS16 TLS. Thanks for all the work. It's great to see this hole in the MIPS16 support finally being plugged. There seem to be three changes in the patch: (1) Enable MIPS16 TLS (which must of course work independently of whether libgcc, libc, etc. were compiled as MIPS16). (2) Allow the mips*-linux-gnu target libraries to be built as MIPS16. This relies on (1) but isn't required by (1). (3) Define a built-in function for accessing the TLS pointer. This is logically independent, although since the motivation was presumably to help build an external MIPS16 library, it's only worthwhile after (1). I agree all three are good things to have, but I'd like to keep them as separate patches. Now that I've seen the implementation, (1) feels fairly low risk and high value, so I'd like it to go in 4.7. (2) is interesting if there is also a way to build those MIPS16 libraries out of the box. I'd like such a mechanism to be added at the same time, so that the new support is easy to test. This is still a 4.7 candidate if it can be done in time, although it's probably a little tight. You've given the built-in function the generic name __builtin_thread_pointer. I agree that's a good idea, but I think we should also _treat_ it as a generic function, and make it available on all targets. The actual implementation can be delegated to a target hook. That makes (3) 4.8 material. (Incidentally, I don't think it's correct to define the builtin if TLS isn't available, so if we did keep it as a MIPS-specific function, d->avail would need to be nonnull. There would need to be some other way of indicating that MIPS16 was OK.) > 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. Well, a fair bit of libgcc is tightly-coupled compiler runtime support. I don't really see any need to handle the new function differently from the other __mips16 wrappers. It's not like we're gaining any benefit in the PIC call overhead: we can't turn JALRs into branches like we can for nearby non-MIPS16-to-non-MIPS16 calls, so PIC calls will still go via the GOT. And we're not gaining any benefit in terms of ABI baggage either. Future libgcc(.a)s would need to continue providing the function as specified now, in order for future gccs to be able to link library archives built with 4.7. By making the function hidden, we lose the important ability to replace all instances of it. E.g. it isn't inconceivable that someone will find a more efficient way to implement the function in cases where the RDHWR is emulated (perhaps on a kernel other than Linux -- this support isn't specific to *-linux-gnu). Being able to replace all instances of a function is useful for other things, such as profiling, debugging, or working around processor errata. > 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. This change is OK as part of (2). > 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. mips.c is missing from the changelog. > 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) V0_REGNUM seems to be unused. We should move PIC_FUNCTION_ADDR_REGNUM here rather than add another name for it. > @@ -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); > +}) mips_symbolic_constant_p allows an offset to be applied, in which case the expression has the form: (const (plus (unspec [BASE] UNSPEC_FOO) (const_int OFFSET))) I'm also not keen on hard-coding the +1 relationship. I think I made the wrong call when adding SYMBOL_32_HIGH. The idea was to reuse the existing move patterns rather than add a special one. That wasn't too bad when there was just this one simple case, but as the patch shows, it doesn't generalise well. Let's add a new "load unshifted high" instruction instead. > @@ -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" "")]) We should set "length" here, instead of "can_delay". We should also reuse the existing call-address handling -- call_insn_operand, mips16_stub_function, etc. -- in order to make sure that things like -mlong-calls are handled correctly. It seems better to do that in mips_get_tp (), then pass the call_insn_operand as an address. > +(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" "")]) Should be: (unspec:P [(match_operand:P 0 "call_insn_operand" "dS")] UNSPEC_TLS_GET_TP)) because we need to tell post-reload passes what they can and can't do. Should set "length" to 12 rather than "can_delay" to "no". > Index: gcc/config/mips/mips.c > =================================================================== > --- gcc/config/mips/mips.c (revision 182952) > +++ gcc/config/mips/mips.c (working copy) > @@ -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; > } For the record, these types would need to have allowed the same offsets as SYMBOL_TPREL and SYMBOL_DTPREL, otherwise we'd have ICEd after splitting a SYMBOL + CONST_INT. It's not important now though. > @@ -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; As below, we should instead replace SYMBOL_FORCE_TO_MEM with a separate predicate, since "force-to-mem"ness is now a separate property. > @@ -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) This is part of (3), but: adjust the comment to mention the parameter. > + 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)); So it looks like I missed a couple of places that should be using PMODE_INSN. Let's put the mode last -- tls_get_tp_mips16_{si,di} -- and use PMODE_INSN for both cases. > @@ -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)); > + } DEST is supposed to be a legitimate address (the sum of two registers isn't). We should also use a higher-level test than TARGET_MIPS16_PCREL_LOADS. Same for TPREL. > @@ -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)) As above, we allow small offsets to be applied to TPREL and DTPREL, so we can't assume that we have (const (unspec ...)). (In this case the HI/LO restriction doesn't apply, so we could actually be a bit more relaxed in the offsets that we allow. That's more stage 1 material though.) > 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 This is part of (2), but: why is the !__PIC__ definition necessary for just this one case? If it's correct, then isn't it correct for !MIPS16 too? And why isn't the default definition in crtstuff.c good enough? I wanted to try this out on my set-up, so here's the modified version of (1). I found I needed a GAS patch in order to get clean results. I'll post that patch soon. The mips_init_relocs change is mostly reindentation, so it looks more frightening that it is. A consequence of the SYMBOL_FORCE_TO_MEM change is that -mcode-readable=pcrel now allows non-PC-relative LEAs of absolute labels to be done via the constant pool rather than using %hi and %lo. I think this is a good thing (it's shorter, and matches the corresponding symbol case) so I've adjusted the testcase to allow it. Tested on mips64-linux-gnu. Does the patch look OK to you? Thanks, Richard gcc/ 2012-01-08 Chung-Lin Tang Richard Sandiford * config/mips/mips-protos.h (SYMBOL_FORCE_TO_MEM): Delete. (SYMBOL_32_HIGH): Likewise. (mips_output_tls_reloc_directive): Declare. * config/mips/mips.h (PIC_FUNCTION_ADDR_REGNUM): Move to mips.md. (mips_use_pcrel_pool_p, mips_lo_relocs, mips_hi_relocs): Declare. * config/mips/mips.c (mips_use_pcrel_pool_p): New variable. (mips_lo_relocs, mips_hi_relocs): Make extern. (mips16_stub_function): Move up file. (mips_classify_symbol): Remove SYMBOL_FORCE_TO_MEM handling. (mips_symbolic_constant_p): Likewise. Remove SYMBOL_32_HIGH too. (mips_symbol_insns_1): Likewise. Check mips_use_pcrel_pool_p. (mips_cannot_force_const_mem): Use mips_use_pcrel_pool_p instead of SYMBOL_FORCE_TO_MEM. Only check mips_tls_symbol_ref_1 if it's false. (mips_get_tp): Add MIPS16 support. (mips_legitimize_tls_address): Remove MIPS16 sorry(). Generalize DTPREL and TPREL handling. (mips_init_relocs): Initialize mips_use_pcrel_pool_p. Add MIPS16 TLS support. (mips_output_tls_reloc_directive): New function. (mips16_rewrite_pool_refs): Ignore UNSPEC_TLS_GET_TPs. * config/mips/predicates.md (symbolic_operand_with_high) (tls_reloc_operand): New predicates. (force_to_mem_operand): Use mips_use_pcrel_pool_p. * config/mips/mips.md (UNSPEC_UNSHIFTED_HIGH): New unspec. (PIC_FUNCTION_ADDR_REGNUM): Moved from mips.h. (*unshifted_high): New instruction. Use it for MIPS16 high splitter. (consttable_tls_reloc, tls_get_tp_mips16_): New patterns. (*tls_get_tp_mips16_call_): Likewise. gcc/testsuite/ * gcc.target/mips/code-readable-2.c: Allow the jump table address to be loaded from the constant pool, rather than via %hi and %lo. libgcc/ 2012-01-08 Chung-Lin Tang Richard Sandiford * config/mips/libgcc-mips16.ver (__mips16_rdhwr): Add. * config/mips/mips16.S (__mips16_rdhwr): New function. * config/mips/t-mips16 (LIB1ASMFUNCS): Add _m16rdhwr. Index: gcc/config/mips/mips-protos.h =================================================================== --- gcc/config/mips/mips-protos.h 2012-01-08 08:43:13.000000000 +0000 +++ gcc/config/mips/mips-protos.h 2012-01-08 10:12:57.000000000 +0000 @@ -56,9 +56,6 @@ enum mips_symbol_context { The symbol's value will be calculated using a MIPS16 PC-relative calculation. - SYMBOL_FORCE_TO_MEM - The symbol's value must be forced to memory and loaded from there. - SYMBOL_GOT_PAGE_OFST The symbol's value will be calculated by loading an address from the GOT and then applying a 16-bit offset. @@ -94,9 +91,6 @@ enum mips_symbol_context { UNSPEC wrappers around SYMBOL_TLS, corresponding to the thread-local storage relocation operators. - SYMBOL_32_HIGH - For a 32-bit symbolic address X, this is the value of %hi(X). - SYMBOL_64_HIGH For a 64-bit symbolic address X, this is the value of (%highest(X) << 16) + %higher(X). @@ -116,7 +110,6 @@ enum mips_symbol_type { SYMBOL_ABSOLUTE, SYMBOL_GP_RELATIVE, SYMBOL_PC_RELATIVE, - SYMBOL_FORCE_TO_MEM, SYMBOL_GOT_PAGE_OFST, SYMBOL_GOT_DISP, SYMBOL_GOTOFF_PAGE, @@ -129,7 +122,6 @@ enum mips_symbol_type { SYMBOL_DTPREL, SYMBOL_GOTTPREL, SYMBOL_TPREL, - SYMBOL_32_HIGH, SYMBOL_64_HIGH, SYMBOL_64_MID, SYMBOL_64_LOW, @@ -260,6 +252,7 @@ extern void mips_push_asm_switch (struct extern void mips_pop_asm_switch (struct mips_asm_switch *); extern void mips_output_external (FILE *, tree, const char *); extern void mips_output_ascii (FILE *, const char *, size_t); +extern const char *mips_output_tls_reloc_directive (rtx *); extern void mips_output_aligned_decl_common (FILE *, tree, const char *, unsigned HOST_WIDE_INT, unsigned int); Index: gcc/config/mips/mips.h =================================================================== --- gcc/config/mips/mips.h 2012-01-08 08:43:13.000000000 +0000 +++ gcc/config/mips/mips.h 2012-01-08 10:12:57.000000000 +0000 @@ -1785,8 +1785,6 @@ #define GLOBAL_POINTER_REGNUM (GP_REG_FI from there after reload. */ #define PIC_OFFSET_TABLE_REGNUM \ (reload_completed ? REGNO (pic_offset_table_rtx) : GLOBAL_POINTER_REGNUM) - -#define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25) /* Define the classes of registers for register constraints in the machine description. Also define ranges of constants. @@ -2868,6 +2866,9 @@ struct mips_asm_switch { extern int mips_dwarf_regno[]; extern bool mips_split_p[]; extern bool mips_split_hi_p[]; +extern bool mips_use_pcrel_pool_p[]; +extern const char *mips_lo_relocs[]; +extern const char *mips_hi_relocs[]; extern enum processor mips_arch; /* which cpu to codegen for */ extern enum processor mips_tune; /* which cpu to schedule for */ extern int mips_isa; /* architectural level */ Index: gcc/config/mips/mips.c =================================================================== --- gcc/config/mips/mips.c 2012-01-08 08:43:13.000000000 +0000 +++ gcc/config/mips/mips.c 2012-01-08 10:54:56.000000000 +0000 @@ -573,13 +573,17 @@ static GTY (()) int mips_output_filename can be split by mips_split_symbol. */ bool mips_split_hi_p[NUM_SYMBOL_TYPES]; +/* mips_use_pcrel_pool_p[X] is true if symbols of type X should be + forced into a PC-relative constant pool. */ +bool mips_use_pcrel_pool_p[NUM_SYMBOL_TYPES]; + /* mips_lo_relocs[X] is the relocation to use when a symbol of type X appears in a LO_SUM. It can be null if such LO_SUMs aren't valid or if they are matched by a special .md file pattern. */ -static const char *mips_lo_relocs[NUM_SYMBOL_TYPES]; +const char *mips_lo_relocs[NUM_SYMBOL_TYPES]; /* Likewise for HIGHs. */ -static const char *mips_hi_relocs[NUM_SYMBOL_TYPES]; +const char *mips_hi_relocs[NUM_SYMBOL_TYPES]; /* Target state for MIPS16. */ struct target_globals *mips16_globals; @@ -1440,6 +1444,18 @@ mips_legitimate_constant_p (enum machine return mips_const_insns (x) > 0; } +/* Return a SYMBOL_REF for a MIPS16 function called NAME. */ + +static rtx +mips16_stub_function (const char *name) +{ + rtx x; + + x = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + SYMBOL_REF_FLAGS (x) |= (SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION); + return x; +} + /* Return true if symbols of type TYPE require a GOT access. */ static bool @@ -1644,9 +1660,6 @@ mips_classify_symbol (const_rtx x, enum return SYMBOL_GOT_PAGE_OFST; } - if (TARGET_MIPS16_PCREL_LOADS && context != SYMBOL_CONTEXT_CALL) - return SYMBOL_FORCE_TO_MEM; - return SYMBOL_ABSOLUTE; } @@ -1709,8 +1722,6 @@ mips_symbolic_constant_p (rtx x, enum mi switch (*symbol_type) { case SYMBOL_ABSOLUTE: - case SYMBOL_FORCE_TO_MEM: - case SYMBOL_32_HIGH: case SYMBOL_64_HIGH: case SYMBOL_64_MID: case SYMBOL_64_LOW: @@ -1776,6 +1787,17 @@ mips_symbolic_constant_p (rtx x, enum mi static int mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode) { + if (mips_use_pcrel_pool_p[(int) type]) + { + if (mode == MAX_MACHINE_MODE) + /* LEAs will be converted into constant-pool references by + mips_reorg. */ + type = SYMBOL_PC_RELATIVE; + else + /* The constant must be loaded and then dereferenced. */ + return 0; + } + switch (type) { case SYMBOL_ABSOLUTE: @@ -1809,15 +1831,6 @@ mips_symbol_insns_1 (enum mips_symbol_ty /* The constant must be loaded using ADDIUPC or DADDIUPC first. */ return 0; - case SYMBOL_FORCE_TO_MEM: - /* LEAs will be converted into constant-pool references by - mips_reorg. */ - if (mode == MAX_MACHINE_MODE) - return 1; - - /* The constant must be loaded and then dereferenced. */ - return 0; - case SYMBOL_GOT_DISP: /* The constant will have to be loaded from the GOT before it is used in an address. */ @@ -1850,7 +1863,6 @@ mips_symbol_insns_1 (enum mips_symbol_ty case SYMBOL_GOTOFF_DISP: case SYMBOL_GOTOFF_CALL: case SYMBOL_GOTOFF_LOADGP: - case SYMBOL_32_HIGH: case SYMBOL_64_HIGH: case SYMBOL_64_MID: case SYMBOL_64_LOW: @@ -1925,9 +1937,12 @@ mips_cannot_force_const_mem (enum machin return true; split_const (x, &base, &offset); - if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type) - && type != SYMBOL_FORCE_TO_MEM) + if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type)) { + /* See whether we explicitly want these symbols in the pool. */ + if (mips_use_pcrel_pool_p[(int) type]) + return false; + /* The same optimization as for CONST_INT. */ if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0) return true; @@ -2822,13 +2837,18 @@ mips_call_tls_get_addr (rtx sym, enum mi static rtx mips_get_tp (void) { - rtx tp; + rtx tp, fn; tp = gen_reg_rtx (Pmode); - if (Pmode == DImode) - emit_insn (gen_tls_get_tp_di (tp)); + if (TARGET_MIPS16) + { + fn = mips16_stub_function ("__mips16_rdhwr"); + if (!call_insn_operand (fn, VOIDmode)) + fn = force_reg (Pmode, fn); + emit_insn (PMODE_INSN (gen_tls_get_tp_mips16, (tp, fn))); + } else - emit_insn (gen_tls_get_tp_si (tp)); + emit_insn (PMODE_INSN (gen_tls_get_tp, (tp))); return tp; } @@ -2839,15 +2859,9 @@ mips_get_tp (void) static rtx mips_legitimize_tls_address (rtx loc) { - rtx dest, insn, v0, tp, tmp1, tmp2, eqv; + rtx dest, insn, v0, tp, tmp1, tmp2, eqv, offset; 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,9 +2889,15 @@ 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)); + offset = mips_unspec_address (loc, SYMBOL_DTPREL); + if (mips_split_p[SYMBOL_DTPREL]) + { + tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL); + dest = gen_rtx_LO_SUM (Pmode, tmp2, offset); + } + else + dest = expand_binop (Pmode, add_optab, tmp1, offset, + 0, 0, OPTAB_DIRECT); break; case TLS_MODEL_INITIAL_EXEC: @@ -2893,10 +2913,16 @@ 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)); + tmp1 = mips_get_tp (); + offset = mips_unspec_address (loc, SYMBOL_TPREL); + if (mips_split_p[SYMBOL_TPREL]) + { + tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_TPREL); + dest = gen_rtx_LO_SUM (Pmode, tmp2, offset); + } + else + dest = expand_binop (Pmode, add_optab, tmp1, offset, + 0, 0, OPTAB_DIRECT); break; default: @@ -5866,18 +5892,6 @@ struct mips16_stub { }; static struct mips16_stub *mips16_stubs; -/* Return a SYMBOL_REF for a MIPS16 function called NAME. */ - -static rtx -mips16_stub_function (const char *name) -{ - rtx x; - - x = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); - SYMBOL_REF_FLAGS (x) |= (SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION); - return x; -} - /* Return the two-character string that identifies floating-point return mode MODE in the name of a MIPS16 function stub. */ @@ -7192,38 +7206,44 @@ mips_init_relocs (void) { memset (mips_split_p, '\0', sizeof (mips_split_p)); memset (mips_split_hi_p, '\0', sizeof (mips_split_hi_p)); + memset (mips_use_pcrel_pool_p, '\0', sizeof (mips_use_pcrel_pool_p)); memset (mips_hi_relocs, '\0', sizeof (mips_hi_relocs)); memset (mips_lo_relocs, '\0', sizeof (mips_lo_relocs)); - if (ABI_HAS_64BIT_SYMBOLS) + if (TARGET_MIPS16_PCREL_LOADS) + mips_use_pcrel_pool_p[SYMBOL_ABSOLUTE] = true; + else { - if (TARGET_EXPLICIT_RELOCS) + if (ABI_HAS_64BIT_SYMBOLS) { - mips_split_p[SYMBOL_64_HIGH] = true; - mips_hi_relocs[SYMBOL_64_HIGH] = "%highest("; - mips_lo_relocs[SYMBOL_64_HIGH] = "%higher("; - - mips_split_p[SYMBOL_64_MID] = true; - mips_hi_relocs[SYMBOL_64_MID] = "%higher("; - mips_lo_relocs[SYMBOL_64_MID] = "%hi("; - - mips_split_p[SYMBOL_64_LOW] = true; - mips_hi_relocs[SYMBOL_64_LOW] = "%hi("; - mips_lo_relocs[SYMBOL_64_LOW] = "%lo("; + if (TARGET_EXPLICIT_RELOCS) + { + mips_split_p[SYMBOL_64_HIGH] = true; + mips_hi_relocs[SYMBOL_64_HIGH] = "%highest("; + mips_lo_relocs[SYMBOL_64_HIGH] = "%higher("; + + mips_split_p[SYMBOL_64_MID] = true; + mips_hi_relocs[SYMBOL_64_MID] = "%higher("; + mips_lo_relocs[SYMBOL_64_MID] = "%hi("; + + mips_split_p[SYMBOL_64_LOW] = true; + mips_hi_relocs[SYMBOL_64_LOW] = "%hi("; + mips_lo_relocs[SYMBOL_64_LOW] = "%lo("; - mips_split_p[SYMBOL_ABSOLUTE] = true; - mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; + mips_split_p[SYMBOL_ABSOLUTE] = true; + mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; + } } - } - else - { - if (TARGET_EXPLICIT_RELOCS || mips_split_addresses_p () || TARGET_MIPS16) + else { - mips_split_p[SYMBOL_ABSOLUTE] = true; - mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi("; - mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; - - mips_lo_relocs[SYMBOL_32_HIGH] = "%hi("; + if (TARGET_EXPLICIT_RELOCS + || mips_split_addresses_p () + || TARGET_MIPS16) + { + mips_split_p[SYMBOL_ABSOLUTE] = true; + mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi("; + mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo("; + } } } @@ -7291,16 +7311,23 @@ 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("; - - mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel("; + if (TARGET_MIPS16_PCREL_LOADS) + { + mips_use_pcrel_pool_p[SYMBOL_DTPREL] = true; + mips_use_pcrel_pool_p[SYMBOL_TPREL] = true; + } + else + { + mips_split_p[SYMBOL_DTPREL] = true; + mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi("; + mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo("; - 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("; + } + mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel("; mips_lo_relocs[SYMBOL_HALF] = "%half("; } @@ -8082,6 +8109,29 @@ mips_output_ascii (FILE *stream, const c fprintf (stream, "\"\n"); } +/* Return the pseudo-op for full SYMBOL_(D)TPREL address *ADDR. + Update *ADDR with the operand that should be printed. */ + +const char * +mips_output_tls_reloc_directive (rtx *addr) +{ + enum mips_symbol_type type; + + type = mips_classify_symbolic_expression (*addr, SYMBOL_CONTEXT_LEA); + *addr = mips_strip_unspec_address (*addr); + switch (type) + { + case SYMBOL_DTPREL: + return Pmode == SImode ? ".dtprelword\t%0" : ".dtpreldword\t%0"; + + case SYMBOL_TPREL: + return Pmode == SImode ? ".tprelword\t%0" : ".tpreldword\t%0"; + + default: + gcc_unreachable (); + } +} + /* Emit either a label, .comm, or .lcomm directive. When using assembler macros, mark the symbol as written so that mips_asm_output_external won't emit an .extern for it. STREAM is the output file, NAME is the @@ -13783,6 +13833,10 @@ mips16_rewrite_pool_refs (rtx *x, void * return -1; } + /* Don't rewrite the __mips16_rdwr symbol. */ + if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS_GET_TP) + return -1; + if (TARGET_MIPS16_TEXT_LOADS) mips16_rewrite_pool_constant (info->pool, x); Index: gcc/config/mips/predicates.md =================================================================== --- gcc/config/mips/predicates.md 2012-01-08 08:43:13.000000000 +0000 +++ gcc/config/mips/predicates.md 2012-01-08 10:12:57.000000000 +0000 @@ -288,12 +288,20 @@ (define_predicate "absolute_symbolic_ope && type == SYMBOL_ABSOLUTE); }) +(define_predicate "symbolic_operand_with_high" + (match_code "const,symbol_ref,label_ref") +{ + enum mips_symbol_type type; + return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &type) + && mips_hi_relocs[(int) type]); +}) + (define_predicate "force_to_mem_operand" (match_code "const,symbol_ref,label_ref") { enum mips_symbol_type symbol_type; return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &symbol_type) - && symbol_type == SYMBOL_FORCE_TO_MEM); + && mips_use_pcrel_pool_p[(int) symbol_type]); }) (define_predicate "got_disp_operand" @@ -312,6 +320,14 @@ (define_predicate "got_page_ofst_operand && 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 2012-01-08 08:43:13.000000000 +0000 +++ gcc/config/mips/mips.md 2012-01-08 10:45:39.000000000 +0000 @@ -103,6 +103,7 @@ (define_c_enum "unspec" [ UNSPEC_LOAD_GOT UNSPEC_TLS_LDM UNSPEC_TLS_GET_TP + UNSPEC_UNSHIFTED_HIGH ;; MIPS16 constant pools. UNSPEC_ALIGN @@ -135,6 +136,7 @@ (define_c_enum "unspec" [ (define_constants [(TLS_GET_TP_REGNUM 3) + (PIC_FUNCTION_ADDR_REGNUM 25) (RETURN_ADDR_REGNUM 31) (CPRESTORE_SLOT_REGNUM 76) (GOT_VERSION_REGNUM 79) @@ -3924,14 +3926,19 @@ (define_insn_and_split "*lea64" ;; ;; on MIPS16 targets. (define_split - [(set (match_operand:SI 0 "d_operand") - (high:SI (match_operand:SI 1 "absolute_symbolic_operand")))] + [(set (match_operand:P 0 "d_operand") + (high:P (match_operand:P 1 "symbolic_operand_with_high")))] "TARGET_MIPS16 && reload_completed" - [(set (match_dup 0) (match_dup 2)) - (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))] -{ - operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH); -}) + [(set (match_dup 0) (unspec:P [(match_dup 1)] UNSPEC_UNSHIFTED_HIGH)) + (set (match_dup 0) (ashift:P (match_dup 0) (const_int 16)))]) + +(define_insn "*unshifted_high" + [(set (match_operand:P 0 "d_operand" "=d") + (unspec:P [(match_operand:P 1 "symbolic_operand_with_high")] + UNSPEC_UNSHIFTED_HIGH))] + "" + "li\t%0,%h1" + [(set_attr "extended_mips16" "yes")]) ;; Insns to fetch a symbol from a big GOT. @@ -6492,6 +6499,14 @@ (define_expand "movcc" ;; .................... ;; +(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" + { return mips_output_tls_reloc_directive (&operands[0]); } + [(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 +6608,49 @@ (define_insn "*tls_get_tp__split" ; 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 [(match_operand:P 1 "call_insn_operand" "dS")] + UNSPEC_TLS_GET_TP)) + (clobber (reg:P TLS_GET_TP_REGNUM)) + (clobber (reg:P PIC_FUNCTION_ADDR_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_FUNCTION_ADDR_REGNUM)) + (clobber (reg:P RETURN_ADDR_REGNUM))]) + (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))] + "" + [(set_attr "type" "multi") + (set_attr "length" "16") + (set_attr "mode" "")]) + +(define_insn "*tls_get_tp_mips16_call_" + [(set (reg:P TLS_GET_TP_REGNUM) + (unspec:P [(match_operand:P 0 "call_insn_operand" "dS")] + UNSPEC_TLS_GET_TP)) + (clobber (reg:P PIC_FUNCTION_ADDR_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 "length" "12") + (set_attr "mode" "")]) ;; Synchronization instructions. Index: gcc/testsuite/gcc.target/mips/code-readable-2.c =================================================================== --- gcc/testsuite/gcc.target/mips/code-readable-2.c 2012-01-08 10:13:04.000000000 +0000 +++ gcc/testsuite/gcc.target/mips/code-readable-2.c 2012-01-08 10:15:24.000000000 +0000 @@ -26,8 +26,7 @@ bar (void) /* { dg-final { scan-assembler-not "\tla\t" } } */ /* { dg-final { scan-assembler-not "\t\\.half\t" } } */ -/* { dg-final { scan-assembler "%hi\\(\[^)\]*L" } } */ -/* { dg-final { scan-assembler "%lo\\(\[^)\]*L" } } */ +/* { dg-final { scan-assembler "\t\\.word\t\[^\n\]*L" } } */ /* { dg-final { scan-assembler "\t\\.word\tk\n" } } */ /* { dg-final { scan-assembler-not "%hi\\(k\\)" } } */ Index: libgcc/config/mips/libgcc-mips16.ver =================================================================== --- libgcc/config/mips/libgcc-mips16.ver 2012-01-08 08:43:13.000000000 +0000 +++ libgcc/config/mips/libgcc-mips16.ver 2012-01-08 10:12:57.000000000 +0000 @@ -84,3 +84,7 @@ GCC_4.4.0 { __mips16_call_stub_dc_9 __mips16_call_stub_dc_10 } + +GCC_4.7.0 { + __mips16_rdhwr +} Index: libgcc/config/mips/mips16.S =================================================================== --- libgcc/config/mips/mips16.S 2012-01-08 08:43:13.000000000 +0000 +++ libgcc/config/mips/mips16.S 2012-01-08 10:12:57.000000000 +0000 @@ -709,4 +709,15 @@ CALL_STUB_RET (__mips16_call_stub_dc_9, CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC) #endif #endif /* !__mips_single_float */ + +#ifdef L_m16rdhwr +STARTFN (__mips16_rdhwr) + .set push + .set mips32r2 + .set noreorder + rdhwr $3,$29 + .set pop + j $31 + ENDFN (__mips16_rdhwr) +#endif #endif Index: libgcc/config/mips/t-mips16 =================================================================== --- libgcc/config/mips/t-mips16 2012-01-08 08:43:13.000000000 +0000 +++ libgcc/config/mips/t-mips16 2012-01-08 10:12:57.000000000 +0000 @@ -36,7 +36,8 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m1 _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \ _m16stubsc9 _m16stubsc10 \ _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \ - _m16stubdc9 _m16stubdc10 + _m16stubdc9 _m16stubdc10 \ + _m16rdhwr SYNC = yes SYNC_CFLAGS = -mno-mips16