X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Fpic%2Fpcode.c;h=cfbd14df942efa7e3bc4bdf1ed9c51625ae10632;hb=5066bebe95a5c1d13f10d7059d4b2541447d680b;hp=45aef3532bd98e9d06ebf501e3827f8c856e2fa9;hpb=f970f0e6603401042048d98927927133a0f9f255;p=fw%2Fsdcc diff --git a/src/pic/pcode.c b/src/pic/pcode.c index 45aef353..cfbd14df 100644 --- a/src/pic/pcode.c +++ b/src/pic/pcode.c @@ -33,12 +33,6 @@ pCode *findFunction(char *fname); static void FixRegisterBanking(pBlock *pb); -#if defined(__BORLANDC__) || defined(_MSC_VER) -#define STRCASECMP stricmp -#else -#define STRCASECMP strcasecmp -#endif - /****************************************************************/ /****************************************************************/ @@ -2556,7 +2550,7 @@ void pCodeReadCodeTable(void) void addpCode2pBlock(pBlock *pb, pCode *pc) { - if(!pc) + if(!pb || !pc) return; if(!pb->pcHead) { @@ -3033,6 +3027,9 @@ char *get_op(pCodeOp *pcop,char *buffer, size_t size) case 1: SAFE_snprintf(&s,&size,"high (%s+%d)",pcop->name, PCOI(pcop)->index); break; + case 2: + SAFE_snprintf(&s,&size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA); + break; default: fprintf (stderr, "PO_IMMEDIATE/_const/offset=%d\n", PCOI(pcop)->offset); assert ( !"offset too large" ); @@ -3056,6 +3053,9 @@ char *get_op(pCodeOp *pcop,char *buffer, size_t size) case 1: SAFE_snprintf(&s,&size,"high (%s + %d)",pcop->name, PCOI(pcop)->index); break; + case 2: + SAFE_snprintf(&s,&size,"0x%02x",PCOI(pcop)->_const ? GPTRTAG_CODE : GPTRTAG_DATA); + break; default: fprintf (stderr, "PO_IMMEDIATE/mutable/offset=%d\n", PCOI(pcop)->offset); assert ( !"offset too large" ); @@ -4315,6 +4315,8 @@ void LinkFlow(pBlock *pb) //fprintf(stderr,"linkflow \n"); + if (!pb) return; + for( pcflow = findNextpCode(pb->pcHead, PC_FLOW); pcflow != NULL; pcflow = findNextpCode(pcflow->next, PC_FLOW) ) { @@ -4621,21 +4623,63 @@ static void insertBankSel(pCodeInstruction *pci, const char *name) insertPCodeInstruction(pci, PCI(new_pc)); } +/* + * isValidIdChar - check if c may be present in an identifier + */ +static int isValidIdChar (char c) +{ + if (c >= 'a' && c <= 'z') return 1; + if (c >= 'A' && c <= 'Z') return 1; + if (c >= '0' && c <= '9') return 1; + if (c == '_') return 1; + return 0; +} + +/* + * bankcompare - check if two operand string refer to the same register + * This functions handles NAME and (NAME + x) in both operands. + * Returns 1 on same register, 0 on different (or unknown) registers. + */ +static int bankCompare(const char *op1, const char *op2) +{ + int i; + + if (!op1 && !op2) return 0; // both unknown, might be different though! + if (!op1 || !op2) return 0; + + // find start of operand name + while (op1[0] == '(' || op1[0] == ' ') op1++; + while (op2[0] == '(' || op2[0] == ' ') op2++; + + // compare till first non-identifier character + for (i = 0; (op1[i] == op2[i]) && isValidIdChar(op1[i]); i++); + if (!isValidIdChar(op1[i]) && !isValidIdChar(op2[i])) return 1; + + // play safe---assume different operands + return 0; +} + /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ -static int sameBank(regs *reg, const char *new_bank, const char *cur_bank) +extern int pic14_operandsAllocatedInSameBank(const char *str1, const char *str2); +static int sameBank(regs *reg, regs *previous_reg, const char *new_bank, const char *cur_bank, unsigned max_mask) { if (!cur_bank) return 0; - // identify '(regname + X)' and 'regname' - if (reg && reg->name && reg->name[0] == '(' && !strncmp(®->name[1], cur_bank, strlen(cur_bank))) return 1; - if (new_bank && new_bank[0] == '(' && !strncmp(&new_bank[1], cur_bank, strlen(cur_bank))) return 1; - if (cur_bank[0] == '(' && reg && reg->name && !strncmp(reg->name, &cur_bank[1], strlen(reg->name))) return 1; - if (cur_bank[0] == '(' && new_bank && !strncmp(new_bank, &cur_bank[1], strlen(new_bank))) return 1; - - // XXX: identify '(regname + X)' and '(regname + Y)' - - return ((reg && reg->name && !strcmp(reg->name, cur_bank)) || (new_bank && !strcmp(new_bank, cur_bank))); + if (previous_reg && reg && previous_reg->isFixed && reg->isFixed && ((previous_reg->address & max_mask) == (reg->address & max_mask))) // only if exists + return 1; // if we have address info, we use it for banksel optimization + + // regard '(regname + X)' and '(regname + Y)' as equal + if (reg && reg->name && bankCompare(reg->name, cur_bank)) return 1; + if (new_bank && bankCompare(new_bank, cur_bank)) return 1; + + // check allocation policy from glue.c + if (reg && reg->name && pic14_operandsAllocatedInSameBank(reg->name, cur_bank)) return 1; + if (new_bank && pic14_operandsAllocatedInSameBank(new_bank, cur_bank)) return 1; + + // seems to be a different operand--might be a different bank + //printf ("BANKSEL from %s to %s/%s\n", cur_bank, reg->name, new_bank); + return 0; } /*-----------------------------------------------------------------*/ @@ -4645,6 +4689,7 @@ void FixRegisterBanking(pBlock *pb) pCode *pc; pCodeInstruction *pci; regs *reg; + regs *previous_reg; // contains the previous variable access info const char *cur_bank, *new_bank; unsigned cur_mask, new_mask, max_mask; int allRAMmshared; @@ -4654,6 +4699,7 @@ void FixRegisterBanking(pBlock *pb) max_mask = pic14_getPIC()->bankMask; cur_mask = max_mask; cur_bank = NULL; + previous_reg = NULL; allRAMmshared = pic14_allRAMShared(); @@ -4662,6 +4708,7 @@ void FixRegisterBanking(pBlock *pb) // this one has a label---might check bank at all jumps here... if (isPCI(pc) && (PCI(pc)->label || PCI(pc)->op == POC_CALL)) { addpCodeComment(pc->prev, "BANKOPT3 drop assumptions: PCI with label or call found"); + previous_reg = NULL; cur_bank = NULL; // start new flow cur_mask = max_mask; } @@ -4669,6 +4716,7 @@ void FixRegisterBanking(pBlock *pb) // this one is/might be a label or BANKSEL---assume nothing if (isPCL(pc) || isPCASMDIR(pc)) { addpCodeComment(pc->prev, "BANKOPT4 drop assumptions: label or ASMDIR found"); + previous_reg = NULL; cur_bank = NULL; cur_mask = max_mask; } @@ -4692,6 +4740,8 @@ void FixRegisterBanking(pBlock *pb) new_mask = 0; // unknown, assume worst case } else { assert(!"Could not get register from instruction."); + new_bank = "UNKNOWN"; + new_mask = 0; // unknown, assume worst case } // optimizations... @@ -4716,7 +4766,7 @@ void FixRegisterBanking(pBlock *pb) // is in (as well as the previous registers) cur_mask &= new_mask; - if (sameBank(reg, new_bank, cur_bank)) { + if (sameBank(reg, previous_reg, new_bank, cur_bank, max_mask)) { // no BANKSEL required addpCodeComment(pc->prev, "BANKOPT2 BANKSEL dropped; %s present in same bank as %s", new_bank, cur_bank); continue; @@ -4725,6 +4775,7 @@ void FixRegisterBanking(pBlock *pb) cur_mask = new_mask; cur_bank = new_bank; + previous_reg = reg; insertBankSel(pci, cur_bank); } // if } // if @@ -4838,7 +4889,7 @@ void pBlockRemoveUnusedLabels(pBlock *pb) { pCode *pc; pCodeLabel *pcl; - if(!pb) + if(!pb || !pb->pcHead) return; for(pc = pb->pcHead; (pc=findNextInstruction(pc->next)) != NULL; ) { @@ -5245,7 +5296,6 @@ DEFSETFUNC (resetrIdx) /*-----------------------------------------------------------------*/ /* InitRegReuse - Initialises variables for code analyzer */ /*-----------------------------------------------------------------*/ - void InitReuseReg(void) { /* Find end of statically allocated variables for start idx */ @@ -5264,56 +5314,77 @@ void InitReuseReg(void) /*-----------------------------------------------------------------*/ /*-----------------------------------------------------------------*/ -static unsigned register_reassign(pBlock *pb, unsigned idx) +static unsigned register_reassign(pBlock *pb, unsigned idx, unsigned level) { - pCode *pc; - - /* check recursion */ - pc = setFirstItem(pb->function_entries); - if(!pc) - return idx; + pCode *pc; - if (pb->visited) { - /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */ - return idx; - } - - pb->visited = 1; - - DFPRINTF((stderr," reassigning registers for function \"%s\"\n",PCF(pc)->fname)); - - if (pb->tregisters) { - regs *r; - for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters)) { - if (r->type == REG_GPR) { - if (!r->isFixed) { - if (r->rIdx < (int)idx) { - char s[20]; - r->rIdx = idx++; - if (peakIdx < idx) peakIdx = idx; - sprintf(s,"r0x%02X", r->rIdx); - DFPRINTF((stderr," reassigning register \"%s\" to \"%s\"\n",r->name,s)); - free(r->name); - r->name = Safe_strdup(s); - } - } - } + /* check recursion */ + pc = setFirstItem(pb->function_entries); + if(!pc) + return idx; + + if (pb->visited) { + /* TODO: Recursion detection missing, should emit a warning as recursive code will fail. */ + return idx; + } + + pb->visited = 1; + + DFPRINTF((stderr," (%u) reassigning registers for function \"%s\"\n",level,PCF(pc)->fname)); + + if (pb->tregisters) { + regs *r; + for (r = setFirstItem(pb->tregisters); r; r = setNextItem(pb->tregisters)) { + if (r->type == REG_GPR) { + if (!r->isFixed) { + if (r->rIdx < (int)idx) { + char s[20]; + set *regset; + // make sure, idx is not yet used in this routine... + do { + regset = pb->tregisters; + // do not touch s->curr ==> outer loop! + while (regset && ((regs *)regset->item)->rIdx != idx) { + regset = regset->next; + } + if (regset) idx++; + } while (regset); + r->rIdx = idx++; + if (peakIdx < idx) peakIdx = idx; + sprintf(s,"r0x%02X", r->rIdx); + DFPRINTF((stderr," (%u) reassigning register %p \"%s\" to \"%s\"\n",level,r,r->name,s)); + free(r->name); + r->name = Safe_strdup(s); + } } + } } - for(pc = setFirstItem(pb->function_calls); pc; pc = setNextItem(pb->function_calls)) { - - if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) { - char *dest = get_op_from_instruction(PCI(pc)); - - pCode *pcn = findFunction(dest); - if(pcn) { - register_reassign(pcn->pb,idx); - } - } - + } + for(pc = setFirstItem(pb->function_calls); pc; pc = setNextItem(pb->function_calls)) { + + if(pc->type == PC_OPCODE && PCI(pc)->op == POC_CALL) { + char *dest = get_op_from_instruction(PCI(pc)); + + pCode *pcn = findFunction(dest); + if(pcn) { + /* This index increment from subroutines is not required, as all subroutines + * may share registers NOT used by this one (< idx). + * BUT if called functions A and B share a register, which gets assigned + * rIdx = idx + 4 while analyzing A, we must not assign idx + 4 again while + * analyzing B! + * As an alternative to this "solution" we could check above whether an + * to-be-assigned rIdx is already present in the register set of the + * current function. This would increase the reused registers and make this + * `idx =' irrelevant. + * UPDATE: Implemented above; not fast, but works. + * (Problem shown with regression test src/regression/sub2.c) + */ + /*idx = */register_reassign(pcn->pb,idx,level+1); + } } - - return idx; + } + + return idx; } /*------------------------------------------------------------------*/ @@ -5344,8 +5415,8 @@ void ReuseReg(void) InitReuseReg(); for(pb = the_pFile->pbHead; pb; pb = pb->next) { /* Non static functions can be called from other modules so their registers must reassign */ - if (pb->function_entries&&(PCF(setFirstItem(pb->function_entries))->isPublic||!pb->visited)) - register_reassign(pb,peakIdx); + if (pb->function_entries && (PCF(setFirstItem(pb->function_entries))->isPublic || !pb->visited)) + register_reassign(pb,peakIdx,0); } }