public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 1/2] [ARC/LIBGCC] Add TLS support.
  2016-04-15 10:00 [PATCH 0/2] [ARC] Add TLS support for ARC Claudiu Zissulescu
  2016-04-15 10:00 ` [PATCH 2/2] [ARC] Add TLS support Claudiu Zissulescu
@ 2016-04-15 10:00 ` Claudiu Zissulescu
  2016-04-28  8:37   ` Joern Wolfgang Rennecke
  1 sibling, 1 reply; 7+ messages in thread
From: Claudiu Zissulescu @ 2016-04-15 10:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, gnu, Francois.Bedard, jeremy.bennett

TLS mods for libgcc.

OK to apply?
Claudiu

libgcc/
2016-04-15  Claudiu Zissulescu  <claziss@synopsys.com>
	    Joern Rennecke  <joern.rennecke@embecosm.com>

	* config/arc/crttls.S: New file.
	* config/arc/t-arc: New rule.
	* config.host (arc*-*-elf*, arc*-*-linux*): Add crttls.o.
---
 libgcc/config.host         |  2 ++
 libgcc/config/arc/crttls.S | 67 ++++++++++++++++++++++++++++++++++++++++++++++
 libgcc/config/arc/t-arc    |  3 +++
 3 files changed, 72 insertions(+)
 create mode 100644 libgcc/config/arc/crttls.S

diff --git a/libgcc/config.host b/libgcc/config.host
index b61a579..c5266ed 100644
--- a/libgcc/config.host
+++ b/libgcc/config.host
@@ -367,10 +367,12 @@ alpha*-dec-*vms*)
 arc*-*-elf*)
 	tmake_file="arc/t-arc-newlib arc/t-arc"
 	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o libgmon.a crtg.o crtgend.o"
+	extra_parts="${extra_parts} crttls.o"
 	;;
 arc*-*-linux-uclibc*)
 	tmake_file="${tmake_file} t-slibgcc-libgcc t-slibgcc-nolc-override arc/t-arc700-uClibc arc/t-arc"
 	extra_parts="crti.o crtn.o crtend.o crtbegin.o crtendS.o crtbeginS.o libgmon.a crtg.o crtgend.o"
+	extra_parts="${extra_parts} crttls.o"
 	;;
 arm-wrs-vxworks)
 	tmake_file="$tmake_file arm/t-arm arm/t-elf t-softfp-sfdf t-softfp-excl arm/t-softfp t-softfp"
diff --git a/libgcc/config/arc/crttls.S b/libgcc/config/arc/crttls.S
new file mode 100644
index 0000000..512c1df5
--- /dev/null
+++ b/libgcc/config/arc/crttls.S
@@ -0,0 +1,67 @@
+; newlib tls glue code for Synopsys DesignWare ARC cpu.
+
+/* Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributor: Joern Rennecke <joern.rennecke@embecosm.com>
+		on behalf of Synopsys Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+a copy of the GCC Runtime Library Exception along with this program;
+see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+<http://www.gnu.org/licenses/>.  */
+
+/* As a special exception, if you link this library with other files,
+   some of which are compiled with GCC, to produce an executable,
+   this library does not by itself cause the resulting executable
+   to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+
+#if (__ARC_TLS_REGNO__ != -1)
+ /* ANSI concatenation macros.  */
+
+#define CONCAT1(a, b) CONCAT2(a, b)
+#define CONCAT2(a, b) a ## b
+
+ /* Use the right prefix for global labels.  */
+
+#define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
+
+#define FUNC(X)         .type SYM(X),@function
+#define ENDFUNC0(X)     .Lfe_##X: .size X,.Lfe_##X-X
+#define ENDFUNC(X)      ENDFUNC0(X)
+
+	.global SYM(__read_tp)
+SYM(__read_tp):
+	FUNC(__read_tp)
+	mov r0, CONCAT1 (r, __ARC_TLS_REGNO__)
+	nop
+	j [blink]
+	ENDFUNC(__read_tp)
+
+	.section .init
+	mov CONCAT1 (r, __ARC_TLS_REGNO__),__main_tcb_end+256
+
+	.section .tbss
+__main_tcb:
+	.long 0
+	.long 0
+__main_tcb_end:
+
+#endif /*__ARC_TLS_REGNO__ != -1 */
diff --git a/libgcc/config/arc/t-arc b/libgcc/config/arc/t-arc
index 7ceb694..3523aed 100644
--- a/libgcc/config/arc/t-arc
+++ b/libgcc/config/arc/t-arc
@@ -68,6 +68,9 @@ crtg.o: $(srcdir)/config/arc/crtg.S
 crtgend.o: $(srcdir)/config/arc/crtgend.S
 	$(crt_compile) -c -x assembler-with-cpp $<
 
+crttls.o: $(srcdir)/config/arc/crttls.S
+	$(crt_compile) -c -x assembler-with-cpp $<
+
 mcount.o: $(srcdir)/config/arc/gmon/mcount.c
 	$(gcc_compile) -isystem $(srcdir)/config/arc/gmon -c $< \
 	-fcall-saved-r0 -fcall-saved-r1 -fcall-saved-r2 -fcall-saved-r3 \
-- 
1.9.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 2/2] [ARC] Add TLS support.
  2016-04-15 10:00 [PATCH 0/2] [ARC] Add TLS support for ARC Claudiu Zissulescu
@ 2016-04-15 10:00 ` Claudiu Zissulescu
  2016-04-28  8:47   ` Joern Wolfgang Rennecke
  2016-04-15 10:00 ` [PATCH 1/2] [ARC/LIBGCC] " Claudiu Zissulescu
  1 sibling, 1 reply; 7+ messages in thread
From: Claudiu Zissulescu @ 2016-04-15 10:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, gnu, Francois.Bedard, jeremy.bennett

TLS mods for ARC backend.

OK to apply?
Claudiu

