binutils: backport auto-litpools xtensa gas option
authorMax Filippov <jcmvbkbc@gmail.com>
Wed, 12 Aug 2015 22:20:00 +0000 (01:20 +0300)
committerThomas Petazzoni <thomas.petazzoni@free-electrons.com>
Sun, 4 Oct 2015 16:27:27 +0000 (17:27 +0100)
Auto-litpools is the automated version of text-section-literals: literal
pool candidate frags are planted every N frags and during relaxation
they are turned into actual literal pools where literals are moved to
become reachable for their first reference by L32R instruction.

Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
package/binutils/2.24/913-xtensa-add-auto-litpools-option.patch [new file with mode: 0644]
package/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch [new file with mode: 0644]

diff --git a/package/binutils/2.24/913-xtensa-add-auto-litpools-option.patch b/package/binutils/2.24/913-xtensa-add-auto-litpools-option.patch
new file mode 100644 (file)
index 0000000..f0199e1
--- /dev/null
@@ -0,0 +1,698 @@
+From 978adaaa4cd3921842e2be8a31c05f081fb17fcf Mon Sep 17 00:00:00 2001
+From: Max Filippov <jcmvbkbc@gmail.com>
+Date: Wed, 29 Jul 2015 17:42:54 +0300
+Subject: [PATCH] xtensa: add --auto-litpools option
+
+Auto-litpools is the automated version of text-section-literals: literal
+pool candidate frags are planted every N frags and during relaxation
+they are turned into actual literal pools where literals are moved to
+become reachable for their first reference by L32R instruction.
+
+2015-08-12  David Weatherford  <weath@cadence.com>
+gas/
+       * config/tc-xtensa.c (struct litpool_frag, struct litpool_seg):
+       New structures.
+       (xtensa_maybe_create_literal_pool_frag): New function.
+       (litpool_seg_list, auto_litpools, auto_litpool_limit)
+       (litpool_buf, litpool_slotbuf): New static variables.
+       (option_auto_litpools, option_no_auto_litpools)
+       (option_auto_litpool_limit): New enum identifiers.
+       (md_longopts): Add entries for auto-litpools, no-auto-litpools
+       and auto-litpool-limit.
+       (md_parse_option): Handle option_auto_litpools,
+       option_no_auto_litpools and option_auto_litpool_limit.
+       (md_show_usage): Add help for --[no-]auto-litpools and
+       --auto-litpool-limit.
+       (xtensa_mark_literal_pool_location): Record a place for literal
+       pool with a call to xtensa_maybe_create_literal_pool_frag.
+       (get_literal_pool_location): Find highest priority literal pool
+       or convert candidate to literal pool when auto-litpools are used.
+       (xg_assemble_vliw_tokens): Create literal pool after jump
+       instruction.
+       (xtensa_check_frag_count): Create candidate literal pool every
+       auto_litpool_limit frags.
+       (xtensa_relax_frag): Add jump around literals to non-empty
+       literal pool.
+       (xtensa_move_literals): Estimate literal pool addresses and move
+       unreachable literals closer to their users, converting candidate
+       to literal pool if needed.
+       (xtensa_switch_to_non_abs_literal_fragment): Only emit error
+       about missing .literal_position in case auto-litpools are not
+       used.
+       * config/tc-xtensa.h (xtensa_relax_statesE): New relaxation
+       state: RELAX_LITERAL_POOL_CANDIDATE_BEGIN.
+
+2015-08-12  Max Filippov  <jcmvbkbc@gmail.com>
+gas/testsuite/
+       * gas/xtensa/all.exp: Add auto-litpools to the list of xtensa
+       tests.
+       * gas/xtensa/auto-litpools.s: New file: auto-litpools test.
+       * gas/xtensa/auto-litpools.s: New file: auto-litpools test
+       result pattern.
+
+Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
+---
+Backported from: b46824bd49648c575372e6d9bc6a6defeabd6ed5
+Changes to ChangeLogs and documentation are dropped.
+
+ gas/config/tc-xtensa.c                   | 432 ++++++++++++++++++++++++++++++-
+ gas/config/tc-xtensa.h                   |   1 +
+ gas/testsuite/gas/xtensa/all.exp         |   1 +
+ gas/testsuite/gas/xtensa/auto-litpools.d |  12 +
+ gas/testsuite/gas/xtensa/auto-litpools.s |  13 +
+ 5 files changed, 454 insertions(+), 5 deletions(-)
+ create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.d
+ create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.s
+
+diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
+index 7311a05..b8b1e7d 100644
+--- a/gas/config/tc-xtensa.c
++++ b/gas/config/tc-xtensa.c
+@@ -440,6 +440,29 @@ bfd_boolean directive_state[] =
+ #endif
+ };
++/* A circular list of all potential and actual literal pool locations
++   in a segment.  */
++struct litpool_frag
++{
++  struct litpool_frag *next;
++  struct litpool_frag *prev;
++  fragS *fragP;
++  addressT addr;
++  short priority; /* 1, 2, or 3 -- 1 is highest  */
++  short original_priority;
++};
++
++/* Map a segment to its litpool_frag list.  */
++struct litpool_seg
++{
++  struct litpool_seg *next;
++  asection *seg;
++  struct litpool_frag frag_list;
++  int frag_count; /* since last litpool location  */
++};
++
++static struct litpool_seg litpool_seg_list;
++
+ /* Directive functions.  */
+@@ -474,6 +497,9 @@ static void xtensa_create_trampoline_frag (bfd_boolean);
+ static void xtensa_maybe_create_trampoline_frag (void);
+ struct trampoline_frag;
+ static int init_trampoline_frag (struct trampoline_frag *);
++static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
++static bfd_boolean auto_litpools = FALSE;
++static int auto_litpool_limit = 10000;
+ /* Alignment Functions.  */
+@@ -698,6 +724,10 @@ enum
+   option_trampolines,
+   option_no_trampolines,
++
++  option_auto_litpools,
++  option_no_auto_litpools,
++  option_auto_litpool_limit,
+ };
+ const char *md_shortopts = "";
+@@ -773,6 +803,10 @@ struct option md_longopts[] =
+   { "trampolines", no_argument, NULL, option_trampolines },
+   { "no-trampolines", no_argument, NULL, option_no_trampolines },
++  { "auto-litpools", no_argument, NULL, option_auto_litpools },
++  { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
++  { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
++
+   { NULL, no_argument, NULL, 0 }
+ };
+@@ -961,6 +995,34 @@ md_parse_option (int c, char *arg)
+       use_trampolines = FALSE;
+       return 1;
++    case option_auto_litpools:
++      auto_litpools = TRUE;
++      use_literal_section = FALSE;
++      return 1;
++
++    case option_no_auto_litpools:
++      auto_litpools = FALSE;
++      auto_litpool_limit = -1;
++      return 1;
++
++    case option_auto_litpool_limit:
++      {
++      int value = 0;
++      if (auto_litpool_limit < 0)
++        as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
++      if (*arg == 0 || *arg == '-')
++        as_fatal (_("invalid auto-litpool-limit argument"));
++      value = strtol (arg, &arg, 10);
++      if (*arg != 0)
++        as_fatal (_("invalid auto-litpool-limit argument"));
++      if (value < 100 || value > 10000)
++        as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
++      auto_litpool_limit = value;
++      auto_litpools = TRUE;
++      use_literal_section = FALSE;
++      return 1;
++      }
++
+     default:
+       return 0;
+     }
+@@ -986,7 +1048,12 @@ Xtensa options:\n\
+                           flix bundles\n\
+   --rename-section old=new Rename section 'old' to 'new'\n\
+   --[no-]trampolines      [Do not] generate trampolines (jumps to jumps)\n\
+-                          when jumps do not reach their targets\n", stream);
++                          when jumps do not reach their targets\n\
++  --[no-]auto-litpools    [Do not] automatically create literal pools\n\
++  --auto-litpool-limit=<value>\n\
++                          (range 100-10000) Maximum number of blocks of\n\
++                          instructions to emit between literal pool\n\
++                          locations; implies --auto-litpools flag\n", stream);
+ }
\f
+@@ -4728,6 +4795,8 @@ xtensa_mark_literal_pool_location (void)
+   pool_location = frag_now;
+   frag_now->tc_frag_data.lit_frchain = frchain_now;
+   frag_now->tc_frag_data.literal_frag = frag_now;
++  /* Just record this frag.  */
++  xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
+   frag_variant (rs_machine_dependent, 0, 0,
+               RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
+   xtensa_set_frag_assembly_state (frag_now);
+@@ -4832,6 +4901,31 @@ get_expanded_loop_offset (xtensa_opcode opcode)
+ static fragS *
+ get_literal_pool_location (segT seg)
+ {
++  struct litpool_seg *lps = litpool_seg_list.next;
++  struct litpool_frag *lpf;
++  for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
++    ;
++  if (lps)
++    {
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      { /* Skip "candidates" for now.  */
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
++            lpf->priority == 1)
++          return lpf->fragP;
++      }
++      /* Must convert a lower-priority pool.  */
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      {
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
++          return lpf->fragP;
++      }
++      /* Still no match -- try for a low priority pool.  */
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      {
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
++          return lpf->fragP;
++      }
++    }
+   return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
+ }
+@@ -7098,6 +7192,11 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
+       frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
+       frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
+       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
++      if (tinsn->opcode == xtensa_l32r_opcode)
++      {
++        frag_now->tc_frag_data.literal_frags[slot] =
++                tinsn->tok[1].X_add_symbol->sy_frag;
++      }
+       if (tinsn->literal_space != 0)
+       xg_assemble_literal_space (tinsn->literal_space, slot);
+       frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
+@@ -7170,6 +7269,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
+                   frag_now->fr_symbol, frag_now->fr_offset, NULL);
+         xtensa_set_frag_assembly_state (frag_now);
+         xtensa_maybe_create_trampoline_frag ();
++        /* Always create one here.  */
++        xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
+       }
+       else if (is_branch && do_align_targets ())
+       {
+@@ -7314,11 +7415,18 @@ xtensa_check_frag_count (void)
+       clear_frag_count ();
+       unreachable_count = 0;
+     }
++
++  /* We create an area for a possible literal pool every N (default 5000)
++     frags or so.  */
++  xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+ }
+ static xtensa_insnbuf trampoline_buf = NULL;
+ static xtensa_insnbuf trampoline_slotbuf = NULL;
++static xtensa_insnbuf litpool_buf = NULL;
++static xtensa_insnbuf litpool_slotbuf = NULL;
++
+ #define TRAMPOLINE_FRAG_SIZE 3000
+ static void
+@@ -7410,6 +7518,135 @@ dump_trampolines (void)
+     }
+ }
++static void dump_litpools (void) __attribute__ ((unused));
++
++static void
++dump_litpools (void)
++{
++  struct litpool_seg *lps = litpool_seg_list.next;
++  struct litpool_frag *lpf;
++
++  for ( ; lps ; lps = lps->next )
++    {
++      printf("litpool seg %s\n", lps->seg->name);
++      for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
++      {
++        fragS *litfrag = lpf->fragP->fr_next;
++        int count = 0;
++        while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
++          {
++            if (litfrag->fr_fix == 4)
++              count++;
++            litfrag = litfrag->fr_next;
++          }
++        printf("   %ld <%d:%d> (%d) [%d]: ",
++               lpf->addr, lpf->priority, lpf->original_priority,
++               lpf->fragP->fr_line, count);
++        //dump_frag(lpf->fragP);
++      }
++    }
++}
++
++static void
++xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
++                                     bfd_boolean only_if_needed)
++{
++  struct litpool_seg *lps = litpool_seg_list.next;
++  fragS *fragP;
++  struct litpool_frag *lpf;
++  bfd_boolean needed = FALSE;
++
++  if (use_literal_section || !auto_litpools)
++    return;
++
++  for ( ; lps ; lps = lps->next )
++    {
++      if (lps->seg == now_seg)
++      break;
++    }
++
++  if (lps == NULL)
++    {
++      lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
++      lps->next = litpool_seg_list.next;
++      litpool_seg_list.next = lps;
++      lps->seg = now_seg;
++      lps->frag_list.next = &lps->frag_list;
++      lps->frag_list.prev = &lps->frag_list;
++    }
++
++  lps->frag_count++;
++
++  if (create)
++    {
++      if (only_if_needed)
++      {
++        if (past_xtensa_end || !use_transform() ||
++            frag_now->tc_frag_data.is_no_transform)
++          {
++            return;
++          }
++        if (auto_litpool_limit <= 0)
++          {
++            /* Don't create a litpool based only on frag count.  */
++            return;
++          }
++        else if (lps->frag_count > auto_litpool_limit)
++          {
++            needed = TRUE;
++          }
++        else
++          {
++            return;
++          }
++      }
++      else
++      {
++        needed = TRUE;
++      }
++    }
++
++  if (needed)
++    {
++      int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn.  */
++      /* Create a potential site for a literal pool.  */
++      frag_wane (frag_now);
++      frag_new (0);
++      xtensa_set_frag_assembly_state (frag_now);
++      fragP = frag_now;
++      fragP->tc_frag_data.lit_frchain = frchain_now;
++      fragP->tc_frag_data.literal_frag = fragP;
++      frag_var (rs_machine_dependent, size, size,
++                  (only_if_needed) ?
++                      RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
++                      RELAX_LITERAL_POOL_BEGIN,
++                  NULL, 0, NULL);
++      frag_now->tc_frag_data.lit_seg = now_seg;
++      frag_variant (rs_machine_dependent, 0, 0,
++                  RELAX_LITERAL_POOL_END, NULL, 0, NULL);
++      xtensa_set_frag_assembly_state (frag_now);
++    }
++  else
++    {
++      /* RELAX_LITERAL_POOL_BEGIN frag is being created;
++       just record it here.  */
++      fragP = frag_now;
++    }
++
++  lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
++  /* Insert at tail of circular list.  */
++  lpf->addr = 0;
++  lps->frag_list.prev->next = lpf;
++  lpf->next = &lps->frag_list;
++  lpf->prev = lps->frag_list.prev;
++  lps->frag_list.prev = lpf;
++  lpf->fragP = fragP;
++  lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
++  lpf->original_priority = lpf->priority;
++
++  lps->frag_count = 0;
++}
++
+ static void
+ xtensa_cleanup_align_frags (void)
+ {
+@@ -9029,7 +9266,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
+       break;
+     case RELAX_LITERAL_POOL_BEGIN:
++      if (fragP->fr_var != 0)
++      {
++        /* We have a converted "candidate" literal pool;
++           assemble a jump around it.  */
++        TInsn insn;
++        if (!litpool_slotbuf)
++          {
++            litpool_buf = xtensa_insnbuf_alloc (isa);
++            litpool_slotbuf = xtensa_insnbuf_alloc (isa);
++          }
++        new_stretch += 3;
++        fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass.  */
++        fragP->tc_frag_data.is_insn = TRUE;
++        tinsn_init (&insn);
++        insn.insn_type = ITYPE_INSN;
++        insn.opcode = xtensa_j_opcode;
++        insn.ntok = 1;
++        set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
++                                fragP->fr_fix);
++        fmt = xg_get_single_format (xtensa_j_opcode);
++        tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
++        xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
++        xtensa_insnbuf_to_chars (isa, litpool_buf,
++                                 (unsigned char *)fragP->fr_literal +
++                                 fragP->fr_fix, 3);
++        fragP->fr_fix += 3;
++        fragP->fr_var -= 3;
++        /* Add a fix-up.  */
++        fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
++                 BFD_RELOC_XTENSA_SLOT0_OP);
++      }
++      break;
++
+     case RELAX_LITERAL_POOL_END:
++    case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
+     case RELAX_MAYBE_UNREACHABLE:
+     case RELAX_MAYBE_DESIRE_ALIGN:
+       /* No relaxation required.  */
+@@ -10789,12 +11060,115 @@ xtensa_move_literals (void)
+   segT dest_seg;
+   fixS *fix, *next_fix, **fix_splice;
+   sym_list *lit;
++  struct litpool_seg *lps;
+   mark_literal_frags (literal_head->next);
+   if (use_literal_section)
+     return;
++  /* Assign addresses (rough estimates) to the potential literal pool locations
++     and create new ones if the gaps are too large.  */
++
++  for (lps = litpool_seg_list.next; lps; lps = lps->next)
++    {
++      frchainS *frchP = seg_info (lps->seg)->frchainP;
++      struct litpool_frag *lpf = lps->frag_list.next;
++      addressT addr = 0;
++
++      for ( ; frchP; frchP = frchP->frch_next)
++      {
++        fragS *fragP;
++        for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
++          {
++            if (lpf && fragP == lpf->fragP)
++              {
++                gas_assert(fragP->fr_type == rs_machine_dependent &&
++                           (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
++                            fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
++                /* Found a litpool location.  */
++                lpf->addr = addr;
++                lpf = lpf->next;
++              }
++            if (fragP->fr_type == rs_machine_dependent &&
++                fragP->fr_subtype == RELAX_SLOTS)
++              {
++                int slot;
++                for (slot = 0; slot < MAX_SLOTS; slot++)
++                  {
++                    if (fragP->tc_frag_data.literal_frags[slot])
++                      {
++                        /* L32R; point its literal to the nearest litpool
++                           preferring non-"candidate" positions to avoid
++                           the jump-around.  */
++                        fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
++                        struct litpool_frag *lp = lpf->prev;
++                        if (!lp->fragP)
++                          {
++                            break;
++                          }
++                        while (lp->fragP->fr_subtype ==
++                               RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
++                          {
++                            lp = lp->prev;
++                            if (lp->fragP == NULL)
++                              {
++                                /* End of list; have to bite the bullet.
++                                   Take the nearest.  */
++                                lp = lpf->prev;
++                                break;
++                              }
++                            /* Does it (conservatively) reach?  */
++                            if (addr - lp->addr <= 128 * 1024)
++                              {
++                                if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
++                                  {
++                                    /* Found a good one.  */
++                                    break;
++                                  }
++                                else if (lp->prev->fragP &&
++                                         addr - lp->prev->addr > 128 * 1024)
++                                  {
++                                    /* This is still a "candidate" but the next one
++                                       will be too far away, so revert to the nearest
++                                       one, convert it and add the jump around.  */
++                                    fragS *poolbeg;
++                                    fragS *poolend;
++                                    symbolS *lsym;
++                                    char label[10 + 2 * sizeof (fragS *)];
++                                    lp = lpf->prev;
++                                    poolbeg = lp->fragP;
++                                    lp->priority = 1;
++                                    poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
++                                    poolend = poolbeg->fr_next;
++                                    gas_assert (poolend->fr_type == rs_machine_dependent &&
++                                                poolend->fr_subtype == RELAX_LITERAL_POOL_END);
++                                    /* Create a local symbol pointing to the
++                                       end of the pool.  */
++                                    sprintf (label, ".L0_LT_%p", poolbeg);
++                                    lsym = (symbolS *)local_symbol_make (label, lps->seg,
++                                                                         0, poolend);
++                                    poolbeg->fr_symbol = lsym;
++                                    /* Rest is done in xtensa_relax_frag.  */
++                                  }
++                              }
++                          }
++                        if (! litfrag->tc_frag_data.literal_frag)
++                          {
++                            /* Take earliest use of this literal to avoid
++                               forward refs.  */
++                            litfrag->tc_frag_data.literal_frag = lp->fragP;
++                          }
++                      }
++                  }
++              }
++            addr += fragP->fr_fix;
++            if (fragP->fr_type == rs_fill)
++              addr += fragP->fr_offset;
++          }
++      }
++    }
++
+   for (segment = literal_head->next; segment; segment = segment->next)
+     {
+       /* Keep the literals for .init and .fini in separate sections.  */
+@@ -10839,9 +11213,6 @@ xtensa_move_literals (void)
+       while (search_frag != frag_now)
+       {
+         next_frag = search_frag->fr_next;
+-
+-        /* First, move the frag out of the literal section and
+-           to the appropriate place.  */
+         if (search_frag->tc_frag_data.literal_frag)
+           {
+             literal_pool = search_frag->tc_frag_data.literal_frag;
+@@ -10849,8 +11220,56 @@ xtensa_move_literals (void)
+             frchain_to = literal_pool->tc_frag_data.lit_frchain;
+             gas_assert (frchain_to);
+           }
++
++        if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
++          {
++            /* Skip empty fill frags.  */
++            *frag_splice = next_frag;
++            search_frag = next_frag;
++            continue;
++          }
++
++        if (search_frag->fr_type == rs_align)
++          {
++            /* Skip alignment frags, because the pool as a whole will be
++               aligned if used, and we don't want to force alignment if the
++               pool is unused.  */
++            *frag_splice = next_frag;
++            search_frag = next_frag;
++            continue;
++          }
++
++        /* First, move the frag out of the literal section and
++           to the appropriate place.  */
++
++        /* Insert an aligmnent frag at start of pool.  */
++        if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
++            literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
++          {
++            segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
++            emit_state prev_state;
++            fragS *prev_frag;
++            fragS *align_frag;
++            xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
++            prev_frag = frag_now;
++            frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
++            align_frag = frag_now;
++            frag_align (2, 0, 0);
++            /* Splice it into the right place.  */
++            prev_frag->fr_next = align_frag->fr_next;
++            align_frag->fr_next = literal_pool->fr_next;
++            literal_pool->fr_next = align_frag;
++            /* Insert after this one.  */
++            literal_pool->tc_frag_data.literal_frag = align_frag;
++            xtensa_restore_emit_state (&prev_state);
++          }
+         insert_after = literal_pool->tc_frag_data.literal_frag;
+         dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
++        /* Skip align frag.  */
++        if (insert_after->fr_next->fr_type == rs_align)
++          {
++            insert_after = insert_after->fr_next;
++          }
+         *frag_splice = next_frag;
+         search_frag->fr_next = insert_after->fr_next;
+@@ -11014,7 +11433,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
+       && !recursive
+       && !is_init && ! is_fini)
+     {
+-      as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
++      if (!auto_litpools)
++      {
++        as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
++      }
+       /* When we mark a literal pool location, we want to put a frag in
+        the literal pool that points to it.  But to do that, we want to
+diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h
+index b2e43fa..290d902 100644
+--- a/gas/config/tc-xtensa.h
++++ b/gas/config/tc-xtensa.h
+@@ -124,6 +124,7 @@ enum xtensa_relax_statesE
+   RELAX_LITERAL_POOL_BEGIN,
+   RELAX_LITERAL_POOL_END,
++  RELAX_LITERAL_POOL_CANDIDATE_BEGIN,
+   /* Technically these are not relaxations at all but mark a location
+      to store literals later.  Note that fr_var stores the frchain for
+      BEGIN frags and fr_var stores now_seg for END frags.  */
+diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp
+index d197ec8..db39629 100644
+--- a/gas/testsuite/gas/xtensa/all.exp
++++ b/gas/testsuite/gas/xtensa/all.exp
+@@ -100,5 +100,6 @@ if [istarget xtensa*-*-*] then {
+     run_dump_test "jlong"
+     run_dump_test "trampoline"
++    run_dump_test "auto-litpools"
+ }
+ if [info exists errorInfo] then {
+diff --git a/gas/testsuite/gas/xtensa/auto-litpools.d b/gas/testsuite/gas/xtensa/auto-litpools.d
+new file mode 100644
+index 0000000..4d1a690
+--- /dev/null
++++ b/gas/testsuite/gas/xtensa/auto-litpools.d
+@@ -0,0 +1,12 @@
++#as: --auto-litpools
++#objdump: -d
++#name: auto literal pool placement
++
++.*: +file format .*xtensa.*
++#...
++.*4:.*l32r.a2, 0 .*
++#...
++.*3e437:.*j.3e440 .*
++#...
++.*40750:.*l32r.a2, 3e43c .*
++#...
+diff --git a/gas/testsuite/gas/xtensa/auto-litpools.s b/gas/testsuite/gas/xtensa/auto-litpools.s
+new file mode 100644
+index 0000000..9a5b26b
+--- /dev/null
++++ b/gas/testsuite/gas/xtensa/auto-litpools.s
+@@ -0,0 +1,13 @@
++      .text
++      .align  4
++      .literal        .L0, 0x12345
++      .literal        .L1, 0x12345
++
++f:
++      l32r    a2, .L0
++      .rep    44000
++      _nop
++      _nop
++      .endr
++      l32r    a2, .L1
++      ret
+-- 
+1.8.1.4
+
diff --git a/package/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch b/package/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch
new file mode 100644 (file)
index 0000000..3ed9af1
--- /dev/null
@@ -0,0 +1,699 @@
+From 978adaaa4cd3921842e2be8a31c05f081fb17fcf Mon Sep 17 00:00:00 2001
+From: Max Filippov <jcmvbkbc@gmail.com>
+Date: Wed, 29 Jul 2015 17:42:54 +0300
+Subject: [PATCH] xtensa: add --auto-litpools option
+
+Auto-litpools is the automated version of text-section-literals: literal
+pool candidate frags are planted every N frags and during relaxation
+they are turned into actual literal pools where literals are moved to
+become reachable for their first reference by L32R instruction.
+
+2015-08-12  David Weatherford  <weath@cadence.com>
+gas/
+       * config/tc-xtensa.c (struct litpool_frag, struct litpool_seg):
+       New structures.
+       (xtensa_maybe_create_literal_pool_frag): New function.
+       (litpool_seg_list, auto_litpools, auto_litpool_limit)
+       (litpool_buf, litpool_slotbuf): New static variables.
+       (option_auto_litpools, option_no_auto_litpools)
+       (option_auto_litpool_limit): New enum identifiers.
+       (md_longopts): Add entries for auto-litpools, no-auto-litpools
+       and auto-litpool-limit.
+       (md_parse_option): Handle option_auto_litpools,
+       option_no_auto_litpools and option_auto_litpool_limit.
+       (md_show_usage): Add help for --[no-]auto-litpools and
+       --auto-litpool-limit.
+       (xtensa_mark_literal_pool_location): Record a place for literal
+       pool with a call to xtensa_maybe_create_literal_pool_frag.
+       (get_literal_pool_location): Find highest priority literal pool
+       or convert candidate to literal pool when auto-litpools are used.
+       (xg_assemble_vliw_tokens): Create literal pool after jump
+       instruction.
+       (xtensa_check_frag_count): Create candidate literal pool every
+       auto_litpool_limit frags.
+       (xtensa_relax_frag): Add jump around literals to non-empty
+       literal pool.
+       (xtensa_move_literals): Estimate literal pool addresses and move
+       unreachable literals closer to their users, converting candidate
+       to literal pool if needed.
+       (xtensa_switch_to_non_abs_literal_fragment): Only emit error
+       about missing .literal_position in case auto-litpools are not
+       used.
+       * config/tc-xtensa.h (xtensa_relax_statesE): New relaxation
+       state: RELAX_LITERAL_POOL_CANDIDATE_BEGIN.
+
+2015-08-12  Max Filippov  <jcmvbkbc@gmail.com>
+gas/testsuite/
+       * gas/xtensa/all.exp: Add auto-litpools to the list of xtensa
+       tests.
+       * gas/xtensa/auto-litpools.s: New file: auto-litpools test.
+       * gas/xtensa/auto-litpools.s: New file: auto-litpools test
+       result pattern.
+
+Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
+---
+Backported from: b46824bd49648c575372e6d9bc6a6defeabd6ed5
+Changes to ChangeLogs and documentation are dropped.
+
+ gas/config/tc-xtensa.c                   | 432 ++++++++++++++++++++++++++++++-
+ gas/config/tc-xtensa.h                   |   1 +
+ gas/testsuite/gas/xtensa/all.exp         |   1 +
+ gas/testsuite/gas/xtensa/auto-litpools.d |  12 +
+ gas/testsuite/gas/xtensa/auto-litpools.s |  13 +
+ 5 files changed, 454 insertions(+), 5 deletions(-)
+ create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.d
+ create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.s
+
+diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
+index 7311a05..b8b1e7d 100644
+--- a/gas/config/tc-xtensa.c
++++ b/gas/config/tc-xtensa.c
+@@ -440,6 +440,29 @@ bfd_boolean directive_state[] =
+ #endif
+ };
++/* A circular list of all potential and actual literal pool locations
++   in a segment.  */
++struct litpool_frag
++{
++  struct litpool_frag *next;
++  struct litpool_frag *prev;
++  fragS *fragP;
++  addressT addr;
++  short priority; /* 1, 2, or 3 -- 1 is highest  */
++  short original_priority;
++};
++
++/* Map a segment to its litpool_frag list.  */
++struct litpool_seg
++{
++  struct litpool_seg *next;
++  asection *seg;
++  struct litpool_frag frag_list;
++  int frag_count; /* since last litpool location  */
++};
++
++static struct litpool_seg litpool_seg_list;
++
+ /* Directive functions.  */
+@@ -474,6 +497,9 @@ static void xtensa_create_trampoline_frag (bfd_boolean);
+ static void xtensa_maybe_create_trampoline_frag (void);
+ struct trampoline_frag;
+ static int init_trampoline_frag (struct trampoline_frag *);
++static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
++static bfd_boolean auto_litpools = FALSE;
++static int auto_litpool_limit = 10000;
+ /* Alignment Functions.  */
+@@ -698,6 +724,10 @@ enum
+   option_trampolines,
+   option_no_trampolines,
++
++  option_auto_litpools,
++  option_no_auto_litpools,
++  option_auto_litpool_limit,
+ };
+ const char *md_shortopts = "";
+@@ -773,6 +803,10 @@ struct option md_longopts[] =
+   { "trampolines", no_argument, NULL, option_trampolines },
+   { "no-trampolines", no_argument, NULL, option_no_trampolines },
++  { "auto-litpools", no_argument, NULL, option_auto_litpools },
++  { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
++  { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
++
+   { NULL, no_argument, NULL, 0 }
+ };
+@@ -961,6 +995,34 @@ md_parse_option (int c, char *arg)
+       use_trampolines = FALSE;
+       return 1;
++    case option_auto_litpools:
++      auto_litpools = TRUE;
++      use_literal_section = FALSE;
++      return 1;
++
++    case option_no_auto_litpools:
++      auto_litpools = FALSE;
++      auto_litpool_limit = -1;
++      return 1;
++
++    case option_auto_litpool_limit:
++      {
++      int value = 0;
++      if (auto_litpool_limit < 0)
++        as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
++      if (*arg == 0 || *arg == '-')
++        as_fatal (_("invalid auto-litpool-limit argument"));
++      value = strtol (arg, &arg, 10);
++      if (*arg != 0)
++        as_fatal (_("invalid auto-litpool-limit argument"));
++      if (value < 100 || value > 10000)
++        as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
++      auto_litpool_limit = value;
++      auto_litpools = TRUE;
++      use_literal_section = FALSE;
++      return 1;
++      }
++
+     default:
+       return 0;
+     }
+@@ -986,7 +1048,12 @@ Xtensa options:\n\
+                           flix bundles\n\
+   --rename-section old=new Rename section 'old' to 'new'\n\
+   --[no-]trampolines      [Do not] generate trampolines (jumps to jumps)\n\
+-                          when jumps do not reach their targets\n", stream);
++                          when jumps do not reach their targets\n\
++  --[no-]auto-litpools    [Do not] automatically create literal pools\n\
++  --auto-litpool-limit=<value>\n\
++                          (range 100-10000) Maximum number of blocks of\n\
++                          instructions to emit between literal pool\n\
++                          locations; implies --auto-litpools flag\n", stream);
+ }
\f
+@@ -4728,6 +4795,8 @@ xtensa_mark_literal_pool_location (void)
+   pool_location = frag_now;
+   frag_now->tc_frag_data.lit_frchain = frchain_now;
+   frag_now->tc_frag_data.literal_frag = frag_now;
++  /* Just record this frag.  */
++  xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
+   frag_variant (rs_machine_dependent, 0, 0,
+               RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
+   xtensa_set_frag_assembly_state (frag_now);
+@@ -4832,6 +4901,31 @@ get_expanded_loop_offset (xtensa_opcode opcode)
+ static fragS *
+ get_literal_pool_location (segT seg)
+ {
++  struct litpool_seg *lps = litpool_seg_list.next;
++  struct litpool_frag *lpf;
++  for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
++    ;
++  if (lps)
++    {
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      { /* Skip "candidates" for now.  */
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
++            lpf->priority == 1)
++          return lpf->fragP;
++      }
++      /* Must convert a lower-priority pool.  */
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      {
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
++          return lpf->fragP;
++      }
++      /* Still no match -- try for a low priority pool.  */
++      for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
++      {
++        if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
++          return lpf->fragP;
++      }
++    }
+   return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
+ }
+@@ -7098,6 +7192,11 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
+       frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
+       frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
+       frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
++      if (tinsn->opcode == xtensa_l32r_opcode)
++      {
++        frag_now->tc_frag_data.literal_frags[slot] =
++                tinsn->tok[1].X_add_symbol->sy_frag;
++      }
+       if (tinsn->literal_space != 0)
+       xg_assemble_literal_space (tinsn->literal_space, slot);
+       frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
+@@ -7170,6 +7269,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
+                   frag_now->fr_symbol, frag_now->fr_offset, NULL);
+         xtensa_set_frag_assembly_state (frag_now);
+         xtensa_maybe_create_trampoline_frag ();
++        /* Always create one here.  */
++        xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
+       }
+       else if (is_branch && do_align_targets ())
+       {
+@@ -7314,11 +7415,18 @@ xtensa_check_frag_count (void)
+       clear_frag_count ();
+       unreachable_count = 0;
+     }
++
++  /* We create an area for a possible literal pool every N (default 5000)
++     frags or so.  */
++  xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
+ }
+ static xtensa_insnbuf trampoline_buf = NULL;
+ static xtensa_insnbuf trampoline_slotbuf = NULL;
++static xtensa_insnbuf litpool_buf = NULL;
++static xtensa_insnbuf litpool_slotbuf = NULL;
++
+ #define TRAMPOLINE_FRAG_SIZE 3000
+ static void
+@@ -7410,6 +7518,135 @@ dump_trampolines (void)
+     }
+ }
++static void dump_litpools (void) __attribute__ ((unused));
++
++static void
++dump_litpools (void)
++{
++  struct litpool_seg *lps = litpool_seg_list.next;
++  struct litpool_frag *lpf;
++
++  for ( ; lps ; lps = lps->next )
++    {
++      printf("litpool seg %s\n", lps->seg->name);
++      for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
++      {
++        fragS *litfrag = lpf->fragP->fr_next;
++        int count = 0;
++        while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
++          {
++            if (litfrag->fr_fix == 4)
++              count++;
++            litfrag = litfrag->fr_next;
++          }
++        printf("   %ld <%d:%d> (%d) [%d]: ",
++               lpf->addr, lpf->priority, lpf->original_priority,
++               lpf->fragP->fr_line, count);
++        //dump_frag(lpf->fragP);
++      }
++    }
++}
++
++static void
++xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
++                                     bfd_boolean only_if_needed)
++{
++  struct litpool_seg *lps = litpool_seg_list.next;
++  fragS *fragP;
++  struct litpool_frag *lpf;
++  bfd_boolean needed = FALSE;
++
++  if (use_literal_section || !auto_litpools)
++    return;
++
++  for ( ; lps ; lps = lps->next )
++    {
++      if (lps->seg == now_seg)
++      break;
++    }
++
++  if (lps == NULL)
++    {
++      lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
++      lps->next = litpool_seg_list.next;
++      litpool_seg_list.next = lps;
++      lps->seg = now_seg;
++      lps->frag_list.next = &lps->frag_list;
++      lps->frag_list.prev = &lps->frag_list;
++    }
++
++  lps->frag_count++;
++
++  if (create)
++    {
++      if (only_if_needed)
++      {
++        if (past_xtensa_end || !use_transform() ||
++            frag_now->tc_frag_data.is_no_transform)
++          {
++            return;
++          }
++        if (auto_litpool_limit <= 0)
++          {
++            /* Don't create a litpool based only on frag count.  */
++            return;
++          }
++        else if (lps->frag_count > auto_litpool_limit)
++          {
++            needed = TRUE;
++          }
++        else
++          {
++            return;
++          }
++      }
++      else
++      {
++        needed = TRUE;
++      }
++    }
++
++  if (needed)
++    {
++      int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn.  */
++      /* Create a potential site for a literal pool.  */
++      frag_wane (frag_now);
++      frag_new (0);
++      xtensa_set_frag_assembly_state (frag_now);
++      fragP = frag_now;
++      fragP->tc_frag_data.lit_frchain = frchain_now;
++      fragP->tc_frag_data.literal_frag = fragP;
++      frag_var (rs_machine_dependent, size, size,
++                  (only_if_needed) ?
++                      RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
++                      RELAX_LITERAL_POOL_BEGIN,
++                  NULL, 0, NULL);
++      frag_now->tc_frag_data.lit_seg = now_seg;
++      frag_variant (rs_machine_dependent, 0, 0,
++                  RELAX_LITERAL_POOL_END, NULL, 0, NULL);
++      xtensa_set_frag_assembly_state (frag_now);
++    }
++  else
++    {
++      /* RELAX_LITERAL_POOL_BEGIN frag is being created;
++       just record it here.  */
++      fragP = frag_now;
++    }
++
++  lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
++  /* Insert at tail of circular list.  */
++  lpf->addr = 0;
++  lps->frag_list.prev->next = lpf;
++  lpf->next = &lps->frag_list;
++  lpf->prev = lps->frag_list.prev;
++  lps->frag_list.prev = lpf;
++  lpf->fragP = fragP;
++  lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
++  lpf->original_priority = lpf->priority;
++
++  lps->frag_count = 0;
++}
++
+ static void
+ xtensa_cleanup_align_frags (void)
+ {
+@@ -9029,7 +9266,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
+       break;
+     case RELAX_LITERAL_POOL_BEGIN:
++      if (fragP->fr_var != 0)
++      {
++        /* We have a converted "candidate" literal pool;
++           assemble a jump around it.  */
++        TInsn insn;
++        if (!litpool_slotbuf)
++          {
++            litpool_buf = xtensa_insnbuf_alloc (isa);
++            litpool_slotbuf = xtensa_insnbuf_alloc (isa);
++          }
++        new_stretch += 3;
++        fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass.  */
++        fragP->tc_frag_data.is_insn = TRUE;
++        tinsn_init (&insn);
++        insn.insn_type = ITYPE_INSN;
++        insn.opcode = xtensa_j_opcode;
++        insn.ntok = 1;
++        set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
++                                fragP->fr_fix);
++        fmt = xg_get_single_format (xtensa_j_opcode);
++        tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
++        xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
++        xtensa_insnbuf_to_chars (isa, litpool_buf,
++                                 (unsigned char *)fragP->fr_literal +
++                                 fragP->fr_fix, 3);
++        fragP->fr_fix += 3;
++        fragP->fr_var -= 3;
++        /* Add a fix-up.  */
++        fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
++                 BFD_RELOC_XTENSA_SLOT0_OP);
++      }
++      break;
++
+     case RELAX_LITERAL_POOL_END:
++    case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
+     case RELAX_MAYBE_UNREACHABLE:
+     case RELAX_MAYBE_DESIRE_ALIGN:
+       /* No relaxation required.  */
+@@ -10789,12 +11060,115 @@ xtensa_move_literals (void)
+   segT dest_seg;
+   fixS *fix, *next_fix, **fix_splice;
+   sym_list *lit;
++  struct litpool_seg *lps;
+   mark_literal_frags (literal_head->next);
+   if (use_literal_section)
+     return;
++  /* Assign addresses (rough estimates) to the potential literal pool locations
++     and create new ones if the gaps are too large.  */
++
++  for (lps = litpool_seg_list.next; lps; lps = lps->next)
++    {
++      frchainS *frchP = seg_info (lps->seg)->frchainP;
++      struct litpool_frag *lpf = lps->frag_list.next;
++      addressT addr = 0;
++
++      for ( ; frchP; frchP = frchP->frch_next)
++      {
++        fragS *fragP;
++        for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
++          {
++            if (lpf && fragP == lpf->fragP)
++              {
++                gas_assert(fragP->fr_type == rs_machine_dependent &&
++                           (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
++                            fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
++                /* Found a litpool location.  */
++                lpf->addr = addr;
++                lpf = lpf->next;
++              }
++            if (fragP->fr_type == rs_machine_dependent &&
++                fragP->fr_subtype == RELAX_SLOTS)
++              {
++                int slot;
++                for (slot = 0; slot < MAX_SLOTS; slot++)
++                  {
++                    if (fragP->tc_frag_data.literal_frags[slot])
++                      {
++                        /* L32R; point its literal to the nearest litpool
++                           preferring non-"candidate" positions to avoid
++                           the jump-around.  */
++                        fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
++                        struct litpool_frag *lp = lpf->prev;
++                        if (!lp->fragP)
++                          {
++                            break;
++                          }
++                        while (lp->fragP->fr_subtype ==
++                               RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
++                          {
++                            lp = lp->prev;
++                            if (lp->fragP == NULL)
++                              {
++                                /* End of list; have to bite the bullet.
++                                   Take the nearest.  */
++                                lp = lpf->prev;
++                                break;
++                              }
++                            /* Does it (conservatively) reach?  */
++                            if (addr - lp->addr <= 128 * 1024)
++                              {
++                                if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
++                                  {
++                                    /* Found a good one.  */
++                                    break;
++                                  }
++                                else if (lp->prev->fragP &&
++                                         addr - lp->prev->addr > 128 * 1024)
++                                  {
++                                    /* This is still a "candidate" but the next one
++                                       will be too far away, so revert to the nearest
++                                       one, convert it and add the jump around.  */
++                                    fragS *poolbeg;
++                                    fragS *poolend;
++                                    symbolS *lsym;
++                                    char label[10 + 2 * sizeof (fragS *)];
++                                    lp = lpf->prev;
++                                    poolbeg = lp->fragP;
++                                    lp->priority = 1;
++                                    poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
++                                    poolend = poolbeg->fr_next;
++                                    gas_assert (poolend->fr_type == rs_machine_dependent &&
++                                                poolend->fr_subtype == RELAX_LITERAL_POOL_END);
++                                    /* Create a local symbol pointing to the
++                                       end of the pool.  */
++                                    sprintf (label, ".L0_LT_%p", poolbeg);
++                                    lsym = (symbolS *)local_symbol_make (label, lps->seg,
++                                                                         0, poolend);
++                                    poolbeg->fr_symbol = lsym;
++                                    /* Rest is done in xtensa_relax_frag.  */
++                                  }
++                              }
++                          }
++                        if (! litfrag->tc_frag_data.literal_frag)
++                          {
++                            /* Take earliest use of this literal to avoid
++                               forward refs.  */
++                            litfrag->tc_frag_data.literal_frag = lp->fragP;
++                          }
++                      }
++                  }
++              }
++            addr += fragP->fr_fix;
++            if (fragP->fr_type == rs_fill)
++              addr += fragP->fr_offset;
++          }
++      }
++    }
++
+   for (segment = literal_head->next; segment; segment = segment->next)
+     {
+       /* Keep the literals for .init and .fini in separate sections.  */
+@@ -10839,9 +11213,6 @@ xtensa_move_literals (void)
+       while (search_frag != frag_now)
+       {
+         next_frag = search_frag->fr_next;
+-
+-        /* First, move the frag out of the literal section and
+-           to the appropriate place.  */
+         if (search_frag->tc_frag_data.literal_frag)
+           {
+             literal_pool = search_frag->tc_frag_data.literal_frag;
+@@ -10849,8 +11220,56 @@ xtensa_move_literals (void)
+             frchain_to = literal_pool->tc_frag_data.lit_frchain;
+             gas_assert (frchain_to);
+           }
++
++        if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
++          {
++            /* Skip empty fill frags.  */
++            *frag_splice = next_frag;
++            search_frag = next_frag;
++            continue;
++          }
++
++        if (search_frag->fr_type == rs_align)
++          {
++            /* Skip alignment frags, because the pool as a whole will be
++               aligned if used, and we don't want to force alignment if the
++               pool is unused.  */
++            *frag_splice = next_frag;
++            search_frag = next_frag;
++            continue;
++          }
++
++        /* First, move the frag out of the literal section and
++           to the appropriate place.  */
++
++        /* Insert an aligmnent frag at start of pool.  */
++        if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
++            literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
++          {
++            segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
++            emit_state prev_state;
++            fragS *prev_frag;
++            fragS *align_frag;
++            xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
++            prev_frag = frag_now;
++            frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
++            align_frag = frag_now;
++            frag_align (2, 0, 0);
++            /* Splice it into the right place.  */
++            prev_frag->fr_next = align_frag->fr_next;
++            align_frag->fr_next = literal_pool->fr_next;
++            literal_pool->fr_next = align_frag;
++            /* Insert after this one.  */
++            literal_pool->tc_frag_data.literal_frag = align_frag;
++            xtensa_restore_emit_state (&prev_state);
++          }
+         insert_after = literal_pool->tc_frag_data.literal_frag;
+         dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
++        /* Skip align frag.  */
++        if (insert_after->fr_next->fr_type == rs_align)
++          {
++            insert_after = insert_after->fr_next;
++          }
+         *frag_splice = next_frag;
+         search_frag->fr_next = insert_after->fr_next;
+@@ -11014,7 +11433,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
+       && !recursive
+       && !is_init && ! is_fini)
+     {
+-      as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
++      if (!auto_litpools)
++      {
++        as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
++      }
+       /* When we mark a literal pool location, we want to put a frag in
+        the literal pool that points to it.  But to do that, we want to
+diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h
+index b2e43fa..290d902 100644
+--- a/gas/config/tc-xtensa.h
++++ b/gas/config/tc-xtensa.h
+@@ -124,6 +124,7 @@ enum xtensa_relax_statesE
+   RELAX_LITERAL_POOL_BEGIN,
+   RELAX_LITERAL_POOL_END,
++  RELAX_LITERAL_POOL_CANDIDATE_BEGIN,
+   /* Technically these are not relaxations at all but mark a location
+      to store literals later.  Note that fr_var stores the frchain for
+      BEGIN frags and fr_var stores now_seg for END frags.  */
+diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp
+index d197ec8..db39629 100644
+--- a/gas/testsuite/gas/xtensa/all.exp
++++ b/gas/testsuite/gas/xtensa/all.exp
+@@ -100,6 +100,7 @@ if [istarget xtensa*-*-*] then {
+     run_dump_test "jlong"
+     run_dump_test "trampoline"
+     run_dump_test "first_frag_align"
++    run_dump_test "auto-litpools"
+ }
+ if [info exists errorInfo] then {
+diff --git a/gas/testsuite/gas/xtensa/auto-litpools.d b/gas/testsuite/gas/xtensa/auto-litpools.d
+new file mode 100644
+index 0000000..4d1a690
+--- /dev/null
++++ b/gas/testsuite/gas/xtensa/auto-litpools.d
+@@ -0,0 +1,12 @@
++#as: --auto-litpools
++#objdump: -d
++#name: auto literal pool placement
++
++.*: +file format .*xtensa.*
++#...
++.*4:.*l32r.a2, 0 .*
++#...
++.*3e437:.*j.3e440 .*
++#...
++.*40750:.*l32r.a2, 3e43c .*
++#...
+diff --git a/gas/testsuite/gas/xtensa/auto-litpools.s b/gas/testsuite/gas/xtensa/auto-litpools.s
+new file mode 100644
+index 0000000..9a5b26b
+--- /dev/null
++++ b/gas/testsuite/gas/xtensa/auto-litpools.s
+@@ -0,0 +1,13 @@
++      .text
++      .align  4
++      .literal        .L0, 0x12345
++      .literal        .L1, 0x12345
++
++f:
++      l32r    a2, .L0
++      .rep    44000
++      _nop
++      _nop
++      .endr
++      l32r    a2, .L1
++      ret
+-- 
+1.8.1.4
+