Index: gcc/config/mips/mips-ftypes.def
===================================================================
--- gcc/config/mips/mips-ftypes.def	(revision 182952)
+++ gcc/config/mips/mips-ftypes.def	(working copy)
@@ -51,6 +51,8 @@ DEF_MIPS_FTYPE (2, (INT, SF, SF))
 DEF_MIPS_FTYPE (2, (INT, V2SF, V2SF))
 DEF_MIPS_FTYPE (4, (INT, V2SF, V2SF, V2SF, V2SF))
 
+DEF_MIPS_FTYPE (0, (POINTER))
+
 DEF_MIPS_FTYPE (2, (SI, DI, SI))
 DEF_MIPS_FTYPE (2, (SI, POINTER, SI))
 DEF_MIPS_FTYPE (2, (DI, POINTER, SI))
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 182952)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -312,6 +312,14 @@
 	  && type == SYMBOL_GOT_PAGE_OFST);
 })
 
+(define_predicate "tls_reloc_operand"
+  (match_code "const,symbol_ref,label_ref")
+{
+  enum mips_symbol_type type;
+  return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &type)
+	  && (type == SYMBOL_DTPREL || type == SYMBOL_TPREL));
+})
+
 (define_predicate "symbol_ref_operand"
   (match_code "symbol_ref"))
 
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 182952)
+++ gcc/config/mips/mips.md	(working copy)
@@ -134,7 +134,9 @@
 ])
 
 (define_constants
-  [(TLS_GET_TP_REGNUM		3)
+  [(V0_REGNUM			2)
+   (TLS_GET_TP_REGNUM		3)
+   (PIC_JUMP_REGNUM		25)
    (RETURN_ADDR_REGNUM		31)
    (CPRESTORE_SLOT_REGNUM	76)
    (GOT_VERSION_REGNUM		79)
@@ -3933,6 +3935,23 @@
   operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
 })
 
+;; MIPS16 %dtprel_hi,%tprel_hi split pattern. Similar transform
+;; as above, for supporting MIPS16 TLS.
+(define_split
+  [(set (match_operand:SI 0 "d_operand")
+	(high:SI (match_operand:SI 1 "tls_reloc_operand")))]
+  "TARGET_MIPS16 && reload_completed"
+  [(set (match_dup 0) (match_dup 2))
+   (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
+{
+  /* SYMBOL_DTPREL_HI/TPREL_HI are ordered immediately after
+     SYMBOL_DTPREL/TPREL respectively, so use unspec_type + 1.  */
+  rtx unspec = XEXP (operands[1], 0);
+  int unspec_type = XINT (unspec, 1);
+  operands[2] = mips_unspec_address (XVECEXP (unspec, 0, 0),
+				     unspec_type + 1 - UNSPEC_ADDRESS_FIRST);
+})
+
 ;; Insns to fetch a symbol from a big GOT.
 
 (define_insn_and_split "*xgot_hi<mode>"
@@ -6492,6 +6511,17 @@
 ;;  ....................
 ;;
 
+(define_insn "consttable_tls_reloc"
+  [(unspec_volatile [(match_operand 0 "tls_reloc_operand" "")
+		     (match_operand 1 "const_int_operand" "")]
+		    UNSPEC_CONSTTABLE_INT)]
+  "TARGET_MIPS16_PCREL_LOADS"
+{
+  mips_output_tls_reloc_directive (operands[0], operands[1]);
+  return "";
+}
+  [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))])
+
 (define_insn "consttable_int"
   [(unspec_volatile [(match_operand 0 "consttable_operand" "")
 		     (match_operand 1 "const_int_operand" "")]
@@ -6593,6 +6623,60 @@
    ; See tls_get_tp_<mode>
    (set_attr "can_delay" "no")
    (set_attr "mode" "<MODE>")])
+
+;; In MIPS16 mode, the TLS base pointer is accessed by a
+;; libgcc helper function __mips16_rdhwr(), as 'rdhwr' is not
+;; accessible in MIPS16.
+;;
+;; This is not represented as a call insn, to avoid the
+;; unnecesarry clobbering of caller-save registers by a
+;; function consisting only of: "rdhwr $3,$29; j $31; nop;"
+;;
+;; A $25 clobber is added to cater for a $25 load stub added by the
+;; linker to __mips16_rdhwr when the call is made from non-PIC code.
+
+(define_insn_and_split "tls_get_tp_<mode>_mips16"
+  [(set (match_operand:P 0 "register_operand" "=d")
+	(unspec:P [(const_int 0)] UNSPEC_TLS_GET_TP))
+   (clobber (reg:P TLS_GET_TP_REGNUM))
+   (clobber (reg:P PIC_JUMP_REGNUM))
+   (clobber (reg:P RETURN_ADDR_REGNUM))]
+  "HAVE_AS_TLS && TARGET_MIPS16"
+  "#"
+  "&& reload_completed"
+  [(parallel [(set (reg:P TLS_GET_TP_REGNUM)
+  	      (unspec:P [(match_dup 1)] UNSPEC_TLS_GET_TP))
+	      (clobber (reg:P PIC_JUMP_REGNUM))
+	      (clobber (reg:P RETURN_ADDR_REGNUM))])
+   (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM)) ]
+  {
+    /* UNSPEC operand decides on direct/indirect pattern below.  */
+    rtx sym = gen_rtx_SYMBOL_REF (Pmode, "__mips16_rdhwr");
+    if (TARGET_ABSOLUTE_JUMPS)
+      operands[1] = sym;
+    else
+      {
+	operands[1] = gen_rtx_REG (Pmode, TLS_GET_TP_REGNUM);
+	mips_emit_move (operands[1], sym);
+      }
+  }
+  [(set_attr "type" "unknown")
+   (set_attr "can_delay" "no")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*tls_get_tp_<mode>_mips16_rdhwr"
+  [(set (reg:P TLS_GET_TP_REGNUM)
+	(unspec:P [(match_operand:P 0 "")] UNSPEC_TLS_GET_TP))
+	(clobber (reg:P PIC_JUMP_REGNUM))
+	(clobber (reg:P RETURN_ADDR_REGNUM))]
+  "HAVE_AS_TLS && TARGET_MIPS16"
+  {
+    return MIPS_CALL ("jal", operands, 0, -1);
+  }
+  [(set_attr "type" "call")
+   (set_attr "can_delay" "no")
+   (set_attr "mode" "<MODE>")])
+
 
 ;; Synchronization instructions.
 
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 182952)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -89,8 +89,10 @@ enum mips_symbol_context {
    SYMBOL_TLSGD
    SYMBOL_TLSLDM
    SYMBOL_DTPREL
+   SYMBOL_DTPREL_HI
    SYMBOL_GOTTPREL
    SYMBOL_TPREL
+   SYMBOL_TPREL_HI
        UNSPEC wrappers around SYMBOL_TLS, corresponding to the
        thread-local storage relocation operators.
 
@@ -127,8 +129,10 @@ enum mips_symbol_type {
   SYMBOL_TLSGD,
   SYMBOL_TLSLDM,
   SYMBOL_DTPREL,
+  SYMBOL_DTPREL_HI,
   SYMBOL_GOTTPREL,
   SYMBOL_TPREL,
+  SYMBOL_TPREL_HI,
   SYMBOL_32_HIGH,
   SYMBOL_64_HIGH,
   SYMBOL_64_MID,
@@ -341,6 +345,7 @@ extern bool mips_epilogue_uses (unsigned int);
 extern void mips_final_prescan_insn (rtx, rtx *, int);
 extern int mips_trampoline_code_size (void);
 extern void mips_function_profiler (FILE *);
+extern void mips_output_tls_reloc_directive (rtx, rtx);
 
 typedef rtx (*mulsidi3_gen_fn) (rtx, rtx, rtx);
 #ifdef RTX_CODE
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 182952)
+++ gcc/config/mips/mips.c	(working copy)
@@ -183,6 +183,7 @@ enum mips_address_type {
 };
 
 /* Macros to create an enumeration identifier for a function prototype.  */
+#define MIPS_FTYPE_NAME0(A) MIPS_##A##_FTYPE_VOID
 #define MIPS_FTYPE_NAME1(A, B) MIPS_##A##_FTYPE_##B
 #define MIPS_FTYPE_NAME2(A, B, C) MIPS_##A##_FTYPE_##B##_##C
 #define MIPS_FTYPE_NAME3(A, B, C, D) MIPS_##A##_FTYPE_##B##_##C##_##D
@@ -233,7 +234,10 @@ enum mips_builtin_type {
   MIPS_BUILTIN_CMP_SINGLE,
 
   /* For generating bposge32 branch instructions in MIPS32 DSP ASE.  */
-  MIPS_BUILTIN_BPOSGE32
+  MIPS_BUILTIN_BPOSGE32,
+
+  /* For generating accesses to the TLS thread pointer.  */
+  MIPS_BUILTIN_THREAD_POINTER
 };
 
 /* Invoke MACRO (COND) for each C.cond.fmt condition.  */
@@ -1763,6 +1767,8 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_
     case SYMBOL_GOTTPREL:
     case SYMBOL_TLS:
     case SYMBOL_HALF:
+    case SYMBOL_TPREL_HI:
+    case SYMBOL_DTPREL_HI:
       return false;
     }
   gcc_unreachable ();
@@ -1857,8 +1863,10 @@ mips_symbol_insns_1 (enum mips_symbol_type type, e
     case SYMBOL_TLSGD:
     case SYMBOL_TLSLDM:
     case SYMBOL_DTPREL:
+    case SYMBOL_DTPREL_HI:
     case SYMBOL_GOTTPREL:
     case SYMBOL_TPREL:
+    case SYMBOL_TPREL_HI:
     case SYMBOL_HALF:
       /* A 16-bit constant formed by a single relocation, or a 32-bit
 	 constant formed from a high 16-bit relocation and a low 16-bit
@@ -1928,14 +1936,23 @@ mips_cannot_force_const_mem (enum machine_mode mod
   if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type)
       && type != SYMBOL_FORCE_TO_MEM)
     {
+      if (TARGET_MIPS16_PCREL_LOADS)
+	{
+	  /* Under MIPS16, TLS DTP/TP-relative offsets are loaded from the
+	     constant pool, as this saves some code size compared to hi/lo
+	     constructing.  */
+	  if (type == SYMBOL_DTPREL || type == SYMBOL_TPREL)
+	    return false;
+
+	  /* If MIPS16 constant pools live in the text section, they should
+	     not refer to anything that might need run-time relocation.  */
+	  if (mips_got_symbol_type_p (type))
+	    return true;
+	}
+
       /* The same optimization as for CONST_INT.  */
       if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0)
 	return true;
-
-      /* If MIPS16 constant pools live in the text section, they should
-	 not refer to anything that might need run-time relocation.  */
-      if (TARGET_MIPS16_PCREL_LOADS && mips_got_symbol_type_p (type))
-	return true;
     }
 
   /* TLS symbols must be computed by mips_legitimize_move.  */
