From 95ce7613d537f5a3e9e36da0ca6aa752f60da8e0 Mon Sep 17 00:00:00 2001 From: Chung-Lin Tang Date: Thu, 20 Feb 2014 16:35:10 +0000 Subject: [PATCH] nios2.md (unspec): Add UNSPEC_PIC_GOTOFF_SYM enum. 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. From-SVN: r207965 --- gcc/ChangeLog | 24 ++++ gcc/config/nios2/nios2.c | 147 ++++++++++++++++------ gcc/config/nios2/nios2.md | 1 + gcc/testsuite/ChangeLog | 5 + gcc/testsuite/gcc.target/nios2/biggot-1.c | 67 ++++++++++ gcc/testsuite/gcc.target/nios2/biggot-2.c | 68 ++++++++++ libgcc/ChangeLog | 7 ++ libgcc/config/nios2/crti.S | 2 - libgcc/config/nios2/crtn.S | 8 +- libgcc/config/nios2/t-nios2 | 3 + 10 files changed, 286 insertions(+), 46 deletions(-) create mode 100644 gcc/testsuite/gcc.target/nios2/biggot-1.c create mode 100644 gcc/testsuite/gcc.target/nios2/biggot-2.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f4cb359b0ea..9333fb6804c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,27 @@ +2014-02-20 Chung-Lin Tang + Sandra Loosemore + + * 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. + 2014-02-20 Richard Biener * tree-cfg.c (replace_uses_by): Mark altered BBs before diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c index b7e629c71ca..19eedf4bb8c 100644 --- a/gcc/config/nios2/nios2.c +++ b/gcc/config/nios2/nios2.c @@ -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 ATTRIBUTE_UNUSED) 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, const char *endp, } 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; } -static rtx -nios2_unspec_address (rtx loc, rtx base_reg, int unspec) +/* Return true for large offsets requiring hiadj/lo relocation pairs. */ +static bool +nios2_large_offset_p (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); + 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_offset (rtx loc, int unspec) +{ + 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,6 +1655,15 @@ nios2_section_type_flags (tree decl, const char *name, int reloc) 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. */ @@ -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 ATTRIBUTE_UNUSED, 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 machine_mode mode) } 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 letter) 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) diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md index 530ce2dcf1a..b5b599ece33 100644 --- a/gcc/config/nios2/nios2.md +++ b/gcc/config/nios2/nios2.md @@ -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 diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9331b754dfc..256c885ad96 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2014-02-20 Sandra Loosemore + + * gcc.target/nios2/biggot-1.c: New. + * gcc.target/nios2/biggot-2.c: New. + 2014-02-20 Martin Jambor PR ipa/55260 diff --git a/gcc/testsuite/gcc.target/nios2/biggot-1.c b/gcc/testsuite/gcc.target/nios2/biggot-1.c new file mode 100644 index 00000000000..49b14ed0c28 --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/biggot-1.c @@ -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; +} diff --git a/gcc/testsuite/gcc.target/nios2/biggot-2.c b/gcc/testsuite/gcc.target/nios2/biggot-2.c new file mode 100644 index 00000000000..7a34d3f6dec --- /dev/null +++ b/gcc/testsuite/gcc.target/nios2/biggot-2.c @@ -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; +} diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog index 4c3ff9181f6..1dae0204892 100644 --- a/libgcc/ChangeLog +++ b/libgcc/ChangeLog @@ -1,3 +1,10 @@ +2014-02-20 Sandra Loosemore + Chung-Lin Tang + + * config/nios2/t-nios2 (CRTSTUFF_T_CFLAGS): Add -mno-gpopt. + * config/nios2/crti.S: Remove .file directive. + * config/nios2/crtn.S: Likewise. + 2014-02-18 Kai Tietz Jonathan Schleifer diff --git a/libgcc/config/nios2/crti.S b/libgcc/config/nios2/crti.S index 9f5d523092b..f21346ce177 100644 --- a/libgcc/config/nios2/crti.S +++ b/libgcc/config/nios2/crti.S @@ -36,8 +36,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see See crt0.s for the code that calls init and fini. */ - .file "crti.asm" - .section ".init" .align 2 .global _init diff --git a/libgcc/config/nios2/crtn.S b/libgcc/config/nios2/crtn.S index a66b44971c2..54c9cb638cf 100644 --- a/libgcc/config/nios2/crtn.S +++ b/libgcc/config/nios2/crtn.S @@ -23,12 +23,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see /* 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) diff --git a/libgcc/config/nios2/t-nios2 b/libgcc/config/nios2/t-nios2 index 320dedfe826..7a81a7f021f 100644 --- a/libgcc/config/nios2/t-nios2 +++ b/libgcc/config/nios2/t-nios2 @@ -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