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