gcc/
2016-04-15  Claudiu Zissulescu  <claziss@synopsys.com>
	    Joern Rennecke  <joern.rennecke@embecosm.com>

	* config/arc/arc-protos.h (arc_legitimize_pic_address): Remove
	declaration.
	(emit_pic_move): Remove.
	(arc_eh_uses, insn_is_tls_gd_dispatch): Declare.
	* config/arc/arc.c (emit_pic_move): Removed.
	(TARGET_HAVE_TLS): Define.
	(arc_conditional_register_usage): Test for arc_tp_regno.
	(arc_print_operand, arc_print_operand_address): Handle TLS
	unspecs.
	(arc_needs_pcl_p): New function.
	(arc_legitimate_pc_offset_p): Use arc_needs_pcl_p.
	(arc_legitimate_pic_addr_p): Handle TLS unspecs.
	(arc_raw_symbolic_reference_mentioned_p): Likewise.
	(arc_get_tp, arc_emit_call_tls_get_addr): New function.
	(arc_legitimize_tls_address): Likewise.
	(DTPOFF_ZERO_SYM): Define.
	(arc_legitimize_pic_address): Make it static, handle TLS cases.
	(arc_output_pic_addr_const): Print TLS unspecs.
	(prepare_pic_move): New function, replaces emit_pic_move.
	(arc_legitimate_constant_p): Handle TLS unspecs.
	(arc_legitimate_address_p): Likewise.
	(arc_rewrite_small_data_p): Use assert for TLS constants.
	(prepare_move_operands): Use prepare_pic_move.
	(arc_legitimize_address): Legitimize tls addresses.
	(arc_epilogue_uses): Check for arc_tp_regno.
	(arc_eh_uses, insn_is_tls_gd_dispatch): New function.
	* config/arc/arc.h [DEFAULT_LIBC != LIBC_UCLIBC] (EXTRA_SPECS):
	Define.
	[DEFAULT_LIBC != LIBC_UCLIBC] (ARC_TLS_EXTRA_START_SPEC):
	Likewise.
	[DEFAULT_LIBC != LIBC_UCLIBC] (STARTFILE_SPEC): Add
	%(arc_tls_extra_start_spec).
	(TARGET_CPU_CPP_BUILTINS): Define __ARC_TLS_REGNO__.
	(REGNO_OK_FOR_BASE_P): Check for arc_tp_regno.
	(EH_USES): Define.
	(INSN_REFERENCES_ARE_DELAYED): Use insn_is_tls_gd_dispatch.
	* config/arc/arc.md (UNSPEC_TLS_GD, UNSPEC_TLS_LD, UNSPEC_TLS_IE)
	(UNSPEC_TLS_OFF): Add.
	(R10_REG): Define.
	(tls_load_tp_soft, tls_gd_load, tls_gd_get_addr, tls_gd_dispatch)
	(get_thread_pointersi): New patterns.
	* config/arc/arc.opt (mtp-regno): New option.
	* config/arc/predicates.md (move_src_operand): Handle TLS symbols.
	(move_dest_operand): Likewise.
	* configure: Regenerate.
	* configure.ac: Add arc*-*-* case to test for tls.
	* doc/invoke.texi (ARC options): Document mtp-regno.
---
 gcc/config/arc/arc-protos.h  |   4 +-
 gcc/config/arc/arc.c         | 503 +++++++++++++++++++++++++++++++------------
 gcc/config/arc/arc.h         |  22 +-
 gcc/config/arc/arc.md        |  71 ++++++
 gcc/config/arc/arc.opt       |   7 +
 gcc/config/arc/predicates.md |  15 +-
 gcc/configure                |   6 +
 gcc/configure.ac             |   6 +
 gcc/doc/invoke.texi          |   6 +-
 9 files changed, 492 insertions(+), 148 deletions(-)

diff --git a/gcc/config/arc/arc-protos.h b/gcc/config/arc/arc-protos.h
index f487291..3bf28a0 100644
--- a/gcc/config/arc/arc-protos.h
+++ b/gcc/config/arc/arc-protos.h
@@ -57,7 +57,6 @@ extern unsigned int arc_compute_frame_size (int);
 extern bool arc_ccfsm_branch_deleted_p (void);
 extern void arc_ccfsm_record_branch_deleted (void);
 
-extern rtx arc_legitimize_pic_address (rtx, rtx);
 void arc_asm_output_aligned_decl_local (FILE *, tree, const char *,
 					unsigned HOST_WIDE_INT,
 					unsigned HOST_WIDE_INT,
@@ -68,7 +67,6 @@ extern bool check_if_valid_sleep_operand (rtx *, int);
 extern bool arc_legitimate_constant_p (machine_mode, rtx);
 extern bool arc_legitimate_pc_offset_p (rtx);
 extern bool arc_legitimate_pic_addr_p (rtx);
-extern void emit_pic_move (rtx *, machine_mode);
 extern bool arc_raw_symbolic_reference_mentioned_p (rtx, bool);
 extern bool arc_legitimate_pic_operand_p (rtx);
 extern bool arc_is_longcall_p (rtx);
@@ -118,8 +116,10 @@ extern bool arc_text_label (rtx_insn *insn);
 extern int arc_decl_pretend_args (tree decl);
 extern bool arc_short_comparison_p (rtx, int);
 extern bool arc_epilogue_uses (int regno);
+extern bool arc_eh_uses (int regno);
 /* insn-attrtab.c doesn't include reload.h, which declares regno_clobbered_p. */
 extern int regno_clobbered_p (unsigned int, rtx_insn *, machine_mode, int);
 extern int arc_return_slot_offset (void);
 extern bool arc_legitimize_reload_address (rtx *, machine_mode, int, int);
 extern void arc_secondary_reload_conv (rtx, rtx, rtx, bool);
+extern bool insn_is_tls_gd_dispatch (rtx_insn *);
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index d60db50..43d0c74 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -217,7 +217,6 @@ static rtx arc_expand_builtin (tree, rtx, rtx, machine_mode, int);
 static int branch_dest (rtx);
 
 static void  arc_output_pic_addr_const (FILE *,  rtx, int);
-void emit_pic_move (rtx *, machine_mode);
 bool arc_legitimate_pic_operand_p (rtx);
 static bool arc_function_ok_for_sibcall (tree, tree);
 static rtx arc_function_value (const_tree, const_tree, bool);
@@ -420,6 +419,11 @@ static void arc_finalize_pic (void);
 #undef TARGET_ASM_ALIGNED_SI_OP
 #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
 
+#ifdef HAVE_AS_TLS
+#undef TARGET_HAVE_TLS
+#define TARGET_HAVE_TLS HAVE_AS_TLS
+#endif
+
 #undef TARGET_DWARF_REGISTER_SPAN
 #define TARGET_DWARF_REGISTER_SPAN arc_dwarf_register_span
 
@@ -1280,6 +1284,14 @@ arc_conditional_register_usage (void)
       strcpy (rname58, TARGET_BIG_ENDIAN ? "mhi" : "mlo");
       strcpy (rname59, TARGET_BIG_ENDIAN ? "mlo" : "mhi");
     }
+
+  /* The nature of arc_tp_regno is actually something more like a global
+     register, however globalize_reg requires a declaration.
+     We use EPILOGUE_USES to compensate so that sets from
+     __builtin_set_frame_pointer are not deleted.  */
+  if (arc_tp_regno != -1)
+    fixed_regs[arc_tp_regno] = call_used_regs[arc_tp_regno] = 1;
+
   if (TARGET_MULMAC_32BY16_SET)
     {
       fix_start = 56;
@@ -3369,7 +3381,16 @@ arc_print_operand (FILE *file, rtx x, int code)
 	}
       /* Fall through.  Let output_addr_const deal with it.  */
     default :
