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