OSDN Git Service

gcc/
authorrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 15 Jan 2012 18:22:55 +0000 (18:22 +0000)
committerrsandifo <rsandifo@138bc75d-0d04-0410-961f-82ee72b054a4>
Sun, 15 Jan 2012 18:22:55 +0000 (18:22 +0000)
2012-01-08  Chung-Lin Tang  <cltang@codesourcery.com>
    Richard Sandiford  <rdsandiford@googlemail.com>

* config/mips/mips-protos.h (SYMBOL_FORCE_TO_MEM): Delete.
(SYMBOL_32_HIGH): Likewise.
(mips_output_tls_reloc_directive): Declare.
* config/mips/mips.h (PIC_FUNCTION_ADDR_REGNUM): Move to mips.md.
(mips_use_pcrel_pool_p, mips_lo_relocs, mips_hi_relocs): Declare.
* config/mips/mips.c (mips_use_pcrel_pool_p): New variable.
(mips_lo_relocs, mips_hi_relocs): Make extern.
(mips16_stub_function): Move up file.
(mips_classify_symbol): Remove SYMBOL_FORCE_TO_MEM handling.
(mips_symbolic_constant_p): Likewise.  Remove SYMBOL_32_HIGH too.
(mips_symbol_insns_1): Likewise.  Check mips_use_pcrel_pool_p.
(mips_cannot_force_const_mem): Use mips_use_pcrel_pool_p instead
of SYMBOL_FORCE_TO_MEM.  Only check mips_tls_symbol_ref_1
if it's false.
(mips_get_tp): Add MIPS16 support.
(mips_legitimize_tls_address): Remove MIPS16 sorry().
Generalize DTPREL and TPREL handling.
(mips_init_relocs): Initialize mips_use_pcrel_pool_p.
Add MIPS16 TLS support.
(mips_output_tls_reloc_directive): New function.
(mips16_rewrite_pool_refs): Ignore UNSPEC_TLS_GET_TPs.
* config/mips/predicates.md (symbolic_operand_with_high)
(tls_reloc_operand): New predicates.
(force_to_mem_operand): Use mips_use_pcrel_pool_p.
* config/mips/mips.md (UNSPEC_UNSHIFTED_HIGH): New unspec.
(PIC_FUNCTION_ADDR_REGNUM): Moved from mips.h.
(*unshifted_high): New instruction.  Use it for MIPS16
high splitter.
(consttable_tls_reloc, tls_get_tp_mips16_<mode>): New patterns.
(*tls_get_tp_mips16_call_<mode>): Likewise.

gcc/testsuite/
* gcc.target/mips/code-readable-2.c: Allow the jump table address
to be loaded from the constant pool, rather than via %hi and %lo.

libgcc/
2012-01-08  Chung-Lin Tang  <cltang@codesourcery.com>
    Richard Sandiford  <rdsandiford@googlemail.com>

* config/mips/libgcc-mips16.ver (__mips16_rdhwr): Add.
* config/mips/mips16.S (__mips16_rdhwr): New function.
* config/mips/t-mips16 (LIB1ASMFUNCS): Add _m16rdhwr.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@183195 138bc75d-0d04-0410-961f-82ee72b054a4

12 files changed:
gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/predicates.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/code-readable-2.c
libgcc/ChangeLog
libgcc/config/mips/libgcc-mips16.ver
libgcc/config/mips/mips16.S
libgcc/config/mips/t-mips16