-      if (flag_pic)
+      if (flag_pic
+	  || (GET_CODE (x) == CONST
+	      && GET_CODE (XEXP (x, 0)) == UNSPEC
+	      && (XINT (XEXP (x, 0), 1) == UNSPEC_TLS_OFF
+		  || XINT (XEXP (x, 0), 1) == UNSPEC_TLS_GD))
+	  || (GET_CODE (x) == CONST
+	      && GET_CODE (XEXP (x, 0)) == PLUS
+	      && GET_CODE (XEXP (XEXP (x, 0), 0)) == UNSPEC
+	      && (XINT (XEXP (XEXP (x, 0), 0), 1) == UNSPEC_TLS_OFF
+		  || XINT (XEXP (XEXP (x, 0), 0), 1) == UNSPEC_TLS_GD)))
 	arc_output_pic_addr_const (file, x, code);
       else
 	{
@@ -3434,6 +3455,17 @@ arc_print_operand_address (FILE *file , rtx addr)
       {
 	rtx c = XEXP (addr, 0);
 
+	if ((GET_CODE (c) == UNSPEC
+	     && (XINT (c, 1) == UNSPEC_TLS_OFF
+		 || XINT (c, 1) == UNSPEC_TLS_IE))
+	    || (GET_CODE (c) == PLUS
+		&& GET_CODE (XEXP (c, 0)) == UNSPEC
+		&& (XINT (XEXP (c, 0), 1) == UNSPEC_TLS_OFF)))
+	  {
+	    arc_output_pic_addr_const (file, c, 0);
+	    break;
+	  }
+	gcc_assert (GET_CODE (c) == PLUS);
 	gcc_assert (GET_CODE (XEXP (c, 0)) == SYMBOL_REF);
 	gcc_assert (GET_CODE (XEXP (c, 1)) == CONST_INT);
 
@@ -4505,6 +4537,44 @@ arc_rtx_costs (rtx x, machine_mode mode, int outer_code,
     }
 }
 
+/* Helper used by arc_legitimate_pc_offset_p.  */
+
+static bool
+arc_needs_pcl_p (rtx x)
+{
+  register const char *fmt;
+  register int i, j;
+
+  if ((GET_CODE (x) == UNSPEC)
+      && (XVECLEN (x, 0) == 1)
+      && (GET_CODE (XVECEXP (x, 0, 0)) == SYMBOL_REF))
+    switch (XINT (x, 1))
+      {
+      case ARC_UNSPEC_GOT:
+      case UNSPEC_TLS_GD:
+      case UNSPEC_TLS_IE:
+	return true;
+      default:
+	break;
+      }
+
+  fmt = GET_RTX_FORMAT (GET_CODE (x));
+  for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'e')
+	{
+	  if (arc_needs_pcl_p (XEXP (x, i)))
+	    return true;
+	}
+      else if (fmt[i] == 'E')
+	for (j = XVECLEN (x, i) - 1; j >= 0; j--)
+	  if (arc_needs_pcl_p (XVECEXP (x, i, j)))
+	    return true;
+    }
+
+  return false;
+}
+
 /* Return true if ADDR is an address that needs to be expressed as an
    explicit sum of pcl + offset.  */
 
@@ -4513,17 +4583,8 @@ arc_legitimate_pc_offset_p (rtx addr)
 {
   if (GET_CODE (addr) != CONST)
     return false;
-  addr = XEXP (addr, 0);
-  if (GET_CODE (addr) == PLUS)
-    {
-      if (GET_CODE (XEXP (addr, 1)) != CONST_INT)
-	return false;
-      addr = XEXP (addr, 0);
-    }
-  return (GET_CODE (addr) == UNSPEC
-	  && XVECLEN (addr, 0) == 1
-	  && XINT (addr, 1) == ARC_UNSPEC_GOT
-	  && GET_CODE (XVECEXP (addr, 0, 0)) == SYMBOL_REF);
+
+  return arc_needs_pcl_p (addr);
 }
 
 /* Return true if ADDR is a valid pic address.
@@ -4552,9 +4613,11 @@ arc_legitimate_pic_addr_p (rtx addr)
       || XVECLEN (addr, 0) != 1)
     return false;
 
-  /* Must be @GOT or @GOTOFF.  */
+  /* Must be one of @GOT, @GOTOFF, @tlsgd, tlsie.  */
   if (XINT (addr, 1) != ARC_UNSPEC_GOT
-      && XINT (addr, 1) != ARC_UNSPEC_GOTOFF)
+      && XINT (addr, 1) != ARC_UNSPEC_GOTOFF
+      && XINT (addr, 1) != UNSPEC_TLS_GD
+      && XINT (addr, 1) != UNSPEC_TLS_IE)
     return false;
 
   if (GET_CODE (XVECEXP (addr, 0, 0)) != SYMBOL_REF
@@ -4612,6 +4675,10 @@ arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
 
   if (GET_CODE (op) == SYMBOL_REF)
     {
+      if (SYMBOL_REF_TLS_MODEL (op))
+	return true;
+      if (!flag_pic)
+	return false;
       tree decl = SYMBOL_REF_DECL (op);
       return !skip_local || !decl || !default_binds_local_p (decl);
     }
@@ -4638,11 +4705,112 @@ arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
   return false;
 }
 
+/* Get the thread pointer.  */
+
+static rtx
+arc_get_tp (void)
+{
+   /* If arc_tp_regno has been set, we can use that hard register
+      directly as a base register.  */
+  if (arc_tp_regno != -1)
+    return gen_rtx_REG (Pmode, arc_tp_regno);
+
+  /* Otherwise, call __read_tp.  Copy the result to a pseudo to avoid
+     conflicts with function arguments / results.  */
+  rtx reg = gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_load_tp_soft ());
+  emit_move_insn (reg, gen_rtx_REG (Pmode, R0_REG));
+  return reg;
+}
+
+static rtx
+arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
+{
+  rtx r0 = gen_rtx_REG (Pmode, R0_REG);
+  rtx insns;
+  rtx call_fusage = NULL_RTX;
+
+  start_sequence ();
+
+  rtx x = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, sym), reloc);
+  x = gen_rtx_CONST (Pmode, x);
+  emit_move_insn (r0, x);
+  use_reg (&call_fusage, r0);
+
+  gcc_assert (reloc == UNSPEC_TLS_GD);
+  rtx call_insn = emit_call_insn (gen_tls_gd_get_addr (sym));
+  /* Should we set RTL_CONST_CALL_P?  We read memory, but not in a
+     way that the application should care.  */
+  RTL_PURE_CALL_P (call_insn) = 1;
+  add_function_usage_to (call_insn, call_fusage);
+
+  insns = get_insns ();
+  end_sequence ();
+
+  rtx dest = gen_reg_rtx (Pmode);
+  emit_libcall_block (insns, dest, r0, eqv);
+  return dest;
+}
+
+#define DTPOFF_ZERO_SYM ".tdata"
+
+/* Return a legitimized address for ADDR,
+   which is a SYMBOL_REF with tls_model MODEL.  */
+
+static rtx
+arc_legitimize_tls_address (rtx addr, enum tls_model model)
+{
+  if (!flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC)
+    model = TLS_MODEL_LOCAL_EXEC;
+
+  switch (model)
+    {
+    case TLS_MODEL_LOCAL_DYNAMIC:
+      rtx base;
+      tree decl;
+      const char *base_name;
+      rtvec v;
+
+      decl = SYMBOL_REF_DECL (addr);
+      base_name = DTPOFF_ZERO_SYM;
+      if (decl && bss_initializer_p (decl))
+	base_name = ".tbss";
+
+      base = gen_rtx_SYMBOL_REF (Pmode, base_name);
+      if (strcmp (base_name, DTPOFF_ZERO_SYM) == 0)
+	{
+	  if (!flag_pic)
+	    goto local_exec;
+	  v = gen_rtvec (1, addr);
+	}
+      else
+	v = gen_rtvec (2, addr, base);
+      addr = gen_rtx_UNSPEC (Pmode, v, UNSPEC_TLS_OFF);
+      addr = gen_rtx_CONST (Pmode, addr);
+      base = arc_legitimize_tls_address (base, TLS_MODEL_GLOBAL_DYNAMIC);
+      return gen_rtx_PLUS (Pmode, force_reg (Pmode, base), addr);
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      return arc_emit_call_tls_get_addr (addr, UNSPEC_TLS_GD, addr);
+    case TLS_MODEL_INITIAL_EXEC:
+      addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLS_IE);
+      addr = gen_rtx_CONST (Pmode, addr);
+      addr = copy_to_mode_reg (Pmode, gen_const_mem (Pmode, addr));
+      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+    case TLS_MODEL_LOCAL_EXEC:
+    local_exec:
+      addr = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), UNSPEC_TLS_OFF);
+      addr = gen_rtx_CONST (Pmode, addr);
+      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Legitimize a pic address reference in ORIG.
    The return value is the legitimated address.
    If OLDX is non-zero, it is the target to assign the address to first.  */
 
