* src/SDCCval.c, src/SDCCval.h:
[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 #include "main.h"
39
40 extern void dbg_dumpregusage(void);
41 extern pCode * findPrevInstruction(pCode *pci);
42 extern pBranch * pBranchAppend(pBranch *h, pBranch *n);
43 void unlinkpCode(pCode *pc);
44 extern int pCodeSearchCondition(pCode *pc, unsigned int cond, int contIfSkip);
45 char *pCode2str(char *str, int size, pCode *pc);
46 void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...);
47 //static int sameRegs (const regs *reg1, const regs *reg2);
48
49 int total_registers_saved=0;
50 int register_optimization=1;
51
52 /*-----------------------------------------------------------------*
53 * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
54 *-----------------------------------------------------------------*/
55 /*
56 void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
57 {
58
59         if(!reg || ! pcfl || !isPCFL(pcflow))
60         return;
61
62         if(!pcfl->registers) 
63         pcfl->registers =  newSet();
64         
65 }
66 */
67
68
69 /*-----------------------------------------------------------------*
70
71 *-----------------------------------------------------------------*/
72 void dbg_regusage(set *fregs)
73 {
74         regs *reg;
75         pCode *pcfl;
76         pCode *pc;
77         
78         
79         for (reg = setFirstItem(fregs) ; reg ;
80         reg = setNextItem(fregs)) {
81                 
82                 if(elementsInSet(reg->reglives.usedpCodes)) {
83                         
84                         fprintf (stderr, "%s  addr=0x%03x rIdx=0x%03x",
85                                 reg->name,
86                                 reg->address,
87                                 reg->rIdx);
88                         
89                         pcfl = setFirstItem(reg->reglives.usedpFlows);
90                         if(pcfl)
91                                 fprintf(stderr, "\n   used in seq");
92                         
93                         while(pcfl) {
94                                 fprintf(stderr," 0x%03x",pcfl->seq);
95                                 pcfl = setNextItem(reg->reglives.usedpFlows);
96                         }
97                         
98                         pcfl = setFirstItem(reg->reglives.assignedpFlows);
99                         if(pcfl)
100                                 fprintf(stderr, "\n   assigned in seq");
101                         
102                         while(pcfl) {
103                                 fprintf(stderr," 0x%03x",pcfl->seq);
104                                 pcfl = setNextItem(reg->reglives.assignedpFlows);
105                         }
106                         
107                         pc = setFirstItem(reg->reglives.usedpCodes);
108                         if(pc)
109                                 fprintf(stderr, "\n   used in instructions ");
110                         
111                         while(pc) {
112                                 pcfl = PCODE(PCI(pc)->pcflow);
113                                 if(pcfl)
114                                         fprintf(stderr," 0x%03x:",pcfl->seq);
115                                 fprintf(stderr,"0x%03x",pc->seq);
116                                 
117                                 pc = setNextItem(reg->reglives.usedpCodes);
118                         }
119                         
120                         fprintf(stderr, "\n");
121                 }
122         }
123 }
124
125 /*-----------------------------------------------------------------*
126
127 *-----------------------------------------------------------------*/
128 void dbg_dumpregusage(void)
129 {
130         
131         fprintf(stderr,"***  Register Usage  ***\n");
132         fprintf(stderr,"InternalRegs:\n");
133         dbg_regusage(dynInternalRegs);
134         fprintf(stderr,"AllocRegs:\n");
135         dbg_regusage(dynAllocRegs);
136         fprintf(stderr,"StackRegs:\n");
137         dbg_regusage(dynStackRegs);
138         fprintf(stderr,"DirectRegs:\n");
139         dbg_regusage(dynDirectRegs);
140         fprintf(stderr,"DirectBitRegs:\n");
141         dbg_regusage(dynDirectBitRegs);
142         fprintf(stderr,"ProcessorRegs:\n");
143         dbg_regusage(dynProcessorRegs);
144         
145 }
146
147
148 /*-----------------------------------------------------------------*
149 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
150 *-----------------------------------------------------------------*/
151 void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
152 {
153         
154         pCode *pc=NULL;
155         
156         regs *reg;
157         
158         if(!pcfl)
159                 return;
160         
161         
162         pc = findNextInstruction(pcfl->pc.next);
163         
164         while(pc && !isPCFL(pc)) {
165                 while (pc && !isPCI(pc) && !isPCFL(pc))
166                 {
167                         pc = pc->next;
168                 } // while
169                 if (!pc || isPCFL(pc)) continue;
170                 assert( isPCI(pc) );
171
172                 reg = getRegFromInstruction(pc);
173                 #if 0
174                 pc->print(stderr, pc);
175                 fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
176                         reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
177                         PCI(pc)->inCond, PCI(pc)->outCond );
178                 #endif
179                 if(reg) {
180                 /*
181                 fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
182                 fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x\n",
183                 reg->address,reg->type,reg->rIdx);
184                         */
185                         
186                         addSetIfnotP(& (PCFL(pcfl)->registers), reg);
187                         
188                         if(PCC_REGISTER & PCI(pc)->inCond)
189                                 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
190                         
191                         if(PCC_REGISTER & PCI(pc)->outCond)
192                                 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
193                         
194                         addSetIfnotP(& (reg->reglives.usedpCodes), pc);
195                         reg->wasUsed = 1;
196                 }
197                 
198                 
199                 //pc = findNextInstruction(pc->next);
200                 pc = pc->next;
201                 
202         }
203
204 }
205
206 /*-----------------------------------------------------------------*
207 * void pCodeRegMapLiveRanges(pBlock *pb) 
208 *-----------------------------------------------------------------*/
209 void pCodeRegMapLiveRanges(pBlock *pb)
210 {
211         pCode *pcflow;
212         
213         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
214         pcflow != NULL;
215         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
216                 
217                 if(!isPCFL(pcflow)) {
218                         fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
219                         continue;
220                 }
221                 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
222         }
223         
224 #if 0
225         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
226         pcflow != NULL;
227         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
228                 
229                 regs *r = setFirstItem(PCFL(pcflow)->registers);
230                 fprintf(stderr,"flow seq %d\n", pcflow->seq);
231                 
232                 while (r) {
233                         fprintf(stderr, "  %s\n",r->name);
234                         r = setNextItem(PCFL(pcflow)->registers);
235                         
236                 }
237                 
238         }
239 #endif
240         
241         //  dbg_dumpregusage();
242         
243 }
244
245
246 /*-----------------------------------------------------------------*
247 *
248 *-----------------------------------------------------------------*/
249 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
250 {
251
252         pCode *pcn=NULL;
253         
254         if(!reg || !pc)
255                 return;
256
257         deleteSetItem (&(reg->reglives.usedpCodes),pc);
258         
259         if(PCI(pc)->label) {
260                 pcn = findNextInstruction(pc->next);
261                 
262                 if(pcn)
263                         PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
264         }
265         
266         if(PCI(pc)->cline) {
267                 if(!pcn)
268                         pcn = findNextInstruction(pc->next);
269                 
270                 if(pcn) {
271                         if(PCI(pcn)->cline) {
272                                 //fprintf(stderr, "source line has been optimized completely out\n");
273                                 //pc->print(stderr,pc);
274                         } else {
275                                 PCI(pcn)->cline = PCI(pc)->cline;
276                         }
277                 }
278         }
279         
280         
281         if(1){
282         /*
283         Debug stuff. Comment out the instruction we're about to delete.
284                 */
285                 
286                 char buff1[256];
287                 size_t size = 256;
288                 
289                 char *pbuff,**ppbuff;
290                 pbuff = buff1;
291                 ppbuff = &pbuff;
292                 
293                 SAFE_snprintf(ppbuff,&size, ";%d", debug_code);
294                 pCode2str(*ppbuff, size, pc);
295                 pCodeInsertBefore(pc, newpCodeCharP(buff1));
296                 //fprintf(stderr,"removing instruction:\n%s\n",buff1);
297         }
298         
299         pc->destruct(pc);
300         
301 }
302
303 /*-----------------------------------------------------------------*
304 * void RemoveRegsFromSet(set *regset)
305 *
306 *-----------------------------------------------------------------*/
307 void  RemoveRegsFromSet(set *regset)
308 {
309         regs *reg;
310         int used;
311         
312         while(regset) {
313                 reg = regset->item;
314                 regset = regset->next;
315                 
316                 used = elementsInSet(reg->reglives.usedpCodes);
317                 
318                 if(used <= 1) {
319                         
320                         //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
321                         if(used == 0) {
322                                 //fprintf(stderr," getting rid of reg %s\n",reg->name);
323                                 reg->isFree = 1;
324                                 reg->wasUsed = 0;
325                         } else {
326                                 pCode *pc;
327                                 
328                                 
329                                 pc = setFirstItem(reg->reglives.usedpCodes);
330                                 
331                                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
332                                         //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
333                                         continue;
334                                 }
335                                 
336                                 
337                                 if(isPCI(pc)) {
338                                         if(PCI(pc)->label) {
339                                                 pCode *pcn = findNextInstruction(pc->next);
340                                                 
341                                                 if(pcn && PCI(pcn)->label) {
342                                                         //fprintf(stderr,"can't delete instruction with label...\n");
343                                                         //pc->print(stderr,pc);
344                                                         continue;
345                                                 } 
346                                                 /* Move the label to the next instruction */
347                                                 
348                                                 PCI(pcn)->label = PCI(pc)->label;
349                                                 
350                                         }
351                                         
352                                         if(isPCI_SKIP(pc)) {
353                                                 regs *r = getRegFromInstruction(pc);
354                                                 fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
355                                                 pc->print(stderr,pc);
356                                                 fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
357                                         }
358                                         //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
359                                         Remove1pcode(pc, reg, 1);
360                                         /*
361                                         unlinkpCode(pc);
362                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
363                                         */
364                                         reg->isFree = 1;
365                                         reg->wasUsed = 0;
366                                         total_registers_saved++;  // debugging stats.
367                                 }
368                         }
369                 }
370                 
371         }
372 }
373
374 void RegsUnMapLiveRanges(void);
375 extern pFile *the_pFile;
376 void pic14_ReMapLiveRanges(void)
377 {
378         pBlock *pb;
379         if (!the_pFile) return;
380         RegsUnMapLiveRanges();
381         for (pb = the_pFile->pbHead; pb; pb = pb->next)
382         {
383         #if 0
384                 pCode *pc = findNextpCode(pb->pcHead, PC_FLOW);
385                 if (pc) {
386                         pc->print( stderr, pc );
387                 } else {
388                         fprintf( stderr, "unnamed pBlock\n");
389                 }
390                 pc = findNextInstruction(pb->pcHead);
391                 while (pc) {
392                   pc->print( stderr, pc );
393                   pc = findNextInstruction(pc->next);;
394                 }
395         #endif  
396                 pCodeRegMapLiveRanges(pb);
397         } // for
398 }
399
400 /*-----------------------------------------------------------------*
401 * void RemoveUnusedRegisters(void)
402 *
403 *-----------------------------------------------------------------*/
404 void RemoveUnusedRegisters(void)
405 {
406         /* First, get rid of registers that are used only one time */
407         pic14_ReMapLiveRanges();
408         
409         //RemoveRegsFromSet(dynInternalRegs);
410         RemoveRegsFromSet(dynAllocRegs);
411         RemoveRegsFromSet(dynStackRegs);
412         /*
413         don't do DirectRegs yet - there's a problem with arrays
414         RemoveRegsFromSet(dynDirectRegs);
415         */
416         RemoveRegsFromSet(dynDirectBitRegs);
417         
418         if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
419 }
420
421
422 /*-----------------------------------------------------------------*
423 *
424 *-----------------------------------------------------------------*/
425 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free)
426 {
427         static int debug_code=99;
428         if(!reg)
429                 return;
430 #if 0
431         fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
432         printpCode (stderr, pc1);
433         printpCode (stderr, pc2);
434 #endif
435         
436         //fprintf(stderr,"%s\n",__FUNCTION__);
437         if(pc1)
438                 Remove1pcode(pc1, reg, debug_code++);
439         
440         if(pc2) {
441                 Remove1pcode(pc2, reg, debug_code++);
442                 deleteSetItem (&(PCFL(pcflow)->registers), reg);
443                 
444                 if(can_free) {
445                         reg->isFree = 1;
446                         reg->wasUsed = 0;
447                 }
448                 
449         }
450         
451         pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
452 }
453
454 /*-----------------------------------------------------------------*
455 *
456 *-----------------------------------------------------------------*/
457 int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
458 {
459         int i=0;
460         regs *testreg;
461         
462         do {
463                 testreg = getRegFromInstruction(pc1);
464                 if(testreg && (testreg->rIdx == reg->rIdx)) {
465                         return 1;
466                 }
467                 if (i++ > 1000) {
468                         fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
469                         return 0;
470                 }
471                 
472                 pc1 = findNextInstruction(pc1->next);
473                 
474         } while (pc1 && (pc1 != pc2)) ;
475         
476         return 0;
477 }
478
479 int regIsSpecial (regs *reg, int mayBeGlobal)
480 {
481   if (!reg) return 0;
482
483   if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
484
485   return 0;
486 }
487
488 #if 0
489 static int regIsLocal (regs *reg)
490 {
491         if (!reg) return 1;
492         /* temporaries are local */
493         if (reg->type == REG_TMP) return 1;
494         /* registers named r0x... are local */
495         if (reg->name && !strncmp(reg->name,"r0x", 3))
496         {
497                 //fprintf (stderr, "reg %s is not marked REG_TMP...\n", reg->name);
498                 return 1;
499         }
500
501         return 0;
502 }
503 #endif
504
505 /*-----------------------------------------------------------------*
506 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2) 
507 *
508 * ADHOC pattern checking 
509 * Now look for specific sequences that are easy to optimize.
510 * Many of these sequences are characteristic of the compiler
511 * (i.e. it'd probably be a waste of time to apply these adhoc
512 * checks to hand written assembly.)
513
514 *
515 *-----------------------------------------------------------------*/
516 int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
517 {
518         pCode *pct1, *pct2;
519         regs  *reg1, *reg2;
520         
521         int t = total_registers_saved;
522
523         if (!isPCI(pc1) || !isPCI(pc2)) return 0;
524         if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
525         
526         if (pc2->seq < pc1->seq) {
527                 pct1 = pc2;
528                 pc2 = pc1;
529                 pc1 = pct1;
530         }
531
532         /* disable this optimization for now -- it's buggy */
533         if (pic14_options.disable_df) return 0;
534         
535         //fprintf(stderr,"pCodeOptime2pCodes\n");
536         //pc1->print(stderr,pc1);
537         //pc2->print(stderr,pc2);
538
539         if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
540             /*
541              * CLRF sets Z
542              * MOVFW affects Z
543              * MOVWF does not touch Z
544              * MOVLW does not touch Z
545              */
546                 pCode *newpc;
547                 /*
548                 clrf  reg    ; pc1
549                 stuff...
550                 movf  reg,w  ; pc2
551                 
552                   can be replaced with (only if following instructions are not going to use W and reg is not used again later)
553                   
554                         stuff...
555                         movlw 0 or clrf  reg
556                 */
557                 DFPRINTF((stderr, "   optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
558                 pct2 = findNextInstruction(pc2->next);
559                 if (pCodeSearchCondition(pct2, PCC_Z, 0) == -1) {
560                         /* Z is definitely overwritten before use */
561                         newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
562                         
563                         pCodeInsertAfter(pc2, newpc);
564                         PCI(newpc)->pcflow = PCFL(pcfl_used);
565                         newpc->seq = pc2->seq;
566                         
567                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
568                         //Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
569                         pc2->destruct(pc2);
570                         //total_registers_saved++;  // debugging stats.
571                 }
572         } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
573                 DFPRINTF((stderr, "   optimising CLRF/IORFW\n"));
574                 
575                 pct2 = findNextInstruction(pc2->next);
576                 
577                 /* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
578                 if (pCodeSearchCondition(pct2, PCC_Z, 0) != -1) {
579                         pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
580                         pct2->seq = pc2->seq;
581                         PCI(pct2)->pcflow = PCFL(pcfl_used);
582                         pCodeInsertAfter(pc1,pct2);
583                 }
584                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
585                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
586                 total_registers_saved++;  // debugging stats.
587                 
588         }  else if(PCI(pc1)->op == POC_MOVWF) {
589                 // Optimising MOVWF reg ...
590                 
591                 pct2 = findNextInstruction(pc2->next);
592                 
593                 if(PCI(pc2)->op == POC_MOVFW) {
594                         // Optimising MOVWF reg ... MOVF reg,W
595                         
596                         if(PCI(pct2)->op == POC_MOVWF) {
597                         /*
598                         Change:
599                         
600                           movwf   reg    ; pc1
601                           stuff...
602                           movf    reg,w  ; pc2
603                           movwf   reg2   ; pct2
604                           
605                                 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
606                                 
607                                   movwf   reg2
608                                   stuff...
609                                   
610                                 */
611                                 reg2 = getRegFromInstruction(pct2);
612                                 /* Check reg2 is not used for something else before it is loaded with reg */
613                                 if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
614                                         pCode *pct3 = findNextInstruction(pct2->next);
615                                         /* Check following instructions are not relying on the use of W or the Z flag condiction */
616                                         /* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
617                                          *      subsequent flows (checking for < 1 is insufficient). */
618                                         if ((pCodeSearchCondition(pct3,PCC_Z,0) == -1) && (pCodeSearchCondition(pct3,PCC_W,0) == -1)) {
619                                                 DFPRINTF((stderr, "   optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
620                                                 pct2->seq = pc1->seq;
621                                                 unlinkpCode(pct2);
622                                                 pCodeInsertBefore(pc1,pct2);
623                                                 if(regUsedinRange(pct2,0,reg))
624                                                 {
625                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
626                                                         Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
627                                                 } else {
628                                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W  MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
629                                                         Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
630                                                 }
631                                                 total_registers_saved++;  // debugging stats.
632                                                 return 1;
633                                         }
634                                 }
635                         }
636                 }
637                 
638                 pct1 = findPrevInstruction(pc1->prev);
639                 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
640                         
641                         if ( (PCI(pct1)->op == POC_MOVFW) &&
642                                 (PCI(pc2)->op == POC_MOVFW)) {
643                                 
644                                 reg1 = getRegFromInstruction(pct1);
645                                 if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
646                                         DFPRINTF((stderr, "   optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
647                                         /*
648                                         Change:
649                                         
650                                                 movf   reg1,w
651                                                 movwf  reg
652
653                                                 stuff...
654                                                 movf   reg,w
655                                                 
656                                         To:
657
658                                                 stuff...
659
660                                                 movf   reg1,w
661
662                                         Or, if we're not deleting the register then the "To" is:
663
664                                                 stuff...
665
666                                                 movf   reg1,w
667                                                 movwf  reg
668                                         */
669                                         pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
670                                         pCodeInsertAfter(pc2, pct2);
671                                         PCI(pct2)->pcflow = PCFL(pcfl_used);
672                                         pct2->seq = pc2->seq;
673                                         
674                                         if(can_free) {
675                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
676                                                 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
677                                         } else {
678                                         /* If we're not freeing the register then that means (probably)
679                                                 * the register is needed somewhere else.*/
680                                                 unlinkpCode(pc1);
681                                                 pCodeInsertAfter(pct2, pc1);
682                                                 
683                                                 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
684                                                 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
685                                         }
686                                         
687                                         //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
688                                         Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
689                                         total_registers_saved++;  // debugging stats.
690                                         
691                                 }
692                         }
693                 }
694   }
695
696   return (total_registers_saved != t);
697 }
698
699 /*-----------------------------------------------------------------*
700 * void pCodeRegOptimeRegUsage(pBlock *pb) 
701 *-----------------------------------------------------------------*/
702 void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
703 {
704         regs *reg;
705         int used;
706         pCode *pc1=NULL, *pc2=NULL;
707         
708         
709         while(fregs) {
710                 pCode *pcfl_used, *pcfl_assigned;
711                 
712                 /* Step through the set by directly accessing the 'next' pointer.
713                 * We could also step through by using the set API, but the 
714                 * the (debug) calls to print instructions affect the state
715                 * of the set pointers */
716                 
717                 reg = fregs->item;
718                 fregs = fregs->next;
719                 /*
720                 if (strcmp(reg->name,"_SubState")==0)
721                 fprintf(stderr,"Reg: %s\n",reg->name);
722                 */
723                 
724                 /* Catch inconsistently set-up live ranges
725                  * (see tracker items #1469504 + #1474602)
726                  * FIXME: Actually we should rather fix the
727                  * computation of the liveranges instead...
728                  */
729                 if (!reg || !reg->reglives.usedpFlows
730                         || !reg->reglives.assignedpFlows)
731                 {
732                   //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
733                   continue;
734                 }
735
736                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
737                         //fprintf(stderr,"skipping SFR: %s\n",reg->name);
738                         continue;
739                 }
740
741                 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
742                 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
743                 
744                 used = elementsInSet(reg->reglives.usedpCodes);
745                 if(used == 2) { 
746                         /*
747                         In this section, all registers that are used in only in two 
748                         instructions are examined. If possible, they're optimized out.
749                         */
750                         
751                         /*
752                         fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
753                         reg->name,
754                         reg->address,
755                         reg->rIdx, reg->type, used);
756                         */
757                         pc1 = setFirstItem(reg->reglives.usedpCodes);
758                         pc2 = setNextItem(reg->reglives.usedpCodes);
759                         
760                         if(pcfl_used && pcfl_assigned) {
761                                 /* 
762                                 expected case - the register has been assigned a value and is
763                                 subsequently used 
764                                 */
765                                 
766                                 //fprintf(stderr," used only twice\n");
767                                 if(pcfl_used->seq == pcfl_assigned->seq) {
768                                         
769                                         //fprintf(stderr, "  and used in same flow\n");
770                                         
771                                         pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
772                                         
773                                 } else {
774                                         // fprintf(stderr, "  and used in different flows\n");
775                                         
776                                 }
777                                 
778                         } else if(pcfl_used) {
779                                 
780                                 /* register has been used twice without ever being assigned */
781                                 fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
782                                 
783                         } else {
784                                 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
785                                 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
786                                 total_registers_saved++;  // debugging stats.
787                         }
788                 } else {
789                         
790                         /* register has been used either once, or more than twice */
791                         
792                         if(used && !pcfl_used && pcfl_assigned) {
793                                 pCode *pc;
794                                 
795                                 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
796                                 
797                                 pc = setFirstItem(reg->reglives.usedpCodes);
798                                 while(pc) {
799                                         
800                                         pcfl_assigned = PCODE(PCI(pc)->pcflow);
801                                         Remove1pcode(pc, reg,2);
802                                         
803                                         deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
804                                         /*
805                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
806                                         pc->destruct(pc);
807                                         */
808                                         pc = setNextItem(reg->reglives.usedpCodes);
809                                 }
810                                 
811                                 
812                                 reg->isFree = 1;
813                                 reg->wasUsed = 0;
814                                 
815                                 total_registers_saved++;  // debugging stats.
816                         } else if( (used > 2) && optimize_multi_uses) {
817                                 
818                                 set *rset1=NULL;
819                                 set *rset2=NULL;
820                                 int searching=1;
821                                 
822                                 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
823                                 
824                                 /* examine the number of times this register is used */
825                                 
826                                 
827                                 rset1 = reg->reglives.usedpCodes;
828                                 while(rset1 && searching) {
829                                         
830                                         pc1 = rset1->item;
831                                         rset2 = rset1->next;
832                                         
833                                         if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
834                                                 
835                                                 //while(rset2 && searching) {
836                                                 if(rset2) {
837                                                         
838                                                         pc2 = rset2->item;
839                                                         if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
840                                                                 if(pcfl2 == pcfl1) {
841                                                                         
842                                                                         if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
843                                                                                 searching = 0;
844                                                                 }
845                                                         }
846                                                         
847                                                         //rset2 = rset2->next;
848                                                         
849                                                 }
850                                         }
851                                         rset1 = rset2;
852                                 }
853                         }
854                 }
855         }
856 }
857
858 #if 0
859
860 /* The following routines implement pCode optimizations based on
861  * dataflow analysis. The effects should be similar to those
862  * of pCodeOptime2pCodes() but more powerful.
863  *
864  * Unfortunately, the current approach (comparing operands by
865  * their associated registers) is seriously flawed:
866  * Some pCodeOps do not provide access to their repsective regs
867  * (PO_DIRs are created from arbitrary strings, immediates need
868  * to take offset and index into account, ...)
869  *
870  * This has to be rewritten based on pCodeOps instead of regs...
871  */
872
873 /* ------------------------------------------------------------------
874    Returns TRUE iff reg1 and reg2 are the same registers.
875    ------------------------------------------------------------------ */
876
877 static int sameRegs (const regs *reg1, const regs *reg2)
878 {
879         if (reg1 == reg2) return 1;
880         if (!reg1 || !reg2) return 0;
881         assert (reg1->name && reg2->name);
882
883         /* Compare names, as rIdx is not unique... */
884         if (!strcmp(reg1->name, reg2->name)) return 1;
885
886         /* Name mismatch -- not the same register. */
887         return 0;
888 }
889
890 /* ------------------------------------------------------------------
891    Returns 1 if the register is live at pc (read in this flow),
892    returns -1 if the register is NOT live at pc (assigned a new value
893    prior to readingi the old value in this flow) or
894    return 0 if the register is not mentioned.
895    ------------------------------------------------------------------ */
896
897 static int checkRegInFlow (regs **reg, int *cond, pCode *pc)
898 {
899         const int verbose = 0;
900         /* find next PCI at or after pc */
901         while (pc && isPCFL(pc)) pc = pc->next;
902
903         assert (reg && cond);
904
905         /* remove pseudo flags from cond */
906         *cond &= ~(PCC_REGISTER | PCC_EXAMINE_PCOP);
907
908         if (verbose && pc)
909         {
910                 fprintf (stderr, "Checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond); pc->print (stderr, pc);
911         }
912         
913         while (pc && !isPCFL(pc))
914         {
915                 if (verbose)
916                 {
917                         fprintf (stderr, "        now checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond);
918                         pc->print (stderr, pc);
919                 }
920                 if (isPCI(pc))
921                 {
922                         pCode *pcprev;
923                         regs *op = NULL;
924                         int prevIsSkip = 0;
925                         
926                         pcprev = findPrevInstruction (pc);
927                         if (pcprev && isPCI_SKIP(pcprev))
928                                 prevIsSkip = 1;
929
930                         if ((PCI(pc)->inCond | PCI(pc)->outCond) & PCC_REGISTER)
931                         {
932                                 op = getRegFromInstruction (pc);
933
934                                 /* pCodeOpRegBits do not provide register information... */
935                                 //if (!op) { __asm__("int3"); pc->print (stderr, pc); }
936                                 //assert (op);
937                                 if (!op) 
938                                 {
939                                         if (reg)
940                                                 return 1; /* assume `reg' is alive */
941                                 }
942
943                                 /* SPECIAL CASE: jump to unknown destination -- assume everything alive */
944                                 if (op->type == PO_PCL)
945                                 {
946                                         return 1;
947                                 }
948                         } // if
949
950                         if (PCI(pc)->inCond & PCC_REGISTER)
951                         {
952                                 /* `op' is live (possibly read) */
953                                 if (*reg && sameRegs (op, *reg))
954                                 {
955                                         if (verbose)
956                                         {
957                                                 fprintf (stderr, "reg is read in pc ");
958                                                 pc->print (stderr, pc);
959                                         }
960                                         return 1;
961                                 }
962                         }
963
964                         /* handle additional implicit operands */
965                         switch (PCI(pc)->op)
966                         {
967                         case POC_CALL: /* read arguments from WREG, clobbers WREG */
968                                 if (*cond & PCC_W)
969                                 {
970                                         if (verbose)
971                                         {
972                                                 fprintf (stderr, "conditions are read at pc ");
973                                                 pc->print (stderr, pc);
974                                         }
975                                         return 1;
976                                 }
977                                 *cond &= ~PCC_W;
978                                 break;
979                         case POC_RETURN: /* returns WREG to caller */
980                                 //fprintf (stderr, "reached RETURN, reg %s, cond %x\n", *reg ? (*reg)->name : "<none>", *cond);
981                                 if (*cond & PCC_W)
982                                 {
983                                         if (verbose)
984                                         {
985                                                 fprintf (stderr, "conditions are read at pc ");
986                                                 pc->print (stderr, pc);
987                                         }
988                                         return 1;
989                                 }
990                                 /* afterwards, no condition is alive */
991                                 *cond = 0;
992                                 /* afterwards, all local registers are dead */
993                                 if (*reg && regIsLocal (*reg)) *reg = NULL;
994                                 break;
995                         case POC_RETLW:
996                         case POC_RETFIE: /* this does not erturn WREG to the "caller", thus its rather a RETLW */
997                                 /* this discards WREG */
998                                 *cond &= ~PCC_W;
999                                 /* afterwards, no condition is alive */
1000                                 *cond = 0;
1001                                 /* afterwards, all local registers are dead */
1002                                 if (*reg && regIsLocal (*reg)) *reg = NULL;
1003                                 break;
1004                         default:
1005                                 /* no implicit arguments */
1006                                 break;
1007                         }
1008
1009                         if (PCI(pc)->inCond & (*cond))
1010                         {
1011                                 /* a condition is read */
1012                                 if (verbose)
1013                                 {
1014                                         fprintf (stderr, "conditions are read at pc ");
1015                                         pc->print (stderr, pc);
1016                                 }
1017                                 return 1;
1018                         }
1019
1020                         /* remove outConds from `cond' */
1021                         (*cond) &= ~(PCI(pc)->outCond);
1022
1023                         if (PCI(pc)->outCond & PCC_REGISTER)
1024                         {
1025                                 /* `op' is (possibly) discarded */
1026                                 if (*reg && !prevIsSkip && sameRegs (op, *reg))
1027                                 {
1028                                         if (verbose)
1029                                         {
1030                                                 fprintf (stderr, "reg is assigned (cont'd) at pc ");
1031                                                 pc->print (stderr, pc);
1032                                         }
1033                                         *reg = NULL;
1034                                 }
1035                         }
1036
1037                         /* have all interesting conditions/registers been discarded? */
1038                         if (!(*reg) && !(*cond))
1039                         {
1040                                 if (verbose)
1041                                 {
1042                                         fprintf (stderr, "reg and conditions are discarded after ");
1043                                         pc->print (stderr, pc);
1044                                 }
1045                                 return -1;
1046                         }
1047                 } // if
1048
1049                 pc = pc->next;
1050         } // while
1051
1052         /* no use of (or only conditional writes to) `reg' found in flow */
1053         if (verbose)
1054         {
1055                 fprintf (stderr, "analysis inconclusive: reg %s, cond %x remains\n", *reg ? "remains" : "is void", *cond);
1056         }
1057         return 0;
1058 }
1059
1060 /* ------------------------------------------------------------------
1061    This will return 1 only if
1062    - reg is NULL or of type REG_TMP
1063    - reg is NULL or its value is discarded after pc
1064    - cond is 0 or all conditions are overwritten before being used
1065    ------------------------------------------------------------------ */
1066
1067 typedef struct {
1068   pCode *pc;
1069   regs *reg;
1070   int cond;
1071 } df_state_t;
1072
1073 df_state_t *df_free_states = NULL;
1074
1075 static df_state_t *
1076 df_newState (regs *reg, int cond, pCode *pc)
1077 {
1078         df_state_t *state;
1079
1080         if (df_free_states) {
1081           state = df_free_states;
1082           df_free_states = (df_state_t *)df_free_states->pc;
1083         } else {
1084           state = Safe_calloc(1, sizeof(df_state_t));
1085         }
1086         state->pc = pc;
1087         state->reg = reg;
1088         state->cond = cond;
1089         return state;
1090 }
1091
1092 static int
1093 df_containsState (set *set, df_state_t *state)
1094 {
1095         /* scan set for presence of `state' */
1096         df_state_t *curr;
1097         for (curr = setFirstItem (set); curr; curr = setNextItem (set))
1098         {
1099                 if ((curr->pc == state->pc)
1100                         && (curr->reg == state->reg)
1101                         && (curr->cond == state->cond))
1102                 {
1103                         /* `state' found */
1104                         return 1;
1105                 }
1106         }
1107         return 0;
1108 }
1109
1110 static void
1111 df_releaseState (df_state_t *state)
1112 {
1113         state->pc = (pCode *)df_free_states;
1114         df_free_states = (df_state_t *)state;
1115         state->reg = NULL;
1116         state->cond = 0;
1117 }
1118
1119 static void
1120 df_removeStates ()
1121 {
1122         df_state_t *next;
1123         while (df_free_states)
1124         {
1125                 next = (df_state_t *)df_free_states->pc;
1126                 Safe_free(df_free_states);
1127                 df_free_states = next;
1128         } // while
1129 }
1130
1131 int regIsDead (regs *reg, int cond, pCode *pc)
1132 {
1133         set *seenStates = NULL;
1134         set *todo = NULL;
1135         pCode *curr;
1136         df_state_t *state;
1137         int result = 1;
1138         
1139         /* sanity checks */
1140         if (reg && !regIsLocal (reg)) return 0;
1141
1142         pc = findNextInstruction (pc->next);
1143
1144         addSet (&todo, df_newState(reg, cond, pc));
1145
1146         while ((result == 1) && (state = getSet (&todo)))
1147         {
1148                 int res;
1149                 
1150                 if (df_containsState (seenStates, state)) continue;
1151                 addSet (&seenStates, state);
1152
1153                 curr = state->pc;
1154                 reg = state->reg;
1155                 cond = state->cond;
1156                 
1157                 //fprintf (stderr, "Checking for reg %s/cond %x at pc ", reg ? reg->name : "<none>", cond);
1158                 //curr->print (stderr, curr);
1159
1160                 res = checkRegInFlow (&reg, &cond, curr);
1161                 switch (res)
1162                 {
1163                 case 1: /* `reg' or `cond' is read---not dead */
1164                         result = 0;
1165                         break;
1166                 case -1: /* `reg' and `cond' are discarded in this flow---need to check other open flows */
1167                         break;
1168                 default: /* `reg' is not read and (possibly) not assigned---check successor flows */
1169                         if (curr)
1170                         {
1171                                 pCodeFlow *pcfl = PCI(curr)->pcflow;
1172                                 pCodeFlowLink *link;
1173                                 pCode *first;
1174                                 assert (pcfl);
1175
1176                                 for (link = setFirstItem(pcfl->to); link; link = setNextItem (pcfl->to))
1177                                 {
1178                                         /* add the first pCodeInstruction in the new flow to `todo' */
1179                                         first = findNextInstruction (&link->pcflow->pc);
1180                                         if (first) addSet (&todo, df_newState (reg, cond, first));
1181                                 } // for
1182                         }
1183                         break;
1184                 } // switch
1185         } // while
1186
1187         /* clean up */
1188         while (NULL != (state = getSet (&todo))) { df_releaseState (state); }
1189         while (NULL != (state = getSet (&seenStates))) { df_releaseState (state); }
1190
1191         /* if result remained 1, `reg' is not even possibly read and thus dead */
1192         return result;
1193 }
1194
1195
1196
1197 /* ------------------------------------------------------------------
1198    Safely remove a pCode.
1199    This needs to check that the previous instruction was no SKIP
1200    (otherwise the SKIP instruction would have to be removed as well,
1201    which may not be done for SFRs (side-effects on read possible)).
1202    ------------------------------------------------------------------ */
1203
1204 extern void unBuildFlow (pBlock *pb);
1205 extern void RegsUnMapLiveRanges ();
1206 extern void BuildFlow (pBlock *pb);
1207 extern void LinkFlow (pBlock *pb);
1208 extern void BuildFlowTree (pBlock *pb);
1209 extern void pCodeRegMapLiveRanges (pBlock *pb);
1210 extern pFile *the_pFile;
1211
1212 static int pCodeRemove (pCode *pc, const char *comment)
1213 {
1214         pCode *pcprev, *pcnext;
1215         unsigned int result = 0;
1216         
1217         /* Sanity checks. */
1218         if (!pc) return 0;
1219         if (!isPCI(pc)) return 0;
1220
1221         pcprev = findPrevInstruction (pc->prev);
1222         if (pcprev && isPCI_SKIP(pcprev))
1223         {
1224                 /* bail out until we know how to fix the Flow... */
1225                 //return 0;
1226
1227                 /* we also need to remove the preceeding SKIP instruction(s) */
1228                 result = pCodeRemove (pcprev, "=DF= removing preceeding SKIP as well");
1229                 if (!result)
1230                 {
1231                         /* previous instruction could not be removed -- this cannot be removed as well */
1232                         return result;
1233                 }
1234                 /* FIXME: We now have to update the flow! */
1235         } // if
1236
1237         /* do not remove pCodes with SFRs as operands (even reading them might cause side effects) */
1238         {
1239                 regs *reg;
1240                 reg = getRegFromInstruction (pc);
1241                 /* accesses to the STATUS register aer always safe, but others... */
1242                 if (reg && reg->type == REG_SFR && reg->pc_type != PO_STATUS) return result;
1243         }
1244
1245         /* MUST SUCEED FROM NOW ON (or revert the changes done since NOW ;-)) */
1246         
1247         /* fix flow */
1248         if (PCI(pc)->pcflow && PCI(pc)->pcflow->end == pc)
1249         {
1250                 pCode *pcprev;
1251                 pcprev = findPrevInstruction (pc->prev);
1252                 if (PCI(pcprev)->pcflow == PCI(pc)->pcflow)
1253                 {
1254                         PCI(pc)->pcflow->end = pcprev;
1255                 } else {
1256                         pBlock *pb = pc->pb;
1257                         RegsUnMapLiveRanges();
1258                         unBuildFlow(pb);
1259                         BuildFlow(pb);
1260                         LinkFlow(pb);
1261                         BuildFlowTree(pb);
1262                         for (pb = the_pFile->pbHead; pb; pb = pb->next)
1263                         {
1264                                 pCodeRegMapLiveRanges(pb);
1265                         }
1266                 }
1267         }
1268         
1269         /* attach labels to next instruction */
1270         pcnext = findNextInstruction (pc->next);
1271         if (pcnext)
1272         {
1273                 PCI(pcnext)->label = pBranchAppend (PCI(pcnext)->label, PCI(pc)->label);
1274                 if (!PCI(pcnext)->cline) PCI(pcnext)->cline = PCI(pc)->cline;
1275         }
1276         else
1277         {
1278                 fprintf (stderr, "Cannot move a label...\n");
1279                 exit(EXIT_FAILURE);
1280         }
1281         
1282         if (comment)
1283         {
1284                 char buffer[512];
1285                 int size = 512;
1286                 char *pbuff = &buffer[0];
1287                 
1288                 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): %s", __FILE__, __LINE__, __FUNCTION__, comment);
1289                 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1290         } // if
1291
1292         if (1)
1293         {
1294                 /* replace removed pCode with out-commented version of itself */
1295                 char buffer[512];
1296                 int size = 512;
1297                 char *pbuff = &buffer[0];
1298                 
1299                 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): ", __FILE__, __LINE__, __FUNCTION__);
1300                 pCode2str (pbuff, size, pc);
1301                 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1302         }
1303
1304         pc->destruct (pc);
1305         return result+1;
1306 }
1307
1308 /* ------------------------------------------------------------------
1309    Find and remove dead pCodes.
1310    ------------------------------------------------------------------ */
1311
1312 static int removeIfDeadPCI (pCode *pc)
1313 {
1314         pCode *pcnext = NULL;
1315         pCode *curr;
1316         unsigned int outCond;
1317         unsigned int result = 0;
1318         regs *dst;
1319         
1320         if (!pc) return 0;
1321         dst = NULL;
1322         
1323         /* skip non-PCIs */
1324         pcnext = findNextInstruction (pc->next);
1325         if (!isPCI(pc)) return 0;
1326
1327         switch (PCI(pc)->op)
1328         {
1329         case POC_ADDLW:
1330         case POC_ADDWF:
1331         case POC_ADDFW:
1332         case POC_ANDLW:
1333         case POC_ANDWF:
1334         case POC_ANDFW:
1335         case POC_BCF:
1336         case POC_BSF:
1337         //case POC_BTFSC:
1338         //case POC_BTFSS:
1339         //case POC_CALL:
1340         case POC_COMF:
1341         case POC_COMFW:
1342         case POC_CLRF:
1343         case POC_CLRW:
1344         //case POC_CLRWDT:
1345         case POC_DECF:
1346         case POC_DECFW:
1347         //case POC_DECFSZ:
1348         //case POC_DECFSZW:
1349         //case POC_GOTO:
1350         case POC_INCF:
1351         case POC_INCFW:
1352         //case POC_INCFSZ:
1353         //case POC_INCFSZW:
1354         case POC_IORLW:
1355         case POC_IORWF:
1356         case POC_IORFW:
1357         case POC_MOVF:
1358         case POC_MOVFW:
1359         case POC_MOVLW:
1360         case POC_MOVWF:
1361         case POC_NOP:
1362         //case POC_RETLW:
1363         //case POC_RETURN:
1364         //case POC_RETFIE:
1365         case POC_RLF:
1366         case POC_RLFW:
1367         case POC_RRF:
1368         case POC_RRFW:
1369         case POC_SUBLW:
1370         case POC_SUBWF:
1371         case POC_SUBFW:
1372         case POC_SWAPF:
1373         case POC_SWAPFW:
1374         //case POC_TRIS:
1375         case POC_XORLW:
1376         case POC_XORWF:
1377         case POC_XORFW:
1378         //case POC_BANKSEL:
1379         //case POC_PAGESEL:
1380                 break;
1381         
1382         default:
1383                 /* do not remove unknown PCIs */
1384                 return 0;
1385         } // switch
1386
1387         /* redundant checks---those instructions may never be removed */
1388         if (isPCI_BRANCH(pc)) return 0;
1389         if (isPCI_SKIP(pc)) return 0;
1390         
1391         outCond = PCI(pc)->outCond;
1392         curr = pcnext;
1393
1394         /* unknown operands assigned to, then ignore */
1395         if ((outCond & (PCC_REGISTER | PCC_C | PCC_Z | PCC_DC | PCC_W)) != outCond)
1396                 return 0;
1397         
1398         if (outCond & PCC_REGISTER)
1399         {
1400                 dst = getRegFromInstruction (pc);
1401                 if (!dst) return 0;
1402
1403                 /* special reg? */
1404                 if (!regIsLocal (dst)) return 0;
1405                 if (regIsSpecial (dst,0)) return 0;
1406         }
1407         
1408         //fprintf (stderr, "--> checking for liveness pc "); pc->print (stderr, pc);
1409         if (regIsDead (dst, outCond, pc))
1410         {
1411                 /* no result from pc has been used -- pc is `dead' */
1412                 //fprintf (stderr, "--> reg %s and cond %x assumed unused\n", dst ? dst->name : "<none>", outCond);
1413                 //fprintf (stderr, "--> removing dead pc "); pc->print (stderr, pc);
1414                 result = pCodeRemove (pc, "=DF= removed dead pCode");
1415         }
1416         
1417         return result;
1418 }
1419
1420 /* ------------------------------------------------------------------
1421    This routine is intended to safely replace one pCodeInstruction
1422    with a different pCodeInstruction.
1423    If desired, the replaced pCode will be left in (commented out) for
1424    debugging.
1425    Further, an optional comment can be inserted to indicate the
1426    reason for the possible removal of the pCode.
1427    ------------------------------------------------------------------ */
1428
1429 static void replace_PCI (pCodeInstruction *pc, pCodeInstruction *newpc, char *comment)
1430 {
1431   newpc->from =  pBranchAppend (newpc->from, pc->from);
1432   newpc->to = pBranchAppend (newpc->to, pc->to);
1433   newpc->label = pBranchAppend (newpc->label, pc->label);
1434   //newpc->pcflow = pc->pcflow; // updated in pCodeInsertAfter, ->pb is as well
1435   newpc->cline = pc->cline;
1436
1437   newpc->pc.seq = pc->pc.seq;
1438
1439   pCodeInsertAfter (&pc->pc, &newpc->pc);
1440
1441   /* FIXME: replacing pc will break the liverange maps (usedpCodes, ...) */
1442   pCodeRegMapLiveRanges( pc->pBlock ); /*FIXME:UNTESTED*/
1443   
1444   if (comment)
1445   {
1446     pCodeInsertAfter (&pc->pc, newpCodeCharP (comment));
1447   } // if
1448
1449   if (1)
1450   {
1451     /* replace pc with commented out version of itself */
1452     char buffer[1024], buffer2[1024];
1453     char *pbuff = &buffer[0];
1454     int size=1024;
1455     pCode2str (&buffer2[0],1024,&pc->pc);
1456     SAFE_snprintf (&pbuff,&size,"%s:%u(%s): removed pCode was %s\t", __FILE__, __LINE__, __FUNCTION__, &buffer2[0]);
1457     pCodeInsertAfter (&pc->pc, newpCodeCharP (&buffer[0]));
1458   } // if
1459
1460   pc->pc.destruct (&pc->pc);
1461 }
1462
1463 /* ------------------------------------------------------------------
1464    Find the first (unique) assignment to `reg' (prior to pc).
1465    ------------------------------------------------------------------ */
1466
1467 pCode *findAssignmentToReg (regs *reg, pCode *pc)
1468 {
1469         pCode *curr;
1470         
1471         assert (pc && isPCI(pc) && reg);
1472
1473         curr = findPrevInstruction (pc->prev);
1474         
1475         while (curr && PCI(curr)->pcflow == PCI(pc)->pcflow)
1476         {
1477                 if (PCI(curr)->outCond & PCC_REGISTER)
1478                 {
1479                         regs *op = getRegFromInstruction (curr);
1480                         if (op && (sameRegs(op,reg)))
1481                                 return curr;
1482                 } // if
1483                 curr = findPrevInstruction (curr->prev);
1484         } // while
1485         
1486         /* no assignment to reg found */
1487         return NULL;
1488 }
1489
1490 /* ------------------------------------------------------------------
1491    Find a register that holds the same value as `reg' (an alias).
1492    ------------------------------------------------------------------ */
1493
1494 regs *findRegisterAlias (regs *reg, pCode *pc)
1495 {
1496         pCode *curr;
1497
1498         if(!reg) return NULL;
1499
1500         if (regIsSpecial (reg, 0)) return NULL;
1501
1502         curr = findAssignmentToReg (reg, pc);
1503
1504         /* no assignment found --> no alias found */
1505         if (!curr) return NULL;
1506
1507         switch (PCI(curr)->op)
1508         {
1509         case POC_MOVWF:
1510                 /* find previous assignment to WREG */
1511                 while (curr && !(PCI(curr)->outCond & PCC_W))
1512                         curr = findPrevInstruction (curr->prev);
1513                 if (curr && PCI(curr)->op == POC_MOVFW)
1514                 {
1515                         regs *op = getRegFromInstruction (curr);
1516                         /* alias must not be changed since assignment... */
1517                         if (PCI(curr)->pcop)
1518                         {
1519                                 switch (PCI(curr)->pcop->type)
1520                                 {
1521                                 case PO_GPR_REGISTER:
1522                                 case PO_GPR_TEMP:
1523                                         /* these operands are ok */
1524                                         break;
1525                                 default:
1526                                         /* not a plain register operand */
1527                                         return NULL;
1528                                         break;
1529                                 }
1530                         }
1531                         if (!op || regIsSpecial (op, 0) || !regIsUnchangedSince (op, pc, curr)) return NULL;
1532                         //fprintf (stderr, "found register alias for %s: %s\n", reg->name, op && op->name ? op->name : "<no name>");
1533                         return op;
1534                 } else {
1535                         /* unknown source to WREG -- unknown register alias */
1536                         return NULL;
1537                 }
1538                 break;
1539         
1540         default:
1541                 /* unhandled instruction -- assume unknown source, no alias */
1542                 return NULL;
1543         }
1544
1545         /* no alias found */
1546         return NULL;
1547 }
1548
1549 /* ------------------------------------------------------------------
1550    Analyze a single pCodeInstruction's dataflow relations and replace
1551    it with a better variant if possible.
1552    ------------------------------------------------------------------ */
1553
1554 void analyzeAndReplacePCI (pCodeInstruction *pci)
1555 {
1556         regs *op_reg, *alias_reg;
1557         
1558         assert (pci);
1559
1560         if (!isPCI(pci)) return;
1561         
1562         switch (pci->op)
1563         {
1564         case POC_MOVFW:
1565         case POC_ADDFW:
1566         case POC_ANDFW:
1567         case POC_IORFW:
1568         case POC_XORFW:
1569                 /* try to find a different source register */
1570                 op_reg = getRegFromInstruction (&pci->pc);
1571                 if (pci->op == POC_MOVFW) /* touches Z */
1572                 {
1573                         pCode *assignment = findAssignmentToReg (op_reg, &pci->pc);
1574                         if (assignment && isPCI(assignment) && (PCI(assignment)->op == POC_CLRF))
1575                         {
1576                                 replace_PCI (pci, PCI(newpCode(POC_MOVLW, newpCodeOpLit(0))), "replaced with CLRF");
1577                                 return;
1578                         }                       
1579                 }
1580                 
1581                 alias_reg = findRegisterAlias (op_reg, &pci->pc);
1582                 if (alias_reg)
1583                 {
1584                         replace_PCI (pci, PCI(newpCode(pci->op, newpCodeOpRegFromStr (alias_reg->name))), "=DF= replaced with move from register alias");
1585                 }
1586                 break;
1587
1588         default:
1589                 /* do not optimize */
1590                 break;
1591         } // switch
1592 }
1593
1594 extern pFile *the_pFile;
1595
1596 /* ------------------------------------------------------------------
1597    Find and remove dead pCodes.
1598    ------------------------------------------------------------------ */
1599
1600 static int removeDeadPCIs (void)
1601 {
1602         pBlock *pb;
1603         unsigned int removed = 0;
1604         
1605         if (!the_pFile) return removed;
1606         
1607         do {
1608                 removed = 0;
1609                 
1610                 /* iterate over all pBlocks */
1611                 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1612                 {
1613                         pCode *pc, *pcnext = NULL;
1614                         
1615                         /* iterate over all pCodes */
1616                         for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1617                         {
1618                                 pcnext = findNextInstruction (pc->next);
1619                                 removed += removeIfDeadPCI (pc);
1620                         } // while
1621                 } // for pb
1622
1623                 fprintf (stderr, "[removed %u dead pCodes]\n", removed);
1624         } while (removed);
1625         
1626         return 0;
1627 }
1628
1629 /* ------------------------------------------------------------------
1630    This routine tries to optimize the dataflow by...
1631    (1) 
1632    
1633    This routine leaves in dead pCodes (assignments whose results are
1634    not used) -- these should be removed in a following sweep phase.
1635    ------------------------------------------------------------------ */
1636
1637 void optimizeDataflow (void)
1638 {
1639         pBlock *pb;
1640         
1641         if (!the_pFile) return;
1642
1643         //fprintf (stderr, "%s:%u(%s): Starting optimization...\n", __FILE__, __LINE__, __FUNCTION__);
1644         
1645         /* iterate over all pBlocks */
1646         for (pb = the_pFile->pbHead; pb; pb = pb->next)
1647         {
1648                 pCode *pc, *pcnext = NULL;
1649                 
1650                 /* iterate over all pCodes */
1651                 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1652                 {
1653                         pcnext = findNextInstruction (pc->next);
1654                         analyzeAndReplacePCI (PCI(pc));
1655                 } // while
1656         } // for pb
1657
1658         while (removeDeadPCIs ()) { /* remove dead codes in multiple passes */};
1659         df_removeStates ();
1660 }
1661
1662 #endif
1663
1664 /*-----------------------------------------------------------------*
1665 * void pCodeRegOptimeRegUsage(pBlock *pb) 
1666 *-----------------------------------------------------------------*/
1667 void pCodeRegOptimizeRegUsage(int level)
1668 {
1669         
1670         int passes;
1671         int saved = 0;
1672         int t = total_registers_saved;
1673
1674 #if 0
1675         /* This is currently broken (need rewrite to correctly
1676          * handle arbitrary pCodeOps instead of registers only). */
1677         if (!pic14_options.disable_df)
1678                 optimizeDataflow ();
1679 #endif
1680
1681         if(!register_optimization)
1682                 return;
1683 #define OPT_PASSES 4
1684         passes = OPT_PASSES;
1685         
1686         do {
1687                 saved = total_registers_saved;
1688                 
1689                 /* Identify registers used in one flow sequence */
1690                 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
1691                 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
1692                 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
1693                 
1694                 if(total_registers_saved != saved)
1695                         DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
1696                         (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
1697                 
1698                 passes--;
1699                 
1700         } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
1701         
1702         if(total_registers_saved == t) 
1703                 DFPRINTF((stderr, "No registers saved on this pass\n"));
1704
1705
1706         /*
1707                 fprintf(stderr,"dynamically allocated regs:\n");
1708                 dbg_regusage(dynAllocRegs);
1709                 fprintf(stderr,"stack regs:\n");
1710                 dbg_regusage(dynStackRegs);
1711                 fprintf(stderr,"direct regs:\n");
1712                 dbg_regusage(dynDirectRegs);
1713         */
1714 }
1715
1716
1717 /*-----------------------------------------------------------------*
1718 * void RegsUnMapLiveRanges(set *regset)
1719 *
1720 *-----------------------------------------------------------------*/
1721 void  RegsSetUnMapLiveRanges(set *regset)
1722 {
1723         regs *reg;
1724         
1725         while(regset) {
1726                 reg = regset->item;
1727                 regset = regset->next;
1728                 
1729                 
1730                 deleteSet(&reg->reglives.usedpCodes);
1731                 deleteSet(&reg->reglives.usedpFlows);
1732                 deleteSet(&reg->reglives.assignedpFlows);
1733                 
1734         }
1735         
1736 }
1737
1738 void  RegsUnMapLiveRanges(void)
1739 {
1740         
1741         RegsSetUnMapLiveRanges(dynAllocRegs);
1742         RegsSetUnMapLiveRanges(dynStackRegs);
1743         RegsSetUnMapLiveRanges(dynDirectRegs);
1744         RegsSetUnMapLiveRanges(dynProcessorRegs);
1745         RegsSetUnMapLiveRanges(dynDirectBitRegs);
1746         RegsSetUnMapLiveRanges(dynInternalRegs);
1747         
1748 }