Imported Upstream version 2.9.0
[debian/cc1111] / 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
30 #include "main.h"
31 #include "pcoderegs.h"
32 #include "pcodeflow.h"
33 #include "ralloc.h"
34
35
36 static int total_registers_saved=0;
37 static int register_optimization=1;
38
39 /*-----------------------------------------------------------------*
40 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
41 *-----------------------------------------------------------------*/
42 static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
43 {
44         
45         pCode *pc=NULL;
46         
47         regs *reg;
48         
49         if(!pcfl)
50                 return;
51         
52         
53         pc = findNextInstruction(pcfl->pc.next);
54         
55         while(pc && !isPCFL(pc)) {
56                 while (pc && !isPCI(pc) && !isPCFL(pc))
57                 {
58                         pc = pc->next;
59                 } // while
60                 if (!pc || isPCFL(pc)) continue;
61                 assert( isPCI(pc) );
62
63                 reg = getRegFromInstruction(pc);
64                 #if 0
65                 pc->print(stderr, pc);
66                 fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
67                         reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
68                         PCI(pc)->inCond, PCI(pc)->outCond );
69                 #endif
70                 if(reg) {
71                 /*
72                 fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
73                 fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x\n",
74                 reg->address,reg->type,reg->rIdx);
75                         */
76                         
77                         addSetIfnotP(& (PCFL(pcfl)->registers), reg);
78                         
79                         if(PCC_REGISTER & PCI(pc)->inCond)
80                                 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
81                         
82                         if(PCC_REGISTER & PCI(pc)->outCond)
83                                 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
84                         
85                         addSetIfnotP(& (reg->reglives.usedpCodes), pc);
86                         reg->wasUsed = 1;
87                 }
88                 
89                 
90                 //pc = findNextInstruction(pc->next);
91                 pc = pc->next;
92                 
93         }
94
95 }
96
97 /*-----------------------------------------------------------------*
98 * void pCodeRegMapLiveRanges(pBlock *pb) 
99 *-----------------------------------------------------------------*/
100 void pCodeRegMapLiveRanges(pBlock *pb)
101 {
102         pCode *pcflow;
103         
104         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
105         pcflow != NULL;
106         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
107                 
108                 if(!isPCFL(pcflow)) {
109                         fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
110                         continue;
111                 }
112                 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
113         }
114         
115 #if 0
116         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
117         pcflow != NULL;
118         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
119                 
120                 regs *r = setFirstItem(PCFL(pcflow)->registers);
121                 fprintf(stderr,"flow seq %d\n", pcflow->seq);
122                 
123                 while (r) {
124                         fprintf(stderr, "  %s\n",r->name);
125                         r = setNextItem(PCFL(pcflow)->registers);
126                         
127                 }
128                 
129         }
130 #endif
131         
132 }
133
134
135 /*-----------------------------------------------------------------*
136 *
137 *-----------------------------------------------------------------*/
138 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
139 {
140
141         pCode *pcn=NULL;
142         
143         if(!reg || !pc)
144                 return;
145
146         deleteSetItem (&(reg->reglives.usedpCodes),pc);
147         
148         if(PCI(pc)->label) {
149                 pcn = findNextInstruction(pc->next);
150                 
151                 if(pcn)
152                         PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
153         }
154         
155         if(PCI(pc)->cline) {
156                 if(!pcn)
157                         pcn = findNextInstruction(pc->next);
158                 
159                 if(pcn) {
160                         if(PCI(pcn)->cline) {
161                                 //fprintf(stderr, "source line has been optimized completely out\n");
162                                 //pc->print(stderr,pc);
163                         } else {
164                                 PCI(pcn)->cline = PCI(pc)->cline;
165                         }
166                 }
167         }
168         
169         
170         if(1) {
171                 /*
172                  * Debug stuff. Comment out the instruction we're about to delete.
173                  */
174                 
175                 char buff1[256];
176                 size_t size = 256;
177                 
178                 char *pbuff;
179                 pbuff = &buff1[0];
180                 
181                 SNPRINTF(pbuff, size, ";%d", debug_code);
182                 size -= strlen(pbuff);
183                 pbuff += strlen(pbuff);
184                 pCode2str(pbuff, size, pc);
185                 pCodeInsertBefore(pc, newpCodeCharP(buff1));
186                 //fprintf(stderr,"removing instruction:\n%s\n",buff1);
187         }
188         
189         pc->destruct(pc);
190         
191 }
192
193 /*-----------------------------------------------------------------*
194 * void RemoveRegsFromSet(set *regset)
195 *
196 *-----------------------------------------------------------------*/
197 static void RemoveRegsFromSet(set *regset)
198 {
199         regs *reg;
200         int used;
201         
202         while(regset) {
203                 reg = regset->item;
204                 regset = regset->next;
205                 
206                 used = elementsInSet(reg->reglives.usedpCodes);
207                 
208                 if(used <= 1) {
209                         
210                         //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
211                         if(used == 0) {
212                                 //fprintf(stderr," getting rid of reg %s\n",reg->name);
213                                 reg->isFree = 1;
214                                 reg->wasUsed = 0;
215                         } else {
216                                 pCode *pc;
217                                 
218                                 
219                                 pc = setFirstItem(reg->reglives.usedpCodes);
220                                 
221                                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
222                                         //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
223                                         continue;
224                                 }
225                                 
226                                 
227                                 if(isPCI(pc)) {
228                                         if(PCI(pc)->label) {
229                                                 pCode *pcn = findNextInstruction(pc->next);
230                                                 
231                                                 if(pcn && PCI(pcn)->label) {
232                                                         //fprintf(stderr,"can't delete instruction with label...\n");
233                                                         //pc->print(stderr,pc);
234                                                         continue;
235                                                 } 
236                                                 /* Move the label to the next instruction */
237                                                 
238                                                 PCI(pcn)->label = PCI(pc)->label;
239                                                 
240                                         }
241                                         
242                                         if(isPCI_SKIP(pc)) {
243                                                 regs *r = getRegFromInstruction(pc);
244                                                 fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
245                                                 pc->print(stderr,pc);
246                                                 fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
247                                         }
248                                         //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
249                                         Remove1pcode(pc, reg, 1);
250                                         /*
251                                         unlinkpCode(pc);
252                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
253                                         */
254                                         reg->isFree = 1;
255                                         reg->wasUsed = 0;
256                                         total_registers_saved++;  // debugging stats.
257                                 }
258                         }
259                 }
260                 
261         }
262 }
263
264 static void pic14_ReMapLiveRanges(void)
265 {
266         pBlock *pb;
267         if (!the_pFile) return;
268         RegsUnMapLiveRanges();
269         for (pb = the_pFile->pbHead; pb; pb = pb->next)
270         {
271         #if 0
272                 pCode *pc = findNextpCode(pb->pcHead, PC_FLOW);
273                 if (pc) {
274                         pc->print( stderr, pc );
275                 } else {
276                         fprintf( stderr, "unnamed pBlock\n");
277                 }
278                 pc = findNextInstruction(pb->pcHead);
279                 while (pc) {
280                   pc->print( stderr, pc );
281                   pc = findNextInstruction(pc->next);;
282                 }
283         #endif  
284                 pCodeRegMapLiveRanges(pb);
285         } // for
286 }
287
288 /*-----------------------------------------------------------------*
289 * void RemoveUnusedRegisters(void)
290 *
291 *-----------------------------------------------------------------*/
292 void RemoveUnusedRegisters(void)
293 {
294         /* First, get rid of registers that are used only one time */
295         pic14_ReMapLiveRanges();
296         
297         //RemoveRegsFromSet(dynInternalRegs);
298         RemoveRegsFromSet(dynAllocRegs);
299         RemoveRegsFromSet(dynStackRegs);
300         /*
301         don't do DirectRegs yet - there's a problem with arrays
302         RemoveRegsFromSet(dynDirectRegs);
303         */
304         RemoveRegsFromSet(dynDirectBitRegs);
305         
306         if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
307 }
308
309
310 /*-----------------------------------------------------------------*
311 *
312 *-----------------------------------------------------------------*/
313 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free)
314 {
315         static int debug_code=99;
316         if(!reg)
317                 return;
318 #if 0
319         fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
320         printpCode (stderr, pc1);
321         printpCode (stderr, pc2);
322 #endif
323         
324         //fprintf(stderr,"%s\n",__FUNCTION__);
325         if(pc1)
326                 Remove1pcode(pc1, reg, debug_code++);
327         
328         if(pc2) {
329                 Remove1pcode(pc2, reg, debug_code++);
330                 deleteSetItem (&(PCFL(pcflow)->registers), reg);
331                 
332                 if(can_free) {
333                         reg->isFree = 1;
334                         reg->wasUsed = 0;
335                 }
336                 
337         }
338         
339         pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
340 }
341
342 /*-----------------------------------------------------------------*
343 *
344 *-----------------------------------------------------------------*/
345 static int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
346 {
347         int i=0;
348         regs *testreg;
349         
350         do {
351                 testreg = getRegFromInstruction(pc1);
352                 if(testreg && (testreg->rIdx == reg->rIdx)) {
353                         return 1;
354                 }
355                 if (i++ > 1000) {
356                         fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
357                         return 0;
358                 }
359                 
360                 pc1 = findNextInstruction(pc1->next);
361                 
362         } while (pc1 && (pc1 != pc2)) ;
363         
364         return 0;
365 }
366
367 static int regIsSpecial (regs *reg, int mayBeGlobal)
368 {
369   if (!reg) return 0;
370
371   if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
372
373   return 0;
374 }
375
376 /*-----------------------------------------------------------------*
377 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2) 
378 *
379 * ADHOC pattern checking 
380 * Now look for specific sequences that are easy to optimize.
381 * Many of these sequences are characteristic of the compiler
382 * (i.e. it'd probably be a waste of time to apply these adhoc
383 * checks to hand written assembly.)
384
385 *
386 *-----------------------------------------------------------------*/
387 static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
388 {
389         pCode *pct1, *pct2;
390         regs  *reg1, *reg2;
391         
392         int t = total_registers_saved;
393
394         if (!isPCI(pc1) || !isPCI(pc2)) return 0;
395         if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
396         
397         if (pc2->seq < pc1->seq) {
398                 pct1 = pc2;
399                 pc2 = pc1;
400                 pc1 = pct1;
401         }
402
403         /* disable this optimization for now -- it's buggy */
404         if (pic14_options.disable_df) return 0;
405         
406         //fprintf(stderr,"pCodeOptime2pCodes\n");
407         //pc1->print(stderr,pc1);
408         //pc2->print(stderr,pc2);
409
410         if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
411             /*
412              * CLRF sets Z
413              * MOVFW affects Z
414              * MOVWF does not touch Z
415              * MOVLW does not touch Z
416              */
417                 pCode *newpc;
418                 /*
419                 clrf  reg    ; pc1
420                 stuff...
421                 movf  reg,w  ; pc2
422                 
423                   can be replaced with (only if following instructions are not going to use W and reg is not used again later)
424                   
425                         stuff...
426                         movlw 0 or clrf  reg
427                 */
428                 DFPRINTF((stderr, "   optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
429                 pct2 = findNextInstruction(pc2->next);
430                 if (pCodeSearchCondition(pct2, PCC_Z, 0) == -1) {
431                         /* Z is definitely overwritten before use */
432                         newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
433                         
434                         pCodeInsertAfter(pc2, newpc);
435                         PCI(newpc)->pcflow = PCFL(pcfl_used);
436                         newpc->seq = pc2->seq;
437                         
438                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
439                         //Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
440                         pc2->destruct(pc2);
441                         //total_registers_saved++;  // debugging stats.
442                 }
443         } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
444                 DFPRINTF((stderr, "   optimising CLRF/IORFW\n"));
445                 
446                 pct2 = findNextInstruction(pc2->next);
447                 
448                 /* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
449                 if (pCodeSearchCondition(pct2, PCC_Z, 0) != -1) {
450                         pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
451                         pct2->seq = pc2->seq;
452                         PCI(pct2)->pcflow = PCFL(pcfl_used);
453                         pCodeInsertAfter(pc1,pct2);
454                 }
455                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
456                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
457                 total_registers_saved++;  // debugging stats.
458                 
459         }  else if(PCI(pc1)->op == POC_MOVWF) {
460                 // Optimising MOVWF reg ...
461                 
462                 pct2 = findNextInstruction(pc2->next);
463                 
464                 if(PCI(pc2)->op == POC_MOVFW) {
465                         // Optimising MOVWF reg ... MOVF reg,W
466                         
467                         if(PCI(pct2)->op == POC_MOVWF) {
468                         /*
469                         Change:
470                         
471                           movwf   reg    ; pc1
472                           stuff...
473                           movf    reg,w  ; pc2
474                           movwf   reg2   ; pct2
475                           
476                                 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
477                                 
478                                   movwf   reg2
479                                   stuff...
480                                   
481                                 */
482                                 reg2 = getRegFromInstruction(pct2);
483                                 /* Check reg2 is not used for something else before it is loaded with reg */
484                                 if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
485                                         pCode *pct3 = findNextInstruction(pct2->next);
486                                         /* Check following instructions are not relying on the use of W or the Z flag condiction */
487                                         /* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
488                                          *      subsequent flows (checking for < 1 is insufficient). */
489                                         if ((pCodeSearchCondition(pct3,PCC_Z,0) == -1) && (pCodeSearchCondition(pct3,PCC_W,0) == -1)) {
490                                                 DFPRINTF((stderr, "   optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
491                                                 pct2->seq = pc1->seq;
492                                                 unlinkpCode(pct2);
493                                                 pCodeInsertBefore(pc1,pct2);
494                                                 if(regUsedinRange(pct2,0,reg))
495                                                 {
496                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
497                                                         Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
498                                                 } else {
499                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
500                                                         Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
501                                                 }
502                                                 total_registers_saved++;  // debugging stats.
503                                                 return 1;
504                                         }
505                                 }
506                         }
507                 }
508                 
509                 pct1 = findPrevInstruction(pc1->prev);
510                 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
511                         
512                         if ( (PCI(pct1)->op == POC_MOVFW) &&
513                                 (PCI(pc2)->op == POC_MOVFW)) {
514                                 
515                                 reg1 = getRegFromInstruction(pct1);
516                                 if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
517                                         DFPRINTF((stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
518                                         /*
519                                         Change:
520                                         
521                                                 movf   reg1,w
522                                                 movwf  reg
523
524                                                 stuff...
525                                                 movf   reg,w
526                                                 
527                                         To:
528
529                                                 stuff...
530
531                                                 movf   reg1,w
532
533                                         Or, if we're not deleting the register then the "To" is:
534
535                                                 stuff...
536
537                                                 movf   reg1,w
538                                                 movwf  reg
539                                         */
540                                         pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
541                                         pCodeInsertAfter(pc2, pct2);
542                                         PCI(pct2)->pcflow = PCFL(pcfl_used);
543                                         pct2->seq = pc2->seq;
544                                         
545                                         if(can_free) {
546                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
547                                                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
548                                         } else {
549                                         /* If we're not freeing the register then that means (probably)
550                                                 * the register is needed somewhere else.*/
551                                                 unlinkpCode(pc1);
552                                                 pCodeInsertAfter(pct2, pc1);
553                                                 
554                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
555                                                 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
556                                         }
557                                         
558                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
559                                         Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
560                                         total_registers_saved++;  // debugging stats.
561                                         
562                                 }
563                         }
564                 }
565   }
566
567   return (total_registers_saved != t);
568 }
569
570 /*-----------------------------------------------------------------*
571 * void pCodeRegOptimeRegUsage(pBlock *pb) 
572 *-----------------------------------------------------------------*/
573 static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
574 {
575         regs *reg;
576         int used;
577         pCode *pc1=NULL, *pc2=NULL;
578         
579         
580         while(fregs) {
581                 pCode *pcfl_used, *pcfl_assigned;
582                 
583                 /* Step through the set by directly accessing the 'next' pointer.
584                 * We could also step through by using the set API, but the 
585                 * the (debug) calls to print instructions affect the state
586                 * of the set pointers */
587                 
588                 reg = fregs->item;
589                 fregs = fregs->next;
590                 /*
591                 if (strcmp(reg->name,"_SubState")==0)
592                 fprintf(stderr,"Reg: %s\n",reg->name);
593                 */
594                 
595                 /* Catch inconsistently set-up live ranges
596                  * (see tracker items #1469504 + #1474602)
597                  * FIXME: Actually we should rather fix the
598                  * computation of the liveranges instead...
599                  */
600                 if (!reg || !reg->reglives.usedpFlows
601                         || !reg->reglives.assignedpFlows)
602                 {
603                   //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
604                   continue;
605                 }
606
607                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
608                         //fprintf(stderr,"skipping SFR: %s\n",reg->name);
609                         continue;
610                 }
611
612                 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
613                 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
614                 
615                 used = elementsInSet(reg->reglives.usedpCodes);
616                 if(used == 2) { 
617                         /*
618                         In this section, all registers that are used in only in two 
619                         instructions are examined. If possible, they're optimized out.
620                         */
621                         
622                         /*
623                         fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
624                         reg->name,
625                         reg->address,
626                         reg->rIdx, reg->type, used);
627                         */
628                         pc1 = setFirstItem(reg->reglives.usedpCodes);
629                         pc2 = setNextItem(reg->reglives.usedpCodes);
630                         
631                         if(pcfl_used && pcfl_assigned) {
632                                 /* 
633                                 expected case - the register has been assigned a value and is
634                                 subsequently used 
635                                 */
636                                 
637                                 //fprintf(stderr," used only twice\n");
638                                 if(pcfl_used->seq == pcfl_assigned->seq) {
639                                         
640                                         //fprintf(stderr, "  and used in same flow\n");
641                                         
642                                         pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
643                                         
644                                 } else {
645                                         // fprintf(stderr, "  and used in different flows\n");
646                                         
647                                 }
648                                 
649                         } else if(pcfl_used) {
650                                 
651                                 /* register has been used twice without ever being assigned */
652                                 fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
653                                 
654                         } else {
655                                 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
656                                 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
657                                 total_registers_saved++;  // debugging stats.
658                         }
659                 } else {
660                         
661                         /* register has been used either once, or more than twice */
662                         
663                         if(used && !pcfl_used && pcfl_assigned) {
664                                 pCode *pc;
665                                 
666                                 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
667                                 
668                                 pc = setFirstItem(reg->reglives.usedpCodes);
669                                 while(pc) {
670                                         
671                                         pcfl_assigned = PCODE(PCI(pc)->pcflow);
672                                         Remove1pcode(pc, reg,2);
673                                         
674                                         deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
675                                         /*
676                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
677                                         pc->destruct(pc);
678                                         */
679                                         pc = setNextItem(reg->reglives.usedpCodes);
680                                 }
681                                 
682                                 
683                                 reg->isFree = 1;
684                                 reg->wasUsed = 0;
685                                 
686                                 total_registers_saved++;  // debugging stats.
687                         } else if( (used > 2) && optimize_multi_uses) {
688                                 
689                                 set *rset1=NULL;
690                                 set *rset2=NULL;
691                                 int searching=1;
692                                 
693                                 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
694                                 
695                                 /* examine the number of times this register is used */
696                                 
697                                 
698                                 rset1 = reg->reglives.usedpCodes;
699                                 while(rset1 && searching) {
700                                         
701                                         pc1 = rset1->item;
702                                         rset2 = rset1->next;
703                                         
704                                         if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
705                                                 
706                                                 if(rset2) {
707                                                         
708                                                         pc2 = rset2->item;
709                                                         if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
710                                                                 if(pcfl2 == pcfl1) {
711                                                                         
712                                                                         if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
713                                                                                 searching = 0;
714                                                                 }
715                                                         }
716                                                         
717                                                         //rset2 = rset2->next;
718                                                         
719                                                 }
720                                         }
721                                         rset1 = rset2;
722                                 }
723                         }
724                 }
725         }
726 }
727
728 /*-----------------------------------------------------------------*
729 * void pCodeRegOptimeRegUsage(pBlock *pb) 
730 *-----------------------------------------------------------------*/
731 void pCodeRegOptimizeRegUsage(int level)
732 {
733         
734         int passes;
735         int saved = 0;
736         int t = total_registers_saved;
737
738 #if 0
739         /* This is currently broken (need rewrite to correctly
740          * handle arbitrary pCodeOps instead of registers only). */
741         if (!pic14_options.disable_df)
742                 optimizeDataflow ();
743 #endif
744
745         if(!register_optimization)
746                 return;
747 #define OPT_PASSES 4
748         passes = OPT_PASSES;
749         
750         do {
751                 saved = total_registers_saved;
752                 
753                 /* Identify registers used in one flow sequence */
754                 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
755                 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
756                 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
757                 
758                 if(total_registers_saved != saved)
759                         DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
760                         (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
761                 
762                 passes--;
763                 
764         } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
765         
766         if(total_registers_saved == t) 
767                 DFPRINTF((stderr, "No registers saved on this pass\n"));
768 }
769
770
771 /*-----------------------------------------------------------------*
772 * void RegsUnMapLiveRanges(set *regset)
773 *
774 *-----------------------------------------------------------------*/
775 static void RegsSetUnMapLiveRanges(set *regset)
776 {
777         regs *reg;
778         
779         while(regset) {
780                 reg = regset->item;
781                 regset = regset->next;
782                 
783                 
784                 deleteSet(&reg->reglives.usedpCodes);
785                 deleteSet(&reg->reglives.usedpFlows);
786                 deleteSet(&reg->reglives.assignedpFlows);
787                 
788         }
789         
790 }
791
792 void  RegsUnMapLiveRanges(void)
793 {
794         
795         RegsSetUnMapLiveRanges(dynAllocRegs);
796         RegsSetUnMapLiveRanges(dynStackRegs);
797         RegsSetUnMapLiveRanges(dynDirectRegs);
798         RegsSetUnMapLiveRanges(dynProcessorRegs);
799         RegsSetUnMapLiveRanges(dynDirectBitRegs);
800         RegsSetUnMapLiveRanges(dynInternalRegs);
801         
802 }