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