2f489e3e63cb6a5a2fea1b6faae7abfe153de672
[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 #if 0
390         fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
391         printpCode (stderr, pc1);
392         printpCode (stderr, pc2);
393 #endif
394         
395         //fprintf(stderr,"%s\n",__FUNCTION__);
396         if(pc1)
397                 Remove1pcode(pc1, reg, debug_code++);
398         
399         if(pc2) {
400                 Remove1pcode(pc2, reg, debug_code++);
401                 deleteSetItem (&(PCFL(pcflow)->registers), reg);
402                 
403                 if(can_free) {
404                         reg->isFree = 1;
405                         reg->wasUsed = 0;
406                 }
407                 
408         }
409         
410         pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
411 }
412
413 /*-----------------------------------------------------------------*
414 *
415 *-----------------------------------------------------------------*/
416 int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
417 {
418         int i=0;
419         regs *testreg;
420         
421         do {
422                 testreg = getRegFromInstruction(pc1);
423                 if(testreg && (testreg->rIdx == reg->rIdx)) {
424                         return 1;
425                 }
426                 if (i++ > 1000) {
427                         fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
428                         return 0;
429                 }
430                 
431                 pc1 = findNextInstruction(pc1->next);
432                 
433         } while (pc1 && (pc1 != pc2)) ;
434         
435         return 0;
436 }
437
438 int regIsSpecial (regs *reg, int mayBeGlobal)
439 {
440   if (!reg) return 0;
441
442   if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
443
444   return 0;
445 }
446
447 /*-----------------------------------------------------------------*
448 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2) 
449 *
450 * ADHOC pattern checking 
451 * Now look for specific sequences that are easy to optimize.
452 * Many of these sequences are characteristic of the compiler
453 * (i.e. it'd probably be a waste of time to apply these adhoc
454 * checks to hand written assembly.)
455
456 *
457 *-----------------------------------------------------------------*/
458 int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
459 {
460         pCode *pct1, *pct2;
461         regs  *reg1, *reg2;
462         
463         int t = total_registers_saved;
464         
465         if(pc2->seq < pc1->seq) {
466                 pct1 = pc2;
467                 pc2 = pc1;
468                 pc1 = pct1;
469         }
470         
471         //fprintf(stderr,"pCodeOptime2pCodes\n");
472         //pc1->print(stderr,pc1);
473         //pc2->print(stderr,pc2);
474         
475         if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
476                 pCode *newpc;
477                 int regUsed = 0;
478                 int wUsed   = 0;
479                 int wSaved  = 0;
480                 /*
481                 clrf  reg    ; pc1
482                 stuff...
483                 movf  reg,w  ; pc2
484                 
485                   can be replaced with (only if following instructions are not going to use W and reg is not used again later)
486                   
487                         stuff...
488                         movlw 0 or clrf  reg
489                 */
490                 DFPRINTF((stderr, "   optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
491                 pct2 = findNextInstruction(pc2->next);
492                 
493                 if(pct2 && PCI(pct2)->op == POC_MOVWF) {
494                         wSaved = wUsed = 1; /* Maybe able to replace with clrf pc2->next->reg. */
495                 } else {
496                         wUsed = pCodeSearchCondition(pct2,PCC_W,1) > 0;
497                 }
498                 regUsed = regUsedinRange(pct2,0,reg);
499                 if ((regUsed&&wUsed) || (pCodeSearchCondition(pct2,PCC_Z,0) > 1)) {
500                         /* Do not optimise as exisiting code is required. */
501                 } else {
502                         /* Can optimise. */
503                         if(regUsed) {
504                                 newpc = newpCode(POC_CLRF, PCI(pc1)->pcop);
505                         } else if(wSaved && !wUsed) {
506                                 newpc = newpCode(POC_CLRF, PCI(pct2)->pcop);
507                                 pct2->destruct(pct2);
508                         } else {
509                                 newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
510                         }
511                         
512                         pCodeInsertAfter(pc2, newpc);
513                         PCI(newpc)->pcflow = PCFL(pcfl_used);
514                         newpc->seq = pc2->seq;
515                         
516                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
517                         Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
518                         total_registers_saved++;  // debugging stats.
519                 }
520         } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
521                 DFPRINTF((stderr, "   optimising CLRF/IORFW\n"));
522                 
523                 pct2 = findNextInstruction(pc2->next);
524                 
525                 if(pCodeSearchCondition(pct2, PCC_Z,0) > 0) {
526                         pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
527                         pct2->seq = pc2->seq;
528                         PCI(pct2)->pcflow = PCFL(pcfl_used);
529                         pCodeInsertAfter(pc1,pct2);
530                 }
531                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
532                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
533                 total_registers_saved++;  // debugging stats.
534                 
535         }  else if(PCI(pc1)->op == POC_MOVWF) {
536                 // Optimising MOVWF reg ...
537                 
538                 pct2 = findNextInstruction(pc2->next);
539                 
540                 if(PCI(pc2)->op == POC_MOVFW) {
541                         // Optimising MOVWF reg ... MOVF reg,W
542                         
543                         if(PCI(pct2)->op == POC_MOVWF) {
544                         /*
545                         Change:
546                         
547                           movwf   reg    ; pc1
548                           stuff...
549                           movf    reg,w  ; pc2
550                           movwf   reg2   ; pct2
551                           
552                                 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
553                                 
554                                   movwf   reg2
555                                   stuff...
556                                   
557                                 */
558                                 reg2 = getRegFromInstruction(pct2);
559                                 /* Check reg2 is not used for something else before it is loaded with reg */
560                                 if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
561                                         pCode *pct3 = findNextInstruction(pct2->next);
562                                         /* Check following instructions are not relying on the use of W or the Z flag condiction */
563                                         if ((pCodeSearchCondition(pct3,PCC_Z,0) < 1) || (pCodeSearchCondition(pct3,PCC_W,0) < 1)) {
564                                                 DFPRINTF((stderr, "   optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
565                                                 pct2->seq = pc1->seq;
566                                                 unlinkpCode(pct2);
567                                                 pCodeInsertBefore(pc1,pct2);
568                                                 if(regUsedinRange(pct2,0,reg))
569                                                 {
570                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
571                                                         Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
572                                                 } else {
573                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
574                                                         Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
575                                                 }
576                                                 total_registers_saved++;  // debugging stats.
577                                                 return 1;
578                                         }
579                                 }
580                         }
581                 }
582                 
583                 pct1 = findPrevInstruction(pc1->prev);
584                 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
585                         
586                         if ( (PCI(pct1)->op == POC_MOVFW) &&
587                                 (PCI(pc2)->op == POC_MOVFW)) {
588                                 
589                                 reg1 = getRegFromInstruction(pct1);
590                                 if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
591                                         DFPRINTF((stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
592                                         /*
593                                         Change:
594                                         
595                                                 movf   reg1,w
596                                                 movwf  reg
597
598                                                 stuff...
599                                                 movf   reg,w
600                                                 
601                                         To:
602
603                                                 stuff...
604
605                                                 movf   reg1,w
606
607                                         Or, if we're not deleting the register then the "To" is:
608
609                                                 stuff...
610
611                                                 movf   reg1,w
612                                                 movwf  reg
613                                         */
614                                         pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
615                                         pCodeInsertAfter(pc2, pct2);
616                                         PCI(pct2)->pcflow = PCFL(pcfl_used);
617                                         pct2->seq = pc2->seq;
618                                         
619                                         if(can_free) {
620                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
621                                                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
622                                         } else {
623                                         /* If we're not freeing the register then that means (probably)
624                                                 * the register is needed somewhere else.*/
625                                                 unlinkpCode(pc1);
626                                                 pCodeInsertAfter(pct2, pc1);
627                                                 
628                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
629                                                 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
630                                         }
631                                         
632                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
633                                         Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
634                                         total_registers_saved++;  // debugging stats.
635                                         
636                                 }
637                         }
638                 }
639   }
640
641   return (total_registers_saved != t);
642 }
643
644 /*-----------------------------------------------------------------*
645 * void pCodeRegOptimeRegUsage(pBlock *pb) 
646 *-----------------------------------------------------------------*/
647 void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
648 {
649         regs *reg;
650         int used;
651         pCode *pc1=NULL, *pc2=NULL;
652         
653         
654         while(fregs) {
655                 pCode *pcfl_used, *pcfl_assigned;
656                 
657                 /* Step through the set by directly accessing the 'next' pointer.
658                 * We could also step through by using the set API, but the 
659                 * the (debug) calls to print instructions affect the state
660                 * of the set pointers */
661                 
662                 reg = fregs->item;
663                 fregs = fregs->next;
664                 /*
665                 if (strcmp(reg->name,"_SubState")==0)
666                 fprintf(stderr,"Reg: %s\n",reg->name);
667                 */
668                 
669                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
670                         //fprintf(stderr,"skipping SFR: %s\n",reg->name);
671                         continue;
672                 }
673                 
674                 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
675                 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
676                 
677                 used = elementsInSet(reg->reglives.usedpCodes);
678                 if(used == 2) { 
679                         /*
680                         In this section, all registers that are used in only in two 
681                         instructions are examined. If possible, they're optimized out.
682                         */
683                         
684                         /*
685                         fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
686                         reg->name,
687                         reg->address,
688                         reg->rIdx, reg->type, used);
689                         */
690                         pc1 = setFirstItem(reg->reglives.usedpCodes);
691                         pc2 = setNextItem(reg->reglives.usedpCodes);
692                         
693                         if(pcfl_used && pcfl_assigned) {
694                                 /* 
695                                 expected case - the register has been assigned a value and is
696                                 subsequently used 
697                                 */
698                                 
699                                 //fprintf(stderr," used only twice\n");
700                                 if(pcfl_used->seq == pcfl_assigned->seq) {
701                                         
702                                         //fprintf(stderr, "  and used in same flow\n");
703                                         
704                                         pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
705                                         
706                                 } else {
707                                         // fprintf(stderr, "  and used in different flows\n");
708                                         
709                                 }
710                                 
711                         } else if(pcfl_used) {
712                                 
713                                 /* register has been used twice without ever being assigned */
714                                 fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
715                                 
716                         } else {
717                                 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
718                                 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
719                                 total_registers_saved++;  // debugging stats.
720                         }
721                 } else {
722                         
723                         /* register has been used either once, or more than twice */
724                         
725                         if(used && !pcfl_used && pcfl_assigned) {
726                                 pCode *pc;
727                                 
728                                 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
729                                 
730                                 pc = setFirstItem(reg->reglives.usedpCodes);
731                                 while(pc) {
732                                         
733                                         pcfl_assigned = PCODE(PCI(pc)->pcflow);
734                                         Remove1pcode(pc, reg,2);
735                                         
736                                         deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
737                                         /*
738                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
739                                         pc->destruct(pc);
740                                         */
741                                         pc = setNextItem(reg->reglives.usedpCodes);
742                                 }
743                                 
744                                 
745                                 reg->isFree = 1;
746                                 reg->wasUsed = 0;
747                                 
748                                 total_registers_saved++;  // debugging stats.
749                         } else if( (used > 2) && optimize_multi_uses) {
750                                 
751                                 set *rset1=NULL;
752                                 set *rset2=NULL;
753                                 int searching=1;
754                                 
755                                 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
756                                 
757                                 /* examine the number of times this register is used */
758                                 
759                                 
760                                 rset1 = reg->reglives.usedpCodes;
761                                 while(rset1 && searching) {
762                                         
763                                         pc1 = rset1->item;
764                                         rset2 = rset1->next;
765                                         
766                                         if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
767                                                 
768                                                 //while(rset2 && searching) {
769                                                 if(rset2) {
770                                                         
771                                                         pc2 = rset2->item;
772                                                         if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
773                                                                 if(pcfl2 == pcfl1) {
774                                                                         
775                                                                         if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
776                                                                                 searching = 0;
777                                                                 }
778                                                         }
779                                                         
780                                                         //rset2 = rset2->next;
781                                                         
782                                                 }
783                                         }
784                                         rset1 = rset1->next;
785                                 }
786                         }
787                 }
788         }
789 }
790
791 /*-----------------------------------------------------------------*
792 * void pCodeRegOptimeRegUsage(pBlock *pb) 
793 *-----------------------------------------------------------------*/
794 void pCodeRegOptimizeRegUsage(int level)
795 {
796         
797         int passes;
798         int saved = 0;
799         int t = total_registers_saved;
800         
801         if(!register_optimization)
802                 return;
803 #define OPT_PASSES 4
804         passes = OPT_PASSES;
805         
806         do {
807                 saved = total_registers_saved;
808                 
809                 /* Identify registers used in one flow sequence */
810                 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
811                 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
812                 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
813                 
814                 if(total_registers_saved != saved)
815                         DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
816                         (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
817                 
818                 passes--;
819                 
820         } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
821         
822         if(total_registers_saved == t) 
823                 DFPRINTF((stderr, "No registers saved on this pass\n"));
824
825
826         /*
827                 fprintf(stderr,"dynamically allocated regs:\n");
828                 dbg_regusage(dynAllocRegs);
829                 fprintf(stderr,"stack regs:\n");
830                 dbg_regusage(dynStackRegs);
831                 fprintf(stderr,"direct regs:\n");
832                 dbg_regusage(dynDirectRegs);
833         */
834 }
835
836
837 /*-----------------------------------------------------------------*
838 * void RegsUnMapLiveRanges(set *regset)
839 *
840 *-----------------------------------------------------------------*/
841 void  RegsSetUnMapLiveRanges(set *regset)
842 {
843         regs *reg;
844         
845         while(regset) {
846                 reg = regset->item;
847                 regset = regset->next;
848                 
849                 
850                 deleteSet(&reg->reglives.usedpCodes);
851                 deleteSet(&reg->reglives.usedpFlows);
852                 deleteSet(&reg->reglives.assignedpFlows);
853                 
854         }
855         
856 }
857
858 void  RegsUnMapLiveRanges(void)
859 {
860         
861         RegsSetUnMapLiveRanges(dynAllocRegs);
862         RegsSetUnMapLiveRanges(dynStackRegs);
863         RegsSetUnMapLiveRanges(dynDirectRegs);
864         RegsSetUnMapLiveRanges(dynProcessorRegs);
865         RegsSetUnMapLiveRanges(dynDirectBitRegs);
866         RegsSetUnMapLiveRanges(dynInternalRegs);
867         
868 }