8a211004f396a41ae6fbf3cee5b3f49b4481d686
[packages/trusty/cirros-testvm.git] / cirros-testvm / src-cirros / buildroot-2015.05 / package / binutils / 2.25 / 906-xtensa-optimize-check_section_ebb_pcrels_fit.patch
1 From 20c79baf82273a0b368587f761f152c4d3a593a4 Mon Sep 17 00:00:00 2001
2 From: Max Filippov <jcmvbkbc@gmail.com>
3 Date: Fri, 27 Mar 2015 07:13:55 +0300
4 Subject: [PATCH 1/4] xtensa: optimize check_section_ebb_pcrels_fit
5
6 The original check_section_ebb_pcrels_fit algorithm checks that text
7 actions proposed for current EBB are OK for every relocation in a
8 section. There's no need to check every relocation, because text actions
9 for EBB can only change size of that EBB, thus only affecting
10 relocations that in any way cross that EBB. In addition EBBs are
11 iterated in ascending order of their VMA, making it easier to track
12 relevant relocations.
13
14 Introduce a structure that can track relocations that cross the range of
15 VMAs of EBB and use it to only check relocations relevant to current EBB
16 in check_section_ebb_pcrels_fit.
17 It takes O(N log N) operations to build it and O(N) operations to move
18 current EBB VMA window through its entire range, where N is the number
19 of relocations in a section. The resulting complexity of
20 compute_text_actions is thus reduced from O(N^2) to O(N log N + N * M),
21 where M is the average number of relocations crossing each EBB.
22
23 Original profile:
24
25 % time    self  children    called     name
26 -----------------------------------------
27          44.26   71.53    6429/6429        compute_text_actions
28   50.2   44.26   71.53    6429         check_section_ebb_pcrels_fit
29           1.16   20.12 347506666/347576152     pcrel_reloc_fits
30           2.95   16.52 347506666/348104944     get_relocation_opnd
31           2.01    9.74 347575100/361252208     r_reloc_init
32           0.55    7.53 347575100/363381467     r_reloc_get_section
33           5.76    0.02 695013332/695013332     xlate_offset_with_removed_text
34           0.68    3.89 347575100/363483827     bfd_octets_per_byte
35           0.32    0.00 347506666/349910253     is_alt_relocation
36           0.18    0.11    6391/6391        build_xlate_map
37           0.00    0.00    6429/19417168     get_xtensa_relax_info
38           0.00    0.00    6391/6391        free_xlate_map
39 -----------------------------------------
40
41 Same data, after optimization:
42
43 % time    self  children    called     name
44 -----------------------------------------
45           2.56    3.08    6429/6429        compute_text_actions
46    8.2    2.56    3.08    6429         check_section_ebb_pcrels_fit
47           0.08    0.91 17721075/17790561     pcrel_reloc_fits
48           0.17    0.47 17721075/31685977     r_reloc_init
49           0.43    0.00 35442150/35442150     xlate_offset_with_removed_text
50           0.02    0.37 17721075/33815236     r_reloc_get_section
51           0.22    0.11    6391/6391        build_xlate_map
52           0.05    0.22 17721075/33917596     bfd_octets_per_byte
53           0.03    0.00 17721075/20405299     is_alt_relocation
54           0.01    0.00    6429/6429        reloc_range_list_update_range
55           0.00    0.00    6429/19417168     get_xtensa_relax_info
56           0.00    0.00    6391/6391        free_xlate_map
57 -----------------------------------------
58
59 2015-04-01  Max Filippov  <jcmvbkbc@gmail.com>
60 bfd/
61         * elf32-xtensa.c (reloc_range_list, reloc_range_list_entry,
62         reloc_range): new typedef.
63         (reloc_range_list_struct, reloc_range_list_entry_struct,
64         reloc_range_struct): new structures.
65         (reloc_range_compare, build_reloc_ranges,
66         reloc_range_list_append, reloc_range_list_remove,
67         reloc_range_list_update_range, free_reloc_range_list): new
68         functions.
69         (compute_text_actions): precompute relocation opcodes before the
70         loop. Add relevant_relocs variable, initialize it before the
71         loop, pass it to the check_section_ebb_pcrels_fit.
72         (check_section_ebb_pcrels_fit): add new parameter:
73         relevant_relocs. Update address range in the relevant_relocs if
74         it's non-NULL and iterate only over relevant relocations.
75
76 Backported from: b2b326d246f839ee218192ac88da2384d929a072
77 Signed-off-by: Max Filippov <jcmvbkbc@gmail.com>
78 ---
79  bfd/elf32-xtensa.c | 321 +++++++++++++++++++++++++++++++++++++++++++++++++----
80  1 file changed, 298 insertions(+), 23 deletions(-)
81
82 diff --git a/bfd/elf32-xtensa.c b/bfd/elf32-xtensa.c
83 index 0b6f584..872370b 100644
84 --- a/bfd/elf32-xtensa.c
85 +++ b/bfd/elf32-xtensa.c
86 @@ -6619,8 +6619,10 @@ static bfd_boolean compute_text_actions
87    (bfd *, asection *, struct bfd_link_info *);
88  static bfd_boolean compute_ebb_proposed_actions (ebb_constraint *);
89  static bfd_boolean compute_ebb_actions (ebb_constraint *);
90 +typedef struct reloc_range_list_struct reloc_range_list;
91  static bfd_boolean check_section_ebb_pcrels_fit
92 -  (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *, const ebb_constraint *,
93 +  (bfd *, asection *, bfd_byte *, Elf_Internal_Rela *,
94 +   reloc_range_list *, const ebb_constraint *,
95     const xtensa_opcode *);
96  static bfd_boolean check_section_ebb_reduces (const ebb_constraint *);
97  static void text_action_add_proposed
98 @@ -7219,6 +7221,221 @@ build_reloc_opcodes (bfd *abfd,
99    return reloc_opcodes;
100  }
101  
102 +struct reloc_range_struct
103 +{
104 +  bfd_vma addr;
105 +  bfd_boolean add; /* TRUE if start of a range, FALSE otherwise.  */
106 +  /* Original irel index in the array of relocations for a section.  */
107 +  unsigned irel_index;
108 +};
109 +typedef struct reloc_range_struct reloc_range;
110 +
111 +typedef struct reloc_range_list_entry_struct reloc_range_list_entry;
112 +struct reloc_range_list_entry_struct
113 +{
114 +  reloc_range_list_entry *next;
115 +  reloc_range_list_entry *prev;
116 +  Elf_Internal_Rela *irel;
117 +  xtensa_opcode opcode;
118 +  int opnum;
119 +};
120 +
121 +struct reloc_range_list_struct
122 +{
123 +  /* The rest of the structure is only meaningful when ok is TRUE.  */
124 +  bfd_boolean ok;
125 +
126 +  unsigned n_range; /* Number of range markers.  */
127 +  reloc_range *range; /* Sorted range markers.  */
128 +
129 +  unsigned first; /* Index of a first range element in the list.  */
130 +  unsigned last; /* One past index of a last range element in the list.  */
131 +
132 +  unsigned n_list; /* Number of list elements.  */
133 +  reloc_range_list_entry *reloc; /*  */
134 +  reloc_range_list_entry list_root;
135 +};
136 +
137 +static int
138 +reloc_range_compare (const void *a, const void *b)
139 +{
140 +  const reloc_range *ra = a;
141 +  const reloc_range *rb = b;
142 +
143 +  if (ra->addr != rb->addr)
144 +    return ra->addr < rb->addr ? -1 : 1;
145 +  if (ra->add != rb->add)
146 +    return ra->add ? -1 : 1;
147 +  return 0;
148 +}
149 +
150 +static void
151 +build_reloc_ranges (bfd *abfd, asection *sec,
152 +                   bfd_byte *contents,
153 +                   Elf_Internal_Rela *internal_relocs,
154 +                   xtensa_opcode *reloc_opcodes,
155 +                   reloc_range_list *list)
156 +{
157 +  unsigned i;
158 +  size_t n = 0;
159 +  size_t max_n = 0;
160 +  reloc_range *ranges = NULL;
161 +  reloc_range_list_entry *reloc =
162 +    bfd_malloc (sec->reloc_count * sizeof (*reloc));
163 +
164 +  memset (list, 0, sizeof (*list));
165 +  list->ok = TRUE;
166 +
167 +  for (i = 0; i < sec->reloc_count; i++)
168 +    {
169 +      Elf_Internal_Rela *irel = &internal_relocs[i];
170 +      int r_type = ELF32_R_TYPE (irel->r_info);
171 +      reloc_howto_type *howto = &elf_howto_table[r_type];
172 +      r_reloc r_rel;
173 +
174 +      if (r_type == R_XTENSA_ASM_SIMPLIFY
175 +         || r_type == R_XTENSA_32_PCREL
176 +         || !howto->pc_relative)
177 +       continue;
178 +
179 +      r_reloc_init (&r_rel, abfd, irel, contents,
180 +                   bfd_get_section_limit (abfd, sec));
181 +
182 +      if (r_reloc_get_section (&r_rel) != sec)
183 +       continue;
184 +
185 +      if (n + 2 > max_n)
186 +       {
187 +         max_n = (max_n + 2) * 2;
188 +         ranges = bfd_realloc (ranges, max_n * sizeof (*ranges));
189 +       }
190 +
191 +      ranges[n].addr = irel->r_offset;
192 +      ranges[n + 1].addr = r_rel.target_offset;
193 +
194 +      ranges[n].add = ranges[n].addr < ranges[n + 1].addr;
195 +      ranges[n + 1].add = !ranges[n].add;
196 +
197 +      ranges[n].irel_index = i;
198 +      ranges[n + 1].irel_index = i;
199 +
200 +      n += 2;
201 +
202 +      reloc[i].irel = irel;
203 +
204 +      /* Every relocation won't possibly be checked in the optimized version of
205 +         check_section_ebb_pcrels_fit, so this needs to be done here.  */
206 +      if (is_alt_relocation (ELF32_R_TYPE (irel->r_info)))
207 +       {
208 +         /* None of the current alternate relocs are PC-relative,
209 +            and only PC-relative relocs matter here.  */
210 +       }
211 +      else
212 +       {
213 +         xtensa_opcode opcode;
214 +         int opnum;
215 +
216 +         if (reloc_opcodes)
217 +           opcode = reloc_opcodes[i];
218 +         else
219 +           opcode = get_relocation_opcode (abfd, sec, contents, irel);
220 +
221 +         if (opcode == XTENSA_UNDEFINED)
222 +           {
223 +             list->ok = FALSE;
224 +             break;
225 +           }
226 +
227 +         opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info));
228 +         if (opnum == XTENSA_UNDEFINED)
229 +           {
230 +             list->ok = FALSE;
231 +             break;
232 +           }
233 +
234 +         /* Record relocation opcode and opnum as we've calculated them
235 +            anyway and they won't change.  */
236 +         reloc[i].opcode = opcode;
237 +         reloc[i].opnum = opnum;
238 +       }
239 +    }
240 +
241 +  if (list->ok)
242 +    {
243 +      ranges = bfd_realloc (ranges, n * sizeof (*ranges));
244 +      qsort (ranges, n, sizeof (*ranges), reloc_range_compare);
245 +
246 +      list->n_range = n;
247 +      list->range = ranges;
248 +      list->reloc = reloc;
249 +      list->list_root.prev = &list->list_root;
250 +      list->list_root.next = &list->list_root;
251 +    }
252 +  else
253 +    {
254 +      free (ranges);
255 +      free (reloc);
256 +    }
257 +}
258 +
259 +static void reloc_range_list_append (reloc_range_list *list,
260 +                                    unsigned irel_index)
261 +{
262 +  reloc_range_list_entry *entry = list->reloc + irel_index;
263 +
264 +  entry->prev = list->list_root.prev;
265 +  entry->next = &list->list_root;
266 +  entry->prev->next = entry;
267 +  entry->next->prev = entry;
268 +  ++list->n_list;
269 +}
270 +
271 +static void reloc_range_list_remove (reloc_range_list *list,
272 +                                    unsigned irel_index)
273 +{
274 +  reloc_range_list_entry *entry = list->reloc + irel_index;
275 +
276 +  entry->next->prev = entry->prev;
277 +  entry->prev->next = entry->next;
278 +  --list->n_list;
279 +}
280 +
281 +/* Update relocation list object so that it lists all relocations that cross
282 +   [first; last] range.  Range bounds should not decrease with successive
283 +   invocations.  */
284 +static void reloc_range_list_update_range (reloc_range_list *list,
285 +                                          bfd_vma first, bfd_vma last)
286 +{
287 +  /* This should not happen: EBBs are iterated from lower addresses to higher.
288 +     But even if that happens there's no need to break: just flush current list
289 +     and start from scratch.  */
290 +  if ((list->last > 0 && list->range[list->last - 1].addr > last) ||
291 +      (list->first > 0 && list->range[list->first - 1].addr >= first))
292 +    {
293 +      list->first = 0;
294 +      list->last = 0;
295 +      list->n_list = 0;
296 +      list->list_root.next = &list->list_root;
297 +      list->list_root.prev = &list->list_root;
298 +      fprintf (stderr, "%s: move backwards requested\n", __func__);
299 +    }
300 +
301 +  for (; list->last < list->n_range &&
302 +       list->range[list->last].addr <= last; ++list->last)
303 +    if (list->range[list->last].add)
304 +      reloc_range_list_append (list, list->range[list->last].irel_index);
305 +
306 +  for (; list->first < list->n_range &&
307 +       list->range[list->first].addr < first; ++list->first)
308 +    if (!list->range[list->first].add)
309 +      reloc_range_list_remove (list, list->range[list->first].irel_index);
310 +}
311 +
312 +static void free_reloc_range_list (reloc_range_list *list)
313 +{
314 +  free (list->range);
315 +  free (list->reloc);
316 +}
317  
318  /* The compute_text_actions function will build a list of potential
319     transformation actions for code in the extended basic block of each
320 @@ -7245,6 +7462,7 @@ compute_text_actions (bfd *abfd,
321    property_table_entry *prop_table = 0;
322    int ptblsize = 0;
323    bfd_size_type sec_size;
324 +  reloc_range_list relevant_relocs;
325  
326    relax_info = get_xtensa_relax_info (sec);
327    BFD_ASSERT (relax_info);
328 @@ -7277,6 +7495,12 @@ compute_text_actions (bfd *abfd,
329        goto error_return;
330      }
331  
332 +  /* Precompute the opcode for each relocation.  */
333 +  reloc_opcodes = build_reloc_opcodes (abfd, sec, contents, internal_relocs);
334 +
335 +  build_reloc_ranges (abfd, sec, contents, internal_relocs, reloc_opcodes,
336 +                     &relevant_relocs);
337 +
338    for (i = 0; i < sec->reloc_count; i++)
339      {
340        Elf_Internal_Rela *irel = &internal_relocs[i];
341 @@ -7340,17 +7564,13 @@ compute_text_actions (bfd *abfd,
342        ebb->start_reloc_idx = i;
343        ebb->end_reloc_idx = i;
344  
345 -      /* Precompute the opcode for each relocation.  */
346 -      if (reloc_opcodes == NULL)
347 -       reloc_opcodes = build_reloc_opcodes (abfd, sec, contents,
348 -                                            internal_relocs);
349 -
350        if (!extend_ebb_bounds (ebb)
351           || !compute_ebb_proposed_actions (&ebb_table)
352           || !compute_ebb_actions (&ebb_table)
353           || !check_section_ebb_pcrels_fit (abfd, sec, contents,
354 -                                           internal_relocs, &ebb_table,
355 -                                           reloc_opcodes)
356 +                                           internal_relocs,
357 +                                           &relevant_relocs,
358 +                                           &ebb_table, reloc_opcodes)
359           || !check_section_ebb_reduces (&ebb_table))
360         {
361           /* If anything goes wrong or we get unlucky and something does
362 @@ -7372,6 +7592,8 @@ compute_text_actions (bfd *abfd,
363        free_ebb_constraint (&ebb_table);
364      }
365  
366 +  free_reloc_range_list (&relevant_relocs);
367 +
368  #if DEBUG
369    if (relax_info->action_list.head)
370      print_action_list (stderr, &relax_info->action_list);
371 @@ -7974,14 +8196,17 @@ check_section_ebb_pcrels_fit (bfd *abfd,
372                               asection *sec,
373                               bfd_byte *contents,
374                               Elf_Internal_Rela *internal_relocs,
375 +                             reloc_range_list *relevant_relocs,
376                               const ebb_constraint *constraint,
377                               const xtensa_opcode *reloc_opcodes)
378  {
379    unsigned i, j;
380 +  unsigned n = sec->reloc_count;
381    Elf_Internal_Rela *irel;
382    xlate_map_t *xmap = NULL;
383    bfd_boolean ok = TRUE;
384    xtensa_relax_info *relax_info;
385 +  reloc_range_list_entry *entry = NULL;
386  
387    relax_info = get_xtensa_relax_info (sec);
388  
389 @@ -7992,7 +8217,40 @@ check_section_ebb_pcrels_fit (bfd *abfd,
390          can still be used.  */
391      }
392  
393 -  for (i = 0; i < sec->reloc_count; i++)
394 +  if (relevant_relocs && constraint->action_count)
395 +    {
396 +      if (!relevant_relocs->ok)
397 +       {
398 +         ok = FALSE;
399 +         n = 0;
400 +       }
401 +      else
402 +       {
403 +         bfd_vma min_offset, max_offset;
404 +         min_offset = max_offset = constraint->actions[0].offset;
405 +
406 +         for (i = 1; i < constraint->action_count; ++i)
407 +           {
408 +             proposed_action *action = &constraint->actions[i];
409 +             bfd_vma offset = action->offset;
410 +
411 +             if (offset < min_offset)
412 +               min_offset = offset;
413 +             if (offset > max_offset)
414 +               max_offset = offset;
415 +           }
416 +         reloc_range_list_update_range (relevant_relocs, min_offset,
417 +                                        max_offset);
418 +         n = relevant_relocs->n_list;
419 +         entry = &relevant_relocs->list_root;
420 +       }
421 +    }
422 +  else
423 +    {
424 +      relevant_relocs = NULL;
425 +    }
426 +
427 +  for (i = 0; i < n; i++)
428      {
429        r_reloc r_rel;
430        bfd_vma orig_self_offset, orig_target_offset;
431 @@ -8001,7 +8259,15 @@ check_section_ebb_pcrels_fit (bfd *abfd,
432        reloc_howto_type *howto;
433        int self_removed_bytes, target_removed_bytes;
434  
435 -      irel = &internal_relocs[i];
436 +      if (relevant_relocs)
437 +       {
438 +         entry = entry->next;
439 +         irel = entry->irel;
440 +       }
441 +      else
442 +       {
443 +         irel = internal_relocs + i;
444 +       }
445        r_type = ELF32_R_TYPE (irel->r_info);
446  
447        howto = &elf_howto_table[r_type];
448 @@ -8067,21 +8333,30 @@ check_section_ebb_pcrels_fit (bfd *abfd,
449           xtensa_opcode opcode;
450           int opnum;
451  
452 -         if (reloc_opcodes)
453 -           opcode = reloc_opcodes[i];
454 -         else
455 -           opcode = get_relocation_opcode (abfd, sec, contents, irel);
456 -         if (opcode == XTENSA_UNDEFINED)
457 +         if (relevant_relocs)
458             {
459 -             ok = FALSE;
460 -             break;
461 +             opcode = entry->opcode;
462 +             opnum = entry->opnum;
463             }
464 -
465 -         opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info));
466 -         if (opnum == XTENSA_UNDEFINED)
467 +         else
468             {
469 -             ok = FALSE;
470 -             break;
471 +             if (reloc_opcodes)
472 +               opcode = reloc_opcodes[relevant_relocs ?
473 +                 (unsigned)(entry - relevant_relocs->reloc) : i];
474 +             else
475 +               opcode = get_relocation_opcode (abfd, sec, contents, irel);
476 +             if (opcode == XTENSA_UNDEFINED)
477 +               {
478 +                 ok = FALSE;
479 +                 break;
480 +               }
481 +
482 +             opnum = get_relocation_opnd (opcode, ELF32_R_TYPE (irel->r_info));
483 +             if (opnum == XTENSA_UNDEFINED)
484 +               {
485 +                 ok = FALSE;
486 +                 break;
487 +               }
488             }
489  
490           if (!pcrel_reloc_fits (opcode, opnum, self_offset, target_offset))
491 @@ -8778,7 +9053,7 @@ move_shared_literal (asection *sec,
492    /* Check all of the PC-relative relocations to make sure they still fit.  */
493    relocs_fit = check_section_ebb_pcrels_fit (target_sec->owner, target_sec,
494                                              target_sec_cache->contents,
495 -                                            target_sec_cache->relocs,
496 +                                            target_sec_cache->relocs, NULL,
497                                              &ebb_table, NULL);
498  
499    if (!relocs_fit)
500 -- 
501 1.8.1.4
502