index b74e609..66c43f1 100644 (file)
@@ -1,3 +1,37 @@
+2012-01-15  Chung-Lin Tang  <cltang@codesourcery.com>
+           Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * config/mips/mips-protos.h (SYMBOL_FORCE_TO_MEM): Delete.
+       (SYMBOL_32_HIGH): Likewise.
+       (mips_output_tls_reloc_directive): Declare.
+       * config/mips/mips.h (PIC_FUNCTION_ADDR_REGNUM): Move to mips.md.
+       (mips_use_pcrel_pool_p, mips_lo_relocs, mips_hi_relocs): Declare.
+       * config/mips/mips.c (mips_use_pcrel_pool_p): New variable.
+       (mips_lo_relocs, mips_hi_relocs): Make extern.
+       (mips16_stub_function): Move up file.
+       (mips_classify_symbol): Remove SYMBOL_FORCE_TO_MEM handling.
+       (mips_symbolic_constant_p): Likewise.  Remove SYMBOL_32_HIGH too.
+       (mips_symbol_insns_1): Likewise.  Check mips_use_pcrel_pool_p.
+       (mips_cannot_force_const_mem): Use mips_use_pcrel_pool_p instead
+       of SYMBOL_FORCE_TO_MEM.  Only check mips_tls_symbol_ref_1
+       if it's false.
+       (mips_get_tp): Add MIPS16 support.
+       (mips_legitimize_tls_address): Remove MIPS16 sorry().
+       Generalize DTPREL and TPREL handling.
+       (mips_init_relocs): Initialize mips_use_pcrel_pool_p.
+       Add MIPS16 TLS support.
+       (mips_output_tls_reloc_directive): New function.
+       (mips16_rewrite_pool_refs): Ignore UNSPEC_TLS_GET_TPs.
+       * config/mips/predicates.md (symbolic_operand_with_high)
+       (tls_reloc_operand): New predicates.
+       (force_to_mem_operand): Use mips_use_pcrel_pool_p.
+       * config/mips/mips.md (UNSPEC_UNSHIFTED_HIGH): New unspec.
+       (PIC_FUNCTION_ADDR_REGNUM): Moved from mips.h.
+       (*unshifted_high): New instruction.  Use it for MIPS16
+       high splitter.
+       (consttable_tls_reloc, tls_get_tp_mips16_<mode>): New patterns.
+       (*tls_get_tp_mips16_call_<mode>): Likewise.
+
 2012-01-15  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/51821
index ca0fb5e..45d2537 100644 (file)
@@ -56,9 +56,6 @@ enum mips_symbol_context {
        The symbol's value will be calculated using a MIPS16 PC-relative
        calculation.
 
-   SYMBOL_FORCE_TO_MEM
-       The symbol's value must be forced to memory and loaded from there.
-
    SYMBOL_GOT_PAGE_OFST
        The symbol's value will be calculated by loading an address
        from the GOT and then applying a 16-bit offset.
@@ -94,9 +91,6 @@ enum mips_symbol_context {
        UNSPEC wrappers around SYMBOL_TLS, corresponding to the
        thread-local storage relocation operators.
 
-   SYMBOL_32_HIGH
-       For a 32-bit symbolic address X, this is the value of %hi(X).
-
    SYMBOL_64_HIGH
        For a 64-bit symbolic address X, this is the value of
        (%highest(X) << 16) + %higher(X).
@@ -116,7 +110,6 @@ enum mips_symbol_type {
   SYMBOL_ABSOLUTE,
   SYMBOL_GP_RELATIVE,
   SYMBOL_PC_RELATIVE,
-  SYMBOL_FORCE_TO_MEM,
   SYMBOL_GOT_PAGE_OFST,
   SYMBOL_GOT_DISP,
   SYMBOL_GOTOFF_PAGE,
@@ -129,7 +122,6 @@ enum mips_symbol_type {
   SYMBOL_DTPREL,
   SYMBOL_GOTTPREL,
   SYMBOL_TPREL,
-  SYMBOL_32_HIGH,
   SYMBOL_64_HIGH,
   SYMBOL_64_MID,
   SYMBOL_64_LOW,
@@ -260,6 +252,7 @@ extern void mips_push_asm_switch (struct mips_asm_switch *);
 extern void mips_pop_asm_switch (struct mips_asm_switch *);
 extern void mips_output_external (FILE *, tree, const char *);
 extern void mips_output_ascii (FILE *, const char *, size_t);
+extern const char *mips_output_tls_reloc_directive (rtx *);
 extern void mips_output_aligned_decl_common (FILE *, tree, const char *,
                                             unsigned HOST_WIDE_INT,
                                             unsigned int);
index 33e238c..b29ec4a 100644 (file)
@@ -573,13 +573,17 @@ bool mips_split_p[NUM_SYMBOL_TYPES];
    can be split by mips_split_symbol.  */
 bool mips_split_hi_p[NUM_SYMBOL_TYPES];
 
+/* mips_use_pcrel_pool_p[X] is true if symbols of type X should be
+   forced into a PC-relative constant pool.  */
+bool mips_use_pcrel_pool_p[NUM_SYMBOL_TYPES];
+
 /* mips_lo_relocs[X] is the relocation to use when a symbol of type X
    appears in a LO_SUM.  It can be null if such LO_SUMs aren't valid or
    if they are matched by a special .md file pattern.  */
-static const char *mips_lo_relocs[NUM_SYMBOL_TYPES];
+const char *mips_lo_relocs[NUM_SYMBOL_TYPES];
 
 /* Likewise for HIGHs.  */
-static const char *mips_hi_relocs[NUM_SYMBOL_TYPES];
+const char *mips_hi_relocs[NUM_SYMBOL_TYPES];
 
 /* Target state for MIPS16.  */
 struct target_globals *mips16_globals;
@@ -1440,6 +1444,18 @@ mips_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x)
   return mips_const_insns (x) > 0;
 }
 \f
+/* Return a SYMBOL_REF for a MIPS16 function called NAME.  */
+
+static rtx
+mips16_stub_function (const char *name)
+{
+  rtx x;
+
+  x = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
+  SYMBOL_REF_FLAGS (x) |= (SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION);
+  return x;
+}
+\f
 /* Return true if symbols of type TYPE require a GOT access.  */
 
 static bool
@@ -1644,9 +1660,6 @@ mips_classify_symbol (const_rtx x, enum mips_symbol_context context)
       return SYMBOL_GOT_PAGE_OFST;
     }
 
-  if (TARGET_MIPS16_PCREL_LOADS && context != SYMBOL_CONTEXT_CALL)
-    return SYMBOL_FORCE_TO_MEM;
-
   return SYMBOL_ABSOLUTE;
 }
 
