[2/6,ARC] Cleanup TLS implementation.

Message ID 20181010080016.12317-3-claziss@gmail.com
State New
Headers show
Series
  • ARC updates
Related show

Commit Message

Claudiu Zissulescu Oct. 10, 2018, 8 a.m.
Cleanup TLS implementation and add a number of tests.

gcc/
2018-07-25  Claudiu Zissulescu  <claziss@synopsys.com>

	* config/arc/arc.c (arc_get_tp): Remove function.
	(arc_emit_call_tls_get_addr): Likewise.
	(arc_call_tls_get_addr): New function.
	(arc_legitimize_tls_address): Make use of arc_call_tls_get_addr.
	* config/arc/arc.md (tls_load_tp_soft): Remove.
	(tls_gd_get_addr): Likewise.

testsuite/
2018-07-25  Claudiu Zissulescu  <claziss@synopsys.com>

	* gcc.target/arc/tls-gd.c: New file.
	* gcc.target/arc/tls-ie.c: Likewise.
	* gcc.target/arc/tls-ld.c: Likewise.
	* gcc.target/arc/tls-le.c: Likewise.
---
 gcc/config/arc/arc.c                  | 95 +++++++++++----------------
 gcc/config/arc/arc.md                 | 21 ------
 gcc/testsuite/gcc.target/arc/tls-1.c  |  2 +-
 gcc/testsuite/gcc.target/arc/tls-gd.c | 17 +++++
 gcc/testsuite/gcc.target/arc/tls-ie.c | 17 +++++
 gcc/testsuite/gcc.target/arc/tls-ld.c | 18 +++++
 gcc/testsuite/gcc.target/arc/tls-le.c | 16 +++++
 7 files changed, 106 insertions(+), 80 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/arc/tls-gd.c
 create mode 100644 gcc/testsuite/gcc.target/arc/tls-ie.c
 create mode 100644 gcc/testsuite/gcc.target/arc/tls-ld.c
 create mode 100644 gcc/testsuite/gcc.target/arc/tls-le.c

Comments

Andrew Burgess Oct. 11, 2018, 10:11 a.m. | #1
* Claudiu Zissulescu <claziss@gmail.com> [2018-10-10 11:00:12 +0300]:

> Cleanup TLS implementation and add a number of tests.
> 
> gcc/
> 2018-07-25  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* config/arc/arc.c (arc_get_tp): Remove function.
> 	(arc_emit_call_tls_get_addr): Likewise.
> 	(arc_call_tls_get_addr): New function.
> 	(arc_legitimize_tls_address): Make use of arc_call_tls_get_addr.
> 	* config/arc/arc.md (tls_load_tp_soft): Remove.
> 	(tls_gd_get_addr): Likewise.
> 
> testsuite/
> 2018-07-25  Claudiu Zissulescu  <claziss@synopsys.com>
> 
> 	* gcc.target/arc/tls-gd.c: New file.
> 	* gcc.target/arc/tls-ie.c: Likewise.
> 	* gcc.target/arc/tls-ld.c: Likewise.
> 	* gcc.target/arc/tls-le.c: Likewise.
> ---
>  gcc/config/arc/arc.c                  | 95 +++++++++++----------------
>  gcc/config/arc/arc.md                 | 21 ------
>  gcc/testsuite/gcc.target/arc/tls-1.c  |  2 +-
>  gcc/testsuite/gcc.target/arc/tls-gd.c | 17 +++++
>  gcc/testsuite/gcc.target/arc/tls-ie.c | 17 +++++
>  gcc/testsuite/gcc.target/arc/tls-ld.c | 18 +++++
>  gcc/testsuite/gcc.target/arc/tls-le.c | 16 +++++
>  7 files changed, 106 insertions(+), 80 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.target/arc/tls-gd.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/tls-ie.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/tls-ld.c
>  create mode 100644 gcc/testsuite/gcc.target/arc/tls-le.c
> 
> diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
> index de4c7433c1b..56f566795ff 100644
> --- a/gcc/config/arc/arc.c
> +++ b/gcc/config/arc/arc.c
> @@ -5559,51 +5559,30 @@ arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
>    return false;
>  }
>  
> -/* Get the thread pointer.  */
> +/* Emit a call to __tls_get_addr.  TI is the argument to this function.
> +   RET is an RTX for the return value location.  The entire insn sequence
> +   is returned.  */

