diff mbox

[2/2,ARC] Add TLS support.

Message ID 1460714331-11715-3-git-send-email-claziss@synopsys.com
State New
Headers show

Commit Message

Claudiu Zissulescu April 15, 2016, 9:58 a.m. UTC
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(-)

Comments

Joern Wolfgang Rennecke April 28, 2016, 8:46 a.m. UTC | #1
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.
Claudiu Zissulescu April 28, 2016, 11:56 a.m. UTC | #2
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.
diff mbox

Patch

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