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 pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
41 *-----------------------------------------------------------------*/
42 static void pCodeRegMapLiveRangesInFlow(pCodeFlow
*pcfl
)
53 pc
= findNextInstruction(pcfl
->pc
.next
);
55 while(pc
&& !isPCFL(pc
)) {
56 while (pc
&& !isPCI(pc
) && !isPCFL(pc
))
60 if (!pc
|| isPCFL(pc
)) continue;
63 reg
= getRegFromInstruction(pc
);
65 pc
->print(stderr
, pc
);
66 fprintf( stderr
, "--> reg %p (%s,%u), inCond/outCond: %x/%x\n",
67 reg
, reg
? reg
->name
: "(null)", reg
? reg
->rIdx
: -1,
68 PCI(pc
)->inCond
, PCI(pc
)->outCond
);
72 fprintf(stderr, "flow seq %d, inst seq %d %s ",PCODE(pcfl)->seq,pc->seq,reg->name);
73 fprintf(stderr, "addr = 0x%03x, type = %d rIdx=0x%03x\n",
74 reg->address,reg->type,reg->rIdx);
77 addSetIfnotP(& (PCFL(pcfl
)->registers
), reg
);
79 if(PCC_REGISTER
& PCI(pc
)->inCond
)
80 addSetIfnotP(& (reg
->reglives
.usedpFlows
), pcfl
);
82 if(PCC_REGISTER
& PCI(pc
)->outCond
)
83 addSetIfnotP(& (reg
->reglives
.assignedpFlows
), pcfl
);
85 addSetIfnotP(& (reg
->reglives
.usedpCodes
), pc
);
90 //pc = findNextInstruction(pc->next);
97 /*-----------------------------------------------------------------*
98 * void pCodeRegMapLiveRanges(pBlock *pb)
99 *-----------------------------------------------------------------*/
100 void pCodeRegMapLiveRanges(pBlock
*pb
)
104 for( pcflow
= findNextpCode(pb
->pcHead
, PC_FLOW
);
106 pcflow
= findNextpCode(pcflow
->next
, PC_FLOW
) ) {
108 if(!isPCFL(pcflow
)) {
109 fprintf(stderr
, "pCodeRegMapLiveRanges - pcflow is not a flow object ");
112 pCodeRegMapLiveRangesInFlow(PCFL(pcflow
));
116 for( pcflow
= findNextpCode(pb
->pcHead
, PC_FLOW
);
118 pcflow
= findNextpCode(pcflow
->next
, PC_FLOW
) ) {
120 regs
*r
= setFirstItem(PCFL(pcflow
)->registers
);
121 fprintf(stderr
,"flow seq %d\n", pcflow
->seq
);
124 fprintf(stderr
, " %s\n",r
->name
);
125 r
= setNextItem(PCFL(pcflow
)->registers
);
135 /*-----------------------------------------------------------------*
137 *-----------------------------------------------------------------*/
138 static void Remove1pcode(pCode
*pc
, reg_info
*reg
, int debug_code
)
146 deleteSetItem (&(reg
->reglives
.usedpCodes
),pc
);
149 pcn
= findNextInstruction(pc
->next
);
152 PCI(pcn
)->label
= pBranchAppend(PCI(pcn
)->label
,PCI(pc
)->label
);
157 pcn
= findNextInstruction(pc
->next
);
160 if(PCI(pcn
)->cline
) {
161 //fprintf(stderr, "source line has been optimized completely out\n");
162 //pc->print(stderr,pc);
164 PCI(pcn
)->cline
= PCI(pc
)->cline
;
172 * Debug stuff. Comment out the instruction we're about to delete.
181 SNPRINTF(pbuff
, size
, ";%d", debug_code
);
182 size
-= strlen(pbuff
);
183 pbuff
+= strlen(pbuff
);
184 pCode2str(pbuff
, size
, pc
);
185 pCodeInsertBefore(pc
, newpCodeCharP(buff1
));
186 //fprintf(stderr,"removing instruction:\n%s\n",buff1);
193 /*-----------------------------------------------------------------*
194 * void RemoveRegsFromSet(set *regset)
196 *-----------------------------------------------------------------*/
197 static void RemoveRegsFromSet(set
*regset
)
204 regset
= regset
->next
;
206 used
= elementsInSet(reg
->reglives
.usedpCodes
);
210 //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
212 //fprintf(stderr," getting rid of reg %s\n",reg->name);
214 reg
->wasUsed
= FALSE
;
219 pc
= setFirstItem(reg
->reglives
.usedpCodes
);
221 if(reg
->type
== REG_SFR
|| reg
->type
== REG_STK
|| reg
->isPublic
|| reg
->isExtern
) {
222 //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
229 pCode
*pcn
= findNextInstruction(pc
->next
);
231 if(pcn
&& PCI(pcn
)->label
) {
232 //fprintf(stderr,"can't delete instruction with label...\n");
233 //pc->print(stderr,pc);
236 /* Move the label to the next instruction */
238 PCI(pcn
)->label
= PCI(pc
)->label
;
243 reg_info
*r
= getRegFromInstruction(pc
);
244 fprintf(stderr
, "WARNING, a skip instruction is being optimized out\n");
245 pc
->print(stderr
,pc
);
246 fprintf(stderr
,"reg %s, type =%d\n",r
->name
, r
->type
);
248 //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
249 Remove1pcode(pc
, reg
, 1);
252 deleteSetItem (&(reg->reglives.usedpCodes),pc);
255 reg
->wasUsed
= FALSE
;
256 total_registers_saved
++; // debugging stats.
264 static void pic14_ReMapLiveRanges(void)
267 if (!the_pFile
) return;
268 RegsUnMapLiveRanges();
269 for (pb
= the_pFile
->pbHead
; pb
; pb
= pb
->next
)
272 pCode
*pc
= findNextpCode(pb
->pcHead
, PC_FLOW
);
274 pc
->print( stderr
, pc
);
276 fprintf( stderr
, "unnamed pBlock\n");
278 pc
= findNextInstruction(pb
->pcHead
);
280 pc
->print( stderr
, pc
);
281 pc
= findNextInstruction(pc
->next
);;
284 pCodeRegMapLiveRanges(pb
);
288 /*-----------------------------------------------------------------*
289 * void RemoveUnusedRegisters(void)
291 *-----------------------------------------------------------------*/
292 void RemoveUnusedRegisters(void)
294 /* First, get rid of registers that are used only one time */
295 pic14_ReMapLiveRanges();
297 //RemoveRegsFromSet(dynInternalRegs);
298 RemoveRegsFromSet(dynAllocRegs
);
299 RemoveRegsFromSet(dynStackRegs
);
301 don't do DirectRegs yet - there's a problem with arrays
302 RemoveRegsFromSet(dynDirectRegs);
304 RemoveRegsFromSet(dynDirectBitRegs
);
306 if(total_registers_saved
) DFPRINTF((stderr
, " *** Saved %d registers ***\n", total_registers_saved
));
310 /*-----------------------------------------------------------------*
312 *-----------------------------------------------------------------*/
313 static void Remove2pcodes(pCode
*pcflow
, pCode
*pc1
, pCode
*pc2
, reg_info
*reg
, int can_free
)
315 static int debug_code
=99;
319 fprintf (stderr
, "%s:%d(%s): %d (reg:%s)\n", __FILE__
, __LINE__
, __FUNCTION__
, debug_code
, reg
? reg
->name
: "???");
320 printpCode (stderr
, pc1
);
321 printpCode (stderr
, pc2
);
324 //fprintf(stderr,"%s\n",__FUNCTION__);
326 Remove1pcode(pc1
, reg
, debug_code
++);
329 Remove1pcode(pc2
, reg
, debug_code
++);
330 deleteSetItem (&(PCFL(pcflow
)->registers
), reg
);
334 reg
->wasUsed
= FALSE
;
339 pCodeRegMapLiveRangesInFlow(PCFL(pcflow
));
342 /*-----------------------------------------------------------------*
344 *-----------------------------------------------------------------*/
345 static int regUsedinRange(pCode
*pc1
, pCode
*pc2
, reg_info
*reg
)
351 testreg
= getRegFromInstruction(pc1
);
352 if(testreg
&& (testreg
->rIdx
== reg
->rIdx
)) {
356 fprintf(stderr
, "warning, regUsedinRange searched through too many pcodes\n");
360 pc1
= findNextInstruction(pc1
->next
);
362 } while (pc1
&& (pc1
!= pc2
)) ;
367 static int regIsSpecial (reg_info
*reg
, int mayBeGlobal
)
371 if (reg
->type
== REG_SFR
|| reg
->type
== REG_STK
|| (!mayBeGlobal
&& (reg
->isPublic
|| reg
->isExtern
))) return 1;
376 /*-----------------------------------------------------------------*
377 * void pCodeOptime2pCodes(pCode *pc1, pCode *pc2)
379 * ADHOC pattern checking
380 * Now look for specific sequences that are easy to optimize.
381 * Many of these sequences are characteristic of the compiler
382 * (i.e. it'd probably be a waste of time to apply these adhoc
383 * checks to hand written assembly.)
386 *-----------------------------------------------------------------*/
387 static int pCodeOptime2pCodes(pCode
*pc1
, pCode
*pc2
, pCode
*pcfl_used
, reg_info
*reg
, int can_free
, int optimize_level
)
390 reg_info
*reg1
, *reg2
;
392 int t
= total_registers_saved
;
394 if (!isPCI(pc1
) || !isPCI(pc2
)) return 0;
395 if (PCI(pc1
)->pcflow
!= PCI(pc2
)->pcflow
) return 0;
397 if (pc2
->seq
< pc1
->seq
) {
403 /* disable this optimization for now -- it's buggy */
404 if (pic14_options
.disable_df
) return 0;
406 //fprintf(stderr,"pCodeOptime2pCodes\n");
407 //pc1->print(stderr,pc1);
408 //pc2->print(stderr,pc2);
410 if((PCI(pc1
)->op
== POC_CLRF
) && (PCI(pc2
)->op
== POC_MOVFW
) ){
414 * MOVWF does not touch Z
415 * MOVLW does not touch Z
423 can be replaced with (only if following instructions are not going to use W and reg is not used again later)
428 DFPRINTF((stderr
, " optimising CLRF reg ... MOVF reg,W to ... MOVLW 0\n"));
429 pct2
= findNextInstruction(pc2
->next
);
430 if (pCodeSearchCondition(pct2
, PCC_Z
, 0) == -1) {
431 /* Z is definitely overwritten before use */
432 newpc
= newpCode(POC_MOVLW
, newpCodeOpLit(0));
434 pCodeInsertAfter(pc2
, newpc
);
435 PCI(newpc
)->pcflow
= PCFL(pcfl_used
);
436 newpc
->seq
= pc2
->seq
;
438 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF reg, ..., MOVF reg,W)\n", __FILE__, __LINE__, __FUNCTION__);
439 //Remove2pcodes(pcfl_used, pc2, NULL, reg, 0);
441 //total_registers_saved++; // debugging stats.
443 } else if((PCI(pc1
)->op
== POC_CLRF
) && (PCI(pc2
)->op
== POC_IORFW
) ){
444 DFPRINTF((stderr
, " optimising CLRF/IORFW\n"));
446 pct2
= findNextInstruction(pc2
->next
);
448 /* We must ensure that Z is destroyed before being read---IORLW must be performed unless this is proven. */
449 if (pCodeSearchCondition(pct2
, PCC_Z
, 0) != -1) {
450 pct2
= newpCode(POC_IORLW
, newpCodeOpLit(0));
451 pct2
->seq
= pc2
->seq
;
452 PCI(pct2
)->pcflow
= PCFL(pcfl_used
);
453 pCodeInsertAfter(pc1
,pct2
);
455 //fprintf (stderr, "%s:%d(%s): Remove2pcodes (CLRF/IORFW)\n", __FILE__, __LINE__, __FUNCTION__);
456 Remove2pcodes(pcfl_used
, pc1
, pc2
, reg
, can_free
);
457 total_registers_saved
++; // debugging stats.
459 } else if(PCI(pc1
)->op
== POC_MOVWF
) {
460 // Optimising MOVWF reg ...
462 pct2
= findNextInstruction(pc2
->next
);
464 if(PCI(pc2
)->op
== POC_MOVFW
) {
465 // Optimising MOVWF reg ... MOVF reg,W
467 if(PCI(pct2
)->op
== POC_MOVWF
) {
476 To: ( as long as 'stuff' does not use reg2 or if following instructions do not use W or reg is not used later)
482 reg2
= getRegFromInstruction(pct2
);
483 /* Check reg2 is not used for something else before it is loaded with reg */
484 if (reg2
&& !regIsSpecial (reg2
, 1) && !regUsedinRange(pc1
,pc2
,reg2
)) {
485 pCode
*pct3
= findNextInstruction(pct2
->next
);
486 /* Check following instructions are not relying on the use of W or the Z flag condiction */
487 /* XXX: We must ensure that this value is destroyed before use---otherwise it might be used in
488 * subsequent flows (checking for < 1 is insufficient). */
489 if ((pCodeSearchCondition(pct3
,PCC_Z
,0) == -1) && (pCodeSearchCondition(pct3
,PCC_W
,0) == -1)) {
490 DFPRINTF((stderr
, " optimising MOVF reg ... MOVF reg,W MOVWF reg2 to MOVWF reg2 ...\n"));
491 pct2
->seq
= pc1
->seq
;
493 pCodeInsertBefore(pc1
,pct2
);
494 if(regUsedinRange(pct2
,0,reg
))
496 //fprintf (stderr, "%s:%d(%s): Remove2pcodes IF (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
497 Remove2pcodes(pcfl_used
, pc2
, NULL
, reg
, can_free
);
499 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVWF reg, ..., MOVW reg,W MOVWF reg2)\n", __FILE__, __LINE__, __FUNCTION__);
500 Remove2pcodes(pcfl_used
, pc1
, pc2
, reg
, can_free
);
502 total_registers_saved
++; // debugging stats.
509 pct1
= findPrevInstruction(pc1
->prev
);
510 if(pct1
&& (PCI(pct1
)->pcflow
== PCI(pc1
)->pcflow
)) {
512 if ( (PCI(pct1
)->op
== POC_MOVFW
) &&
513 (PCI(pc2
)->op
== POC_MOVFW
)) {
515 reg1
= getRegFromInstruction(pct1
);
516 if(reg1
&& !regIsSpecial (reg1
, 0) && !regUsedinRange(pc1
,pc2
,reg1
)) {
517 DFPRINTF((stderr
, " optimising MOVF reg1,W MOVWF reg ... MOVF reg,W\n"));
533 Or, if we're not deleting the register then the "To" is:
540 pct2
= newpCode(PCI(pc2
)->op
, PCI(pct1
)->pcop
);
541 pCodeInsertAfter(pc2
, pct2
);
542 PCI(pct2
)->pcflow
= PCFL(pcfl_used
);
543 pct2
->seq
= pc2
->seq
;
546 //fprintf (stderr, "%s:%d(%s): Remove2pcodes CANFREE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
547 Remove2pcodes(pcfl_used
, pc1
, pc2
, reg
, can_free
);
549 /* If we're not freeing the register then that means (probably)
550 * the register is needed somewhere else.*/
552 pCodeInsertAfter(pct2
, pc1
);
554 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ELSE (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
555 Remove2pcodes(pcfl_used
, pc2
, NULL
, reg
, can_free
);
558 //fprintf (stderr, "%s:%d(%s): Remove2pcodes ALWAYS (MOVF reg1,W; MOVWF reg2; MOVF reg2,W)\n", __FILE__, __LINE__, __FUNCTION__);
559 Remove2pcodes(pcfl_used
, pct1
, NULL
, reg1
, 0);
560 total_registers_saved
++; // debugging stats.
567 return (total_registers_saved
!= t
);
570 /*-----------------------------------------------------------------*
571 * void pCodeRegOptimeRegUsage(pBlock *pb)
572 *-----------------------------------------------------------------*/
573 static void OptimizeRegUsage(set
*fregs
, int optimize_multi_uses
, int optimize_level
)
577 pCode
*pc1
=NULL
, *pc2
=NULL
;
581 pCode
*pcfl_used
, *pcfl_assigned
;
583 /* Step through the set by directly accessing the 'next' pointer.
584 * We could also step through by using the set API, but the
585 * the (debug) calls to print instructions affect the state
586 * of the set pointers */
591 if (strcmp(reg->name,"_SubState")==0)
592 fprintf(stderr,"Reg: %s\n",reg->name);
595 /* Catch inconsistently set-up live ranges
596 * (see tracker items #1469504 + #1474602)
597 * FIXME: Actually we should rather fix the
598 * computation of the liveranges instead...
600 if (!reg
|| !reg
->reglives
.usedpFlows
601 || !reg
->reglives
.assignedpFlows
)
603 //fprintf( stderr, "skipping reg w/o liveranges: %s\n", reg ? reg->name : "(unknown)");
607 if(reg
->type
== REG_SFR
|| reg
->type
== REG_STK
|| reg
->isPublic
|| reg
->isExtern
|| reg
->isFixed
) {
608 //fprintf(stderr,"skipping SFR: %s\n",reg->name);
612 pcfl_used
= setFirstItem(reg
->reglives
.usedpFlows
);
613 pcfl_assigned
= setFirstItem(reg
->reglives
.assignedpFlows
);
615 used
= elementsInSet(reg
->reglives
.usedpCodes
);
618 In this section, all registers that are used in only in two
619 instructions are examined. If possible, they're optimized out.
623 fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
626 reg->rIdx, reg->type, used);
628 pc1
= setFirstItem(reg
->reglives
.usedpCodes
);
629 pc2
= setNextItem(reg
->reglives
.usedpCodes
);
631 if(pcfl_used
&& pcfl_assigned
) {
633 expected case - the register has been assigned a value and is
637 //fprintf(stderr," used only twice\n");
638 if(pcfl_used
->seq
== pcfl_assigned
->seq
) {
640 //fprintf(stderr, " and used in same flow\n");
642 pCodeOptime2pCodes(pc1
, pc2
, pcfl_used
, reg
, 1,optimize_level
);
645 // fprintf(stderr, " and used in different flows\n");
649 } else if(pcfl_used
) {
651 /* register has been used twice without ever being assigned */
652 fprintf(stderr
,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__
,reg
->name
);
655 //fprintf(stderr,"WARNING %s.1: reg %s assigned without being used\n",__FUNCTION__,reg->name);
656 Remove2pcodes(pcfl_assigned
, pc1
, pc2
, reg
, 1);
657 total_registers_saved
++; // debugging stats.
661 /* register has been used either once, or more than twice */
663 if(used
&& !pcfl_used
&& pcfl_assigned
) {
666 //fprintf(stderr,"WARNING %s.2: reg %s assigned without being used\n",__FUNCTION__,reg->name);
668 pc
= setFirstItem(reg
->reglives
.usedpCodes
);
671 pcfl_assigned
= PCODE(PCI(pc
)->pcflow
);
672 Remove1pcode(pc
, reg
,2);
674 deleteSetItem (&(PCFL(pcfl_assigned
)->registers
), reg
);
676 deleteSetItem (&(reg->reglives.usedpCodes),pc);
679 pc
= setNextItem(reg
->reglives
.usedpCodes
);
684 reg
->wasUsed
= FALSE
;
686 total_registers_saved
++; // debugging stats.
687 } else if( (used
> 2) && optimize_multi_uses
) {
693 pCodeFlow
*pcfl1
=NULL
, *pcfl2
=NULL
;
695 /* examine the number of times this register is used */
698 rset1
= reg
->reglives
.usedpCodes
;
699 while(rset1
&& searching
) {
704 if(pc1
&& isPCI(pc1
) && ( (pcfl1
= PCI(pc1
)->pcflow
) != NULL
) ) {
709 if(pc2
&& isPCI(pc2
) && ( (pcfl2
= PCI(pc2
)->pcflow
) != NULL
) ) {
712 if(pCodeOptime2pCodes(pc1
, pc2
, pcfl_used
, reg
, 0,optimize_level
))
717 //rset2 = rset2->next;
728 /*-----------------------------------------------------------------*
729 * void pCodeRegOptimeRegUsage(pBlock *pb)
730 *-----------------------------------------------------------------*/
731 void pCodeRegOptimizeRegUsage(int level
)
736 int t
= total_registers_saved
;
739 /* This is currently broken (need rewrite to correctly
740 * handle arbitrary pCodeOps instead of registers only). */
741 if (!pic14_options
.disable_df
)
745 if(!register_optimization
)
751 saved
= total_registers_saved
;
753 /* Identify registers used in one flow sequence */
754 OptimizeRegUsage(dynAllocRegs
,level
, (OPT_PASSES
-passes
));
755 OptimizeRegUsage(dynStackRegs
,level
, (OPT_PASSES
-passes
));
756 OptimizeRegUsage(dynDirectRegs
,0, (OPT_PASSES
-passes
));
758 if(total_registers_saved
!= saved
)
759 DFPRINTF((stderr
, " *** pass %d, Saved %d registers, total saved %d ***\n",
760 (1+OPT_PASSES
-passes
),total_registers_saved
-saved
,total_registers_saved
));
764 } while( passes
&& ((total_registers_saved
!= saved
) || (passes
==OPT_PASSES
-1)) );
766 if(total_registers_saved
== t
)
767 DFPRINTF((stderr
, "No registers saved on this pass\n"));
771 /*-----------------------------------------------------------------*
772 * void RegsUnMapLiveRanges(set *regset)
774 *-----------------------------------------------------------------*/
775 static void RegsSetUnMapLiveRanges(set
*regset
)
781 regset
= regset
->next
;
784 deleteSet(®
->reglives
.usedpCodes
);
785 deleteSet(®
->reglives
.usedpFlows
);
786 deleteSet(®
->reglives
.assignedpFlows
);
792 void RegsUnMapLiveRanges(void)
795 RegsSetUnMapLiveRanges(dynAllocRegs
);
796 RegsSetUnMapLiveRanges(dynStackRegs
);
797 RegsSetUnMapLiveRanges(dynDirectRegs
);
798 RegsSetUnMapLiveRanges(dynProcessorRegs
);
799 RegsSetUnMapLiveRanges(dynDirectBitRegs
);
800 RegsSetUnMapLiveRanges(dynInternalRegs
);