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 "pcoderegs.h"
32 #include "pcodeflow.h"
36 static int total_registers_saved=0;
37 static int register_optimization=1;
39 /*-----------------------------------------------------------------*
40 * void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
41 *-----------------------------------------------------------------*/
43 static void AddRegToFlow(regs *reg, pCodeFlow *pcfl)
46 if(!reg || ! pcfl || !isPCFL(pcflow))
50 pcfl->registers = newSet();
57 /*-----------------------------------------------------------------*
59 *-----------------------------------------------------------------*/
60 static void dbg_regusage(set *fregs)
67 for (reg = setFirstItem(fregs) ; reg ;
68 reg = setNextItem(fregs)) {
70 if(elementsInSet(reg->reglives.usedpCodes)) {
72 fprintf (stderr, "%s addr=0x%03x rIdx=0x%03x",
77 pcfl = setFirstItem(reg->reglives.usedpFlows);
79 fprintf(stderr, "\n used in seq");
82 fprintf(stderr," 0x%03x",pcfl->seq);
83 pcfl = setNextItem(reg->reglives.usedpFlows);
86 pcfl = setFirstItem(reg->reglives.assignedpFlows);
88 fprintf(stderr, "\n assigned in seq");
91 fprintf(stderr," 0x%03x",pcfl->seq);
92 pcfl = setNextItem(reg->reglives.assignedpFlows);
95 pc = setFirstItem(reg->reglives.usedpCodes);
97 fprintf(stderr, "\n used in instructions ");
100 pcfl = PCODE(PCI(pc)->pcflow);
102 fprintf(stderr," 0x%03x:",pcfl->seq);
103 fprintf(stderr,"0x%03x",pc->seq);
105 pc = setNextItem(reg->reglives.usedpCodes);
108 fprintf(stderr, "\n");
115 /*-----------------------------------------------------------------*
117 *-----------------------------------------------------------------*/
118 static void dbg_dumpregusage(void)
121 fprintf(stderr,"*** Register Usage ***\n");
122 fprintf(stderr,"InternalRegs:\n");
123 dbg_regusage(dynInternalRegs);
124 fprintf(stderr,"AllocRegs:\n");
125 dbg_regusage(dynAllocRegs);
126 fprintf(stderr,"StackRegs:\n");
127 dbg_regusage(dynStackRegs);
128 fprintf(stderr,"DirectRegs:\n");
129 dbg_regusage(dynDirectRegs);
130 fprintf(stderr,"DirectBitRegs:\n");
131 dbg_regusage(dynDirectBitRegs);
132 fprintf(stderr,"ProcessorRegs:\n");
133 dbg_regusage(dynProcessorRegs);
138 /*-----------------------------------------------------------------*
139 * void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
140 *-----------------------------------------------------------------*/
141 static void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
152 pc = findNextInstruction(pcfl->pc.next);
154 while(pc && !isPCFL(pc)) {
155 while (pc && !isPCI(pc) && !isPCFL(pc))
159 if (!pc || isPCFL(pc)) continue;
162 reg = getRegFromInstruction(pc);
164 pc->print(stderr, pc);
165 fprintf( stderr, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
166 reg, reg ? reg->name : "(null)", reg ? reg->rIdx : -1,
167 PCI(pc)->inCond, PCI(pc)->outCond );
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);
189 //pc = findNextInstruction(pc->next);
196 /*-----------------------------------------------------------------*
197 * void pCodeRegMapLiveRanges(pBlock *pb)
198 *-----------------------------------------------------------------*/
199 void pCodeRegMapLiveRanges(pBlock *pb)
203 for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
205 pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
207 if(!isPCFL(pcflow)) {
208 fprintf(stderr, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
211 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
215 for( pcflow = findNextpCode(pb->pcHead, PC_FLOW);
217 pcflow = findNextpCode(pcflow->next, PC_FLOW) ) {
219 regs *r = setFirstItem(PCFL(pcflow)->registers);
220 fprintf(stderr,"flow seq %d\n", pcflow->seq);
223 fprintf(stderr, " %s\n",r->name);
224 r = setNextItem(PCFL(pcflow)->registers);
231 // dbg_dumpregusage();
236 /*-----------------------------------------------------------------*
238 *-----------------------------------------------------------------*/
239 static void Remove1pcode(pCode *pc, regs *reg, int debug_code)
247 deleteSetItem (&(reg->reglives.usedpCodes),pc);
250 pcn = findNextInstruction(pc->next);
253 PCI(pcn)->label = pBranchAppend(PCI(pcn)->label,PCI(pc)->label);
258 pcn = findNextInstruction(pc->next);
261 if(PCI(pcn)->cline) {
262 //fprintf(stderr, "source line has been optimized completely out\n");
263 //pc->print(stderr,pc);
265 PCI(pcn)->cline = PCI(pc)->cline;
273 * Debug stuff. Comment out the instruction we're about to delete.
282 SNPRINTF(pbuff, size, ";%d", debug_code);
283 size -= strlen(pbuff);
284 pbuff += strlen(pbuff);
285 pCode2str(pbuff, size, pc);
286 pCodeInsertBefore(pc, newpCodeCharP(buff1));
287 //fprintf(stderr,"removing instruction:\n%s\n",buff1);
294 /*-----------------------------------------------------------------*
295 * void RemoveRegsFromSet(set *regset)
297 *-----------------------------------------------------------------*/
298 static void RemoveRegsFromSet(set *regset)
305 regset = regset->next;
307 used = elementsInSet(reg->reglives.usedpCodes);
311 //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
313 //fprintf(stderr," getting rid of reg %s\n",reg->name);
320 pc = setFirstItem(reg->reglives.usedpCodes);
322 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern) {
323 //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
330 pCode *pcn = findNextInstruction(pc->next);
332 if(pcn && PCI(pcn)->label) {
333 //fprintf(stderr,"can't delete instruction with label...\n");
334 //pc->print(stderr,pc);
337 /* Move the label to the next instruction */
339 PCI(pcn)->label = PCI(pc)->label;
344 regs *r = getRegFromInstruction(pc);
345 fprintf(stderr, "WARNING, a skip instruction is being optimized out\n");
346 pc->print(stderr,pc);
347 fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
349 //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
350 Remove1pcode(pc, reg, 1);
353 deleteSetItem (&(reg->reglives.usedpCodes),pc);
357 total_registers_saved++; // debugging stats.
365 static void pic14_ReMapLiveRanges(void)
368 if (!the_pFile) return;
369 RegsUnMapLiveRanges();
370 for (pb = the_pFile->pbHead; pb; pb = pb->next)
373 pCode *pc = findNextpCode(pb->pcHead, PC_FLOW);
375 pc->print( stderr, pc );
377 fprintf( stderr, "unnamed pBlock\n");
379 pc = findNextInstruction(pb->pcHead);
381 pc->print( stderr, pc );
382 pc = findNextInstruction(pc->next);;
385 pCodeRegMapLiveRanges(pb);
389 /*-----------------------------------------------------------------*
390 * void RemoveUnusedRegisters(void)
392 *-----------------------------------------------------------------*/
393 void RemoveUnusedRegisters(void)
395 /* First, get rid of registers that are used only one time */
396 pic14_ReMapLiveRanges();
398 //RemoveRegsFromSet(dynInternalRegs);
399 RemoveRegsFromSet(dynAllocRegs);
400 RemoveRegsFromSet(dynStackRegs);
402 don't do DirectRegs yet - there's a problem with arrays
403 RemoveRegsFromSet(dynDirectRegs);
405 RemoveRegsFromSet(dynDirectBitRegs);
407 if(total_registers_saved) DFPRINTF((stderr, " *** Saved %d registers ***\n", total_registers_saved));
411 /*-----------------------------------------------------------------*
413 *-----------------------------------------------------------------*/
414 static void Remove2pcodes(pCode *pcflow, pCode *pc1, pCode *pc2, regs *reg, int can_free)
416 static int debug_code=99;
420 fprintf (stderr, "%s:%d(%s): %d (reg:%s)\n", __FILE__, __LINE__, __FUNCTION__, debug_code, reg ? reg->name : "???");
421 printpCode (stderr, pc1);
422 printpCode (stderr, pc2);
425 //fprintf(stderr,"%s\n",__FUNCTION__);
427 Remove1pcode(pc1, reg, debug_code++);
430 Remove1pcode(pc2, reg, debug_code++);
431 deleteSetItem (&(PCFL(pcflow)->registers), reg);
440 pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
443 /*-----------------------------------------------------------------*
445 *-----------------------------------------------------------------*/
446 static int regUsedinRange(pCode *pc1, pCode *pc2, regs *reg)
452 testreg = getRegFromInstruction(pc1);
453 if(testreg && (testreg->rIdx == reg->rIdx)) {
457 fprintf(stderr, "warning, regUsedinRange searched through too many pcodes\n");
461 pc1 = findNextInstruction(pc1->next);
463 } while (pc1 && (pc1 != pc2)) ;
468 static int regIsSpecial (regs *reg, int mayBeGlobal)
472 if (reg->type == REG_SFR || reg->type == REG_STK || (!mayBeGlobal && (reg->isPublic || reg->isExtern))) return 1;
478 static int regIsLocal (regs *reg)
481 /* temporaries are local */
482 if (reg->type == REG_TMP) return 1;
483 /* registers named r0x... are local */
484 if (reg->name && !strncmp(reg->name,"r0x", 3))
486 //fprintf (stderr, "reg %s is not marked REG_TMP...\n", reg->name);
494 /*-----------------------------------------------------------------*
495 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2)
497 * ADHOC pattern checking
498 * Now look for specific sequences that are easy to optimize.
499 * Many of these sequences are characteristic of the compiler
500 * (i.e. it'd probably be a waste of time to apply these adhoc
501 * checks to hand written assembly.)
504 *-----------------------------------------------------------------*/
505 static int pCodeOptime2pCodes(pCode *pc1, pCode *pc2, pCode *pcfl_used, regs *reg, int can_free, int optimize_level)
510 int t = total_registers_saved;
512 if (!isPCI(pc1) || !isPCI(pc2)) return 0;
513 if (PCI(pc1)->pcflow != PCI(pc2)->pcflow) return 0;
515 if (pc2->seq < pc1->seq) {
521 /* disable this optimization for now -- it's buggy */
522 if (pic14_options.disable_df) return 0;
524 //fprintf(stderr,"pCodeOptime2pCodes\n");
525 //pc1->print(stderr,pc1);
526 //pc2->print(stderr,pc2);
528 if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_MOVFW) ){
532 * MOVWF does not touch Z
533 * MOVLW does not touch Z
541 can be replaced with (only if following instructions are not going to use W and reg is not used again later)
546 DFPRINTF((stderr, " optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
547 pct2 = findNextInstruction(pc2->next);
548 if (pCodeSearchCondition(pct2, PCC_Z, 0) == -1) {
549 /* Z is definitely overwritten before use */
550 newpc = newpCode(POC_MOVLW, newpCodeOpLit(0));
552 pCodeInsertAfter(pc2, newpc);
553 PCI(newpc)->pcflow = PCFL(pcfl_used);
554 newpc->seq = pc2->seq;
556 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
557 //Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
559 //total_registers_saved++; // debugging stats.
561 } else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
562 DFPRINTF((stderr, " optimising CLRF/IORFW\n"));
564 pct2 = findNextInstruction(pc2->next);
566 /* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
567 if (pCodeSearchCondition(pct2, PCC_Z, 0) != -1) {
568 pct2 = newpCode(POC_IORLW, newpCodeOpLit(0));
569 pct2->seq = pc2->seq;
570 PCI(pct2)->pcflow = PCFL(pcfl_used);
571 pCodeInsertAfter(pc1,pct2);
573 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
574 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
575 total_registers_saved++; // debugging stats.
577 } else if(PCI(pc1)->op == POC_MOVWF) {
578 // Optimising MOVWF reg ...
580 pct2 = findNextInstruction(pc2->next);
582 if(PCI(pc2)->op == POC_MOVFW) {
583 // Optimising MOVWF reg ... MOVF reg,W
585 if(PCI(pct2)->op == POC_MOVWF) {
594 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
600 reg2 = getRegFromInstruction(pct2);
601 /* Check reg2 is not used for something else before it is loaded with reg */
602 if (reg2 && !regIsSpecial (reg2, 1) && !regUsedinRange(pc1,pc2,reg2)) {
603 pCode *pct3 = findNextInstruction(pct2->next);
604 /* Check following instructions are not relying on the use of W or the Z flag condiction */
605 /* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
606 * subsequent flows (checking for < 1 is insufficient). */
607 if ((pCodeSearchCondition(pct3,PCC_Z,0) == -1) && (pCodeSearchCondition(pct3,PCC_W,0) == -1)) {
608 DFPRINTF((stderr, " optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
609 pct2->seq = pc1->seq;
611 pCodeInsertBefore(pc1,pct2);
612 if(regUsedinRange(pct2,0,reg))
614 //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
615 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
617 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
618 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
620 total_registers_saved++; // debugging stats.
627 pct1 = findPrevInstruction(pc1->prev);
628 if(pct1 && (PCI(pct1)->pcflow == PCI(pc1)->pcflow)) {
630 if ( (PCI(pct1)->op == POC_MOVFW) &&
631 (PCI(pc2)->op == POC_MOVFW)) {
633 reg1 = getRegFromInstruction(pct1);
634 if(reg1 && !regIsSpecial (reg1, 0) && !regUsedinRange(pc1,pc2,reg1)) {
635 DFPRINTF((stderr, " optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
651 Or, if we're not deleting the register then the "To" is:
658 pct2 = newpCode(PCI(pc2)->op, PCI(pct1)->pcop);
659 pCodeInsertAfter(pc2, pct2);
660 PCI(pct2)->pcflow = PCFL(pcfl_used);
661 pct2->seq = pc2->seq;
664 //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
665 Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
667 /* If we're not freeing the register then that means (probably)
668 * the register is needed somewhere else.*/
670 pCodeInsertAfter(pct2, pc1);
672 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
673 Remove2pcodes(pcfl_used, pc2, NULL, reg, can_free);
676 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
677 Remove2pcodes(pcfl_used, pct1, NULL, reg1, 0);
678 total_registers_saved++; // debugging stats.
685 return (total_registers_saved != t);
688 /*-----------------------------------------------------------------*
689 * void pCodeRegOptimeRegUsage(pBlock *pb)
690 *-----------------------------------------------------------------*/
691 static void OptimizeRegUsage(set *fregs, int optimize_multi_uses, int optimize_level)
695 pCode *pc1=NULL, *pc2=NULL;
699 pCode *pcfl_used, *pcfl_assigned;
701 /* Step through the set by directly accessing the 'next' pointer.
702 * We could also step through by using the set API, but the
703 * the (debug) calls to print instructions affect the state
704 * of the set pointers */
709 if (strcmp(reg->name,"_SubState")==0)
710 fprintf(stderr,"Reg: %s\n",reg->name);
713 /* Catch inconsistently set-up live ranges
714 * (see tracker items #1469504 + #1474602)
715 * FIXME: Actually we should rather fix the
716 * computation of the liveranges instead...
718 if (!reg || !reg->reglives.usedpFlows
719 || !reg->reglives.assignedpFlows)
721 //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
725 if(reg->type == REG_SFR || reg->type == REG_STK || reg->isPublic || reg->isExtern|| reg->isFixed) {
726 //fprintf(stderr,"skipping SFR: %s\n",reg->name);
730 pcfl_used = setFirstItem(reg->reglives.usedpFlows);
731 pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
733 used = elementsInSet(reg->reglives.usedpCodes);
736 In this section, all registers that are used in only in two
737 instructions are examined. If possible, they're optimized out.
741 fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
744 reg->rIdx, reg->type, used);
746 pc1 = setFirstItem(reg->reglives.usedpCodes);
747 pc2 = setNextItem(reg->reglives.usedpCodes);
749 if(pcfl_used && pcfl_assigned) {
751 expected case - the register has been assigned a value and is
755 //fprintf(stderr," used only twice\n");
756 if(pcfl_used->seq == pcfl_assigned->seq) {
758 //fprintf(stderr, " and used in same flow\n");
760 pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 1,optimize_level);
763 // fprintf(stderr, " and used in different flows\n");
767 } else if(pcfl_used) {
769 /* register has been used twice without ever being assigned */
770 fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
773 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
774 Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
775 total_registers_saved++; // debugging stats.
779 /* register has been used either once, or more than twice */
781 if(used && !pcfl_used && pcfl_assigned) {
784 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
786 pc = setFirstItem(reg->reglives.usedpCodes);
789 pcfl_assigned = PCODE(PCI(pc)->pcflow);
790 Remove1pcode(pc, reg,2);
792 deleteSetItem (&(PCFL(pcfl_assigned)->registers), reg);
794 deleteSetItem (&(reg->reglives.usedpCodes),pc);
797 pc = setNextItem(reg->reglives.usedpCodes);
804 total_registers_saved++; // debugging stats.
805 } else if( (used > 2) && optimize_multi_uses) {
811 pCodeFlow *pcfl1=NULL, *pcfl2=NULL;
813 /* examine the number of times this register is used */
816 rset1 = reg->reglives.usedpCodes;
817 while(rset1 && searching) {
822 if(pc1 && isPCI(pc1) && ( (pcfl1 = PCI(pc1)->pcflow) != NULL) ) {
827 if(pc2 && isPCI(pc2) && ( (pcfl2 = PCI(pc2)->pcflow) != NULL) ) {
830 if(pCodeOptime2pCodes(pc1, pc2, pcfl_used, reg, 0,optimize_level))
835 //rset2 = rset2->next;
848 /* The following routines implement pCode optimizations based on
849 * dataflow analysis. The effects should be similar to those
850 * of pCodeOptime2pCodes() but more powerful.
852 * Unfortunately, the current approach (comparing operands by
853 * their associated registers) is seriously flawed:
854 * Some pCodeOps do not provide access to their repsective regs
855 * (PO_DIRs are created from arbitrary strings, immediates need
856 * to take offset and index into account, ...)
858 * This has to be rewritten based on pCodeOps instead of regs...
861 /* ------------------------------------------------------------------
862 Returns TRUE iff reg1 and reg2 are the same registers.
863 ------------------------------------------------------------------ */
865 static int sameRegs (const regs *reg1, const regs *reg2)
867 if (reg1 == reg2) return 1;
868 if (!reg1 || !reg2) return 0;
869 assert (reg1->name && reg2->name);
871 /* Compare names, as rIdx is not unique... */
872 if (!strcmp(reg1->name, reg2->name)) return 1;
874 /* Name mismatch -- not the same register. */
878 /* ------------------------------------------------------------------
879 Returns 1 if the register is live at pc (read in this flow),
880 returns -1 if the register is NOT live at pc (assigned a new value
881 prior to readingi the old value in this flow) or
882 return 0 if the register is not mentioned.
883 ------------------------------------------------------------------ */
885 static int checkRegInFlow (regs **reg, int *cond, pCode *pc)
887 const int verbose = 0;
888 /* find next PCI at or after pc */
889 while (pc && isPCFL(pc)) pc = pc->next;
891 assert (reg && cond);
893 /* remove pseudo flags from cond */
894 *cond &= ~(PCC_REGISTER | PCC_EXAMINE_PCOP);
898 fprintf (stderr, "Checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond); pc->print (stderr, pc);
901 while (pc && !isPCFL(pc))
905 fprintf (stderr, " now checking for reg %s, cond %x on pc ", *reg ? (*reg)->name : "<none>", *cond);
906 pc->print (stderr, pc);
914 pcprev = findPrevInstruction (pc);
915 if (pcprev && isPCI_SKIP(pcprev))
918 if ((PCI(pc)->inCond | PCI(pc)->outCond) & PCC_REGISTER)
920 op = getRegFromInstruction (pc);
922 /* pCodeOpRegBits do not provide register information... */
923 //if (!op) { __asm__("int3"); pc->print (stderr, pc); }
928 return 1; /* assume `reg' is alive */
931 /* SPECIAL CASE: jump to unknown destination -- assume everything alive */
932 if (op->type == PO_PCL)
938 if (PCI(pc)->inCond & PCC_REGISTER)
940 /* `op' is live (possibly read) */
941 if (*reg && sameRegs (op, *reg))
945 fprintf (stderr, "reg is read in pc ");
946 pc->print (stderr, pc);
952 /* handle additional implicit operands */
955 case POC_CALL: /* read arguments from WREG, clobbers WREG */
960 fprintf (stderr, "conditions are read at pc ");
961 pc->print (stderr, pc);
967 case POC_RETURN: /* returns WREG to caller */
968 //fprintf (stderr, "reached RETURN, reg %s, cond %x\n", *reg ? (*reg)->name : "<none>", *cond);
973 fprintf (stderr, "conditions are read at pc ");
974 pc->print (stderr, pc);
978 /* afterwards, no condition is alive */
980 /* afterwards, all local registers are dead */
981 if (*reg && regIsLocal (*reg)) *reg = NULL;
984 case POC_RETFIE: /* this does not erturn WREG to the "caller", thus its rather a RETLW */
985 /* this discards WREG */
987 /* afterwards, no condition is alive */
989 /* afterwards, all local registers are dead */
990 if (*reg && regIsLocal (*reg)) *reg = NULL;
993 /* no implicit arguments */
997 if (PCI(pc)->inCond & (*cond))
999 /* a condition is read */
1002 fprintf (stderr, "conditions are read at pc ");
1003 pc->print (stderr, pc);
1008 /* remove outConds from `cond' */
1009 (*cond) &= ~(PCI(pc)->outCond);
1011 if (PCI(pc)->outCond & PCC_REGISTER)
1013 /* `op' is (possibly) discarded */
1014 if (*reg && !prevIsSkip && sameRegs (op, *reg))
1018 fprintf (stderr, "reg is assigned (cont'd) at pc ");
1019 pc->print (stderr, pc);
1025 /* have all interesting conditions/registers been discarded? */
1026 if (!(*reg) && !(*cond))
1030 fprintf (stderr, "reg and conditions are discarded after ");
1031 pc->print (stderr, pc);
1040 /* no use of (or only conditional writes to) `reg' found in flow */
1043 fprintf (stderr, "analysis inconclusive: reg %s, cond %x remains\n", *reg ? "remains" : "is void", *cond);
1048 /* ------------------------------------------------------------------
1049 This will return 1 only if
1050 - reg is NULL or of type REG_TMP
1051 - reg is NULL or its value is discarded after pc
1052 - cond is 0 or all conditions are overwritten before being used
1053 ------------------------------------------------------------------ */
1061 df_state_t *df_free_states = NULL;
1064 df_newState (regs *reg, int cond, pCode *pc)
1068 if (df_free_states) {
1069 state = df_free_states;
1070 df_free_states = (df_state_t *)df_free_states->pc;
1072 state = Safe_calloc(1, sizeof(df_state_t));
1081 df_containsState (set *set, df_state_t *state)
1083 /* scan set for presence of `state' */
1085 for (curr = setFirstItem (set); curr; curr = setNextItem (set))
1087 if ((curr->pc == state->pc)
1088 && (curr->reg == state->reg)
1089 && (curr->cond == state->cond))
1099 df_releaseState (df_state_t *state)
1101 state->pc = (pCode *)df_free_states;
1102 df_free_states = (df_state_t *)state;
1111 while (df_free_states)
1113 next = (df_state_t *)df_free_states->pc;
1114 Safe_free(df_free_states);
1115 df_free_states = next;
1119 static int regIsDead (regs *reg, int cond, pCode *pc)
1121 set *seenStates = NULL;
1128 if (reg && !regIsLocal (reg)) return 0;
1130 pc = findNextInstruction (pc->next);
1132 addSet (&todo, df_newState(reg, cond, pc));
1134 while ((result == 1) && (state = getSet (&todo)))
1138 if (df_containsState (seenStates, state)) continue;
1139 addSet (&seenStates, state);
1145 //fprintf (stderr, "Checking for reg %s/cond %x at pc ", reg ? reg->name : "<none>", cond);
1146 //curr->print (stderr, curr);
1148 res = checkRegInFlow (®, &cond, curr);
1151 case 1: /* `reg' or `cond' is read---not dead */
1154 case -1: /* `reg' and `cond' are discarded in this flow---need to check other open flows */
1156 default: /* `reg' is not read and (possibly) not assigned---check successor flows */
1159 pCodeFlow *pcfl = PCI(curr)->pcflow;
1160 pCodeFlowLink *link;
1164 for (link = setFirstItem(pcfl->to); link; link = setNextItem (pcfl->to))
1166 /* add the first pCodeInstruction in the new flow to `todo' */
1167 first = findNextInstruction (&link->pcflow->pc);
1168 if (first) addSet (&todo, df_newState (reg, cond, first));
1176 while (NULL != (state = getSet (&todo))) { df_releaseState (state); }
1177 while (NULL != (state = getSet (&seenStates))) { df_releaseState (state); }
1179 /* if result remained 1, `reg' is not even possibly read and thus dead */
1185 /* ------------------------------------------------------------------
1186 Safely remove a pCode.
1187 This needs to check that the previous instruction was no SKIP
1188 (otherwise the SKIP instruction would have to be removed as well,
1189 which may not be done for SFRs (side-effects on read possible)).
1190 ------------------------------------------------------------------ */
1192 static int pCodeRemove (pCode *pc, const char *comment)
1194 pCode *pcprev, *pcnext;
1195 unsigned int result = 0;
1197 /* Sanity checks. */
1199 if (!isPCI(pc)) return 0;
1201 pcprev = findPrevInstruction (pc->prev);
1202 if (pcprev && isPCI_SKIP(pcprev))
1204 /* bail out until we know how to fix the Flow... */
1207 /* we also need to remove the preceeding SKIP instruction(s) */
1208 result = pCodeRemove (pcprev, "=DF= removing preceeding SKIP as well");
1211 /* previous instruction could not be removed -- this cannot be removed as well */
1214 /* FIXME: We now have to update the flow! */
1217 /* do not remove pCodes with SFRs as operands (even reading them might cause side effects) */
1220 reg = getRegFromInstruction (pc);
1221 /* accesses to the STATUS register aer always safe, but others... */
1222 if (reg && reg->type == REG_SFR && reg->pc_type != PO_STATUS) return result;
1225 /* MUST SUCEED FROM NOW ON (or revert the changes done since NOW ;-)) */
1228 if (PCI(pc)->pcflow && PCI(pc)->pcflow->end == pc)
1231 pcprev = findPrevInstruction (pc->prev);
1232 if (PCI(pcprev)->pcflow == PCI(pc)->pcflow)
1234 PCI(pc)->pcflow->end = pcprev;
1236 pBlock *pb = pc->pb;
1237 RegsUnMapLiveRanges();
1242 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1244 pCodeRegMapLiveRanges(pb);
1249 /* attach labels to next instruction */
1250 pcnext = findNextInstruction (pc->next);
1253 PCI(pcnext)->label = pBranchAppend (PCI(pcnext)->label, PCI(pc)->label);
1254 if (!PCI(pcnext)->cline) PCI(pcnext)->cline = PCI(pc)->cline;
1258 fprintf (stderr, "Cannot move a label...\n");
1266 char *pbuff = &buffer[0];
1268 SNPRINTF (pbuff, size, "; %s:%u(%s): %s", __FILE__, __LINE__, __FUNCTION__, comment);
1269 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1274 /* replace removed pCode with out-commented version of itself */
1277 char *pbuff = &buffer[0];
1279 SNPRINTF (pbuff, size, "; %s:%u(%s): ", __FILE__, __LINE__, __FUNCTION__);
1280 size -= strlen(pbuff);
1281 pbuff += strlen(pbuff);
1282 pCode2str (pbuff, size, pc);
1283 pCodeInsertAfter(pc->prev, newpCodeCharP (&buffer[0]));
1290 /* ------------------------------------------------------------------
1291 Find and remove dead pCodes.
1292 ------------------------------------------------------------------ */
1294 static int removeIfDeadPCI (pCode *pc)
1296 pCode *pcnext = NULL;
1298 unsigned int outCond;
1299 unsigned int result = 0;
1306 pcnext = findNextInstruction (pc->next);
1307 if (!isPCI(pc)) return 0;
1309 switch (PCI(pc)->op)
1365 /* do not remove unknown PCIs */
1369 /* redundant checks---those instructions may never be removed */
1370 if (isPCI_BRANCH(pc)) return 0;
1371 if (isPCI_SKIP(pc)) return 0;
1373 outCond = PCI(pc)->outCond;
1376 /* unknown operands assigned to, then ignore */
1377 if ((outCond & (PCC_REGISTER | PCC_C | PCC_Z | PCC_DC | PCC_W)) != outCond)
1380 if (outCond & PCC_REGISTER)
1382 dst = getRegFromInstruction (pc);
1386 if (!regIsLocal (dst)) return 0;
1387 if (regIsSpecial (dst,0)) return 0;
1390 //fprintf (stderr, "--> checking for liveness pc "); pc->print (stderr, pc);
1391 if (regIsDead (dst, outCond, pc))
1393 /* no result from pc has been used -- pc is `dead' */
1394 //fprintf (stderr, "--> reg %s and cond %x assumed unused\n", dst ? dst->name : "<none>", outCond);
1395 //fprintf (stderr, "--> removing dead pc "); pc->print (stderr, pc);
1396 result = pCodeRemove (pc, "=DF= removed dead pCode");
1402 /* ------------------------------------------------------------------
1403 This routine is intended to safely replace one pCodeInstruction
1404 with a different pCodeInstruction.
1405 If desired, the replaced pCode will be left in (commented out) for
1407 Further, an optional comment can be inserted to indicate the
1408 reason for the possible removal of the pCode.
1409 ------------------------------------------------------------------ */
1411 static void replace_PCI (pCodeInstruction *pc, pCodeInstruction *newpc, char *comment)
1413 newpc->from = pBranchAppend (newpc->from, pc->from);
1414 newpc->to = pBranchAppend (newpc->to, pc->to);
1415 newpc->label = pBranchAppend (newpc->label, pc->label);
1416 //newpc->pcflow = pc->pcflow; // updated in pCodeInsertAfter, ->pb is as well
1417 newpc->cline = pc->cline;
1419 newpc->pc.seq = pc->pc.seq;
1421 pCodeInsertAfter (&pc->pc, &newpc->pc);
1423 /* FIXME: replacing pc will break the liverange maps (usedpCodes, ...) */
1424 pCodeRegMapLiveRanges( pc->pBlock ); /*FIXME:UNTESTED*/
1428 pCodeInsertAfter (&pc->pc, newpCodeCharP (comment));
1433 /* replace pc with commented out version of itself */
1434 char buffer[1024], buffer2[1024];
1435 char *pbuff = &buffer[0];
1437 pCode2str (&buffer2[0],1024,&pc->pc);
1438 SNPRINTF (pbuff,size,"%s:%u(%s): removed pCode was %s\t", __FILE__, __LINE__, __FUNCTION__, &buffer2[0]);
1439 pCodeInsertAfter (&pc->pc, newpCodeCharP (&buffer[0]));
1442 pc->pc.destruct (&pc->pc);
1445 /* ------------------------------------------------------------------
1446 Find the first (unique) assignment to `reg' (prior to pc).
1447 ------------------------------------------------------------------ */
1449 static pCode *findAssignmentToReg (regs *reg, pCode *pc)
1453 assert (pc && isPCI(pc) && reg);
1455 curr = findPrevInstruction (pc->prev);
1457 while (curr && PCI(curr)->pcflow == PCI(pc)->pcflow)
1459 if (PCI(curr)->outCond & PCC_REGISTER)
1461 regs *op = getRegFromInstruction (curr);
1462 if (op && (sameRegs(op,reg)))
1465 curr = findPrevInstruction (curr->prev);
1468 /* no assignment to reg found */
1472 /* ------------------------------------------------------------------
1473 Find a register that holds the same value as `reg' (an alias).
1474 ------------------------------------------------------------------ */
1476 static regs *findRegisterAlias (regs *reg, pCode *pc)
1480 if(!reg) return NULL;
1482 if (regIsSpecial (reg, 0)) return NULL;
1484 curr = findAssignmentToReg (reg, pc);
1486 /* no assignment found --> no alias found */
1487 if (!curr) return NULL;
1489 switch (PCI(curr)->op)
1492 /* find previous assignment to WREG */
1493 while (curr && !(PCI(curr)->outCond & PCC_W))
1494 curr = findPrevInstruction (curr->prev);
1495 if (curr && PCI(curr)->op == POC_MOVFW)
1497 regs *op = getRegFromInstruction (curr);
1498 /* alias must not be changed since assignment... */
1499 if (PCI(curr)->pcop)
1501 switch (PCI(curr)->pcop->type)
1503 case PO_GPR_REGISTER:
1505 /* these operands are ok */
1508 /* not a plain register operand */
1513 if (!op || regIsSpecial (op, 0) || !regIsUnchangedSince (op, pc, curr)) return NULL;
1514 //fprintf (stderr, "found register alias for %s: %s\n", reg->name, op && op->name ? op->name : "<no name>");
1517 /* unknown source to WREG -- unknown register alias */
1523 /* unhandled instruction -- assume unknown source, no alias */
1527 /* no alias found */
1531 /* ------------------------------------------------------------------
1532 Analyze a single pCodeInstruction's dataflow relations and replace
1533 it with a better variant if possible.
1534 ------------------------------------------------------------------ */
1536 static void analyzeAndReplacePCI (pCodeInstruction *pci)
1538 regs *op_reg, *alias_reg;
1542 if (!isPCI(pci)) return;
1551 /* try to find a different source register */
1552 op_reg = getRegFromInstruction (&pci->pc);
1553 if (pci->op == POC_MOVFW) /* touches Z */
1555 pCode *assignment = findAssignmentToReg (op_reg, &pci->pc);
1556 if (assignment && isPCI(assignment) && (PCI(assignment)->op == POC_CLRF))
1558 replace_PCI (pci, PCI(newpCode(POC_MOVLW, newpCodeOpLit(0))), "replaced with CLRF");
1563 alias_reg = findRegisterAlias (op_reg, &pci->pc);
1566 replace_PCI (pci, PCI(newpCode(pci->op, newpCodeOpRegFromStr (alias_reg->name))), "=DF= replaced with move from register alias");
1571 /* do not optimize */
1576 /* ------------------------------------------------------------------
1577 Find and remove dead pCodes.
1578 ------------------------------------------------------------------ */
1580 static int removeDeadPCIs (void)
1583 unsigned int removed = 0;
1585 if (!the_pFile) return removed;
1590 /* iterate over all pBlocks */
1591 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1593 pCode *pc, *pcnext = NULL;
1595 /* iterate over all pCodes */
1596 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1598 pcnext = findNextInstruction (pc->next);
1599 removed += removeIfDeadPCI (pc);
1603 fprintf (stderr, "[removed %u dead pCodes]\n", removed);
1609 /* ------------------------------------------------------------------
1610 This routine tries to optimize the dataflow by...
1613 This routine leaves in dead pCodes (assignments whose results are
1614 not used) -- these should be removed in a following sweep phase.
1615 ------------------------------------------------------------------ */
1617 static void optimizeDataflow (void)
1621 if (!the_pFile) return;
1623 //fprintf (stderr, "%s:%u(%s): Starting optimization...\n", __FILE__, __LINE__, __FUNCTION__);
1625 /* iterate over all pBlocks */
1626 for (pb = the_pFile->pbHead; pb; pb = pb->next)
1628 pCode *pc, *pcnext = NULL;
1630 /* iterate over all pCodes */
1631 for (pc = findNextInstruction (pb->pcHead); pc; pc = pcnext)
1633 pcnext = findNextInstruction (pc->next);
1634 analyzeAndReplacePCI (PCI(pc));
1638 while (removeDeadPCIs ()) { /* remove dead codes in multiple passes */};
1644 /*-----------------------------------------------------------------*
1645 * void pCodeRegOptimeRegUsage(pBlock *pb)
1646 *-----------------------------------------------------------------*/
1647 void pCodeRegOptimizeRegUsage(int level)
1652 int t = total_registers_saved;
1655 /* This is currently broken (need rewrite to correctly
1656 * handle arbitrary pCodeOps instead of registers only). */
1657 if (!pic14_options.disable_df)
1658 optimizeDataflow ();
1661 if(!register_optimization)
1663 #define OPT_PASSES 4
1664 passes = OPT_PASSES;
1667 saved = total_registers_saved;
1669 /* Identify registers used in one flow sequence */
1670 OptimizeRegUsage(dynAllocRegs,level, (OPT_PASSES-passes));
1671 OptimizeRegUsage(dynStackRegs,level, (OPT_PASSES-passes));
1672 OptimizeRegUsage(dynDirectRegs,0, (OPT_PASSES-passes));
1674 if(total_registers_saved != saved)
1675 DFPRINTF((stderr, " *** pass %d, Saved %d registers, total saved %d ***\n",
1676 (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved));
1680 } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
1682 if(total_registers_saved == t)
1683 DFPRINTF((stderr, "No registers saved on this pass\n"));
1687 fprintf(stderr,"dynamically allocated regs:\n");
1688 dbg_regusage(dynAllocRegs);
1689 fprintf(stderr,"stack regs:\n");
1690 dbg_regusage(dynStackRegs);
1691 fprintf(stderr,"direct regs:\n");
1692 dbg_regusage(dynDirectRegs);
1697 /*-----------------------------------------------------------------*
1698 * void RegsUnMapLiveRanges(set *regset)
1700 *-----------------------------------------------------------------*/
1701 static void RegsSetUnMapLiveRanges(set *regset)
1707 regset = regset->next;
1710 deleteSet(®->reglives.usedpCodes);
1711 deleteSet(®->reglives.usedpFlows);
1712 deleteSet(®->reglives.assignedpFlows);
1718 void RegsUnMapLiveRanges(void)
1721 RegsSetUnMapLiveRanges(dynAllocRegs);
1722 RegsSetUnMapLiveRanges(dynStackRegs);
1723 RegsSetUnMapLiveRanges(dynDirectRegs);
1724 RegsSetUnMapLiveRanges(dynProcessorRegs);
1725 RegsSetUnMapLiveRanges(dynDirectBitRegs);
1726 RegsSetUnMapLiveRanges(dynInternalRegs);