This comment should be moved down to arc_call_tls_get_addr, and a new
comment should be added explaining what arc_tls_symbol is used for.

Otherwise, this seems fine.

Thanks,
Andrew

> +static GTY(()) rtx arc_tls_symbol;
>  
>  static rtx
> -arc_get_tp (void)
> +arc_call_tls_get_addr (rtx ti)
>  {
> -   /* 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;
> -}
> -
> -/* Helper to be used by TLS Global dynamic model.  */
> -
> -static rtx
> -arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
> -{
> -  rtx r0 = gen_rtx_REG (Pmode, R0_REG);
> -  rtx call_fusage = NULL_RTX;
> -
> -  start_sequence ();
> -
> -  rtx x = arc_unspec_offset (sym, reloc);
> -  emit_move_insn (r0, x);
> -  use_reg (&call_fusage, r0);
> +  rtx arg = gen_rtx_REG (Pmode, R0_REG);
> +  rtx ret = gen_rtx_REG (Pmode, R0_REG);
> +  rtx fn;
> +  rtx_insn *insn;
>  
> -  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);
> +  if (!arc_tls_symbol)
> +    arc_tls_symbol = init_one_libfunc ("__tls_get_addr");
>  
> -  rtx_insn *insns = get_insns ();
> -  end_sequence ();
> +  emit_move_insn (arg, ti);
> +  fn = gen_rtx_MEM (SImode, arc_tls_symbol);
> +  insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx));
> +  RTL_CONST_CALL_P (insn) = 1;
> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret);
> +  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg);
>  
> -  rtx dest = gen_reg_rtx (Pmode);
> -  emit_libcall_block (insns, dest, r0, eqv);
> -  return dest;
> +  return ret;
>  }
>  
>  #define DTPOFF_ZERO_SYM ".tdata"
> @@ -5614,16 +5593,26 @@ arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
>  static rtx
>  arc_legitimize_tls_address (rtx addr, enum tls_model model)
>  {
> +  rtx tmp;
> +
>    if (!flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC)
>      model = TLS_MODEL_LOCAL_EXEC;
>  
> +
> +  /* The TP pointer needs to be set.  */
> +  gcc_assert (arc_tp_regno != -1);
> +
>    switch (model)
>      {
> +    case TLS_MODEL_GLOBAL_DYNAMIC:
> +      tmp = gen_reg_rtx (Pmode);
> +      emit_move_insn (tmp, arc_unspec_offset (addr, UNSPEC_TLS_GD));
> +      return arc_call_tls_get_addr (tmp);
> +
>      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;
> @@ -5631,31 +5620,21 @@ arc_legitimize_tls_address (rtx addr, enum tls_model model)
>  	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);
> +      tmp = gen_reg_rtx (Pmode);
> +      emit_move_insn (tmp, arc_unspec_offset (base, UNSPEC_TLS_GD));
> +      base = arc_call_tls_get_addr (tmp);
> +      return gen_rtx_PLUS (Pmode, force_reg (Pmode, base),
> +			   arc_unspec_offset (addr, UNSPEC_TLS_OFF));
>  
>      case TLS_MODEL_INITIAL_EXEC:
>        addr = arc_unspec_offset (addr, UNSPEC_TLS_IE);
>        addr = copy_to_mode_reg (Pmode, gen_const_mem (Pmode, addr));
> -      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
> +      return gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, arc_tp_regno), addr);
>  
>      case TLS_MODEL_LOCAL_EXEC:
> -    local_exec:
>        addr = arc_unspec_offset (addr, UNSPEC_TLS_OFF);
> -      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
> +      return gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, arc_tp_regno), addr);
> +
>      default:
>        gcc_unreachable ();
>      }
> diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
> index d73289a20c4..6ea67791627 100644
> --- a/gcc/config/arc/arc.md
> +++ b/gcc/config/arc/arc.md
> @@ -5310,27 +5310,6 @@ archs4x, archs4xd, archs4xd_slow"
>    [(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_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")])
> -
>  ;; For thread pointer builtins
>  (define_expand "get_thread_pointersi"
>    [(set (match_operand:SI 0 "register_operand") (match_dup 1))]
> diff --git a/gcc/testsuite/gcc.target/arc/tls-1.c b/gcc/testsuite/gcc.target/arc/tls-1.c
> index 6521b641549..da21a5ba032 100644
> --- a/gcc/testsuite/gcc.target/arc/tls-1.c
> +++ b/gcc/testsuite/gcc.target/arc/tls-1.c
> @@ -1,6 +1,6 @@
>  /* { dg-do compile } */
>  /* { dg-require-effective-target tls } */
> -/* { dg-skip-if "" { arc-*-elf* } } */
> +/* { dg-skip-if "" { arc*-*-elf* } } */
>  /* { dg-options "-O3 -std=gnu99" } */
>  
>  /* Check if addressing the `pos` member of struct is done via tls
> diff --git a/gcc/testsuite/gcc.target/arc/tls-gd.c b/gcc/testsuite/gcc.target/arc/tls-gd.c
> new file mode 100644
> index 00000000000..aa1b5429b08
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/tls-gd.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target fpic } */
> +/* { dg-options "-O2 -fpic -ftls-model=global-dynamic" } */
> +/* { dg-require-effective-target tls } */
> +/* { dg-skip-if "" { arc*-*-elf* } } */
> +
> +/* Check if tls global dynamic is correctly generated.  */
> +
> +extern __thread int e2;
> +
> +int *ae2 (void)
> +{
> +  return &e2;
> +}
> +
> +/* { dg-final { scan-assembler "add r0,pcl,@e2@tlsgd" } } */
> +/* { dg-final { scan-assembler "bl @__tls_get_addr@plt" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/tls-ie.c b/gcc/testsuite/gcc.target/arc/tls-ie.c
> new file mode 100644
> index 00000000000..0c981cfbf67
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/tls-ie.c
> @@ -0,0 +1,17 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target fpic } */
> +/* { dg-options "-O2 -fpic -ftls-model=initial-exec" } */
> +/* { dg-require-effective-target tls } */
> +/* { dg-skip-if "" { arc*-*-elf* } } */
> +
> +/* Check if tls initial execution is correctly generated.  */
> +
> +extern __thread int e2;
> +
> +int *ae2 (void)
> +{
> +  return &e2;
> +}
> +
> +/* { dg-final { scan-assembler "ld r0,\\\[pcl,@e2@tlsie\\\]" } } */
> +/* { dg-final { scan-assembler "add_s r0,r0,r25" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/tls-ld.c b/gcc/testsuite/gcc.target/arc/tls-ld.c
> new file mode 100644
> index 00000000000..351c3f02abd
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/tls-ld.c
> @@ -0,0 +1,18 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target fpic } */
> +/* { dg-options "-O2 -fpic -ftls-model=local-dynamic" } */
> +/* { dg-require-effective-target tls } */
> +/* { dg-skip-if "" { arc*-*-elf* } } */
> +
> +/* Check if tls local dynamic is correctly generated.  */
> +
> +extern __thread int e2;
> +
> +int *ae2 (void)
> +{
> +  return &e2;
> +}
> +
> +/* { dg-final { scan-assembler "add r0,pcl,@.tbss@tlsgd" } } */
> +/* { dg-final { scan-assembler "bl @__tls_get_addr@plt" } } */
> +/* { dg-final { scan-assembler "add_s r0,r0,@e2@dtpoff" } } */
> diff --git a/gcc/testsuite/gcc.target/arc/tls-le.c b/gcc/testsuite/gcc.target/arc/tls-le.c
> new file mode 100644
> index 00000000000..ae3089b5070
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/arc/tls-le.c
> @@ -0,0 +1,16 @@
> +/* { dg-do compile } */
> +/* { dg-require-effective-target fpic } */
> +/* { dg-options "-O2 -fpic -ftls-model=local-exec" } */
> +/* { dg-require-effective-target tls } */
> +/* { dg-skip-if "" { arc*-*-elf* } } */
> +
> +/* Check if tls local execution is correctly generated.  */
> +
> +extern __thread int e2;
> +
> +int *ae2 (void)
> +{
> +  return &e2;
> +}
> +
> +/* { dg-final { scan-assembler "add r0,r25,@e2@tpoff" } } */
> -- 
> 2.17.1
>

Patch

diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index de4c7433c1b..56f566795ff 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -5559,51 +5559,30 @@  arc_raw_symbolic_reference_mentioned_p (rtx op, bool skip_local)
   return false;
 }
 
-/* Get the thread pointer.  */
+/* Emit a call to __tls_get_addr.  TI is the argument to this function.
+   RET is an RTX for the return value location.  The entire insn sequence
+   is returned.  */
+static GTY(()) rtx arc_tls_symbol;
 
 static rtx
-arc_get_tp (void)
+arc_call_tls_get_addr (rtx ti)
 {
-   /* 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;
-}
-
-/* Helper to be used by TLS Global dynamic model.  */
-
-static rtx
-arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
-{
-  rtx r0 = gen_rtx_REG (Pmode, R0_REG);
-  rtx call_fusage = NULL_RTX;
-
-  start_sequence ();
-
-  rtx x = arc_unspec_offset (sym, reloc);
-  emit_move_insn (r0, x);
-  use_reg (&call_fusage, r0);
+  rtx arg = gen_rtx_REG (Pmode, R0_REG);
+  rtx ret = gen_rtx_REG (Pmode, R0_REG);
+  rtx fn;
+  rtx_insn *insn;
 
-  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);
+  if (!arc_tls_symbol)
+    arc_tls_symbol = init_one_libfunc ("__tls_get_addr");
 
-  rtx_insn *insns = get_insns ();
-  end_sequence ();
+  emit_move_insn (arg, ti);
+  fn = gen_rtx_MEM (SImode, arc_tls_symbol);
+  insn = emit_call_insn (gen_call_value (ret, fn, const0_rtx));
+  RTL_CONST_CALL_P (insn) = 1;
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), ret);
+  use_reg (&CALL_INSN_FUNCTION_USAGE (insn), arg);
 
-  rtx dest = gen_reg_rtx (Pmode);
-  emit_libcall_block (insns, dest, r0, eqv);
-  return dest;
+  return ret;
 }
 
 #define DTPOFF_ZERO_SYM ".tdata"