-rtx
+static rtx
 arc_legitimize_pic_address (rtx orig, rtx oldx)
 {
   rtx addr = orig;
@@ -4654,40 +4822,36 @@ arc_legitimize_pic_address (rtx orig, rtx oldx)
 
   if (GET_CODE (addr) == LABEL_REF)
     ; /* Do nothing.  */
-  else if (GET_CODE (addr) == SYMBOL_REF
-	   && (CONSTANT_POOL_ADDRESS_P (addr)
-	       || SYMBOL_REF_LOCAL_P (addr)))
+  else if (GET_CODE (addr) == SYMBOL_REF)
     {
-      /* This symbol may be referenced via a displacement from the PIC
-	 base address (@GOTOFF).  */
-
-      /* FIXME: if we had a way to emit pc-relative adds that don't
-	 create a GOT entry, we could do without the use of the gp register.  */
-      crtl->uses_pic_offset_table = 1;
-      pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOTOFF);
-      pat = gen_rtx_CONST (Pmode, pat);
-      pat = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pat);
-
-      if (oldx == NULL)
-	oldx = gen_reg_rtx (Pmode);
-
-      if (oldx != 0)
+      enum tls_model model = SYMBOL_REF_TLS_MODEL (addr);
+      if (model != 0)
+	return arc_legitimize_tls_address (addr, model);
+      else if (!flag_pic)
+	return orig;
+      else if (CONSTANT_POOL_ADDRESS_P (addr) || SYMBOL_REF_LOCAL_P (addr))
 	{
-	  emit_move_insn (oldx, pat);
-	  pat = oldx;
+	  /* This symbol may be referenced via a displacement from the
+	     PIC base address (@GOTOFF).  */
+
+	  /* FIXME: if we had a way to emit pc-relative adds that
+	     don't create a GOT entry, we could do without the use of
+	     the gp register.  */
+	  crtl->uses_pic_offset_table = 1;
+	  pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOTOFF);
+	  pat = gen_rtx_CONST (Pmode, pat);
+	  pat = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pat);
+	}
+      else
+	{
+	  /* This symbol must be referenced via a load from the
+	     Global Offset Table (@GOTPC).  */
+	  pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOT);
+	  pat = gen_rtx_CONST (Pmode, pat);
+	  pat = gen_const_mem (Pmode, pat);
 	}
 
-    }
-  else if (GET_CODE (addr) == SYMBOL_REF)
-    {
-      /* This symbol must be referenced via a load from the
-	 Global Offset Table (@GOTPC).  */
-
-      pat = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, addr), ARC_UNSPEC_GOT);
-      pat = gen_rtx_CONST (Pmode, pat);
-      pat = gen_const_mem (Pmode, pat);
-
-      if (oldx == 0)
+      if (oldx == NULL)
 	oldx = gen_reg_rtx (Pmode);
 
       emit_move_insn (oldx, pat);
@@ -4710,45 +4874,23 @@ arc_legitimize_pic_address (rtx orig, rtx oldx)
 	{
 	  rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
 
-	  /* Check first to see if this is a constant offset from a @GOTOFF
-	     symbol reference.  */
-	  if ((GET_CODE (op0) == LABEL_REF
-	       || (GET_CODE (op0) == SYMBOL_REF
-		   && (CONSTANT_POOL_ADDRESS_P (op0)
-		       || SYMBOL_REF_LOCAL_P (op0))))
-	      && GET_CODE (op1) == CONST_INT)
-	    {
-	      /* FIXME: like above, could do without gp reference.  */
-	      crtl->uses_pic_offset_table = 1;
-	      pat
-		= gen_rtx_UNSPEC (Pmode, gen_rtvec (1, op0), ARC_UNSPEC_GOTOFF);
-	      pat = gen_rtx_PLUS (Pmode, pat, op1);
-	      pat = gen_rtx_CONST (Pmode, pat);
-	      pat = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, pat);
-
-	      if (oldx != 0)
-		{
-		  emit_move_insn (oldx, pat);
-		  pat = oldx;
-		}
-	    }
-	  else
-	    {
-	      base = arc_legitimize_pic_address (XEXP (addr, 0), oldx);
-	      pat  = arc_legitimize_pic_address (XEXP (addr, 1),
+	  base = arc_legitimize_pic_address (op0, oldx);
+	  pat  = arc_legitimize_pic_address (op1,
 					     base == oldx ? NULL_RTX : oldx);
 
-	      if (GET_CODE (pat) == CONST_INT)
-		pat = plus_constant (Pmode, base, INTVAL (pat));
-	      else
+	  if (base == op0 && pat == op1)
+	    return orig;
+
+	  if (GET_CODE (pat) == CONST_INT)
+	    pat = plus_constant (Pmode, base, INTVAL (pat));
+	  else
+	    {
+	      if (GET_CODE (pat) == PLUS && CONSTANT_P (XEXP (pat, 1)))
 		{
-		  if (GET_CODE (pat) == PLUS && CONSTANT_P (XEXP (pat, 1)))
-		    {
-		      base = gen_rtx_PLUS (Pmode, base, XEXP (pat, 0));
-		      pat = XEXP (pat, 1);
-		    }
-		  pat = gen_rtx_PLUS (Pmode, base, pat);
+		  base = gen_rtx_PLUS (Pmode, base, XEXP (pat, 0));
+		  pat = XEXP (pat, 1);
 		}
+	      pat = gen_rtx_PLUS (Pmode, base, pat);
 	    }
 	}
     }
@@ -4864,26 +5006,47 @@ arc_output_pic_addr_const (FILE * file, rtx x, int code)
 
 
     case UNSPEC:
-      gcc_assert (XVECLEN (x, 0) == 1);
-      if (XINT (x, 1) == ARC_UNSPEC_GOT)
-	fputs ("pcl,", file);
-      arc_output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+      const char *suffix;
+      bool pcrel; pcrel = false;
+      rtx base; base = NULL;
+      gcc_assert (XVECLEN (x, 0) >= 1);
       switch (XINT (x, 1))
 	{
 	case ARC_UNSPEC_GOT:
-	  fputs ("@gotpc", file);
+	  suffix = "@gotpc", pcrel = true;
 	  break;
 	case ARC_UNSPEC_GOTOFF:
-	  fputs ("@gotoff", file);
+	  suffix = "@gotoff";
 	  break;
 	case ARC_UNSPEC_PLT:
-	  fputs ("@plt", file);
+	  suffix = "@plt";
+	  break;
+	case UNSPEC_TLS_GD:
+	  suffix = "@tlsgd", pcrel = true;
+	  break;
+	case UNSPEC_TLS_IE:
+	  suffix = "@tlsie", pcrel = true;
+	  break;
+	case UNSPEC_TLS_OFF:
+	  if (XVECLEN (x, 0) == 2)
+	    base = XVECEXP (x, 0, 1);
+	  if (SYMBOL_REF_TLS_MODEL (XVECEXP (x, 0, 0)) == TLS_MODEL_LOCAL_EXEC
+	      || (!flag_pic && !base))
+	    suffix = "@tpoff";
+	  else
+	    suffix = "@dtpoff";
 	  break;
 	default:
 	  output_operand_lossage ("invalid UNSPEC as operand: %d", XINT (x,1));
 	  break;
 	}
