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(&reg->reglives.usedpCodes);
992     deleteSet(&reg->reglives.usedpFlows);
993     deleteSet(&reg->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