From patchwork Thu Feb 20 16:36:14 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chung-Lin Tang X-Patchwork-Id: 322260 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]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id C5EF62C0256 for ; Fri, 21 Feb 2014 03:36:23 +1100 (EST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; q=dns; s=default; b=cIRqY85r6K/RHNNPQdSG5i+aa+UHJhHc/grNeP1PRq8 qes3ePC739wWUX3a5j0fBy7xdLhh1yBA+Hb8PjRpvvmEG7iCWG7KkcfGbV9c8jnJ /Nfydvd/rCzvdYfk7qzae/vSv/I0glqcuY7rjHUge6IOb88Cp/A/KYSbaLe7Nxag = DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender :message-id:date:from:mime-version:to:cc:subject:content-type; s=default; bh=IYz8r9k5/5tb/KV8feEbNDVizX8=; b=aDP/w+LfG9cN1QFbG XBfNDZuZzmf+h7nnTIPfAVflPpwwgFf5mdUZeAldJNfnX1+CSv0xTkYFpkyH1D0a aGH7II607ZOGFptZ5GwV4/NLMnnP0dqh9I7+ZXv824j+uWzOK+dYUQLYNXeAbRYR cN6cFgfLdHd73bwnKhccY2GKx4= Received: (qmail 11091 invoked by alias); 20 Feb 2014 16:36:15 -0000 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 Received: (qmail 11080 invoked by uid 89); 20 Feb 2014 16:36:14 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.8 required=5.0 tests=AWL, BAYES_00, KAM_STOCKGEN autolearn=no version=3.3.2 X-HELO: relay1.mentorg.com Received: from relay1.mentorg.com (HELO relay1.mentorg.com) (192.94.38.131) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Thu, 20 Feb 2014 16:36:13 +0000 Received: from svr-orw-exc-10.mgc.mentorg.com ([147.34.98.58]) by relay1.mentorg.com with esmtp id 1WGWbY-0004Iz-DE from ChungLin_Tang@mentor.com for gcc-patches@gcc.gnu.org; Thu, 20 Feb 2014 08:36:08 -0800 Received: from SVR-ORW-FEM-05.mgc.mentorg.com ([147.34.97.43]) by SVR-ORW-EXC-10.mgc.mentorg.com with Microsoft SMTPSVC(6.0.3790.4675); Thu, 20 Feb 2014 08:36:08 -0800 Received: from [0.0.0.0] (147.34.91.1) by svr-orw-fem-05.mgc.mentorg.com (147.34.97.43) with Microsoft SMTP Server id 14.2.247.3; Thu, 20 Feb 2014 08:35:22 -0800 Message-ID: <53062EFE.2050105@codesourcery.com> Date: Fri, 21 Feb 2014 00:36:14 +0800 From: Chung-Lin Tang User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.3.0 MIME-Version: 1.0 To: gcc-patches CC: Sandra Loosemore Subject: [PATCH, nios2] Large -fPIC support X-IsSubscribed: yes This patch adds large GOT support for the Nios II backend. Tested by running glibc tests with -fPIC forced on. A few smaller libgcc fixes are also included as well. Patch committed. Chung-Lin 2014-02-20 Chung-Lin Tang Sandra Loosemore gcc/ * config/nios2/nios2.md (unspec): Add UNSPEC_PIC_GOTOFF_SYM enum. * config/nios2/nios2.c (nios2_function_profiler): Add -fPIC (flag_pic == 2) support. (nios2_handle_custom_fpu_cfg): Fix warning parameter. (nios2_large_offset_p): New function. (nios2_unspec_reloc_p): Move up position, update to use nios2_large_offset_p. (nios2_unspec_address): Remove function. (nios2_unspec_offset): New function. (nios2_large_got_address): New function. (nios2_got_address): Add large offset support. (nios2_legitimize_tls_address): Update usage of removed and new functions. (nios2_symbol_binds_local_p): New function. (nios2_load_pic_address): Add -fPIC (flag_pic == 2) support. (nios2_legitimize_address): Update to use nios2_large_offset_p. (nios2_emit_move_sequence): Avoid legitimizing (const (unspec ...)). (nios2_print_operand): Merge H/L processing, add hiadj/lo processing for (const (unspec ...)). (nios2_unspec_reloc_name): Add UNSPEC_PIC_GOTOFF_SYM case. gcc/testsuite/ * gcc.target/nios2/biggot-1.c: New. * gcc.target/nios2/biggot-2.c: New. libgcc/ * config/nios2/t-nios2 (CRTSTUFF_T_CFLAGS): Add -mno-gpopt. * config/nios2/crti.S: Remove .file directive. * config/nios2/crtn.S: Likewise. Index: gcc/config/nios2/nios2.c =================================================================== --- gcc/config/nios2/nios2.c (revision 207964) +++ gcc/config/nios2/nios2.c (working copy) @@ -664,7 +664,7 @@ void nios2_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED) { fprintf (file, "\tmov\tr8, ra\n"); - if (flag_pic) + if (flag_pic == 1) { fprintf (file, "\tnextpc\tr2\n"); fprintf (file, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n"); @@ -673,6 +673,18 @@ nios2_function_profiler (FILE *file, int labelno A fprintf (file, "\tldw\tr2, %%call(_mcount)(r2)\n"); fprintf (file, "\tcallr\tr2\n"); } + else if (flag_pic == 2) + { + fprintf (file, "\tnextpc\tr2\n"); + fprintf (file, "\t1: movhi\tr3, %%hiadj(_gp_got - 1b)\n"); + fprintf (file, "\taddi\tr3, r3, %%lo(_gp_got - 1b)\n"); + fprintf (file, "\tadd\tr2, r2, r3\n"); + fprintf (file, "\tmovhi\tr3, %%call_hiadj(_mcount)\n"); + fprintf (file, "\taddi\tr3, %%call_lo(_mcount)\n"); + fprintf (file, "\tadd\tr3, r2, r3\n"); + fprintf (file, "\tldw\tr2, 0(r3)\n"); + fprintf (file, "\tcallr\tr2\n"); + } else fprintf (file, "\tcall\t_mcount\n"); fprintf (file, "\tmov\tra, r8\n"); @@ -920,7 +932,7 @@ nios2_handle_custom_fpu_cfg (const char *cfgname, } else warning (0, "ignoring unrecognized switch %<-mcustom-fpu-cfg%> " - "value %<%s%>", cfg); + "value %<%s%>", cfgname); /* Guard against errors in the standard configurations. */ nios2_custom_check_insns (); @@ -1116,20 +1128,64 @@ nios2_call_tls_get_addr (rtx ti) return ret; } +/* Return true for large offsets requiring hiadj/lo relocation pairs. */ +static bool +nios2_large_offset_p (int unspec) +{ + gcc_assert (nios2_unspec_reloc_name (unspec) != NULL); + + if (flag_pic == 2 + /* FIXME: TLS GOT offset relocations will eventually also get this + treatment, after binutils support for those are also completed. */ + && (unspec == UNSPEC_PIC_SYM || unspec == UNSPEC_PIC_CALL_SYM)) + return true; + + /* 'gotoff' offsets are always hiadj/lo. */ + if (unspec == UNSPEC_PIC_GOTOFF_SYM) + return true; + + return false; +} + +/* Return true for conforming unspec relocations. Also used in + constraints.md and predicates.md. */ +bool +nios2_unspec_reloc_p (rtx op) +{ + return (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == UNSPEC + && ! nios2_large_offset_p (XINT (XEXP (op, 0), 1))); +} + +/* Helper to generate unspec constant. */ static rtx -nios2_unspec_address (rtx loc, rtx base_reg, int unspec) +nios2_unspec_offset (rtx loc, int unspec) { - rtx unspec_offset = - gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc), - unspec)); - return gen_rtx_PLUS (Pmode, base_reg, unspec_offset); + return gen_rtx_CONST (Pmode, gen_rtx_UNSPEC (Pmode, gen_rtvec (1, loc), + unspec)); } +/* Generate GOT pointer based address with large offset. */ static rtx +nios2_large_got_address (rtx sym, rtx offset) +{ + rtx addr = gen_reg_rtx (Pmode); + emit_insn (gen_add3_insn (addr, pic_offset_table_rtx, + force_reg (Pmode, offset))); + return addr; +} + +/* Generate a GOT pointer based address. */ +static rtx nios2_got_address (rtx loc, int unspec) { + rtx offset = nios2_unspec_offset (loc, unspec); crtl->uses_pic_offset_table = 1; - return nios2_unspec_address (loc, pic_offset_table_rtx, unspec); + + if (nios2_large_offset_p (unspec)) + return nios2_large_got_address (loc, offset); + + return gen_rtx_PLUS (Pmode, pic_offset_table_rtx, offset); } /* Generate the code to access LOC, a thread local SYMBOL_REF. The @@ -1151,8 +1207,8 @@ nios2_legitimize_tls_address (rtx loc) case TLS_MODEL_LOCAL_DYNAMIC: tmp = gen_reg_rtx (Pmode); emit_move_insn (tmp, nios2_got_address (loc, UNSPEC_ADD_TLS_LDM)); - return nios2_unspec_address (loc, nios2_call_tls_get_addr (tmp), - UNSPEC_ADD_TLS_LDO); + return gen_rtx_PLUS (Pmode, nios2_call_tls_get_addr (tmp), + nios2_unspec_offset (loc, UNSPEC_ADD_TLS_LDO)); case TLS_MODEL_INITIAL_EXEC: tmp = gen_reg_rtx (Pmode); @@ -1163,8 +1219,8 @@ nios2_legitimize_tls_address (rtx loc) case TLS_MODEL_LOCAL_EXEC: tp = gen_rtx_REG (Pmode, TP_REGNO); - return nios2_unspec_address (loc, tp, UNSPEC_ADD_TLS_LE); - + return gen_rtx_PLUS (Pmode, tp, + nios2_unspec_offset (loc, UNSPEC_ADD_TLS_LE)); default: gcc_unreachable (); } @@ -1599,7 +1655,16 @@ nios2_section_type_flags (tree decl, const char *n return flags; } +/* Return true if SYMBOL_REF X binds locally. */ +static bool +nios2_symbol_binds_local_p (const_rtx x) +{ + return (SYMBOL_REF_DECL (x) + ? targetm.binds_local_p (SYMBOL_REF_DECL (x)) + : SYMBOL_REF_LOCAL_P (x)); +} + /* Position independent code related. */ /* Emit code to load the PIC register. */ @@ -1616,8 +1681,13 @@ nios2_load_pic_register (void) static rtx nios2_load_pic_address (rtx sym, int unspec) { - rtx gotaddr = nios2_got_address (sym, unspec); - return gen_const_mem (Pmode, gotaddr); + if (flag_pic == 2 + && GET_CODE (sym) == SYMBOL_REF + && nios2_symbol_binds_local_p (sym)) + /* Under -fPIC, generate a GOTOFF address for local symbols. */ + return nios2_got_address (sym, UNSPEC_PIC_GOTOFF_SYM); + + return gen_const_mem (Pmode, nios2_got_address (sym, unspec)); } /* Nonzero if the constant value X is a legitimate general operand @@ -1626,6 +1696,11 @@ nios2_load_pic_address (rtx sym, int unspec) bool nios2_legitimate_pic_operand_p (rtx x) { + if (GET_CODE (x) == CONST + && GET_CODE (XEXP (x, 0)) == UNSPEC + && nios2_large_offset_p (XINT (XEXP (x, 0), 1))) + return true; + return ! (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF || GET_CODE (x) == CONST); } @@ -1701,7 +1776,7 @@ nios2_legitimize_address (rtx x, rtx oldx ATTRIBUT rtx unspec, offset, reg = XEXP (x, 0); split_const (XEXP (x, 1), &unspec, &offset); if (GET_CODE (unspec) == UNSPEC - && nios2_unspec_reloc_name (XINT (unspec, 1)) != NULL + && !nios2_large_offset_p (XINT (unspec, 1)) && offset != const0_rtx) { unspec = copy_rtx (unspec); @@ -1728,7 +1803,8 @@ nios2_emit_move_sequence (rtx *operands, enum mach } if (GET_CODE (from) == SYMBOL_REF || GET_CODE (from) == LABEL_REF - || GET_CODE (from) == CONST) + || (GET_CODE (from) == CONST + && GET_CODE (XEXP (from, 0)) != UNSPEC)) from = nios2_legitimize_constant_address (from); operands[0] = to; @@ -1845,20 +1921,23 @@ nios2_print_operand (FILE *file, rtx op, int lette output_addr_const (file, op); return; } - else if (letter == 'H') - { - fprintf (file, "%%hiadj("); + else if (letter == 'H' || letter == 'L') + { + fprintf (file, "%%"); + if (GET_CODE (op) == CONST + && GET_CODE (XEXP (op, 0)) == UNSPEC) + { + rtx unspec = XEXP (op, 0); + int unspec_reloc = XINT (unspec, 1); + gcc_assert (nios2_large_offset_p (unspec_reloc)); + fprintf (file, "%s_", nios2_unspec_reloc_name (unspec_reloc)); + op = XVECEXP (unspec, 0, 0); + } + fprintf (file, letter == 'H' ? "hiadj(" : "lo("); output_addr_const (file, op); fprintf (file, ")"); return; - } - else if (letter == 'L') - { - fprintf (file, "%%lo("); - output_addr_const (file, op); - fprintf (file, ")"); - return; - } + } break; case SUBREG: @@ -1910,6 +1989,8 @@ nios2_unspec_reloc_name (int unspec) return "got"; case UNSPEC_PIC_CALL_SYM: return "call"; + case UNSPEC_PIC_GOTOFF_SYM: + return "gotoff"; case UNSPEC_LOAD_TLS_IE: return "tls_ie"; case UNSPEC_ADD_TLS_LE: @@ -1925,16 +2006,6 @@ nios2_unspec_reloc_name (int unspec) } } -/* Return true for conforming unspec relocations. Also used in - constraints.md and predicates.md. */ -bool -nios2_unspec_reloc_p (rtx op) -{ - return (GET_CODE (op) == CONST - && GET_CODE (XEXP (op, 0)) == UNSPEC - && nios2_unspec_reloc_name (XINT (XEXP (op, 0), 1)) != NULL); -} - /* Implement TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA. */ static bool nios2_output_addr_const_extra (FILE *file, rtx op) Index: gcc/config/nios2/nios2.md =================================================================== --- gcc/config/nios2/nios2.md (revision 207964) +++ gcc/config/nios2/nios2.md (working copy) @@ -73,6 +73,7 @@ UNSPEC_LOAD_GOT_REGISTER UNSPEC_PIC_SYM UNSPEC_PIC_CALL_SYM + UNSPEC_PIC_GOTOFF_SYM UNSPEC_TLS UNSPEC_TLS_LDM UNSPEC_LOAD_TLS_IE Index: gcc/testsuite/gcc.target/nios2/biggot-1.c =================================================================== --- gcc/testsuite/gcc.target/nios2/biggot-1.c (revision 0) +++ gcc/testsuite/gcc.target/nios2/biggot-1.c (revision 0) @@ -0,0 +1,67 @@ +/* Check that the GOT pointer is being initialized correctly to allow + access to the full 64K maximum GOT size for -fpic, rather than only 32K + (which would happen if the GOT pointer points to the base of the GOT, + as the GOT16 and CALL16 relocations are signed). */ + +/* { dg-options "-fpic" } */ +/* { dg-do run { target nios2-*-linux-gnu } } */ + +extern void abort (void); + +static int n = 0; + +void +doit (int m) +{ + if (m != n) + abort (); + n++; +} + +#define X(N) \ + void f_##N (void) { doit (0x##N); } + +#define F(N) f_##N (); + +#define A(N) \ + X(N##0) X(N##1) X(N##2) X(N##3) X(N##4) X(N##5) X(N##6) X(N##7) \ + X(N##8) X(N##9) X(N##a) X(N##b) X(N##c) X(N##d) X(N##e) X(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define B(N) \ + A(N##0) A(N##1) A(N##2) A(N##3) A(N##4) A(N##5) A(N##6) A(N##7) \ + A(N##8) A(N##9) A(N##a) A(N##b) A(N##c) A(N##d) A(N##e) A(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define C(N) \ + B(N##0) B(N##1) B(N##2) B(N##3) B(N##4) B(N##5) B(N##6) B(N##7) \ + B(N##8) B(N##9) B(N##a) B(N##b) B(N##c) B(N##d) B(N##e) B(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define D(N) \ + C(N##0) C(N##1) C(N##2) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) \ + } + +/* This defines 16x16x16x3 leaf functions, requiring something over + 48K of GOT space overall. */ +D(0) + +int +main (void) +{ + f_0 (); + if (n != 16*16*16*3) + abort (); + return 0; +} Index: gcc/testsuite/gcc.target/nios2/biggot-2.c =================================================================== --- gcc/testsuite/gcc.target/nios2/biggot-2.c (revision 0) +++ gcc/testsuite/gcc.target/nios2/biggot-2.c (revision 0) @@ -0,0 +1,68 @@ +/* Check that a program that requires large-GOT support builds and + executes without error. This program defines a very large number + of leaf functions; compiled with -fPIC, they all require GOT + entries, which will overflow the range addressible by 16-bit -fpic + offsets by about a factor of 2. */ + +/* { dg-options "-fPIC" } */ +/* { dg-do run { target nios2-*-linux-gnu } } */ + +extern void abort (void); + +static int n = 0; + +void +doit (int m) +{ + if (m != n) + abort (); + n++; +} + +#define X(N) \ + void f_##N (void) { doit (0x##N); } + +#define F(N) f_##N (); + +#define A(N) \ + X(N##0) X(N##1) X(N##2) X(N##3) X(N##4) X(N##5) X(N##6) X(N##7) \ + X(N##8) X(N##9) X(N##a) X(N##b) X(N##c) X(N##d) X(N##e) X(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define B(N) \ + A(N##0) A(N##1) A(N##2) A(N##3) A(N##4) A(N##5) A(N##6) A(N##7) \ + A(N##8) A(N##9) A(N##a) A(N##b) A(N##c) A(N##d) A(N##e) A(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define C(N) \ + B(N##0) B(N##1) B(N##2) B(N##3) B(N##4) B(N##5) B(N##6) B(N##7) \ + B(N##8) B(N##9) B(N##a) B(N##b) B(N##c) B(N##d) B(N##e) B(N##f) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + F(N##8) F(N##9) F(N##a) F(N##b) F(N##c) F(N##d) F(N##e) F(N##f) \ + } + +#define D(N) \ + C(N##0) C(N##1) C(N##2) C(N##3) C(N##4) C(N##5) C(N##6) C(N##7) \ + void f_##N (void) { \ + F(N##0) F(N##1) F(N##2) F(N##3) F(N##4) F(N##5) F(N##6) F(N##7) \ + } + +/* This defines 16x16x16x8 leaf functions, requiring something over + 128K of GOT space overall. */ +D(0) + +int +main (void) +{ + f_0 (); + if (n != 16*16*16*8) + abort (); + return 0; +} Index: libgcc/config/nios2/crti.S =================================================================== --- libgcc/config/nios2/crti.S (revision 207964) +++ libgcc/config/nios2/crti.S (working copy) @@ -36,8 +36,6 @@ see the files COPYING3 and COPYING.RUNTIME respect See crt0.s for the code that calls init and fini. */ - .file "crti.asm" - .section ".init" .align 2 .global _init Index: libgcc/config/nios2/crtn.S =================================================================== --- libgcc/config/nios2/crtn.S (revision 207964) +++ libgcc/config/nios2/crtn.S (working copy) @@ -23,13 +23,9 @@ see the files COPYING3 and COPYING.RUNTIME respect /* This file just makes sure that the .fini and .init sections do in -fact return. Users may put any desired instructions in those sections. -This file is the last thing linked into any executable. -*/ - .file "crtn.asm" + fact return. Users may put any desired instructions in those sections. + This file is the last thing linked into any executable. */ - - .section ".init" ldw ra, 44(sp) ldw r23, 40(sp) Index: libgcc/config/nios2/t-nios2 =================================================================== --- libgcc/config/nios2/t-nios2 (revision 207964) +++ libgcc/config/nios2/t-nios2 (working copy) @@ -3,3 +3,6 @@ LIB2ADD += $(srcdir)/config/nios2/lib2-divmod.c \ $(srcdir)/config/nios2/lib2-divtable.c \ $(srcdir)/config/nios2/lib2-mul.c \ $(srcdir)/config/nios2/tramp.c + +# Disable use of GP-relative addressing in startup code. +CRTSTUFF_T_CFLAGS += -mno-gpopt