@@ -2820,11 +2837,20 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_
 /* Return a pseudo register that contains the current thread pointer.  */
 
 static rtx
-mips_get_tp (void)
+mips_get_tp (rtx target)
 {
-  rtx tp;
+  rtx tp = (target != NULL_RTX && REG_P (target)
+	    ? target : gen_reg_rtx (Pmode));
 
-  tp = gen_reg_rtx (Pmode);
+  if (TARGET_MIPS16)
+    {
+      if (Pmode == DImode)
+	emit_insn (gen_tls_get_tp_di_mips16 (tp));
+      else
+	emit_insn (gen_tls_get_tp_si_mips16 (tp));
+      return tp;
+    }
+
   if (Pmode == DImode)
     emit_insn (gen_tls_get_tp_di (tp));
   else
@@ -2842,12 +2868,6 @@ mips_legitimize_tls_address (rtx loc)
   rtx dest, insn, v0, tp, tmp1, tmp2, eqv;
   enum tls_model model;
 
-  if (TARGET_MIPS16)
-    {
-      sorry ("MIPS16 TLS");
-      return gen_reg_rtx (Pmode);
-    }
-
   model = SYMBOL_REF_TLS_MODEL (loc);
   /* Only TARGET_ABICALLS code can have more than one module; other
      code must be be static and should not use a GOT.  All TLS models
@@ -2875,13 +2895,23 @@ mips_legitimize_tls_address (rtx loc)
 			    UNSPEC_TLS_LDM);
       emit_libcall_block (insn, tmp1, v0, eqv);
 
-      tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
-      dest = gen_rtx_LO_SUM (Pmode, tmp2,
-			     mips_unspec_address (loc, SYMBOL_DTPREL));
+      if (TARGET_MIPS16_PCREL_LOADS)
+	{
+	  tmp2 = mips_force_temporary (NULL,
+				       mips_unspec_address (loc,
+							    SYMBOL_DTPREL));
+	  dest = gen_rtx_PLUS (Pmode, tmp1, tmp2);
+	}
+      else
+	{
+	  tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+	  dest = gen_rtx_LO_SUM (Pmode, tmp2,
+				 mips_unspec_address (loc, SYMBOL_DTPREL));
+	}
       break;
 
     case TLS_MODEL_INITIAL_EXEC:
-      tp = mips_get_tp ();
+      tp = mips_get_tp (NULL_RTX);
       tmp1 = gen_reg_rtx (Pmode);
       tmp2 = mips_unspec_address (loc, SYMBOL_GOTTPREL);
       if (Pmode == DImode)
@@ -2893,10 +2923,20 @@ mips_legitimize_tls_address (rtx loc)
       break;
 
     case TLS_MODEL_LOCAL_EXEC:
-      tp = mips_get_tp ();
-      tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL);
-      dest = gen_rtx_LO_SUM (Pmode, tmp1,
-			     mips_unspec_address (loc, SYMBOL_TPREL));
+      tp = mips_get_tp (NULL_RTX);
+      if (TARGET_MIPS16_PCREL_LOADS)
+	{
+	  tmp1 = mips_force_temporary (NULL,
+				       mips_unspec_address (loc,
+							    SYMBOL_TPREL));
+	  dest = gen_rtx_PLUS (Pmode, tp, tmp1);
+	}
+      else
+	{
+	  tmp1 = mips_unspec_offset_high (NULL, tp, loc, SYMBOL_TPREL);
+	  dest = gen_rtx_LO_SUM (Pmode, tmp1,
+				 mips_unspec_address (loc, SYMBOL_TPREL));
+	}
       break;
 
     default:
@@ -7291,16 +7331,24 @@ mips_init_relocs (void)
   mips_lo_relocs[SYMBOL_TLSGD] = "%tlsgd(";
   mips_lo_relocs[SYMBOL_TLSLDM] = "%tlsldm(";
 
-  mips_split_p[SYMBOL_DTPREL] = true;
-  mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
-  mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
+  if (! TARGET_MIPS16_PCREL_LOADS)
+    {
+      mips_split_p[SYMBOL_DTPREL] = true;
+      mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+      mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
 
-  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+      mips_split_p[SYMBOL_TPREL] = true;
+      mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
+      mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
 
-  mips_split_p[SYMBOL_TPREL] = true;
-  mips_hi_relocs[SYMBOL_TPREL] = "%tprel_hi(";
-  mips_lo_relocs[SYMBOL_TPREL] = "%tprel_lo(";
+      if (TARGET_MIPS16)
+	{
+	  mips_lo_relocs[SYMBOL_TPREL_HI] = "%tprel_hi(";
+	  mips_lo_relocs[SYMBOL_DTPREL_HI] = "%dtprel_hi(";
+	}
+    }
 
+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
   mips_lo_relocs[SYMBOL_HALF] = "%half(";
 }
 
@@ -12734,7 +12782,8 @@ struct mips_builtin_description {
   /* The function's prototype.  */
   enum mips_function_type function_type;
 
-  /* Whether the function is available.  */
+  /* Whether the function is available.  A NULL pointer value here
+     means the builtin is always available.  */
   unsigned int (*avail) (void);
 };
 
