Slade Rich fixed an optimization bug
[fw/sdcc] / src / pic / pcoderegs.c
1 /*-------------------------------------------------------------------------
2
3    pcoderegs.c - post code generation register optimizations
4
5    Written By -  Scott Dattalo scott@dattalo.com
6
7    This program is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by the
9    Free Software Foundation; either version 2, or (at your option) any
10    later version.
11    
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16    
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20    
21 -------------------------------------------------------------------------*/
22
23 /*
24   pcoderegs.c
25
26   The purpose of the code in this file is to optimize the register usage.
27
28 */
29 #include <stdio.h>
30
31 #include "common.h"   // Include everything in the SDCC src directory
32 #include "newalloc.h"
33 #include "ralloc.h"
34 #include "device.h"
35 #include "pcode.h"
36 #include "pcoderegs.h"
37 #include "pcodeflow.h"
38
39 extern void dbg_dumpregusage(void);
40 extern pCode * findPrevInstruction(pCode *pci);
41 extern pBranch * pBranchAppend(pBranch *h, pBranch *n);
42 void unlinkpCode(pCode *pc);
43 extern int pCodeSearchCondition(pCode *pc, unsigned int cond, int contIfSkip);
44 char *pCode2str(char *str, int size, pCode *pc);
45 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...);
46 int total_registers_saved=0;
47 int register_optimization=1;
48
49 /*-----------------------------------------------------------------*
50  * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
51  *-----------------------------------------------------------------*/
52 /*
53 void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
54 {
55
56   if(!reg || ! pcfl || !isPCFL(pcflow))
57     return;
58
59   if(!pcfl->registers) 
60     pcfl->registers =  newSet();
61
62 }
63 */
64
65
66 /*-----------------------------------------------------------------*
67  * 
68  *-----------------------------------------------------------------*/
69 void dbg_regusage(set *fregs)
70 {
71   regs *reg;
72   pCode *pcfl;
73   pCode *pc;
74
75
76   for (reg = setFirstItem(fregs) ; reg ;
77        reg = setNextItem(fregs)) {
78
79     if(elementsInSet(reg->reglives.usedpCodes)) {
80     
81       fprintf (stderr, "%s  addr=0x%03x rIdx=0x%03x",
82                reg->name,
83                reg->address,
84                reg->rIdx);
85
86       pcfl = setFirstItem(reg->reglives.usedpFlows);
87       if(pcfl)
88         fprintf(stderr, "\n   used in seq");
89
90       while(pcfl) {
91         fprintf(stderr," 0x%03x",pcfl->seq);
92         pcfl = setNextItem(reg->reglives.usedpFlows);
93       }
94
95       pcfl = setFirstItem(reg->reglives.assignedpFlows);
96       if(pcfl)
97         fprintf(stderr, "\n   assigned in seq");
98
99       while(pcfl) {
100         fprintf(stderr," 0x%03x",pcfl->seq);
101         pcfl = setNextItem(reg->reglives.assignedpFlows);
102       }
103
104       pc = setFirstItem(reg->reglives.usedpCodes);
105       if(pc)
106         fprintf(stderr, "\n   used in instructions ");
107
108       while(pc) {
109         pcfl = PCODE(PCI(pc)->pcflow);
110         if(pcfl)
111           fprintf(stderr," 0x%03x:",pcfl->seq);
112         fprintf(stderr,"0x%03x",pc->seq);
113
114         pc = setNextItem(reg->reglives.usedpCodes);
115       }
116
117       fprintf(stderr, "\n");
118     }
119   }
120 }
121
122 /*-----------------------------------------------------------------*
123  * 
124  *-----------------------------------------------------------------*/
125 void dbg_dumpregusage(void)
126 {
127
128   fprintf(stderr,"***  Register Usage  ***\n");
129   fprintf(stderr,"InternalRegs:\n");
130   dbg_regusage(dynInternalRegs);
131   fprintf(stderr,"AllocRegs:\n");
132   dbg_regusage(dynAllocRegs);
133   fprintf(stderr,"StackRegs:\n");
134   dbg_regusage(dynStackRegs);
135   fprintf(stderr,"DirectRegs:\n");
136   dbg_regusage(dynDirectRegs);
137   fprintf(stderr,"DirectBitRegs:\n");
138   dbg_regusage(dynDirectBitRegs);
139   fprintf(stderr,"ProcessorRegs:\n");
140   dbg_regusage(dynProcessorRegs);
141
142 }
143
144
145 /*-----------------------------------------------------------------*
146  * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
147  *-----------------------------------------------------------------*/
148 void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
149 {
150
151   pCode *pc=NULL;
152   pCode *pcprev=NULL;
153
154   regs *reg;
155
156   if(!pcfl)
157     return;
158
159
160   pc = findNextInstruction(pcfl->pc.next);
161
162   while(isPCinFlow(pc,PCODE(pcfl))) {
163
164
165     reg = getRegFromInstruction(pc);
166
167     if(reg) {
168 /*
169       fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
170       fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x\n",
171               reg->address,reg->type,reg->rIdx);
172 */
173
174       addSetIfnotP(& (PCFL(pcfl)->registers), reg);
175
176       if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
177         addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
178
179       if(PCC_REGISTER & PCI(pc)->outCond)
180         addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
181
182       addSetIfnotP(& (reg->reglives.usedpCodes), pc);
183     }
184
185
186     pcprev = pc;
187     pc = findNextInstruction(pc->next);
188
189   }
190
191 }
192
193 /*-----------------------------------------------------------------*
194  * void pCodeRegMapLiveRanges(pBlock *pb) 
195  *-----------------------------------------------------------------*/
196 void pCodeRegMapLiveRanges(pBlock *pb)
197 {
198   pCode *pcflow;
199
200   for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
201        pcflow != NULL;
202        pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
203
204     if(!isPCFL(pcflow)) {
205       fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
206       continue;
207     }
208     pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
209   }
210
211 #if 0
212   for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
213        pcflow != NULL;
214        pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
215
216     regs *r = setFirstItem(PCFL(pcflow)->registers);
217     fprintf(stderr,"flow seq %d\n", pcflow->seq);
218
219     while (r) {
220       fprintf(stderr, "  %s\n",r->name);
221       r = setNextItem(PCFL(pcflow)->registers);
222
223     }
224
225   }
226 #endif
227
228 //  dbg_dumpregusage();
229
230 }
231
232
233 /*-----------------------------------------------------------------*
234  *
235  *-----------------------------------------------------------------*/
236 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
237 {
238
239   pCode *pcn=NULL;
240
241   if(!reg || !pc)
242     return;
243
244   deleteSetItem (&(reg->reglives.usedpCodes),pc);
245
246   if(PCI(pc)->label) {
247     pcn = findNextInstruction(pc->next);
248
249     if(pcn)
250       PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
251   }
252
253   if(PCI(pc)->cline) {
254     if(!pcn)
255       pcn = findNextInstruction(pc->next);
256
257     if(pcn) {
258       if(PCI(pcn)->cline) {
259         //fprintf(stderr, "source line has been optimized completely out\n");
260         //pc->print(stderr,pc);
261       } else {
262         PCI(pcn)->cline = PCI(pc)->cline;
263       }
264     }
265   }
266
267
268   if(1){
269     /*
270       Debug stuff. Comment out the instruction we're about to delete.
271     */
272
273     char buff1[256];
274     size_t size = 256;
275
276     char *pbuff,**ppbuff;
277     pbuff = buff1;
278     ppbuff = &pbuff;
279
280     SAFE_snprintf(ppbuff,&size, ";%d", debug_code);
281     pCode2str(*ppbuff, size, pc);
282     pCodeInsertBefore(pc, newpCodeCharP(buff1));
283     //fprintf(stderr,"removing instruction:\n%s\n",buff1);
284   }
285
286   pc->destruct(pc);
287
288 }
289
290 /*-----------------------------------------------------------------*
291  * void RemoveRegsFromSet(set *regset)
292  *
293  *-----------------------------------------------------------------*/
294 void  RemoveRegsFromSet(set *regset)
295 {
296   regs *reg;
297   int used;
298
299   while(regset) {
300     reg = regset->item;
301     regset = regset->next;
302
303     used = elementsInSet(reg->reglives.usedpCodes);
304
305     if(used <= 1) {
306
307       //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
308       if(used == 0) {
309         //fprintf(stderr," getting rid of reg %s\n",reg->name);
310         reg->isFree = 1;
311         reg->wasUsed = 0;
312       } else {
313         pCode *pc;
314
315
316         pc = setFirstItem(reg->reglives.usedpCodes);
317
318     if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
319           //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
320           continue;
321         }
322
323
324         if(isPCI(pc)) {
325           if(PCI(pc)->label) {
326             pCode *pcn = findNextInstruction(pc->next);
327
328             if(pcn && PCI(pcn)->label) {
329               //fprintf(stderr,"can't delete instruction with label...\n");
330               //pc->print(stderr,pc);
331               continue;
332             } 
333             /* Move the label to the next instruction */
334
335             PCI(pcn)->label = PCI(pc)->label;
336
337           }
338
339           if(isPCI_SKIP(pc)) {
340             regs *r = getRegFromInstruction(pc);
341             fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
342             pc->print(stderr,pc);
343             fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
344           }
345           //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
346           Remove1pcode(pc, reg, 1);
347           /*
348             unlinkpCode(pc);
349             deleteSetItem (&(reg->reglives.usedpCodes),pc);
350           */
351           reg->isFree = 1;
352           reg->wasUsed = 0;
353           total_registers_saved++;  // debugging stats.
354         }
355       }
356     }
357
358   }
359 }
360 /*-----------------------------------------------------------------*
361  * void RemoveUnusedRegisters(void)
362  *
363  *-----------------------------------------------------------------*/
364 void RemoveUnusedRegisters(void)
365 {
366   /* First, get rid of registers that are used only one time */
367
368   //RemoveRegsFromSet(dynInternalRegs);
369   RemoveRegsFromSet(dynAllocRegs);
370   RemoveRegsFromSet(dynStackRegs);
371   /*
372     don't do DirectRegs yet - there's a problem with arrays
373   RemoveRegsFromSet(dynDirectRegs);
374   */
375   RemoveRegsFromSet(dynDirectBitRegs);
376
377   if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
378 }
379
380
381 /*-----------------------------------------------------------------*
382  *
383  *-----------------------------------------------------------------*/
384 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free)
385 {
386   static int debug_code=99;
387   if(!reg)
388     return;
389
390   //fprintf(stderr,"%s\n",__FUNCTION__);
391   if(pc1)
392     Remove1pcode(pc1, reg, debug_code++);
393
394   if(pc2) {
395     Remove1pcode(pc2, reg, debug_code++);
396     deleteSetItem (&(PCFL(pcflow)->registers), reg);
397
398     if(can_free) {
399       reg->isFree = 1;
400       reg->wasUsed = 0;
401     }
402
403   }
404
405   pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
406 }
407
408 /*-----------------------------------------------------------------*
409  *
410  *-----------------------------------------------------------------*/
411 int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
412 {
413   int i=0;
414   regs *testreg;
415
416   do {
417     testreg = getRegFromInstruction(pc1);
418     if(testreg && (testreg->rIdx == reg->rIdx)) {
419       return 1;
420     }
421
422     pc1 = findNextInstruction(pc1->next);
423
424   } while (pc1 && (pc1 != pc2) && (i++ < 100)) ;
425
426   if(i >= 100)
427     fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
428
429   return 0;
430 }
431
432 /*-----------------------------------------------------------------*
433  * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2) 
434  *
435  * ADHOC pattern checking 
436  * Now look for specific sequences that are easy to optimize.
437  * Many of these sequences are characteristic of the compiler
438  * (i.e. it'd probably be a waste of time to apply these adhoc
439  * checks to hand written assembly.)
440  * 
441  *
442  *-----------------------------------------------------------------*/
443 int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
444 {
445   pCode *pct1, *pct2;
446   regs  *reg1, *reg2;
447
448   int t = total_registers_saved;
449
450   if(pc2->seq < pc1->seq) {
451     pct1 = pc2;
452     pc2 = pc1;
453     pc1 = pct1;
454   }
455
456   //fprintf(stderr,"pCodeOptime2pCodes\n");
457   //pc1->print(stderr,pc1);
458   //pc2->print(stderr,pc2);
459
460   if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
461     pCode *newpc;
462     int regUsed = 0;
463     int wUsed   = 0;
464     int wSaved  = 0;
465     /*
466       clrf  reg    ; pc1
467       stuff...
468       movf  reg,w  ; pc2
469
470       can be replaced with (only if following instructions are not going to use W and reg is not used again later)
471
472       stuff...
473       movlw 0 or clrf  reg
474     */
475     DFPRINTF((stderr, "   optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
476     pct2 = findNextInstruction(pc2->next);
477
478     if(pct2 && PCI(pct2)->op == POC_MOVWF) {
479       wSaved = wUsed = 1; /* Maybe able to replace with clrf pc2->next->reg. */
480         } else {
481                 wUsed = pCodeSearchCondition(pct2,PCC_W,1) > 0;
482     }
483     regUsed = regUsedinRange(pct2,0,reg);
484     if ((regUsed&&wUsed) || (pCodeSearchCondition(pct2,PCC_Z,0) > 1)) {
485       /* Do not optimise as exisiting code is required. */
486     } else {
487       /* Can optimise. */
488       if(regUsed) {
489         newpc = newpCode(POC_CLRF, PCI(pc1)->pcop);
490       } else if(wSaved && !wUsed) {
491         newpc = newpCode(POC_CLRF, PCI(pct2)->pcop);
492         pct2->destruct(pct2);
493       } else {
494         newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
495       }
496
497       pCodeInsertAfter(pc2, newpc);
498       PCI(newpc)->pcflow = PCFL(pcfl_used);
499       newpc->seq = pc2->seq;
500
501       Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
502       total_registers_saved++;  // debugging stats.
503     }
504   } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
505     DFPRINTF((stderr, "   optimising CLRF/IORFW\n"));
506
507     pct2 = findNextInstruction(pc2->next);
508
509     if(pCodeSearchCondition(pct2, PCC_Z,0) > 0) {
510       pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
511       pct2->seq = pc2->seq;
512       PCI(pct2)->pcflow = PCFL(pcfl_used);
513       pCodeInsertAfter(pc1,pct2);
514     }
515     Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
516     total_registers_saved++;  // debugging stats.
517
518   }  else if(PCI(pc1)->op == POC_MOVWF) {
519     // Optimising MOVWF reg ...
520
521     pct2 = findNextInstruction(pc2->next);
522
523     if(PCI(pc2)->op == POC_MOVFW) {
524       // Optimising MOVWF reg ... MOVF reg,W
525
526       if(PCI(pct2)->op == POC_MOVWF) {
527         /*
528         Change:
529
530         movwf   reg    ; pc1
531         stuff...
532         movf    reg,w  ; pc2
533         movwf   reg2   ; pct2
534
535         To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
536
537         movwf   reg2
538         stuff...
539
540         */
541         reg2 = getRegFromInstruction(pct2);
542         /* Check reg2 is not used for something else before it is loaded with reg */
543         if (reg2 && !regUsedinRange(pc1,pc2,reg2)) {
544           pCode *pct3 = findNextInstruction(pct2->next);
545           /* Check following instructions are not relying on the use of W or the Z flag condiction */
546           if ((pCodeSearchCondition(pct3,PCC_Z,0) < 1) || (pCodeSearchCondition(pct3,PCC_W,0) < 1)) {
547             DFPRINTF((stderr, "   optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
548             pct2->seq = pc1->seq;
549             unlinkpCode(pct2);
550             pCodeInsertBefore(pc1,pct2);
551             if(regUsedinRange(pct2,0,reg))
552               Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
553             else
554               Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
555
556             total_registers_saved++;  // debugging stats.
557             return 1;
558           }
559         }
560       }
561     }
562
563     pct1 = findPrevInstruction(pc1->prev);
564     if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
565
566       if ( (PCI(pct1)->op == POC_MOVFW) &&
567            (PCI(pc2)->op == POC_MOVFW)) {
568
569         reg1 = getRegFromInstruction(pct1);
570         if(reg1 && !regUsedinRange(pc1,pc2,reg1)) {
571           DFPRINTF((stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
572           /*
573             Change:
574
575             movf   reg1,w
576             movwf  reg
577
578             stuff...
579             movf   reg,w
580
581             To:
582
583             stuff...
584
585             movf   reg1,w
586
587             Or, if we're not deleting the register then the "To" is:
588
589             stuff...
590
591             movf   reg1,w
592             movwf  reg
593           */
594           pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
595           pCodeInsertAfter(pc2, pct2);
596           PCI(pct2)->pcflow = PCFL(pcfl_used);
597           pct2->seq = pc2->seq;
598
599           if(can_free) {
600             Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
601           } else {
602             /* If we're not freeing the register then that means (probably)
603              * the register is needed somewhere else.*/
604             unlinkpCode(pc1);
605             pCodeInsertAfter(pct2, pc1);
606
607             Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
608           }
609
610           Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
611           total_registers_saved++;  // debugging stats.
612
613         }
614 /* Note this else if is same conditional as the if - DELETE ME 
615       } else if ( (PCI(pct1)->op == POC_MOVWF) &&
616            (PCI(pc2)->op == POC_MOVFW)) {
617         DFPRINTF(stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n");
618         if(optimize_level > 1 && can_free) {
619           pct2 = newpCode(POC_MOVFW, PCI(pc1)->pcop);
620           pCodeInsertAfter(pc2, pct2);
621           Remove2pcodes(pcfl_used, pc1, pc2, reg, 1);
622           total_registers_saved++;  // debugging stats.
623         }
624 */
625       }
626     }
627   }
628
629   return (total_registers_saved != t);
630 }
631
632 /*-----------------------------------------------------------------*
633  * void pCodeRegOptimeRegUsage(pBlock *pb) 
634  *-----------------------------------------------------------------*/
635 void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
636 {
637   regs *reg;
638   int used;
639   pCode *pc1=NULL, *pc2=NULL;
640
641
642   while(fregs) {
643     pCode *pcfl_used, *pcfl_assigned;
644
645     /* Step through the set by directly accessing the 'next' pointer.
646      * We could also step through by using the set API, but the 
647      * the (debug) calls to print instructions affect the state
648      * of the set pointers */
649
650     reg = fregs->item;
651     fregs = fregs->next;
652 /*
653 if (strcmp(reg->name,"_SubState")==0)
654      fprintf(stderr,"Reg: %s\n",reg->name);
655 */
656
657     if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
658       //fprintf(stderr,"skipping SFR: %s\n",reg->name);
659       continue;
660     }
661
662     pcfl_used = setFirstItem(reg->reglives.usedpFlows);
663     pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
664
665     used = elementsInSet(reg->reglives.usedpCodes);
666     if(used == 2) { 
667
668       /*
669        * In this section, all registers that are used in only in two 
670        * instructions are examined. If possible, they're optimized out.
671        */
672
673 /*
674       fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
675                reg->name,
676                reg->address,
677                reg->rIdx, reg->type, used);
678 */
679       pc1 = setFirstItem(reg->reglives.usedpCodes);
680       pc2 = setNextItem(reg->reglives.usedpCodes);
681
682       if(pcfl_used && pcfl_assigned) {
683
684         /* 
685            expected case - the register has been assigned a value and is
686            subsequently used 
687         */
688
689         //fprintf(stderr," used only twice\n");
690         if(pcfl_used->seq == pcfl_assigned->seq) {
691
692           //fprintf(stderr, "  and used in same flow\n");
693
694           pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
695
696         } else {
697           // fprintf(stderr, "  and used in different flows\n");
698
699         }
700
701       } else if(pcfl_used) {
702
703         /*
704           register has been used twice without ever being assigned */
705         fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
706
707       } else {
708         fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
709         Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
710         total_registers_saved++;  // debugging stats.
711       }
712     } else {
713
714       /* register has been used either once, or more than twice */
715
716       if(used && !pcfl_used && pcfl_assigned) {
717         pCode *pc;
718
719         fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
720
721         pc = setFirstItem(reg->reglives.usedpCodes);
722         while(pc) {
723
724           pcfl_assigned = PCODE(PCI(pc)->pcflow);
725           Remove1pcode(pc, reg,2);
726
727           deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
728           /*
729           deleteSetItem (&(reg->reglives.usedpCodes),pc);
730           pc->destruct(pc);
731           */
732           pc = setNextItem(reg->reglives.usedpCodes);
733         }
734
735
736         reg->isFree = 1;
737         reg->wasUsed = 0;
738
739         total_registers_saved++;  // debugging stats.
740       } else if( (used > 2) && optimize_multi_uses) {
741
742         set *rset1=NULL;
743         set *rset2=NULL;
744         int searching=1;
745
746         pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
747
748         /* examine the number of times this register is used */
749
750
751         rset1 = reg->reglives.usedpCodes;
752         while(rset1 && searching) {
753
754           pc1 = rset1->item;
755           rset2 = rset1->next;
756
757           if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
758
759             //while(rset2 && searching) {
760             if(rset2) {
761
762               pc2 = rset2->item;
763               if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
764                 if(pcfl2 == pcfl1) {
765
766                   if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
767                     searching = 0;
768                 }
769               }
770
771               //rset2 = rset2->next;
772               
773             }
774           }
775           rset1 = rset1->next;
776         }
777       }
778     }
779
780   }
781
782 }
783 /*-----------------------------------------------------------------*
784  * void pCodeRegOptimeRegUsage(pBlock *pb) 
785  *-----------------------------------------------------------------*/
786 void pCodeRegOptimizeRegUsage(int level)
787 {
788
789   int passes;
790   int saved = 0;
791   int t = total_registers_saved;
792
793   if(!register_optimization)
794     return;
795 #define OPT_PASSES 4
796   passes = OPT_PASSES;
797
798   do {
799     saved = total_registers_saved;
800
801     /* Identify registers used in one flow sequence */
802     OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
803     OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
804     OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
805
806     if(total_registers_saved != saved)
807       DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
808               (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
809       
810     passes--;
811
812   } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
813
814   if(total_registers_saved == t) 
815     DFPRINTF((stderr, "No registers saved on this pass\n"));
816
817
818 /*
819   fprintf(stderr,"dynamically allocated regs:\n");
820   dbg_regusage(dynAllocRegs);
821   fprintf(stderr,"stack regs:\n");
822   dbg_regusage(dynStackRegs);
823   fprintf(stderr,"direct regs:\n");
824   dbg_regusage(dynDirectRegs);
825 */
826 }
827
828
829 /*-----------------------------------------------------------------*
830  * void RegsUnMapLiveRanges(set *regset)
831  *
832  *-----------------------------------------------------------------*/
833 void  RegsSetUnMapLiveRanges(set *regset)
834 {
835   regs *reg;
836
837   while(regset) {
838     reg = regset->item;
839     regset = regset->next;
840
841     
842     deleteSet(&reg->reglives.usedpCodes);
843     deleteSet(&reg->reglives.usedpFlows);
844     deleteSet(&reg->reglives.assignedpFlows);
845
846   }
847
848 }
849
850 void  RegsUnMapLiveRanges(void)
851 {
852
853   RegsSetUnMapLiveRanges(dynAllocRegs);
854   RegsSetUnMapLiveRanges(dynStackRegs);
855   RegsSetUnMapLiveRanges(dynDirectRegs);
856   RegsSetUnMapLiveRanges(dynProcessorRegs);
857   RegsSetUnMapLiveRanges(dynDirectBitRegs);
858   RegsSetUnMapLiveRanges(dynInternalRegs);
859
860 }