-       break;
+      if (pcrel)
+	fputs ("pcl,", file);
+      arc_output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+      fputs (suffix, file);
+      if (base)
+	arc_output_pic_addr_const (file, base, code);
+      break;
 
     default:
       output_operand_lossage ("invalid expression as operand");
@@ -4897,15 +5060,18 @@ arc_output_pic_addr_const (FILE * file, rtx x, int code)
 
 /* Emit insns to move operands[1] into operands[0].  */
 
-void
-emit_pic_move (rtx *operands, machine_mode)
+static void
+prepare_pic_move (rtx *operands, machine_mode)
 {
-  rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
-
-  if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
+  if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1])
+      && flag_pic)
     operands[1] = force_reg (Pmode, operands[1]);
   else
-    operands[1] = arc_legitimize_pic_address (operands[1], temp);
+    {
+      rtx temp = (reload_in_progress ? operands[0]
+		  : flag_pic? gen_reg_rtx (Pmode) : NULL_RTX);
+      operands[1] = arc_legitimize_pic_address (operands[1], temp);
+    }
 }
 
 
@@ -5107,9 +5273,12 @@ arc_legitimate_pic_operand_p (rtx x)
    satisfies CONSTANT_P.  */
 
 bool
-arc_legitimate_constant_p (machine_mode, rtx x)
+arc_legitimate_constant_p (machine_mode mode, rtx x)
 {
-  if (!flag_pic)
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
+    return false;
+
+  if (!flag_pic && mode != Pmode)
     return true;
 
   switch (GET_CODE (x))
@@ -5119,7 +5288,9 @@ arc_legitimate_constant_p (machine_mode, rtx x)
 
       if (GET_CODE (x) == PLUS)
 	{
-	  if (GET_CODE (XEXP (x, 1)) != CONST_INT)
+	  if (flag_pic
+	      ? GET_CODE (XEXP (x, 1)) != CONST_INT
+	      : !arc_legitimate_constant_p (mode, XEXP (x, 1)))
 	    return false;
 	  x = XEXP (x, 0);
 	}
@@ -5131,6 +5302,9 @@ arc_legitimate_constant_p (machine_mode, rtx x)
 	  case ARC_UNSPEC_PLT:
 	  case ARC_UNSPEC_GOTOFF:
 	  case ARC_UNSPEC_GOT:
+	  case UNSPEC_TLS_GD:
+	  case UNSPEC_TLS_IE:
+	  case UNSPEC_TLS_OFF:
 	  case UNSPEC_PROF:
 	    return true;
 
@@ -5145,9 +5319,14 @@ arc_legitimate_constant_p (machine_mode, rtx x)
       /* Return true.  */
       break;
 
-    case LABEL_REF:
     case SYMBOL_REF:
-      return false;
+      if (SYMBOL_REF_TLS_MODEL (x))
+	return false;
+      /* Fall through.  */
+    case LABEL_REF:
+      if (flag_pic)
+	return false;
+      /* Fall through.  */
 
     default:
       break;
@@ -5170,12 +5349,29 @@ arc_legitimate_address_p (machine_mode mode, rtx x, bool strict)
      return true;
   if (GET_CODE (x) == CONST_INT && LARGE_INT (INTVAL (x)))
      return true;
-  if ((GET_MODE_SIZE (mode) != 16)
-      && (GET_CODE (x) == SYMBOL_REF
-	  || GET_CODE (x) == LABEL_REF
-	  || GET_CODE (x) == CONST))
+
+  /* When we compile for size avoid const (@sym + offset)
+     addresses.  */
+  if (!flag_pic && optimize_size && !reload_completed
+      && (GET_CODE (x) == CONST)
+      && (GET_CODE (XEXP (x, 0)) == PLUS)
+      && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF)
+      && SYMBOL_REF_TLS_MODEL (XEXP (XEXP (x, 0), 0)) == 0
+      && !SYMBOL_REF_FUNCTION_P (XEXP (XEXP (x, 0), 0)))
     {
-      if (!flag_pic || arc_legitimate_pic_addr_p (x))
+      rtx addend = XEXP (XEXP (x, 0), 1);
+      gcc_assert (CONST_INT_P (addend));
+      HOST_WIDE_INT offset = INTVAL (addend);
+
+      /* Allow addresses having a large offset to pass.  Anyhow they
+	 will end in a limm.  */
+      return !(offset > -1024 && offset < 1020);
+    }
+
+  if ((GET_MODE_SIZE (mode) != 16) && CONSTANT_P (x))
+    {
+      if (flag_pic ? arc_legitimate_pic_addr_p (x)
+	  : arc_legitimate_constant_p (Pmode, x))
 	return true;
     }
   if ((GET_CODE (x) == PRE_DEC || GET_CODE (x) == PRE_INC
@@ -6787,8 +6983,12 @@ arc_rewrite_small_data_p (const_rtx x)
 	x = XEXP (x, 0);
     }
 
-  return (GET_CODE (x) ==  SYMBOL_REF
-	  && SYMBOL_REF_SMALL_P(x));
+  if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_SMALL_P (x))
+    {
+      gcc_assert (SYMBOL_REF_TLS_MODEL (x) == 0);
+      return true;
+    }
+  return false;
 }
 
 /* If possible, rewrite OP so that it refers to small data using
@@ -7207,40 +7407,39 @@ prepare_move_operands (rtx *operands, machine_mode mode)
 {
   /* We used to do this only for MODE_INT Modes, but addresses to floating
      point variables may well be in the small data section.  */