@@ -12904,6 +12953,12 @@ AVAIL_NON_MIPS16 (cache, TARGET_CACHE_BUILTIN)
 #define CODE_FOR_loongson_psubush CODE_FOR_ussubv4hi3
 #define CODE_FOR_loongson_psubusb CODE_FOR_ussubv8qi3
 
+/* Define a MIPS_BUILTIN_THREAD_POINTER builtin.  The parameters are fixed,
+   but we allow both __builtin* and __builtin_mips* prefixes below.  */
+#define THREAD_POINTER_BUILTIN(NAME)					\
+  { CODE_FOR_nothing, MIPS_FP_COND_f, #NAME,				\
+    MIPS_BUILTIN_THREAD_POINTER, MIPS_POINTER_FTYPE_VOID, NULL }
+
 static const struct mips_builtin_description mips_builtins[] = {
   DIRECT_BUILTIN (pll_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
   DIRECT_BUILTIN (pul_ps, MIPS_V2SF_FTYPE_V2SF_V2SF, paired_single),
@@ -13187,7 +13242,11 @@ static const struct mips_builtin_description mips_
   LOONGSON_BUILTIN_SUFFIX (punpcklwd, s, MIPS_V2SI_FTYPE_V2SI_V2SI),
 
   /* Sundry other built-in functions.  */
-  DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache)
+  DIRECT_NO_TARGET_BUILTIN (cache, MIPS_VOID_FTYPE_SI_CVPOINTER, cache),
+
+  /* TLS thread pointer built-in functions.  */
+  THREAD_POINTER_BUILTIN (__builtin_mips_thread_pointer),
+  THREAD_POINTER_BUILTIN (__builtin_thread_pointer)
 };
 
 /* Index I is the function declaration for mips_builtins[I], or null if the
@@ -13258,6 +13317,8 @@ mips_build_cvpointer_type (void)
 
 /* MIPS_FTYPE_ATYPESN takes N MIPS_FTYPES-like type codes and lists
    their associated MIPS_ATYPEs.  */
