* src/pic/pcoderegs.c (OptimizeRegUsage): do not optimize
[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                 /* Catch inconsistently set-up live ranges
736                  * (see tracker items #1469504 + #1474602)
737                  * FIXME: Actually we should rather fix the
738                  * computation of the liveranges instead...
739                  */
740                 if (!reg || !reg->reglives.usedpFlows
741                         || !reg->reglives.assignedpFlows)
742                 {
743                   //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
744                   continue;
745                 }
746
747                 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
748                         //fprintf(stderr,"skipping SFR: %s\n",reg->name);
749                         continue;
750                 }
751
752                 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
753                 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
754                 
755                 used = elementsInSet(reg->reglives.usedpCodes);
756                 if(used == 2) { 
757                         /*
758                         In this section, all registers that are used in only in two 
759                         instructions are examined. If possible, they're optimized out.
760                         */
761                         
762                         /*
763                         fprintf (stderr, "OptimizeRegUsage: %s  addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
764                         reg->name,
765                         reg->address,
766                         reg->rIdx, reg->type, used);
767                         */
768                         pc1 = setFirstItem(reg->reglives.usedpCodes);
769                         pc2 = setNextItem(reg->reglives.usedpCodes);
770                         
771                         if(pcfl_used && pcfl_assigned) {
772                                 /* 
773                                 expected case - the register has been assigned a value and is
774                                 subsequently used 
775                                 */
776                                 
777                                 //fprintf(stderr," used only twice\n");
778                                 if(pcfl_used->seq == pcfl_assigned->seq) {
779                                         
780                                         //fprintf(stderr, "  and used in same flow\n");
781                                         
782                                         pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
783                                         
784                                 } else {
785                                         // fprintf(stderr, "  and used in different flows\n");
786                                         
787                                 }
788                                 
789                         } else if(pcfl_used) {
790                                 
791                                 /* register has been used twice without ever being assigned */
792                                 fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
793                                 
794                         } else {
795                                 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
796                                 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
797                                 total_registers_saved++;  // debugging stats.
798                         }
799                 } else {
800                         
801                         /* register has been used either once, or more than twice */
802                         
803                         if(used && !pcfl_used && pcfl_assigned) {
804                                 pCode *pc;
805                                 
806                                 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
807                                 
808                                 pc = setFirstItem(reg->reglives.usedpCodes);
809                                 while(pc) {
810                                         
811                                         pcfl_assigned = PCODE(PCI(pc)->pcflow);
812                                         Remove1pcode(pc, reg,2);
813                                         
814                                         deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
815                                         /*
816                                         deleteSetItem (&(reg->reglives.usedpCodes),pc);
817                                         pc->destruct(pc);
818                                         */
819                                         pc = setNextItem(reg->reglives.usedpCodes);
820                                 }
821                                 
822                                 
823                                 reg->isFree = 1;
824                                 reg->wasUsed = 0;
825                                 
826                                 total_registers_saved++;  // debugging stats.
827                         } else if( (used > 2) && optimize_multi_uses) {
828                                 
829                                 set *rset1=NULL;
830                                 set *rset2=NULL;
831                                 int searching=1;
832                                 
833                                 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
834                                 
835                                 /* examine the number of times this register is used */
836                                 
837                                 
838                                 rset1 = reg->reglives.usedpCodes;
839                                 while(rset1 && searching) {
840                                         
841                                         pc1 = rset1->item;
842                                         rset2 = rset1->next;
843                                         
844                                         if(pc1 && isPCI(pc1) &&  ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
845                                                 
846                                                 //while(rset2 && searching) {
847                                                 if(rset2) {
848                                                         
849                                                         pc2 = rset2->item;
850                                                         if(pc2 && isPCI(pc2)  &&  ( (pcfl2 = PCI(pc2)->pcflow) != NULL) )  {
851                                                                 if(pcfl2 == pcfl1) {
852                                                                         
853                                                                         if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
854                                                                                 searching = 0;
855                                                                 }
856                                                         }
857                                                         
858                                                         //rset2 = rset2->next;
859                                                         
860                                                 }
861                                         }
862                                         rset1 = rset1->next;
863                                 }
864                         }
865                 }
866         }
867 }
868
869 #if 0
870
871 /* The following routines implement pCode optimizations based on
872  * dataflow analysis. The effects should be similar to those
873  * of pCodeOptime2pCodes() but more powerful.
874  *
875  * Unfortunately, the current approach (comparing operands by
876  * their associated registers) is seriously flawed:
877  * Some pCodeOps do not provide access to their repsective regs
878  * (PO_DIRs are created from arbitrary strings, immediates need
879  * to take offset and index into account, ...)
880  *
881  * This has to be rewritten based on pCodeOps instead of regs...
882  */
883
884 /* ------------------------------------------------------------------
885    Returns TRUE iff reg1 and reg2 are the same registers.
886    ------------------------------------------------------------------ */
887
888 static int sameRegs (const regs *reg1, const regs *reg2)
889 {
890         if (reg1 == reg2) return 1;
891         if (!reg1 || !reg2) return 0;
892         assert (reg1->name && reg2->name);
893
894         /* Compare names, as rIdx is not unique... */
895         if (!strcmp(reg1->name, reg2->name)) return 1;
896
897         /* Name mismatch -- not the same register. */
898         return 0;
899 }
900
901 /* ------------------------------------------------------------------
902    Returns 1 if the register is live at pc (read in this flow),
903    returns -1 if the register is NOT live at pc (assigned a new value
904    prior to readingi the old value in this flow) or
905    return 0 if the register is not mentioned.
906    ------------------------------------------------------------------ */
907
908 static int checkRegInFlow (regs **reg, int *cond, pCode *pc)
909 {
910         const int verbose = 0;
911         /* find next PCI at or after pc */
912         while (pc && isPCFL(pc)) pc = pc->next;
913
914         assert (reg && cond);
915
916         /* remove pseudo flags from cond */
917         *cond &= ~(PCC_REGISTER | PCC_EXAMINE_PCOP);
918
919         if (verbose && pc)
920         {
921                 fprintf (stderr, "Checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond); pc->print (stderr, pc);
922         }
923         
924         while (pc && !isPCFL(pc))
925         {
926                 if (verbose)
927                 {
928                         fprintf (stderr, "        now checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond);
929                         pc->print (stderr, pc);
930                 }
931                 if (isPCI(pc))
932                 {
933                         pCode *pcprev;
934                         regs *op = NULL;
935                         int prevIsSkip = 0;
936                         
937                         pcprev = findPrevInstruction (pc);
938                         if (pcprev && isPCI_SKIP(pcprev))
939                                 prevIsSkip = 1;
940
941                         if ((PCI(pc)->inCond | PCI(pc)->outCond) & PCC_REGISTER)
942                         {
943                                 op = getRegFromInstruction (pc);
944
945                                 /* pCodeOpRegBits do not provide register information... */
946                                 //if (!op) { __asm__("int3"); pc->print (stderr, pc); }
947                                 //assert (op);
948                                 if (!op) 
949                                 {
950                                         if (reg)
951                                                 return 1; /* assume `reg' is alive */
952                                 }
953
954                                 /* SPECIAL CASE: jump to unknown destination -- assume everything alive */
955                                 if (op->type == PO_PCL)
956                                 {
957                                         return 1;
958                                 }
959                         } // if
960
961                         if (PCI(pc)->inCond & PCC_REGISTER)
962                         {
963                                 /* `op' is live (possibly read) */
964                                 if (*reg && sameRegs (op, *reg))
965                                 {
966                                         if (verbose)
967                                         {
968                                                 fprintf (stderr, "reg is read in pc ");
969                                                 pc->print (stderr, pc);
970                                         }
971                                         return 1;
972                                 }
973                         }
974
975                         /* handle additional implicit operands */
976                         switch (PCI(pc)->op)
977                         {
978                         case POC_CALL: /* read arguments from WREG, clobbers WREG */
979                                 if (*cond & PCC_W)
980                                 {
981                                         if (verbose)
982                                         {
983                                                 fprintf (stderr, "conditions are read at pc ");
984                                                 pc->print (stderr, pc);
985                                         }
986                                         return 1;
987                                 }
988                                 *cond &= ~PCC_W;
989                                 break;
990                         case POC_RETURN: /* returns WREG to caller */
991                                 //fprintf (stderr, "reached RETURN, reg %s, cond %x\n", *reg ? (*reg)->name : "<none>", *cond);
992                                 if (*cond & PCC_W)
993                                 {
994                                         if (verbose)
995                                         {
996                                                 fprintf (stderr, "conditions are read at pc ");
997                                                 pc->print (stderr, pc);
998                                         }
999                                         return 1;
1000                                 }
1001                                 /* afterwards, no condition is alive */
1002                                 *cond = 0;
1003                                 /* afterwards, all local registers are dead */
1004                                 if (*reg && regIsLocal (*reg)) *reg = NULL;
1005                                 break;
1006                         case POC_RETLW:
1007                         case POC_RETFIE: /* this does not erturn WREG to the "caller", thus its rather a RETLW */
1008                                 /* this discards WREG */
1009                                 *cond &= ~PCC_W;
1010                                 /* afterwards, no condition is alive */
1011                                 *cond = 0;
1012                                 /* afterwards, all local registers are dead */
1013                                 if (*reg && regIsLocal (*reg)) *reg = NULL;
1014                                 break;
1015                         default:
1016                                 /* no implicit arguments */
1017                                 break;
1018                         }
1019
1020                         if (PCI(pc)->inCond & (*cond))
1021                         {
1022                                 /* a condition is read */
1023                                 if (verbose)
1024                                 {
1025                                         fprintf (stderr, "conditions are read at pc ");
1026                                         pc->print (stderr, pc);
1027                                 }
1028                                 return 1;
1029                         }
1030
1031                         /* remove outConds from `cond' */
1032                         (*cond) &= ~(PCI(pc)->outCond);
1033
1034                         if (PCI(pc)->outCond & PCC_REGISTER)
1035                         {
1036                                 /* `op' is (possibly) discarded */
1037                                 if (*reg && !prevIsSkip && sameRegs (op, *reg))
1038                                 {
1039                                         if (verbose)
1040                                         {
1041                                                 fprintf (stderr, "reg is assigned (cont'd) at pc ");
1042                                                 pc->print (stderr, pc);
1043                                         }
1044                                         *reg = NULL;
1045                                 }
1046                         }
1047
1048                         /* have all interesting conditions/registers been discarded? */
1049                         if (!(*reg) && !(*cond))
1050                         {
1051                                 if (verbose)
1052                                 {
1053                                         fprintf (stderr, "reg and conditions are discarded after ");
1054                                         pc->print (stderr, pc);
1055                                 }
1056                                 return -1;
1057                         }
1058                 } // if
1059
1060                 pc = pc->next;
1061         } // while
1062
1063         /* no use of (or only conditional writes to) `reg' found in flow */
1064         if (verbose)
1065         {
1066                 fprintf (stderr, "analysis inconclusive: reg %s, cond %x remains\n", *reg ? "remains" : "is void", *cond);
1067         }
1068         return 0;
1069 }
1070
1071 /* ------------------------------------------------------------------
1072    This will return 1 only if
1073    - reg is NULL or of type REG_TMP
1074    - reg is NULL or its value is discarded after pc
1075    - cond is 0 or all conditions are overwritten before being used
1076    ------------------------------------------------------------------ */
1077
1078 typedef struct {
1079   pCode *pc;
1080   regs *reg;
1081   int cond;
1082 } df_state_t;
1083
1084 df_state_t *df_free_states = NULL;
1085
1086 static df_state_t *
1087 df_newState (regs *reg, int cond, pCode *pc)
1088 {
1089         df_state_t *state;
1090
1091         if (df_free_states) {
1092           state = df_free_states;
1093           df_free_states = (df_state_t *)df_free_states->pc;
1094         } else {
1095           state = Safe_calloc(1, sizeof(df_state_t));
1096         }
1097         state->pc = pc;
1098         state->reg = reg;
1099         state->cond = cond;
1100         return state;
1101 }
1102
1103 static int
1104 df_containsState (set *set, df_state_t *state)
1105 {
1106         /* scan set for presence of `state' */
1107         df_state_t *curr;
1108         for (curr = setFirstItem (set); curr; curr = setNextItem (set))
1109         {
1110                 if ((curr->pc == state->pc)
1111                         && (curr->reg == state->reg)
1112                         && (curr->cond == state->cond))
1113                 {
1114                         /* `state' found */
1115                         return 1;
1116                 }
1117         }
1118         return 0;
1119 }
1120
1121 static void
1122 df_releaseState (df_state_t *state)
1123 {
1124         state->pc = (pCode *)df_free_states;
1125         df_free_states = (df_state_t *)state;
1126         state->reg = NULL;
1127         state->cond = 0;
1128 }
1129
1130 static void
1131 df_removeStates ()
1132 {
1133         df_state_t *next;
1134         while (df_free_states)
1135         {
1136                 next = (df_state_t *)df_free_states->pc;
1137                 Safe_free(df_free_states);
1138                 df_free_states = next;
1139         } // while
1140 }
1141
1142 int regIsDead (regs *reg, int cond, pCode *pc)
1143 {
1144         set *seenStates = NULL;
1145         set *todo = NULL;
1146         pCode *curr;
1147         df_state_t *state;
1148         int result = 1;
1149         
1150         /* sanity checks */
1151         if (reg && !regIsLocal (reg)) return 0;
1152
1153         pc = findNextInstruction (pc->next);
1154
1155         addSet (&todo, df_newState(reg, cond, pc));
1156
1157         while ((result == 1) && (state = getSet (&todo)))
1158         {
1159                 int res;
1160                 
1161                 if (df_containsState (seenStates, state)) continue;
1162                 addSet (&seenStates, state);
1163
1164                 curr = state->pc;
1165                 reg = state->reg;
1166                 cond = state->cond;
1167                 
1168                 //fprintf (stderr, "Checking for reg %s/cond %x at pc ", reg ? reg->name : "<none>", cond);
1169                 //curr->print (stderr, curr);
1170
1171                 res = checkRegInFlow (&reg, &cond, curr);
1172                 switch (res)
1173                 {
1174                 case 1: /* `reg' or `cond' is read---not dead */
1175                         result = 0;
1176                         break;
1177                 case -1: /* `reg' and `cond' are discarded in this flow---need to check other open flows */
1178                         break;
1179                 default: /* `reg' is not read and (possibly) not assigned---check successor flows */
1180                         if (curr)
1181                         {
1182                                 pCodeFlow *pcfl = PCI(curr)->pcflow;
1183                                 pCodeFlowLink *link;
1184                                 pCode *first;
1185                                 assert (pcfl);
1186
1187                                 for (link = setFirstItem(pcfl->to); link; link = setNextItem (pcfl->to))
1188                                 {
1189                                         /* add the first pCodeInstruction in the new flow to `todo' */
1190                                         first = findNextInstruction (&link->pcflow->pc);
1191                                         if (first) addSet (&todo, df_newState (reg, cond, first));
1192                                 } // for
1193                         }
1194                         break;
1195                 } // switch
1196         } // while
1197
1198         /* clean up */
1199         while (NULL != (state = getSet (&todo))) { df_releaseState (state); }
1200         while (NULL != (state = getSet (&seenStates))) { df_releaseState (state); }
1201
1202         /* if result remained 1, `reg' is not even possibly read and thus dead */
1203         return result;
1204 }
1205
1206
1207
1208 /* ------------------------------------------------------------------
1209    Safely remove a pCode.
1210    This needs to check that the previous instruction was no SKIP
1211    (otherwise the SKIP instruction would have to be removed as well,
1212    which may not be done for SFRs (side-effects on read possible)).
1213    ------------------------------------------------------------------ */
1214
1215 extern void unBuildFlow (pBlock *pb);
1216 extern void RegsUnMapLiveRanges ();
1217 extern void BuildFlow (pBlock *pb);
1218 extern void LinkFlow (pBlock *pb);
1219 extern void BuildFlowTree (pBlock *pb);
1220 extern void pCodeRegMapLiveRanges (pBlock *pb);
1221 extern pFile *the_pFile;
1222
1223 static int pCodeRemove (pCode *pc, const char *comment)
1224 {
1225         pCode *pcprev, *pcnext;
1226         unsigned int result = 0;
1227         
1228         /* Sanity checks. */
1229         if (!pc) return 0;
1230         if (!isPCI(pc)) return 0;
1231
1232         pcprev = findPrevInstruction (pc->prev);
1233         if (pcprev && isPCI_SKIP(pcprev))
1234         {
1235                 /* bail out until we know how to fix the Flow... */
1236                 //return 0;
1237
1238                 /* we also need to remove the preceeding SKIP instruction(s) */
1239                 result = pCodeRemove (pcprev, "=DF= removing preceeding SKIP as well");
1240                 if (!result)
1241                 {
1242                         /* previous instruction could not be removed -- this cannot be removed as well */
1243                         return result;
1244                 }
1245                 /* FIXME: We now have to update the flow! */
1246         } // if
1247
1248         /* do not remove pCodes with SFRs as operands (even reading them might cause side effects) */
1249         {
1250                 regs *reg;
1251                 reg = getRegFromInstruction (pc);
1252                 /* accesses to the STATUS register aer always safe, but others... */
1253                 if (reg && reg->type == REG_SFR && reg->pc_type != PO_STATUS) return result;
1254         }
1255
1256         /* MUST SUCEED FROM NOW ON (or revert the changes done since NOW ;-)) */
1257         
1258         /* fix flow */
1259         if (PCI(pc)->pcflow && PCI(pc)->pcflow->end == pc)
1260         {
1261                 pCode *pcprev;
1262                 pcprev = findPrevInstruction (pc->prev);
1263                 if (PCI(pcprev)->pcflow == PCI(pc)->pcflow)
1264                 {
1265                         PCI(pc)->pcflow->end = pcprev;
1266                 } else {
1267                         pBlock *pb = pc->pb;
1268                         RegsUnMapLiveRanges();
1269                         unBuildFlow(pb);
1270                         BuildFlow(pb);
1271                         LinkFlow(pb);
1272                         BuildFlowTree(pb);
1273                         for (pb = the_pFile->pbHead; pb; pb = pb->next)
1274                         {
1275                                 pCodeRegMapLiveRanges(pb);
1276                         }
1277                 }
1278         }
1279         
1280         /* attach labels to next instruction */
1281         pcnext = findNextInstruction (pc->next);
1282         if (pcnext)
1283         {
1284                 PCI(pcnext)->label = pBranchAppend (PCI(pcnext)->label, PCI(pc)->label);
1285                 if (!PCI(pcnext)->cline) PCI(pcnext)->cline = PCI(pc)->cline;
1286         }
1287         else
1288         {
1289                 fprintf (stderr, "Cannot move a label...\n");
1290                 exit(-1);
1291         }
1292         
1293         if (comment)
1294         {
1295                 char buffer[512];
1296                 int size = 512;
1297                 char *pbuff = &buffer[0];
1298                 
1299                 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): %s", __FILE__, __LINE__, __FUNCTION__, comment);
1300                 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1301         } // if
1302
1303         if (1)
1304         {
1305                 /* replace removed pCode with out-commented version of itself */
1306                 char buffer[512];
1307                 int size = 512;
1308                 char *pbuff = &buffer[0];
1309                 
1310                 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): ", __FILE__, __LINE__, __FUNCTION__);
1311                 pCode2str (pbuff, size, pc);
1312                 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1313         }
1314
1315         pc->destruct (pc);
1316         return result+1;
1317 }
1318
1319 /* ------------------------------------------------------------------
1320    Find and remove dead pCodes.
1321    ------------------------------------------------------------------ */
1322
1323 static int removeIfDeadPCI (pCode *pc)
1324 {
1325         pCode *pcnext = NULL;
1326         pCode *curr;
1327         unsigned int outCond;
1328         unsigned int result = 0;
1329         regs *dst;
1330         
1331         if (!pc) return 0;
1332         dst = NULL;
1333         
1334         /* skip non-PCIs */
1335         pcnext = findNextInstruction (pc->next);
1336         if (!isPCI(pc)) return 0;
1337
1338         switch (PCI(pc)->op)
1339         {
1340         case POC_ADDLW:
1341         case POC_ADDWF:
1342         case POC_ADDFW:
1343         case POC_ANDLW:
1344         case POC_ANDWF:
1345         case POC_ANDFW:
1346         case POC_BCF:
1347         case POC_BSF:
1348         //case POC_BTFSC:
1349         //case POC_BTFSS:
1350         //case POC_CALL:
1351         case POC_COMF:
1352         case POC_COMFW:
1353         case POC_CLRF:
1354         case POC_CLRW:
1355         //case POC_CLRWDT:
1356         case POC_DECF:
1357         case POC_DECFW:
1358         //case POC_DECFSZ:
1359         //case POC_DECFSZW:
1360         //case POC_GOTO:
1361         case POC_INCF:
1362         case POC_INCFW:
1363         //case POC_INCFSZ:
1364         //case POC_INCFSZW:
1365         case POC_IORLW:
1366         case POC_IORWF:
1367         case POC_IORFW:
1368         case POC_MOVF:
1369         case POC_MOVFW:
1370         case POC_MOVLW:
1371         case POC_MOVWF:
1372         case POC_NOP:
1373         //case POC_RETLW:
1374         //case POC_RETURN:
1375         //case POC_RETFIE:
1376         case POC_RLF:
1377         case POC_RLFW:
1378         case POC_RRF:
1379         case POC_RRFW:
1380         case POC_SUBLW:
1381         case POC_SUBWF:
1382         case POC_SUBFW:
1383         case POC_SWAPF:
1384         case POC_SWAPFW:
1385         //case POC_TRIS:
1386         case POC_XORLW:
1387         case POC_XORWF:
1388         case POC_XORFW:
1389         //case POC_BANKSEL:
1390         //case POC_PAGESEL:
1391                 break;
1392         
1393         default:
1394                 /* do not remove unknown PCIs */
1395                 return 0;
1396         } // switch
1397
1398         /* redundant checks---those instructions may never be removed */
1399         if (isPCI_BRANCH(pc)) return 0;
1400         if (isPCI_SKIP(pc)) return 0;
1401         
1402         outCond = PCI(pc)->outCond;
1403         curr = pcnext;
1404
1405         /* unknown operands assigned to, then ignore */
1406         if ((outCond & (PCC_REGISTER | PCC_C | PCC_Z | PCC_DC | PCC_W)) != outCond)
1407                 return 0;
1408         
1409         if (outCond & PCC_REGISTER)
1410         {
1411                 dst = getRegFromInstruction (pc);
1412                 if (!dst) return 0;
1413
1414                 /* special reg? */
1415                 if (!regIsLocal (dst)) return 0;
1416                 if (regIsSpecial (dst,0)) return 0;
1417         }
1418         
1419         //fprintf (stderr, "--> checking for liveness pc "); pc->print (stderr, pc);
1420         if (regIsDead (dst, outCond, pc))
1421         {
1422                 /* no result from pc has been used -- pc is `dead' */
1423                 //fprintf (stderr, "--> reg %s and cond %x assumed unused\n", dst ? dst->name : "<none>", outCond);
1424                 //fprintf (stderr, "--> removing dead pc "); pc->print (stderr, pc);
1425                 result = pCodeRemove (pc, "=DF= removed dead pCode");
1426         }
1427         
1428         return result;
1429 }
1430
1431 /* ------------------------------------------------------------------
1432    This routine is intended to safely replace one pCodeInstruction
1433    with a different pCodeInstruction.
1434    If desired, the replaced pCode will be left in (commented out) for
1435    debugging.
1436    Further, an optional comment can be inserted to indicate the
1437    reason for the possible removal of the pCode.
1438    ------------------------------------------------------------------ */
1439
1440 static void replace_PCI (pCodeInstruction *pc, pCodeInstruction *newpc, char *comment)
1441 {
1442   newpc->from =  pBranchAppend (newpc->from, pc->from);
1443   newpc->to = pBranchAppend (newpc->to, pc->to);
1444   newpc->label = pBranchAppend (newpc->label, pc->label);
1445   //newpc->pcflow = pc->pcflow; // updated in pCodeInsertAfter, ->pb is as well
1446   newpc->cline = pc->cline;
1447
1448   newpc->pc.seq = pc->pc.seq;
1449
1450   pCodeInsertAfter (&pc->pc, &newpc->pc);
1451
1452   /* FIXME: replacing pc will break the liverange maps (usedpCodes, ...) */
1453   pCodeRegMapLiveRanges( pc->pBlock ); /*FIXME:UNTESTED*/
1454   
1455   if (comment)
1456   {
1457     pCodeInsertAfter (&pc->pc, newpCodeCharP (comment));
1458   } // if
1459
1460   if (1)
1461   {
1462     /* replace pc with commented out version of itself */
1463     char buffer[1024], buffer2[1024];
1464     char *pbuff = &buffer[0];
1465     int size=1024;
1466     pCode2str (&buffer2[0],1024,&pc->pc);
1467     SAFE_snprintf (&pbuff,&size,"%s:%u(%s): removed pCode was %s\t", __FILE__, __LINE__, __FUNCTION__, &buffer2[0]);
1468     pCodeInsertAfter (&pc->pc, newpCodeCharP (&buffer[0]));
1469   } // if
1470
1471   pc->pc.destruct (&pc->pc);
1472 }
1473
1474 /* ------------------------------------------------------------------
1475    Find the first (unique) assignment to `reg' (prior to pc).
1476    ------------------------------------------------------------------ */
1477
1478 pCode *findAssignmentToReg (regs *reg, pCode *pc)
1479 {
1480         pCode *curr;
1481         
1482         assert (pc && isPCI(pc) && reg);
1483
1484         curr = findPrevInstruction (pc->prev);
1485         
1486         while (curr && PCI(curr)->pcflow == PCI(pc)->pcflow)
1487         {
1488                 if (PCI(curr)->outCond & PCC_REGISTER)
1489                 {
1490                         regs *op = getRegFromInstruction (curr);
1491                         if (op && (sameRegs(op,reg)))
1492                                 return curr;
1493                 } // if
1494                 curr = findPrevInstruction (curr->prev);
1495         } // while
1496         
1497         /* no assignment to reg found */
1498         return NULL;
1499 }
1500
1501 /* ------------------------------------------------------------------
1502    Find a register that holds the same value as `reg' (an alias).
1503    ------------------------------------------------------------------ */
1504
1505 regs *findRegisterAlias (regs *reg, pCode *pc)
1506 {
1507         pCode *curr;
1508
1509         if(!reg) return NULL;
1510
1511         if (regIsSpecial (reg, 0)) return NULL;
1512
1513         curr = findAssignmentToReg (reg, pc);
1514
1515         /* no assignment found --> no alias found */
1516         if (!curr) return NULL;
1517
1518         switch (PCI(curr)->op)
1519         {
1520         case POC_MOVWF:
1521                 /* find previous assignment to WREG */
1522                 while (curr && !(PCI(curr)->outCond & PCC_W))
1523                         curr = findPrevInstruction (curr->prev);
1524                 if (curr && PCI(curr)->op == POC_MOVFW)
1525                 {
1526                         regs *op = getRegFromInstruction (curr);
1527                         /* alias must not be changed since assignment... */
1528                         if (PCI(curr)->pcop)
1529                         {
1530                                 switch (PCI(curr)->pcop->type)
1531                                 {
1532                                 case PO_GPR_REGISTER:
1533                                 case PO_GPR_TEMP:
1534                                         /* these operands are ok */
1535                                         break;
1536                                 default:
1537                                         /* not a plain register operand */
1538                                         return NULL;
1539                                         break;
1540                                 }
1541                         }
1542                         if (!op || regIsSpecial (op, 0) || !regIsUnchangedSince (op, pc, curr)) return NULL;
1543                         //fprintf (stderr, "found register alias for %s: %s\n", reg->name, op && op->name ? op->name : "<no name>");
1544                         return op;
1545                 } else {
1546                         /* unknown source to WREG -- unknown register alias */
1547                         return NULL;
1548                 }
1549                 break;
1550         
1551         default:
1552                 /* unhandled instruction -- assume unknown source, no alias */
1553                 return NULL;
1554         }
1555
1556         /* no alias found */
1557         return NULL;
1558 }
1559
1560 /* ------------------------------------------------------------------
1561    Analyze a single pCodeInstruction's dataflow relations and replace
1562    it with a better variant if possible.
1563    ------------------------------------------------------------------ */
1564
1565 void analyzeAndReplacePCI (pCodeInstruction *pci)
1566 {
1567         regs *op_reg, *alias_reg;
1568         
1569         assert (pci);
1570
1571         if (!isPCI(pci)) return;
1572         
1573         switch (pci->op)
1574         {
1575         case POC_MOVFW:
1576         case POC_ADDFW:
1577         case POC_ANDFW:
1578         case POC_IORFW:
1579         case POC_XORFW:
1580                 /* try to find a different source register */
1581                 op_reg = getRegFromInstruction (&pci->pc);
1582                 if (pci->op == POC_MOVFW) /* touches Z */
1583                 {
1584                         pCode *assignment = findAssignmentToReg (op_reg, &pci->pc);
1585                         if (assignment && isPCI(assignment) && (PCI(assignment)->op == POC_CLRF))
1586                         {
1587                                 replace_PCI (pci, PCI(newpCode(POC_MOVLW, newpCodeOpLit(0))), "replaced with CLRF");
1588                                 return;
1589                         }                       
1590                 }
1591                 
1592                 alias_reg = findRegisterAlias (op_reg, &pci->pc);
1593                 if (alias_reg)
1594                 {
1595                         replace_PCI (pci, PCI(newpCode(pci->op, newpCodeOpRegFromStr (alias_reg->name))), "=DF= replaced with move from register alias");
1596                 }
1597                 break;
1598
1599         default:
1600                 /* do not optimize */
1601                 break;
1602         } // switch
1603 }
1604
1605 extern pFile *the_pFile;
1606
1607 /* ------------------------------------------------------------------
1608    Find and remove dead pCodes.
1609    ------------------------------------------------------------------ */
1610
1611 static int removeDeadPCIs (void)
1612 {
1613         pBlock *pb;
1614         unsigned int removed = 0;
1615         
1616         if (!the_pFile) return removed;
1617         
1618         do {
1619                 removed = 0;
1620                 
1621                 /* iterate over all pBlocks */
1622                 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1623                 {
1624                         pCode *pc, *pcnext = NULL;
1625                         
1626                         /* iterate over all pCodes */
1627                         for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1628                         {
1629                                 pcnext = findNextInstruction (pc->next);
1630                                 removed += removeIfDeadPCI (pc);
1631                         } // while
1632                 } // for pb
1633
1634                 fprintf (stderr, "[removed %u dead pCodes]\n", removed);
1635         } while (removed);
1636         
1637         return 0;
1638 }
1639
1640 /* ------------------------------------------------------------------
1641    This routine tries to optimize the dataflow by...
1642    (1) 
1643    
1644    This routine leaves in dead pCodes (assignments whose results are
1645    not used) -- these should be removed in a following sweep phase.
1646    ------------------------------------------------------------------ */
1647
1648 void optimizeDataflow (void)
1649 {
1650         pBlock *pb;
1651         
1652         if (!the_pFile) return;
1653
1654         //fprintf (stderr, "%s:%u(%s): Starting optimization...\n", __FILE__, __LINE__, __FUNCTION__);
1655         
1656         /* iterate over all pBlocks */
1657         for (pb = the_pFile->pbHead; pb; pb = pb->next)
1658         {
1659                 pCode *pc, *pcnext = NULL;
1660                 
1661                 /* iterate over all pCodes */
1662                 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1663                 {
1664                         pcnext = findNextInstruction (pc->next);
1665                         analyzeAndReplacePCI (PCI(pc));
1666                 } // while
1667         } // for pb
1668
1669         while (removeDeadPCIs ()) { /* remove dead codes in multiple passes */};
1670         df_removeStates ();
1671 }
1672
1673 #endif
1674
1675 /*-----------------------------------------------------------------*
1676 * void pCodeRegOptimeRegUsage(pBlock *pb) 
1677 *-----------------------------------------------------------------*/
1678 void pCodeRegOptimizeRegUsage(int level)
1679 {
1680         
1681         int passes;
1682         int saved = 0;
1683         int t = total_registers_saved;
1684
1685 #if 0
1686         /* This is currently broken (need rewrite to correctly
1687          * handle arbitrary pCodeOps instead of registers only). */
1688         if (!pic14_options.disable_df)
1689                 optimizeDataflow ();
1690 #endif
1691
1692         if(!register_optimization)
1693                 return;
1694 #define OPT_PASSES 4
1695         passes = OPT_PASSES;
1696         
1697         do {
1698                 saved = total_registers_saved;
1699                 
1700                 /* Identify registers used in one flow sequence */
1701                 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
1702                 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
1703                 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
1704                 
1705                 if(total_registers_saved != saved)
1706                         DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n", 
1707                         (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
1708                 
1709                 passes--;
1710                 
1711         } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
1712         
1713         if(total_registers_saved == t) 
1714                 DFPRINTF((stderr, "No registers saved on this pass\n"));
1715
1716
1717         /*
1718                 fprintf(stderr,"dynamically allocated regs:\n");
1719                 dbg_regusage(dynAllocRegs);
1720                 fprintf(stderr,"stack regs:\n");
1721                 dbg_regusage(dynStackRegs);
1722                 fprintf(stderr,"direct regs:\n");
1723                 dbg_regusage(dynDirectRegs);
1724         */
1725 }
1726
1727
1728 /*-----------------------------------------------------------------*
1729 * void RegsUnMapLiveRanges(set *regset)
1730 *
1731 *-----------------------------------------------------------------*/
1732 void  RegsSetUnMapLiveRanges(set *regset)
1733 {
1734         regs *reg;
1735         
1736         while(regset) {
1737                 reg = regset->item;
1738                 regset = regset->next;
1739                 
1740                 
1741                 deleteSet(&reg->reglives.usedpCodes);
1742                 deleteSet(&reg->reglives.usedpFlows);
1743                 deleteSet(&reg->reglives.assignedpFlows);
1744                 
1745         }
1746         
1747 }
1748
1749 void  RegsUnMapLiveRanges(void)
1750 {
1751         
1752         RegsSetUnMapLiveRanges(dynAllocRegs);
1753         RegsSetUnMapLiveRanges(dynStackRegs);
1754         RegsSetUnMapLiveRanges(dynDirectRegs);
1755         RegsSetUnMapLiveRanges(dynProcessorRegs);
1756         RegsSetUnMapLiveRanges(dynDirectBitRegs);
1757         RegsSetUnMapLiveRanges(dynInternalRegs);
1758         
1759 }