* src/pic/pcoderegs.c,
[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 //static int sameRegs (const regs *reg1, const regs *reg2);
47
48 int total_registers_saved=0;
49 int register_optimization=1;
50
51 /*-----------------------------------------------------------------*
52 * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
53 *-----------------------------------------------------------------*/
54 /*
55 void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
56 {
57
58         if(!reg || ! pcfl || !isPCFL(pcflow))
59         return;
60
61         if(!pcfl->registers) 
62         pcfl->registers =  newSet();
63         
64 }
65 */
66
67
68 /*-----------------------------------------------------------------*
69
70 *-----------------------------------------------------------------*/
71 void dbg_regusage(set *fregs)
72 {
73         regs *reg;
74         pCode *pcfl;
75         pCode *pc;
76         
77         
78         for (reg = setFirstItem(fregs) ; reg ;
79         reg = setNextItem(fregs)) {
80                 
81                 if(elementsInSet(reg->reglives.usedpCodes)) {
82                         
83                         fprintf (stderr, "%s  addr=0x%03x rIdx=0x%03x",
84                                 reg->name,
85                                 reg->address,
86                                 reg->rIdx);
87                         
88                         pcfl = setFirstItem(reg->reglives.usedpFlows);
89                         if(pcfl)
90                                 fprintf(stderr, "\n   used in seq");
91                         
92                         while(pcfl) {
93                                 fprintf(stderr," 0x%03x",pcfl->seq);
94                                 pcfl = setNextItem(reg->reglives.usedpFlows);
95                         }
96                         
97                         pcfl = setFirstItem(reg->reglives.assignedpFlows);
98                         if(pcfl)
99                                 fprintf(stderr, "\n   assigned in seq");
100                         
101                         while(pcfl) {
102                                 fprintf(stderr," 0x%03x",pcfl->seq);
103                                 pcfl = setNextItem(reg->reglives.assignedpFlows);
104                         }
105                         
106                         pc = setFirstItem(reg->reglives.usedpCodes);
107                         if(pc)
108                                 fprintf(stderr, "\n   used in instructions ");
109                         
110                         while(pc) {
111                                 pcfl = PCODE(PCI(pc)->pcflow);
112                                 if(pcfl)
113                                         fprintf(stderr," 0x%03x:",pcfl->seq);
114                                 fprintf(stderr,"0x%03x",pc->seq);
115                                 
116                                 pc = setNextItem(reg->reglives.usedpCodes);
117                         }
118                         
119                         fprintf(stderr, "\n");
120                 }
121         }
122 }
123
124 /*-----------------------------------------------------------------*
125
126 *-----------------------------------------------------------------*/
127 void dbg_dumpregusage(void)
128 {
129         
130         fprintf(stderr,"***  Register Usage  ***\n");
131         fprintf(stderr,"InternalRegs:\n");
132         dbg_regusage(dynInternalRegs);
133         fprintf(stderr,"AllocRegs:\n");
134         dbg_regusage(dynAllocRegs);
135         fprintf(stderr,"StackRegs:\n");
136         dbg_regusage(dynStackRegs);
137         fprintf(stderr,"DirectRegs:\n");
138         dbg_regusage(dynDirectRegs);
139         fprintf(stderr,"DirectBitRegs:\n");
140         dbg_regusage(dynDirectBitRegs);
141         fprintf(stderr,"ProcessorRegs:\n");
142         dbg_regusage(dynProcessorRegs);
143         
144 }
145
146
147 /*-----------------------------------------------------------------*
148 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
149 *-----------------------------------------------------------------*/
150 void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
151 {
152         
153         pCode *pc=NULL;
154         
155         regs *reg;
156         
157         if(!pcfl)
158                 return;
159         
160         
161         pc = findNextInstruction(pcfl->pc.next);
162         
163         while(pc && !isPCFL(pc)) {
164                 while (pc && !isPCI(pc) && !isPCFL(pc))
165                 {
166                         pc = pc->next;
167                 } // while
168                 if (!pc || isPCFL(pc)) continue;
169                 assert( isPCI(pc) );
170
171                 reg = getRegFromInstruction(pc);
172                 #if 0
173                 pc->print(stderr, pc);
174                 fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
175                         reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
176                         PCI(pc)->inCond, PCI(pc)->outCond );
177                 #endif
178                 if(reg) {
179                 /*
180                 fprintf(stderr, "flow seq %d, inst seq %d  %s  ",PCODE(pcfl)->seq,pc->seq,reg->name);
181                 fprintf(stderr, "addr = 0x%03x, type = %d  rIdx=0x%03x\n",
182                 reg->address,reg->type,reg->rIdx);
183                         */
184                         
185                         addSetIfnotP(& (PCFL(pcfl)->registers), reg);
186                         
187                         if(PCC_REGISTER & PCI(pc)->inCond)
188                                 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
189                         
190                         if(PCC_REGISTER & PCI(pc)->outCond)
191                                 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
192                         
193                         addSetIfnotP(& (reg->reglives.usedpCodes), pc);
194                         reg->wasUsed = 1;
195                 }
196                 
197                 
198                 //pc = findNextInstruction(pc->next);
199                 pc = pc->next;
200                 
201         }
202
203 }
204
205 /*-----------------------------------------------------------------*
206 * void pCodeRegMapLiveRanges(pBlock *pb) 
207 *-----------------------------------------------------------------*/
208 void pCodeRegMapLiveRanges(pBlock *pb)
209 {
210         pCode *pcflow;
211         
212         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
213         pcflow != NULL;
214         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
215                 
216                 if(!isPCFL(pcflow)) {
217                         fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
218                         continue;
219                 }
220                 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
221         }
222         
223 #if 0
224         for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); 
225         pcflow != NULL;
226         pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
227                 
228                 regs *r = setFirstItem(PCFL(pcflow)->registers);
229                 fprintf(stderr,"flow seq %d\n", pcflow->seq);
230                 
231                 while (r) {
232                         fprintf(stderr, "  %s\n",r->name);
233                         r = setNextItem(PCFL(pcflow)->registers);
234                         
235                 }
236                 
237         }
238 #endif
239         
240         //  dbg_dumpregusage();
241         
242 }
243
244
245 /*-----------------------------------------------------------------*
246 *
247 *-----------------------------------------------------------------*/
248 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
249 {
250
251         pCode *pcn=NULL;
252         
253         if(!reg || !pc)
254                 return;
255
256         deleteSetItem (&(reg->reglives.usedpCodes),pc);
257         
258         if(PCI(pc)->label) {
259                 pcn = findNextInstruction(pc->next);
260                 
261                 if(pcn)
262                         PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
263         }
264         
265         if(PCI(pc)->cline) {
266                 if(!pcn)
267                         pcn = findNextInstruction(pc->next);
268                 
269                 if(pcn) {
270                         if(PCI(pcn)->cline) {
271                                 //fprintf(stderr, "source line has been optimized completely out\n");
272                                 //pc->print(stderr,pc);
273                         } else {
274                                 PCI(pcn)->cline = PCI(pc)->cline;
275                         }
276                 }
277         }
278         
279         
280         if(1) {
281                 /*
282                  * Debug stuff. Comment out the instruction we're about to delete.
283                  */
284                 
285                 char buff1[256];
286                 size_t size = 256;
287                 
288                 char *pbuff;
289                 pbuff = &buff1[0];
290                 
291                 SNPRINTF(pbuff, size, ";%d", debug_code);
292                 size -= strlen(pbuff);
293                 pbuff += strlen(pbuff);
294                 pCode2str(pbuff, 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                 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                 SNPRINTF (pbuff, size, "; %s:%u(%s): ", __FILE__, __LINE__, __FUNCTION__);
1300                 size -= strlen(pbuff);
1301                 pbuff += strlen(pbuff);
1302                 pCode2str (pbuff, size, pc);
1303                 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1304         }
1305
1306         pc->destruct (pc);
1307         return result+1;
1308 }
1309
1310 /* ------------------------------------------------------------------
1311    Find and remove dead pCodes.
1312    ------------------------------------------------------------------ */
1313
1314 static int removeIfDeadPCI (pCode *pc)
1315 {
1316         pCode *pcnext = NULL;
1317         pCode *curr;
1318         unsigned int outCond;
1319         unsigned int result = 0;
1320         regs *dst;
1321         
1322         if (!pc) return 0;
1323         dst = NULL;
1324         
1325         /* skip non-PCIs */
1326         pcnext = findNextInstruction (pc->next);
1327         if (!isPCI(pc)) return 0;
1328
1329         switch (PCI(pc)->op)
1330         {
1331         case POC_ADDLW:
1332         case POC_ADDWF:
1333         case POC_ADDFW:
1334         case POC_ANDLW:
1335         case POC_ANDWF:
1336         case POC_ANDFW:
1337         case POC_BCF:
1338         case POC_BSF:
1339         //case POC_BTFSC:
1340         //case POC_BTFSS:
1341         //case POC_CALL:
1342         case POC_COMF:
1343         case POC_COMFW:
1344         case POC_CLRF:
1345         case POC_CLRW:
1346         //case POC_CLRWDT:
1347         case POC_DECF:
1348         case POC_DECFW:
1349         //case POC_DECFSZ:
1350         //case POC_DECFSZW:
1351         //case POC_GOTO:
1352         case POC_INCF:
1353         case POC_INCFW:
1354         //case POC_INCFSZ:
1355         //case POC_INCFSZW:
1356         case POC_IORLW:
1357         case POC_IORWF:
1358         case POC_IORFW:
1359         case POC_MOVF:
1360         case POC_MOVFW:
1361         case POC_MOVLW:
1362         case POC_MOVWF:
1363         case POC_NOP:
1364         //case POC_RETLW:
1365         //case POC_RETURN:
1366         //case POC_RETFIE:
1367         case POC_RLF:
1368         case POC_RLFW:
1369         case POC_RRF:
1370         case POC_RRFW:
1371         case POC_SUBLW:
1372         case POC_SUBWF:
1373         case POC_SUBFW:
1374         case POC_SWAPF:
1375         case POC_SWAPFW:
1376         //case POC_TRIS:
1377         case POC_XORLW:
1378         case POC_XORWF:
1379         case POC_XORFW:
1380         //case POC_BANKSEL:
1381         //case POC_PAGESEL:
1382                 break;
1383         
1384         default:
1385                 /* do not remove unknown PCIs */
1386                 return 0;
1387         } // switch
1388
1389         /* redundant checks---those instructions may never be removed */
1390         if (isPCI_BRANCH(pc)) return 0;
1391         if (isPCI_SKIP(pc)) return 0;
1392         
1393         outCond = PCI(pc)->outCond;
1394         curr = pcnext;
1395
1396         /* unknown operands assigned to, then ignore */
1397         if ((outCond & (PCC_REGISTER | PCC_C | PCC_Z | PCC_DC | PCC_W)) != outCond)
1398                 return 0;
1399         
1400         if (outCond & PCC_REGISTER)
1401         {
1402                 dst = getRegFromInstruction (pc);
1403                 if (!dst) return 0;
1404
1405                 /* special reg? */
1406                 if (!regIsLocal (dst)) return 0;
1407                 if (regIsSpecial (dst,0)) return 0;
1408         }
1409         
1410         //fprintf (stderr, "--> checking for liveness pc "); pc->print (stderr, pc);
1411         if (regIsDead (dst, outCond, pc))
1412         {
1413                 /* no result from pc has been used -- pc is `dead' */
1414                 //fprintf (stderr, "--> reg %s and cond %x assumed unused\n", dst ? dst->name : "<none>", outCond);
1415                 //fprintf (stderr, "--> removing dead pc "); pc->print (stderr, pc);
1416                 result = pCodeRemove (pc, "=DF= removed dead pCode");
1417         }
1418         
1419         return result;
1420 }
1421
1422 /* ------------------------------------------------------------------
1423    This routine is intended to safely replace one pCodeInstruction
1424    with a different pCodeInstruction.
1425    If desired, the replaced pCode will be left in (commented out) for
1426    debugging.
1427    Further, an optional comment can be inserted to indicate the
1428    reason for the possible removal of the pCode.
1429    ------------------------------------------------------------------ */
1430
1431 static void replace_PCI (pCodeInstruction *pc, pCodeInstruction *newpc, char *comment)
1432 {
1433   newpc->from =  pBranchAppend (newpc->from, pc->from);
1434   newpc->to = pBranchAppend (newpc->to, pc->to);
1435   newpc->label = pBranchAppend (newpc->label, pc->label);
1436   //newpc->pcflow = pc->pcflow; // updated in pCodeInsertAfter, ->pb is as well
1437   newpc->cline = pc->cline;
1438
1439   newpc->pc.seq = pc->pc.seq;
1440
1441   pCodeInsertAfter (&pc->pc, &newpc->pc);
1442
1443   /* FIXME: replacing pc will break the liverange maps (usedpCodes, ...) */
1444   pCodeRegMapLiveRanges( pc->pBlock ); /*FIXME:UNTESTED*/
1445   
1446   if (comment)
1447   {
1448     pCodeInsertAfter (&pc->pc, newpCodeCharP (comment));
1449   } // if
1450
1451   if (1)
1452   {
1453     /* replace pc with commented out version of itself */
1454     char buffer[1024], buffer2[1024];
1455     char *pbuff = &buffer[0];
1456     int size=1024;
1457     pCode2str (&buffer2[0],1024,&pc->pc);
1458     SNPRINTF (pbuff,size,"%s:%u(%s): removed pCode was %s\t", __FILE__, __LINE__, __FUNCTION__, &buffer2[0]);
1459     pCodeInsertAfter (&pc->pc, newpCodeCharP (&buffer[0]));
1460   } // if
1461
1462   pc->pc.destruct (&pc->pc);
1463 }
1464
1465 /* ------------------------------------------------------------------
1466    Find the first (unique) assignment to `reg' (prior to pc).
1467    ------------------------------------------------------------------ */
1468
1469 pCode *findAssignmentToReg (regs *reg, pCode *pc)
1470 {
1471         pCode *curr;
1472         
1473         assert (pc && isPCI(pc) && reg);
1474
1475         curr = findPrevInstruction (pc->prev);
1476         
1477         while (curr && PCI(curr)->pcflow == PCI(pc)->pcflow)
1478         {
1479                 if (PCI(curr)->outCond & PCC_REGISTER)
1480                 {
1481                         regs *op = getRegFromInstruction (curr);
1482                         if (op && (sameRegs(op,reg)))
1483                                 return curr;
1484                 } // if
1485                 curr = findPrevInstruction (curr->prev);
1486         } // while
1487         
1488         /* no assignment to reg found */
1489         return NULL;
1490 }
1491
1492 /* ------------------------------------------------------------------
1493    Find a register that holds the same value as `reg' (an alias).
1494    ------------------------------------------------------------------ */
1495
1496 regs *findRegisterAlias (regs *reg, pCode *pc)
1497 {
1498         pCode *curr;
1499
1500         if(!reg) return NULL;
1501
1502         if (regIsSpecial (reg, 0)) return NULL;
1503
1504         curr = findAssignmentToReg (reg, pc);
1505
1506         /* no assignment found --> no alias found */
1507         if (!curr) return NULL;
1508
1509         switch (PCI(curr)->op)
1510         {
1511         case POC_MOVWF:
1512                 /* find previous assignment to WREG */
1513                 while (curr && !(PCI(curr)->outCond & PCC_W))
1514                         curr = findPrevInstruction (curr->prev);
1515                 if (curr && PCI(curr)->op == POC_MOVFW)
1516                 {
1517                         regs *op = getRegFromInstruction (curr);
1518                         /* alias must not be changed since assignment... */
1519                         if (PCI(curr)->pcop)
1520                         {
1521                                 switch (PCI(curr)->pcop->type)
1522                                 {
1523                                 case PO_GPR_REGISTER:
1524                                 case PO_GPR_TEMP:
1525                                         /* these operands are ok */
1526                                         break;
1527                                 default:
1528                                         /* not a plain register operand */
1529                                         return NULL;
1530                                         break;
1531                                 }
1532                         }
1533                         if (!op || regIsSpecial (op, 0) || !regIsUnchangedSince (op, pc, curr)) return NULL;
1534                         //fprintf (stderr, "found register alias for %s: %s\n", reg->name, op && op->name ? op->name : "<no name>");
1535                         return op;
1536                 } else {
1537                         /* unknown source to WREG -- unknown register alias */
1538                         return NULL;
1539                 }
1540                 break;
1541         
1542         default:
1543                 /* unhandled instruction -- assume unknown source, no alias */
1544                 return NULL;
1545         }
1546
1547         /* no alias found */
1548         return NULL;
1549 }
1550
1551 /* ------------------------------------------------------------------
1552    Analyze a single pCodeInstruction's dataflow relations and replace
1553    it with a better variant if possible.
1554    ------------------------------------------------------------------ */
1555
1556 void analyzeAndReplacePCI (pCodeInstruction *pci)
1557 {
1558         regs *op_reg, *alias_reg;
1559         
1560         assert (pci);
1561
1562         if (!isPCI(pci)) return;
1563         
1564         switch (pci->op)
1565         {
1566         case POC_MOVFW:
1567         case POC_ADDFW:
1568         case POC_ANDFW:
1569         case POC_IORFW:
1570         case POC_XORFW:
1571                 /* try to find a different source register */
1572                 op_reg = getRegFromInstruction (&pci->pc);
1573                 if (pci->op == POC_MOVFW) /* touches Z */
1574                 {
1575                         pCode *assignment = findAssignmentToReg (op_reg, &pci->pc);
1576                         if (assignment && isPCI(assignment) && (PCI(assignment)->op == POC_CLRF))
1577                         {
1578                                 replace_PCI (pci, PCI(newpCode(POC_MOVLW, newpCodeOpLit(0))), "replaced with CLRF");
1579                                 return;
1580                         }                       
1581                 }
1582                 
1583                 alias_reg = findRegisterAlias (op_reg, &pci->pc);
1584                 if (alias_reg)
1585                 {
1586                         replace_PCI (pci, PCI(newpCode(pci->op, newpCodeOpRegFromStr (alias_reg->name))), "=DF= replaced with move from register alias");
1587                 }
1588                 break;
1589
1590         default:
1591                 /* do not optimize */
1592                 break;
1593         } // switch
1594 }
1595
1596 extern pFile *the_pFile;
1597
1598 /* ------------------------------------------------------------------
1599    Find and remove dead pCodes.
1600    ------------------------------------------------------------------ */
1601
1602 static int removeDeadPCIs (void)
1603 {
1604         pBlock *pb;
1605         unsigned int removed = 0;
1606         
1607         if (!the_pFile) return removed;
1608         
1609         do {
1610                 removed = 0;
1611                 
1612                 /* iterate over all pBlocks */
1613                 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1614                 {
1615                         pCode *pc, *pcnext = NULL;
1616                         
1617                         /* iterate over all pCodes */
1618                         for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1619                         {
1620                                 pcnext = findNextInstruction (pc->next);
1621                                 removed += removeIfDeadPCI (pc);
1622                         } // while
1623                 } // for pb
1624
1625                 fprintf (stderr, "[removed %u dead pCodes]\n", removed);
1626         } while (removed);
1627         
1628         return 0;
1629 }
1630
1631 /* ------------------------------------------------------------------
1632    This routine tries to optimize the dataflow by...
1633    (1) 
1634    
1635    This routine leaves in dead pCodes (assignments whose results are
1636    not used) -- these should be removed in a following sweep phase.
1637    ------------------------------------------------------------------ */
1638
1639 void optimizeDataflow (void)
1640 {
1641         pBlock *pb;
1642         
1643         if (!the_pFile) return;
1644
1645         //fprintf (stderr, "%s:%u(%s): Starting optimization...\n", __FILE__, __LINE__, __FUNCTION__);
1646         
1647         /* iterate over all pBlocks */
1648         for (pb = the_pFile->pbHead; pb; pb = pb->next)
1649         {
1650                 pCode *pc, *pcnext = NULL;
1651                 
1652                 /* iterate over all pCodes */
1653                 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1654                 {
1655                         pcnext = findNextInstruction (pc->next);
1656                         analyzeAndReplacePCI (PCI(pc));
1657                 } // while
1658         } // for pb
1659
1660         while (removeDeadPCIs ()) { /* remove dead codes in multiple passes */};
1661         df_removeStates ();
1662 }
1663
1664 #endif
1665
1666 /*-----------------------------------------------------------------*
1667 * void pCodeRegOptimeRegUsage(pBlock *pb) 
1668 *-----------------------------------------------------------------*/
1669 void pCodeRegOptimizeRegUsage(int level)
1670 {
1671         
1672         int passes;
1673         int saved = 0;
1674         int t = total_registers_saved;
1675
1676 #if 0
1677         /* This is currently broken (need rewrite to correctly
1678          * handle arbitrary pCodeOps instead of registers only). */
1679         if (!pic14_options.disable_df)
1680                 optimizeDataflow ();
1681 #endif
1682
1683         if(!register_optimization)
1684                 return;
1685 #define OPT_PASSES 4
1686         passes = OPT_PASSES;
1687         
1688         do {
1689                 saved = total_registers_saved;
1690                 
1691                 /* Identify registers used in one flow sequence */
1692                 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
1693                 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
1694                 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
1695                 
1696                 if(total_registers_saved != saved)
1697                         DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
1698                         (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
1699                 
1700                 passes--;
1701                 
1702         } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
1703         
1704         if(total_registers_saved == t) 
1705                 DFPRINTF((stderr, "No registers saved on this pass\n"));
1706
1707
1708         /*
1709                 fprintf(stderr,"dynamically allocated regs:\n");
1710                 dbg_regusage(dynAllocRegs);
1711                 fprintf(stderr,"stack regs:\n");
1712                 dbg_regusage(dynStackRegs);
1713                 fprintf(stderr,"direct regs:\n");
1714                 dbg_regusage(dynDirectRegs);
1715         */
1716 }
1717
1718
1719 /*-----------------------------------------------------------------*
1720 * void RegsUnMapLiveRanges(set *regset)
1721 *
1722 *-----------------------------------------------------------------*/
1723 void  RegsSetUnMapLiveRanges(set *regset)
1724 {
1725         regs *reg;
1726         
1727         while(regset) {
1728                 reg = regset->item;
1729                 regset = regset->next;
1730                 
1731                 
1732                 deleteSet(&reg->reglives.usedpCodes);
1733                 deleteSet(&reg->reglives.usedpFlows);
1734                 deleteSet(&reg->reglives.assignedpFlows);
1735                 
1736         }
1737         
1738 }
1739
1740 void  RegsUnMapLiveRanges(void)
1741 {
1742         
1743         RegsSetUnMapLiveRanges(dynAllocRegs);
1744         RegsSetUnMapLiveRanges(dynStackRegs);
1745         RegsSetUnMapLiveRanges(dynDirectRegs);
1746         RegsSetUnMapLiveRanges(dynProcessorRegs);
1747         RegsSetUnMapLiveRanges(dynDirectBitRegs);
1748         RegsSetUnMapLiveRanges(dynInternalRegs);
1749         
1750 }