1 /*-------------------------------------------------------------------------
3 pcoderegs.c - post code generation register optimizations
5 Written By - Scott Dattalo scott@dattalo.com
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
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.
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.
21 -------------------------------------------------------------------------*/
26 The purpose of the code in this file is to optimize the register usage.
31 #include "common.h" // Include everything in the SDCC src directory
36 #include "pcoderegs.h"
37 #include "pcodeflow.h"
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);
49 int total_registers_saved=0;
50 int register_optimization=1;
52 /*-----------------------------------------------------------------*
53 * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
54 *-----------------------------------------------------------------*/
56 void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
59 if(!reg || ! pcfl || !isPCFL(pcflow))
63 pcfl->registers = newSet();
69 /*-----------------------------------------------------------------*
71 *-----------------------------------------------------------------*/
72 void dbg_regusage(set *fregs)
79 for (reg = setFirstItem(fregs) ; reg ;
80 reg = setNextItem(fregs)) {
82 if(elementsInSet(reg->reglives.usedpCodes)) {
84 fprintf (stderr, "%s addr=0x%03x rIdx=0x%03x",
89 pcfl = setFirstItem(reg->reglives.usedpFlows);
91 fprintf(stderr, "\n used in seq");
94 fprintf(stderr," 0x%03x",pcfl->seq);
95 pcfl = setNextItem(reg->reglives.usedpFlows);
98 pcfl = setFirstItem(reg->reglives.assignedpFlows);
100 fprintf(stderr, "\n assigned in seq");
103 fprintf(stderr," 0x%03x",pcfl->seq);
104 pcfl = setNextItem(reg->reglives.assignedpFlows);
107 pc = setFirstItem(reg->reglives.usedpCodes);
109 fprintf(stderr, "\n used in instructions ");
112 pcfl = PCODE(PCI(pc)->pcflow);
114 fprintf(stderr," 0x%03x:",pcfl->seq);
115 fprintf(stderr,"0x%03x",pc->seq);
117 pc = setNextItem(reg->reglives.usedpCodes);
120 fprintf(stderr, "\n");
125 /*-----------------------------------------------------------------*
127 *-----------------------------------------------------------------*/
128 void dbg_dumpregusage(void)
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);
148 /*-----------------------------------------------------------------*
149 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
150 *-----------------------------------------------------------------*/
151 void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
162 pc = findNextInstruction(pcfl->pc.next);
164 while(isPCinFlow(pc,PCODE(pcfl))) {
167 reg = getRegFromInstruction(pc);
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);
176 addSetIfnotP(& (PCFL(pcfl)->registers), reg);
178 if(PCC_REGISTER & PCI(pc)->inCond)
179 addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
181 if(PCC_REGISTER & PCI(pc)->outCond)
182 addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
184 addSetIfnotP(& (reg->reglives.usedpCodes), pc);
188 pc = findNextInstruction(pc->next);
194 /*-----------------------------------------------------------------*
195 * void pCodeRegMapLiveRanges(pBlock *pb)
196 *-----------------------------------------------------------------*/
197 void pCodeRegMapLiveRanges(pBlock *pb)
201 for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
203 pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
205 if(!isPCFL(pcflow)) {
206 fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
209 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
213 for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
215 pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
217 regs *r = setFirstItem(PCFL(pcflow)->registers);
218 fprintf(stderr,"flow seq %d\n", pcflow->seq);
221 fprintf(stderr, " %s\n",r->name);
222 r = setNextItem(PCFL(pcflow)->registers);
229 // dbg_dumpregusage();
234 /*-----------------------------------------------------------------*
236 *-----------------------------------------------------------------*/
237 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
245 deleteSetItem (&(reg->reglives.usedpCodes),pc);
248 pcn = findNextInstruction(pc->next);
251 PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
256 pcn = findNextInstruction(pc->next);
259 if(PCI(pcn)->cline) {
260 //fprintf(stderr, "source line has been optimized completely out\n");
261 //pc->print(stderr,pc);
263 PCI(pcn)->cline = PCI(pc)->cline;
271 Debug stuff. Comment out the instruction we're about to delete.
277 char *pbuff,**ppbuff;
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);
291 /*-----------------------------------------------------------------*
292 * void RemoveRegsFromSet(set *regset)
294 *-----------------------------------------------------------------*/
295 void RemoveRegsFromSet(set *regset)
302 regset = regset->next;
304 used = elementsInSet(reg->reglives.usedpCodes);
308 //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
310 //fprintf(stderr," getting rid of reg %s\n",reg->name);
317 pc = setFirstItem(reg->reglives.usedpCodes);
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);
327 pCode *pcn = findNextInstruction(pc->next);
329 if(pcn && PCI(pcn)->label) {
330 //fprintf(stderr,"can't delete instruction with label...\n");
331 //pc->print(stderr,pc);
334 /* Move the label to the next instruction */
336 PCI(pcn)->label = PCI(pc)->label;
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);
346 //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
347 Remove1pcode(pc, reg, 1);
350 deleteSetItem (&(reg->reglives.usedpCodes),pc);
354 total_registers_saved++; // debugging stats.
361 /*-----------------------------------------------------------------*
362 * void RemoveUnusedRegisters(void)
364 *-----------------------------------------------------------------*/
365 void RemoveUnusedRegisters(void)
367 /* First, get rid of registers that are used only one time */
369 //RemoveRegsFromSet(dynInternalRegs);
370 RemoveRegsFromSet(dynAllocRegs);
371 RemoveRegsFromSet(dynStackRegs);
373 don't do DirectRegs yet - there's a problem with arrays
374 RemoveRegsFromSet(dynDirectRegs);
376 RemoveRegsFromSet(dynDirectBitRegs);
378 if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
382 /*-----------------------------------------------------------------*
384 *-----------------------------------------------------------------*/
385 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free)
387 static int debug_code=99;
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);
396 //fprintf(stderr,"%s\n",__FUNCTION__);
398 Remove1pcode(pc1, reg, debug_code++);
401 Remove1pcode(pc2, reg, debug_code++);
402 deleteSetItem (&(PCFL(pcflow)->registers), reg);
411 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
414 /*-----------------------------------------------------------------*
416 *-----------------------------------------------------------------*/
417 int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
423 testreg = getRegFromInstruction(pc1);
424 if(testreg && (testreg->rIdx == reg->rIdx)) {
428 fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
432 pc1 = findNextInstruction(pc1->next);
434 } while (pc1 && (pc1 != pc2)) ;
439 int regIsSpecial (regs *reg, int mayBeGlobal)
443 if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
449 static int regIsLocal (regs *reg)
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))
457 //fprintf (stderr, "reg %s is not marked REG_TMP...\n", reg->name);
465 /*-----------------------------------------------------------------*
466 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2)
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.)
475 *-----------------------------------------------------------------*/
476 int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
481 int t = total_registers_saved;
483 if (!isPCI(pc1) || !isPCI(pc2)) return 0;
484 if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
486 if(pc2->seq < pc1->seq) {
492 /* disable this optimization for now -- it's buggy */
493 if(pic14_options.disable_df) return 0;
495 //fprintf(stderr,"pCodeOptime2pCodes\n");
496 //pc1->print(stderr,pc1);
497 //pc2->print(stderr,pc2);
499 if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
509 can be replaced with (only if following instructions are not going to use W and reg is not used again later)
514 DFPRINTF((stderr, " optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
515 pct2 = findNextInstruction(pc2->next);
517 if(pct2 && PCI(pct2)->op == POC_MOVWF) {
518 wSaved = wUsed = 1; /* Maybe able to replace with clrf pc2->next->reg. */
520 wUsed = pCodeSearchCondition(pct2,PCC_W,1) != -1;
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. */
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);
533 newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
536 pCodeInsertAfter(pc2, newpc);
537 PCI(newpc)->pcflow = PCFL(pcfl_used);
538 newpc->seq = pc2->seq;
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.
544 } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
545 DFPRINTF((stderr, " optimising CLRF/IORFW\n"));
547 pct2 = findNextInstruction(pc2->next);
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);
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.
560 } else if(PCI(pc1)->op == POC_MOVWF) {
561 // Optimising MOVWF reg ...
563 pct2 = findNextInstruction(pc2->next);
565 if(PCI(pc2)->op == POC_MOVFW) {
566 // Optimising MOVWF reg ... MOVF reg,W
568 if(PCI(pct2)->op == POC_MOVWF) {
577 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
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;
594 pCodeInsertBefore(pc1,pct2);
595 if(regUsedinRange(pct2,0,reg))
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);
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);
603 total_registers_saved++; // debugging stats.
610 pct1 = findPrevInstruction(pc1->prev);
611 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
613 if ( (PCI(pct1)->op == POC_MOVFW) &&
614 (PCI(pc2)->op == POC_MOVFW)) {
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"));
634 Or, if we're not deleting the register then the "To" is:
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;
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);
650 /* If we're not freeing the register then that means (probably)
651 * the register is needed somewhere else.*/
653 pCodeInsertAfter(pct2, pc1);
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);
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.
668 return (total_registers_saved != t);
671 /*-----------------------------------------------------------------*
672 * void pCodeRegOptimeRegUsage(pBlock *pb)
673 *-----------------------------------------------------------------*/
674 void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
678 pCode *pc1=NULL, *pc2=NULL;
682 pCode *pcfl_used, *pcfl_assigned;
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 */
692 if (strcmp(reg->name,"_SubState")==0)
693 fprintf(stderr,"Reg: %s\n",reg->name);
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);
701 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
702 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
704 used = elementsInSet(reg->reglives.usedpCodes);
707 In this section, all registers that are used in only in two
708 instructions are examined. If possible, they're optimized out.
712 fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
715 reg->rIdx, reg->type, used);
717 pc1 = setFirstItem(reg->reglives.usedpCodes);
718 pc2 = setNextItem(reg->reglives.usedpCodes);
720 if(pcfl_used && pcfl_assigned) {
722 expected case - the register has been assigned a value and is
726 //fprintf(stderr," used only twice\n");
727 if(pcfl_used->seq == pcfl_assigned->seq) {
729 //fprintf(stderr, " and used in same flow\n");
731 pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
734 // fprintf(stderr, " and used in different flows\n");
738 } else if(pcfl_used) {
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);
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.
750 /* register has been used either once, or more than twice */
752 if(used && !pcfl_used && pcfl_assigned) {
755 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
757 pc = setFirstItem(reg->reglives.usedpCodes);
760 pcfl_assigned = PCODE(PCI(pc)->pcflow);
761 Remove1pcode(pc, reg,2);
763 deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
765 deleteSetItem (&(reg->reglives.usedpCodes),pc);
768 pc = setNextItem(reg->reglives.usedpCodes);
775 total_registers_saved++; // debugging stats.
776 } else if( (used > 2) && optimize_multi_uses) {
782 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
784 /* examine the number of times this register is used */
787 rset1 = reg->reglives.usedpCodes;
788 while(rset1 && searching) {
793 if(pc1 && isPCI(pc1) && ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
795 //while(rset2 && searching) {
799 if(pc2 && isPCI(pc2) && ( (pcfl2 = PCI(pc2)->pcflow) != NULL) ) {
802 if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
807 //rset2 = rset2->next;
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.
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, ...)
830 * This has to be rewritten based on pCodeOps instead of regs...
833 /* ------------------------------------------------------------------
834 Returns TRUE iff reg1 and reg2 are the same registers.
835 ------------------------------------------------------------------ */
837 static int sameRegs (const regs *reg1, const regs *reg2)
839 if (reg1 == reg2) return 1;
840 if (!reg1 || !reg2) return 0;
841 assert (reg1->name && reg2->name);
843 /* Compare names, as rIdx is not unique... */
844 if (!strcmp(reg1->name, reg2->name)) return 1;
846 /* Name mismatch -- not the same register. */
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 ------------------------------------------------------------------ */
857 static int checkRegInFlow (regs **reg, int *cond, pCode *pc)
859 const int verbose = 0;
860 /* find next PCI at or after pc */
861 while (pc && isPCFL(pc)) pc = pc->next;
863 assert (reg && cond);
865 /* remove pseudo flags from cond */
866 *cond &= ~(PCC_REGISTER | PCC_EXAMINE_PCOP);
870 fprintf (stderr, "Checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond); pc->print (stderr, pc);
873 while (pc && !isPCFL(pc))
877 fprintf (stderr, " now checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond);
878 pc->print (stderr, pc);
886 pcprev = findPrevInstruction (pc);
887 if (pcprev && isPCI_SKIP(pcprev))
890 if ((PCI(pc)->inCond | PCI(pc)->outCond) & PCC_REGISTER)
892 op = getRegFromInstruction (pc);
894 /* pCodeOpRegBits do not provide register information... */
895 //if (!op) { __asm__("int3"); pc->print (stderr, pc); }
900 return 1; /* assume `reg' is alive */
903 /* SPECIAL CASE: jump to unknown destination -- assume everything alive */
904 if (op->type == PO_PCL)
910 if (PCI(pc)->inCond & PCC_REGISTER)
912 /* `op' is live (possibly read) */
913 if (*reg && sameRegs (op, *reg))
917 fprintf (stderr, "reg is read in pc ");
918 pc->print (stderr, pc);
924 /* handle additional implicit operands */
927 case POC_CALL: /* read arguments from WREG, clobbers WREG */
932 fprintf (stderr, "conditions are read at pc ");
933 pc->print (stderr, pc);
939 case POC_RETURN: /* returns WREG to caller */
940 //fprintf (stderr, "reached RETURN, reg %s, cond %x\n", *reg ? (*reg)->name : "<none>", *cond);
945 fprintf (stderr, "conditions are read at pc ");
946 pc->print (stderr, pc);
950 /* afterwards, no condition is alive */
952 /* afterwards, all local registers are dead */
953 if (*reg && regIsLocal (*reg)) *reg = NULL;
956 case POC_RETFIE: /* this does not erturn WREG to the "caller", thus its rather a RETLW */
957 /* this discards WREG */
959 /* afterwards, no condition is alive */
961 /* afterwards, all local registers are dead */
962 if (*reg && regIsLocal (*reg)) *reg = NULL;
965 /* no implicit arguments */
969 if (PCI(pc)->inCond & (*cond))
971 /* a condition is read */
974 fprintf (stderr, "conditions are read at pc ");
975 pc->print (stderr, pc);
980 /* remove outConds from `cond' */
981 (*cond) &= ~(PCI(pc)->outCond);
983 if (PCI(pc)->outCond & PCC_REGISTER)
985 /* `op' is (possibly) discarded */
986 if (*reg && !prevIsSkip && sameRegs (op, *reg))
990 fprintf (stderr, "reg is assigned (cont'd) at pc ");
991 pc->print (stderr, pc);
997 /* have all interesting conditions/registers been discarded? */
998 if (!(*reg) && !(*cond))
1002 fprintf (stderr, "reg and conditions are discarded after ");
1003 pc->print (stderr, pc);
1012 /* no use of (or only conditional writes to) `reg' found in flow */
1015 fprintf (stderr, "analysis inconclusive: reg %s, cond %x remains\n", *reg ? "remains" : "is void", *cond);
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 ------------------------------------------------------------------ */
1033 df_state_t *df_free_states = NULL;
1036 df_newState (regs *reg, int cond, pCode *pc)
1040 if (df_free_states) {
1041 state = df_free_states;
1042 df_free_states = (df_state_t *)df_free_states->pc;
1044 state = Safe_calloc(1, sizeof(df_state_t));
1053 df_containsState (set *set, df_state_t *state)
1055 /* scan set for presence of `state' */
1057 for (curr = setFirstItem (set); curr; curr = setNextItem (set))
1059 if ((curr->pc == state->pc)
1060 && (curr->reg == state->reg)
1061 && (curr->cond == state->cond))
1071 df_releaseState (df_state_t *state)
1073 state->pc = (pCode *)df_free_states;
1074 df_free_states = (df_state_t *)state;
1083 while (df_free_states)
1085 next = (df_state_t *)df_free_states->pc;
1086 Safe_free(df_free_states);
1087 df_free_states = next;
1091 int regIsDead (regs *reg, int cond, pCode *pc)
1093 set *seenStates = NULL;
1100 if (reg && !regIsLocal (reg)) return 0;
1102 pc = findNextInstruction (pc->next);
1104 addSet (&todo, df_newState(reg, cond, pc));
1106 while ((result == 1) && (state = getSet (&todo)))
1110 if (df_containsState (seenStates, state)) continue;
1111 addSet (&seenStates, state);
1117 //fprintf (stderr, "Checking for reg %s/cond %x at pc ", reg ? reg->name : "<none>", cond);
1118 //curr->print (stderr, curr);
1120 res = checkRegInFlow (®, &cond, curr);
1123 case 1: /* `reg' or `cond' is read---not dead */
1126 case -1: /* `reg' and `cond' are discarded in this flow---need to check other open flows */
1128 default: /* `reg' is not read and (possibly) not assigned---check successor flows */
1131 pCodeFlow *pcfl = PCI(curr)->pcflow;
1132 pCodeFlowLink *link;
1136 for (link = setFirstItem(pcfl->to); link; link = setNextItem (pcfl->to))
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));
1148 while (NULL != (state = getSet (&todo))) { df_releaseState (state); }
1149 while (NULL != (state = getSet (&seenStates))) { df_releaseState (state); }
1151 /* if result remained 1, `reg' is not even possibly read and thus dead */
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 ------------------------------------------------------------------ */
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;
1172 static int pCodeRemove (pCode *pc, const char *comment)
1174 pCode *pcprev, *pcnext;
1175 unsigned int result = 0;
1177 /* Sanity checks. */
1179 if (!isPCI(pc)) return 0;
1181 pcprev = findPrevInstruction (pc->prev);
1182 if (pcprev && isPCI_SKIP(pcprev))
1184 /* bail out until we know how to fix the Flow... */
1187 /* we also need to remove the preceeding SKIP instruction(s) */
1188 result = pCodeRemove (pcprev, "=DF= removing preceeding SKIP as well");
1191 /* previous instruction could not be removed -- this cannot be removed as well */
1194 /* FIXME: We now have to update the flow! */
1197 /* do not remove pCodes with SFRs as operands (even reading them might cause side effects) */
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;
1205 /* MUST SUCEED FROM NOW ON (or ervert the changes done since NOW ;-)) */
1208 if (PCI(pc)->pcflow && PCI(pc)->pcflow->end == pc)
1211 pcprev = findPrevInstruction (pc->prev);
1212 if (PCI(pcprev)->pcflow == PCI(pc)->pcflow)
1214 PCI(pc)->pcflow->end = pcprev;
1216 pBlock *pb = pc->pb;
1217 RegsUnMapLiveRanges();
1222 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1224 pCodeRegMapLiveRanges(pb);
1229 /* attach labels to next instruction */
1230 pcnext = findNextInstruction (pc->next);
1233 PCI(pcnext)->label = pBranchAppend (PCI(pcnext)->label, PCI(pc)->label);
1234 if (!PCI(pcnext)->cline) PCI(pcnext)->cline = PCI(pc)->cline;
1238 fprintf (stderr, "Cannot move a label...\n");
1246 char *pbuff = &buffer[0];
1248 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): %s", __FILE__, __LINE__, __FUNCTION__, comment);
1249 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1254 /* replace removed pCode with out-commented version of itself */
1257 char *pbuff = &buffer[0];
1259 SAFE_snprintf (&pbuff, &size, "; %s:%u(%s): ", __FILE__, __LINE__, __FUNCTION__);
1260 pCode2str (pbuff, size, pc);
1261 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1268 /* ------------------------------------------------------------------
1269 Find and remove dead pCodes.
1270 ------------------------------------------------------------------ */
1272 static int removeIfDeadPCI (pCode *pc)
1274 pCode *pcnext = NULL;
1276 unsigned int outCond;
1277 unsigned int result = 0;
1284 pcnext = findNextInstruction (pc->next);
1285 if (!isPCI(pc)) return 0;
1287 switch (PCI(pc)->op)
1343 /* do not remove unknown PCIs */
1347 /* redundant checks---those instructions may never be removed */
1348 if (isPCI_BRANCH(pc)) return 0;
1349 if (isPCI_SKIP(pc)) return 0;
1351 outCond = PCI(pc)->outCond;
1354 /* unknown operands assigned to, then ignore */
1355 if ((outCond & (PCC_REGISTER | PCC_C | PCC_Z | PCC_DC | PCC_W)) != outCond)
1358 if (outCond & PCC_REGISTER)
1360 dst = getRegFromInstruction (pc);
1364 if (!regIsLocal (dst)) return 0;
1365 if (regIsSpecial (dst,0)) return 0;
1368 //fprintf (stderr, "--> checking for liveness pc "); pc->print (stderr, pc);
1369 if (regIsDead (dst, outCond, pc))
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");
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
1385 Further, an optional comment can be inserted to indicate the
1386 reason for the possible removal of the pCode.
1387 ------------------------------------------------------------------ */
1389 static void replace_PCI (pCodeInstruction *pc, pCodeInstruction *newpc, char *comment)
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;
1397 newpc->pc.seq = pc->pc.seq;
1399 pCodeInsertAfter (&pc->pc, &newpc->pc);
1401 /* FIXME: replacing pc will break the liverange maps (usedpCodes, ...) */
1405 pCodeInsertAfter (&pc->pc, newpCodeCharP (comment));
1410 /* replace pc with commented out version of itself */
1411 char buffer[1024], buffer2[1024];
1412 char *pbuff = &buffer[0];
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]));
1419 pc->pc.destruct (&pc->pc);
1422 /* ------------------------------------------------------------------
1423 Find the first (unique) assignment to `reg' (prior to pc).
1424 ------------------------------------------------------------------ */
1426 pCode *findAssignmentToReg (regs *reg, pCode *pc)
1430 assert (pc && isPCI(pc) && reg);
1432 curr = findPrevInstruction (pc->prev);
1434 while (curr && PCI(curr)->pcflow == PCI(pc)->pcflow)
1436 if (PCI(curr)->outCond & PCC_REGISTER)
1438 regs *op = getRegFromInstruction (curr);
1439 if (op && (sameRegs(op,reg)))
1442 curr = findPrevInstruction (curr->prev);
1445 /* no assignment to reg found */
1449 /* ------------------------------------------------------------------
1450 Find a register that holds the same value as `reg' (an alias).
1451 ------------------------------------------------------------------ */
1453 regs *findRegisterAlias (regs *reg, pCode *pc)
1457 if(!reg) return NULL;
1459 if (regIsSpecial (reg, 0)) return NULL;
1461 curr = findAssignmentToReg (reg, pc);
1463 /* no assignment found --> no alias found */
1464 if (!curr) return NULL;
1466 switch (PCI(curr)->op)
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)
1474 regs *op = getRegFromInstruction (curr);
1475 /* alias must not be changed since assignment... */
1476 if (PCI(curr)->pcop)
1478 switch (PCI(curr)->pcop->type)
1480 case PO_GPR_REGISTER:
1482 /* these operands are ok */
1485 /* not a plain register operand */
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>");
1494 /* unknown source to WREG -- unknown register alias */
1500 /* unhandled instruction -- assume unknown source, no alias */
1504 /* no alias found */
1508 /* ------------------------------------------------------------------
1509 Analyze a single pCodeInstruction's dataflow relations and replace
1510 it with a better variant if possible.
1511 ------------------------------------------------------------------ */
1513 void analyzeAndReplacePCI (pCodeInstruction *pci)
1515 regs *op_reg, *alias_reg;
1519 if (!isPCI(pci)) return;
1528 /* try to find a different source register */
1529 op_reg = getRegFromInstruction (&pci->pc);
1530 if (pci->op == POC_MOVFW) /* touches Z */
1532 pCode *assignment = findAssignmentToReg (op_reg, &pci->pc);
1533 if (assignment && isPCI(assignment) && (PCI(assignment)->op == POC_CLRF))
1535 replace_PCI (pci, PCI(newpCode(POC_MOVLW, newpCodeOpLit(0))), "replaced with CLRF");
1540 alias_reg = findRegisterAlias (op_reg, &pci->pc);
1543 replace_PCI (pci, PCI(newpCode(pci->op, newpCodeOpRegFromStr (alias_reg->name))), "=DF= replaced with move from register alias");
1548 /* do not optimize */
1553 extern pFile *the_pFile;
1555 /* ------------------------------------------------------------------
1556 Find and remove dead pCodes.
1557 ------------------------------------------------------------------ */
1559 static int removeDeadPCIs (void)
1562 unsigned int removed = 0;
1564 if (!the_pFile) return removed;
1569 /* iterate over all pBlocks */
1570 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1572 pCode *pc, *pcnext = NULL;
1574 /* iterate over all pCodes */
1575 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1577 pcnext = findNextInstruction (pc->next);
1578 removed += removeIfDeadPCI (pc);
1582 fprintf (stderr, "[removed %u dead pCodes]\n", removed);
1588 /* ------------------------------------------------------------------
1589 This routine tries to optimize the dataflow by...
1592 This routine leaves in dead pCodes (assignments whose results are
1593 not used) -- these should be removed in a following sweep phase.
1594 ------------------------------------------------------------------ */
1596 void optimizeDataflow (void)
1600 if (!the_pFile) return;
1602 //fprintf (stderr, "%s:%u(%s): Starting optimization...\n", __FILE__, __LINE__, __FUNCTION__);
1604 /* iterate over all pBlocks */
1605 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1607 pCode *pc, *pcnext = NULL;
1609 /* iterate over all pCodes */
1610 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1612 pcnext = findNextInstruction (pc->next);
1613 analyzeAndReplacePCI (PCI(pc));
1617 while (removeDeadPCIs ()) { /* remove dead codes in multiple passes */};
1623 /*-----------------------------------------------------------------*
1624 * void pCodeRegOptimeRegUsage(pBlock *pb)
1625 *-----------------------------------------------------------------*/
1626 void pCodeRegOptimizeRegUsage(int level)
1631 int t = total_registers_saved;
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 ();
1640 if(!register_optimization)
1642 #define OPT_PASSES 4
1643 passes = OPT_PASSES;
1646 saved = total_registers_saved;
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));
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));
1659 } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
1661 if(total_registers_saved == t)
1662 DFPRINTF((stderr, "No registers saved on this pass\n"));
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);
1676 /*-----------------------------------------------------------------*
1677 * void RegsUnMapLiveRanges(set *regset)
1679 *-----------------------------------------------------------------*/
1680 void RegsSetUnMapLiveRanges(set *regset)
1686 regset = regset->next;
1689 deleteSet(®->reglives.usedpCodes);
1690 deleteSet(®->reglives.usedpFlows);
1691 deleteSet(®->reglives.assignedpFlows);
1697 void RegsUnMapLiveRanges(void)
1700 RegsSetUnMapLiveRanges(dynAllocRegs);
1701 RegsSetUnMapLiveRanges(dynStackRegs);
1702 RegsSetUnMapLiveRanges(dynDirectRegs);
1703 RegsSetUnMapLiveRanges(dynProcessorRegs);
1704 RegsSetUnMapLiveRanges(dynDirectBitRegs);
1705 RegsSetUnMapLiveRanges(dynInternalRegs);