-  if (1)
+  if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[0], Pmode))
+    operands[0] = arc_rewrite_small_data (operands[0]);
+
+  if (mode == SImode && SYMBOLIC_CONST (operands[1]))
     {
-      if (!TARGET_NO_SDATA_SET && small_data_pattern (operands[0], Pmode))
-	operands[0] = arc_rewrite_small_data (operands[0]);
-      else if (mode == SImode && flag_pic && SYMBOLIC_CONST (operands[1]))
-	{
-	  emit_pic_move (operands, SImode);
+      prepare_pic_move (operands, SImode);
 
-	  /* Disable any REG_EQUALs associated with the symref
-	     otherwise the optimization pass undoes the work done
-	     here and references the variable directly.  */
-	}
-      else if (GET_CODE (operands[0]) != MEM
-	       && !TARGET_NO_SDATA_SET
-	       && small_data_pattern (operands[1], Pmode))
-       {
-	  /* This is to take care of address calculations involving sdata
-	     variables.  */
-	  operands[1] = arc_rewrite_small_data (operands[1]);
-
-	  emit_insn (gen_rtx_SET (operands[0],operands[1]));
-	  /* ??? This note is useless, since it only restates the set itself.
-	     We should rather use the original SYMBOL_REF.  However, there is
-	     the problem that we are lying to the compiler about these
-	     SYMBOL_REFs to start with.  symbol@sda should be encoded specially
-	     so that we can tell it apart from an actual symbol.  */
-	  set_unique_reg_note (get_last_insn (), REG_EQUAL, operands[1]);
-
-	  /* Take care of the REG_EQUAL note that will be attached to mark the
-	     output reg equal to the initial symbol_ref after this code is
-	     executed.  */
-	  emit_move_insn (operands[0], operands[0]);
-	  return true;
-	}
+      /* Disable any REG_EQUALs associated with the symref
+	 otherwise the optimization pass undoes the work done
+	 here and references the variable directly.  */
+    }
+
+  if (GET_CODE (operands[0]) != MEM
+      && !TARGET_NO_SDATA_SET
+      && small_data_pattern (operands[1], Pmode))
+    {
+      /* This is to take care of address calculations involving sdata
+	 variables.  */
+      operands[1] = arc_rewrite_small_data (operands[1]);
+
+      emit_insn (gen_rtx_SET (operands[0],operands[1]));
+      /* ??? This note is useless, since it only restates the set itself.
+	 We should rather use the original SYMBOL_REF.  However, there is
+	 the problem that we are lying to the compiler about these
+	 SYMBOL_REFs to start with.  symbol@sda should be encoded specially
+	 so that we can tell it apart from an actual symbol.  */
+      set_unique_reg_note (get_last_insn (), REG_EQUAL, operands[1]);
+
+      /* Take care of the REG_EQUAL note that will be attached to mark the
+	 output reg equal to the initial symbol_ref after this code is
+	 executed.  */
+      emit_move_insn (operands[0], operands[0]);
+      return true;
     }
 
   if (MEM_P (operands[0])
@@ -8238,6 +8437,13 @@ arc_legitimize_address_0 (rtx x, rtx oldx ATTRIBUTE_UNUSED,
 static rtx
 arc_legitimize_address (rtx orig_x, rtx oldx, machine_mode mode)
 {
+  if (GET_CODE (orig_x) == SYMBOL_REF)
+    {
+      enum tls_model model = SYMBOL_REF_TLS_MODEL (orig_x);
+      if (model != 0)
+	return arc_legitimize_tls_address (orig_x, model);
+    }
+
   rtx new_x = arc_legitimize_address_0 (orig_x, oldx, mode);
 
   if (new_x)
@@ -8972,6 +9178,8 @@ arc_can_follow_jump (const rtx_insn *follower, const rtx_insn *followee)
 bool
 arc_epilogue_uses (int regno)
 {
+  if (regno == arc_tp_regno)
+    return true;
   if (reload_completed)
     {
       if (ARC_INTERRUPT_P (cfun->machine->fn_type))
@@ -8987,6 +9195,16 @@ arc_epilogue_uses (int regno)
     return regno == arc_return_address_regs[arc_compute_function_type (cfun)];
 }
 
+/* Helper for EH_USES macro.  */
+
+bool
+arc_eh_uses (int regno)
+{
+  if (regno == arc_tp_regno)
+    return true;
+  return false;
+}
+
 #ifndef TARGET_NO_LRA
 #define TARGET_NO_LRA !TARGET_LRA
 #endif
@@ -9492,6 +9710,13 @@ arc_dwarf_register_span (rtx rtl)
    return p;
 }
 
+/* We can't inline this in INSN_REFERENCES_ARE_DELAYED because
+   resource.h doesn't include the required header files.  */
+bool
+insn_is_tls_gd_dispatch (rtx_insn *insn)
+{
+  return recog_memoized (insn) == CODE_FOR_tls_gd_dispatch;
+}
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index 1c2a38d..13dc867 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -109,6 +109,8 @@ along with GCC; see the file COPYING3.  If not see
       builtin_define ("__ARC_SIMD__");	\
     if (TARGET_BARREL_SHIFTER)		\
       builtin_define ("__Xbarrel_shifter");\
+    builtin_define_with_int_value ("__ARC_TLS_REGNO__", \
+				   arc_tp_regno);	\
     builtin_assert ("cpu=arc");		\
     builtin_assert ("machine=arc");	\
     builtin_define (TARGET_BIG_ENDIAN	\
@@ -201,7 +203,13 @@ along with GCC; see the file COPYING3.  If not see
 #endif
 
 #if DEFAULT_LIBC != LIBC_UCLIBC
-#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti%O%s %{pg|p:crtg.o%s} crtbegin.o%s"
+#define ARC_TLS_EXTRA_START_SPEC "crttls.o%s"
+
+#define EXTRA_SPECS \
+  { "arc_tls_extra_start_spec", ARC_TLS_EXTRA_START_SPEC }, \
+
+#define STARTFILE_SPEC "%{!shared:crt0.o%s} crti%O%s %{pg|p:crtg.o%s} " \
+  "%(arc_tls_extra_start_spec) crtbegin.o%s"
 #else
 #define STARTFILE_SPEC   "%{!shared:%{!mkernel:crt1.o%s}} crti.o%s \
   %{!shared:%{pg|p|profile:crtg.o%s} crtbegin.o%s} %{shared:crtbeginS.o%s}"
@@ -748,9 +756,10 @@ extern enum reg_class arc_regno_reg_class[];
    or a pseudo reg currently allocated to a suitable hard reg.
    Since they use reg_renumber, they are safe only once reg_renumber
    has been allocated, which happens in local-alloc.c.  */
-#define REGNO_OK_FOR_BASE_P(REGNO) \
-((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63) ||\
- (unsigned) reg_renumber[REGNO] < 29)
+#define REGNO_OK_FOR_BASE_P(REGNO)					\
+  ((REGNO) < 29 || ((REGNO) == ARG_POINTER_REGNUM) || ((REGNO) == 63)	\
+   || ((unsigned) reg_renumber[REGNO] < 29)				\
+   || ((unsigned) (REGNO) == (unsigned) arc_tp_regno))
 
 #define REGNO_OK_FOR_INDEX_P(REGNO) REGNO_OK_FOR_BASE_P(REGNO)
 
@@ -937,6 +946,8 @@ arc_return_addr_rtx(COUNT,FRAME)
 
 #define EPILOGUE_USES(REGNO) arc_epilogue_uses ((REGNO))
 
+#define EH_USES(REGNO) arc_eh_uses((REGNO))
+
 /* Definitions for register eliminations.
 
    This is an array of structures.  Each structure initializes one pair
@@ -1657,7 +1668,8 @@ extern enum arc_function_type arc_compute_function_type (struct function *);
    && GET_CODE (PATTERN (X)) != CLOBBER		\
    && (get_attr_type (X) == TYPE_CALL || get_attr_type (X) == TYPE_SFUNC))
 
-#define INSN_REFERENCES_ARE_DELAYED(insn) INSN_SETS_ARE_DELAYED (insn)
+#define INSN_REFERENCES_ARE_DELAYED(insn)				\
+  (INSN_SETS_ARE_DELAYED (insn) && !insn_is_tls_gd_dispatch (insn))
 
 #define CALL_ATTR(X, NAME) \
   ((CALL_P (X) || NONJUMP_INSN_P (X)) \
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index 4193d26..99fd878 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -111,6 +111,10 @@
   ARC_UNSPEC_PLT
   ARC_UNSPEC_GOT
   ARC_UNSPEC_GOTOFF
+  UNSPEC_TLS_GD
+  UNSPEC_TLS_LD
+  UNSPEC_TLS_IE
+  UNSPEC_TLS_OFF
   UNSPEC_ARC_NORM
   UNSPEC_ARC_NORMW
   UNSPEC_ARC_SWAP
@@ -169,6 +173,7 @@
    (R1_REG 1)
    (R2_REG 2)
    (R3_REG 3)
+   (R10_REG 10)
    (R12_REG 12)
    (SP_REG 28)
    (ILINK1_REGNUM 29)
@@ -5277,6 +5282,72 @@
   [(set_attr "type" "call")
    (set_attr "is_SIBCALL" "yes")])
 
+(define_insn "tls_load_tp_soft"
+  [(set (reg:SI R0_REG) (unspec:SI [(const_int 0)] UNSPEC_TLS_OFF))
+   (clobber (reg:SI RETURN_ADDR_REGNUM))]
+  ""
+  "*return arc_output_libcall (\"__read_tp\");"
+  [(set_attr "is_sfunc" "yes")
+   (set_attr "predicable" "yes")])
+
+(define_insn "tls_gd_load"
+  [(set (match_operand:SI 0 "dest_reg_operand" "=Rcq#q,c")
+	(unspec:SI [(match_operand:SI 1 "register_operand" "Rcq#q,c")
+		    (match_operand:SI 2 "symbolic_operand" "X,X")]
+	 UNSPEC_TLS_GD))]
+  ""
+  ".tls_gd_ld %2`ld%? %0,[%1]"
+  [(set_attr "type" "load")
+   ; if the linker has to patch this into IE, we need a long insns
+   ; (FIXME: or two short insn, ld_s / jl_s.  missing -Os optimization.)
+   (set_attr_alternative "iscompact"
+     [(cond [(ne (symbol_ref "arc_tp_regno == 30") (const_int 0))
+	     (const_string "*")] (const_string "maybe"))
+      (const_string "*")])])
+
+(define_insn "tls_gd_get_addr"
+  [(set (reg:SI R0_REG)
+	(call:SI (mem:SI (unspec:SI [(match_operand:SI 0
+				      "symbolic_operand" "X,X")]
+			  UNSPEC_TLS_GD))
+		 (const_int 0)))
+   (clobber (reg:SI RETURN_ADDR_REGNUM))]
+  ""
+  ".tls_gd_ld %0`bl%* __tls_get_addr@plt"
+  [(set_attr "type" "call")
+   ; With TARGET_MEDIUM_CALLS, plt calls are not predicable.
+   (set_attr "predicable" "no")])
+
+; We make this call specific to the tls symbol to avoid commoning this
+; with calls for other symbols; we want the linker to be able to
+(define_insn "tls_gd_dispatch"
+  [(set (reg:SI R0_REG)
+	(unspec:SI
+	  [(reg:SI R0_REG)
+	   (call (mem:SI (match_operand:SI 0 "register_operand" "Rcq,q,c"))
+		 (const_int 0))
+	   (match_operand:SI 1 "symbolic_operand" "X,X,X")]
+	 UNSPEC_TLS_GD))
+   (clobber (reg:SI RETURN_ADDR_REGNUM))
+   (clobber (reg:DI R10_REG))
+   (clobber (reg:SI R12_REG))]
+  ""
+  ".tls_gd_call %1`jl%!%* [%0]"
+  [(set_attr "type" "call")
+   (set_attr "iscompact" "maybe,false,*")
+   (set_attr "predicable" "no,no,yes")])
+
+;; For thread pointer builtins
+(define_expand "get_thread_pointersi"
+  [(set (match_operand:SI 0 "register_operand") (match_dup 1))]
+ ""
+ "operands[1] = gen_rtx_REG (Pmode, arc_tp_regno);")
+
+(define_expand "set_thread_pointersi"
+  [(set (match_dup 1) (match_operand:SI 0 "register_operand"))]
+ ""
+ "operands[1] = gen_rtx_REG (Pmode, arc_tp_regno);")
+
 ;; If hardware floating point is available, don't define a negdf pattern;
 ;; it would be something like:
 ;;(define_insn "negdf2"
diff --git a/gcc/config/arc/arc.opt b/gcc/config/arc/arc.opt
index 2227b75..76f66a2 100644
--- a/gcc/config/arc/arc.opt
+++ b/gcc/config/arc/arc.opt
@@ -456,3 +456,10 @@ Enum(arc_fpu) String(fpus_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD)
 
 EnumValue
 Enum(arc_fpu) String(fpud_all) Value(FPU_SP | FPU_SC | FPU_SF | FPU_SD | FPU_DP | FPU_DC | FPU_DF | FPU_DD)
+
+mtp-regno=
+Target RejectNegative Joined UInteger Var(arc_tp_regno) Init(25)
+Specify thread pointer register number
+
+mtp-regno=none
+Target RejectNegative Var(arc_tp_regno,-1)
diff --git a/gcc/config/arc/predicates.md b/gcc/config/arc/predicates.md
index 85bbf84..3c657c6 100644
--- a/gcc/config/arc/predicates.md
+++ b/gcc/config/arc/predicates.md
@@ -351,9 +351,12 @@
   switch (GET_CODE (op))
     {
     case SYMBOL_REF :
+      if (SYMBOL_REF_TLS_MODEL (op))
+	return 0;
     case LABEL_REF :
+      return 1;
     case CONST :
-      return (!flag_pic || arc_legitimate_pic_operand_p(op));
+      return arc_legitimate_constant_p (mode, op);
     case CONST_INT :
       return (LARGE_INT (INTVAL (op)));
     case CONST_DOUBLE :
@@ -451,6 +454,16 @@
 	    && (GET_CODE (XEXP (addr, 1)) != PLUS
 		|| !CONST_INT_P (XEXP (XEXP (addr, 1), 1))))
 	  return 0;
+	/* CONST_INT / CONST_DOUBLE is fine, but the PIC CONST ([..] UNSPEC))
+	   constructs are effectively indexed.  */
+	if (flag_pic)
+	  {
+	    rtx ad0 = addr;
+	    while (GET_CODE (ad0) == PLUS)
+	      ad0 = XEXP (ad0, 0);
+	    if (GET_CODE (ad0) == CONST || GET_CODE (ad0) == UNSPEC)
+	      return 0;
+	  }
 	return address_operand (addr, mode);
       }
     default :
diff --git a/gcc/configure b/gcc/configure
index 1c6e340..4bff5b3 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -23849,6 +23849,12 @@ foo:	.long	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  arc*-*-*)
+    conftest_s='
+	add_s r0,r0, @foo@tpoff'
+	tls_first_major=2
+	tls_first_minor=23
+	;;
   cris-*-*|crisv32-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 6c1dcd9..e6198ec 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -3081,6 +3081,12 @@ foo:	.long	25
 	tls_first_minor=13
 	tls_as_opt=--fatal-warnings
 	;;
+  arc*-*-*)
+    conftest_s='
+	add_s r0,r0, @foo@tpoff'
+	tls_first_major=2
+	tls_first_minor=23
+	;;
   cris-*-*|crisv32-*-*)
     conftest_s='
 	.section ".tdata","awT",@progbits
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index e9763d4..b6aa7f0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -592,7 +592,7 @@ Objective-C and Objective-C++ Dialects}.
 -mcrc -mdsp-packa -mdvbf -mlock -mmac-d16 -mmac-24 -mrtsc -mswape @gol
 -mtelephony -mxy -misize -mannotate-align -marclinux -marclinux_prof @gol
 -mlong-calls -mmedium-calls -msdata @gol
