mips-protos.h (m16_usym8_4, [...]): Delete.
authorRichard Sandiford <rsandifo@redhat.com>
Sun, 18 Apr 2004 08:22:38 +0000 (08:22 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Sun, 18 Apr 2004 08:22:38 +0000 (08:22 +0000)
* config/mips/mips-protos.h (m16_usym8_4, m16_usym5_4): Delete.
* config/mips/mips.h (mips_entry, mips_string_length): Delete.
(CONSTANT_POOL_BEFORE_FUNCTION, ASM_OUTPUT_POOL_EPILOGUE): Undefine.
* config/mips/mips.c (struct mips16_constant): Renamed from struct
constant.  Propogate change throughout file.
(struct machine_function): Remove insns_len.
(mips_string_length, mips16_strings, string_constants): Delete.
(mips_classify_symbol): Return SYMBOL_CONSTANT_POOL for LABEL_REFs
when generating mips16 code.  Remove special mips16 treatment of
string constants.
(mips_symbolic_constant_p): Allow mips16 constant pool accesses
to have the form LABEL+CONSTANT.
(mips_symbolic_address_p): Fix comment.
(m16_usym8_4, m16_usym5_4): Delete.
(mips_output_function_epilogue): Remove mips16 string handling.
(mips_output_mi_thunk): Call mips16_lay_out_constants.
(mips_select_section, mips_encode_section_info): Remove mips16
string handling.
(struct mips16_constant_pool): New.
(add_constant): Take a mips16_constant_pool structure.  Keep pool
sorted into order of ascending mode size.  Keep track of the highest
possible start address, taking padding and the masking of the base PC
value into account.
(dump_constants_1): New function, split out from dump_constants.
Handle vector constants.  Use gen_consttable_{int,float} rather than
separate functions for each mode.
(dump_constants): Simplify.  Use GET_MODE_ALIGNMENT.  Use gen_align
rather than separate functions for each alignment.
(mips_find_symbol): Delete.
(mips16_insn_length): New function, split out from
mips16_lay_out_constants.
(mips16_rewrite_pool_refs): New function.
(mips16_lay_out_constants): Rework. Remove string handling.
Always create an inline constant pool.
* config/mips/mips.md (UNSPEC_CONSTTABLE_INT, UNSPEC_CONSTTABLE_FLOAT)
(UNSPEC_ALIGN): New constants.
(UNSPEC_CONSTTABLE_[QHSD]I, UNSPEC_CONSTTABLE_[SD]F): Delete.
(UNSPEC_ALIGN_[248]): Delete.
(consttable_int, consttable_float, align): New patterns.
(consttable_[qhsd]i, consttable_[sd]f, align_[248]): Delete.

From-SVN: r80814

gcc/ChangeLog
gcc/config/mips/mips-protos.h
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md

index ee1ceb76fb844c8b745dcdc61e69b6d3e53cb59d..cad431e19bdd0d431f677a1468868467380561a9 100644 (file)
@@ -1,3 +1,46 @@
+2004-04-18  Richard Sandiford  <rsandifo@redhat.com>
+
+       * config/mips/mips-protos.h (m16_usym8_4, m16_usym5_4): Delete.
+       * config/mips/mips.h (mips_entry, mips_string_length): Delete.
+       (CONSTANT_POOL_BEFORE_FUNCTION, ASM_OUTPUT_POOL_EPILOGUE): Undefine.
+       * config/mips/mips.c (struct mips16_constant): Renamed from struct
+       constant.  Propogate change throughout file.
+       (struct machine_function): Remove insns_len.
+       (mips_string_length, mips16_strings, string_constants): Delete.
+       (mips_classify_symbol): Return SYMBOL_CONSTANT_POOL for LABEL_REFs
+       when generating mips16 code.  Remove special mips16 treatment of
+       string constants.
+       (mips_symbolic_constant_p): Allow mips16 constant pool accesses
+       to have the form LABEL+CONSTANT.
+       (mips_symbolic_address_p): Fix comment.
+       (m16_usym8_4, m16_usym5_4): Delete.
+       (mips_output_function_epilogue): Remove mips16 string handling.
+       (mips_output_mi_thunk): Call mips16_lay_out_constants.
+       (mips_select_section, mips_encode_section_info): Remove mips16
+       string handling.
+       (struct mips16_constant_pool): New.
+       (add_constant): Take a mips16_constant_pool structure.  Keep pool
+       sorted into order of ascending mode size.  Keep track of the highest
+       possible start address, taking padding and the masking of the base PC
+       value into account.
+       (dump_constants_1): New function, split out from dump_constants.
+       Handle vector constants.  Use gen_consttable_{int,float} rather than
+       separate functions for each mode.
+       (dump_constants): Simplify.  Use GET_MODE_ALIGNMENT.  Use gen_align
+       rather than separate functions for each alignment.
+       (mips_find_symbol): Delete.
+       (mips16_insn_length): New function, split out from
+       mips16_lay_out_constants.
+       (mips16_rewrite_pool_refs): New function.
+       (mips16_lay_out_constants): Rework. Remove string handling.
+       Always create an inline constant pool.
+       * config/mips/mips.md (UNSPEC_CONSTTABLE_INT, UNSPEC_CONSTTABLE_FLOAT)
+       (UNSPEC_ALIGN): New constants.
+       (UNSPEC_CONSTTABLE_[QHSD]I, UNSPEC_CONSTTABLE_[SD]F): Delete.
+       (UNSPEC_ALIGN_[248]): Delete.
+       (consttable_int, consttable_float, align): New patterns.
+       (consttable_[qhsd]i, consttable_[sd]f, align_[248]): Delete.
+
 2004-04-17  Aldy Hernandez  <aldyh@redhat.com>
 
        * config/rs6000/altivec.h (vec_any_numeric): Correct typo in
index 05a7983d1065b9024fc742d33bf149633da97878..fac8246966277105f4d1d756842f19c8a09b63dd 100644 (file)
@@ -114,8 +114,6 @@ extern int m16_uimm8_4 (rtx, enum machine_mode);
 extern int m16_nuimm8_4 (rtx, enum machine_mode);
 extern int m16_simm8_8 (rtx, enum machine_mode);
 extern int m16_nsimm8_8 (rtx, enum machine_mode);
-extern int m16_usym8_4 (rtx, enum machine_mode);
-extern int m16_usym5_4 (rtx, enum machine_mode);
 
 extern struct rtx_def *embedded_pic_fnaddr_reg (void);
 extern struct rtx_def *embedded_pic_offset (rtx);
index 16a1ab2529867821fa31ad89664fb30a298dba9e..5368a1ba3c9ce3eba8ba3761c18a8ec6a60c8de7 100644 (file)
@@ -134,7 +134,7 @@ enum mips_address_type {
    register and the second is the stack slot.  */
 typedef void (*mips_save_restore_fn) (rtx, rtx);
 
-struct constant;
+struct mips16_constant;
 struct mips_arg_info;
 struct mips_address_info;
 struct mips_integer_op;
@@ -215,9 +215,10 @@ static rtx mips_return_fpr_pair (enum machine_mode mode,
 static rtx mips16_gp_pseudo_reg (void);
 static void mips16_fp_args (FILE *, int, int);
 static void build_mips16_function_stub (FILE *);
-static rtx add_constant        (struct constant **, rtx, enum machine_mode);
-static void dump_constants (struct constant *, rtx);
-static rtx mips_find_symbol (rtx);
+static rtx dump_constants_1 (enum machine_mode, rtx, rtx);
+static void dump_constants (struct mips16_constant *, rtx);
+static int mips16_insn_length (rtx);
+static int mips16_rewrite_pool_refs (rtx *, void *);
 static void mips16_lay_out_constants (void);
 static void mips_avoid_hazard (rtx, rtx, int *, rtx *, rtx);
 static void mips_avoid_hazards (void);
@@ -283,9 +284,6 @@ struct machine_function GTY(()) {
   /* Current frame information, calculated by compute_frame_size.  */
   struct mips_frame_info frame;
 
-  /* Length of instructions in function; mips16 only.  */
-  long insns_len;
-
   /* The register to use as the global pointer within this function.  */
   unsigned int global_pointer;
 
@@ -462,28 +460,6 @@ static enum machine_mode gpr_mode;
    can support a given mode.  */
 char mips_hard_regno_mode_ok[(int)MAX_MACHINE_MODE][FIRST_PSEUDO_REGISTER];
 
-/* The length of all strings seen when compiling for the mips16.  This
-   is used to tell how many strings are in the constant pool, so that
-   we can see if we may have an overflow.  This is reset each time the
-   constant pool is output.  */
-int mips_string_length;
-
-/* When generating mips16 code, a list of all strings that are to be
-   output after the current function.  */
-
-static GTY(()) rtx mips16_strings;
-
-/* In mips16 mode, we build a list of all the string constants we see
-   in a particular function.  */
-
-struct string_constant
-{
-  struct string_constant *next;
-  const char *label;
-};
-
-static struct string_constant *string_constants;
-
 /* List of all MIPS punctuation characters used by print_operand.  */
 char mips_print_operand_punct[256];
 
@@ -776,7 +752,13 @@ static enum mips_symbol_type
 mips_classify_symbol (rtx x)
 {
   if (GET_CODE (x) == LABEL_REF)
-    return (TARGET_ABICALLS ? SYMBOL_GOT_LOCAL : SYMBOL_GENERAL);
+    {
+      if (TARGET_MIPS16)
+       return SYMBOL_CONSTANT_POOL;
+      if (TARGET_ABICALLS)
+       return SYMBOL_GOT_LOCAL;
+      return SYMBOL_GENERAL;
+    }
 
   if (GET_CODE (x) != SYMBOL_REF)
     abort ();
@@ -798,11 +780,6 @@ mips_classify_symbol (rtx x)
   if (SYMBOL_REF_SMALL_P (x))
     return SYMBOL_SMALL_DATA;
 
-  /* When generating mips16 code, SYMBOL_REF_FLAG indicates a string
-     in the current function's constant pool.  */
-  if (TARGET_MIPS16 && SYMBOL_REF_FLAG (x))
-    return SYMBOL_CONSTANT_POOL;
-
   if (TARGET_ABICALLS)
     {
       if (SYMBOL_REF_DECL (x) == 0)
@@ -919,8 +896,16 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
       /* In other cases the relocations can handle any offset.  */
       return true;
 
-    case SYMBOL_SMALL_DATA:
     case SYMBOL_CONSTANT_POOL:
+      /* Allow constant pool references to be converted to LABEL+CONSTANT.
+        In this case, we no longer have access to the underlying constant,
+        but the original symbol-based access was known to be valid.  */
+      if (GET_CODE (x) == LABEL_REF)
+       return true;
+
+      /* Fall through.  */
+
+    case SYMBOL_SMALL_DATA:
       /* Make sure that the offset refers to something within the
         underlying object.  This should guarantee that the final
         PC- or GP-relative offset is within the 16-bit limit.  */
@@ -1012,7 +997,7 @@ mips_symbolic_address_p (enum mips_symbol_type symbol_type,
       return true;
 
     case SYMBOL_CONSTANT_POOL:
-      /* PC-relative addressing is only available for lw, sw, ld and sd.  */
+      /* PC-relative addressing is only available for lw and ld.  */
       return GET_MODE_SIZE (mode) == 4 || GET_MODE_SIZE (mode) == 8;
 
     case SYMBOL_GOT_LOCAL:
@@ -2125,55 +2110,6 @@ m16_nsimm8_8 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
 {
   return m16_check_op (op, (- 0x7f) << 3, 0x80 << 3, 7);
 }
-
-/* References to the string table on the mips16 only use a small
-   offset if the function is small.  We can't check for LABEL_REF here,
-   because the offset is always large if the label is before the
-   referencing instruction.  */
-
-int
-m16_usym8_4 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == SYMBOL_REF
-      && SYMBOL_REF_FLAG (op)
-      && cfun->machine->insns_len > 0
-      && (cfun->machine->insns_len + get_pool_size () + mips_string_length
-         < 4 * 0x100))
-    {
-      struct string_constant *l;
-
-      /* Make sure this symbol is on thelist of string constants to be
-         output for this function.  It is possible that it has already
-         been output, in which case this requires a large offset.  */
-      for (l = string_constants; l != NULL; l = l->next)
-       if (strcmp (l->label, XSTR (op, 0)) == 0)
-         return 1;
-    }
-
-  return 0;
-}
-
-int
-m16_usym5_4 (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
-{
-  if (GET_CODE (op) == SYMBOL_REF
-      && SYMBOL_REF_FLAG (op)
-      && cfun->machine->insns_len > 0
-      && (cfun->machine->insns_len + get_pool_size () + mips_string_length
-         < 4 * 0x20))
-    {
-      struct string_constant *l;
-
-      /* Make sure this symbol is on thelist of string constants to be
-         output for this function.  It is possible that it has already
-         been output, in which case this requires a large offset.  */
-      for (l = string_constants; l != NULL; l = l->next)
-       if (strcmp (l->label, XSTR (op, 0)) == 0)
-         return 1;
-    }
-
-  return 0;
-}
 \f
 static bool
 mips_rtx_costs (rtx x, int code, int outer_code, int *total)
@@ -6887,8 +6823,6 @@ static void
 mips_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
                               HOST_WIDE_INT size ATTRIBUTE_UNUSED)
 {
-  rtx string;
-
   /* Reinstate the normal $gp.  */
   REGNO (pic_offset_table_rtx) = GLOBAL_POINTER_REGNUM;
   mips_output_cplocal ();
@@ -6913,26 +6847,6 @@ mips_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
       assemble_name (file, fnname);
       fputs ("\n", file);
     }
-
-  while (string_constants != NULL)
-    {
-      struct string_constant *next;
-
-      next = string_constants->next;
-      free (string_constants);
-      string_constants = next;
-    }
-
-  /* If any following function uses the same strings as this one, force
-     them to refer those strings indirectly.  Nearby functions could
-     refer them using pc-relative addressing, but it isn't safe in
-     general.  For instance, some functions may be placed in sections
-     other than .text, and we don't know whether they be close enough
-     to this one.  In large files, even other .text functions can be
-     too far away.  */
-  for (string = mips16_strings; string != 0; string = XEXP (string, 1))
-    SYMBOL_REF_FLAG (XEXP (string, 0)) = 0;
-  free_EXPR_LIST_list (&mips16_strings);
 }
 \f
 /* Emit instructions to restore register REG from slot MEM.  */
@@ -7218,6 +7132,8 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   insn = get_insns ();
   insn_locators_initialize ();
   split_all_insns_noflow ();
+  if (TARGET_MIPS16)
+    mips16_lay_out_constants ();
   shorten_branches (insn);
   final_start_function (insn, file, 1);
   final (insn, file, 1, 0);
@@ -7298,12 +7214,9 @@ static void
 mips_select_section (tree decl, int reloc,
                     unsigned HOST_WIDE_INT align ATTRIBUTE_UNUSED)
 {
-  if ((TARGET_EMBEDDED_PIC || TARGET_MIPS16)
-      && TREE_CODE (decl) == STRING_CST)
+  if (TARGET_EMBEDDED_PIC && TREE_CODE (decl) == STRING_CST)
     /* For embedded position independent code, put constant strings in the
-       text section, because the data section is limited to 64K in size.
-       For mips16 code, put strings in the text section so that a PC
-       relative load instruction can be used to get their address.  */
+       text section, because the data section is limited to 64K in size.  */
     text_section ();
   else if (targetm.have_named_sections)
     default_elf_select_section (decl, reloc, align);
@@ -7362,13 +7275,7 @@ mips_in_small_data_p (tree decl)
 
 
 /* When generating embedded PIC code, SYMBOL_REF_FLAG is set for
-   symbols which are not in the .text section.
-
-   When generating mips16 code, SYMBOL_REF_FLAG is set for string
-   constants which are put in the .text section.  We also record the
-   total length of all such strings; this total is used to decide
-   whether we need to split the constant table, and need not be
-   precisely correct.  */
+   symbols which are not in the .text section.  */
 
 static void
 mips_encode_section_info (tree decl, rtx rtl, int first)
@@ -7383,29 +7290,6 @@ mips_encode_section_info (tree decl, rtx rtl, int first)
   if (GET_CODE (symbol) != SYMBOL_REF)
     return;
 
-  if (TARGET_MIPS16)
-    {
-      if (first && TREE_CODE (decl) == STRING_CST
-          /* If this string is from a function, and the function will
-             go in a gnu linkonce section, then we can't directly
-             access the string.  This gets an assembler error
-             "unsupported PC relative reference to different section".
-             If we modify SELECT_SECTION to put it in function_section
-             instead of text_section, it still fails because
-             DECL_SECTION_NAME isn't set until assemble_start_function.
-             If we fix that, it still fails because strings are shared
-             among multiple functions, and we have cross section
-             references again.  We force it to work by putting string
-             addresses in the constant pool and indirecting.  */
-          && (! current_function_decl
-              || ! DECL_ONE_ONLY (current_function_decl)))
-        {
-          mips16_strings = alloc_EXPR_LIST (0, symbol, mips16_strings);
-          SYMBOL_REF_FLAG (symbol) = 1;
-          mips_string_length += TREE_STRING_LENGTH (decl);
-        }
-    }
-
   if (TARGET_EMBEDDED_PIC)
     {
       if (TREE_CODE (decl) == VAR_DECL)
@@ -8319,329 +8203,236 @@ build_mips16_call_stub (rtx retval, rtx fn, rtx arg_size, int fp_code)
   return 0;
 }
 
-/* We keep a list of constants we which we have to add to internal
-   constant tables in the middle of large functions.  */
+/* An entry in the mips16 constant pool.  VALUE is the pool constant,
+   MODE is its mode, and LABEL is the CODE_LABEL associated with it.  */
 
-struct constant
-{
-  struct constant *next;
+struct mips16_constant {
+  struct mips16_constant *next;
   rtx value;
   rtx label;
   enum machine_mode mode;
 };
 
-/* Add a constant to the list in *PCONSTANTS.  */
+/* Information about an incomplete mips16 constant pool.  FIRST is the
+   first constant, HIGHEST_ADDRESS is the highest address that the first
+   byte of the pool can have, and INSN_ADDRESS is the current instruction
+   address.  */
+
+struct mips16_constant_pool {
+  struct mips16_constant *first;
+  int highest_address;
+  int insn_address;
+};
+
+/* Add constant VALUE to POOL and return its label.  MODE is the
+   value's mode (used for CONST_INTs, etc.).  */
 
 static rtx
-add_constant (struct constant **pconstants, rtx val, enum machine_mode mode)
+add_constant (struct mips16_constant_pool *pool,
+             rtx value, enum machine_mode mode)
 {
-  struct constant *c;
+  struct mips16_constant **p, *c;
+  bool first_of_size_p;
 
-  for (c = *pconstants; c != NULL; c = c->next)
-    if (mode == c->mode && rtx_equal_p (val, c->value))
-      return c->label;
+  /* See whether the constant is already in the pool.  If so, return the
+     existing label, otherwise leave P pointing to the place where the
+     constant should be added.
 
-  c = (struct constant *) xmalloc (sizeof *c);
-  c->value = val;
+     Keep the pool sorted in increasing order of mode size so that we can
+     reduce the number of alignments needed.  */
+  first_of_size_p = true;
+  for (p = &pool->first; *p != 0; p = &(*p)->next)
+    {
+      if (mode == (*p)->mode && rtx_equal_p (value, (*p)->value))
+       return (*p)->label;
+      if (GET_MODE_SIZE (mode) < GET_MODE_SIZE ((*p)->mode))
+       break;
+      if (GET_MODE_SIZE (mode) == GET_MODE_SIZE ((*p)->mode))
+       first_of_size_p = false;
+    }
+
+  /* In the worst case, the constant needed by the earliest instruction
+     will end up at the end of the pool.  The entire pool must then be
+     accessible from that instruction.
+
+     When adding the first constant, set the pool's highest address to
+     the address of the first out-of-range byte.  Adjust this address
+     downwards each time a new constant is added.  */
+  if (pool->first == 0)
+    /* For pc-relative lw, addiu and daddiu instructions, the base PC value
+       is the address of the instruction with the lowest two bits clear.
+       The base PC value for ld has the lowest three bits clear.  Assume
+       the worst case here.  */
+    pool->highest_address = pool->insn_address - (UNITS_PER_WORD - 2) + 0x8000;
+  pool->highest_address -= GET_MODE_SIZE (mode);
+  if (first_of_size_p)
+    /* Take into account the worst possible padding due to alignment.  */
+    pool->highest_address -= GET_MODE_SIZE (mode) - 1;
+
+  /* Create a new entry.  */
+  c = (struct mips16_constant *) xmalloc (sizeof *c);
+  c->value = value;
   c->mode = mode;
   c->label = gen_label_rtx ();
-  c->next = *pconstants;
-  *pconstants = c;
+  c->next = *p;
+  *p = c;
+
   return c->label;
 }
 
+/* Output constant VALUE after instruction INSN and return the last
+   instruction emitted.  MODE is the mode of the constant.  */
+
+static rtx
+dump_constants_1 (enum machine_mode mode, rtx value, rtx insn)
+{
+  switch (GET_MODE_CLASS (mode))
+    {
+    case MODE_INT:
+      {
+       rtx size = GEN_INT (GET_MODE_SIZE (mode));
+       return emit_insn_after (gen_consttable_int (value, size), insn);
+      }
+
+    case MODE_FLOAT:
+      return emit_insn_after (gen_consttable_float (value), insn);
+
+    case MODE_VECTOR_FLOAT:
+    case MODE_VECTOR_INT:
+      {
+       int i;
+       for (i = 0; i < CONST_VECTOR_NUNITS (value); i++)
+         insn = dump_constants_1 (GET_MODE_INNER (mode),
+                                  CONST_VECTOR_ELT (value, i), insn);
+       return insn;
+      }
+
+    default:
+      abort ();
+    }
+}
+
+
 /* Dump out the constants in CONSTANTS after INSN.  */
 
 static void
-dump_constants (struct constant *constants, rtx insn)
+dump_constants (struct mips16_constant *constants, rtx insn)
 {
-  struct constant *c;
+  struct mips16_constant *c, *next;
   int align;
 
-  c = constants;
   align = 0;
-  while (c != NULL)
+  for (c = constants; c != NULL; c = next)
     {
-      rtx r;
-      struct constant *next;
-
-      switch (GET_MODE_SIZE (c->mode))
+      /* If necessary, increase the alignment of PC.  */
+      if (align < GET_MODE_SIZE (c->mode))
        {
-       case 1:
-         align = 0;
-         break;
-       case 2:
-         if (align < 1)
-           insn = emit_insn_after (gen_align_2 (), insn);
-         align = 1;
-         break;
-       case 4:
-         if (align < 2)
-           insn = emit_insn_after (gen_align_4 (), insn);
-         align = 2;
-         break;
-       default:
-         if (align < 3)
-           insn = emit_insn_after (gen_align_8 (), insn);
-         align = 3;
-         break;
+         int align_log = floor_log2 (GET_MODE_SIZE (c->mode));
+         insn = emit_insn_after (gen_align (GEN_INT (align_log)), insn);
        }
+      align = GET_MODE_SIZE (c->mode);
 
       insn = emit_label_after (c->label, insn);
-
-      switch (c->mode)
-       {
-       case QImode:
-         r = gen_consttable_qi (c->value);
-         break;
-       case HImode:
-         r = gen_consttable_hi (c->value);
-         break;
-       case SImode:
-         r = gen_consttable_si (c->value);
-         break;
-       case SFmode:
-         r = gen_consttable_sf (c->value);
-         break;
-       case DImode:
-         r = gen_consttable_di (c->value);
-         break;
-       case DFmode:
-         r = gen_consttable_df (c->value);
-         break;
-       default:
-         abort ();
-       }
-
-      insn = emit_insn_after (r, insn);
+      insn = dump_constants_1 (c->mode, c->value, insn);
 
       next = c->next;
       free (c);
-      c = next;
     }
 
   emit_barrier_after (insn);
 }
 
-/* Find the symbol in an address expression.  */
+/* Return the length of instruction INSN.
 
-static rtx
-mips_find_symbol (rtx addr)
+   ??? MIPS16 switch tables go in .text, but we don't define
+   JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
+   compute their lengths correctly.  */
+
+static int
+mips16_insn_length (rtx insn)
 {
-  if (GET_CODE (addr) == MEM)
-    addr = XEXP (addr, 0);
-  while (GET_CODE (addr) == CONST)
-    addr = XEXP (addr, 0);
-  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
-    return addr;
-  if (GET_CODE (addr) == PLUS)
+  if (GET_CODE (insn) == JUMP_INSN)
     {
-      rtx l1, l2;
-
-      l1 = mips_find_symbol (XEXP (addr, 0));
-      l2 = mips_find_symbol (XEXP (addr, 1));
-      if (l1 != NULL_RTX && l2 == NULL_RTX)
-       return l1;
-      else if (l1 == NULL_RTX && l2 != NULL_RTX)
-       return l2;
+      rtx body = PATTERN (insn);
+      if (GET_CODE (body) == ADDR_VEC)
+       return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, 0);
+      if (GET_CODE (body) == ADDR_DIFF_VEC)
+       return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, 1);
     }
-  return NULL_RTX;
+  return get_attr_length (insn);
 }
 
-/* In mips16 mode, we need to look through the function to check for
-   PC relative loads that are out of range.  */
+/* Rewrite *X so that constant pool references refer to the constant's
+   label instead.  DATA points to the constant pool structure.  */
 
-static void
-mips16_lay_out_constants (void)
+static int
+mips16_rewrite_pool_refs (rtx *x, void *data)
 {
-  int insns_len, max_internal_pool_size, pool_size, addr, first_constant_ref;
-  rtx first, insn;
-  struct constant *constants;
+  struct mips16_constant_pool *pool = data;
+  if (GET_CODE (*x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (*x))
+    *x = gen_rtx_LABEL_REF (Pmode, add_constant (pool,
+                                                get_pool_constant (*x),
+                                                get_pool_mode (*x)));
+  return 0;
+}
 
-  first = get_insns ();
+/* Build MIPS16 constant pools.  */
 
-  /* Scan the function looking for PC relative loads which may be out
-     of range.  All such loads will either be from the constant table,
-     or be getting the address of a constant string.  If the size of
-     the function plus the size of the constant table is less than
-     0x8000, then all loads are in range.  */
+static void
+mips16_lay_out_constants (void)
+{
+  struct mips16_constant_pool pool;
+  rtx insn, barrier;
 
-  insns_len = 0;
-  for (insn = first; insn; insn = NEXT_INSN (insn))
+  barrier = 0;
+  memset (&pool, 0, sizeof (pool));
+  for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
     {
-      insns_len += get_attr_length (insn);
-
-      /* ??? We put switch tables in .text, but we don't define
-         JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
-         compute their lengths correctly.  */
-      if (GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx body;
-
-         body = PATTERN (insn);
-         if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
-           insns_len += (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
-                         * GET_MODE_SIZE (GET_MODE (body)));
-         insns_len += GET_MODE_SIZE (GET_MODE (body)) - 1;
-       }
-    }
-
-  /* Store the original value of insns_len in cfun->machine, so
-     that m16_usym8_4 and m16_usym5_4 can look at it.  */
-  cfun->machine->insns_len = insns_len;
+      /* Rewrite constant pool references in INSN.  */
+      if (INSN_P (insn))
+       for_each_rtx (&PATTERN (insn), mips16_rewrite_pool_refs, &pool);
 
-  pool_size = get_pool_size ();
-  if (insns_len + pool_size + mips_string_length < 0x8000)
-    return;
+      pool.insn_address += mips16_insn_length (insn);
 
-  /* Loop over the insns and figure out what the maximum internal pool
-     size could be.  */
-  max_internal_pool_size = 0;
-  for (insn = first; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == INSN
-         && GET_CODE (PATTERN (insn)) == SET)
+      if (pool.first != NULL)
        {
-         rtx src;
-
-         src = mips_find_symbol (SET_SRC (PATTERN (insn)));
-         if (src == NULL_RTX)
-           continue;
-         if (CONSTANT_POOL_ADDRESS_P (src))
-           max_internal_pool_size += GET_MODE_SIZE (get_pool_mode (src));
-         else if (SYMBOL_REF_FLAG (src))
-           max_internal_pool_size += GET_MODE_SIZE (Pmode);
-       }
-    }
+         /* If there are no natural barriers between the first user of
+            the pool and the highest acceptable address, we'll need to
+            create a new instruction to jump around the constant pool.
+            In the worst case, this instruction will be 4 bytes long.
+
+            If it's too late to do this transformation after INSN,
+            do it immediately before INSN.  */
+         if (barrier == 0 && pool.insn_address + 4 > pool.highest_address)
+           {
+             rtx label, jump;
 
-  constants = NULL;
-  addr = 0;
-  first_constant_ref = -1;
+             label = gen_label_rtx ();
 
-  for (insn = first; insn; insn = NEXT_INSN (insn))
-    {
-      if (GET_CODE (insn) == INSN
-         && GET_CODE (PATTERN (insn)) == SET)
-       {
-         rtx val, src;
-         enum machine_mode mode = VOIDmode;
+             jump = emit_jump_insn_before (gen_jump (label), insn);
+             JUMP_LABEL (jump) = label;
+             LABEL_NUSES (label) = 1;
+             barrier = emit_barrier_after (jump);
 
-         val = NULL_RTX;
-         src = mips_find_symbol (SET_SRC (PATTERN (insn)));
-         if (src != NULL_RTX && CONSTANT_POOL_ADDRESS_P (src))
-           {
-             /* ??? This is very conservative, which means that we
-                 will generate too many copies of the constant table.
-                 The only solution would seem to be some form of
-                 relaxing.  */
-             if (((insns_len - addr)
-                  + max_internal_pool_size
-                  + get_pool_offset (src))
-                 >= 0x8000)
-               {
-                 val = get_pool_constant (src);
-                 mode = get_pool_mode (src);
-               }
-             max_internal_pool_size -= GET_MODE_SIZE (get_pool_mode (src));
-           }
-         else if (src != NULL_RTX && SYMBOL_REF_FLAG (src))
-           {
-             /* Including all of mips_string_length is conservative,
-                 and so is including all of max_internal_pool_size.  */
-             if (((insns_len - addr)
-                  + max_internal_pool_size
-                  + pool_size
-                  + mips_string_length)
-                 >= 0x8000)
-               {
-                 val = src;
-                 mode = Pmode;
-               }
-             max_internal_pool_size -= Pmode;
+             emit_label_after (label, barrier);
+             pool.insn_address += 4;
            }
 
-         if (val != NULL_RTX)
+         /* See whether the constant pool is now out of range of the first
+            user.  If so, output the constants after the previous barrier.
+            Note that any instructions between BARRIER and INSN (inclusive)
+            will use negative offsets to refer to the pool.  */
+         if (pool.insn_address > pool.highest_address)
            {
-             rtx lab, newsrc;
-
-             /* This PC relative load is out of range.  ??? In the
-                case of a string constant, we are only guessing that
-                it is range, since we don't know the offset of a
-                particular string constant.  */
-
-             lab = add_constant (&constants, val, mode);
-             newsrc = gen_rtx_MEM (mode,
-                                   gen_rtx_LABEL_REF (VOIDmode, lab));
-             RTX_UNCHANGING_P (newsrc) = 1;
-             PATTERN (insn) = gen_rtx_SET (VOIDmode,
-                                           SET_DEST (PATTERN (insn)),
-                                           newsrc);
-             INSN_CODE (insn) = -1;
-
-             if (first_constant_ref < 0)
-               first_constant_ref = addr;
+             dump_constants (pool.first, barrier);
+             pool.first = NULL;
+             barrier = 0;
            }
+         else if (BARRIER_P (insn))
+           barrier = insn;
        }
-
-      addr += get_attr_length (insn);
-
-      /* ??? We put switch tables in .text, but we don't define
-         JUMP_TABLES_IN_TEXT_SECTION, so get_attr_length will not
-         compute their lengths correctly.  */
-      if (GET_CODE (insn) == JUMP_INSN)
-       {
-         rtx body;
-
-         body = PATTERN (insn);
-         if (GET_CODE (body) == ADDR_VEC || GET_CODE (body) == ADDR_DIFF_VEC)
-           addr += (XVECLEN (body, GET_CODE (body) == ADDR_DIFF_VEC)
-                         * GET_MODE_SIZE (GET_MODE (body)));
-         addr += GET_MODE_SIZE (GET_MODE (body)) - 1;
-       }
-
-      if (GET_CODE (insn) == BARRIER)
-       {
-         /* Output any constants we have accumulated.  Note that we
-             don't need to change ADDR, since its only use is
-             subtraction from INSNS_LEN, and both would be changed by
-             the same amount.
-            ??? If the instructions up to the next barrier reuse a
-            constant, it would often be better to continue
-            accumulating.  */
-         if (constants != NULL)
-           dump_constants (constants, insn);
-         constants = NULL;
-         first_constant_ref = -1;
-       }
-
-      if (constants != NULL
-              && (NEXT_INSN (insn) == NULL
-                  || (first_constant_ref >= 0
-                      && (((addr - first_constant_ref)
-                           + 2 /* for alignment */
-                           + 2 /* for a short jump insn */
-                           + pool_size)
-                          >= 0x8000))))
-       {
-         /* If we haven't had a barrier within 0x8000 bytes of a
-             constant reference or we are at the end of the function,
-             emit a barrier now.  */
-
-         rtx label, jump, barrier;
-
-         label = gen_label_rtx ();
-         jump = emit_jump_insn_after (gen_jump (label), insn);
-         JUMP_LABEL (jump) = label;
-         LABEL_NUSES (label) = 1;
-         barrier = emit_barrier_after (jump);
-         emit_label_after (label, barrier);
-         first_constant_ref = -1;
-       }
-     }
-
-  /* ??? If we output all references to a constant in internal
-     constants table, we don't need to output the constant in the real
-     constant table, but we have no way to prevent that.  */
+    }
+  dump_constants (pool.first, get_last_insn ());
 }
 
 
index 8bd9fb710de6130d58b78d14f6463d29d86e537e..26775d4fbba1aa838c92740e6f85c9e51caec359 100644 (file)
@@ -117,13 +117,11 @@ extern enum processor_type mips_tune;   /* which cpu to schedule for */
 extern int mips_isa;                   /* architectural level */
 extern int mips_abi;                   /* which ABI to use */
 extern int mips16_hard_float;          /* mips16 without -msoft-float */
-extern int mips_entry;                 /* generate entry/exit for mips16 */
 extern const char *mips_arch_string;    /* for -march=<xxx> */
 extern const char *mips_tune_string;    /* for -mtune=<xxx> */
 extern const char *mips_isa_string;    /* for -mips{1,2,3,4} */
 extern const char *mips_abi_string;    /* for -mabi={32,n32,64} */
 extern const char *mips_cache_flush_func;/* for -mflush-func= and -mno-flush-func */
-extern int mips_string_length;         /* length of strings for mips16 */
 extern const struct mips_cpu_info mips_cpu_info_table[];
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
@@ -2574,14 +2572,6 @@ typedef struct mips_args {
                 XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0)); \
   else                                                                 \
     asm_fprintf ((FILE), "%U%s", (NAME))
-
-/* The mips16 wants the constant pool to be after the function,
-   because the PC relative load instructions use unsigned offsets.  */
-
-#define CONSTANT_POOL_BEFORE_FUNCTION (! TARGET_MIPS16)
-
-#define ASM_OUTPUT_POOL_EPILOGUE(FILE, FNNAME, FNDECL, SIZE)   \
-  mips_string_length = 0;
 \f
 /* Specify the machine mode that this machine uses
    for the index in the tablejump instruction.
index 0ac944419ec4a0258811d6022f86496ff0c3a736..84efc359e16161306e02db96a717d568e02fab7e 100644 (file)
    (UNSPEC_CPRESTORE            5)
    (UNSPEC_EH_RECEIVER          6)
    (UNSPEC_EH_RETURN            7)
-   (UNSPEC_CONSTTABLE_QI        8)
-   (UNSPEC_CONSTTABLE_HI        9)
-   (UNSPEC_CONSTTABLE_SI       10)
-   (UNSPEC_CONSTTABLE_DI       11)
-   (UNSPEC_CONSTTABLE_SF       12)
-   (UNSPEC_CONSTTABLE_DF       13)
-   (UNSPEC_ALIGN_2             14)
-   (UNSPEC_ALIGN_4             15)
-   (UNSPEC_ALIGN_8             16)
+   (UNSPEC_CONSTTABLE_INT       8)
+   (UNSPEC_CONSTTABLE_FLOAT     9)
+   (UNSPEC_ALIGN               14)
    (UNSPEC_HIGH                        17)
    (UNSPEC_LWL                 18)
    (UNSPEC_LWR                 19)
@@ -9147,74 +9141,21 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2%/"
 ;;  ....................
 ;;
 
-(define_insn "consttable_qi"
-  [(unspec_volatile [(match_operand:QI 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_QI)]
+(define_insn "consttable_int"
+  [(unspec_volatile [(match_operand 0 "consttable_operand" "")
+                    (match_operand 1 "const_int_operand" "")]
+                   UNSPEC_CONSTTABLE_INT)]
   "TARGET_MIPS16"
 {
-  assemble_integer (operands[0], 1, BITS_PER_UNIT, 1);
+  assemble_integer (operands[0], INTVAL (operands[1]),
+                   BITS_PER_UNIT * INTVAL (operands[1]), 1);
   return "";
 }
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "QI")
-   (set_attr "length"  "8")])
-
-(define_insn "consttable_hi"
-  [(unspec_volatile [(match_operand:HI 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_HI)]
-  "TARGET_MIPS16"
-{
-  assemble_integer (operands[0], 2, BITS_PER_UNIT * 2, 1);
-  return "";
-}
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "HI")
-   (set_attr "length"  "8")])
-
-(define_insn "consttable_si"
-  [(unspec_volatile [(match_operand:SI 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_SI)]
-  "TARGET_MIPS16"
-{
-  assemble_integer (operands[0], 4, BITS_PER_UNIT * 4, 1);
-  return "";
-}
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "SI")
-   (set_attr "length"  "8")])
-
-(define_insn "consttable_di"
-  [(unspec_volatile [(match_operand:DI 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_DI)]
-  "TARGET_MIPS16"
-{
-  assemble_integer (operands[0], 8, BITS_PER_UNIT * 8, 1);
-  return "";
-}
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "DI")
-   (set_attr "length"  "16")])
-
-(define_insn "consttable_sf"
-  [(unspec_volatile [(match_operand:SF 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_SF)]
-  "TARGET_MIPS16"
-{
-  REAL_VALUE_TYPE d;
+  [(set (attr "length") (symbol_ref "INTVAL (operands[1])"))])
 
-  if (GET_CODE (operands[0]) != CONST_DOUBLE)
-    abort ();
-  REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]);
-  assemble_real (d, SFmode, GET_MODE_ALIGNMENT (SFmode));
-  return "";
-}
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "SF")
-   (set_attr "length"  "8")])
-
-(define_insn "consttable_df"
-  [(unspec_volatile [(match_operand:DF 0 "consttable_operand" "=g")]
-                   UNSPEC_CONSTTABLE_DF)]
+(define_insn "consttable_float"
+  [(unspec_volatile [(match_operand 0 "consttable_operand" "")]
+                   UNSPEC_CONSTTABLE_FLOAT)]
   "TARGET_MIPS16"
 {
   REAL_VALUE_TYPE d;
@@ -9222,36 +9163,18 @@ ld\\t%2,%1-%S1(%2)\;daddu\\t%2,%2,$31\\n\\t%*j\\t%2%/"
   if (GET_CODE (operands[0]) != CONST_DOUBLE)
     abort ();
   REAL_VALUE_FROM_CONST_DOUBLE (d, operands[0]);
-  assemble_real (d, DFmode, GET_MODE_ALIGNMENT (DFmode));
+  assemble_real (d, GET_MODE (operands[0]),
+                GET_MODE_BITSIZE (GET_MODE (operands[0])));
   return "";
 }
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "DF")
-   (set_attr "length"  "16")])
+  [(set (attr "length")
+       (symbol_ref "GET_MODE_SIZE (GET_MODE (operands[0]))"))])
 
-(define_insn "align_2"
-  [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_2)]
-  "TARGET_MIPS16"
-  ".align 1"
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "HI")
-   (set_attr "length"  "8")])
-
-(define_insn "align_4"
-  [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_4)]
-  "TARGET_MIPS16"
-  ".align 2"
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "SI")
-   (set_attr "length"  "8")])
-
-(define_insn "align_8"
-  [(unspec_volatile [(const_int 0)] UNSPEC_ALIGN_8)]
-  "TARGET_MIPS16"
-  ".align 3"
-  [(set_attr "type"    "unknown")
-   (set_attr "mode"    "DI")
-   (set_attr "length"  "12")])
+(define_insn "align"
+  [(unspec_volatile [(match_operand 0 "const_int_operand" "")] UNSPEC_ALIGN)]
+  ""
+  ".align\t%0"
+  [(set (attr "length") (symbol_ref "(1 << INTVAL (operands[0])) - 1"))])
 \f
 ;;
 ;;  ....................