1 /* GNU PIC coff optimizing functions
2    Copyright (C) 2005
3    Craig Franklin
4 
5    Copyright (C) 2015-2016 Molnar Karoly
6 
7 This file is part of gputils.
8 
9 gputils is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2, or (at your option)
12 any later version.
13 
14 gputils is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with gputils; see the file COPYING.  If not, write to
21 the Free Software Foundation, 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA.  */
23 
24 #include "stdhdr.h"
25 #include "libgputils.h"
26 
27 #define COPT_NULL                           0
28 #define COPT_BRA14E_CURR_PAGE               (1 << 0)
29 #define COPT_BRA14E_OTHER_PAGE              (1 << 1)
30 #define COPT_GOTO_CURR_PAGE                 (1 << 2)
31 #define COPT_GOTO_OTHER_PAGE                (1 << 3)
32 #define COPT_CALL_CURR_PAGE                 (1 << 4)
33 #define COPT_CALL_OTHER_PAGE                (1 << 5)
34 #define COPT_PAGESEL_CURR_PAGE              (1 << 6)
35 #define COPT_PAGESEL_OTHER_PAGE             (1 << 7)
36 
37 #define COPT_BANKSEL                        (1 << 8)
38 
39 /* Only PIC14E and PIC14EX. */
40 #define COPT_BRA14E_MASK                    (COPT_BRA14E_CURR_PAGE | COPT_BRA14E_OTHER_PAGE)
41 
42 #define COPT_GOTO_MASK                      (COPT_GOTO_CURR_PAGE | COPT_GOTO_OTHER_PAGE)
43 
44 #define COPT_CALL_MASK                      (COPT_CALL_CURR_PAGE | COPT_CALL_OTHER_PAGE)
45 
46 /* Only PIC14E and PIC14EX. */
47 #define COPT_REL_BRANCH_CURR_PAGE_MASK      COPT_BRA14E_CURR_PAGE
48 #define COPT_REL_BRANCH_OTHER_PAGE_MASK     COPT_BRA14E_OTHER_PAGE
49 #define COPT_REL_BRANCH_MASK                COPT_BRA14E_MASK
50 
51 #define COPT_ABS_BRANCH_CURR_PAGE_MASK      (COPT_GOTO_CURR_PAGE | COPT_CALL_CURR_PAGE)
52 #define COPT_ABS_BRANCH_OTHER_PAGE_MASK     (COPT_GOTO_OTHER_PAGE | COPT_CALL_OTHER_PAGE)
53 #define COPT_ABS_BRANCH_MASK                (COPT_ABS_BRANCH_CURR_PAGE_MASK | COPT_ABS_BRANCH_OTHER_PAGE_MASK)
54 
55 #define COPT_BRANCH_CURR_PAGE_MASK          (COPT_REL_BRANCH_CURR_PAGE_MASK | COPT_ABS_BRANCH_CURR_PAGE_MASK)
56 #define COPT_BRANCH_OTHER_PAGE_MASK         (COPT_REL_BRANCH_OTHER_PAGE_MASK | COPT_ABS_BRANCH_OTHER_PAGE_MASK)
57 #define COPT_BRANCH_MASK                    (COPT_BRANCH_CURR_PAGE_MASK | COPT_BRANCH_OTHER_PAGE_MASK)
58 
59 #define COPT_PAGESEL_MASK                   (COPT_PAGESEL_CURR_PAGE | COPT_PAGESEL_OTHER_PAGE)
60 
61 /* Number of reloc_properties_t type in an array. */
62 #define RELOC_PIPE_LENGTH                   4
63 
64 typedef struct reloc_properties {
65   gp_reloc_t        *relocation;
66   const gp_symbol_t *label;             /* If exists so label which is linked here to. */
67   const insn_t      *instruction;       /* The actual instruction. */
68   unsigned int       state;             /* For COPT_... constants. */
69   gp_boolean         protected;
70 
71   uint32_t           target_page;
72   uint32_t           reloc_page;
73 
74   uint32_t           reloc_byte_addr;
75   uint32_t           reloc_insn_addr;
76 
77   uint32_t           reloc_byte_length;
78   uint32_t           reloc_insn_length;
79 
80   uint32_t           ram_bank;
81 } reloc_properties_t;
82 
83 static reloc_properties_t   reloc_pipe[RELOC_PIPE_LENGTH];
84 
85 static gp_section_t       **section_array;
86 static unsigned int         num_sections;
87 
88 static gp_symbol_t        **register_array;
89 static unsigned int         num_registers;
90 
91 static gp_boolean           first_banksel = false;
92 
93 /*------------------------------------------------------------------------------------------------*/
94 
95 /* Remove any weak symbols in the object. */
96 
97 void
gp_coffopt_remove_weak(gp_object_t * Object)98 gp_coffopt_remove_weak(gp_object_t *Object)
99 {
100   gp_symbol_t *symbol;
101 
102   gp_debug("Removing weak symbols from \"%s\".", Object->filename);
103 
104   /* Search the symbol table for extern symbols. */
105   symbol = Object->symbol_list.first;
106   while (symbol != NULL) {
107     if (gp_coffgen_is_external_symbol(symbol) && (!gp_coffgen_symbol_has_reloc(symbol, COFF_SYM_RELOC_ALL))) {
108       gp_debug("  removed weak symbol \"%s\"", symbol->name);
109       /* It is not allowed to deleted because the gplink/cod.c will need this. */
110       gp_coffgen_move_reserve_symbol(Object, symbol);
111     }
112 
113     symbol = symbol->next;
114   }
115 }
116 
117 /*------------------------------------------------------------------------------------------------*/
118 
119 /* Remove any relocatable section that doesn't have a symbol pointed to by a relocation. */
120 
121 void
gp_coffopt_remove_dead_sections(gp_object_t * Object,int Pass,gp_boolean Enable_cinit_wanings)122 gp_coffopt_remove_dead_sections(gp_object_t *Object, int Pass, gp_boolean Enable_cinit_wanings)
123 {
124   gp_section_t *section;
125   gp_section_t *section_next;
126   gp_boolean    section_removed;
127 
128   do {
129     section_removed = false;
130     gp_debug("Removing dead sections pass %i.", Pass);
131 
132     gp_coffgen_check_relocations(Object, Enable_cinit_wanings);
133     section = Object->section_list.first;
134     while (section != NULL) {
135       section_next = section->next;
136 
137       if (FlagIsClr(section->opt_flags, OPT_FLAGS_PROTECTED_SECTION)) {
138         gp_debug("Removing section \"%s\".", section->name);
139         /* It is not allowed to deleted because the gplink/cod.c will need these. */
140         gp_coffgen_move_reserve_section_symbols(Object, section);
141         /* It is not allowed to deleted because the gplink/cod.c will need this. */
142         gp_coffgen_move_reserve_section(Object, section);
143         section_removed = true;
144       }
145       section = section_next;
146     }
147 
148     /* take another pass */
149     ++Pass;
150   } while (section_removed);
151 }
152 
153 
154 /*------------------------------------------------------------------------------------------------*/
155 
156 /* Deletes all states from relocation pipe. */
157 
158 static void
_reloc_pipe_clear(void)159 _reloc_pipe_clear(void)
160 {
161   memset(reloc_pipe, 0, sizeof(reloc_pipe));
162 }
163 
164 /*------------------------------------------------------------------------------------------------*/
165 
166 /* Moves the contents of relocation tube forward or backward. */
167 
168 static void
_reloc_pipe_shift(gp_boolean Forward)169 _reloc_pipe_shift(gp_boolean Forward)
170 {
171   size_t i;
172 
173   if (Forward) {
174     /* Moves forward.
175 
176        reloc_pipe[last - 1] --> reloc_pipe[last]  -- The oldest relocation.
177          .
178          .
179          .
180        reloc_pipe[first]    --> reloc_pipe[first+1]
181        reloc_pipe[first]    <-- 0                 -- The current relocation. */
182     for (i = RELOC_PIPE_LENGTH - 1; i > 0; --i) {
183       memcpy(&reloc_pipe[i], &reloc_pipe[i - 1], sizeof(reloc_properties_t));
184     }
185 
186     memset(&reloc_pipe[0], 0, sizeof(reloc_properties_t));
187   }
188   else {
189     /* Moves backward.
190 
191        reloc_pipe[first + 1] --> reloc_pipe[first] -- The current relocation.
192          .
193          .
194          .
195        reloc_pipe[last]      --> reloc_pipe[last - 1]
196        reloc_pipe[last]      <-- 0                 -- The oldest relocation. */
197     for (i = 0; i < (RELOC_PIPE_LENGTH - 1); ++i) {
198       memcpy(&reloc_pipe[i], &reloc_pipe[i + 1], sizeof(reloc_properties_t));
199     }
200 
201     memset(&reloc_pipe[RELOC_PIPE_LENGTH - 1], 0, sizeof(reloc_properties_t));
202   }
203 }
204 
205 /*------------------------------------------------------------------------------------------------*/
206 
207 /* Deletes one state from the relocation pipe. */
208 
209 static void
_reloc_pipe_delete_state(size_t State_index)210 _reloc_pipe_delete_state(size_t State_index)
211 {
212   assert(State_index < RELOC_PIPE_LENGTH);
213 
214   while (State_index < (RELOC_PIPE_LENGTH - 1)) {
215     memcpy(&reloc_pipe[State_index], &reloc_pipe[State_index + 1], sizeof(reloc_properties_t));
216     ++State_index;
217   }
218 
219   memset(&reloc_pipe[RELOC_PIPE_LENGTH - 1], 0, sizeof(reloc_properties_t));
220 }
221 
222 /*------------------------------------------------------------------------------------------------*/
223 
224 /* Make page address from an instruction address. */
225 
226 static uint32_t
_page_addr_from_insn_addr(proc_class_t Class,uint32_t Insn_addr)227 _page_addr_from_insn_addr(proc_class_t Class, uint32_t Insn_addr)
228 {
229   return gp_processor_page_addr(Class, Insn_addr);
230 }
231 
232 /*------------------------------------------------------------------------------------------------*/
233 
234 /* Make page address from an byte address. */
235 
236 static uint32_t
_page_addr_from_byte_addr(proc_class_t Class,uint32_t Byte_addr)237 _page_addr_from_byte_addr(proc_class_t Class, uint32_t Byte_addr)
238 {
239   return gp_processor_page_addr(Class, gp_processor_insn_from_byte_c(Class, Byte_addr));
240 }
241 
242 /*------------------------------------------------------------------------------------------------*/
243 
244 /* Decrease relocation addresses in a given list. */
245 
246 static void
_reloc_decrease_addresses(proc_class_t Class,gp_reloc_t * Relocation,uint32_t Relocation_page,uint32_t Insn_offset,uint32_t Byte_offset)247 _reloc_decrease_addresses(proc_class_t Class, gp_reloc_t *Relocation, uint32_t Relocation_page,
248                           uint32_t Insn_offset, uint32_t Byte_offset)
249 {
250   gp_reloc_t         *reloc;
251   gp_symbol_t        *symbol;
252   const gp_section_t *section;
253 
254   if (Relocation == NULL) {
255     return;
256   }
257 
258   reloc = Relocation;
259   while (reloc != NULL) {
260     if (reloc->address >= Byte_offset) {
261       reloc->address -= Byte_offset;
262       symbol  = reloc->symbol;
263       section = symbol->section;
264 
265       /* Prevents the modification of symbols on the other pages. */
266       if (FlagIsSet(section->flags, STYP_ROM_AREA) &&
267           (_page_addr_from_insn_addr(Class, symbol->value) == Relocation_page)) {
268           /* Prevents the multiple modifications of symbol. */
269         if (FlagIsClr(symbol->opt_flags, OPT_FLAGS_GPCOFFOPT_MODULE)) {
270           symbol->value -= Insn_offset;
271           FlagSet(symbol->opt_flags, OPT_FLAGS_GPCOFFOPT_MODULE);
272         }
273       }
274     }
275 
276     reloc = reloc->next;
277   }
278 }
279 
280 /*------------------------------------------------------------------------------------------------*/
281 
282 static void
_label_arrays_make(proc_class_t Class)283 _label_arrays_make(proc_class_t Class)
284 {
285   gp_section_t *section;
286   unsigned int  i;
287 
288   if ((section_array == NULL) || (num_sections == 0)) {
289     return;
290   }
291 
292   for (i = 0; i < num_sections; ++i) {
293     section = section_array[i];
294     section->num_labels  = 0;
295     section->label_array = gp_symbol_make_label_array(section, Class->org_to_byte_shift,
296                                                       &(section->num_labels));
297   }
298 }
299 
300 /*------------------------------------------------------------------------------------------------*/
301 
302 static void
_label_arrays_free(void)303 _label_arrays_free(void)
304 {
305   gp_section_t *section;
306   unsigned int  i;
307 
308   if ((section_array == NULL) || (num_sections == 0)) {
309     return;
310   }
311 
312   for (i = 0; i < num_sections; ++i) {
313     section = section_array[i];
314 
315     if (section->label_array != NULL) {
316       free(section->label_array);
317       section->label_array = NULL;
318     }
319 
320     section->num_labels  = 0;
321   }
322 }
323 
324 /*------------------------------------------------------------------------------------------------*/
325 
326 /* Sets or clears section optimize flag in a given list. */
327 
328 static void
_label_clear_opt_flag(void)329 _label_clear_opt_flag(void)
330 {
331   gp_section_t *section;
332   gp_symbol_t  *label;
333   unsigned int  i;
334   unsigned int  j;
335 
336   if ((section_array == NULL) || (num_sections == 0)) {
337     return;
338   }
339 
340   for (i = 0; i < num_sections; ++i) {
341     section = section_array[i];
342     for (j = 0; j < section->num_labels; ++j) {
343       label = section->label_array[j];
344       /* This will be modifiable. */
345       FlagClr(label->opt_flags, OPT_FLAGS_GPCOFFOPT_MODULE);
346     }
347   }
348 }
349 
350 /*------------------------------------------------------------------------------------------------*/
351 
352 /* Decrease label addresses in a given list. */
353 
354 static void
_label_array_decrease_addresses(proc_class_t Class,gp_section_t * Section,uint32_t Start_address,uint32_t Insn_offset)355 _label_array_decrease_addresses(proc_class_t Class, gp_section_t *Section, uint32_t Start_address,
356                                 uint32_t Insn_offset)
357 {
358   unsigned int  i;
359   gp_symbol_t  *label;
360 
361   for (i = 0; i < Section->num_labels; ++i) {
362     label = Section->label_array[i];
363 
364     /* Prevents the multiple modifications of symbol. */
365     if (label->value >= Start_address) {
366       if (FlagIsClr(label->opt_flags, OPT_FLAGS_GPCOFFOPT_MODULE)) {
367         label->value -= Insn_offset;
368         FlagSet(label->opt_flags, OPT_FLAGS_GPCOFFOPT_MODULE);
369       }
370     }
371   }
372 }
373 
374 /*------------------------------------------------------------------------------------------------*/
375 
376 /* Decrease section addresses in a given list. */
377 
378 static void
_sections_decrease_start_address(proc_class_t Class,const gp_section_t * Section,uint32_t Insn_offset,uint32_t Byte_offset)379 _sections_decrease_start_address(proc_class_t Class, const gp_section_t *Section, uint32_t Insn_offset,
380                                  uint32_t Byte_offset)
381 {
382   gp_section_t  *section;
383   gp_symbol_t   *symbol;
384   unsigned int   i;
385   uint32_t       byte_address;
386   uint32_t       insn_address;
387   gp_symvalue_t  value_prev;
388 
389   if ((section_array == NULL) || (num_sections < 1)) {
390     return;
391   }
392 
393   for (i = 0; i < num_sections; ++i) {
394     section = section_array[i];
395     /* Prevents the modification of sections on other pages. */
396     if (section->address > Section->address) {
397       byte_address = section->address - Byte_offset;
398       insn_address = gp_processor_insn_from_byte_c(Class, byte_address);
399       gp_mem_b_move(section->data, section->address, byte_address, section->size);
400       section->address = byte_address;
401 
402       symbol = section->symbol;
403       if (symbol != NULL) {
404         value_prev     = symbol->value;
405         symbol->value -= Insn_offset;
406         assert((gp_symvalue_t)insn_address == symbol->value);
407       }
408 
409       _label_array_decrease_addresses(Class, section, value_prev, Insn_offset);
410     }
411   }
412 }
413 
414 /*------------------------------------------------------------------------------------------------*/
415 
416 /* Decrease line number addresses in a given list. */
417 
418 static void
_linenum_decrease_addresses(proc_class_t Class,gp_section_t * First_section,uint32_t Relocation_page,uint32_t Start_address,uint32_t Byte_offset)419 _linenum_decrease_addresses(proc_class_t Class, gp_section_t *First_section,
420                             uint32_t Relocation_page, uint32_t Start_address, uint32_t Byte_offset)
421 {
422   gp_section_t *section;
423   gp_linenum_t *linenum;
424 
425   section = First_section;
426   while (section != NULL) {
427     linenum = section->line_number_list.first;
428     while (linenum != NULL) {
429       /* Prevents the modification of linenumbers on other pages. */
430       if ((_page_addr_from_byte_addr(Class, linenum->address) == Relocation_page) &&
431           (linenum->address >= Start_address)) {
432         linenum->address -= Byte_offset;
433       }
434       linenum = linenum->next;
435     }
436     section = section->next;
437   }
438 }
439 
440 /*------------------------------------------------------------------------------------------------*/
441 
442 /* Destroys an instruction from data memory of given section. */
443 
444 static void
_destroy_insn(proc_class_t Class,gp_section_t * Section,uint32_t Byte_address,uint32_t Byte_length,const char * Symbol_name)445 _destroy_insn(proc_class_t Class, gp_section_t *Section, uint32_t Byte_address, uint32_t Byte_length,
446               const char *Symbol_name)
447 {
448   gp_mem_b_delete_area(Section->data, Byte_address, Byte_length);
449   Section->size -= Byte_length;
450 }
451 
452 /*------------------------------------------------------------------------------------------------*/
453 
454 /* Destroys a Pagesel directive and updates all related addresses. */
455 
456 static void
_destroy_insn_and_update_addr(proc_class_t Class,gp_section_t * First_section,gp_section_t * Section,unsigned int Insn_index)457 _destroy_insn_and_update_addr(proc_class_t Class, gp_section_t *First_section, gp_section_t *Section,
458                               unsigned int Insn_index)
459 {
460   unsigned int  i;
461   uint32_t      start_page;
462   uint32_t      byte_addr_curr;
463   uint32_t      byte_length_curr;
464   uint32_t      insn_addr_curr;
465   uint32_t      insn_length_curr;
466   uint32_t      byte_addr_next;
467   const char   *sym_name;
468 
469   byte_addr_curr   = reloc_pipe[Insn_index].reloc_byte_addr;
470   byte_length_curr = reloc_pipe[Insn_index].reloc_byte_length;
471   insn_addr_curr   = reloc_pipe[Insn_index].reloc_insn_addr;
472   insn_length_curr = reloc_pipe[Insn_index].reloc_insn_length;
473   byte_addr_next   = byte_addr_curr + byte_length_curr;
474   start_page       = reloc_pipe[Insn_index].reloc_page;
475   sym_name         = (reloc_pipe[Insn_index].relocation->symbol != NULL) ?
476                                         reloc_pipe[Insn_index].relocation->symbol->name : NULL;
477 
478   _destroy_insn(Class, Section, byte_addr_curr, byte_length_curr, sym_name);
479   gp_symbol_delete_by_value(Section->label_array, &Section->num_labels, insn_addr_curr);
480 
481   gp_coffgen_del_linenum_by_address_area(Section, byte_addr_curr, byte_addr_next - 1);
482   _linenum_decrease_addresses(Class, First_section, start_page, byte_addr_next, byte_length_curr);
483 
484   /* Enable modification of address only in program memory. */
485   _label_clear_opt_flag();
486 
487   _sections_decrease_start_address(Class, Section, insn_length_curr, byte_length_curr);
488 
489   _reloc_decrease_addresses(Class, reloc_pipe[Insn_index].relocation->next, start_page, insn_length_curr,
490                             byte_length_curr);
491 
492   gp_coffgen_del_reloc(Section, reloc_pipe[Insn_index].relocation);
493 
494   /* Decrease the address of instruction in newer (younger) states. */
495   for (i = 0; i < Insn_index; ++i) {
496     reloc_pipe[i].reloc_byte_addr -= byte_length_curr;
497     reloc_pipe[i].reloc_insn_addr -= insn_length_curr;
498   }
499 
500   _reloc_pipe_delete_state(Insn_index);
501 }
502 
503 /*------------------------------------------------------------------------------------------------*/
504 
505 static gp_boolean
_insn_isReturn(proc_class_t Class,const gp_section_t * Section,unsigned int Byte_addr)506 _insn_isReturn(proc_class_t Class, const gp_section_t *Section, unsigned int Byte_addr)
507 {
508   uint16_t      data;
509   const insn_t *instruction;
510 
511   if (Class->find_insn == NULL) {
512     return false;
513   }
514 
515   if (Class->i_memory_get(Section->data, Byte_addr, &data, NULL, NULL) != W_USED_ALL) {
516     return false;
517   }
518 
519   instruction = Class->find_insn(Class, data);
520   if (instruction == NULL) {
521     return false;
522   }
523 
524   switch (instruction->icode) {
525     case ICODE_RETFIE:
526     case ICODE_RETI:
527     case ICODE_RETIW:
528     case ICODE_RETLW:
529     case ICODE_RETP:
530     case ICODE_RETURN:
531       return true;
532 
533     default:
534       return false;
535   }
536 }
537 
538 /*------------------------------------------------------------------------------------------------*/
539 
540 /* Analyze and add a new relocation state unto the relocation pipe. */
541 
542 static void
_pagesel_reloc_analyze(proc_class_t Class,gp_section_t * Section,gp_reloc_t * Relocation,unsigned int Num_pages)543 _pagesel_reloc_analyze(proc_class_t Class, gp_section_t *Section, gp_reloc_t *Relocation,
544                        unsigned int Num_pages)
545 {
546   const gp_symbol_t *symbol;
547   uint16_t           data;
548   uint32_t           reloc_byte_addr;
549   uint32_t           reloc_insn_addr;
550   uint32_t           reloc_byte_length;
551   uint32_t           value;
552   uint32_t           reloc_page;
553   uint32_t           target_page;
554 
555   symbol          = Relocation->symbol;
556   reloc_byte_addr = Section->address        + Relocation->address;
557   value           = (uint32_t)symbol->value + Relocation->offset;
558 
559   if (Class->i_memory_get(Section->data, reloc_byte_addr, &data, NULL, NULL) != W_USED_ALL) {
560     gp_error("No instruction at 0x%0*X in program memory!", Class->addr_digits, reloc_byte_addr);
561     assert(0);
562   }
563 
564   reloc_insn_addr = gp_processor_insn_from_byte_c(Class, reloc_byte_addr);
565   reloc_page      = gp_processor_page_addr(Class, reloc_insn_addr);
566   target_page     = gp_processor_page_addr(Class, value);
567 
568   /* No relocation. */
569   if ((reloc_pipe[1].relocation == NULL) ||
570       /* A relocation which is not interesting. */
571       (reloc_pipe[1].state == COPT_NULL) ||
572       /* A relocation which is too far away. Meanwhile there is at least one other instruction. */
573       ((reloc_pipe[1].reloc_insn_addr + reloc_pipe[1].reloc_insn_length) != reloc_insn_addr)) {
574     /* Clears the contents of status pipe. */
575     _reloc_pipe_clear();
576   }
577 
578   reloc_pipe[0].relocation      = Relocation;
579   reloc_pipe[0].label           = gp_symbol_find_by_value(Section->label_array, Section->num_labels, reloc_insn_addr);
580   reloc_pipe[0].instruction     = (Class->find_insn != NULL) ? Class->find_insn(Class, data) : NULL;
581   reloc_pipe[0].state           = COPT_NULL;
582   reloc_pipe[0].protected       = ((reloc_pipe[0].label != NULL) && (reloc_pipe[0].label->reloc_count_all_section > 1)) ? true : false;
583   reloc_pipe[0].target_page     = target_page;
584   reloc_pipe[0].reloc_page      = reloc_page;
585   reloc_pipe[0].reloc_byte_addr = reloc_byte_addr;
586   reloc_pipe[0].reloc_insn_addr = reloc_insn_addr;
587 
588   reloc_byte_length = 0;
589 
590   switch (Relocation->type) {
591     case RELOC_ALL:
592       break;
593 
594     case RELOC_CALL:
595       /* call function */
596       reloc_pipe[0].state = (reloc_page == target_page) ? COPT_CALL_CURR_PAGE : COPT_CALL_OTHER_PAGE;
597       reloc_byte_length   = 2;
598       break;
599 
600     case RELOC_GOTO:
601       /* goto label */
602       reloc_pipe[0].state = (reloc_page == target_page) ? COPT_GOTO_CURR_PAGE : COPT_GOTO_OTHER_PAGE;
603       reloc_byte_length   = 2;
604       break;
605 
606     case RELOC_LOW:
607       break;
608 
609     case RELOC_HIGH: {
610       /* high(value) */
611       if ((reloc_pipe[0].instruction != NULL) && (reloc_pipe[0].instruction->icode == ICODE_MOVLP)) {
612         /* movlp high(value) */
613         reloc_pipe[0].state = (reloc_page == target_page) ? COPT_PAGESEL_CURR_PAGE : COPT_PAGESEL_OTHER_PAGE;
614       }
615       reloc_byte_length = 2;
616       break;
617     }
618 
619     case RELOC_UPPER:
620     case RELOC_P:
621     case RELOC_BANKSEL:
622     case RELOC_IBANKSEL:
623     case RELOC_F:
624     case RELOC_TRIS:
625     case RELOC_TRIS_3BIT:
626     case RELOC_MOVLR:
627     case RELOC_MOVLB:
628     case RELOC_GOTO2:
629     case RELOC_FF1:
630     case RELOC_FF2:
631     case RELOC_LFSR1:
632     case RELOC_LFSR2:
633       break;
634 
635     case RELOC_BRA:
636       /* bra label */
637       reloc_pipe[0].state = (reloc_page == target_page) ? COPT_BRA14E_CURR_PAGE : COPT_BRA14E_OTHER_PAGE;
638       reloc_byte_length   = 2;
639       break;
640 
641     case RELOC_CONDBRA:
642     case RELOC_ACCESS:
643       break;
644 
645     case RELOC_PAGESEL_WREG:
646       /* PIC12, PIC12E, PIC12I
647 
648        movlw value
649        movwf STATUS
650 
651         OR
652 
653        PIC14
654 
655        movlw value
656        movwf PCLATH */
657       reloc_pipe[0].state = (reloc_page == target_page) ? COPT_PAGESEL_CURR_PAGE : COPT_PAGESEL_OTHER_PAGE;
658       reloc_byte_length   = Class->pagesel_byte_length(Num_pages, true);
659       break;
660 
661     case RELOC_PAGESEL_BITS:
662       /* PIC12, PIC12E, PIC12I
663 
664        bcf STATUS, x
665        bsf STATUS, x
666 
667         OR
668 
669        PIC14
670 
671        bcf PCLATH, x
672        bsf PCLATH, x */
673     case RELOC_PAGESEL_MOVLP:
674       /* PIC14E, PIC14EX
675 
676        movlp value */
677       reloc_pipe[0].state = (reloc_page == target_page) ? COPT_PAGESEL_CURR_PAGE : COPT_PAGESEL_OTHER_PAGE;
678       reloc_byte_length   = Class->pagesel_byte_length(Num_pages, false);
679       break;
680 
681     /* unimplemented relocations */
682     case RELOC_PAGESEL:
683     case RELOC_SCNSZ_LOW:
684     case RELOC_SCNSZ_HIGH:
685     case RELOC_SCNSZ_UPPER:
686     case RELOC_SCNEND_LOW:
687     case RELOC_SCNEND_HIGH:
688     case RELOC_SCNEND_UPPER:
689     case RELOC_SCNEND_LFSR1:
690     case RELOC_SCNEND_LFSR2:
691     default: {
692         if (symbol->name != NULL) {
693           gp_error("Unimplemented relocation = %s (%u) in section \"%s\" at symbol \"%s\".",
694                    gp_coffgen_reloc_type_to_str(Relocation->type),
695                    Relocation->type, Section->name, symbol->name);
696         }
697         else {
698           gp_error("Unimplemented relocation = %s (%u) in section \"%s\".",
699                    gp_coffgen_reloc_type_to_str(Relocation->type),
700                    Relocation->type, Section->name);
701         }
702         assert(0);
703       }
704   }
705 
706   reloc_pipe[0].reloc_byte_length = reloc_byte_length;
707   reloc_pipe[0].reloc_insn_length = gp_processor_insn_from_byte_c(Class, reloc_byte_length);
708 }
709 
710 /*------------------------------------------------------------------------------------------------*/
711 
712 /* If possible according to the rules, then removes a Pagesel directive. */
713 
714 static gp_boolean
_pagesel_remove(proc_class_t Class,gp_section_t * First_section,gp_section_t * Section,gp_boolean Completion)715 _pagesel_remove(proc_class_t Class, gp_section_t *First_section, gp_section_t *Section,
716                 gp_boolean Completion)
717 {
718   unsigned int saturation;
719   unsigned int byte_addr_next;
720 
721   saturation  = (reloc_pipe[0].relocation != NULL);
722   saturation += (reloc_pipe[1].relocation != NULL);
723   saturation += (reloc_pipe[2].relocation != NULL);
724   saturation += (reloc_pipe[3].relocation != NULL);
725 
726   if (saturation == 0) {
727     /* The State Pipe is empty. */
728     return false;
729   }
730 
731   if (Completion) {
732     /* This is the last relocation on chain (a code section). */
733     if ((reloc_pipe[0].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[0].protected)) {
734       byte_addr_next = reloc_pipe[0].reloc_byte_addr + reloc_pipe[0].reloc_byte_length;
735 
736       if (_insn_isReturn(Class, Section, byte_addr_next)) {
737         /*
738           reloc_pipe[0]   pagesel current_page  <-- UNNECESSARY if not PROTECTED
739           byte_addr_next: return (or these: retfie, retlw, reti, retp)
740         */
741         _destroy_insn_and_update_addr(Class, First_section, Section, 0);
742         _reloc_pipe_shift(false);
743         return true;
744       }
745     }
746   }
747 
748   if (saturation >= 2) {
749     /* The saturation of State Pipe at least 1/2. */
750     if ((reloc_pipe[1].state == COPT_CALL_CURR_PAGE) &&
751         (reloc_pipe[0].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[0].protected)) {
752       /*
753         reloc_pipe[1] call    function_on_current_page
754         reloc_pipe[0] pagesel current_page  <--------- UNNECESSARY if not PROTECTED
755       */
756       _destroy_insn_and_update_addr(Class, First_section, Section, 0);
757     }
758     else if ((reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[1].protected) &&
759              (reloc_pipe[0].state == COPT_PAGESEL_OTHER_PAGE)) {
760       /*
761         reloc_pipe[1] pagesel current_page  <------- UNNECESSARY if not PROTECTED
762         reloc_pipe[0] pagesel other_page
763       */
764       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
765     }
766     else if ((reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[1].protected) &&
767              (reloc_pipe[0].state & COPT_ABS_BRANCH_CURR_PAGE_MASK)) {
768       /*
769         reloc_pipe[1] pagesel current_page  <------ UNNECESSARY if not PROTECTED
770         reloc_pipe[0] goto    label_on_current_page
771 
772           OR
773 
774         reloc_pipe[1] pagesel current_page  <--------- UNNECESSARY if not PROTECTED
775         reloc_pipe[0] call    function_on_current_page
776       */
777       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
778     }
779     else if ((reloc_pipe[1].state & COPT_PAGESEL_MASK) && (!reloc_pipe[1].protected) &&
780              (reloc_pipe[0].state & COPT_REL_BRANCH_MASK)) {
781       /*
782         The 'bra' is a relative jump, no need to Pagesel.
783 
784         reloc_pipe[1] pagesel current_or_other_page  <----- UNNECESSARY if not PROTECTED
785         reloc_pipe[0] bra     label_on_current_or_other_page
786       */
787       gp_warning("Strange relocation = %s (%u) with = %s (%u) in section \"%s\" at symbol \"%s\".",
788                  gp_coffgen_reloc_type_to_str(reloc_pipe[1].relocation->type), reloc_pipe[1].relocation->type,
789                  gp_coffgen_reloc_type_to_str(reloc_pipe[0].relocation->type), reloc_pipe[0].relocation->type,
790                  Section->name, reloc_pipe[0].relocation->symbol->name);
791       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
792     }
793   } /* if (saturation >= 2) */
794 
795   if (saturation >= 3) {
796     /* The saturation of State Pipe at least 3/4. */
797     if ((reloc_pipe[2].state == COPT_CALL_OTHER_PAGE) &&
798         (reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) &&
799         (reloc_pipe[0].state == COPT_PAGESEL_CURR_PAGE)) {
800       /*
801         reloc_pipe[2] call    function_on_other_page
802         reloc_pipe[1] pagesel current_page  <------- clear PROTECTED
803         reloc_pipe[0] pagesel current_page  <------- set PROTECTED
804       */
805       reloc_pipe[1].protected = false;
806       reloc_pipe[0].protected = true;
807     }
808     else if ((reloc_pipe[2].state == COPT_CALL_OTHER_PAGE) &&
809              (reloc_pipe[1].state == COPT_PAGESEL_OTHER_PAGE) && (!reloc_pipe[1].protected) &&
810              (reloc_pipe[2].target_page == reloc_pipe[1].target_page) &&
811              (reloc_pipe[0].state == COPT_CALL_OTHER_PAGE) &&
812              (reloc_pipe[1].target_page == reloc_pipe[0].target_page)) {
813       /*
814         reloc_pipe[2] call    function_on_other_page
815         reloc_pipe[1] pagesel other_page  <--------- UNNECESSARY if not PROTECTED
816         reloc_pipe[0] call    function_on_other_page
817       */
818       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
819     }
820     else if ((reloc_pipe[2].state == COPT_CALL_CURR_PAGE) &&
821              (reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[1].protected) &&
822              (reloc_pipe[0].state == COPT_PAGESEL_CURR_PAGE)) {
823       /*
824         reloc_pipe[2] call    function_on_current_page
825         reloc_pipe[1] pagesel current_page  <--------- UNNECESSARY if not PROTECTED
826         reloc_pipe[0] pagesel current_page
827       */
828       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
829     }
830     else if ((reloc_pipe[2].state == COPT_CALL_CURR_PAGE) &&
831              (reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[1].protected) &&
832              (reloc_pipe[0].state == COPT_CALL_CURR_PAGE)) {
833       /*
834         reloc_pipe[2] call    function_on_current_page
835         reloc_pipe[1] pagesel current_page  <--------- UNNECESSARY if not PROTECTED
836         reloc_pipe[0] call    function_on_current_page
837       */
838       _destroy_insn_and_update_addr(Class, First_section, Section, 1);
839     }
840   } /* if (saturation >= 3) */
841 
842   if (saturation == 4) {
843     /* The State Pipe is full. */
844     if ((reloc_pipe[3].state == COPT_CALL_OTHER_PAGE) &&
845         (reloc_pipe[2].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[2].protected) &&
846         (reloc_pipe[1].state == COPT_PAGESEL_CURR_PAGE) &&
847         (reloc_pipe[0].state == COPT_CALL_CURR_PAGE)) {
848       /*
849         reloc_pipe[3] call    function_on_other_page
850         reloc_pipe[2] pagesel current_page  <------- UNNECESSARY if not PROTECTED
851         reloc_pipe[1] pagesel current_page
852         reloc_pipe[0] call    function_on_current_page
853       */
854       _destroy_insn_and_update_addr(Class, First_section, Section, 2);
855     }
856     else if ((reloc_pipe[3].state == COPT_CALL_OTHER_PAGE) &&
857              (reloc_pipe[2].state == COPT_PAGESEL_CURR_PAGE) && (!reloc_pipe[2].protected) &&
858              (reloc_pipe[1].state == COPT_PAGESEL_OTHER_PAGE) &&
859              (reloc_pipe[0].state == COPT_CALL_OTHER_PAGE)) {
860       /*
861         reloc_pipe[3] call    function_on_other_page
862         reloc_pipe[2] pagesel current_page  <------- UNNECESSARY if not PROTECTED
863         reloc_pipe[1] pagesel other_page
864         reloc_pipe[0] call    function_on_other_page
865       */
866       _destroy_insn_and_update_addr(Class, First_section, Section, 2);
867     }
868   } /* if (saturation == 4) */
869 
870   return true;
871 }
872 
873 /*------------------------------------------------------------------------------------------------*/
874 
875 /* Deletes the unnecessary Pagesel directives from an object. */
876 
877 void
gp_coffopt_remove_unnecessary_pagesel(gp_object_t * Object)878 gp_coffopt_remove_unnecessary_pagesel(gp_object_t *Object)
879 {
880   proc_class_t  class;
881   gp_section_t *first_section;
882   gp_section_t *section;
883   gp_reloc_t   *reloc_curr;
884   gp_reloc_t   *reloc_next;
885   unsigned int  num_pages;
886   unsigned int  i;
887 
888   class = Object->class;
889 
890   /* Only case of PIC12 and PIC14 families. */
891   if ((class != PROC_CLASS_PIC12)  && (class != PROC_CLASS_PIC12E) &&
892       (class != PROC_CLASS_PIC12I) && (class != PROC_CLASS_SX)     &&
893       (class != PROC_CLASS_PIC14)  && (class != PROC_CLASS_PIC14E) &&
894       (class != PROC_CLASS_PIC14EX)) {
895     return;
896   }
897 
898   section_array  = NULL;
899   num_sections   = 0;
900   register_array = NULL;
901   num_registers  = 0;
902 
903   gp_debug("Removing unnecessary pagesel instructions.");
904   _reloc_pipe_clear();
905   num_pages     = gp_processor_num_pages(Object->processor);
906   first_section = Object->section_list.first;
907 
908   section = first_section;
909   while (section != NULL) {
910     _reloc_pipe_clear();
911 
912     if (gp_coffgen_section_has_data(section)) {
913       num_sections  = 0;
914       section_array = gp_coffgen_make_section_array(Object, &num_sections,
915                               gp_processor_page_addr(class, gp_processor_insn_from_byte_c(class, section->address)),
916                               STYP_ROM_AREA);
917       _label_arrays_make(class);
918 
919       if (section->label_array != NULL) {
920         reloc_curr = section->relocation_list.first;
921         if (reloc_curr != NULL) {
922           i = 0;
923           do {
924             reloc_next = reloc_curr->next;
925             _pagesel_reloc_analyze(class, section, reloc_curr, num_pages);
926             reloc_curr = reloc_next;
927             _pagesel_remove(class, first_section, section, (reloc_curr == NULL));
928             _reloc_pipe_shift(true);
929             ++i;
930           } while (reloc_curr != NULL);
931         }
932       }
933 
934       _label_arrays_free();
935 
936       if (section_array != NULL) {
937         free(section_array);
938       }
939     }
940 
941     section = section->next;
942   } /* while (section != NULL) */
943 }
944 
945 /*------------------------------------------------------------------------------------------------*/
946 
947 /* Analyze and add a new relocation state unto the relocation pipe. */
948 
949 static gp_boolean
_banksel_reloc_analyze(proc_class_t Class,pic_processor_t Processor,gp_section_t * Section,gp_reloc_t * Relocation,unsigned int Num_pages)950 _banksel_reloc_analyze(proc_class_t Class, pic_processor_t Processor, gp_section_t *Section,
951                        gp_reloc_t *Relocation, unsigned int Num_pages)
952 {
953   const gp_symbol_t *symbol;
954   uint16_t           data;
955   uint32_t           reloc_byte_addr;
956   uint32_t           reloc_insn_addr;
957   uint32_t           reloc_byte_length;
958   uint32_t           reloc_page;
959   uint32_t           value;
960   uint32_t           ram_bank;
961   gp_boolean         need_clear;
962   gp_boolean         there_is_banksel;
963 
964   symbol          = Relocation->symbol;
965   reloc_byte_addr = Section->address + Relocation->address;
966   reloc_insn_addr = gp_processor_insn_from_byte_c(Class, reloc_byte_addr);
967   value           = (uint32_t)symbol->value + Relocation->offset;
968 
969   reloc_page      = gp_processor_page_addr(Class, reloc_insn_addr);
970 
971   if (Class->i_memory_get(Section->data, reloc_byte_addr, &data, NULL, NULL) != W_USED_ALL) {
972     gp_error("No instruction at 0x%0*X in program memory!", Class->addr_digits, reloc_byte_addr);
973     assert(0);
974   }
975 
976   reloc_byte_length = 0;
977   ram_bank          = 0;
978   need_clear        = false;
979   there_is_banksel  = false;
980 
981   switch (Relocation->type) {
982     case RELOC_ALL:
983       break;
984 
985     case RELOC_CALL:
986     case RELOC_GOTO:
987       need_clear = true;
988       break;
989 
990     case RELOC_LOW:
991     case RELOC_HIGH:
992     case RELOC_UPPER:
993     case RELOC_P:
994       break;
995 
996     case RELOC_BANKSEL:
997       ram_bank          = gp_processor_bank_addr(Processor, value);
998       reloc_byte_length = Class->banksel_byte_length(Num_pages, false);
999       there_is_banksel  = true;
1000       break;
1001 
1002     case RELOC_IBANKSEL:
1003       break;
1004 
1005     case RELOC_F:
1006     case RELOC_TRIS:
1007     case RELOC_TRIS_3BIT:
1008     case RELOC_MOVLR:
1009       break;
1010 
1011     case RELOC_MOVLB:
1012       ram_bank          = gp_processor_bank_addr(Processor, value);
1013       reloc_byte_length = 2;
1014       there_is_banksel  = true;
1015       break;
1016 
1017     case RELOC_GOTO2:
1018       need_clear = true;
1019       break;
1020 
1021     case RELOC_FF1:
1022     case RELOC_FF2:
1023     case RELOC_LFSR1:
1024     case RELOC_LFSR2:
1025       break;
1026 
1027     case RELOC_BRA:
1028     case RELOC_CONDBRA:
1029       need_clear = true;
1030       break;
1031 
1032     case RELOC_ACCESS:
1033     case RELOC_PAGESEL_WREG:
1034     case RELOC_PAGESEL_BITS:
1035     case RELOC_PAGESEL_MOVLP:
1036       break;
1037 
1038     /* unimplemented relocations */
1039     case RELOC_PAGESEL:
1040     case RELOC_SCNSZ_LOW:
1041     case RELOC_SCNSZ_HIGH:
1042     case RELOC_SCNSZ_UPPER:
1043     case RELOC_SCNEND_LOW:
1044     case RELOC_SCNEND_HIGH:
1045     case RELOC_SCNEND_UPPER:
1046     case RELOC_SCNEND_LFSR1:
1047     case RELOC_SCNEND_LFSR2:
1048     default: {
1049         if (symbol->name != NULL) {
1050           gp_error("Unimplemented relocation = %s (%u) in section \"%s\" at symbol \"%s\".",
1051                    gp_coffgen_reloc_type_to_str(Relocation->type),
1052                    Relocation->type, Section->name, symbol->name);
1053         }
1054         else {
1055           gp_error("Unimplemented relocation = %s (%u) in section \"%s\".",
1056                    gp_coffgen_reloc_type_to_str(Relocation->type),
1057                    Relocation->type, Section->name);
1058         }
1059         assert(0);
1060       }
1061   }
1062 
1063   if (need_clear) {
1064     _reloc_pipe_clear();
1065     return false;
1066   }
1067 
1068   if (there_is_banksel) {
1069     _reloc_pipe_shift(true);
1070 
1071     reloc_pipe[0].relocation        = Relocation;
1072     reloc_pipe[0].label             = gp_symbol_find_by_value(Section->label_array, Section->num_labels, reloc_insn_addr);
1073     reloc_pipe[0].instruction       = (Class->find_insn != NULL) ? Class->find_insn(Class, data) : NULL;
1074     reloc_pipe[0].state             = COPT_BANKSEL;
1075     reloc_pipe[0].protected         = ((reloc_pipe[0].label != NULL) && (reloc_pipe[0].label->reloc_count_all_section > 1)) ? true : false;
1076     reloc_pipe[0].reloc_page        = reloc_page;
1077     reloc_pipe[0].reloc_byte_addr   = reloc_byte_addr;
1078     reloc_pipe[0].reloc_insn_addr   = reloc_insn_addr;
1079     reloc_pipe[0].reloc_byte_length = reloc_byte_length;
1080     reloc_pipe[0].reloc_insn_length = gp_processor_insn_from_byte_c(Class, reloc_byte_length);
1081     reloc_pipe[0].ram_bank          = ram_bank;
1082 
1083     if (!first_banksel) {
1084       /* This is the first Banksel directive of section. Absolutely must protect it. */
1085       reloc_pipe[0].protected = true;
1086       first_banksel           = true;
1087     }
1088     return true;
1089   }
1090 
1091   return false;
1092 }
1093 
1094 /*------------------------------------------------------------------------------------------------*/
1095 
1096 /* If possible according to the rules, then removes a Pagesel directive. */
1097 
1098 static gp_boolean
_banksel_remove(proc_class_t Class,gp_section_t * First_section,gp_section_t * Section)1099 _banksel_remove(proc_class_t Class, gp_section_t *First_section, gp_section_t *Section)
1100 {
1101   unsigned int saturation;
1102 
1103   saturation  = (reloc_pipe[0].relocation != NULL);
1104   saturation += (reloc_pipe[1].relocation != NULL);
1105   saturation += (reloc_pipe[2].relocation != NULL);
1106   saturation += (reloc_pipe[3].relocation != NULL);
1107 
1108   if (saturation == 0) {
1109     /* The State Pipe is empty. */
1110     return false;
1111   }
1112 
1113   if (saturation >= 2) {
1114     if ((reloc_pipe[1].state == COPT_BANKSEL) &&
1115         (reloc_pipe[0].state == COPT_BANKSEL) &&
1116         (reloc_pipe[1].ram_bank == reloc_pipe[0].ram_bank)) {
1117       if (!reloc_pipe[1].protected) {
1118         /*
1119           reloc_pipe[1] banksel Z <--------- UNNECESSARY if not PROTECTED
1120           reloc_pipe[0] banksel Z
1121         */
1122         _destroy_insn_and_update_addr(Class, First_section, Section, 1);
1123       }
1124       else if (!reloc_pipe[0].protected) {
1125         /*
1126           reloc_pipe[1] banksel Z
1127           reloc_pipe[0] banksel Z <--------- UNNECESSARY if not PROTECTED
1128         */
1129         _destroy_insn_and_update_addr(Class, First_section, Section, 0);
1130       }
1131     }
1132   } /* if (saturation >= 2) */
1133 
1134   return true;
1135 }
1136 
1137 /*------------------------------------------------------------------------------------------------*/
1138 
1139 /* Deletes the unnecessary Banksel directives from an object. */
1140 
1141 void
gp_coffopt_remove_unnecessary_banksel(gp_object_t * Object)1142 gp_coffopt_remove_unnecessary_banksel(gp_object_t *Object)
1143 {
1144   proc_class_t     class;
1145   pic_processor_t  processor;
1146   gp_section_t    *first_section;
1147   gp_section_t    *section;
1148   gp_reloc_t      *reloc_curr;
1149   gp_reloc_t      *reloc_next;
1150   unsigned int     num_banks;
1151   unsigned int     i;
1152   gp_boolean       may_remove;
1153 
1154   class     = Object->class;
1155   processor = Object->processor;
1156 
1157   if ((class != PROC_CLASS_PIC12)   && (class != PROC_CLASS_PIC12E) &&
1158       (class != PROC_CLASS_PIC12I)  && (class != PROC_CLASS_SX)     &&
1159       (class != PROC_CLASS_PIC14)   && (class != PROC_CLASS_PIC14E) &&
1160       (class != PROC_CLASS_PIC14EX) && (class != PROC_CLASS_PIC16)  &&
1161       (class != PROC_CLASS_PIC16E)) {
1162     return;
1163   }
1164 
1165   section_array  = NULL;
1166   num_sections   = 0;
1167   register_array = NULL;
1168   num_registers  = 0;
1169 
1170   gp_debug("Removing unnecessary banksel instructions.");
1171   num_registers  = 0;
1172   register_array = gp_symbol_make_register_array(Object, &num_registers);
1173 
1174   if (register_array == NULL) {
1175     return;
1176   }
1177 
1178   _reloc_pipe_clear();
1179   num_banks     = gp_processor_num_banks(Object->processor);
1180   first_section = Object->section_list.first;
1181 
1182   section = first_section;
1183   while (section != NULL) {
1184     first_banksel = false;
1185     _reloc_pipe_clear();
1186 
1187     if (gp_coffgen_section_has_data(section)) {
1188       num_sections  = 0;
1189       section_array = gp_coffgen_make_section_array(Object, &num_sections,
1190                               gp_processor_page_addr(class, gp_processor_insn_from_byte_c(class, section->address)),
1191                               STYP_ROM_AREA);
1192       _label_arrays_make(class);
1193       reloc_curr = section->relocation_list.first;
1194       if (reloc_curr != NULL) {
1195         i = 0;
1196         while (reloc_curr != NULL) {
1197           reloc_next = reloc_curr->next;
1198           may_remove = _banksel_reloc_analyze(class, processor, section, reloc_curr, num_banks);
1199 
1200           if (may_remove) {
1201             _banksel_remove(class, first_section, section);
1202           }
1203 
1204           reloc_curr = reloc_next;
1205           ++i;
1206         }
1207 
1208       }
1209 
1210       _label_arrays_free();
1211 
1212       if (section_array != NULL) {
1213         free(section_array);
1214       }
1215     } /* if (gp_coffgen_section_has_data(section)) */
1216 
1217     section = section->next;
1218   } /* while (section != NULL) */
1219 
1220   free(register_array);
1221 }
1222