--mucb-mcount -mvolatile-cache @gol
+-mucb-mcount -mvolatile-cache -mtp-regno=@var{regno} @gol
 -malign-call -mauto-modify-reg -mbbit-peephole -mno-brcc @gol
 -mcase-vector-pcrel -mcompact-casesi -mno-cond-exec -mearly-cbranchsi @gol
 -mexpand-adddi -mindexed-loads -mlra -mlra-priority-none @gol
@@ -13340,6 +13340,10 @@ Enable code density instructions for ARC EM, default on for ARC HS.
 @opindex mll64
 Enable double load/store operations for ARC HS cores.
 
+@item -mtp-regno=@var{regno}
+@opindex mtp-regno
+Specify thread pointer register number.
+
 @item -mmpy-option=@var{multo}
 @opindex mmpy-option
 Compile ARCv2 code with a multiplier design option.  @samp{wlh1} is
-- 
1.9.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 0/2] [ARC] Add TLS support for ARC.
@ 2016-04-15 10:00 Claudiu Zissulescu
  2016-04-15 10:00 ` [PATCH 2/2] [ARC] Add TLS support Claudiu Zissulescu
  2016-04-15 10:00 ` [PATCH 1/2] [ARC/LIBGCC] " Claudiu Zissulescu
  0 siblings, 2 replies; 7+ messages in thread
