summaryrefslogtreecommitdiff
path: root/patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch')
-rw-r--r--patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch699
1 files changed, 0 insertions, 699 deletions
diff --git a/patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch b/patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch
deleted file mode 100644
index 3ed9af1..0000000
--- a/patches/binutils/2.25.1/913-xtensa-add-auto-litpools-option.patch
+++ /dev/null
@@ -1,699 +0,0 @@
-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);
- }
-
-
-@@ -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
-