+#define MIPS_FTYPE_ATYPES0(A) MIPS_ATYPE_##A
+
 #define MIPS_FTYPE_ATYPES1(A, B) \
   MIPS_ATYPE_##A, MIPS_ATYPE_##B
 
@@ -13309,11 +13370,19 @@ mips_init_builtins (void)
   for (i = 0; i < ARRAY_SIZE (mips_builtins); i++)
     {
       d = &mips_builtins[i];
-      if (d->avail ())
-	mips_builtin_decls[i]
-	  = add_builtin_function (d->name,
-				  mips_build_function_type (d->function_type),
-				  i, BUILT_IN_MD, NULL, NULL);
+      if (d->avail && !d->avail ())
+	continue;
+
+      mips_builtin_decls[i]
+	= add_builtin_function (d->name,
+				mips_build_function_type (d->function_type),
+				i, BUILT_IN_MD, NULL, NULL);
+
+      if (d->builtin_type == MIPS_BUILTIN_THREAD_POINTER)
+ 	{
+ 	  TREE_NOTHROW (mips_builtin_decls[i]) = 1;
+ 	  TREE_READONLY (mips_builtin_decls[i]) = 1;
+ 	}
     }
 }
 
@@ -13544,20 +13613,21 @@ mips_expand_builtin (tree exp, rtx target, rtx sub
 		     enum machine_mode mode, int ignore)
 {
   tree fndecl;
-  unsigned int fcode, avail;
+  unsigned int fcode;
   const struct mips_builtin_description *d;
 
   fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
   fcode = DECL_FUNCTION_CODE (fndecl);
   gcc_assert (fcode < ARRAY_SIZE (mips_builtins));
   d = &mips_builtins[fcode];
-  avail = d->avail ();
-  gcc_assert (avail != 0);
-  if (TARGET_MIPS16)
+  if (d->avail && !d->avail ())
     {
-      error ("built-in function %qE not supported for MIPS16",
-	     DECL_NAME (fndecl));
-      return ignore ? const0_rtx : CONST0_RTX (mode);
+      if (TARGET_MIPS16)
+	{
+	  error ("built-in function %qE not supported for MIPS16",
+		 DECL_NAME (fndecl));
+	  return ignore ? const0_rtx : CONST0_RTX (mode);
+	}
     }
   switch (d->builtin_type)
     {
@@ -13582,6 +13652,9 @@ mips_expand_builtin (tree exp, rtx target, rtx sub
 
     case MIPS_BUILTIN_BPOSGE32:
       return mips_expand_builtin_bposge (d->builtin_type, target);
+
+    case MIPS_BUILTIN_THREAD_POINTER:
+      return mips_get_tp (target);
     }
   gcc_unreachable ();
 }
@@ -13771,7 +13844,7 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
   struct mips16_rewrite_pool_refs_info *info =
     (struct mips16_rewrite_pool_refs_info *) data;
 
-  if (force_to_mem_operand (*x, Pmode))
+  if (force_to_mem_operand (*x, Pmode) || tls_reloc_operand (*x, Pmode))
     {
       rtx mem = force_const_mem (GET_MODE (*x), *x);
       validate_change (info->insn, x, mem, false);
@@ -13783,6 +13856,11 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
       return -1;
     }
 
+  if (GET_CODE (*x) == UNSPEC
+      && XINT (*x, 1) == UNSPEC_TLS_GET_TP
+      && GET_CODE (XVECEXP (*x, 0, 0)) == SYMBOL_REF)
+    return -1;
+
   if (TARGET_MIPS16_TEXT_LOADS)
     mips16_rewrite_pool_constant (info->pool, x);
 
@@ -17108,6 +17186,28 @@ mips_expand_vec_minmax (rtx target, rtx op0, rtx o
   x = gen_rtx_IOR (vmode, t0, t1);
   emit_insn (gen_rtx_SET (VOIDmode, target, x));
 }
+
+/* Output a DTP/TP-relative relocation, used in MIPS16 TLS.  */
+
+void
+mips_output_tls_reloc_directive (rtx x, rtx size)
+{
+  const char *dir = NULL;
+  if (GET_CODE (x) == CONST)
+    x = XEXP (x, 0);
+  switch (UNSPEC_ADDRESS_TYPE (x))
+    {
+    case SYMBOL_DTPREL:
+      dir = INTVAL (size) == 4 ? ".dtprelword" : ".dtpreldword";
+      break;
+    case SYMBOL_TPREL:
+      dir = INTVAL (size) == 4 ? ".tprelword" : ".tpreldword";
+      break;
+    default:
+      gcc_unreachable ();
+    }
+  fprintf (asm_out_file, "\t%s\t%s\n", dir, XSTR (UNSPEC_ADDRESS (x), 0));
+}
 
 /* Initialize the GCC target structure.  */
 #undef TARGET_ASM_ALIGNED_HI_OP
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 182952)
+++ gcc/config/mips/mips.h	(working copy)
@@ -2841,8 +2841,32 @@ while (0)
 	jal " USER_LABEL_PREFIX #FUNC "\n\
 	" TEXT_SECTION_ASM_OP);
 #endif
+
+#else
+#if (defined _ABIO32 && _MIPS_SIM == _ABIO32)
+#ifdef __PIC__
+/* For MIPS16 PIC, construct the GP-value in $2 using PC-relative insns.  */
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)	\
+   asm (SECTION_OP "\n\
+	li $2,%hi(_gp_disp)\n\
+	addiu $3,$pc,%lo(_gp_disp)\n\
+	sll $2,16\n\
+	addu $2,$3\n\
+	lw $2,%got(" USER_LABEL_PREFIX #FUNC ")($2)\n\
+	addiu $2,%lo(" USER_LABEL_PREFIX #FUNC ")\n\
+	move $25,$2\n\
+	jalr $2\n\
+	" TEXT_SECTION_ASM_OP);
+#else
+#define CRT_CALL_STATIC_FUNCTION(SECTION_OP, FUNC)	\
+   asm (SECTION_OP "\n\
+	jal " USER_LABEL_PREFIX #FUNC "\n\
+	" TEXT_SECTION_ASM_OP);
 #endif
+#endif
 
+#endif /* __mips16 */
+
 #ifndef HAVE_AS_TLS
 #define HAVE_AS_TLS 0
 #endif