From: Claudiu Zissulescu @ 2016-04-15 10:00 UTC (permalink / raw)
  To: gcc-patches; +Cc: Claudiu.Zissulescu, gnu, Francois.Bedard, jeremy.bennett

Hi,

This series of two patches are adding TLS support for ARC
processors. The first patch is changing libgcc, the second patch is
changing the ARC' backend. I've tested the mods using dg.exp,
compile.exp, tls.exp, and execute.exp.

Ok to apply?
Claudiu

Claudiu Zissulescu (2):
  [ARC/LIBGCC] Add TLS support.
  [ARC] Add TLS support.

 gcc/config/arc/arc-protos.h  |   4 +-
 gcc/config/arc/arc.c         | 503 +++++++++++++++++++++++++++++++------------
 gcc/config/arc/arc.h         |  22 +-
 gcc/config/arc/arc.md        |  71 ++++++
 gcc/config/arc/arc.opt       |   7 +
 gcc/config/arc/predicates.md |  15 +-
 gcc/configure                |   6 +
 gcc/configure.ac             |   6 +
 gcc/doc/invoke.texi          |   6 +-
 libgcc/config.host           |   2 +
 libgcc/config/arc/crttls.S   |  67 ++++++
 libgcc/config/arc/t-arc      |   3 +
 12 files changed, 564 insertions(+), 148 deletions(-)
 create mode 100644 libgcc/config/arc/crttls.S

-- 
1.9.1

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] [ARC/LIBGCC] Add TLS support.
  2016-04-15 10:00 ` [PATCH 1/2] [ARC/LIBGCC] " Claudiu Zissulescu
@ 2016-04-28  8:37   ` Joern Wolfgang Rennecke
  2016-04-28 11:55     ` Claudiu Zissulescu
  0 siblings, 1 reply; 7+ messages in thread
From: Joern Wolfgang Rennecke @ 2016-04-28  8:37 UTC (permalink / raw)
  To: Claudiu Zissulescu, gcc-patches; +Cc: Francois.Bedard, jeremy.bennett



On 15/04/16 10:58, Claudiu Zissulescu wrote:
> TLS mods for libgcc.
>
> OK to apply?
> Claudiu
>
> libgcc/
> 2016-04-15  Claudiu Zissulescu  <claziss@synopsys.com>
> 	    Joern Rennecke  <joern.rennecke@embecosm.com>
>
> 	* config/arc/crttls.S: New file.
> 	* config/arc/t-arc: New rule.
> 	* config.host (arc*-*-elf*, arc*-*-linux*): Add crttls.o.
> -
  The libgcc part is OK.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] [ARC] Add TLS support.
  2016-04-15 10:00 ` [PATCH 2/2] [ARC] Add TLS support Claudiu Zissulescu
@ 2016-04-28  8:47   ` Joern Wolfgang Rennecke
  2016-04-28 11:56     ` Claudiu Zissulescu
  0 siblings, 1 reply; 7+ messages in thread
From: Joern Wolfgang Rennecke @ 2016-04-28  8:47 UTC (permalink / raw)
  To: Claudiu Zissulescu, gcc-patches; +Cc: Francois.Bedard, jeremy.bennett



On 15/04/16 10:58, Claudiu Zissulescu wrote:
> TLS mods for ARC backend.
>
> OK to apply?
> Claudiu
>
>
This is using an inefficient TLS global dynamic implementation that 
would not
be expected in a new and/or well-tuned port.
However, if you have to work with a legacy runtime, that can't be helped.

> +(define_insn "tls_gd_load"
..
> +   ; if the linker has to patch this into IE, we need a long insns

Typo: a long insn.

arc_emit_call_tls_get_addr is missing a start-of-function comment.

Otherwise this is OK.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH 1/2] [ARC/LIBGCC] Add TLS support.
  2016-04-28  8:37   ` Joern Wolfgang Rennecke
@ 2016-04-28 11:55     ` Claudiu Zissulescu
  0 siblings, 0 replies; 7+ messages in thread
From: Claudiu Zissulescu @ 2016-04-28 11:55 UTC (permalink / raw)
  To: Joern Wolfgang Rennecke, gcc-patches; +Cc: Francois.Bedard, jeremy.bennett

Committed r235558.

Thanks,
Claudiu

> > libgcc/
> > 2016-04-15  Claudiu Zissulescu  <claziss@synopsys.com>
> > 	    Joern Rennecke  <joern.rennecke@embecosm.com>
> >
> > 	* config/arc/crttls.S: New file.
> > 	* config/arc/t-arc: New rule.
> > 	* config.host (arc*-*-elf*, arc*-*-linux*): Add crttls.o.
> > -
>   The libgcc part is OK.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* RE: [PATCH 2/2] [ARC] Add TLS support.
  2016-04-28  8:47   ` Joern Wolfgang Rennecke
@ 2016-04-28 11:56     ` Claudiu Zissulescu
  0 siblings, 0 replies; 7+ messages in thread
From: Claudiu Zissulescu @ 2016-04-28 11:56 UTC (permalink / raw)
  To: Joern Wolfgang Rennecke, gcc-patches; +Cc: Francois.Bedard, jeremy.bennett

Fixing the loose ends. Committed r235559

Thanks,
Claudiu

> 
> > +(define_insn "tls_gd_load"
> ..
> > +   ; if the linker has to patch this into IE, we need a long insns
> 
> Typo: a long insn.
> 
> arc_emit_call_tls_get_addr is missing a start-of-function comment.
> 
> Otherwise this is OK.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2016-04-28 11:56 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-15 10:00 [PATCH 0/2] [ARC] Add TLS support for ARC Claudiu Zissulescu
2016-04-15 10:00 ` [PATCH 2/2] [ARC] Add TLS support Claudiu Zissulescu
2016-04-28  8:47   ` Joern Wolfgang Rennecke
2016-04-28 11:56     ` Claudiu Zissulescu
2016-04-15 10:00 ` [PATCH 1/2] [ARC/LIBGCC] " Claudiu Zissulescu
2016-04-28  8:37   ` Joern Wolfgang Rennecke
2016-04-28 11:55     ` Claudiu Zissulescu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).