@@ -1709,8 +1722,6 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_context context,
   switch (*symbol_type)
     {
     case SYMBOL_ABSOLUTE:
-    case SYMBOL_FORCE_TO_MEM:
-    case SYMBOL_32_HIGH:
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
@@ -1776,6 +1787,17 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_context context,
 static int
 mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode)
 {
+  if (mips_use_pcrel_pool_p[(int) type])
+    {
+      if (mode == MAX_MACHINE_MODE)
+       /* LEAs will be converted into constant-pool references by
+          mips_reorg.  */
+       type = SYMBOL_PC_RELATIVE;
+      else
+       /* The constant must be loaded and then dereferenced.  */
+       return 0;
+    }
+
   switch (type)
     {
     case SYMBOL_ABSOLUTE:
@@ -1809,15 +1831,6 @@ mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode)
       /* The constant must be loaded using ADDIUPC or DADDIUPC first.  */
       return 0;
 
-    case SYMBOL_FORCE_TO_MEM:
-      /* LEAs will be converted into constant-pool references by
-        mips_reorg.  */
-      if (mode == MAX_MACHINE_MODE)
-       return 1;
-
-      /* The constant must be loaded and then dereferenced.  */
-      return 0;
-
     case SYMBOL_GOT_DISP:
       /* The constant will have to be loaded from the GOT before it
         is used in an address.  */
@@ -1850,7 +1863,6 @@ mips_symbol_insns_1 (enum mips_symbol_type type, enum machine_mode mode)
     case SYMBOL_GOTOFF_DISP:
     case SYMBOL_GOTOFF_CALL:
     case SYMBOL_GOTOFF_LOADGP:
-    case SYMBOL_32_HIGH:
     case SYMBOL_64_HIGH:
     case SYMBOL_64_MID:
     case SYMBOL_64_LOW:
@@ -1925,9 +1937,12 @@ mips_cannot_force_const_mem (enum machine_mode mode, rtx x)
     return true;
 
   split_const (x, &base, &offset);
-  if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type)
-      && type != SYMBOL_FORCE_TO_MEM)
+  if (mips_symbolic_constant_p (base, SYMBOL_CONTEXT_LEA, &type))
     {
+      /* See whether we explicitly want these symbols in the pool.  */
+      if (mips_use_pcrel_pool_p[(int) type])
+       return false;
+
       /* The same optimization as for CONST_INT.  */
       if (SMALL_INT (offset) && mips_symbol_insns (type, MAX_MACHINE_MODE) > 0)
        return true;
@@ -2822,13 +2837,18 @@ mips_call_tls_get_addr (rtx sym, enum mips_symbol_type type, rtx v0)
 static rtx
 mips_get_tp (void)
 {
-  rtx tp;
+  rtx tp, fn;
 
   tp = gen_reg_rtx (Pmode);
-  if (Pmode == DImode)
-    emit_insn (gen_tls_get_tp_di (tp));
+  if (TARGET_MIPS16)
+    {
+      fn = mips16_stub_function ("__mips16_rdhwr");
+      if (!call_insn_operand (fn, VOIDmode))
+       fn = force_reg (Pmode, fn);
+      emit_insn (PMODE_INSN (gen_tls_get_tp_mips16, (tp, fn)));
+    }
   else
-    emit_insn (gen_tls_get_tp_si (tp));
+    emit_insn (PMODE_INSN (gen_tls_get_tp, (tp)));
   return tp;
 }
 
@@ -2839,15 +2859,9 @@ mips_get_tp (void)
 static rtx
 mips_legitimize_tls_address (rtx loc)
 {
-  rtx dest, insn, v0, tp, tmp1, tmp2, eqv;
+  rtx dest, insn, v0, tp, tmp1, tmp2, eqv, offset;
   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,9 +2889,15 @@ 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));
