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;
 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);
   /* 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;
 
    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];
 
 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 ();
   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)
       /* 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.  */
       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:
 {
   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)
 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 ();
       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.  */
   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);
 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);
 
 
 /* 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)
   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)
   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 ());
 }