This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [4.5][PATCH][M68K] GCC support for TLS
- From: Maxim Kuvyrkov <maxim at codesourcery dot com>
- To: Andreas Schwab <schwab at suse dot de>
- Cc: gcc-patches <gcc-patches at gcc dot gnu dot org>, Jeff Law <law at redhat dot com>
- Date: Sat, 16 May 2009 16:48:53 +0400
- Subject: Re: [4.5][PATCH][M68K] GCC support for TLS
- References: <497B4C2E.5070801@codesourcery.com> <jehc3n2fn5.fsf@sykes.suse.de>
Andreas Schwab wrote:
There is a problem with emitting @TLS decoration in the assembler
output: the decoration is emitted before the addend, which the assembler
can't parse. The normal way for @GOT decoration is to emit the addend
before it. If you try building libgomp with tls forced to be enabled
you get assembler errors when compiling team.c:
/tmp/ccJozhax.s: Assembler messages:
/tmp/ccJozhax.s:108: Error: syntax error -- statement `pea gomp_tls_data@TLSLE+40(%a0)' ignored
/tmp/ccJozhax.s:183: Error: syntax error -- statement `move.l gomp_tls_data@TLSLE+56(%a0),%a3' ignored
/tmp/ccJozhax.s:252: Error: syntax error -- statement `clr.l gomp_tls_data@TLSLE+56(%a0)' ignored
/tmp/ccJozhax.s:257: Error: syntax error -- statement `move.l gomp_tls_data@TLSLE+36(%a0),%a2' ignored
/tmp/ccJozhax.s:729: Error: syntax error -- statement `move.l gomp_tls_data@TLSLE+36(%a0),%d4' ignored
/tmp/ccJozhax.s:826: Error: syntax error -- statement `move.l gomp_tls_data@TLSLE+28(%a0),28(%a2)' ignored
/tmp/ccJozhax.s:920: Error: syntax error -- statement `move.l gomp_tls_data@TLSLE+28(%a0),28(%a2)' ignored
Andreas,
I apologize for such a long delay.
It turned out that there is no simple fix for the above problem. After
trying a few hacks here and there, I came to using FINAL_PRESCAN_INSN
macro, which looks like the best way of handling the problem; for the
details, see the comment in m68k_final_prescan_insn() function.
Along the way of fixing the problem with decorations, I've cleaned up
handling of GOT symbols, now they are alse wrapped into (const (unspec
[(symbol)])) during legitimization process.
I've updated the patch to the latest trunk and retested it; no new
regressions appeared.
In case you've reviewed the majority of changes already,
fsf-nptl-gcc-23.patch is a diff between previous and current patches;
fsf-nptl-gcc-3.patch is the full patch.
OK to apply?
Thanks,
--
Maxim K.
CodeSourcery
diff -rup -x .svn ./gcc-mainline-2/gcc/config/m68k/m68k.c ./gcc-mainline/gcc/config/m68k/m68k.c
--- ./gcc-mainline-2/gcc/config/m68k/m68k.c 2009-05-15 08:43:46.000000000 -0700
+++ ./gcc-mainline/gcc/config/m68k/m68k.c 2009-05-15 05:06:12.000000000 -0700
@@ -1862,7 +1862,7 @@ m68k_illegitimate_symbolic_constant_p (r
&& !offset_within_block_p (base, INTVAL (offset)))
return true;
}
- return m68k_tls_referenced_p (x);
+ return m68k_tls_reference_p (x, false);
}
/* Return true if X is a legitimate constant address that can reach
@@ -1890,7 +1890,7 @@ m68k_legitimate_constant_address_p (rtx
return false;
}
- return !m68k_tls_referenced_p (x);
+ return !m68k_tls_reference_p (x, false);
}
/* Return true if X is a LABEL_REF for a jump table. Assume that unplaced
@@ -1910,40 +1910,6 @@ m68k_jump_table_ref_p (rtx x)
return x && JUMP_TABLE_DATA_P (x);
}
-/* Unwrap symbol from UNSPEC_RELOC16 and, if unwrap_reloc32_p,
- UNSPEC_RELOC32 wrappers. */
-
-rtx
-m68k_unwrap_symbol (rtx orig, bool unwrap_reloc32_p)
-{
- if (GET_CODE (orig) == CONST)
- {
- rtx x;
-
- x = XEXP (orig, 0);
-
- if (GET_CODE (x) == UNSPEC)
- {
- switch (XINT (x, 1))
- {
- case UNSPEC_RELOC16:
- orig = XVECEXP (x, 0, 0);
- break;
-
- case UNSPEC_RELOC32:
- if (unwrap_reloc32_p)
- orig = XVECEXP (x, 0, 0);
- break;
-
- default:
- break;
- }
- }
- }
-
- return orig;
-}
-
/* Return true if X is a legitimate address for values of mode MODE.
STRICT_P says whether strict checking is needed. If the address
is valid, describe its components in *ADDRESS. */
@@ -1991,18 +1957,12 @@ m68k_decompose_address (enum machine_mod
/* Check for GOT loads. These are (bd,An,Xn) addresses if
TARGET_68020 && flag_pic == 2, otherwise they are (d16,An)
addresses. */
- if (pic_offset_table_rtx != NULL_RTX
- && GET_CODE (x) == PLUS
+ if (GET_CODE (x) == PLUS
&& XEXP (x, 0) == pic_offset_table_rtx)
{
- rtx sym;
-
- /* As we are processing a PLUS, do not unwrap RELOC32
- symbols here; they are invalid in this context. */
- sym = m68k_unwrap_symbol (XEXP (x, 1), false);
-
- if (GET_CODE (sym) == SYMBOL_REF
- || GET_CODE (sym) == LABEL_REF)
+ /* As we are processing a PLUS, do not unwrap RELOC32 symbols --
+ they are invalid in this context. */
+ if (m68k_unwrap_symbol (XEXP (x, 1), false) != XEXP (x, 1))
{
address->base = XEXP (x, 0);
address->offset = XEXP (x, 1);
@@ -2173,7 +2133,6 @@ enum m68k_reloc { RELOC_GOT, RELOC_TLSGD
#define TLS_RELOC_P(RELOC) ((RELOC) != RELOC_GOT)
/* Wrap symbol X into unspec representing relocation RELOC.
- If USE_X_P, use 32-bit relocations, otherwise use 16-bit relocs.
BASE_REG - register that should be added to the result.
TEMP_REG - if non-null, temporary register. */
@@ -2208,16 +2167,9 @@ m68k_wrap_symbol (rtx x, enum m68k_reloc
}
else
{
- /* ??? It would be simplier to wrap 16-bit GOT relocs into UNSPEC too,
- historically, we don't do this, but I'm not aware of any downside
- of such a change. */
- if (reloc != RELOC_GOT)
- /* Wrap X into (const (unspec (X))). */
- {
- x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
- UNSPEC_RELOC16);
- x = gen_rtx_CONST (Pmode, x);
- }
+ x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
+ UNSPEC_RELOC16);
+ x = gen_rtx_CONST (Pmode, x);
x = gen_rtx_PLUS (Pmode, base_reg, x);
}
@@ -2225,6 +2177,127 @@ m68k_wrap_symbol (rtx x, enum m68k_reloc
return x;
}
+/* Helper for m68k_unwrap_symbol.
+ Also, if unwrapping was successful (that is if (ORIG != <return value>)),
+ sets *RELOC_PTR to relocation type for the symbol. */
+
+static rtx
+m68k_unwrap_symbol_1 (rtx orig, bool unwrap_reloc32_p,
+ enum m68k_reloc *reloc_ptr)
+{
+ if (GET_CODE (orig) == CONST)
+ {
+ rtx x;
+ enum m68k_reloc dummy;
+
+ x = XEXP (orig, 0);
+
+ if (reloc_ptr == NULL)
+ reloc_ptr = &dummy;
+
+ /* Handle an addend. */
+ if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS)
+ && CONST_INT_P (XEXP (x, 1)))
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == UNSPEC)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_RELOC16:
+ orig = XVECEXP (x, 0, 0);
+ *reloc_ptr = (enum m68k_reloc) INTVAL (XVECEXP (x, 0, 1));
+ break;
+
+ case UNSPEC_RELOC32:
+ if (unwrap_reloc32_p)
+ {
+ orig = XVECEXP (x, 0, 0);
+ *reloc_ptr = (enum m68k_reloc) INTVAL (XVECEXP (x, 0, 1));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return orig;
+}
+
+/* Unwrap symbol from UNSPEC_RELOC16 and, if unwrap_reloc32_p,
+ UNSPEC_RELOC32 wrappers. */
+
+rtx
+m68k_unwrap_symbol (rtx orig, bool unwrap_reloc32_p)
+{
+ return m68k_unwrap_symbol_1 (orig, unwrap_reloc32_p, NULL);
+}
+
+/* Prescan insn before outputing assembler for it. */
+
+void
+m68k_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED,
+ rtx *operands, int n_operands)
+{
+ int i;
+
+ /* Combine and, possibly, other optimizations may do good job
+ converting
+ (const (unspec [(symbol)]))
+ into
+ (const (plus (unspec [(symbol)])
+ (const_int N))).
+ The problem with this is emitting @TLS or @GOT decorations.
+ The decoration is emitted when processing (unspec), so the
+ result would be "#symbol@TLSLE+N" instead of "#symbol+N@TLSLE".
+
+ It seems that the easiest solution to this is to convert such
+ operands to
+ (const (unspec [(plus (symbol)
+ (const_int N))])).
+ Note, that the top level of operand remains intact, so we don't have
+ to patch up anything outside of the operand. */
+
+ for (i = 0; i < n_operands; ++i)
+ {
+ rtx op;
+
+ op = operands[i];
+
+ if (m68k_unwrap_symbol (op, true) != op)
+ {
+ rtx plus;
+
+ gcc_assert (GET_CODE (op) == CONST);
+ plus = XEXP (op, 0);
+
+ if (GET_CODE (plus) == PLUS || GET_CODE (plus) == MINUS)
+ {
+ rtx unspec;
+ rtx addend;
+
+ unspec = XEXP (plus, 0);
+ gcc_assert (GET_CODE (unspec) == UNSPEC);
+ addend = XEXP (plus, 1);
+ gcc_assert (CONST_INT_P (addend));
+
+ /* We now have all the pieces, rearrange them. */
+
+ /* Move symbol to plus. */
+ XEXP (plus, 0) = XVECEXP (unspec, 0, 0);
+
+ /* Move plus inside unspec. */
+ XVECEXP (unspec, 0, 0) = plus;
+
+ /* Move unspec to top level of const. */
+ XEXP (op, 0) = unspec;
+ }
+ }
+ }
+}
+
/* Move X to a register and add REG_EQUAL note pointing to ORIG.
If REG is non-null, use it; generate new pseudo otherwise. */
@@ -2320,11 +2393,6 @@ legitimize_pic_address (rtx orig, enum m
rtx base;
/* Make sure this has not already been legitimized. */
- if (GET_CODE (XEXP (orig, 0)) == PLUS
- && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
- return orig;
-
- /* Handle the case where we have: const (UNSPEC_RELOC??). */
if (m68k_unwrap_symbol (orig, true) != orig)
return orig;
@@ -2555,49 +2623,37 @@ m68k_tls_symbol_p (rtx x)
/* Helper for m68k_tls_referenced_p. */
static int
-m68k_tls_referenced_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+m68k_tls_reference_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
{
+ /* Note: this is not the same as m68k_tls_symbol_p. */
if (GET_CODE (*x) == SYMBOL_REF)
- return SYMBOL_REF_TLS_MODEL (*x) != 0;
+ return SYMBOL_REF_TLS_MODEL (*x) != 0 ? 1 : 0;
- /* Don't recurse into UNSPEC_TLS looking for TLS symbols; these are
- TLS offsets, not real symbol references. */
- if (GET_CODE (*x) == UNSPEC
- && (XINT (*x, 1) == UNSPEC_RELOC16 || XINT (*x, 1) == UNSPEC_RELOC32)
- && TLS_RELOC_P (INTVAL (XVECEXP (*x, 0, 1))))
+ /* Don't recurse into legitimate TLS references. */
+ if (m68k_tls_reference_p (*x, true))
return -1;
return 0;
}
-/* Return true if X contains any TLS symbol references. */
+/* If !LEGITIMATE_P, return true if X is a TLS symbol reference,
+ though illegitimate one.
+ If LEGITIMATE_P, return true if X is a legitimate TLS symbol reference. */
bool
-m68k_tls_referenced_p (rtx x)
+m68k_tls_reference_p (rtx x, bool legitimate_p)
{
if (!TARGET_HAVE_TLS)
return false;
- return for_each_rtx (&x, m68k_tls_referenced_p_1, NULL);
-}
-
-/* Return true if X is legitimate TLS symbol reference. */
-
-bool
-m68k_tls_mentioned_p (rtx x)
-{
- switch (GET_CODE (x))
+ if (!legitimate_p)
+ return for_each_rtx (&x, m68k_tls_reference_p_1, NULL) == 1 ? true : false;
+ else
{
- case CONST:
- return m68k_tls_mentioned_p (XEXP (x, 0));
+ enum m68k_reloc reloc = RELOC_GOT;
- case UNSPEC:
- if ((XINT (x, 1) == UNSPEC_RELOC16 || XINT (x, 1) == UNSPEC_RELOC32)
- && TLS_RELOC_P (INTVAL (XVECEXP (x, 0, 1))))
- return 1;
-
- default:
- return 0;
+ return (m68k_unwrap_symbol_1 (x, true, &reloc) != x
+ && TLS_RELOC_P (reloc));
}
}
@@ -4383,11 +4439,10 @@ print_operand (FILE *file, rtx op, int l
else
{
/* Use `print_operand_address' instead of `output_addr_const'
- to ensure that we print relevant PIC or TLS stuff. */
+ to ensure that we print relevant PIC stuff. */
asm_fprintf (file, "%I");
- if ((TARGET_PCREL
- && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST))
- || m68k_unwrap_symbol (op, true) != op)
+ if (TARGET_PCREL
+ && (GET_CODE (op) == SYMBOL_REF || GET_CODE (op) == CONST))
print_operand_address (file, op);
else
output_addr_const (file, op);
@@ -4399,10 +4454,34 @@ print_operand (FILE *file, rtx op, int l
static const char *
m68k_get_reloc_decoration (enum m68k_reloc reloc)
{
+ /* To my knowledge, !MOTOROLA assemblers don't support TLS. */
+ gcc_assert (MOTOROLA || reloc == RELOC_GOT);
+
switch (reloc)
{
case RELOC_GOT:
- return "@GOT";
+ if (MOTOROLA)
+ {
+ if (flag_pic == 1 && TARGET_68020)
+ return "@GOT.w";
+ else
+ return "@GOT";
+ }
+ else
+ {
+ if (TARGET_68020)
+ {
+ switch (flag_pic)
+ {
+ case 1:
+ return ":w";
+ case 2:
+ return ":l";
+ default:
+ return "";
+ }
+ }
+ }
case RELOC_TLSGD:
return "@TLSGD";
@@ -4433,10 +4512,6 @@ m68k_output_addr_const_extra (FILE *file
{
switch (XINT (x, 1))
{
- /* ??? It would be cleaner to wrap normal GOT references into
- UNSPEC_GOT too, then we won't have to handle them separately
- in print_operand_address. I'm not aware of any downside of
- such clean up. */
case UNSPEC_RELOC16:
case UNSPEC_RELOC32:
output_addr_const (file, XVECEXP (x, 0, 0));
@@ -4549,17 +4624,8 @@ print_operand_address (FILE *file, rtx a
else
{
if (address.offset)
- {
- output_addr_const (file, address.offset);
- if (flag_pic && address.base == pic_offset_table_rtx
- && (m68k_unwrap_symbol (address.offset, false)
- == address.offset))
- {
- fprintf (file, "@GOT");
- if (flag_pic == 1 && TARGET_68020)
- fprintf (file, ".w");
- }
- }
+ output_addr_const (file, address.offset);
+
putc ('(', file);
if (address.base)
fputs (M68K_REGNAME (REGNO (address.base)), file);
@@ -4592,19 +4658,7 @@ print_operand_address (FILE *file, rtx a
fputs (M68K_REGNAME (REGNO (address.base)), file);
fprintf (file, "@(");
if (address.offset)
- {
- output_addr_const (file, address.offset);
- if (address.base == pic_offset_table_rtx && TARGET_68020)
- switch (flag_pic)
- {
- case 1:
- fprintf (file, ":w"); break;
- case 2:
- fprintf (file, ":l"); break;
- default:
- break;
- }
- }
+ output_addr_const (file, address.offset);
}
/* Print the ",index" component, if any. */
if (address.index)
diff -rup -x .svn ./gcc-mainline-2/gcc/config/m68k/m68k.h ./gcc-mainline/gcc/config/m68k/m68k.h
--- ./gcc-mainline-2/gcc/config/m68k/m68k.h 2009-05-15 08:43:46.000000000 -0700
+++ ./gcc-mainline/gcc/config/m68k/m68k.h 2009-05-15 03:56:33.000000000 -0700
@@ -750,7 +750,7 @@ __transfer_from_trampoline () \
#define LEGITIMATE_PIC_OPERAND_P(X) \
(!symbolic_operand (X, VOIDmode) \
|| (TARGET_PCREL && REG_STRICT_P) \
- || m68k_tls_mentioned_p (X))
+ || m68k_tls_reference_p (X, true))
#define REG_OK_FOR_BASE_P(X) \
m68k_legitimate_base_reg_p (X, REG_STRICT_P)
@@ -975,6 +975,9 @@ do { if (cc_prev_status.flags & CC_IN_68
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (int)(ROUNDED)))
+#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \
+ m68k_final_prescan_insn (INSN, OPVEC, NOPERANDS)
+
/* On the 68000, we use several CODE characters:
'.' for dot needed in Motorola-style opcode names.
'-' for an operand pushing on the stack:
diff -rup -x .svn ./gcc-mainline-2/gcc/config/m68k/m68k.md ./gcc-mainline/gcc/config/m68k/m68k.md
--- ./gcc-mainline-2/gcc/config/m68k/m68k.md 2009-05-15 08:43:46.000000000 -0700
+++ ./gcc-mainline/gcc/config/m68k/m68k.md 2009-05-15 03:58:54.000000000 -0700
@@ -872,7 +872,7 @@
/* Recognize the case where operand[1] is a reference to thread-local
data and load its address to a register. */
- if (!TARGET_PCREL && m68k_tls_referenced_p (operands[1]))
+ if (!TARGET_PCREL && m68k_tls_reference_p (operands[1], false))
{
rtx tmp = operands[1];
rtx addend = NULL;
diff -rup -x .svn ./gcc-mainline-2/gcc/config/m68k/m68k-protos.h ./gcc-mainline/gcc/config/m68k/m68k-protos.h
--- ./gcc-mainline-2/gcc/config/m68k/m68k-protos.h 2009-05-15 08:43:46.000000000 -0700
+++ ./gcc-mainline/gcc/config/m68k/m68k-protos.h 2009-05-15 03:56:06.000000000 -0700
@@ -61,14 +61,14 @@ extern bool m68k_matches_q_p (rtx);
extern bool m68k_matches_u_p (rtx);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
extern rtx m68k_legitimize_tls_address (rtx);
-extern bool m68k_tls_referenced_p (rtx);
-extern bool m68k_tls_mentioned_p (rtx);
+extern bool m68k_tls_reference_p (rtx, bool);
extern int valid_dbcc_comparison_p_2 (rtx, enum machine_mode);
extern rtx m68k_libcall_value (enum machine_mode);
extern rtx m68k_function_value (const_tree, const_tree);
extern int emit_move_sequence (rtx *, enum machine_mode, rtx);
extern bool m68k_movem_pattern_p (rtx, rtx, HOST_WIDE_INT, bool);
extern const char *m68k_output_movem (rtx *, rtx, HOST_WIDE_INT, bool);
+extern void m68k_final_prescan_insn (rtx, rtx *, int);
/* Functions from m68k.c used in constraints.md. */
extern rtx m68k_unwrap_symbol (rtx, bool);
2009-01-23 Maxim Kuvyrkov <maxim@codesourcery.com>
M68K TLS support.
gcc/
* configure.ac (m68k-*-*): Check if binutils support TLS.
* configure: Regenerate.
* config/m68k/predicates.md (symbolic_operand): Extend comment.
* config/m68k/constraints.md (Cu): New constraint.
* config/m68k/m68k.md (UNSPEC_GOTOFF): Remove.
(UNSPEC_RELOC16, UNSPEC_RELOC32): New constants.
(movsi): Handle TLS symbols.
(addsi3_5200): Handle XTLS symbols, indent.
* config/m68k/m68k-protos.h (m68k_legitimize_tls_address): Declare.
(m68k_tls_reference_p): Declare.
(m68k_legitimize_address): Declare.
(m68k_unwrap_symbol): Declare.
* config/m68k/m68k.opt (mxtls): New option.
* config/m68k/m68k.c (ggc.h): Include.
(m68k_output_dwarf_dtprel): Implement hook.
(TARGET_HAVE_TLS, TARGET_ASM_OUTPUT_DWARF_DTPREL): Define.
(m68k_expand_prologue): Load GOT pointer when function needs it.
(m68k_illegitimate_symbolic_constant_p): Handle TLS symbols.
(m68k_legitimate_constant_address_p): Same.
(m68k_decompose_address): Handle TLS references.
(m68k_get_gp): New static function.
(enum m68k_reloc): New contants.
(TLS_RELOC_P): New macro.
(m68k_wrap_symbol): New static function.
(m68k_unwrap_symbol, m68k_final_prescan_insn): New functions.
(m68k_move_to_reg, m68k_wrap_symbol_into_got_ref): New static
functions.
(legitimize_pic_address): Handle TLS references..
(m68k_tls_get_addr, m68k_get_tls_get_addr)
(m68k_libcall_value_in_a0_p)
(m68k_call_tls_get_addr, m68k_read_tp, m68k_get_m68k_read_tp)
(m68k_call_m68k_read_tp): Helper variables and functions for ...
(m68k_legitimize_tls_address): Handle TLS references.
(m68k_tls_symbol_p, m68k_tls_reference_p_1, m68k_tls_reference_p):
New functions.
(m68k_legitimize_address): Handle TLS symbols.
(m68k_get_reloc_decoration): New static function.
(m68k_output_addr_const_extra): Handle UNSPEC_RELOC16 and
UNSPEC_RELOC32.
(m68k_output_dwarf_dtprel): Implement hook.
(print_operand_address): Handle UNSPEC_RELOC16 adn UNSPEC_RELOC32.
(m68k_libcall_value): Return result in A0 instead of D0 when asked by
m68k_call_* routines.
(sched_attr_op_type): Handle TLS symbols.
(gt-m68k.h): Include.
* config/m68k/m68k.h (FINAL_PRESCAN_INSN): Define.
(LEGITIMATE_PIC_OPERAND_P): Support TLS.
gcc/testsuite/
* gcc.target/m68k/tls-ie.c: New test.
* gcc.target/m68k/tls-le.c: New test.
* gcc.target/m68k/tls-gd.c: New test.
* gcc.target/m68k/tls-ld.c: New test.
* gcc.target/m68k/tls-ie-xgot.c: New test.
* gcc.target/m68k/tls-le-xtls.c: New test.
* gcc.target/m68k/tls-gd-xgot.c: New test.
* gcc.target/m68k/tls-ld-xgot.c: New test.
* gcc.target/m68k/tls-ld-xtls.c: New test.
* gcc.target/m68k/tls-ld-xgot-xtls.c: New test.
Index: gcc-mainline/gcc/configure
===================================================================
--- gcc-mainline/gcc/configure (revision 147467)
+++ gcc-mainline/gcc/configure (working copy)
@@ -21984,6 +21984,22 @@ x:
tls_first_minor=16
tls_as_opt='-32 --fatal-warnings'
;;
+ m68k-*-*)
+ conftest_s='
+ .section .tdata,"awT",@progbits
+x:
+ .word 2
+ .text
+foo:
+ move.l x@TLSGD(%a5),%a0
+ move.l x@TLSLDM(%a5),%a0
+ move.l x@TLSLDO(%a5),%a0
+ move.l x@TLSIE(%a5),%a0
+ move.l x@TLSLE(%a5),%a0'
+ tls_first_major=2
+ tls_first_minor=19
+ tls_as_opt='--fatal-warnings'
+ ;;
powerpc-*-*)
conftest_s='
.section ".tdata","awT",@progbits
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic" } */
+/* { dg-final { scan-assembler "foo@TLSLDM\\(\%a5\\)" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+/* { dg-final { scan-assembler "lea \\(foo@TLSLDO,\%a0\\)" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler "jsr __m68k_read_tp" } } */
+/* { dg-final { scan-assembler "lea \\(foo@TLSLE,\%a0\\)" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot-xtls.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot-xtls.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot-xtls.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic -mxgot -mxtls" } */
+/* { dg-final { scan-assembler "#foo@TLSLDM,\%\[ad\]\[0-7\]" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+/* { dg-final { scan-assembler "#foo@TLSLDO,\%\[ad\]\[0-7\]" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd-xgot.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd-xgot.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd-xgot.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic -mxgot" } */
+/* { dg-final { scan-assembler "#foo@TLSGD,\%\[ad\]\[0-7\]" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+
+extern int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie-xgot.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie-xgot.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie-xgot.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -mxgot" } */
+/* { dg-final { scan-assembler "jsr __m68k_read_tp" } } */
+/* { dg-final { scan-assembler "#foo@TLSIE,\%\[ad\]\[0-7\]" } } */
+
+extern int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xgot.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic -mxgot" } */
+/* { dg-final { scan-assembler "#foo@TLSLDM,\%\[ad\]\[0-7\]" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+/* { dg-final { scan-assembler "lea \\(foo@TLSLDO,\%a0\\)" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xtls.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xtls.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ld-xtls.c (revision 0)
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic -mxtls" } */
+/* { dg-final { scan-assembler "foo@TLSLDM\\(\%a5\\)" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+/* { dg-final { scan-assembler "#foo@TLSLDO,\%\[ad\]\[0-7\]" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le-xtls.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le-xtls.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-le-xtls.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -mxtls" } */
+/* { dg-final { scan-assembler "jsr __m68k_read_tp" } } */
+/* { dg-final { scan-assembler "#foo@TLSLE,\%\[ad\]\[0-7\]" } } */
+
+static int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-gd.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2 -fpic" } */
+/* { dg-final { scan-assembler "foo@TLSGD\\(\%a5\\)" } } */
+/* { dg-final { scan-assembler "bsr.l __tls_get_addr@PLTPC" } } */
+
+extern int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie.c
===================================================================
--- gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie.c (revision 0)
+++ gcc-mainline/gcc/testsuite/gcc.target/m68k/tls-ie.c (revision 0)
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-skip-if "" { ! *-linux-* } { "*" } { "" } } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler "jsr __m68k_read_tp" } } */
+/* { dg-final { scan-assembler "foo@TLSIE\\(\%a5\\)" } } */
+
+extern int __thread foo;
+
+int *
+bar (void)
+{
+ return &foo;
+}
Index: gcc-mainline/gcc/configure.ac
===================================================================
--- gcc-mainline/gcc/configure.ac (revision 147467)
+++ gcc-mainline/gcc/configure.ac (working copy)
@@ -2570,6 +2570,22 @@ x:
tls_first_minor=16
tls_as_opt='-32 --fatal-warnings'
;;
+ m68k-*-*)
+ conftest_s='
+ .section .tdata,"awT",@progbits
+x:
+ .word 2
+ .text
+foo:
+ move.l x@TLSGD(%a5),%a0
+ move.l x@TLSLDM(%a5),%a0
+ move.l x@TLSLDO(%a5),%a0
+ move.l x@TLSIE(%a5),%a0
+ move.l x@TLSLE(%a5),%a0'
+ tls_first_major=2
+ tls_first_minor=19
+ tls_as_opt='--fatal-warnings'
+ ;;
powerpc-*-*)
conftest_s='
.section ".tdata","awT",@progbits
Index: gcc-mainline/gcc/config/m68k/predicates.md
===================================================================
--- gcc-mainline/gcc/config/m68k/predicates.md (revision 147467)
+++ gcc-mainline/gcc/config/m68k/predicates.md (working copy)
@@ -135,7 +135,9 @@
(match_code "sign_extend,zero_extend"))
;; Returns true if OP is either a symbol reference or a sum of a
-;; symbol reference and a constant.
+;; symbol reference and a constant. This predicate is for "raw"
+;; symbol references not yet processed by legitimize*_address,
+;; hence we do not handle UNSPEC_{XGOT, TLS, XTLS} here.
(define_predicate "symbolic_operand"
(match_code "symbol_ref,label_ref,const")
Index: gcc-mainline/gcc/config/m68k/m68k.md
===================================================================
--- gcc-mainline/gcc/config/m68k/m68k.md (revision 147467)
+++ gcc-mainline/gcc/config/m68k/m68k.md (working copy)
@@ -116,7 +116,8 @@
(UNSPEC_GOT 3)
(UNSPEC_IB 4)
(UNSPEC_TIE 5)
- (UNSPEC_GOTOFF 6)
+ (UNSPEC_RELOC16 6)
+ (UNSPEC_RELOC32 7)
])
;; UNSPEC_VOLATILE usage:
@@ -869,7 +870,41 @@
{
rtx tmp, base, offset;
- if (flag_pic && !TARGET_PCREL && symbolic_operand (operands[1], SImode))
+ /* Recognize the case where operand[1] is a reference to thread-local
+ data and load its address to a register. */
+ if (!TARGET_PCREL && m68k_tls_reference_p (operands[1], false))
+ {
+ rtx tmp = operands[1];
+ rtx addend = NULL;
+
+ if (GET_CODE (tmp) == CONST && GET_CODE (XEXP (tmp, 0)) == PLUS)
+ {
+ addend = XEXP (XEXP (tmp, 0), 1);
+ tmp = XEXP (XEXP (tmp, 0), 0);
+ }
+
+ gcc_assert (GET_CODE (tmp) == SYMBOL_REF);
+ gcc_assert (SYMBOL_REF_TLS_MODEL (tmp) != 0);
+
+ tmp = m68k_legitimize_tls_address (tmp);
+
+ if (addend)
+ {
+ if (!REG_P (tmp))
+ {
+ rtx reg;
+
+ reg = gen_reg_rtx (Pmode);
+ emit_move_insn (reg, tmp);
+ tmp = reg;
+ }
+
+ tmp = gen_rtx_PLUS (SImode, tmp, addend);
+ }
+
+ operands[1] = tmp;
+ }
+ else if (flag_pic && !TARGET_PCREL && symbolic_operand (operands[1], SImode))
{
/* The source is an address which requires PIC relocation.
Call legitimize_pic_address with the source, mode, and a relocation
@@ -2428,9 +2463,9 @@
"* return output_addsi3 (operands);")
(define_insn_and_split "*addsi3_5200"
- [(set (match_operand:SI 0 "nonimmediate_operand" "=mr,mr,a,m,r, ?a, ?a,?a,?a")
- (plus:SI (match_operand:SI 1 "general_operand" "%0, 0, 0,0,0, a, a, r, a")
- (match_operand:SI 2 "general_src_operand" " I, L, J,d,mrKi,Cj, r, a, J")))]
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=mr,mr,a, m,r, ?a, ?a,?a,?a")
+ (plus:SI (match_operand:SI 1 "general_operand" "%0, 0, 0, 0,0, a, a, r, a")
+ (match_operand:SI 2 "general_src_operand" " I, L, JCu,d,mrKi,Cj, r, a, JCu")))]
"TARGET_COLDFIRE"
{
switch (which_alternative)
@@ -2472,9 +2507,9 @@
(plus:SI (match_dup 0)
(match_dup 1)))]
""
- [(set_attr "type" "aluq_l,aluq_l,lea,alu_l,alu_l,*,lea,lea,lea")
- (set_attr "opy" "2,2,*,2,2,*,*,*,*")
- (set_attr "opy_type" "*,*,mem5,*,*,*,mem6,mem6,mem5")])
+ [(set_attr "type" "aluq_l,aluq_l,lea, alu_l,alu_l,*,lea, lea, lea")
+ (set_attr "opy" "2, 2, *, 2, 2, *,*, *, *")
+ (set_attr "opy_type" "*, *, mem5,*, *, *,mem6,mem6,mem5")])
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=a")
Index: gcc-mainline/gcc/config/m68k/m68k-protos.h
===================================================================
--- gcc-mainline/gcc/config/m68k/m68k-protos.h (revision 147467)
+++ gcc-mainline/gcc/config/m68k/m68k-protos.h (working copy)
@@ -60,13 +60,20 @@ extern bool m68k_legitimate_address_p (e
extern bool m68k_matches_q_p (rtx);
extern bool m68k_matches_u_p (rtx);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
+extern rtx m68k_legitimize_tls_address (rtx);
+extern bool m68k_tls_reference_p (rtx, bool);
extern int valid_dbcc_comparison_p_2 (rtx, enum machine_mode);
extern rtx m68k_libcall_value (enum machine_mode);
extern rtx m68k_function_value (const_tree, const_tree);
extern int emit_move_sequence (rtx *, enum machine_mode, rtx);
extern bool m68k_movem_pattern_p (rtx, rtx, HOST_WIDE_INT, bool);
extern const char *m68k_output_movem (rtx *, rtx, HOST_WIDE_INT, bool);
+extern void m68k_final_prescan_insn (rtx, rtx *, int);
+/* Functions from m68k.c used in constraints.md. */
+extern rtx m68k_unwrap_symbol (rtx, bool);
+
+/* Functions from m68k.c used in genattrtab. */
#ifdef HAVE_ATTR_cpu
extern enum attr_cpu m68k_sched_cpu;
extern enum attr_mac m68k_sched_mac;
Index: gcc-mainline/gcc/config/m68k/m68k.opt
===================================================================
--- gcc-mainline/gcc/config/m68k/m68k.opt (revision 147467)
+++ gcc-mainline/gcc/config/m68k/m68k.opt (working copy)
@@ -182,3 +182,7 @@ Tune for the specified target CPU or arc
mxgot
Target Report Mask(XGOT)
Support more than 8192 GOT entries on ColdFire
+
+mxtls
+Target Report Mask(XTLS)
+Support TLS segment larger than 64K
Index: gcc-mainline/gcc/config/m68k/m68k.c
===================================================================
--- gcc-mainline/gcc/config/m68k/m68k.c (revision 147467)
+++ gcc-mainline/gcc/config/m68k/m68k.c (working copy)
@@ -46,6 +46,7 @@ along with GCC; see the file COPYING3.
/* ??? Need to add a dependency between m68k.o and sched-int.h. */
#include "sched-int.h"
#include "insn-codes.h"
+#include "ggc.h"
enum reg_class regno_reg_class[] =
{
@@ -143,11 +144,13 @@ static tree m68k_handle_fndecl_attribute
static void m68k_compute_frame_layout (void);
static bool m68k_save_reg (unsigned int regno, bool interrupt_handler);
static bool m68k_ok_for_sibcall_p (tree, tree);
+static bool m68k_tls_symbol_p (rtx);
static rtx m68k_legitimize_address (rtx, rtx, enum machine_mode);
static bool m68k_rtx_costs (rtx, int, int, int *, bool);
#if M68K_HONOR_TARGET_STRICT_ALIGNMENT
static bool m68k_return_in_memory (const_tree, const_tree);
#endif
+static void m68k_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
/* Specify the identification number of the library being built */
@@ -248,6 +251,14 @@ const char *m68k_library_id_string = "_c
#define TARGET_RETURN_IN_MEMORY m68k_return_in_memory
#endif
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS (true)
+
+#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
+#define TARGET_ASM_OUTPUT_DWARF_DTPREL m68k_output_dwarf_dtprel
+#endif
+
static const struct attribute_spec m68k_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
@@ -1145,8 +1156,7 @@ m68k_expand_prologue (void)
current_frame.reg_mask, true, true));
}
- if (flag_pic
- && !TARGET_SEP_DATA
+ if (!TARGET_SEP_DATA
&& crtl->uses_pic_offset_table)
insn = emit_insn (gen_load_got (pic_offset_table_rtx));
}
@@ -1431,6 +1441,9 @@ m68k_legitimize_sibcall_address (rtx x)
rtx
m68k_legitimize_address (rtx x, rtx oldx, enum machine_mode mode)
{
+ if (m68k_tls_symbol_p (x))
+ return m68k_legitimize_tls_address (x);
+
if (GET_CODE (x) == PLUS)
{
int ch = (x) != (oldx);
@@ -1849,7 +1862,7 @@ m68k_illegitimate_symbolic_constant_p (r
&& !offset_within_block_p (base, INTVAL (offset)))
return true;
}
- return false;
+ return m68k_tls_reference_p (x, false);
}
/* Return true if X is a legitimate constant address that can reach
@@ -1877,7 +1890,7 @@ m68k_legitimate_constant_address_p (rtx
return false;
}
- return true;
+ return !m68k_tls_reference_p (x, false);
}
/* Return true if X is a LABEL_REF for a jump table. Assume that unplaced
@@ -1944,15 +1957,17 @@ m68k_decompose_address (enum machine_mod
/* Check for GOT loads. These are (bd,An,Xn) addresses if
TARGET_68020 && flag_pic == 2, otherwise they are (d16,An)
addresses. */
- if (flag_pic
- && GET_CODE (x) == PLUS
- && XEXP (x, 0) == pic_offset_table_rtx
- && (GET_CODE (XEXP (x, 1)) == SYMBOL_REF
- || GET_CODE (XEXP (x, 1)) == LABEL_REF))
+ if (GET_CODE (x) == PLUS
+ && XEXP (x, 0) == pic_offset_table_rtx)
{
- address->base = XEXP (x, 0);
- address->offset = XEXP (x, 1);
- return true;
+ /* As we are processing a PLUS, do not unwrap RELOC32 symbols --
+ they are invalid in this context. */
+ if (m68k_unwrap_symbol (XEXP (x, 1), false) != XEXP (x, 1))
+ {
+ address->base = XEXP (x, 0);
+ address->offset = XEXP (x, 1);
+ return true;
+ }
}
/* The ColdFire FPU only accepts addressing modes 2-5. */
@@ -2097,6 +2112,228 @@ m68k_matches_u_p (rtx x)
&& !address.index);
}
+/* Return GOT pointer. */
+
+static rtx
+m68k_get_gp (void)
+{
+ if (pic_offset_table_rtx == NULL_RTX)
+ pic_offset_table_rtx = gen_rtx_REG (Pmode, PIC_REG);
+
+ crtl->uses_pic_offset_table = 1;
+
+ return pic_offset_table_rtx;
+}
+
+/* M68K relocations, used to distinguish GOT and TLS relocations in UNSPEC
+ wrappers. */
+enum m68k_reloc { RELOC_GOT, RELOC_TLSGD, RELOC_TLSLDM, RELOC_TLSLDO,
+ RELOC_TLSIE, RELOC_TLSLE };
+
+#define TLS_RELOC_P(RELOC) ((RELOC) != RELOC_GOT)
+
+/* Wrap symbol X into unspec representing relocation RELOC.
+ BASE_REG - register that should be added to the result.
+ TEMP_REG - if non-null, temporary register. */
+
+static rtx
+m68k_wrap_symbol (rtx x, enum m68k_reloc reloc, rtx base_reg, rtx temp_reg)
+{
+ bool use_x_p;
+
+ use_x_p = (base_reg == pic_offset_table_rtx) ? TARGET_XGOT : TARGET_XTLS;
+
+ if (TARGET_COLDFIRE && use_x_p)
+ /* When compiling with -mx{got, tls} switch the code will look like this:
+
+ move.l <X>@<RELOC>,<TEMP_REG>
+ add.l <BASE_REG>,<TEMP_REG> */
+ {
+ /* Wrap X in UNSPEC_??? to tip m68k_output_addr_const_extra
+ to put @RELOC after reference. */
+ x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
+ UNSPEC_RELOC32);
+ x = gen_rtx_CONST (Pmode, x);
+
+ if (temp_reg == NULL)
+ {
+ gcc_assert (can_create_pseudo_p ());
+ temp_reg = gen_reg_rtx (Pmode);
+ }
+
+ emit_move_insn (temp_reg, x);
+ emit_insn (gen_addsi3 (temp_reg, temp_reg, base_reg));
+ x = temp_reg;
+ }
+ else
+ {
+ x = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (reloc)),
+ UNSPEC_RELOC16);
+ x = gen_rtx_CONST (Pmode, x);
+
+ x = gen_rtx_PLUS (Pmode, base_reg, x);
+ }
+
+ return x;
+}
+
+/* Helper for m68k_unwrap_symbol.
+ Also, if unwrapping was successful (that is if (ORIG != <return value>)),
+ sets *RELOC_PTR to relocation type for the symbol. */
+
+static rtx
+m68k_unwrap_symbol_1 (rtx orig, bool unwrap_reloc32_p,
+ enum m68k_reloc *reloc_ptr)
+{
+ if (GET_CODE (orig) == CONST)
+ {
+ rtx x;
+ enum m68k_reloc dummy;
+
+ x = XEXP (orig, 0);
+
+ if (reloc_ptr == NULL)
+ reloc_ptr = &dummy;
+
+ /* Handle an addend. */
+ if ((GET_CODE (x) == PLUS || GET_CODE (x) == MINUS)
+ && CONST_INT_P (XEXP (x, 1)))
+ x = XEXP (x, 0);
+
+ if (GET_CODE (x) == UNSPEC)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_RELOC16:
+ orig = XVECEXP (x, 0, 0);
+ *reloc_ptr = (enum m68k_reloc) INTVAL (XVECEXP (x, 0, 1));
+ break;
+
+ case UNSPEC_RELOC32:
+ if (unwrap_reloc32_p)
+ {
+ orig = XVECEXP (x, 0, 0);
+ *reloc_ptr = (enum m68k_reloc) INTVAL (XVECEXP (x, 0, 1));
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ return orig;
+}
+
+/* Unwrap symbol from UNSPEC_RELOC16 and, if unwrap_reloc32_p,
+ UNSPEC_RELOC32 wrappers. */
+
+rtx
+m68k_unwrap_symbol (rtx orig, bool unwrap_reloc32_p)
+{
+ return m68k_unwrap_symbol_1 (orig, unwrap_reloc32_p, NULL);
+}
+
+/* Prescan insn before outputing assembler for it. */
+
+void
+m68k_final_prescan_insn (rtx insn ATTRIBUTE_UNUSED,
+ rtx *operands, int n_operands)
+{
+ int i;
+
+ /* Combine and, possibly, other optimizations may do good job
+ converting
+ (const (unspec [(symbol)]))
+ into
+ (const (plus (unspec [(symbol)])
+ (const_int N))).
+ The problem with this is emitting @TLS or @GOT decorations.
+ The decoration is emitted when processing (unspec), so the
+ result would be "#symbol@TLSLE+N" instead of "#symbol+N@TLSLE".
+
+ It seems that the easiest solution to this is to convert such
+ operands to
+ (const (unspec [(plus (symbol)
+ (const_int N))])).
+ Note, that the top level of operand remains intact, so we don't have
+ to patch up anything outside of the operand. */
+
+ for (i = 0; i < n_operands; ++i)
+ {
+ rtx op;
+
+ op = operands[i];
+
+ if (m68k_unwrap_symbol (op, true) != op)
+ {
+ rtx plus;
+
+ gcc_assert (GET_CODE (op) == CONST);
+ plus = XEXP (op, 0);
+
+ if (GET_CODE (plus) == PLUS || GET_CODE (plus) == MINUS)
+ {
+ rtx unspec;
+ rtx addend;
+
+ unspec = XEXP (plus, 0);
+ gcc_assert (GET_CODE (unspec) == UNSPEC);
+ addend = XEXP (plus, 1);
+ gcc_assert (CONST_INT_P (addend));
+
+ /* We now have all the pieces, rearrange them. */
+
+ /* Move symbol to plus. */
+ XEXP (plus, 0) = XVECEXP (unspec, 0, 0);
+
+ /* Move plus inside unspec. */
+ XVECEXP (unspec, 0, 0) = plus;
+
+ /* Move unspec to top level of const. */
+ XEXP (op, 0) = unspec;
+ }
+ }
+ }
+}
+
+/* Move X to a register and add REG_EQUAL note pointing to ORIG.
+ If REG is non-null, use it; generate new pseudo otherwise. */
+
+static rtx
+m68k_move_to_reg (rtx x, rtx orig, rtx reg)
+{
+ rtx insn;
+
+ if (reg == NULL_RTX)
+ {
+ gcc_assert (can_create_pseudo_p ());
+ reg = gen_reg_rtx (Pmode);
+ }
+
+ insn = emit_move_insn (reg, x);
+ /* Put a REG_EQUAL note on this insn, so that it can be optimized
+ by loop. */
+ set_unique_reg_note (insn, REG_EQUAL, orig);
+
+ return reg;
+}
+
+/* Does the same as m68k_wrap_symbol, but returns a memory reference to
+ GOT slot. */
+
+static rtx
+m68k_wrap_symbol_into_got_ref (rtx x, enum m68k_reloc reloc, rtx temp_reg)
+{
+ x = m68k_wrap_symbol (x, reloc, m68k_get_gp (), temp_reg);
+
+ x = gen_rtx_MEM (Pmode, x);
+ MEM_READONLY_P (x) = 1;
+
+ return x;
+}
+
/* Legitimize PIC addresses. If the address is already
position-independent, we return ORIG. Newly generated
position-independent addresses go to REG. If we need more
@@ -2148,42 +2385,15 @@ legitimize_pic_address (rtx orig, enum m
{
gcc_assert (reg);
- if (TARGET_COLDFIRE && TARGET_XGOT)
- /* When compiling with -mxgot switch the code for the above
- example will look like this:
-
- movel a5, a0
- addl _foo@GOT, a0
- movel a0@, a0
- movel #12345, a0@ */
- {
- rtx pic_offset;
-
- /* Wrap ORIG in UNSPEC_GOTOFF to tip m68k_output_addr_const_extra
- to put @GOT after reference. */
- pic_offset = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, orig),
- UNSPEC_GOTOFF);
- pic_offset = gen_rtx_CONST (Pmode, pic_offset);
- emit_move_insn (reg, pic_offset);
- emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
- pic_ref = gen_rtx_MEM (Pmode, reg);
- }
- else
- pic_ref = gen_rtx_MEM (Pmode,
- gen_rtx_PLUS (Pmode,
- pic_offset_table_rtx, orig));
- crtl->uses_pic_offset_table = 1;
- MEM_READONLY_P (pic_ref) = 1;
- emit_move_insn (reg, pic_ref);
- return reg;
+ pic_ref = m68k_wrap_symbol_into_got_ref (orig, RELOC_GOT, reg);
+ pic_ref = m68k_move_to_reg (pic_ref, orig, reg);
}
else if (GET_CODE (orig) == CONST)
{
rtx base;
/* Make sure this has not already been legitimized. */
- if (GET_CODE (XEXP (orig, 0)) == PLUS
- && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+ if (m68k_unwrap_symbol (orig, true) != orig)
return orig;
gcc_assert (reg);
@@ -2196,13 +2406,257 @@ legitimize_pic_address (rtx orig, enum m
base == reg ? 0 : reg);
if (GET_CODE (orig) == CONST_INT)
- return plus_constant (base, INTVAL (orig));
- pic_ref = gen_rtx_PLUS (Pmode, base, orig);
- /* Likewise, should we set special REG_NOTEs here? */
+ pic_ref = plus_constant (base, INTVAL (orig));
+ else
+ pic_ref = gen_rtx_PLUS (Pmode, base, orig);
}
+
return pic_ref;
}
+/* The __tls_get_addr symbol. */
+static GTY(()) rtx m68k_tls_get_addr;
+
+/* Return SYMBOL_REF for __tls_get_addr. */
+
+static rtx
+m68k_get_tls_get_addr (void)
+{
+ if (m68k_tls_get_addr == NULL_RTX)
+ m68k_tls_get_addr = init_one_libfunc ("__tls_get_addr");
+
+ return m68k_tls_get_addr;
+}
+
+/* Return libcall result in A0 instead of usual D0. */
+static bool m68k_libcall_value_in_a0_p = false;
+
+/* Emit instruction sequence that calls __tls_get_addr. X is
+ the TLS symbol we are referencing and RELOC is the symbol type to use
+ (either TLSGD or TLSLDM). EQV is the REG_EQUAL note for the sequence
+ emitted. A pseudo register with result of __tls_get_addr call is
+ returned. */
+
+static rtx
+m68k_call_tls_get_addr (rtx x, rtx eqv, enum m68k_reloc reloc)
+{
+ rtx a0;
+ rtx insns;
+ rtx dest;
+
+ /* Emit the call sequence. */
+ start_sequence ();
+
+ /* FIXME: Unfortunately, emit_library_call_value does not
+ consider (plus (%a5) (const (unspec))) to be a good enough
+ operand for push, so it forces it into a register. The bad
+ thing about this is that combiner, due to copy propagation and other
+ optimizations, sometimes can not later fix this. As a consequence,
+ additional register may be allocated resulting in a spill.
+ For reference, see args processing loops in
+ calls.c:emit_library_call_value_1.
+ For testcase, see gcc.target/m68k/tls-{gd, ld}.c */
+ x = m68k_wrap_symbol (x, reloc, m68k_get_gp (), NULL_RTX);
+
+ /* __tls_get_addr() is not a libcall, but emitting a libcall_value
+ is the simpliest way of generating a call. The difference between
+ __tls_get_addr() and libcall is that the result is returned in D0
+ instead of A0. To workaround this, we use m68k_libcall_value_in_a0_p
+ which temporarily switches returning the result to A0. */
+
+ m68k_libcall_value_in_a0_p = true;
+ a0 = emit_library_call_value (m68k_get_tls_get_addr (), NULL_RTX, LCT_PURE,
+ Pmode, 1, x, Pmode);
+ m68k_libcall_value_in_a0_p = false;
+
+ insns = get_insns ();
+ end_sequence ();
+
+ gcc_assert (can_create_pseudo_p ());
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, a0, eqv);
+
+ return dest;
+}
+
+/* The __tls_get_addr symbol. */
+static GTY(()) rtx m68k_read_tp;
+
+/* Return SYMBOL_REF for __m68k_read_tp. */
+
+static rtx
+m68k_get_m68k_read_tp (void)
+{
+ if (m68k_read_tp == NULL_RTX)
+ m68k_read_tp = init_one_libfunc ("__m68k_read_tp");
+
+ return m68k_read_tp;
+}
+
+/* Emit instruction sequence that calls __m68k_read_tp.
+ A pseudo register with result of __m68k_read_tp call is returned. */
+
+static rtx
+m68k_call_m68k_read_tp (void)
+{
+ rtx a0;
+ rtx eqv;
+ rtx insns;
+ rtx dest;
+
+ start_sequence ();
+
+ /* __m68k_read_tp() is not a libcall, but emitting a libcall_value
+ is the simpliest way of generating a call. The difference between
+ __m68k_read_tp() and libcall is that the result is returned in D0
+ instead of A0. To workaround this, we use m68k_libcall_value_in_a0_p
+ which temporarily switches returning the result to A0. */
+
+ /* Emit the call sequence. */
+ m68k_libcall_value_in_a0_p = true;
+ a0 = emit_library_call_value (m68k_get_m68k_read_tp (), NULL_RTX, LCT_PURE,
+ Pmode, 0);
+ m68k_libcall_value_in_a0_p = false;
+ insns = get_insns ();
+ end_sequence ();
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the m68k_read_tp result with other IE/LE model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx), UNSPEC_RELOC32);
+
+ gcc_assert (can_create_pseudo_p ());
+ dest = gen_reg_rtx (Pmode);
+ emit_libcall_block (insns, dest, a0, eqv);
+
+ return dest;
+}
+
+/* Return a legitimized address for accessing TLS SYMBOL_REF X.
+ For explanations on instructions sequences see TLS/NPTL ABI for m68k and
+ ColdFire. */
+
+rtx
+m68k_legitimize_tls_address (rtx orig)
+{
+ switch (SYMBOL_REF_TLS_MODEL (orig))
+ {
+ case TLS_MODEL_GLOBAL_DYNAMIC:
+ orig = m68k_call_tls_get_addr (orig, orig, RELOC_TLSGD);
+ break;
+
+ case TLS_MODEL_LOCAL_DYNAMIC:
+ {
+ rtx eqv;
+ rtx a0;
+ rtx x;
+
+ /* Attach a unique REG_EQUIV, to allow the RTL optimizers to
+ share the LDM result with other LD model accesses. */
+ eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
+ UNSPEC_RELOC32);
+
+ a0 = m68k_call_tls_get_addr (orig, eqv, RELOC_TLSLDM);
+
+ x = m68k_wrap_symbol (orig, RELOC_TLSLDO, a0, NULL_RTX);
+
+ if (can_create_pseudo_p ())
+ x = m68k_move_to_reg (x, orig, NULL_RTX);
+
+ orig = x;
+ break;
+ }
+
+ case TLS_MODEL_INITIAL_EXEC:
+ {
+ rtx a0;
+ rtx x;
+
+ a0 = m68k_call_m68k_read_tp ();
+
+ x = m68k_wrap_symbol_into_got_ref (orig, RELOC_TLSIE, NULL_RTX);
+ x = gen_rtx_PLUS (Pmode, x, a0);
+
+ if (can_create_pseudo_p ())
+ x = m68k_move_to_reg (x, orig, NULL_RTX);
+
+ orig = x;
+ break;
+ }
+
+ case TLS_MODEL_LOCAL_EXEC:
+ {
+ rtx a0;
+ rtx x;
+
+ a0 = m68k_call_m68k_read_tp ();
+
+ x = m68k_wrap_symbol (orig, RELOC_TLSLE, a0, NULL_RTX);
+
+ if (can_create_pseudo_p ())
+ x = m68k_move_to_reg (x, orig, NULL_RTX);
+
+ orig = x;
+ break;
+ }
+
+ default:
+ gcc_unreachable ();
+ }
+
+ return orig;
+}
+
+/* Return true if X is a TLS symbol. */
+
+static bool
+m68k_tls_symbol_p (rtx x)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ if (GET_CODE (x) != SYMBOL_REF)
+ return false;
+
+ return SYMBOL_REF_TLS_MODEL (x) != 0;
+}
+
+/* Helper for m68k_tls_referenced_p. */
+
+static int
+m68k_tls_reference_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
+{
+ /* Note: this is not the same as m68k_tls_symbol_p. */
+ if (GET_CODE (*x) == SYMBOL_REF)
+ return SYMBOL_REF_TLS_MODEL (*x) != 0 ? 1 : 0;
+
+ /* Don't recurse into legitimate TLS references. */
+ if (m68k_tls_reference_p (*x, true))
+ return -1;
+
+ return 0;
+}
+
+/* If !LEGITIMATE_P, return true if X is a TLS symbol reference,
+ though illegitimate one.
+ If LEGITIMATE_P, return true if X is a legitimate TLS symbol reference. */
+
+bool
+m68k_tls_reference_p (rtx x, bool legitimate_p)
+{
+ if (!TARGET_HAVE_TLS)
+ return false;
+
+ if (!legitimate_p)
+ return for_each_rtx (&x, m68k_tls_reference_p_1, NULL) == 1 ? true : false;
+ else
+ {
+ enum m68k_reloc reloc = RELOC_GOT;
+
+ return (m68k_unwrap_symbol_1 (x, true, &reloc) != x
+ && TLS_RELOC_P (reloc));
+ }
+}
+
#define USE_MOVQ(i) ((unsigned) ((i) + 128) <= 255)
@@ -3995,18 +4449,92 @@ print_operand (FILE *file, rtx op, int l
}
}
+/* Return string for TLS relocation RELOC. */
+
+static const char *
+m68k_get_reloc_decoration (enum m68k_reloc reloc)
+{
+ /* To my knowledge, !MOTOROLA assemblers don't support TLS. */
+ gcc_assert (MOTOROLA || reloc == RELOC_GOT);
+
+ switch (reloc)
+ {
+ case RELOC_GOT:
+ if (MOTOROLA)
+ {
+ if (flag_pic == 1 && TARGET_68020)
+ return "@GOT.w";
+ else
+ return "@GOT";
+ }
+ else
+ {
+ if (TARGET_68020)
+ {
+ switch (flag_pic)
+ {
+ case 1:
+ return ":w";
+ case 2:
+ return ":l";
+ default:
+ return "";
+ }
+ }
+ }
+
+ case RELOC_TLSGD:
+ return "@TLSGD";
+
+ case RELOC_TLSLDM:
+ return "@TLSLDM";
+
+ case RELOC_TLSLDO:
+ return "@TLSLDO";
+
+ case RELOC_TLSIE:
+ return "@TLSIE";
+
+ case RELOC_TLSLE:
+ return "@TLSLE";
+
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* m68k implementation of OUTPUT_ADDR_CONST_EXTRA. */
bool
m68k_output_addr_const_extra (FILE *file, rtx x)
{
- if (GET_CODE (x) != UNSPEC || XINT (x, 1) != UNSPEC_GOTOFF)
- return false;
+ if (GET_CODE (x) == UNSPEC)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_RELOC16:
+ case UNSPEC_RELOC32:
+ output_addr_const (file, XVECEXP (x, 0, 0));
+ fputs (m68k_get_reloc_decoration (INTVAL (XVECEXP (x, 0, 1))), file);
+ return true;
- output_addr_const (file, XVECEXP (x, 0, 0));
- /* ??? What is the non-MOTOROLA syntax? */
- fputs ("@GOT", file);
- return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
+/* M68K implementation of TARGET_ASM_OUTPUT_DWARF_DTPREL. */
+
+static void
+m68k_output_dwarf_dtprel (FILE *file, int size, rtx x)
+{
+ gcc_assert (size == 4);
+ fputs ("\t.long\t", file);
+ output_addr_const (file, x);
+ fputs ("@TLSLDO+0x8000", file);
}
@@ -4096,15 +4624,8 @@ print_operand_address (FILE *file, rtx a
else
{
if (address.offset)
- {
- output_addr_const (file, address.offset);
- if (flag_pic && address.base == pic_offset_table_rtx)
- {
- fprintf (file, "@GOT");
- if (flag_pic == 1 && TARGET_68020)
- fprintf (file, ".w");
- }
- }
+ output_addr_const (file, address.offset);
+
putc ('(', file);
if (address.base)
fputs (M68K_REGNAME (REGNO (address.base)), file);
@@ -4137,19 +4658,7 @@ print_operand_address (FILE *file, rtx a
fputs (M68K_REGNAME (REGNO (address.base)), file);
fprintf (file, "@(");
if (address.offset)
- {
- output_addr_const (file, address.offset);
- if (address.base == pic_offset_table_rtx && TARGET_68020)
- switch (flag_pic)
- {
- case 1:
- fprintf (file, ":w"); break;
- case 2:
- fprintf (file, ":l"); break;
- default:
- break;
- }
- }
+ output_addr_const (file, address.offset);
}
/* Print the ",index" component, if any. */
if (address.index)
@@ -4637,7 +5146,8 @@ m68k_libcall_value (enum machine_mode mo
default:
break;
}
- return gen_rtx_REG (mode, D0_REG);
+
+ return gen_rtx_REG (mode, m68k_libcall_value_in_a0_p ? A0_REG : D0_REG);
}
rtx
@@ -4903,9 +5413,8 @@ sched_attr_op_type (rtx insn, bool opx_p
return OP_TYPE_IMM_L;
default:
- if (GET_CODE (op) == SYMBOL_REF)
- /* ??? Just a guess. Probably we can guess better using length
- attribute of the instructions. */
+ if (symbolic_operand (m68k_unwrap_symbol (op, false), VOIDmode))
+ /* Just a guess. */
return OP_TYPE_IMM_W;
return OP_TYPE_IMM_L;
@@ -5850,3 +6359,5 @@ m68k_sched_indexed_address_bypass_p (rtx
return 0;
}
}
+
+#include "gt-m68k.h"
Index: gcc-mainline/gcc/config/m68k/constraints.md
===================================================================
--- gcc-mainline/gcc/config/m68k/constraints.md (revision 147467)
+++ gcc-mainline/gcc/config/m68k/constraints.md (working copy)
@@ -129,6 +129,11 @@
(and (match_code "const_int")
(match_test "ival < -0x8000 || ival > 0x7FFF")))
+(define_constraint "Cu"
+ "16-bit offset for wrapped symbols"
+ (and (match_code "const")
+ (match_test "m68k_unwrap_symbol (op, false) != op")))
+
(define_constraint "CQ"
"Integers valid for mvq."
(and (match_code "const_int")
Index: gcc-mainline/gcc/config/m68k/m68k.h
===================================================================
--- gcc-mainline/gcc/config/m68k/m68k.h (revision 147467)
+++ gcc-mainline/gcc/config/m68k/m68k.h (working copy)
@@ -749,7 +749,8 @@ __transfer_from_trampoline () \
#define LEGITIMATE_PIC_OPERAND_P(X) \
(!symbolic_operand (X, VOIDmode) \
- || (TARGET_PCREL && REG_STRICT_P))
+ || (TARGET_PCREL && REG_STRICT_P) \
+ || m68k_tls_reference_p (X, true))
#define REG_OK_FOR_BASE_P(X) \
m68k_legitimate_base_reg_p (X, REG_STRICT_P)
@@ -974,6 +975,9 @@ do { if (cc_prev_status.flags & CC_IN_68
assemble_name ((FILE), (NAME)), \
fprintf ((FILE), ",%u\n", (int)(ROUNDED)))
+#define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \
+ m68k_final_prescan_insn (INSN, OPVEC, NOPERANDS)
+
/* On the 68000, we use several CODE characters:
'.' for dot needed in Motorola-style opcode names.
'-' for an operand pushing on the stack: