All of lore.kernel.org
 help / color / mirror / Atom feed
From: Max Filippov <jcmvbkbc@gmail.com>
To: buildroot@busybox.net
Subject: [Buildroot] [PATCH 1/4] binutils: backport auto-litpools xtensa gas option
Date: Thu, 13 Aug 2015 01:20:00 +0300	[thread overview]
Message-ID: <1439418003-23805-2-git-send-email-jcmvbkbc@gmail.com> (raw)
In-Reply-To: <1439418003-23805-1-git-send-email-jcmvbkbc@gmail.com>

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>
---
 .../2.24/913-xtensa-add-auto-litpools-option.patch | 698 ++++++++++++++++++++
 .../913-xtensa-add-auto-litpools-option.patch      | 699 +++++++++++++++++++++
 2 files changed, 1397 insertions(+)
 create mode 100644 package/binutils/2.24/913-xtensa-add-auto-litpools-option.patch
 create mode 100644 package/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch

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
index 0000000..f0199e1
--- /dev/null
+++ b/package/binutils/2.24/913-xtensa-add-auto-litpools-option.patch
@@ -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
index 0000000..3ed9af1
--- /dev/null
+++ b/package/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch
@@ -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
+
-- 
1.8.1.4

  reply	other threads:[~2015-08-12 22:20 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-12 22:19 [Buildroot] [PATCH 0/4] xtensa: toolchain fix for compiling huge functions Max Filippov
2015-08-12 22:20 ` Max Filippov [this message]
2015-08-12 22:20 ` [Buildroot] [PATCH 2/4] gcc: backport mauto-litpools xtensa option Max Filippov
2015-08-12 22:20 ` [Buildroot] [PATCH 3/4] xtensa: switch from text-section-literals to auto-litpools Max Filippov
2015-08-12 22:20 ` [Buildroot] [PATCH 4/4] Revert "opencv: mark as not available on Xtensa" Max Filippov
2015-08-18 21:29 ` [Buildroot] [PATCH 0/4] xtensa: toolchain fix for compiling huge functions Yann E. MORIN
2015-08-18 22:20   ` Max Filippov
2015-10-04 16:28 ` Thomas Petazzoni
2015-10-05 14:52   ` Max Filippov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1439418003-23805-2-git-send-email-jcmvbkbc@gmail.com \
    --to=jcmvbkbc@gmail.com \
    --cc=buildroot@busybox.net \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.