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