aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog24
-rw-r--r--gcc/config/nios2/nios2.c145
-rw-r--r--gcc/config/nios2/nios2.md1
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.target/nios2/biggot-1.c67
-rw-r--r--gcc/testsuite/gcc.target/nios2/biggot-2.c68
-rw-r--r--libgcc/ChangeLog7
-rw-r--r--libgcc/config/nios2/crti.S2
-rw-r--r--libgcc/config/nios2/crtn.S8
-rw-r--r--libgcc/config/nios2/t-nios23
10 files changed, 285 insertions, 45 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index f4cb359..9333fb6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,27 @@
+2014-02-20 Chung-Lin Tang <cltang@codesourcery.com>
+ Sandra Loosemore <sandra@codesourcery.com>
+
+ * 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 <rguenther@suse.de>
* 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 b7e629c..19eedf4 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;
}
+/* 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_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_unspec_address (rtx loc, rtx base_reg, int unspec)
+nios2_large_got_address (rtx sym, rtx offset)
{
- 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);
+ 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(");
- output_addr_const (file, op);
- fprintf (file, ")");
- return;
- }
- else if (letter == 'L')
- {
- fprintf (file, "%%lo(");
+ 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;
- }
+ }
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 530ce2d..b5b599e 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 9331b75..256c885 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,8 @@
+2014-02-20 Sandra Loosemore <sandra@codesourcery.com>
+
+ * gcc.target/nios2/biggot-1.c: New.
+ * gcc.target/nios2/biggot-2.c: New.
+
2014-02-20 Martin Jambor <mjambor@suse.cz>
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 0000000..49b14ed
--- /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 0000000..7a34d3f
--- /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 4c3ff91..1dae020 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,10 @@
+2014-02-20 Sandra Loosemore <sandra@codesourcery.com>
+ Chung-Lin Tang <cltang@codesourcery.com>
+
+ * 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 <ktietz@redhat.com>
Jonathan Schleifer <js@webkeks.org>
diff --git a/libgcc/config/nios2/crti.S b/libgcc/config/nios2/crti.S
index 9f5d523..f21346c 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 a66b449..54c9cb6 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 320dedf..7a81a7f 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