/*-------------------------------------------------------------------------
- pcoderegs.c - post code generation register optimizations
+ pcoderegs.c - post code generation register optimizations
Written By - Scott Dattalo scott@dattalo.com
Ported To PIC16 By - m.dubuc@rogers.com
#include "pcoderegs.h"
#include "pcodeflow.h"
+
+#define DEBUG_REMOVE1PCODE 0
+#define HAVE_DBGREGUSAGE 0
+
+
extern void pic16_pCodeInsertAfter(pCode *pc1, pCode *pc2);
extern pCode * pic16_findPrevInstruction(pCode *pci);
extern pBranch * pic16_pBranchAppend(pBranch *h, pBranch *n);
/*-----------------------------------------------------------------*
*
*-----------------------------------------------------------------*/
+
+#if HAVE_DBGREGUSAGE
static void dbg_regusage(set *fregs)
{
regs *reg;
/*-----------------------------------------------------------------*
*
*-----------------------------------------------------------------*/
-static void dbg_dumpregusage(void)
+
+//static
+void dbg_dumpregusage(void)
{
fprintf(stderr,"*** Register Usage ***\n");
dbg_regusage(pic16_dynProcessorRegs);
}
-
+#endif
/*-----------------------------------------------------------------*
* void pCodeRegMapLiveRangesInFlow(pCodeFlow *pcfl)
reg = pic16_getRegFromInstruction(pc);
- if(reg) {
-/*
+ if(reg && (reg->type != REG_TMP)) {
+
+#if 0
+ fprintf(stderr, "reg= %p\n", reg);
fprintf(stderr, "flow seq %d, inst seq %d %s ",PCODE(pcfl)->seq,pc->seq,reg->name);
- fprintf(stderr, "addr = 0x%03x, type = %d rIdx=0x%03x\n",
- reg->address,reg->type,reg->rIdx);
-*/
+ fprintf(stderr, "addr = 0x%03x, type = %d rIdx=0x%03x ",
+ reg->address,reg->type,reg->rIdx);
+ fprintf(stderr, "command = %s\n", PCI(pc)->mnemonic);
+
+#endif
+// fprintf(stderr, "%s:%d: trying to get first operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
addSetIfnotP(& (PCFL(pcfl)->registers), reg);
if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
if(PCC_REGISTER & PCI(pc)->outCond)
addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
- addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+ addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+
+// reg->wasUsed=1;
+
+#if 1
+ /* check to see if this pCode has 2 memory operands,
+ and set up the second operand too */
+ if(PCI(pc)->is2MemOp) {
+ reg = pic16_getRegFromInstruction2(pc);
+ if(reg) {
+// fprintf(stderr, "%s:%d: trying to get second operand from pCode reg= %s\n", __FILE__, __LINE__, reg->name);
+ addSetIfnotP(& (PCFL(pcfl)->registers), reg);
+
+ if((PCC_REGISTER | PCC_LITERAL) & PCI(pc)->inCond)
+ addSetIfnotP(& (reg->reglives.usedpFlows), pcfl);
+
+ if((PCC_REGISTER | PCC_REGISTER2) & PCI(pc)->outCond)
+ addSetIfnotP(& (reg->reglives.assignedpFlows), pcfl);
+
+ addSetIfnotP(& (reg->reglives.usedpCodes), pc);
+
+// reg->wasUsed=1;
+ }
+ }
+#endif
+
}
}
#endif
-// dbg_dumpregusage();
+#if HAVE_DBGREGUSAGE
+ dbg_dumpregusage();
+#endif
}
return;
deleteSetItem (&(reg->reglives.usedpCodes),pc);
-/*
+
+#if DEBUG_REMOVE1PCODE
fprintf(stderr,"removing instruction:\n");
pc->print(stderr,pc);
-*/
+#endif
+
if(PCI(pc)->label) {
pcn = pic16_findNextInstruction(pc->next);
if(pcn) {
if(PCI(pcn)->cline) {
- //fprintf(stderr, "source line has been optimized completely out\n");
- //pc->print(stderr,pc);
+
+#if DEBUG_REMOVE1PCODE
+ fprintf(stderr, "source line has been optimized completely out\n");
+ pc->print(stderr,pc);
+#endif
+
} else {
PCI(pcn)->cline = PCI(pc)->cline;
}
if(used <= 1) {
- //fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
+// fprintf(stderr," reg %s isfree=%d, wasused=%d\n",reg->name,reg->isFree,reg->wasUsed);
+
if(used == 0) {
- //fprintf(stderr," getting rid of reg %s\n",reg->name);
+
+// fprintf(stderr,"%s:%d: getting rid of reg %s\n",__FILE__, __LINE__, reg->name);
+
reg->isFree = 1;
reg->wasUsed = 0;
} else {
pc = setFirstItem(reg->reglives.usedpCodes);
if(reg->type == REG_SFR) {
- //fprintf(stderr, "not removing SFR reg %s even though used only once\n",reg->name);
+ fprintf(stderr, "not removing SFR reg %s even though used only once\n", reg->name);
continue;
}
-
if(isPCI(pc)) {
if(PCI(pc)->label) {
pCode *pcn = pic16_findNextInstruction(pc->next);
pc->print(stderr,pc);
fprintf(stderr,"reg %s, type =%d\n",r->name, r->type);
}
- //fprintf(stderr," removing reg %s because it is used only once\n",reg->name);
+
Remove1pcode(pc, reg);
/*
pic16_unlinkpCode(pc);
*/
RemoveRegsFromSet(pic16_dynDirectBitRegs);
- if(total_registers_saved) fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved);
+ if(total_registers_saved && pic16_pcode_verbose)
+ fprintf(stderr, " *** Saved %d registers ***\n", total_registers_saved);
+}
+
+static int insideLRBlock(pCode *pc)
+{
+ pCode *pc1;
+ int t1=-1, t2=-1;
+
+ pc1 = pc->prev;
+ while(pc1) {
+ if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
+ t1 = PCOLR (PCINF (pc1)->oper1)->type;
+ break;
+ }
+ pc1 = pc1->prev;
+ }
+
+ pc1 = pc->next;
+ while(pc1) {
+ if(isPCINFO(pc1) && (PCINF(pc1)->type == INF_LOCALREGS)) {
+ t2 = PCOLR (PCINF (pc1)->oper1)->type;
+ break;
+ }
+ pc1 = pc1->next;
+ }
+
+ if((t1 == LR_ENTRY_BEGIN && t2 == LR_ENTRY_END)
+ || (t1 == LR_EXIT_BEGIN && t2 == LR_EXIT_END))
+ return 1;
+
+ return 0;
}
+
+static void RemoveRegFromLRBlock(regs *reg)
+{
+ if(elementsInSet(reg->reglives.usedpCodes) == 2) {
+ pCode *pc1;
+
+ /* only continue if there are just 2 uses of the register,
+ * in in the local *entry* block and one in the local *exit* block */
+
+ /* search for entry block */
+ pc1 = indexSet(reg->reglives.usedpCodes, 1);
+
+ if(insideLRBlock( pc1 )) {
+ fprintf(stderr, "usedpCodes[0] inside LR block\n");
+ deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
+ Remove1pcode(pc1, reg);
+ }
+
+ pc1 = indexSet(reg->reglives.usedpCodes, 0);
+ if(insideLRBlock( pc1 )) {
+ fprintf(stderr, "usedpCodes[1] inside LR block\n");
+ deleteSetItem(&pc1->pb->tregisters, PCOR(PCI(pc1)->pcop)->r);
+ Remove1pcode(pc1, reg);
+ }
+
+ /* remove r0x00 */
+ reg->isFree = 1;
+ reg->wasUsed = 0;
+ }
+}
+
+
/*-----------------------------------------------------------------*
*
if(!reg)
return;
+#if 0
+ fprintf(stderr,"removing 2 instructions:\n");
+ pc1->print(stderr,pc1);
+ pc2->print(stderr,pc2);
+#endif
+
if(pc1)
Remove1pcode(pc1, reg);
}
pCodeRegMapLiveRangesInFlow(PCFL(pcflow));
+
+#if 1
+// fprintf(stderr, "register %s is used in %d pCodes, assigned in %d pCodes\n", reg->name,
+// elementsInSet(reg->reglives.usedpCodes),
+// elementsInSet(reg->reglives.assignedpFlows));
+
+ RemoveRegFromLRBlock(reg);
+#endif
+
}
/*-----------------------------------------------------------------*
return 1;
}
+ if(PCI(pc1)->is2MemOp) {
+ testreg = pic16_getRegFromInstruction2(pc1);
+ if(testreg && (testreg->rIdx == reg->rIdx)) {
+ return 1;
+ }
+ }
+
pc1 = pic16_findNextInstruction(pc1->next);
} while (pc1 && (pc1 != pc2) && (i++ < 100)) ;
int t = total_registers_saved;
+ if(reg->type == REG_SFR)return 0;
+
if(pc2->seq < pc1->seq) {
pct1 = pc2;
pc2 = pc1;
PCI(newpc)->pcflow = PCFL(pcfl_used);
newpc->seq = pc2->seq;
- Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+ /* take care if register is used after pc2, if yes, then don't delete
+ * clrf reg, because, reg should be initialized with zero */
+ {
+ pCode *spc;
+ int maxSeq=0;
+
+ for(spc=setFirstItem(reg->reglives.usedpCodes);spc;spc=setNextItem(reg->reglives.usedpCodes)) {
+ if(maxSeq < spc->seq)maxSeq = spc->seq;
+ }
+
+// fprintf(stderr, "pc1->seq = %d\tpc2->seq = %d\tspc->seq = %d\n", pc1->seq, pc2->seq, maxSeq);
+
+ if(maxSeq > pc2->seq) {
+ /* this means that a pCode uses register after pc2, then
+ * we can't delete pc1 pCode */
+ Remove2pcodes(pcfl_used, NULL, pc2, reg, can_free);
+ } else {
+ /* we can remove both pCodes */
+ Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
+ }
+ }
total_registers_saved++; // debugging stats.
} else if((PCI(pc1)->op == POC_CLRF) && (PCI(pc2)->op == POC_IORFW) ){
} else if(PCI(pc1)->op == POC_MOVWF) {
+ reg1 = pic16_getRegFromInstruction(pc1);
+
+ if(reg1->type == REG_SFR)return (total_registers_saved != t);
+
pct2 = pic16_findNextInstruction(pc2->next);
if(PCI(pc2)->op == POC_MOVFW) {
- /*
+
+#if 0
fprintf(stderr, " MOVWF/MOVFW. instruction after MOVFW is:\n");
pct2->print(stderr,pct2);
- */
+#endif
if(PCI(pct2)->op == POC_MOVWF) {
/*
*/
reg2 = pic16_getRegFromInstruction(pct2);
- //if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) {
- if(reg2 && !regUsedinRange(pc1,pc2,reg2)) {
+ if(reg2 && !regUsedinRange(pc1,pc2,reg2) && (reg2->type != REG_SFR)) {
+// if(reg2 && !regUsedinRange(pc1,pc2,reg2))
if(pic16_pCodeSearchCondition(pct2, PCC_Z) < 1) {
pCode *pct3 = pic16_findNextInstruction(pct2->next);
if(usesW(pct3))
; // Remove2pcodes(pcfl_used, pc1, NULL, reg, can_free);
- else
+ else {
Remove2pcodes(pcfl_used, pc1, pc2, reg, can_free);
-
- total_registers_saved++; // debugging stats.
- return 1;
- } else {
- //fprintf(stderr,"didn't optimize because Z bit is used\n");
- }
+ total_registers_saved++; // debugging stats.
+ return 1;
+ }
+ } else {
+// fprintf(stderr,"didn't optimize because Z bit is used\n");
+ }
}
-/*
+#if 0
fprintf(stderr, " couldn't optimize\n");
if(reg2)
- fprintf(stderr, " %s is used in range\n",reg2->name);
+ fprintf(stderr, " %s is used in range\n", reg2->name);
else
fprintf(stderr, " reg2 is NULL\n");
-*/
+#endif
}
}
reg1 = pic16_getRegFromInstruction(pct1);
if(reg1 && !regUsedinRange(pc1,pc2,reg1)) {
- /*
+
+#if 0
fprintf(stderr, " MOVF/MOVFW. \n");
fprintf(stderr, " ...optimizing\n");
- */
+#endif
/*
Change:
}
} else if ( (PCI(pct1)->op == POC_MOVWF) &&
(PCI(pc2)->op == POC_MOVFW)) {
- //fprintf(stderr,"movwf MOVWF/MOVFW\n");
+
+// fprintf(stderr,"movwf MOVWF/MOVFW\n");
+
if(optimize_level > 1 && can_free) {
pct2 = pic16_newpCode(POC_MOVFW, PCI(pc1)->pcop);
pic16_pCodeInsertAfter(pc2, pct2);
reg = fregs->item;
fregs = fregs->next;
- if(reg->type == REG_SFR) {
- //fprintf(stderr,"skipping SFR: %s\n",reg->name);
- continue;
- }
+ if(reg->type == REG_SFR) {
+// fprintf(stderr,"skipping SFR: %s\n",reg->name);
+ continue;
+ }
pcfl_used = setFirstItem(reg->reglives.usedpFlows);
pcfl_assigned = setFirstItem(reg->reglives.assignedpFlows);
used = elementsInSet(reg->reglives.usedpCodes);
+// fprintf(stderr, "%s:%d register %s used %d times in pCode\n", __FILE__, __LINE__, reg->name, used);
if(used == 2) {
/*
* instructions are examined. If possible, they're optimized out.
*/
-/*
+#if 0
fprintf (stderr, "OptimizeRegUsage: %s addr=0x%03x rIdx=0x%03x type=%d used=%d\n",
reg->name,
reg->address,
reg->rIdx, reg->type, used);
-*/
+#endif
+
pc1 = setFirstItem(reg->reglives.usedpCodes);
pc2 = setNextItem(reg->reglives.usedpCodes);
*/
//fprintf(stderr," used only twice\n");
- if(pcfl_used->seq == pcfl_assigned->seq) {
+ if(pcfl_used->seq == pcfl_assigned->seq && !(setNextItem(reg->reglives.usedpFlows)) && !(setNextItem(reg->reglives.assignedpFlows))) {
//fprintf(stderr, " and used in same flow\n");
//fprintf(stderr,"WARNING %s: reg %s used without being assigned\n",__FUNCTION__,reg->name);
} else {
- //fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
+// fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
Remove2pcodes(pcfl_assigned, pc1, pc2, reg, 1);
total_registers_saved++; // debugging stats.
}
if(used && !pcfl_used && pcfl_assigned) {
pCode *pc;
- //fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
+ fprintf(stderr,"WARNING %s: reg %s assigned without being used\n",__FUNCTION__,reg->name);
pc = setFirstItem(reg->reglives.usedpCodes);
while(pc) {
int saved = 0;
int t = total_registers_saved;
- if(!register_optimization)
- return;
-#define OPT_PASSES 4
- passes = OPT_PASSES;
+ if(getenv("NO_REG_OPT"))
+ return;
- do {
- saved = total_registers_saved;
+ if(!register_optimization)
+ return;
+
+#define OPT_PASSES 8
+ passes = OPT_PASSES;
- /* Identify registers used in one flow sequence */
- OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes));
- OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes));
- OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes));
+ do {
+ saved = total_registers_saved;
- if(total_registers_saved != saved)
- fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n",
- (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved);
+ /* Identify registers used in one flow sequence */
+ OptimizeRegUsage(pic16_dynAllocRegs,level, (OPT_PASSES-passes));
+ OptimizeRegUsage(pic16_dynStackRegs,level, (OPT_PASSES-passes));
+ OptimizeRegUsage(pic16_dynDirectRegs,0, (OPT_PASSES-passes));
+
+ if((total_registers_saved != saved)
+ && (pic16_pcode_verbose))
+ fprintf(stderr, " *** pass %d, Saved %d registers, total saved %d ***\n",
+ (1+OPT_PASSES-passes),total_registers_saved-saved,total_registers_saved);
- passes--;
+ passes--;
- } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
+ } while( passes && ((total_registers_saved != saved) || (passes==OPT_PASSES-1)) );
- if(total_registers_saved == t)
- fprintf(stderr, "No registers saved on this pass\n");
+ if(total_registers_saved == t)
+ if(pic16_debug_verbose)
+ fprintf(stderr, "No registers saved on this pass\n");
-/*
- fprintf(stderr,"dynamically allocated regs:\n");
- dbg_regusage(pic16_dynAllocRegs);
- fprintf(stderr,"stack regs:\n");
- dbg_regusage(pic16_dynStackRegs);
- fprintf(stderr,"direct regs:\n");
- dbg_regusage(pic16_dynDirectRegs);
-*/
+#if 0
+ fprintf(stderr,"dynamically allocated regs:\n");
+ dbg_regusage(pic16_dynAllocRegs);
+ fprintf(stderr,"stack regs:\n");
+ dbg_regusage(pic16_dynStackRegs);
+ fprintf(stderr,"direct regs:\n");
+ dbg_regusage(pic16_dynDirectRegs);
+#endif
}
while(regset) {
reg = regset->item;
regset = regset->next;
-
deleteSet(®->reglives.usedpCodes);
deleteSet(®->reglives.usedpFlows);
void pic16_RegsUnMapLiveRanges(void)
{
-
RegsSetUnMapLiveRanges(pic16_dynAllocRegs);
RegsSetUnMapLiveRanges(pic16_dynStackRegs);
RegsSetUnMapLiveRanges(pic16_dynDirectRegs);
RegsSetUnMapLiveRanges(pic16_dynProcessorRegs);
RegsSetUnMapLiveRanges(pic16_dynDirectBitRegs);
RegsSetUnMapLiveRanges(pic16_dynInternalRegs);
-
}