1 From 978adaaa4cd3921842e2be8a31c05f081fb17fcf Mon Sep 17 00:00:00 2001
2 From: Max Filippov <jcmvbkbc@gmail.com>
3 Date: Wed, 29 Jul 2015 17:42:54 +0300
4 Subject: [PATCH] xtensa: add --auto-litpools option
6 Auto-litpools is the automated version of text-section-literals: literal
7 pool candidate frags are planted every N frags and during relaxation
8 they are turned into actual literal pools where literals are moved to
9 become reachable for their first reference by L32R instruction.
11 2015-08-12 David Weatherford <weath@cadence.com>
13 * config/tc-xtensa.c (struct litpool_frag, struct litpool_seg):
15 (xtensa_maybe_create_literal_pool_frag): New function.
16 (litpool_seg_list, auto_litpools, auto_litpool_limit)
17 (litpool_buf, litpool_slotbuf): New static variables.
18 (option_auto_litpools, option_no_auto_litpools)
19 (option_auto_litpool_limit): New enum identifiers.
20 (md_longopts): Add entries for auto-litpools, no-auto-litpools
21 and auto-litpool-limit.
22 (md_parse_option): Handle option_auto_litpools,
23 option_no_auto_litpools and option_auto_litpool_limit.
24 (md_show_usage): Add help for --[no-]auto-litpools and
26 (xtensa_mark_literal_pool_location): Record a place for literal
27 pool with a call to xtensa_maybe_create_literal_pool_frag.
28 (get_literal_pool_location): Find highest priority literal pool
29 or convert candidate to literal pool when auto-litpools are used.
30 (xg_assemble_vliw_tokens): Create literal pool after jump
32 (xtensa_check_frag_count): Create candidate literal pool every
33 auto_litpool_limit frags.
34 (xtensa_relax_frag): Add jump around literals to non-empty
36 (xtensa_move_literals): Estimate literal pool addresses and move
37 unreachable literals closer to their users, converting candidate
38 to literal pool if needed.
39 (xtensa_switch_to_non_abs_literal_fragment): Only emit error
40 about missing .literal_position in case auto-litpools are not
42 * config/tc-xtensa.h (xtensa_relax_statesE): New relaxation
43 state: RELAX_LITERAL_POOL_CANDIDATE_BEGIN.
45 2015-08-12 Max Filippov <jcmvbkbc@gmail.com>
47 * gas/xtensa/all.exp: Add auto-litpools to the list of xtensa
49 * gas/xtensa/auto-litpools.s: New file: auto-litpools test.
50 * gas/xtensa/auto-litpools.s: New file: auto-litpools test
53 Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
55 Backported from: b46824bd49648c575372e6d9bc6a6defeabd6ed5
56 Changes to ChangeLogs and documentation are dropped.
58 gas/config/tc-xtensa.c | 432 ++++++++++++++++++++++++++++++-
59 gas/config/tc-xtensa.h | 1 +
60 gas/testsuite/gas/xtensa/all.exp | 1 +
61 gas/testsuite/gas/xtensa/auto-litpools.d | 12 +
62 gas/testsuite/gas/xtensa/auto-litpools.s | 13 +
63 5 files changed, 454 insertions(+), 5 deletions(-)
64 create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.d
65 create mode 100644 gas/testsuite/gas/xtensa/auto-litpools.s
67 diff --git a/gas/config/tc-xtensa.c b/gas/config/tc-xtensa.c
68 index 7311a05..b8b1e7d 100644
69 --- a/gas/config/tc-xtensa.c
70 +++ b/gas/config/tc-xtensa.c
71 @@ -440,6 +440,29 @@ bfd_boolean directive_state[] =
75 +/* A circular list of all potential and actual literal pool locations
79 + struct litpool_frag *next;
80 + struct litpool_frag *prev;
83 + short priority; /* 1, 2, or 3 -- 1 is highest */
84 + short original_priority;
87 +/* Map a segment to its litpool_frag list. */
90 + struct litpool_seg *next;
92 + struct litpool_frag frag_list;
93 + int frag_count; /* since last litpool location */
96 +static struct litpool_seg litpool_seg_list;
99 /* Directive functions. */
101 @@ -474,6 +497,9 @@ static void xtensa_create_trampoline_frag (bfd_boolean);
102 static void xtensa_maybe_create_trampoline_frag (void);
103 struct trampoline_frag;
104 static int init_trampoline_frag (struct trampoline_frag *);
105 +static void xtensa_maybe_create_literal_pool_frag (bfd_boolean, bfd_boolean);
106 +static bfd_boolean auto_litpools = FALSE;
107 +static int auto_litpool_limit = 10000;
109 /* Alignment Functions. */
111 @@ -698,6 +724,10 @@ enum
114 option_no_trampolines,
116 + option_auto_litpools,
117 + option_no_auto_litpools,
118 + option_auto_litpool_limit,
121 const char *md_shortopts = "";
122 @@ -773,6 +803,10 @@ struct option md_longopts[] =
123 { "trampolines", no_argument, NULL, option_trampolines },
124 { "no-trampolines", no_argument, NULL, option_no_trampolines },
126 + { "auto-litpools", no_argument, NULL, option_auto_litpools },
127 + { "no-auto-litpools", no_argument, NULL, option_no_auto_litpools },
128 + { "auto-litpool-limit", required_argument, NULL, option_auto_litpool_limit },
130 { NULL, no_argument, NULL, 0 }
133 @@ -961,6 +995,34 @@ md_parse_option (int c, char *arg)
134 use_trampolines = FALSE;
137 + case option_auto_litpools:
138 + auto_litpools = TRUE;
139 + use_literal_section = FALSE;
142 + case option_no_auto_litpools:
143 + auto_litpools = FALSE;
144 + auto_litpool_limit = -1;
147 + case option_auto_litpool_limit:
150 + if (auto_litpool_limit < 0)
151 + as_fatal (_("no-auto-litpools is incompatible with auto-litpool-limit"));
152 + if (*arg == 0 || *arg == '-')
153 + as_fatal (_("invalid auto-litpool-limit argument"));
154 + value = strtol (arg, &arg, 10);
156 + as_fatal (_("invalid auto-litpool-limit argument"));
157 + if (value < 100 || value > 10000)
158 + as_fatal (_("invalid auto-litpool-limit argument (range is 100-10000)"));
159 + auto_litpool_limit = value;
160 + auto_litpools = TRUE;
161 + use_literal_section = FALSE;
168 @@ -986,7 +1048,12 @@ Xtensa options:\n\
170 --rename-section old=new Rename section 'old' to 'new'\n\
171 --[no-]trampolines [Do not] generate trampolines (jumps to jumps)\n\
172 - when jumps do not reach their targets\n", stream);
173 + when jumps do not reach their targets\n\
174 + --[no-]auto-litpools [Do not] automatically create literal pools\n\
175 + --auto-litpool-limit=<value>\n\
176 + (range 100-10000) Maximum number of blocks of\n\
177 + instructions to emit between literal pool\n\
178 + locations; implies --auto-litpools flag\n", stream);
182 @@ -4728,6 +4795,8 @@ xtensa_mark_literal_pool_location (void)
183 pool_location = frag_now;
184 frag_now->tc_frag_data.lit_frchain = frchain_now;
185 frag_now->tc_frag_data.literal_frag = frag_now;
186 + /* Just record this frag. */
187 + xtensa_maybe_create_literal_pool_frag (FALSE, FALSE);
188 frag_variant (rs_machine_dependent, 0, 0,
189 RELAX_LITERAL_POOL_BEGIN, NULL, 0, NULL);
190 xtensa_set_frag_assembly_state (frag_now);
191 @@ -4832,6 +4901,31 @@ get_expanded_loop_offset (xtensa_opcode opcode)
193 get_literal_pool_location (segT seg)
195 + struct litpool_seg *lps = litpool_seg_list.next;
196 + struct litpool_frag *lpf;
197 + for ( ; lps && lps->seg->id != seg->id; lps = lps->next)
201 + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
202 + { /* Skip "candidates" for now. */
203 + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN &&
204 + lpf->priority == 1)
207 + /* Must convert a lower-priority pool. */
208 + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
210 + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
213 + /* Still no match -- try for a low priority pool. */
214 + for (lpf = lps->frag_list.prev; lpf->fragP; lpf = lpf->prev)
216 + if (lpf->fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
220 return seg_info (seg)->tc_segment_info_data.literal_pool_loc;
223 @@ -7098,6 +7192,11 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
224 frag_now->tc_frag_data.slot_symbols[slot] = tinsn->symbol;
225 frag_now->tc_frag_data.slot_offsets[slot] = tinsn->offset;
226 frag_now->tc_frag_data.literal_frags[slot] = tinsn->literal_frag;
227 + if (tinsn->opcode == xtensa_l32r_opcode)
229 + frag_now->tc_frag_data.literal_frags[slot] =
230 + tinsn->tok[1].X_add_symbol->sy_frag;
232 if (tinsn->literal_space != 0)
233 xg_assemble_literal_space (tinsn->literal_space, slot);
234 frag_now->tc_frag_data.free_reg[slot] = tinsn->extra_arg;
235 @@ -7170,6 +7269,8 @@ xg_assemble_vliw_tokens (vliw_insn *vinsn)
236 frag_now->fr_symbol, frag_now->fr_offset, NULL);
237 xtensa_set_frag_assembly_state (frag_now);
238 xtensa_maybe_create_trampoline_frag ();
239 + /* Always create one here. */
240 + xtensa_maybe_create_literal_pool_frag (TRUE, FALSE);
242 else if (is_branch && do_align_targets ())
244 @@ -7314,11 +7415,18 @@ xtensa_check_frag_count (void)
246 unreachable_count = 0;
249 + /* We create an area for a possible literal pool every N (default 5000)
251 + xtensa_maybe_create_literal_pool_frag (TRUE, TRUE);
254 static xtensa_insnbuf trampoline_buf = NULL;
255 static xtensa_insnbuf trampoline_slotbuf = NULL;
257 +static xtensa_insnbuf litpool_buf = NULL;
258 +static xtensa_insnbuf litpool_slotbuf = NULL;
260 #define TRAMPOLINE_FRAG_SIZE 3000
263 @@ -7410,6 +7518,135 @@ dump_trampolines (void)
267 +static void dump_litpools (void) __attribute__ ((unused));
270 +dump_litpools (void)
272 + struct litpool_seg *lps = litpool_seg_list.next;
273 + struct litpool_frag *lpf;
275 + for ( ; lps ; lps = lps->next )
277 + printf("litpool seg %s\n", lps->seg->name);
278 + for ( lpf = lps->frag_list.next; lpf->fragP; lpf = lpf->next )
280 + fragS *litfrag = lpf->fragP->fr_next;
282 + while (litfrag && litfrag->fr_subtype != RELAX_LITERAL_POOL_END)
284 + if (litfrag->fr_fix == 4)
286 + litfrag = litfrag->fr_next;
288 + printf(" %ld <%d:%d> (%d) [%d]: ",
289 + lpf->addr, lpf->priority, lpf->original_priority,
290 + lpf->fragP->fr_line, count);
291 + //dump_frag(lpf->fragP);
297 +xtensa_maybe_create_literal_pool_frag (bfd_boolean create,
298 + bfd_boolean only_if_needed)
300 + struct litpool_seg *lps = litpool_seg_list.next;
302 + struct litpool_frag *lpf;
303 + bfd_boolean needed = FALSE;
305 + if (use_literal_section || !auto_litpools)
308 + for ( ; lps ; lps = lps->next )
310 + if (lps->seg == now_seg)
316 + lps = (struct litpool_seg *)xcalloc (sizeof (struct litpool_seg), 1);
317 + lps->next = litpool_seg_list.next;
318 + litpool_seg_list.next = lps;
319 + lps->seg = now_seg;
320 + lps->frag_list.next = &lps->frag_list;
321 + lps->frag_list.prev = &lps->frag_list;
328 + if (only_if_needed)
330 + if (past_xtensa_end || !use_transform() ||
331 + frag_now->tc_frag_data.is_no_transform)
335 + if (auto_litpool_limit <= 0)
337 + /* Don't create a litpool based only on frag count. */
340 + else if (lps->frag_count > auto_litpool_limit)
357 + int size = (only_if_needed) ? 3 : 0; /* Space for a "j" insn. */
358 + /* Create a potential site for a literal pool. */
359 + frag_wane (frag_now);
361 + xtensa_set_frag_assembly_state (frag_now);
363 + fragP->tc_frag_data.lit_frchain = frchain_now;
364 + fragP->tc_frag_data.literal_frag = fragP;
365 + frag_var (rs_machine_dependent, size, size,
367 + RELAX_LITERAL_POOL_CANDIDATE_BEGIN :
368 + RELAX_LITERAL_POOL_BEGIN,
370 + frag_now->tc_frag_data.lit_seg = now_seg;
371 + frag_variant (rs_machine_dependent, 0, 0,
372 + RELAX_LITERAL_POOL_END, NULL, 0, NULL);
373 + xtensa_set_frag_assembly_state (frag_now);
377 + /* RELAX_LITERAL_POOL_BEGIN frag is being created;
378 + just record it here. */
382 + lpf = (struct litpool_frag *)xmalloc(sizeof (struct litpool_frag));
383 + /* Insert at tail of circular list. */
385 + lps->frag_list.prev->next = lpf;
386 + lpf->next = &lps->frag_list;
387 + lpf->prev = lps->frag_list.prev;
388 + lps->frag_list.prev = lpf;
389 + lpf->fragP = fragP;
390 + lpf->priority = (needed) ? (only_if_needed) ? 3 : 2 : 1;
391 + lpf->original_priority = lpf->priority;
393 + lps->frag_count = 0;
397 xtensa_cleanup_align_frags (void)
399 @@ -9029,7 +9266,41 @@ xtensa_relax_frag (fragS *fragP, long stretch, int *stretched_p)
402 case RELAX_LITERAL_POOL_BEGIN:
403 + if (fragP->fr_var != 0)
405 + /* We have a converted "candidate" literal pool;
406 + assemble a jump around it. */
408 + if (!litpool_slotbuf)
410 + litpool_buf = xtensa_insnbuf_alloc (isa);
411 + litpool_slotbuf = xtensa_insnbuf_alloc (isa);
414 + fragP->tc_frag_data.relax_seen = FALSE; /* Need another pass. */
415 + fragP->tc_frag_data.is_insn = TRUE;
416 + tinsn_init (&insn);
417 + insn.insn_type = ITYPE_INSN;
418 + insn.opcode = xtensa_j_opcode;
420 + set_expr_symbol_offset (&insn.tok[0], fragP->fr_symbol,
422 + fmt = xg_get_single_format (xtensa_j_opcode);
423 + tinsn_to_slotbuf (fmt, 0, &insn, litpool_slotbuf);
424 + xtensa_format_set_slot (isa, fmt, 0, litpool_buf, litpool_slotbuf);
425 + xtensa_insnbuf_to_chars (isa, litpool_buf,
426 + (unsigned char *)fragP->fr_literal +
428 + fragP->fr_fix += 3;
429 + fragP->fr_var -= 3;
430 + /* Add a fix-up. */
431 + fix_new (fragP, 0, 3, fragP->fr_symbol, 0, TRUE,
432 + BFD_RELOC_XTENSA_SLOT0_OP);
436 case RELAX_LITERAL_POOL_END:
437 + case RELAX_LITERAL_POOL_CANDIDATE_BEGIN:
438 case RELAX_MAYBE_UNREACHABLE:
439 case RELAX_MAYBE_DESIRE_ALIGN:
440 /* No relaxation required. */
441 @@ -10789,12 +11060,115 @@ xtensa_move_literals (void)
443 fixS *fix, *next_fix, **fix_splice;
445 + struct litpool_seg *lps;
447 mark_literal_frags (literal_head->next);
449 if (use_literal_section)
452 + /* Assign addresses (rough estimates) to the potential literal pool locations
453 + and create new ones if the gaps are too large. */
455 + for (lps = litpool_seg_list.next; lps; lps = lps->next)
457 + frchainS *frchP = seg_info (lps->seg)->frchainP;
458 + struct litpool_frag *lpf = lps->frag_list.next;
461 + for ( ; frchP; frchP = frchP->frch_next)
464 + for (fragP = frchP->frch_root; fragP; fragP = fragP->fr_next)
466 + if (lpf && fragP == lpf->fragP)
468 + gas_assert(fragP->fr_type == rs_machine_dependent &&
469 + (fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN ||
470 + fragP->fr_subtype == RELAX_LITERAL_POOL_CANDIDATE_BEGIN));
471 + /* Found a litpool location. */
475 + if (fragP->fr_type == rs_machine_dependent &&
476 + fragP->fr_subtype == RELAX_SLOTS)
479 + for (slot = 0; slot < MAX_SLOTS; slot++)
481 + if (fragP->tc_frag_data.literal_frags[slot])
483 + /* L32R; point its literal to the nearest litpool
484 + preferring non-"candidate" positions to avoid
485 + the jump-around. */
486 + fragS *litfrag = fragP->tc_frag_data.literal_frags[slot];
487 + struct litpool_frag *lp = lpf->prev;
492 + while (lp->fragP->fr_subtype ==
493 + RELAX_LITERAL_POOL_CANDIDATE_BEGIN)
496 + if (lp->fragP == NULL)
498 + /* End of list; have to bite the bullet.
499 + Take the nearest. */
503 + /* Does it (conservatively) reach? */
504 + if (addr - lp->addr <= 128 * 1024)
506 + if (lp->fragP->fr_subtype == RELAX_LITERAL_POOL_BEGIN)
508 + /* Found a good one. */
511 + else if (lp->prev->fragP &&
512 + addr - lp->prev->addr > 128 * 1024)
514 + /* This is still a "candidate" but the next one
515 + will be too far away, so revert to the nearest
516 + one, convert it and add the jump around. */
520 + char label[10 + 2 * sizeof (fragS *)];
522 + poolbeg = lp->fragP;
524 + poolbeg->fr_subtype = RELAX_LITERAL_POOL_BEGIN;
525 + poolend = poolbeg->fr_next;
526 + gas_assert (poolend->fr_type == rs_machine_dependent &&
527 + poolend->fr_subtype == RELAX_LITERAL_POOL_END);
528 + /* Create a local symbol pointing to the
529 + end of the pool. */
530 + sprintf (label, ".L0_LT_%p", poolbeg);
531 + lsym = (symbolS *)local_symbol_make (label, lps->seg,
533 + poolbeg->fr_symbol = lsym;
534 + /* Rest is done in xtensa_relax_frag. */
538 + if (! litfrag->tc_frag_data.literal_frag)
540 + /* Take earliest use of this literal to avoid
542 + litfrag->tc_frag_data.literal_frag = lp->fragP;
547 + addr += fragP->fr_fix;
548 + if (fragP->fr_type == rs_fill)
549 + addr += fragP->fr_offset;
554 for (segment = literal_head->next; segment; segment = segment->next)
556 /* Keep the literals for .init and .fini in separate sections. */
557 @@ -10839,9 +11213,6 @@ xtensa_move_literals (void)
558 while (search_frag != frag_now)
560 next_frag = search_frag->fr_next;
562 - /* First, move the frag out of the literal section and
563 - to the appropriate place. */
564 if (search_frag->tc_frag_data.literal_frag)
566 literal_pool = search_frag->tc_frag_data.literal_frag;
567 @@ -10849,8 +11220,56 @@ xtensa_move_literals (void)
568 frchain_to = literal_pool->tc_frag_data.lit_frchain;
569 gas_assert (frchain_to);
572 + if (search_frag->fr_type == rs_fill && search_frag->fr_fix == 0)
574 + /* Skip empty fill frags. */
575 + *frag_splice = next_frag;
576 + search_frag = next_frag;
580 + if (search_frag->fr_type == rs_align)
582 + /* Skip alignment frags, because the pool as a whole will be
583 + aligned if used, and we don't want to force alignment if the
585 + *frag_splice = next_frag;
586 + search_frag = next_frag;
590 + /* First, move the frag out of the literal section and
591 + to the appropriate place. */
593 + /* Insert an aligmnent frag at start of pool. */
594 + if (literal_pool->fr_next->fr_type == rs_machine_dependent &&
595 + literal_pool->fr_next->fr_subtype == RELAX_LITERAL_POOL_END)
597 + segT pool_seg = literal_pool->fr_next->tc_frag_data.lit_seg;
598 + emit_state prev_state;
601 + xtensa_switch_section_emit_state (&prev_state, pool_seg, 0);
602 + prev_frag = frag_now;
603 + frag_variant (rs_fill, 0, 0, 0, NULL, 0, NULL);
604 + align_frag = frag_now;
605 + frag_align (2, 0, 0);
606 + /* Splice it into the right place. */
607 + prev_frag->fr_next = align_frag->fr_next;
608 + align_frag->fr_next = literal_pool->fr_next;
609 + literal_pool->fr_next = align_frag;
610 + /* Insert after this one. */
611 + literal_pool->tc_frag_data.literal_frag = align_frag;
612 + xtensa_restore_emit_state (&prev_state);
614 insert_after = literal_pool->tc_frag_data.literal_frag;
615 dest_seg = insert_after->fr_next->tc_frag_data.lit_seg;
616 + /* Skip align frag. */
617 + if (insert_after->fr_next->fr_type == rs_align)
619 + insert_after = insert_after->fr_next;
622 *frag_splice = next_frag;
623 search_frag->fr_next = insert_after->fr_next;
624 @@ -11014,7 +11433,10 @@ xtensa_switch_to_non_abs_literal_fragment (emit_state *result)
626 && !is_init && ! is_fini)
628 - as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
629 + if (!auto_litpools)
631 + as_bad (_("literal pool location required for text-section-literals; specify with .literal_position"));
634 /* When we mark a literal pool location, we want to put a frag in
635 the literal pool that points to it. But to do that, we want to
636 diff --git a/gas/config/tc-xtensa.h b/gas/config/tc-xtensa.h
637 index b2e43fa..290d902 100644
638 --- a/gas/config/tc-xtensa.h
639 +++ b/gas/config/tc-xtensa.h
640 @@ -124,6 +124,7 @@ enum xtensa_relax_statesE
642 RELAX_LITERAL_POOL_BEGIN,
643 RELAX_LITERAL_POOL_END,
644 + RELAX_LITERAL_POOL_CANDIDATE_BEGIN,
645 /* Technically these are not relaxations at all but mark a location
646 to store literals later. Note that fr_var stores the frchain for
647 BEGIN frags and fr_var stores now_seg for END frags. */
648 diff --git a/gas/testsuite/gas/xtensa/all.exp b/gas/testsuite/gas/xtensa/all.exp
649 index d197ec8..db39629 100644
650 --- a/gas/testsuite/gas/xtensa/all.exp
651 +++ b/gas/testsuite/gas/xtensa/all.exp
652 @@ -100,6 +100,7 @@ if [istarget xtensa*-*-*] then {
653 run_dump_test "jlong"
654 run_dump_test "trampoline"
655 run_dump_test "first_frag_align"
656 + run_dump_test "auto-litpools"
659 if [info exists errorInfo] then {
660 diff --git a/gas/testsuite/gas/xtensa/auto-litpools.d b/gas/testsuite/gas/xtensa/auto-litpools.d
662 index 0000000..4d1a690
664 +++ b/gas/testsuite/gas/xtensa/auto-litpools.d
666 +#as: --auto-litpools
668 +#name: auto literal pool placement
670 +.*: +file format .*xtensa.*
674 +.*3e437:.*j.3e440 .*
676 +.*40750:.*l32r.a2, 3e43c .*
678 diff --git a/gas/testsuite/gas/xtensa/auto-litpools.s b/gas/testsuite/gas/xtensa/auto-litpools.s
680 index 0000000..9a5b26b
682 +++ b/gas/testsuite/gas/xtensa/auto-litpools.s
686 + .literal .L0, 0x12345
687 + .literal .L1, 0x12345