+      offset = mips_unspec_address (loc, SYMBOL_DTPREL);
+      if (mips_split_p[SYMBOL_DTPREL])
+       {
+         tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_DTPREL);
+         dest = gen_rtx_LO_SUM (Pmode, tmp2, offset);
+       }
+      else
+       dest = expand_binop (Pmode, add_optab, tmp1, offset,
+                            0, 0, OPTAB_DIRECT);
       break;
 
     case TLS_MODEL_INITIAL_EXEC:
@@ -2893,10 +2913,16 @@ 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));
+      tmp1 = mips_get_tp ();
+      offset = mips_unspec_address (loc, SYMBOL_TPREL);
+      if (mips_split_p[SYMBOL_TPREL])
+       {
+         tmp2 = mips_unspec_offset_high (NULL, tmp1, loc, SYMBOL_TPREL);
+         dest = gen_rtx_LO_SUM (Pmode, tmp2, offset);
+       }
+      else
+       dest = expand_binop (Pmode, add_optab, tmp1, offset,
+                            0, 0, OPTAB_DIRECT);
       break;
 
     default:
@@ -5866,18 +5892,6 @@ struct mips16_stub {
 };
 static struct mips16_stub *mips16_stubs;
 
-/* Return a SYMBOL_REF for a MIPS16 function called NAME.  */
-
-static rtx
-mips16_stub_function (const char *name)
-{
-  rtx x;
-
-  x = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
-  SYMBOL_REF_FLAGS (x) |= (SYMBOL_FLAG_EXTERNAL | SYMBOL_FLAG_FUNCTION);
-  return x;
-}
-
 /* Return the two-character string that identifies floating-point
    return mode MODE in the name of a MIPS16 function stub.  */
 
