This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH 2/2] xtensa: add --auto-litpools option


On Tue, Aug 11, 2015 at 5:54 PM, Max Filippov <jcmvbkbc@gmail.com> wrote:
> 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-11  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.
>         * doc/as.texinfo (Xtensa options):  Document --auto-litpools and
>         --no-auto-litpools options.
>         * doc/c-xtensa.texi (Xtensa options): Likewise.

This is a terrific change and a long time in coming. Approved after
you fix the very minor formatting issue below.

> +struct litpool_frag {

gnu-style requires the brace on a separate line. This happens in a
couple of spots. Fix those and you are set to go.

> +  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.  */
>
> @@ -475,6 +496,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.  */
>
> @@ -700,6 +724,10 @@ enum
>    option_trampolines,
>    option_no_trampolines,
>    option_trampoline_limit,
> +
> +  option_auto_litpools,
> +  option_no_auto_litpools,
> +  option_auto_litpool_limit,
>  };
>
>  const char *md_shortopts = "";
> @@ -776,6 +804,10 @@ struct option md_longopts[] =
>    { "no-trampolines", no_argument, NULL, option_no_trampolines },
>    { "tramp-limit", required_argument, NULL, option_trampoline_limit },
>
> +  { "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 }
>  };
>
> @@ -979,6 +1011,34 @@ md_parse_option (int c, char *arg)
>         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;
>      }
> @@ -1007,7 +1067,12 @@ Xtensa options:\n\
>                            when jumps do not reach their targets\n\
>    --tramp-limit=<value>   (default 8000, range 100-10000) Maximum number of\n\
>                            blocks of instructions to emit between trampoline\n\
> -                          locations; implies --trampolines flag\n", stream);
> +                          locations; implies --trampolines flag\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);
>  }
>
>
> @@ -4749,6 +4814,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);
> @@ -4853,6 +4920,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;
>  }
>
> @@ -7119,6 +7211,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;
> @@ -7191,6 +7288,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 ())
>         {
> @@ -7333,11 +7432,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
> @@ -7429,6 +7535,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)
>  {
> @@ -9048,7 +9283,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.  */
> @@ -10808,12 +11077,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.  */
> @@ -10858,9 +11230,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;
> @@ -10868,8 +11237,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;
> @@ -11033,7 +11450,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 c6c7699..6c0d131 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/doc/as.texinfo b/gas/doc/as.texinfo
> index 5710e1c..0b27c54 100644
> --- a/gas/doc/as.texinfo
> +++ b/gas/doc/as.texinfo
> @@ -552,7 +552,8 @@ gcc(1), ld(1), and the Info entries for @file{binutils} and @file{ld}.
>  @ifset XTENSA
>
>  @emph{Target Xtensa options:}
> - [@b{--[no-]text-section-literals}] [@b{--[no-]absolute-literals}]
> + [@b{--[no-]text-section-literals}] [@b{--[no-]auto-litpools}]
> + [@b{--[no-]absolute-literals}]
>   [@b{--[no-]target-align}] [@b{--[no-]longcalls}]
>   [@b{--[no-]transform}]
>   [@b{--rename-section} @var{oldname}=@var{newname}]
> diff --git a/gas/doc/c-xtensa.texi b/gas/doc/c-xtensa.texi
> index 7019f84..26155c4 100644
> --- a/gas/doc/c-xtensa.texi
> +++ b/gas/doc/c-xtensa.texi
> @@ -43,9 +43,30 @@ placed in a data RAM/ROM.  With @samp{--text-@-section-@-literals}, the
>  literals are interspersed in the text section in order to keep them as
>  close as possible to their references.  This may be necessary for large
>  assembly files, where the literals would otherwise be out of range of the
> -@code{L32R} instructions in the text section.  These options only affect
> +@code{L32R} instructions in the text section.  Literals are grouped into
> +pools following @code{.literal_position} directives or preceding
> +@code{ENTRY} instructions.  These options only affect literals referenced
> +via PC-relative @code{L32R} instructions; literals for absolute mode
> +@code{L32R} instructions are handled separately.
> +@xref{Literal Directive, ,literal}.
> +
> +@item --auto-litpools | --no-auto-litpools
> +@kindex --auto-litpools
> +@kindex --no-auto-litpools
> +Control the treatment of literal pools.  The default is
> +@samp{--no-@-auto-@-litpools}, which in the absence of
> +@samp{--text-@-section-@-literals} places literals in separate sections
> +in the output file.  This allows the literal pool to be placed in a data
> +RAM/ROM.  With @samp{--auto-@-litpools}, the literals are interspersed
> +in the text section in order to keep them as close as possible to their
> +references, explicit @code{.literal_position} directives are not
> +required.  This may be necessary for very large functions, where single
> +literal pool at the beginning of the function may not be reachable by
> +@code{L32R} instructions at the end.  These options only affect
>  literals referenced via PC-relative @code{L32R} instructions; literals
>  for absolute mode @code{L32R} instructions are handled separately.
> +When used together with @samp{--text-@-section-@-literals},
> +@samp{--auto-@-litpools} takes precedence.
>  @xref{Literal Directive, ,literal}.
>
>  @item --absolute-literals | --no-absolute-literals
> 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
>


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]