1 /*-------------------------------------------------------------------------
2
3 pcoderegs.c - post code generation register optimizations
4
5 Written By - Scott Dattalo scott@dattalo.com
6 Ported To PIC16 By - m.dubuc@rogers.com
7
8 This program is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
11 later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21
22 -------------------------------------------------------------------------*/
23
24 /*
25 pcoderegs.c
26
27 The purpose of the code in this file is to optimize the register usage.
28
29 */
30 #include <stdio.h>
31
32 #include "common.h" // Include everything in the SDCC src directory
33 #include "newalloc.h"
34 #include "ralloc.h"
35 #include "device.h"
36 #include "pcode.h"
37 #include "pcoderegs.h"
38 #include "pcodeflow.h"
39
40
41 #define DEBUG_REMOVE1PCODE 0
42 #define HAVE_DBGREGUSAGE 0
43
44
45 extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
46 extern pCode * pic16_findPrevInstruction(pCode *pci);
47 extern pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n);
48 void pic16_unlinkpCode(pCode *pc);
49 extern int pic16_pCodeSearchCondition(pCode *pc, unsigned int cond);
50
51 static int total_registers_saved=0;
52 static int register_optimization=1;
53
54 /*-----------------------------------------------------------------*
55 * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
56 *-----------------------------------------------------------------*/
57 /*
58 void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
59 {
60
61 if(!reg || ! pcfl || !isPCFL(pcflow))
62 return;
63
64 if(!pcfl->registers)
65 pcfl->registers = newSet();
66
67 }
68 */
69
70
71 /*-----------------------------------------------------------------*
72 *
73 *-----------------------------------------------------------------*/
74
75 #if HAVE_DBGREGUSAGE
dbg_regusage(set * fregs)76 static void dbg_regusage(set *fregs)
77 {
78 reg_info *reg;
79 pCode *pcfl;
80 pCode *pc;
81
82
83 for (reg = setFirstItem(fregs) ; reg ;
84 reg = setNextItem(fregs)) {
85
86 if(elementsInSet(reg->reglives.usedpCodes)) {
87
88 fprintf (stderr, "%s addr=0x%03x rIdx=0x%03x",
89 reg->name,
90 reg->address,
91 reg->rIdx);
92
93 pcfl = setFirstItem(reg->reglives.usedpFlows);
94 if(pcfl)
95 fprintf(stderr, "\n used in seq");
96
97 while(pcfl) {
98 fprintf(stderr," 0x%03x",pcfl->seq);
99 pcfl = setNextItem(reg->reglives.usedpFlows);
100 }
101
102 pcfl = setFirstItem(reg->reglives.assignedpFlows);
103 if(pcfl)
104 fprintf(stderr, "\n assigned in seq");
105
106 while(pcfl) {
107 fprintf(stderr," 0x%03x",pcfl->seq);
108 pcfl = setNextItem(reg->reglives.assignedpFlows);
109 }
110
111 pc = setFirstItem(reg->reglives.usedpCodes);
112 if(pc)
113 fprintf(stderr, "\n used in instructions ");
114
115 while(pc) {
116 pcfl = PCODE(PCI(pc)->pcflow);
117 if(pcfl)
118 fprintf(stderr," 0x%03x:",pcfl->seq);
119 fprintf(stderr,"0x%03x",pc->seq);
120
121 pc = setNextItem(reg->reglives.usedpCodes);
122 }
123
124 fprintf(stderr, "\n");
125 }
126 }
127 }
128
129 /*-----------------------------------------------------------------*
130 *
131 *-----------------------------------------------------------------*/
132
133 //static
dbg_dumpregusage(void)134 void dbg_dumpregusage(void)
135 {
136
137 fprintf(stderr,"*** Register Usage ***\n");
138 fprintf(stderr,"InternalRegs:\n");
139 dbg_regusage(pic16_dynInternalRegs);
140 fprintf(stderr,"AllocRegs:\n");
141 dbg_regusage(pic16_dynAllocRegs);
142 fprintf(stderr,"StackRegs:\n");
143 dbg_regusage(pic16_dynStackRegs);
144 fprintf(stderr,"DirectRegs:\n");
145 dbg_regusage(pic16_dynDirectRegs);
146 fprintf(stderr,"DirectBitRegs:\n");
147 dbg_regusage(pic16_dynDirectBitRegs);
148 fprintf(stderr,"ProcessorRegs:\n");
149 dbg_regusage(pic16_dynProcessorRegs);
150
151 }
152 #endif
153
154 /*-----------------------------------------------------------------*
155 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
156 *-----------------------------------------------------------------*/
pCodeRegMapLiveRangesInFlow(pCodeFlow * pcfl)157 static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
158 {
159 pCode *pc=NULL;
160
161 reg_info *reg;
162
163 if(!pcfl)
164 return;
165
166
167 pc = pic16_findNextInstruction(pcfl->pc.next);
168
169 while (pic16_isPCinFlow(pc,PCODE(pcfl)))
170 {
171 reg = pic16_getRegFromInstruction(pc);
172
173 if (reg && (reg->type != REG_TMP))
174 {
175 #if 0
176 fprintf(stderr, "reg= %p\n", reg);
177 fprintf(stderr, "flow seq %d, inst seq %d %s ",PCODE(pcfl)->seq,pc->seq,reg->name);
178 fprintf(stderr, "addr = 0x%03x, type = %d rIdx=0x%03x ",
179 reg->address,reg->type,reg->rIdx);
180 fprintf(stderr, "command = %s\n", PCI(pc)->mnemonic);
181 #endif
182
183 //fprintf(stderr, "%s:%d: trying to get first operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
184 addSetIfnotP(& (PCFL(pcfl)->registers), reg);
185
186 if ((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
187 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
188
189 if (PCC_REGISTER & PCI(pc)->outCond)
190 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
191
192 addSetIfnotP(& (reg->reglives.usedpCodes), pc);
193
194 //reg->wasUsed=1;
195
196 #if 1
197 /* check to see if this pCode has 2 memory operands,
198 and set up the second operand too */
199 if (PCI(pc)->is2MemOp)
200 {
201 reg = pic16_getRegFromInstruction2(pc);
202 if (reg)
203 {
204 //fprintf(stderr, "%s:%d: trying to get second operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
205 addSetIfnotP(& (PCFL(pcfl)->registers), reg);
206
207 if ((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
208 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
209
210 if ((PCC_REGISTER | PCC_REGISTER2) & PCI(pc)->outCond)
211 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
212
213 addSetIfnotP(& (reg->reglives.usedpCodes), pc);
214
215 //reg->wasUsed=1;
216 } // if
217 } // if
218 #endif
219 } // if
220
221 pc = pic16_findNextInstruction(pc->next);
222 } // while
223 }
224
225 /*-----------------------------------------------------------------*
226 * void pic16_pCodeRegMapLiveRanges(pBlock *pb)
227 *-----------------------------------------------------------------*/
pic16_pCodeRegMapLiveRanges(pBlock * pb)228 void pic16_pCodeRegMapLiveRanges(pBlock *pb)
229 {
230 pCode *pcflow;
231
232 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
233 pcflow != NULL;
234 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
235
236 if(!isPCFL(pcflow)) {
237 fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
238 continue;
239 }
240 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
241 }
242
243 #if 0
244 for( pcflow = pic16_findNextpCode(pb->pcHead, PC_FLOW);
245 pcflow != NULL;
246 pcflow = pic16_findNextpCode(pcflow->next, PC_FLOW) ) {
247
248 regs *r = setFirstItem(PCFL(pcflow)->registers);
249 fprintf(stderr,"flow seq %d\n", pcflow->seq);
250
251 while (r) {
252 fprintf(stderr, " %s\n",r->name);
253 r = setNextItem(PCFL(pcflow)->registers);
254
255 }
256
257 }
258 #endif
259
260 #if HAVE_DBGREGUSAGE
261 dbg_dumpregusage();
262 #endif
263
264 }
265
266
267 /*-----------------------------------------------------------------*
268 *
269 *-----------------------------------------------------------------*/
Remove1pcode(pCode * pc,reg_info * reg)270 static void Remove1pcode(pCode *pc, reg_info *reg)
271 {
272 pCode *pcn=NULL;
273
274 if(!reg || !pc)
275 return;
276
277 deleteSetItem (&(reg->reglives.usedpCodes),pc);
278
279 #if DEBUG_REMOVE1PCODE
280 fprintf(stderr,"removing instruction:\n");
281 pc->print(stderr,pc);
282 #endif
283
284 if(PCI(pc)->label) {
285 pcn = pic16_findNextInstruction(pc->next);
286
287 if(pcn)
288 PCI(pcn)->label = pic16_pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
289 }
290
291 if(PCI(pc)->cline) {
292 if(!pcn)
293 pcn = pic16_findNextInstruction(pc->next);
294
295 if(pcn) {
296 if(PCI(pcn)->cline) {
297
298 #if DEBUG_REMOVE1PCODE
299 fprintf(stderr, "source line has been optimized completely out\n");
300 pc->print(stderr,pc);
301 #endif
302
303 } else {
304 PCI(pcn)->cline = PCI(pc)->cline;
305 }
306 }
307 }
308
309 pc->destruct(pc);
310
311 }
312
313 /*-----------------------------------------------------------------*
314 * void RemoveRegsFromSet(set *regset)
315 *
316 *-----------------------------------------------------------------*/
RemoveRegsFromSet(set * regset)317 static void RemoveRegsFromSet(set *regset)
318 {
319 reg_info *reg;
320 int used;
321
322 while(regset) {
323 reg = regset->item;
324 regset = regset->next;
325
326 used = elementsInSet(reg->reglives.usedpCodes);
327
328 if(used <= 1) {
329
330 // fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
331
332 if(used == 0) {
333
334 // fprintf(stderr,"%s:%d: getting rid of reg %s\n",__FILE__, __LINE__, reg->name);
335
336 reg->isFree = 1;
337 reg->wasUsed = 0;
338 } else {
339 pCode *pc;
340
341
342 pc = setFirstItem(reg->reglives.usedpCodes);
343
344 if(reg->type == REG_SFR) {
345 fprintf(stderr, "not removing SFR reg %s even though used only once\n", reg->name);
346 continue;
347 }
348
349 if(isPCI(pc)) {
350 if(PCI(pc)->label) {
351 pCode *pcn = pic16_findNextInstruction(pc->next);
352
353 if(pcn && PCI(pcn)->label) {
354 //fprintf(stderr,"can't delete instruction with label...\n");
355 //pc->print(stderr,pc);
356 continue;
357 }
358 /* Move the label to the next instruction */
359
360 assert (PCI(pcn) != NULL);
361 PCI(pcn)->label = PCI(pc)->label;
362
363 }
364
365 if(isPCI_SKIP(pc)) {
366 reg_info *r = pic16_getRegFromInstruction(pc);
367 fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
368 pc->print(stderr,pc);
369 fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
370 }
371
372 Remove1pcode(pc, reg);
373 /*
374 pic16_unlinkpCode(pc);
375 deleteSetItem (&(reg->reglives.usedpCodes),pc);
376 */
377 reg->isFree = 1;
378 reg->wasUsed = 0;
379 total_registers_saved++; // debugging stats.
380 }
381 }
382 }
383
384 }
385 }
386 /*-----------------------------------------------------------------*
387 * void pic16_RemoveUnusedRegisters(void)
388 *
389 *-----------------------------------------------------------------*/
pic16_RemoveUnusedRegisters(void)390 void pic16_RemoveUnusedRegisters(void)
391 {
392 /* First, get rid of registers that are used only one time */
393
394 //RemoveRegsFromSet(pic16_dynInternalRegs);
395 RemoveRegsFromSet(pic16_dynAllocRegs);
396 RemoveRegsFromSet(pic16_dynStackRegs);
397 /*
398 don't do DirectRegs yet - there's a problem with arrays
399 RemoveRegsFromSet(pic16_dynDirectRegs);
400 */
401 RemoveRegsFromSet(pic16_dynDirectBitRegs);
402
403 if(total_registers_saved && pic16_pcode_verbose)
404 fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved);
405 }
406
insideLRBlock(pCode * pc)407 static int insideLRBlock(pCode *pc)
408 {
409 pCode *pc1;
410 int t1=-1, t2=-1;
411
412 pc1 = pc->prev;
413 while(pc1) {
414 if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
415 t1 = PCOLR (PCINF (pc1)->oper1)->type;
416 break;
417 }
418 pc1 = pc1->prev;
419 }
420
421 pc1 = pc->next;
422 while(pc1) {
423 if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
424 t2 = PCOLR (PCINF (pc1)->oper1)->type;
425 break;
426 }
427 pc1 = pc1->next;
428 }
429
430 if((t1 == LR_ENTRY_BEGIN && t2 == LR_ENTRY_END)
431 || (t1 == LR_EXIT_BEGIN && t2 == LR_EXIT_END))
432 return 1;
433
434 return 0;
435 }
436
437
RemoveRegFromLRBlock(reg_info * reg)438 static void RemoveRegFromLRBlock(reg_info *reg)
439 {
440 if(elementsInSet(reg->reglives.usedpCodes) == 2) {
441 pCode *pc1;
442
443 /* only continue if there are just 2 uses of the register,
444 * in in the local *entry* block and one in the local *exit* block */
445
446 /* search for entry block */
447 pc1 = indexSet(reg->reglives.usedpCodes, 1);
448
449 if(insideLRBlock( pc1 )) {
450 fprintf(stderr, "usedpCodes[0] inside LR block\n");
451 deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
452 Remove1pcode(pc1, reg);
453 }
454
455 pc1 = indexSet(reg->reglives.usedpCodes, 0);
456 if(insideLRBlock( pc1 )) {
457 fprintf(stderr, "usedpCodes[1] inside LR block\n");
458 deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
459 Remove1pcode(pc1, reg);
460 }
461
462 /* remove r0x00 */
463 reg->isFree = 1;
464 reg->wasUsed = 0;
465 }
466 }
467
468
469
470 /*-----------------------------------------------------------------*
471 *
472 *-----------------------------------------------------------------*/
Remove2pcodes(pCode * pcflow,pCode * pc1,pCode * pc2,reg_info * reg,int can_free)473 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, reg_info *reg, int can_free)
474 {
475 if(!reg)
476 return;
477
478 #if 0
479 fprintf(stderr,"removing 2 instructions:\n");
480 pc1->print(stderr,pc1);
481 pc2->print(stderr,pc2);
482 #endif
483
484 if(pc1)
485 Remove1pcode(pc1, reg);
486
487 if(pc2) {
488 Remove1pcode(pc2, reg);
489 deleteSetItem (&(PCFL(pcflow)->registers), reg);
490
491 if(can_free) {
492 reg->isFree = 1;
493 reg->wasUsed = 0;
494 }
495
496 }
497
498 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
499
500 #if 1
501 // fprintf(stderr, "register %s is used in %d pCodes, assigned in %d pCodes\n", reg->name,
502 // elementsInSet(reg->reglives.usedpCodes),
503 // elementsInSet(reg->reglives.assignedpFlows));
504
505 RemoveRegFromLRBlock(reg);
506 #endif
507
508 }
509
510 /*-----------------------------------------------------------------*
511 *
512 *-----------------------------------------------------------------*/
regUsedinRange(pCode * pc1,pCode * pc2,reg_info * reg)513 static int regUsedinRange(pCode *pc1, pCode *pc2, reg_info *reg)
514 {
515 int i=0;
516 reg_info *testreg;
517
518 do {
519 testreg = pic16_getRegFromInstruction(pc1);
520 if(testreg && (testreg->rIdx == reg->rIdx)) {
521 return 1;
522 }
523
524 if(PCI(pc1)->is2MemOp) {
525 testreg = pic16_getRegFromInstruction2(pc1);
526 if(testreg && (testreg->rIdx == reg->rIdx)) {
527 return 1;
528 }
529 }
530
531 pc1 = pic16_findNextInstruction(pc1->next);
532
533 } while (pc1 && (pc1 != pc2) && (i++ < 100)) ;
534
535 if(i >= 100)
536 fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
537
538 return 0;
539 }
540
541 /*-----------------------------------------------------------------*
542 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2)
543 *
544 * ADHOC pattern checking
545 * Now look for specific sequences that are easy to optimize.
546 * Many of these sequences are characteristic of the compiler
547 * (i.e. it'd probably be a waste of time to apply these adhoc
548 * checks to hand written assembly.)
549 *
550 *
551 *-----------------------------------------------------------------*/
pCodeOptime2pCodes(pCode * pc1,pCode * pc2,pCode * pcfl_used,reg_info * reg,int can_free,int optimize_level)552 static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, reg_info *reg, int can_free, int optimize_level)
553 {
554 pCode *pct1, *pct2;
555 reg_info *reg1, *reg2;
556
557 int t = total_registers_saved;
558
559 if(reg->type == REG_SFR)return 0;
560
561 if(pc2->seq < pc1->seq) {
562 pct1 = pc2;
563 pc2 = pc1;
564 pc1 = pct1;
565 }
566 /*
567 fprintf(stderr,"pCodeOptime2pCodes\n");
568 pc1->print(stderr,pc1);
569 pc2->print(stderr,pc2);
570 */
571 if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
572
573 /*
574 clrf reg
575 stuff...
576 movf reg,w
577
578 can be replaced with
579
580 stuff...
581 movlw 0
582 */
583
584 pCode *newpc;
585 //fprintf(stderr, " CLRF/MOVFW. instruction after MOVFW is:\n");
586 pct1 = pic16_findNextInstruction(pc2->next);
587
588 if(PCI(pct1)->op == POC_MOVWF) {
589 newpc = pic16_newpCode(POC_CLRF, PCI(pct1)->pcop);
590 pct1->destruct(pct1);
591 } else {
592 newpc = pic16_newpCode(POC_MOVLW, pic16_newpCodeOpLit(0));
593 }
594
595 pic16_pCodeInsertAfter(pc2, newpc);
596 PCI(newpc)->pcflow = PCFL(pcfl_used);
597 newpc->seq = pc2->seq;
598
599 /* take care if register is used after pc2, if yes, then don't delete
600 * clrf reg, because, reg should be initialized with zero */
601 {
602 pCode *spc;
603 int maxSeq=0;
604
605 for(spc=setFirstItem(reg->reglives.usedpCodes);spc;spc=setNextItem(reg->reglives.usedpCodes)) {
606 if(maxSeq < spc->seq)maxSeq = spc->seq;
607 }
608
609 // fprintf(stderr, "pc1->seq = %d\tpc2->seq = %d\tspc->seq = %d\n", pc1->seq, pc2->seq, maxSeq);
610
611 if(maxSeq > pc2->seq) {
612 /* this means that a pCode uses register after pc2, then
613 * we can't delete pc1 pCode */
614 Remove2pcodes(pcfl_used, NULL, pc2, reg, can_free);
615 } else {
616 /* we can remove both pCodes */
617 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
618 }
619 }
620 total_registers_saved++; // debugging stats.
621
622 } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
623 //fprintf(stderr, " CLRF/IORFW.\n");
624
625 pct2 = pic16_findNextInstruction(pc2->next);
626
627 if(pic16_pCodeSearchCondition(pct2, PCC_Z) > 0) {
628 pct2 = pic16_newpCode(POC_IORLW, pic16_newpCodeOpLit(0));
629 pct2->seq = pc2->seq;
630 PCI(pct2)->pcflow = PCFL(pcfl_used);
631 pic16_pCodeInsertAfter(pc1,pct2);
632 }
633 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
634 total_registers_saved++; // debugging stats.
635
636 } else if(PCI(pc1)->op == POC_MOVWF) {
637
638 reg1 = pic16_getRegFromInstruction(pc1);
639
640 if(reg1->type == REG_SFR)return (total_registers_saved != t);
641
642 pct2 = pic16_findNextInstruction(pc2->next);
643
644 if(PCI(pc2)->op == POC_MOVFW) {
645
646 #if 0
647 fprintf(stderr, " MOVWF/MOVFW. instruction after MOVFW is:\n");
648 pct2->print(stderr,pct2);
649 #endif
650
651 if(PCI(pct2)->op == POC_MOVWF) {
652 /*
653 Change:
654
655 movwf reg
656
657 stuff...
658
659 movf reg,w
660 movwf reg2
661
662 To:
663
664
665 */
666 reg2 = pic16_getRegFromInstruction(pct2);
667 if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) {
668 // if(reg2 && !regUsedinRange(pc1,pc2,reg2))
669
670 if(pic16_pCodeSearchCondition(pct2, PCC_Z) < 1) {
671 pCode *pct3 = pic16_findNextInstruction(pct2->next);
672 pct2->seq = pc1->seq;
673 pic16_unlinkpCode(pct2);
674 pic16_pCodeInsertAfter(pic16_findPrevInstruction(pc1->prev),pct2);
675
676 #define usesW(x) ((x) && (isPCI(x)) && ( (PCI(x)->inCond & PCC_W) != 0))
677
678 if(usesW(pct3))
679 ; // Remove2pcodes(pcfl_used, pc1, NULL, reg, can_free);
680 else {
681 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
682 total_registers_saved++; // debugging stats.
683 return 1;
684 }
685 } else {
686 // fprintf(stderr,"didn't optimize because Z bit is used\n");
687 }
688 }
689 #if 0
690 fprintf(stderr, " couldn't optimize\n");
691 if(reg2)
692 fprintf(stderr, " %s is used in range\n", reg2->name);
693 else
694 fprintf(stderr, " reg2 is NULL\n");
695 #endif
696 }
697 }
698
699 pct1 = pic16_findPrevInstruction(pc1->prev);
700 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
701
702 if ( (PCI(pct1)->op == POC_MOVFW) &&
703 (PCI(pc2)->op == POC_MOVFW)) {
704
705 reg1 = pic16_getRegFromInstruction(pct1);
706 if(reg1 && !regUsedinRange(pc1,pc2,reg1)) {
707
708 #if 0
709 fprintf(stderr, " MOVF/MOVFW. \n");
710 fprintf(stderr, " ...optimizing\n");
711 #endif
712
713 /*
714 Change:
715
716 movf reg1,w
717 movwf reg
718
719 stuff...
720 movf reg,w
721
722 To:
723
724 stuff...
725
726 movf reg1,w
727
728 Or, if we're not deleting the register then the "To" is:
729
730 stuff...
731
732 movf reg1,w
733 movwf reg
734
735
736 */
737 pct2 = pic16_newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
738 pic16_pCodeInsertAfter(pc2, pct2);
739 PCI(pct2)->pcflow = PCFL(pcfl_used);
740 pct2->seq = pc2->seq;
741
742 if(can_free) {
743 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
744 } else {
745 /* If we're not freeing the register then that means (probably)
746 * the register is needed somewhere else.*/
747 pic16_unlinkpCode(pc1);
748 pic16_pCodeInsertAfter(pct2, pc1);
749
750 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
751 }
752
753 Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
754 total_registers_saved++; // debugging stats.
755
756 }
757 } else if ( (PCI(pct1)->op == POC_MOVWF) &&
758 (PCI(pc2)->op == POC_MOVFW)) {
759
760 // fprintf(stderr,"movwf MOVWF/MOVFW\n");
761
762 if(optimize_level > 1 && can_free) {
763 pct2 = pic16_newpCode(POC_MOVFW, PCI(pc1)->pcop);
764 pic16_pCodeInsertAfter(pc2, pct2);
765 Remove2pcodes(pcfl_used, pc1, pc2, reg, 1);
766 total_registers_saved++; // debugging stats.
767 }
768 }
769
770
771 }
772
773 }
774
775 return (total_registers_saved != t);
776 }
777
778 /*-----------------------------------------------------------------*
779 * void pCodeRegOptimeRegUsage(pBlock *pb)
780 *-----------------------------------------------------------------*/
OptimizeRegUsage(set * fregs,int optimize_multi_uses,int optimize_level)781 static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
782 {
783 reg_info *reg;
784 int used;
785 pCode *pc1=NULL, *pc2=NULL;
786
787
788 while(fregs) {
789 pCode *pcfl_used, *pcfl_assigned;
790
791 /* Step through the set by directly accessing the 'next' pointer.
792 * We could also step through by using the set API, but the
793 * the (debug) calls to print instructions affect the state
794 * of the set pointers */
795
796 reg = fregs->item;
797 fregs = fregs->next;
798
799 if(reg->type == REG_SFR) {
800 // fprintf(stderr,"skipping SFR: %s\n",reg->name);
801 continue;
802 }
803
804 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
805 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
806
807 used = elementsInSet(reg->reglives.usedpCodes);
808 // fprintf(stderr, "%s:%d register %s used %d times in pCode\n", __FILE__, __LINE__, reg->name, used);
809 if(used == 2) {
810
811 /*
812 * In this section, all registers that are used in only in two
813 * instructions are examined. If possible, they're optimized out.
814 */
815
816 #if 0
817 fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
818 reg->name,
819 reg->address,
820 reg->rIdx, reg->type, used);
821 #endif
822
823 pc1 = setFirstItem(reg->reglives.usedpCodes);
824 pc2 = setNextItem(reg->reglives.usedpCodes);
825
826 if(pcfl_used && pcfl_assigned) {
827
828 /*
829 expected case - the register has been assigned a value and is
830 subsequently used
831 */
832
833 //fprintf(stderr," used only twice\n");
834 if(pcfl_used->seq == pcfl_assigned->seq && !(setNextItem(reg->reglives.usedpFlows)) && !(setNextItem(reg->reglives.assignedpFlows))) {
835
836 //fprintf(stderr, " and used in same flow\n");
837
838 pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
839
840 } else {
841 // fprintf(stderr, " and used in different flows\n");
842
843 }
844
845 } else if(pcfl_used) {
846
847 /*
848 register has been used twice without ever being assigned */
849 //fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
850
851 } else {
852 // fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
853 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
854 total_registers_saved++; // debugging stats.
855 }
856 } else {
857
858 /* register has been used either once, or more than twice */
859
860 if(used && !pcfl_used && pcfl_assigned) {
861 pCode *pc;
862
863 fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
864
865 pc = setFirstItem(reg->reglives.usedpCodes);
866 while(pc) {
867
868 pcfl_assigned = PCODE(PCI(pc)->pcflow);
869 Remove1pcode(pc, reg);
870
871 deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
872 /*
873 deleteSetItem (&(reg->reglives.usedpCodes),pc);
874 pc->destruct(pc);
875 */
876 pc = setNextItem(reg->reglives.usedpCodes);
877 }
878
879
880 reg->isFree = 1;
881 reg->wasUsed = 0;
882
883 total_registers_saved++; // debugging stats.
884 } else if( (used > 2) && optimize_multi_uses) {
885
886 set *rset1=NULL;
887 set *rset2=NULL;
888 int searching=1;
889
890 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
891
892 /* examine the number of times this register is used */
893
894
895 rset1 = reg->reglives.usedpCodes;
896 while(rset1 && searching) {
897
898 pc1 = rset1->item;
899 rset2 = rset1->next;
900
901 if(pc1 && isPCI(pc1) && ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
902
903 //while(rset2 && searching) {
904 if(rset2) {
905
906 pc2 = rset2->item;
907 if(pc2 && isPCI(pc2) && ( (pcfl2 = PCI(pc2)->pcflow) != NULL) ) {
908 if(pcfl2 == pcfl1) {
909
910 if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
911 searching = 0;
912 }
913 }
914
915 //rset2 = rset2->next;
916
917 }
918 }
919 rset1 = rset1->next;
920 }
921 }
922 }
923
924 }
925
926 }
927 /*-----------------------------------------------------------------*
928 * void pic16_pCodeRegOptimeRegUsage(pBlock *pb)
929 *-----------------------------------------------------------------*/
pic16_pCodeRegOptimizeRegUsage(int level)930 void pic16_pCodeRegOptimizeRegUsage(int level)
931 {
932
933 int passes;
934 int saved = 0;
935 int t = total_registers_saved;
936
937 if(getenv("NO_REG_OPT"))
938 return;
939
940 if(!register_optimization)
941 return;
942
943 #define OPT_PASSES 8
944 passes = OPT_PASSES;
945
946 do {
947 saved = total_registers_saved;
948
949 /* Identify registers used in one flow sequence */
950 OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes));
951 OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes));
952 OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes));
953
954 if((total_registers_saved != saved)
955 && (pic16_pcode_verbose))
956 fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n",
957 (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved);
958
959 passes--;
960
961 } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
962
963 if(total_registers_saved == t)
964 if(pic16_debug_verbose)
965 fprintf(stderr, "No registers saved on this pass\n");
966
967
968 #if 0
969 fprintf(stderr,"dynamically allocated regs:\n");
970 dbg_regusage(pic16_dynAllocRegs);
971 fprintf(stderr,"stack regs:\n");
972 dbg_regusage(pic16_dynStackRegs);
973 fprintf(stderr,"direct regs:\n");
974 dbg_regusage(pic16_dynDirectRegs);
975 #endif
976 }
977
978
979 /*-----------------------------------------------------------------*
980 * void RegsUnMapLiveRanges(set *regset)
981 *
982 *-----------------------------------------------------------------*/
RegsSetUnMapLiveRanges(set * regset)983 static void RegsSetUnMapLiveRanges(set *regset)
984 {
985 reg_info *reg;
986
987 while(regset) {
988 reg = regset->item;
989 regset = regset->next;
990
991 deleteSet(®->reglives.usedpCodes);
992 deleteSet(®->reglives.usedpFlows);
993 deleteSet(®->reglives.assignedpFlows);
994
995 }
996
997 }
998
pic16_RegsUnMapLiveRanges(void)999 void pic16_RegsUnMapLiveRanges(void)
1000 {
1001 RegsSetUnMapLiveRanges(pic16_dynAllocRegs);
1002 RegsSetUnMapLiveRanges(pic16_dynStackRegs);
1003 RegsSetUnMapLiveRanges(pic16_dynDirectRegs);
1004 RegsSetUnMapLiveRanges(pic16_dynProcessorRegs);
1005 RegsSetUnMapLiveRanges(pic16_dynDirectBitRegs);
1006 RegsSetUnMapLiveRanges(pic16_dynInternalRegs);
1007 }
1008