@@ -7192,38 +7206,44 @@ mips_init_relocs (void)
 {
   memset (mips_split_p, '\0', sizeof (mips_split_p));
   memset (mips_split_hi_p, '\0', sizeof (mips_split_hi_p));
+  memset (mips_use_pcrel_pool_p, '\0', sizeof (mips_use_pcrel_pool_p));
   memset (mips_hi_relocs, '\0', sizeof (mips_hi_relocs));
   memset (mips_lo_relocs, '\0', sizeof (mips_lo_relocs));
 
-  if (ABI_HAS_64BIT_SYMBOLS)
+  if (TARGET_MIPS16_PCREL_LOADS)
+    mips_use_pcrel_pool_p[SYMBOL_ABSOLUTE] = true;
+  else
     {
-      if (TARGET_EXPLICIT_RELOCS)
+      if (ABI_HAS_64BIT_SYMBOLS)
        {
-         mips_split_p[SYMBOL_64_HIGH] = true;
-         mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
-         mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
+         if (TARGET_EXPLICIT_RELOCS)
+           {
+             mips_split_p[SYMBOL_64_HIGH] = true;
+             mips_hi_relocs[SYMBOL_64_HIGH] = "%highest(";
+             mips_lo_relocs[SYMBOL_64_HIGH] = "%higher(";
 
-         mips_split_p[SYMBOL_64_MID] = true;
-         mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
-         mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
+             mips_split_p[SYMBOL_64_MID] = true;
+             mips_hi_relocs[SYMBOL_64_MID] = "%higher(";
+             mips_lo_relocs[SYMBOL_64_MID] = "%hi(";
 
-         mips_split_p[SYMBOL_64_LOW] = true;
-         mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
-         mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
+             mips_split_p[SYMBOL_64_LOW] = true;
+             mips_hi_relocs[SYMBOL_64_LOW] = "%hi(";
+             mips_lo_relocs[SYMBOL_64_LOW] = "%lo(";
 
-         mips_split_p[SYMBOL_ABSOLUTE] = true;
-         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
+             mips_split_p[SYMBOL_ABSOLUTE] = true;
+             mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
+           }
        }
-    }
-  else
-    {
-      if (TARGET_EXPLICIT_RELOCS || mips_split_addresses_p () || TARGET_MIPS16)
+      else
        {
-         mips_split_p[SYMBOL_ABSOLUTE] = true;
-         mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
-         mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
-
-         mips_lo_relocs[SYMBOL_32_HIGH] = "%hi(";
+         if (TARGET_EXPLICIT_RELOCS
+             || mips_split_addresses_p ()
+             || TARGET_MIPS16)
+           {
+             mips_split_p[SYMBOL_ABSOLUTE] = true;
+             mips_hi_relocs[SYMBOL_ABSOLUTE] = "%hi(";
+             mips_lo_relocs[SYMBOL_ABSOLUTE] = "%lo(";
+           }
        }
     }
 
@@ -7291,16 +7311,23 @@ 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(";
-
-  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
+  if (TARGET_MIPS16_PCREL_LOADS)
+    {
+      mips_use_pcrel_pool_p[SYMBOL_DTPREL] = true;
+      mips_use_pcrel_pool_p[SYMBOL_TPREL] = true;
+    }
+  else
+    {
+      mips_split_p[SYMBOL_DTPREL] = true;
+      mips_hi_relocs[SYMBOL_DTPREL] = "%dtprel_hi(";
+      mips_lo_relocs[SYMBOL_DTPREL] = "%dtprel_lo(";
 
-  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(";
+    }
 
+  mips_lo_relocs[SYMBOL_GOTTPREL] = "%gottprel(";
   mips_lo_relocs[SYMBOL_HALF] = "%half(";
 }
 
@@ -8082,6 +8109,29 @@ mips_output_ascii (FILE *stream, const char *string, size_t len)
   fprintf (stream, "\"\n");
 }
 
+/* Return the pseudo-op for full SYMBOL_(D)TPREL address *ADDR.
+   Update *ADDR with the operand that should be printed.  */
+
+const char *
+mips_output_tls_reloc_directive (rtx *addr)
+{
+  enum mips_symbol_type type;
+
+  type = mips_classify_symbolic_expression (*addr, SYMBOL_CONTEXT_LEA);
+  *addr = mips_strip_unspec_address (*addr);
+  switch (type)
+    {
+    case SYMBOL_DTPREL:
+      return Pmode == SImode ? ".dtprelword\t%0" : ".dtpreldword\t%0";
+
+    case SYMBOL_TPREL:
+      return Pmode == SImode ? ".tprelword\t%0" : ".tpreldword\t%0";
+
+    default:
+      gcc_unreachable ();
+    }
+}
+
 /* Emit either a label, .comm, or .lcomm directive.  When using assembler
    macros, mark the symbol as written so that mips_asm_output_external
    won't emit an .extern for it.  STREAM is the output file, NAME is the
@@ -13783,6 +13833,10 @@ mips16_rewrite_pool_refs (rtx *x, void *data)
       return -1;
     }
 
+  /* Don't rewrite the __mips16_rdwr symbol.  */
+  if (GET_CODE (*x) == UNSPEC && XINT (*x, 1) == UNSPEC_TLS_GET_TP)
+    return -1;
+
   if (TARGET_MIPS16_TEXT_LOADS)
     mips16_rewrite_pool_constant (info->pool, x);
 
index d07e241..1c19f8b 100644 (file)
@@ -1785,8 +1785,6 @@ struct mips_cpu_info {
    from there after reload.  */
 #define PIC_OFFSET_TABLE_REGNUM \
   (reload_completed ? REGNO (pic_offset_table_rtx) : GLOBAL_POINTER_REGNUM)
-
-#define PIC_FUNCTION_ADDR_REGNUM (GP_REG_FIRST + 25)
 \f
 /* Define the classes of registers for register constraints in the
    machine description.  Also define ranges of constants.
@@ -2868,6 +2866,9 @@ extern int mips_dbx_regno[];
 extern int mips_dwarf_regno[];
 extern bool mips_split_p[];
 extern bool mips_split_hi_p[];
+extern bool mips_use_pcrel_pool_p[];
+extern const char *mips_lo_relocs[];
+extern const char *mips_hi_relocs[];
 extern enum processor mips_arch;        /* which cpu to codegen for */
 extern enum processor mips_tune;        /* which cpu to schedule for */
 extern int mips_isa;                   /* architectural level */
index 3be7dd4..3b3eecf 100644 (file)
   UNSPEC_LOAD_GOT
   UNSPEC_TLS_LDM
   UNSPEC_TLS_GET_TP
+  UNSPEC_UNSHIFTED_HIGH
 
   ;; MIPS16 constant pools.
   UNSPEC_ALIGN
 
 (define_constants
   [(TLS_GET_TP_REGNUM          3)
+   (PIC_FUNCTION_ADDR_REGNUM   25)
    (RETURN_ADDR_REGNUM         31)
    (CPRESTORE_SLOT_REGNUM      76)
    (GOT_VERSION_REGNUM         79)
 ;;
 ;; on MIPS16 targets.
 (define_split
-  [(set (match_operand:SI 0 "d_operand")
-       (high:SI (match_operand:SI 1 "absolute_symbolic_operand")))]
+  [(set (match_operand:P 0 "d_operand")
+       (high:P (match_operand:P 1 "symbolic_operand_with_high")))]
   "TARGET_MIPS16 && reload_completed"
-  [(set (match_dup 0) (match_dup 2))
-   (set (match_dup 0) (ashift:SI (match_dup 0) (const_int 16)))]
-{
-  operands[2] = mips_unspec_address (operands[1], SYMBOL_32_HIGH);
-})
+  [(set (match_dup 0) (unspec:P [(match_dup 1)] UNSPEC_UNSHIFTED_HIGH))
+   (set (match_dup 0) (ashift:P (match_dup 0) (const_int 16)))])
+
+(define_insn "*unshifted_high"
+  [(set (match_operand:P 0 "d_operand" "=d")
+       (unspec:P [(match_operand:P 1 "symbolic_operand_with_high")]
+                 UNSPEC_UNSHIFTED_HIGH))]
+  ""
+  "li\t%0,%h1"
+  [(set_attr "extended_mips16" "yes")])
 
 ;; Insns to fetch a symbol from a big GOT.
 
 ;;  ....................
 ;;
 
+(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"
+  { return mips_output_tls_reloc_directive (&operands[0]); }
+  [(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" "")]
    ; 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_mips16_<mode>"
+  [(set (match_operand:P 0 "register_operand" "=d")
+       (unspec:P [(match_operand:P 1 "call_insn_operand" "dS")]
+                 UNSPEC_TLS_GET_TP))
+   (clobber (reg:P TLS_GET_TP_REGNUM))
+   (clobber (reg:P PIC_FUNCTION_ADDR_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_FUNCTION_ADDR_REGNUM))
+             (clobber (reg:P RETURN_ADDR_REGNUM))])
+   (set (match_dup 0) (reg:P TLS_GET_TP_REGNUM))]
+  ""
+  [(set_attr "type" "multi")
+   (set_attr "length" "16")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*tls_get_tp_mips16_call_<mode>"
+  [(set (reg:P TLS_GET_TP_REGNUM)
+       (unspec:P [(match_operand:P 0 "call_insn_operand" "dS")]
+                 UNSPEC_TLS_GET_TP))
+   (clobber (reg:P PIC_FUNCTION_ADDR_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 "length" "12")
+   (set_attr "mode" "<MODE>")])
 \f
 ;; Synchronization instructions.
 
index b611373..57b1af2 100644 (file)
          && type == SYMBOL_ABSOLUTE);
 })
 
+(define_predicate "symbolic_operand_with_high"
+  (match_code "const,symbol_ref,label_ref")
+{
+  enum mips_symbol_type type;
+  return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &type)
+         && mips_hi_relocs[(int) type]);
+})
+
 (define_predicate "force_to_mem_operand"
   (match_code "const,symbol_ref,label_ref")
 {
   enum mips_symbol_type symbol_type;
   return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &symbol_type)
-         && symbol_type == SYMBOL_FORCE_TO_MEM);
+         && mips_use_pcrel_pool_p[(int) symbol_type]);
 })
 
 (define_predicate "got_disp_operand"
          && 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 8bf1c29..5d5bd3e 100644 (file)
@@ -1,3 +1,8 @@
+2012-01-15  Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * gcc.target/mips/code-readable-2.c: Allow the jump table address
+       to be loaded from the constant pool, rather than via %hi and %lo.
+
 2012-01-15  Uros Bizjak  <ubizjak@gmail.com>
 
        PR rtl-optimization/51821
index 8b87ff6..e0176c3 100644 (file)
@@ -26,8 +26,7 @@ bar (void)
 
 /* { dg-final { scan-assembler-not "\tla\t" } } */
 /* { dg-final { scan-assembler-not "\t\\.half\t" } } */
-/* { dg-final { scan-assembler "%hi\\(\[^)\]*L" } } */
-/* { dg-final { scan-assembler "%lo\\(\[^)\]*L" } } */
+/* { dg-final { scan-assembler "\t\\.word\t\[^\n\]*L" } } */
 
 /* { dg-final { scan-assembler "\t\\.word\tk\n" } } */
 /* { dg-final { scan-assembler-not "%hi\\(k\\)" } } */
index f47f76b..70880b0 100644 (file)
@@ -1,3 +1,10 @@
+2012-01-15  Chung-Lin Tang  <cltang@codesourcery.com>
+           Richard Sandiford  <rdsandiford@googlemail.com>
+
+       * config/mips/libgcc-mips16.ver (__mips16_rdhwr): Add.
+       * config/mips/mips16.S (__mips16_rdhwr): New function.
+       * config/mips/t-mips16 (LIB1ASMFUNCS): Add _m16rdhwr.
+
 2012-01-11  Nathan Sidwell  <nathan@acm.org>
 
        * libgcov.c (__gcov_init): Ignore objects with no functions.
index ddb23e7..a925744 100644 (file)
@@ -84,3 +84,7 @@ GCC_4.4.0 {
   __mips16_call_stub_dc_9
   __mips16_call_stub_dc_10
 }
+
+GCC_4.7.0 {
+  __mips16_rdhwr
+}
index ec331b5..a087508 100644 (file)
@@ -709,4 +709,15 @@ CALL_STUB_RET (__mips16_call_stub_dc_9, 9, DC)
 CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
 #endif
 #endif /* !__mips_single_float */
+
+#ifdef L_m16rdhwr
+STARTFN (__mips16_rdhwr)
+       .set    push
+       .set    mips32r2
+       .set    noreorder
+       rdhwr   $3,$29
+       .set    pop
+       j       $31
+       ENDFN (__mips16_rdhwr)
+#endif
 #endif
index 5553ed7..7fe37f6 100644 (file)
@@ -36,7 +36,8 @@ LIB1ASMFUNCS = _m16addsf3 _m16subsf3 _m16mulsf3 _m16divsf3 \
        _m16stubsc0 _m16stubsc1 _m16stubsc2 _m16stubsc5 _m16stubsc6 \
        _m16stubsc9 _m16stubsc10 \
        _m16stubdc0 _m16stubdc1 _m16stubdc2 _m16stubdc5 _m16stubdc6 \
-       _m16stubdc9 _m16stubdc10
+       _m16stubdc9 _m16stubdc10 \
+       _m16rdhwr
 
 SYNC = yes
 SYNC_CFLAGS = -mno-mips16