* src/pic/pcode.c (ReuseReg): do not overlay the registers used for
[fw/sdcc] / src / pic / pcode.c
index 100a5f76f036b310cd3081ec8bbd5c17efb9f2f1..659c749aaec315db541977870077515122609fa7 100644 (file)
@@ -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
-
 /****************************************************************/
 /****************************************************************/
 
@@ -1267,74 +1261,6 @@ unsigned PCodeID(void) {
        return pcodeId++;
 }
 
-#ifdef HAVE_VSNPRINTF
-// Alas, vsnprintf is not ANSI standard, and does not exist
-// on Solaris (and probably other non-Gnu flavored Unixes).
-
-/*-----------------------------------------------------------------*/
-/* SAFE_snprintf - like snprintf except the string pointer is      */
-/*                 after the string has been printed to. This is   */
-/*                 useful for printing to string as though if it   */
-/*                 were a stream.                                  */
-/*-----------------------------------------------------------------*/
-void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
-{
-       va_list val;
-       int len;
-       
-       if(!str || !*str)
-               return;
-       
-       va_start(val, format);
-       
-       vsnprintf(*str, *size, format, val);
-       
-       va_end (val);
-       
-       len = strlen(*str);
-       if((size_t)len > *size) {
-               fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
-               fprintf(stderr,"len = %d is > str size %d\n",len,(int)*size);
-       }
-       
-       *str += len;
-       *size -= len;
-       
-}
-
-#else  //  HAVE_VSNPRINTF
-
-// This version is *not* safe, despite the name.
-
-void SAFE_snprintf(char **str, size_t *size, const  char  *format, ...)
-{
-       va_list val;
-       int len;
-       static char buffer[1024]; /* grossly conservative, but still not inherently safe */
-       
-       if(!str || !*str)
-               return;
-       
-       va_start(val, format);
-       
-       vsprintf(buffer, format, val);
-       va_end (val);
-       
-       len = strlen(buffer);
-       if(len > *size) {
-               fprintf(stderr,"WARNING, it looks like %s has overflowed\n",__FUNCTION__);
-               fprintf(stderr,"len = %d is > str size %d\n",len,*size);
-       }
-       
-       strcpy(*str, buffer);
-       *str += len;
-       *size -= len;
-       
-}
-
-#endif    //  HAVE_VSNPRINTF
-
-
 extern  void initStack(int base_address, int size, int shared);
 extern regs *allocProcessorRegister(int rIdx, char * name, short po_type, int alias);
 extern regs *allocInternalRegister(int rIdx, char * name, PIC_OPTYPE po_type, int alias);
