This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [4.5][PATCH][M68K] GCC support for TLS


Andreas Schwab wrote:
The insns I see in m68k_final_prescan_insn are of this form:

(insn 12 187 13 ../../../gcc/libgomp/config/posix/sem.h:72 (set (reg/f:SI 13 %a5 [60])
        (plus:SI (reg/f:SI 13 %a5 [60])
            (const:SI (unspec:SI [
                        (symbol_ref:SI ("gomp_tls_data") [flags 0x2a] <var_decl 0x401577e0 gomp_tls_data>)
                        (const_int 5 [0x5])
                    ] 6)))) 132 {*addsi3_internal} (expr_list:REG_EQUIV (symbol_ref:SI ("gomp_tls_data") [flags 0x2a] <var_decl 0x401577e0 gomp_tls_data>)
        (nil)))

This one is fine, actually. The errors are caused by operands which have TLS reference not on the top level, such as


|(insn 13 12 14 ../../../gcc/libgomp/team.c:213 (set (reg/v/f:SI 11 %a3 [orig:32 pool ] [32])
| (mem/s/f/c:SI (plus:SI (reg:SI 8 %a0)
| (const:SI (plus:SI (unspec:SI [
| (symbol_ref:SI ("gomp_tls_data") [flags 0x2a] <var_decl 0xf7d73958 gomp_tls_data>)
| (const_int 5 [0x5])
| ] 6)
| (const_int 56 [0x38])))) [24 gomp_tls_data.thread_pool+0 S4 A16])) 37 {*movsi_m68k2} (expr_list:REG_DEAD (reg:SI 8 %a0)
| (nil)))


The above insn has
(mem (plus (reg)
(const (unspec))))
for one of the operands, and the prescan were skipping it because it expected (const) to be on the top level.


The attached patch dully fixes the bug by walking the whole rtx tree of the operand with for_each_rtx.

BTW, the attached version of the patch also contains a piece for calls.c, which fixes some of the new tests. I'll be submitting that piece separately, but you may want it handy in case you'll be doing more testing.

--
Maxim
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): New function.
	(m68k_final_prescan_insn_1): New static function.
	(m68k_final_prescan_insn): New function.
	(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/calls.c
===================================================================
--- gcc-mainline/gcc/calls.c	(revision 147467)
+++ gcc-mainline/gcc/calls.c	(working copy)
@@ -3412,11 +3412,6 @@ emit_library_call_value_1 (int retval, r
 
       nargs++;
 
-      /* Make sure it is a reasonable operand for a move or push insn.  */
-      if (!REG_P (addr) && !MEM_P (addr)
-	  && ! (CONSTANT_P (addr) && LEGITIMATE_CONSTANT_P (addr)))
-	addr = force_operand (addr, NULL_RTX);
-
       argvec[count].value = addr;
       argvec[count].mode = Pmode;
       argvec[count].partial = 0;
@@ -3452,11 +3447,6 @@ emit_library_call_value_1 (int retval, r
       gcc_assert (mode != BLKmode
 		  && (GET_MODE (val) == mode || GET_MODE (val) == VOIDmode));
 
-      /* Make sure it is a reasonable operand for a move or push insn.  */
-      if (!REG_P (val) && !MEM_P (val)
-	  && ! (CONSTANT_P (val) && LEGITIMATE_CONSTANT_P (val)))
-	val = force_operand (val, NULL_RTX);
-
       if (pass_by_reference (&args_so_far, mode, NULL_TREE, 1))
 	{
 	  rtx slot;
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,243 @@ 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);
+}
+
+/* Helper for m68k_final_prescan_insn.  */
+
+static int
+m68k_final_prescan_insn_1 (rtx *x_ptr, void *data ATTRIBUTE_UNUSED)
+{
+  rtx x = *x_ptr;
+
+  if (m68k_unwrap_symbol (x, true) != x)
+    /* For rationale of the below, see comment in m68k_final_prescan_insn.  */
+    {
+      rtx plus;
+
+      gcc_assert (GET_CODE (x) == CONST);
+      plus = XEXP (x, 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 (x, 0) = unspec;
+	}
+
+      return -1;
+    }
+
+  return 0;
+}
+
+/* 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];
+
+      for_each_rtx (&op, m68k_final_prescan_insn_1, NULL);
+    }
+}
+
+/* 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 +2400,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 +2421,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_ptr, void *data ATTRIBUTE_UNUSED)
+{
+  /* Note: this is not the same as m68k_tls_symbol_p.  */
+  if (GET_CODE (*x_ptr) == SYMBOL_REF)
+    return SYMBOL_REF_TLS_MODEL (*x_ptr) != 0 ? 1 : 0;
+
+  /* Don't recurse into legitimate TLS references.  */
+  if (m68k_tls_reference_p (*x_ptr, 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 +4464,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 +4639,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 +4673,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 +5161,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 +5428,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 +6374,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:

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]