@@ -5614,16 +5593,26 @@  arc_emit_call_tls_get_addr (rtx sym, int reloc, rtx eqv)
 static rtx
 arc_legitimize_tls_address (rtx addr, enum tls_model model)
 {
+  rtx tmp;
+
   if (!flag_pic && model == TLS_MODEL_LOCAL_DYNAMIC)
     model = TLS_MODEL_LOCAL_EXEC;
 
+
+  /* The TP pointer needs to be set.  */
+  gcc_assert (arc_tp_regno != -1);
+
   switch (model)
     {
+    case TLS_MODEL_GLOBAL_DYNAMIC:
+      tmp = gen_reg_rtx (Pmode);
+      emit_move_insn (tmp, arc_unspec_offset (addr, UNSPEC_TLS_GD));
+      return arc_call_tls_get_addr (tmp);
+
     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;
@@ -5631,31 +5620,21 @@  arc_legitimize_tls_address (rtx addr, enum tls_model model)
 	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);
+      tmp = gen_reg_rtx (Pmode);
+      emit_move_insn (tmp, arc_unspec_offset (base, UNSPEC_TLS_GD));
+      base = arc_call_tls_get_addr (tmp);
+      return gen_rtx_PLUS (Pmode, force_reg (Pmode, base),
+			   arc_unspec_offset (addr, UNSPEC_TLS_OFF));
 
     case TLS_MODEL_INITIAL_EXEC:
       addr = arc_unspec_offset (addr, UNSPEC_TLS_IE);
       addr = copy_to_mode_reg (Pmode, gen_const_mem (Pmode, addr));
-      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+      return gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, arc_tp_regno), addr);
 
     case TLS_MODEL_LOCAL_EXEC:
-    local_exec:
       addr = arc_unspec_offset (addr, UNSPEC_TLS_OFF);
-      return gen_rtx_PLUS (Pmode, arc_get_tp (), addr);
+      return gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, arc_tp_regno), addr);
+
     default:
       gcc_unreachable ();
     }
diff --git a/gcc/config/arc/arc.md b/gcc/config/arc/arc.md
index d73289a20c4..6ea67791627 100644
--- a/gcc/config/arc/arc.md
+++ b/gcc/config/arc/arc.md
@@ -5310,27 +5310,6 @@  archs4x, archs4xd, archs4xd_slow"
   [(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_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")])
-
 ;; For thread pointer builtins
 (define_expand "get_thread_pointersi"
   [(set (match_operand:SI 0 "register_operand") (match_dup 1))]
diff --git a/gcc/testsuite/gcc.target/arc/tls-1.c b/gcc/testsuite/gcc.target/arc/tls-1.c
index 6521b641549..da21a5ba032 100644
--- a/gcc/testsuite/gcc.target/arc/tls-1.c
+++ b/gcc/testsuite/gcc.target/arc/tls-1.c
@@ -1,6 +1,6 @@ 
 /* { dg-do compile } */
 /* { dg-require-effective-target tls } */
-/* { dg-skip-if "" { arc-*-elf* } } */
+/* { dg-skip-if "" { arc*-*-elf* } } */
 /* { dg-options "-O3 -std=gnu99" } */
 
 /* Check if addressing the `pos` member of struct is done via tls
diff --git a/gcc/testsuite/gcc.target/arc/tls-gd.c b/gcc/testsuite/gcc.target/arc/tls-gd.c
new file mode 100644
index 00000000000..aa1b5429b08
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/tls-gd.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -fpic -ftls-model=global-dynamic" } */
+/* { dg-require-effective-target tls } */
+/* { dg-skip-if "" { arc*-*-elf* } } */
+
+/* Check if tls global dynamic is correctly generated.  */
+
+extern __thread int e2;
+
+int *ae2 (void)
+{
+  return &e2;
+}
+
+/* { dg-final { scan-assembler "add r0,pcl,@e2@tlsgd" } } */
+/* { dg-final { scan-assembler "bl @__tls_get_addr@plt" } } */
diff --git a/gcc/testsuite/gcc.target/arc/tls-ie.c b/gcc/testsuite/gcc.target/arc/tls-ie.c
new file mode 100644
index 00000000000..0c981cfbf67
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/tls-ie.c
@@ -0,0 +1,17 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -fpic -ftls-model=initial-exec" } */
+/* { dg-require-effective-target tls } */
+/* { dg-skip-if "" { arc*-*-elf* } } */
+
+/* Check if tls initial execution is correctly generated.  */
+
+extern __thread int e2;
+
+int *ae2 (void)
+{
+  return &e2;
+}
+
+/* { dg-final { scan-assembler "ld r0,\\\[pcl,@e2@tlsie\\\]" } } */
+/* { dg-final { scan-assembler "add_s r0,r0,r25" } } */
diff --git a/gcc/testsuite/gcc.target/arc/tls-ld.c b/gcc/testsuite/gcc.target/arc/tls-ld.c
new file mode 100644
index 00000000000..351c3f02abd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/tls-ld.c
@@ -0,0 +1,18 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -fpic -ftls-model=local-dynamic" } */
+/* { dg-require-effective-target tls } */
+/* { dg-skip-if "" { arc*-*-elf* } } */
+
+/* Check if tls local dynamic is correctly generated.  */
+
+extern __thread int e2;
+
+int *ae2 (void)
+{
+  return &e2;
+}
+
+/* { dg-final { scan-assembler "add r0,pcl,@.tbss@tlsgd" } } */
+/* { dg-final { scan-assembler "bl @__tls_get_addr@plt" } } */
+/* { dg-final { scan-assembler "add_s r0,r0,@e2@dtpoff" } } */
diff --git a/gcc/testsuite/gcc.target/arc/tls-le.c b/gcc/testsuite/gcc.target/arc/tls-le.c
new file mode 100644
index 00000000000..ae3089b5070
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arc/tls-le.c
@@ -0,0 +1,16 @@ 
+/* { dg-do compile } */
+/* { dg-require-effective-target fpic } */
+/* { dg-options "-O2 -fpic -ftls-model=local-exec" } */
+/* { dg-require-effective-target tls } */
+/* { dg-skip-if "" { arc*-*-elf* } } */
+
+/* Check if tls local execution is correctly generated.  */
+
+extern __thread int e2;
+
+int *ae2 (void)
+{
+  return &e2;
+}
+
+/* { dg-final { scan-assembler "add r0,r25,@e2@tpoff" } } */