@@ -2556,7 +2482,7 @@ void pCodeReadCodeTable(void)
 void addpCode2pBlock(pBlock *pb, pCode *pc)
 {
        
-       if(!pc)
+       if(!pb || !pc)
                return;
        
        if(!pb->pcHead) {
@@ -3001,10 +2927,9 @@ char *get_op(pCodeOp *pcop,char *buffer, size_t size)
                case PO_INDF:
                case PO_FSR:
                        if(use_buffer) {
-                               SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
+                               SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
                                return buffer;
                        }
-                       //return PCOR(pcop)->r->name;
                        return pcop->name;
                        break;
                case PO_GPR_TEMP:
@@ -3014,12 +2939,12 @@ char *get_op(pCodeOp *pcop,char *buffer, size_t size)
                                r = pic14_regWithIdx(PCOR(pcop)->r->rIdx);
                        
                        if(use_buffer) {
-                               SAFE_snprintf(&buffer,&size,"%s",r->name);
+                               SNPRINTF(buffer,size,"%s",r->name);
                                return buffer;
                        }
                        
                        return r->name;
-                       
+                       break;
                        
                case PO_IMMEDIATE:
                        s = buffer;
@@ -3028,81 +2953,87 @@ char *get_op(pCodeOp *pcop,char *buffer, size_t size)
                                if( PCOI(pcop)->offset >= 0 && PCOI(pcop)->offset<4) {
                                        switch(PCOI(pcop)->offset) {
                                        case 0:
-                                               SAFE_snprintf(&s,&size,"low (%s+%d)",pcop->name, PCOI(pcop)->index);
+                                               SNPRINTF(s,size,"low (%s+%d)",pcop->name, PCOI(pcop)->index);
                                                break;
                                        case 1:
-                                               SAFE_snprintf(&s,&size,"high (%s+%d)",pcop->name, PCOI(pcop)->index);
+                                               SNPRINTF(s,size,"high (%s+%d)",pcop->name, PCOI(pcop)->index);
+                                               break;
+                                       case 2:
+                                               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" );
-                                               SAFE_snprintf(&s,&size,"(((%s+%d) >> %d)&0xff)",
+                                               SNPRINTF(s,size,"(((%s+%d) >> %d)&0xff)",
                                                        pcop->name,
                                                        PCOI(pcop)->index,
                                                        8 * PCOI(pcop)->offset );
                                        }
                                } else
-                                       SAFE_snprintf(&s,&size,"LOW (%s+%d)",pcop->name,PCOI(pcop)->index);
+                                       SNPRINTF(s,size,"LOW (%s+%d)",pcop->name,PCOI(pcop)->index);
                        } else {
                                if( !PCOI(pcop)->offset) { // && PCOI(pcc->pcop)->offset<4) 
-                                       SAFE_snprintf(&s,&size,"(%s + %d)",
+                                       SNPRINTF(s,size,"(%s + %d)",
                                                pcop->name,
                                                PCOI(pcop)->index);
                                } else {
                                        switch(PCOI(pcop)->offset) {
                                        case 0:
-                                               SAFE_snprintf(&s,&size,"(%s + %d)",pcop->name, PCOI(pcop)->index);
+                                               SNPRINTF(s,size,"(%s + %d)",pcop->name, PCOI(pcop)->index);
                                                break;
                                        case 1:
-                                               SAFE_snprintf(&s,&size,"high (%s + %d)",pcop->name, PCOI(pcop)->index);
+                                               SNPRINTF(s,size,"high (%s + %d)",pcop->name, PCOI(pcop)->index);
+                                               break;
+                                       case 2:
+                                               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" );
-                                               SAFE_snprintf(&s,&size,"((%s + %d) >> %d)&0xff",pcop->name, PCOI(pcop)->index, 8*PCOI(pcop)->offset);
+                                               SNPRINTF(s,size,"((%s + %d) >> %d)&0xff",pcop->name, PCOI(pcop)->index, 8*PCOI(pcop)->offset);
                                                break;
                                        }
                                }
                        }
-                       
                        return buffer;
+                       break;
                        
                case PO_DIR:
                        s = buffer;
-                       //size = sizeof(buffer);
                        if( PCOR(pcop)->instance) {
-                               SAFE_snprintf(&s,&size,"(%s + %d)",
+                               SNPRINTF(s,size,"(%s + %d)",
                                        pcop->name,
                                        PCOR(pcop)->instance );
-                               //fprintf(stderr,"PO_DIR %s\n",buffer);
                        } else
-                               SAFE_snprintf(&s,&size,"%s",pcop->name);
+                               SNPRINTF(s,size,"%s",pcop->name);
                        return buffer;
+                       break;
                        
                case PO_LABEL:
                        s = buffer;
                        if  (pcop->name) {
                                if(PCOLAB(pcop)->offset == 1)
-                                       SAFE_snprintf(&s,&size,"HIGH(%s)",pcop->name);
+                                       SNPRINTF(s,size,"HIGH(%s)",pcop->name);
                                else
-                                       SAFE_snprintf(&s,&size,"%s",pcop->name);
+                                       SNPRINTF(s,size,"%s",pcop->name);
                        }
                        return buffer;
+                       break;
 
                case PO_GPR_BIT:
                        if(PCOR(pcop)->r) {
                                if(use_buffer) {
-                                       SAFE_snprintf(&buffer,&size,"%s",PCOR(pcop)->r->name);
+                                       SNPRINTF(buffer,size,"%s",PCOR(pcop)->r->name);
                                        return buffer;
                                }
                                return PCOR(pcop)->r->name;
                        }
-                       
                        /* fall through to the default case */
+
                default:
                        if(pcop->name) {
                                if(use_buffer) {
-                                       SAFE_snprintf(&buffer,&size,"%s",pcop->name);
+                                       SNPRINTF(buffer,size,"%s",pcop->name);
                                        return buffer;
                                }
                                return pcop->name;
@@ -3142,86 +3073,86 @@ static void pCodeOpPrint(FILE *of, pCodeOp *pcop)
 /*-----------------------------------------------------------------*/
 char *pCode2str(char *str, size_t size, pCode *pc)
 {
-  char *s = str;
+    char *s = str;
 
-  switch(pc->type) {
+    switch(pc->type) {
 
-  case PC_OPCODE:
+        case PC_OPCODE:
 
-    SAFE_snprintf(&s,&size, "\t%s\t", PCI(pc)->mnemonic);
-
-    if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
-
-      if(PCI(pc)->isBitInst) {
-        if(PCI(pc)->pcop->type == PO_GPR_BIT) {
-          char *name = PCI(pc)->pcop->name;
-          if (!name)
-            name = PCOR(PCI(pc)->pcop)->r->name;
-          if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
-            SAFE_snprintf(&s,&size,"(%s >> 3), (%s & 7)", name, name);
-          else
-            SAFE_snprintf(&s,&size,"%s,%d", name, 
-            (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit)&7);
-        } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
-          SAFE_snprintf(&s,&size,"%s,%d", get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
-      } else
-          SAFE_snprintf(&s,&size,"%s,0 ; ?bug", get_op_from_instruction(PCI(pc)));
-        //PCI(pc)->pcop->t.bit );
-      } else {
-        if(PCI(pc)->pcop->type == PO_GPR_BIT) {
-          if( PCI(pc)->num_ops == 2)
-            SAFE_snprintf(&s,&size,"(%s >> 3),%c",get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
-          else
-            SAFE_snprintf(&s,&size,"(1 << (%s & 7))",get_op_from_instruction(PCI(pc)));
-        } else {
-          SAFE_snprintf(&s,&size,"%s",get_op_from_instruction(PCI(pc)));
-          if( PCI(pc)->num_ops == 2)
-            SAFE_snprintf(&s,&size,",%c", ( (PCI(pc)->isModReg) ? 'F':'W'));
-        }
-      }
-    }
-    break;
+            SNPRINTF(s,size, "\t%s\t", PCI(pc)->mnemonic);
+            size -= strlen(s);
+            s += strlen(s);
+
+            if( (PCI(pc)->num_ops >= 1) && (PCI(pc)->pcop)) {
+                if(PCI(pc)->isBitInst) {
+                    if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+                        char *name = PCI(pc)->pcop->name;
+                        if (!name)
+                            name = PCOR(PCI(pc)->pcop)->r->name;
+                        if( (((pCodeOpRegBit *)(PCI(pc)->pcop))->inBitSpace) )
+                            SNPRINTF(s,size,"(%s >> 3), (%s & 7)", name, name);
+                        else
+                            SNPRINTF(s,size,"%s,%d", name, (((pCodeOpRegBit *)(PCI(pc)->pcop))->bit)&7);
+                    } else if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+                        SNPRINTF(s,size,"%s,%d", get_op_from_instruction(PCI(pc)),PCORB(PCI(pc)->pcop)->bit);
+                    } else
+                        SNPRINTF(s,size,"%s,0 ; ?bug", get_op_from_instruction(PCI(pc)));
+                } else {
+                    if(PCI(pc)->pcop->type == PO_GPR_BIT) {
+                        if( PCI(pc)->num_ops == 2)
+                            SNPRINTF(s,size,"(%s >> 3),%c",get_op_from_instruction(PCI(pc)),((PCI(pc)->isModReg) ? 'F':'W'));
+                        else
+                            SNPRINTF(s,size,"(1 << (%s & 7))",get_op_from_instruction(PCI(pc)));
+                    } else {
+                        SNPRINTF(s,size,"%s",get_op_from_instruction(PCI(pc)));
+                        size -= strlen(s);
+                        s += strlen(s);
+                        if( PCI(pc)->num_ops == 2)
+                            SNPRINTF(s,size,",%c", ( (PCI(pc)->isModReg) ? 'F':'W'));
+                    }
+                }
+            }
+            break;
 
-  case PC_COMMENT:
-    /* assuming that comment ends with a \n */
-    SAFE_snprintf(&s,&size,";%s", ((pCodeComment *)pc)->comment);
-    break;
+        case PC_COMMENT:
+            /* assuming that comment ends with a \n */
+            SNPRINTF(s,size,";%s", ((pCodeComment *)pc)->comment);
+            break;
 
-  case PC_INLINE:
-    /* assuming that inline code ends with a \n */
-    SAFE_snprintf(&s,&size,"%s", ((pCodeComment *)pc)->comment);
-    break;
+        case PC_INLINE:
+            /* assuming that inline code ends with a \n */
+            SNPRINTF(s,size,"%s", ((pCodeComment *)pc)->comment);
+            break;
 
-  case PC_LABEL:
-    SAFE_snprintf(&s,&size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
-    break;
-  case PC_FUNCTION:
-    SAFE_snprintf(&s,&size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
-    break;
-  case PC_WILD:
-    SAFE_snprintf(&s,&size,";\tWild opcode: id=%d\n",PCW(pc)->id);
-    break;
-  case PC_FLOW:
-    SAFE_snprintf(&s,&size,";\t--FLOW change\n");
-    break;
-  case PC_CSOURCE:
-//    SAFE_snprintf(&s,&size,";#CSRC\t%s %d\n; %s\n", PCCS(pc)->file_name, PCCS(pc)->line_number, PCCS(pc)->line);
-    SAFE_snprintf(&s,&size,"%s\t.line\t%d; \"%s\"\t%s\n",(options.debug?"":";"),PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
-    break;
-  case PC_ASMDIR:
-    if(PCAD(pc)->directive) {
-      SAFE_snprintf(&s,&size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
-    } else if(PCAD(pc)->arg) {
-      /* special case to handle inline labels without a tab */
-      SAFE_snprintf(&s,&size,"%s\n", PCAD(pc)->arg);
+        case PC_LABEL:
+            SNPRINTF(s,size,";label=%s, key=%d\n",PCL(pc)->label,PCL(pc)->key);
+            break;
+        case PC_FUNCTION:
+            SNPRINTF(s,size,";modname=%s,function=%s: id=%d\n",PCF(pc)->modname,PCF(pc)->fname);
+            break;
+        case PC_WILD:
+            SNPRINTF(s,size,";\tWild opcode: id=%d\n",PCW(pc)->id);
+            break;
+        case PC_FLOW:
+            SNPRINTF(s,size,";\t--FLOW change\n");
+            break;
+        case PC_CSOURCE:
+            SNPRINTF(s,size,"%s\t.line\t%d; \"%s\"\t%s\n",(options.debug?"":";"),PCCS(pc)->line_number, PCCS(pc)->file_name, PCCS(pc)->line);
+            break;
+        case PC_ASMDIR:
+            if(PCAD(pc)->directive) {
+                SNPRINTF(s,size,"\t%s%s%s\n", PCAD(pc)->directive, PCAD(pc)->arg?"\t":"", PCAD(pc)->arg?PCAD(pc)->arg:"");
+            } else if(PCAD(pc)->arg) {
+                /* special case to handle inline labels without a tab */
+                SNPRINTF(s,size,"%s\n", PCAD(pc)->arg);
+            }
+            break;
+
+        case PC_BAD:
+            SNPRINTF(s,size,";A bad pCode is being used\n");
     }
-    break;
-
-  case PC_BAD:
-    SAFE_snprintf(&s,&size,";A bad pCode is being used\n");
-  }
 
-  return str;
+    return str;
 }
 
 /*-----------------------------------------------------------------*/
@@ -4315,6 +4246,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 +4554,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(&reg->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 +4620,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 +4630,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 +4639,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 +4647,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 +4671,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 +4697,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 +4706,7 @@ void FixRegisterBanking(pBlock *pb)
 
                cur_mask = new_mask;
                cur_bank = new_bank;
+               previous_reg = reg;
                insertBankSel(pci, cur_bank);
            } // if
        } // if
@@ -4838,7 +4820,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 +5227,6 @@ DEFSETFUNC (resetrIdx)
 /*-----------------------------------------------------------------*/
 /* InitRegReuse - Initialises variables for code analyzer          */
 /*-----------------------------------------------------------------*/
-
 void InitReuseReg(void)
 {
        /* Find end of statically allocated variables for start idx */
@@ -5264,51 +5245,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;
-       
-       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);
-                                       }
-                               }
-                       }
+    pCode *pc;
+
+    /* 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;
 }
 
 /*------------------------------------------------------------------*/
@@ -5335,12 +5342,12 @@ static unsigned register_reassign(pBlock *pb, unsigned idx)
 void ReuseReg(void)
 {
        pBlock  *pb;
-       if (!the_pFile) return;
+       if (options.noOverlay || !the_pFile) return;
        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);
        }
 }