* src/SDCCast.c (fixupInline, createFunction): save currBlockno in
authorMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 13 May 2008 08:10:12 +0000 (08:10 +0000)
committerMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Tue, 13 May 2008 08:10:12 +0000 (08:10 +0000)
  fixupInline instead of createFunction to fix bug 1864577
  (inlineFindMaxBlockno): removed, use global blockNo
* src/SDCCglobl.h: added blockNo
* src/z80/peep.c,
* src/z80/peep.h: modified properties
* support/regression/tests/bug1864577.c: new, added

git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@5155 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
src/SDCCast.c
src/SDCCglobl.h
src/z80/peep.c
support/regression/tests/bug1864577.c [new file with mode: 0644]

index cb97c511d5f64995b20118313bdf555e60785944..3ea7ed34cf318d0dfd91edfe240f929b4af64f81 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-05-07 Maarten Brock <sourceforge.brock AT dse.nl>
+
+       * src/SDCCast.c (fixupInline, createFunction): save currBlockno in
+         fixupInline instead of createFunction to fix bug 1864577
+         (inlineFindMaxBlockno): removed, use global blockNo
+       * src/SDCCglobl.h: added blockNo
+       * src/z80/peep.c,
+       * src/z80/peep.h: modified properties
+       * support/regression/tests/bug1864577.c: new, added
+
 2008-05-07 Maarten Brock <sourceforge.brock AT dse.nl>
 
        * as/mcs51/asdata.c,
index 4b16e347aa386ead902d6e019fbe67b9b7608f09..a3cff8a4c5e5d5f77abd694c146614a2e3729eca 100644 (file)
@@ -6007,13 +6007,13 @@ copyAstLoc (ast * dest, ast * src)
 static void
 fixupInline (ast * tree, int level)
 {
-  tree->block = currBlockno;
+  int savedBlockno = currBlockno;
 
   if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
     {
       symbol * decls;
 
-      currBlockno++;
+      currBlockno = ++blockNo;
       level++;
 
       /* Add any declared variables back into the symbol table */
@@ -6028,6 +6028,7 @@ fixupInline (ast * tree, int level)
     }
 
   tree->level = level;
+  tree->block = currBlockno;
 
   /* Update symbols */
   if (IS_AST_VALUE (tree) &&
@@ -6100,6 +6101,7 @@ fixupInline (ast * tree, int level)
   if (IS_AST_OP (tree) && (tree->opval.op == BLOCK))
     {
       level--;
+      currBlockno = savedBlockno;
     }
 }
 
@@ -6200,33 +6202,6 @@ inlineFindParm (ast * parms, int index)
   return inlineFindParmRecurse (parms, &index);
 }
 
-/*-----------------------------------------------------------------*/
-/* inlineFindMaxBlockno - find maximum block number in an ast tree */
-/*-----------------------------------------------------------------*/
-static int
-inlineFindMaxBlockno (ast * tree, int maxBlockno)
-{
-  int tempBlockno;
-
-  if (!tree)
-    return maxBlockno;
-
-  tempBlockno = inlineFindMaxBlockno (tree->left, maxBlockno);
-  if (tempBlockno > maxBlockno)
-    maxBlockno = tempBlockno;
-
-  tempBlockno = inlineFindMaxBlockno (tree->right, maxBlockno);
-  if (tempBlockno > maxBlockno)
-    maxBlockno = tempBlockno;
-
-  if (tree->block > maxBlockno)
-    maxBlockno = tree->block;
-  return maxBlockno;
-}
-
-
-
-
 /*-----------------------------------------------------------------*/
 /* expandInlineFuncs - replace calls to inline functions with the  */
 /*                     function itself                             */
@@ -6404,7 +6379,6 @@ createFunction (symbol * name, ast * body)
   int stack = 0;
   sym_link *fetype;
   iCode *piCode = NULL;
-  int savedBlockno;
 
   if (getenv("SDCC_DEBUG_FUNCTION_POINTERS"))
     fprintf (stderr, "SDCCast.c:createFunction(%s)\n", name->name);
@@ -6461,10 +6435,7 @@ createFunction (symbol * name, ast * body)
     reentrant++;
 
   inlineState.count = 0;
-  savedBlockno = currBlockno;
-  currBlockno = inlineFindMaxBlockno (body, 0);
   expandInlineFuncs (body, NULL);
-  currBlockno = savedBlockno;
 
   if (FUNC_ISINLINE (name->type))
     name->funcTree = copyAst (body);
index 4f41446d70f82b54f60e9fcecae495c564ae22a1..7166d88177841520743536b7ec1e7a3134ec55d7 100644 (file)
@@ -325,7 +325,8 @@ extern int RegBankUsed[4];      /* JCF: register banks used  SDCCmain.c */
 extern int BitBankUsed;         /* MB: overlayable bit bank  SDCCmain.c */
 extern struct symbol *currFunc; /* current function    SDCCgens.c */
 extern int cNestLevel;          /* block nest level  SDCCval.c */
-extern int currBlockno;         /* sequentail block number */
+extern int blockNo;             /* maximum sequential block number */
+extern int currBlockno;         /* sequential block number */
 extern struct optimize optimize;
 extern struct options options;
 extern unsigned maxInterrupts;
index 03aae37ae3ad1dff9790e34b3505df2ae453b087..bef434a7d51af643425f097f6afee16a3f4cc673 100644 (file)
-/*-------------------------------------------------------------------------\r
-  peep.c - source file for peephole optimizer helper functions\r
-\r
-  Written By -  Philipp Klaus Krause\r
-\r
-  This program is free software; you can redistribute it and/or modify it\r
-  under the terms of the GNU General Public License as published by the\r
-  Free Software Foundation; either version 2, or (at your option) any\r
-  later version.\r
-\r
-  This program is distributed in the hope that it will be useful,\r
-  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
-  GNU General Public License for more details.\r
-\r
-  You should have received a copy of the GNU General Public License\r
-  along with this program; if not, write to the Free Software\r
-  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
-\r
-  In other words, you are welcome to use, share and improve this program.\r
-  You are forbidden to forbid anyone else to use, share and improve\r
-  what you give them.   Help stamp out software-hoarding!\r
--------------------------------------------------------------------------*/\r
-\r
-#include "common.h"\r
-#include "SDCCicode.h"\r
-#include "z80.h"\r
-#include "SDCCglobl.h"\r
-#include "SDCCpeeph.h"\r
-#include "gen.h"\r
-\r
-#define NOTUSEDERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");} while(0)\r
-\r
-/*#define D(_s) { printf _s; fflush(stdout); }*/\r
-#define D(_s)\r
-\r
-typedef enum\r
-{\r
-  S4O_CONDJMP,\r
-  S4O_WR_OP,\r
-  S4O_RD_OP,\r
-  S4O_TERM,\r
-  S4O_VISITED,\r
-  S4O_ABORT,\r
-  S4O_CONTINUE\r
-} S4O_RET;\r
-\r
-static struct\r
-{\r
-  lineNode *head;\r
-} _G;\r
-\r
-/*-----------------------------------------------------------------*/\r
-/* univisitLines - clear "visited" flag in all lines               */\r
-/*-----------------------------------------------------------------*/\r
-static void\r
-unvisitLines (lineNode *pl)\r
-{\r
-  for (; pl; pl = pl->next)\r
-    pl->visited = FALSE;\r
-}\r
-\r
-#define AOP(op) op->aop\r
-#define AOP_SIZE(op) AOP(op)->size\r
-\r
-static bool\r
-isReturned(const char *what)\r
-{\r
-  symbol *sym;\r
-  sym_link *sym_lnk;\r
-  int size;\r
-  lineNode *l;\r
-\r
-  if(strncmp(what, "iy", 2) == 0)\r
-    return FALSE;\r
-  if(strlen(what) != 1)\r
-    return TRUE;\r
-\r
-  l = _G.head;\r
-  do\r
-  {\r
-    l = l->next;\r
-  } while(l->ic->op != FUNCTION);\r
-\r
-  sym = OP_SYMBOL(IC_LEFT(_G.head->next->next->ic));\r
-\r
-  if(sym && IS_DECL(sym->type))\r
-    {\r
-      // Find size of return value.\r
-      specifier *spec;\r
-      if(sym->type->select.d.dcl_type != FUNCTION)\r
-        NOTUSEDERROR();\r
-      spec = &(sym->etype->select.s);\r
-      if(spec->noun == V_VOID)\r
-         size = 0;\r
-      else if(spec->noun == V_CHAR)\r
-         size = 1;\r
-      else if(spec->noun == V_INT && !(spec->b_long))\r
-         size = 2;\r
-      else\r
-        size = 4;\r
-\r
-      // Check for returned pointer.\r
-      sym_lnk = sym->type;\r
-      while (sym_lnk && !IS_PTR (sym_lnk))\r
-        sym_lnk = sym_lnk->next;\r
-      if(IS_PTR(sym_lnk))\r
-        size = 2;\r
-    }\r
-  else\r
-    {\r
-      NOTUSEDERROR();\r
-      size = 4;\r
-    }\r
-\r
-  switch(*what)\r
-    {\r
-    case 'd':\r
-      return(size >= 4);\r
-    case 'e':\r
-      return(size >= 3);\r
-    case 'h':\r
-      return(size >= 2);\r
-    case 'l':\r
-      return(size >= 1);\r
-    default:\r
-      return FALSE;\r
-    }\r
-}\r
-\r
-/*-----------------------------------------------------------------*/\r
-/* incLabelJmpToCount - increment counter "jmpToCount" in entry    */\r
-/* of the list labelHash                                           */\r
-/*-----------------------------------------------------------------*/\r
-static bool\r
-incLabelJmpToCount (const char *label)\r
-{\r
-  labelHashEntry *entry;\r
-\r
-  entry = getLabelRef (label, _G.head);\r
-  if (!entry)\r
-    return FALSE;\r
-  entry->jmpToCount++;\r
-  return TRUE;\r
-}\r
-\r
-/*-----------------------------------------------------------------*/\r
-/* findLabel -                                                     */\r
-/* 1. extracts label in the opcode pl                              */\r
-/* 2. increment "label jump-to count" in labelHash                 */\r
-/* 3. search lineNode with label definition and return it          */\r
-/*-----------------------------------------------------------------*/\r
-static lineNode *\r
-findLabel (const lineNode *pl)\r
-{\r
-  char *p;\r
-  lineNode *cpl;\r
-\r
-  /* 1. extract label in opcode */\r
-\r
-  /* In each mcs51 jumping opcode the label is at the end of the opcode */\r
-  p = strlen (pl->line) - 1 + pl->line;\r
-\r
-  /* scan backward until ',' or '\t' */\r
-  for (; p > pl->line; p--)\r
-    if (*p == ',' || *p == '\t')\r
-      break;\r
-\r
-  /* sanity check */\r
-  if (p == pl->line)\r
-    {\r
-      NOTUSEDERROR();\r
-      return NULL;\r
-    }\r
-\r
-  /* skip ',' resp. '\t' */\r
-  ++p;\r
-\r
-  /* 2. increment "label jump-to count" */\r
-  if (!incLabelJmpToCount (p))\r
-    return NULL;\r
-\r
-  /* 3. search lineNode with label definition and return it */\r
-  for (cpl = _G.head; cpl; cpl = cpl->next)\r
-    {\r
-      if (   cpl->isLabel\r
-          && strncmp (p, cpl->line, strlen(p)) == 0)\r
-        {\r
-          return cpl;\r
-        }\r
-    }\r
-  return NULL;\r
-}\r
-\r
-static bool\r
-z80MightRead(const lineNode *pl, const char *what)\r
-{\r
-  if(strcmp(pl->line, "call\t__initrleblock") == 0)\r
-    return TRUE;\r
-\r
-  if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)\r
-    what = "iy";\r
-\r
-  if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)\r
-    return FALSE;\r
-\r
-  if(strncmp(pl->line, "ret", 3) == 0 && !isReturned(what))\r
-    return FALSE;\r
-\r
-  if(strcmp(pl->line, "ex\tde,hl") == 0 && strchr(what, 'h') == 0 && strchr(what, 'l') == 0 && strchr(what, 'd') == 0&& strchr(what, 'e') == 0)\r
-    return FALSE;\r
-  if(strncmp(pl->line, "ld\t", 3) == 0)\r
-    {\r
-      if(strstr(strchr(pl->line, ','), what) && strchr(pl->line, ',')[1] != '#')\r
-        return TRUE;\r
-      if(*(strchr(pl->line, ',') - 1) == ')' && strstr(pl->line + 3, what) && (strchr(pl->line, '#') == 0 || strchr(pl->line, '#') > strchr(pl->line, ',')))\r
-        return TRUE;\r
-      return FALSE;\r
-    }\r
-\r
-  if(strcmp(pl->line, "xor\ta,a") == 0)\r
-    return FALSE;\r
-\r
-  if(strncmp(pl->line, "adc\t", 4) == 0 ||\r
-    strncmp(pl->line, "add\t", 4) == 0 ||\r
-    strncmp(pl->line, "and\t", 4) == 0 ||\r
-    strncmp(pl->line, "or\t", 3) == 0 ||\r
-    strncmp(pl->line, "sbc\t", 4) == 0 ||\r
-    strncmp(pl->line, "sub\t", 4) == 0 ||\r
-    strncmp(pl->line, "xor\t", 4) == 0)\r
-    {\r
-      if( strstr(pl->line + 3, what) == 0 && strcmp("a", what))\r
-        return FALSE;\r
-    }\r
-\r
-  if(strncmp(pl->line, "pop\t", 4) == 0)\r
-    return FALSE;\r
-\r
-  if(strncmp(pl->line, "push\t", 5) == 0)\r
-    return(strstr(pl->line + 5, what) != 0);\r
-\r
-  if(\r
-    strncmp(pl->line, "dec\t", 4) == 0 ||\r
-    strncmp(pl->line, "inc\t", 4) == 0 ||\r
-    strncmp(pl->line, "rl\t", 3) == 0 ||\r
-    strncmp(pl->line, "rr\t", 3) == 0 ||  \r
-    strncmp(pl->line, "sla\t", 4) == 0 ||\r
-    strncmp(pl->line, "srl\t", 4) == 0)\r
-    {\r
-       return (strstr(pl->line + 3, what) != 0);\r
-    }\r
-\r
-  if(strncmp(pl->line, "jp\t", 3) == 0 ||\r
-    (bool)(strncmp(pl->line, "jr\t", 3)) == 0)\r
-    return FALSE;\r
-\r
-  if(strncmp(pl->line, "rla", 3) == 0 ||\r
-    strncmp(pl->line, "rlca", 4) == 0)\r
-    return(strcmp(what, "a") == 0);\r
-\r
-  return TRUE;\r
-}\r
-\r
-static bool\r
-z80UncondJump(const lineNode *pl)\r
-{\r
-  if((strncmp(pl->line, "jp\t", 3) == 0 ||\r
-    strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)\r
-    return TRUE;\r
-  return FALSE;\r
-}\r
-\r
-static bool\r
-z80CondJump(const lineNode *pl)\r
-{\r
-  if((strncmp(pl->line, "jp\t", 3) == 0 ||\r
-    strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0)\r
-    return TRUE;\r
-  return FALSE;\r
-}\r
-\r
-static bool\r
-z80SurelyWrites(const lineNode *pl, const char *what)\r
-{\r
-  if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)\r
-    return TRUE;\r
-  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))\r
-    return TRUE;\r
-  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))\r
-    return TRUE;\r
-  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))\r
-    return TRUE;\r
-  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')\r
-    return TRUE;\r
-  if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))\r
-    return TRUE;\r
-  if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)\r
-    return TRUE;\r
-  if(strcmp(pl->line, "ret") == 0)\r
-    return TRUE;\r
-  if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)\r
-    return TRUE;\r
-  return FALSE;\r
-}\r
-\r
-static bool\r
-z80SurelyReturns(const lineNode *pl)\r
-{\r
-  if(strcmp(pl->line, "\tret") == 0)\r
-    return TRUE;\r
-  return FALSE;\r
-}\r
-\r
-/*-----------------------------------------------------------------*/\r
-/* scan4op - "executes" and examines the assembler opcodes,        */\r
-/* follows conditional and un-conditional jumps.                   */\r
-/* Moreover it registers all passed labels.                        */\r
-/*                                                                 */\r
-/* Parameter:                                                      */\r
-/*    lineNode **pl                                                */\r
-/*       scanning starts from pl;                                  */\r
-/*       pl also returns the last scanned line                     */\r
-/*    const char *pReg                                             */\r
-/*       points to a register (e.g. "ar0"). scan4op() tests for    */\r
-/*       read or write operations with this register               */\r
-/*    const char *untilOp                                          */\r
-/*       points to NULL or a opcode (e.g. "push").                 */\r
-/*       scan4op() returns if it hits this opcode.                 */\r
-/*    lineNode **plCond                                            */\r
-/*       If a conditional branch is met plCond points to the       */\r
-/*       lineNode of the conditional branch                        */\r
-/*                                                                 */\r
-/* Returns:                                                        */\r
-/*    S4O_ABORT                                                    */\r
-/*       on error                                                  */\r
-/*    S4O_VISITED                                                  */\r
-/*       hit lineNode with "visited" flag set: scan4op() already   */\r
-/*       scanned this opcode.                                      */\r
-/*    S4O_FOUNDOPCODE                                              */\r
-/*       found opcode and operand, to which untilOp and pReg are   */\r
-/*       pointing to.                                              */\r
-/*    S4O_RD_OP, S4O_WR_OP                                         */\r
-/*       hit an opcode reading or writing from pReg                */\r
-/*    S4O_CONDJMP                                                  */\r
-/*       hit a conditional jump opcode. pl and plCond return the   */\r
-/*       two possible branches.                                    */\r
-/*    S4O_TERM                                                     */\r
-/*       acall, lcall, ret and reti "terminate" a scan.            */\r
-/*-----------------------------------------------------------------*/\r
-static S4O_RET\r
-scan4op (lineNode **pl, const char *what, const char *untilOp,\r
-         lineNode **plCond)\r
-{\r
-  for (; *pl; *pl = (*pl)->next)\r
-    {\r
-      if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)\r
-        continue;\r
-      D(("Scanning %s for %s\n", (*pl)->line, what));\r
-      /* don't optimize across inline assembler,\r
-         e.g. isLabel doesn't work there */\r
-      if ((*pl)->isInline)\r
-        return S4O_ABORT;\r
-\r
-      if ((*pl)->visited)\r
-        return S4O_VISITED;\r
-      (*pl)->visited = TRUE;\r
-\r
-      if(z80MightRead(*pl, what))\r
-        {\r
-          D(("S4O_RD_OP\n"));\r
-          return S4O_RD_OP;\r
-        }\r
-\r
-      if(z80UncondJump(*pl))\r
-        {\r
-          *pl = findLabel (*pl);\r
-            if (!*pl)\r
-              {\r
-                D(("S4O_ABORT\n"));\r
-                return S4O_ABORT;\r
-              }\r
-        }\r
-      if(z80CondJump(*pl))\r
-        {\r
-          *plCond = findLabel (*pl);\r
-          if (!*plCond)\r
-            {\r
-              D(("S4O_ABORT\n"));\r
-              return S4O_ABORT;\r
-            }\r
-          D(("S4O_CONDJMP\n"));\r
-          return S4O_CONDJMP;\r
-        }\r
-\r
-      if(z80SurelyWrites(*pl, what))\r
-        {\r
-          D(("S4O_WR_OP\n"));\r
-          return S4O_WR_OP;\r
-        }\r
-\r
-      /* Don't need to check for de, hl since z80MightRead() does that */\r
-      if(z80SurelyReturns(*pl))\r
-        {\r
-          D(("S4O_TERM\n"));\r
-          return S4O_TERM;\r
-        }\r
-    }\r
-  D(("S4O_ABORT\n"));\r
-  return S4O_ABORT;\r
-}\r
-\r
-/*-----------------------------------------------------------------*/\r
-/* doTermScan - scan through area 2. This small wrapper handles:   */\r
-/* - action required on different return values                    */\r
-/* - recursion in case of conditional branches                     */\r
-/*-----------------------------------------------------------------*/\r
-static bool\r
-doTermScan (lineNode **pl, const char *what)\r
-{\r
-  lineNode *plConditional;\r
-\r
-  for (;; *pl = (*pl)->next)\r
-    {\r
-      switch (scan4op (pl, what, NULL, &plConditional))\r
-        {\r
-          case S4O_TERM:\r
-          case S4O_VISITED:\r
-          case S4O_WR_OP:\r
-            /* all these are terminating condtions */\r
-            return TRUE;\r
-          case S4O_CONDJMP:\r
-            /* two possible destinations: recurse */\r
-              {\r
-                lineNode *pl2 = plConditional;\r
-                D(("CONDJMP trying other branch first\n"));\r
-                if (!doTermScan (&pl2, what))\r
-                  return FALSE;\r
-                D(("Other branch OK.\n"));\r
-              }\r
-            continue;\r
-          case S4O_RD_OP:\r
-          default:\r
-            /* no go */\r
-            return FALSE;\r
-        }\r
-    }\r
-}\r
-\r
-static bool\r
-isReg(const char *what)\r
-{\r
-  if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)\r
-    return TRUE;\r
-  if(strlen(what) != 1)\r
-    return FALSE;\r
-  switch(*what)\r
-    {\r
-    case 'a':\r
-    case 'b':\r
-    case 'c':\r
-    case 'd':\r
-    case 'e':\r
-    case 'h':\r
-    case 'l':\r
-      return TRUE;\r
-    }\r
-  return FALSE;\r
-}\r
-\r
-static bool\r
-isRegPair(const char *what)\r
-{\r
-  if(strlen(what) != 2)\r
-    return FALSE;\r
-  if(strcmp(what, "bc") == 0)\r
-    return TRUE;\r
-  if(strcmp(what, "de") == 0)\r
-    return TRUE;\r
-  if(strcmp(what, "hl") == 0)\r
-    return TRUE;\r
-  if(strcmp(what, "iy") == 0)\r
-    return TRUE;\r
-  return FALSE;\r
-}\r
-\r
-/* Check that what is never read after endPl. */\r
-\r
-bool\r
-z80notUsed (const char *what, lineNode *endPl, lineNode *head)\r
-{\r
-  lineNode *pl;\r
-  D(("Checking for %s\n", what));\r
-  if(isRegPair(what))\r
-    {\r
-      char low[2], high[2];\r
-      low[0] = what[1];\r
-      high[0] = what[0];\r
-      low[1] = 0;\r
-      high[1] = 0;\r
-      if(strcmp(what, "iy") == 0)\r
-        return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));\r
-      return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));\r
-    }\r
-\r
-  if(!isReg(what))\r
-    return FALSE;\r
-\r
-  _G.head = head;\r
-\r
-  unvisitLines (_G.head);\r
-\r
-  pl = endPl->next;\r
-  if (!doTermScan (&pl, what))\r
-    return FALSE;\r
-\r
-  return TRUE;\r
-}\r
-\r
+/*-------------------------------------------------------------------------
+  peep.c - source file for peephole optimizer helper functions
+
+  Written By -  Philipp Klaus Krause
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms of the GNU General Public License as published by the
+  Free Software Foundation; either version 2, or (at your option) any
+  later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; if not, write to the Free Software
+  Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+  In other words, you are welcome to use, share and improve this program.
+  You are forbidden to forbid anyone else to use, share and improve
+  what you give them.   Help stamp out software-hoarding!
+-------------------------------------------------------------------------*/
+
+#include "common.h"
+#include "SDCCicode.h"
+#include "z80.h"
+#include "SDCCglobl.h"
+#include "SDCCpeeph.h"
+#include "gen.h"
+
+#define NOTUSEDERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");} while(0)
+
+/*#define D(_s) { printf _s; fflush(stdout); }*/
+#define D(_s)
+
+typedef enum
+{
+  S4O_CONDJMP,
+  S4O_WR_OP,
+  S4O_RD_OP,
+  S4O_TERM,
+  S4O_VISITED,
+  S4O_ABORT,
+  S4O_CONTINUE
+} S4O_RET;
+
+static struct
+{
+  lineNode *head;
+} _G;
+
+/*-----------------------------------------------------------------*/
+/* univisitLines - clear "visited" flag in all lines               */
+/*-----------------------------------------------------------------*/
+static void
+unvisitLines (lineNode *pl)
+{
+  for (; pl; pl = pl->next)
+    pl->visited = FALSE;
+}
+
+#define AOP(op) op->aop
+#define AOP_SIZE(op) AOP(op)->size
+
+static bool
+isReturned(const char *what)
+{
+  symbol *sym;
+  sym_link *sym_lnk;
+  int size;
+  lineNode *l;
+
+  if(strncmp(what, "iy", 2) == 0)
+    return FALSE;
+  if(strlen(what) != 1)
+    return TRUE;
+
+  l = _G.head;
+  do
+  {
+    l = l->next;
+  } while(l->ic->op != FUNCTION);
+
+  sym = OP_SYMBOL(IC_LEFT(_G.head->next->next->ic));
+
+  if(sym && IS_DECL(sym->type))
+    {
+      // Find size of return value.
+      specifier *spec;
+      if(sym->type->select.d.dcl_type != FUNCTION)
+        NOTUSEDERROR();
+      spec = &(sym->etype->select.s);
+      if(spec->noun == V_VOID)
+         size = 0;
+      else if(spec->noun == V_CHAR)
+         size = 1;
+      else if(spec->noun == V_INT && !(spec->b_long))
+         size = 2;
+      else
+        size = 4;
+
+      // Check for returned pointer.
+      sym_lnk = sym->type;
+      while (sym_lnk && !IS_PTR (sym_lnk))
+        sym_lnk = sym_lnk->next;
+      if(IS_PTR(sym_lnk))
+        size = 2;
+    }
+  else
+    {
+      NOTUSEDERROR();
+      size = 4;
+    }
+
+  switch(*what)
+    {
+    case 'd':
+      return(size >= 4);
+    case 'e':
+      return(size >= 3);
+    case 'h':
+      return(size >= 2);
+    case 'l':
+      return(size >= 1);
+    default:
+      return FALSE;
+    }
+}
+
+/*-----------------------------------------------------------------*/
+/* incLabelJmpToCount - increment counter "jmpToCount" in entry    */
+/* of the list labelHash                                           */
+/*-----------------------------------------------------------------*/
+static bool
+incLabelJmpToCount (const char *label)
+{
+  labelHashEntry *entry;
+
+  entry = getLabelRef (label, _G.head);
+  if (!entry)
+    return FALSE;
+  entry->jmpToCount++;
+  return TRUE;
+}
+
+/*-----------------------------------------------------------------*/
+/* findLabel -                                                     */
+/* 1. extracts label in the opcode pl                              */
+/* 2. increment "label jump-to count" in labelHash                 */
+/* 3. search lineNode with label definition and return it          */
+/*-----------------------------------------------------------------*/
+static lineNode *
+findLabel (const lineNode *pl)
+{
+  char *p;
+  lineNode *cpl;
+
+  /* 1. extract label in opcode */
+
+  /* In each mcs51 jumping opcode the label is at the end of the opcode */
+  p = strlen (pl->line) - 1 + pl->line;
+
+  /* scan backward until ',' or '\t' */
+  for (; p > pl->line; p--)
+    if (*p == ',' || *p == '\t')
+      break;
+
+  /* sanity check */
+  if (p == pl->line)
+    {
+      NOTUSEDERROR();
+      return NULL;
+    }
+
+  /* skip ',' resp. '\t' */
+  ++p;
+
+  /* 2. increment "label jump-to count" */
+  if (!incLabelJmpToCount (p))
+    return NULL;
+
+  /* 3. search lineNode with label definition and return it */
+  for (cpl = _G.head; cpl; cpl = cpl->next)
+    {
+      if (   cpl->isLabel
+          && strncmp (p, cpl->line, strlen(p)) == 0)
+        {
+          return cpl;
+        }
+    }
+  return NULL;
+}
+
+static bool
+z80MightRead(const lineNode *pl, const char *what)
+{
+  if(strcmp(pl->line, "call\t__initrleblock") == 0)
+    return TRUE;
+
+  if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
+    what = "iy";
+
+  if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
+    return FALSE;
+
+  if(strncmp(pl->line, "ret", 3) == 0 && !isReturned(what))
+    return FALSE;
+
+  if(strcmp(pl->line, "ex\tde,hl") == 0 && strchr(what, 'h') == 0 && strchr(what, 'l') == 0 && strchr(what, 'd') == 0&& strchr(what, 'e') == 0)
+    return FALSE;
+  if(strncmp(pl->line, "ld\t", 3) == 0)
+    {
+      if(strstr(strchr(pl->line, ','), what) && strchr(pl->line, ',')[1] != '#')
+        return TRUE;
+      if(*(strchr(pl->line, ',') - 1) == ')' && strstr(pl->line + 3, what) && (strchr(pl->line, '#') == 0 || strchr(pl->line, '#') > strchr(pl->line, ',')))
+        return TRUE;
+      return FALSE;
+    }
+
+  if(strcmp(pl->line, "xor\ta,a") == 0)
+    return FALSE;
+
+  if(strncmp(pl->line, "adc\t", 4) == 0 ||
+    strncmp(pl->line, "add\t", 4) == 0 ||
+    strncmp(pl->line, "and\t", 4) == 0 ||
+    strncmp(pl->line, "or\t", 3) == 0 ||
+    strncmp(pl->line, "sbc\t", 4) == 0 ||
+    strncmp(pl->line, "sub\t", 4) == 0 ||
+    strncmp(pl->line, "xor\t", 4) == 0)
+    {
+      if( strstr(pl->line + 3, what) == 0 && strcmp("a", what))
+        return FALSE;
+    }
+
+  if(strncmp(pl->line, "pop\t", 4) == 0)
+    return FALSE;
+
+  if(strncmp(pl->line, "push\t", 5) == 0)
+    return(strstr(pl->line + 5, what) != 0);
+
+  if(
+    strncmp(pl->line, "dec\t", 4) == 0 ||
+    strncmp(pl->line, "inc\t", 4) == 0 ||
+    strncmp(pl->line, "rl\t", 3) == 0 ||
+    strncmp(pl->line, "rr\t", 3) == 0 ||  
+    strncmp(pl->line, "sla\t", 4) == 0 ||
+    strncmp(pl->line, "srl\t", 4) == 0)
+    {
+       return (strstr(pl->line + 3, what) != 0);
+    }
+
+  if(strncmp(pl->line, "jp\t", 3) == 0 ||
+    (bool)(strncmp(pl->line, "jr\t", 3)) == 0)
+    return FALSE;
+
+  if(strncmp(pl->line, "rla", 3) == 0 ||
+    strncmp(pl->line, "rlca", 4) == 0)
+    return(strcmp(what, "a") == 0);
+
+  return TRUE;
+}
+
+static bool
+z80UncondJump(const lineNode *pl)
+{
+  if((strncmp(pl->line, "jp\t", 3) == 0 ||
+    strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') == 0)
+    return TRUE;
+  return FALSE;
+}
+
+static bool
+z80CondJump(const lineNode *pl)
+{
+  if((strncmp(pl->line, "jp\t", 3) == 0 ||
+    strncmp(pl->line, "jr\t", 3) == 0) && strchr(pl->line, ',') != 0)
+    return TRUE;
+  return FALSE;
+}
+
+static bool
+z80SurelyWrites(const lineNode *pl, const char *what)
+{
+  if(strcmp(pl->line, "xor\ta,a") == 0 && strcmp(what, "a") == 0)
+    return TRUE;
+  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "hl", 2) == 0 && (what[0] == 'h' || what[0] == 'l'))
+    return TRUE;
+  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "de", 2) == 0 && (what[0] == 'd' || what[0] == 'e'))
+    return TRUE;
+  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, "bc", 2) == 0 && (what[0] == 'b' || what[0] == 'c'))
+    return TRUE;
+  if(strncmp(pl->line, "ld\t", 3) == 0 && strncmp(pl->line + 3, what, strlen(what)) == 0 && pl->line[3 + strlen(what)] == ',')
+    return TRUE;
+  if(strncmp(pl->line, "pop\t", 4) == 0 && strstr(pl->line + 4, what))
+    return TRUE;
+  if(strncmp(pl->line, "call\t", 5) == 0 && strchr(pl->line, ',') == 0)
+    return TRUE;
+  if(strcmp(pl->line, "ret") == 0)
+    return TRUE;
+  if(strncmp(pl->line, "ld\tiy", 5) == 0 && strncmp(what, "iy", 2) == 0)
+    return TRUE;
+  return FALSE;
+}
+
+static bool
+z80SurelyReturns(const lineNode *pl)
+{
+  if(strcmp(pl->line, "\tret") == 0)
+    return TRUE;
+  return FALSE;
+}
+
+/*-----------------------------------------------------------------*/
+/* scan4op - "executes" and examines the assembler opcodes,        */
+/* follows conditional and un-conditional jumps.                   */
+/* Moreover it registers all passed labels.                        */
+/*                                                                 */
+/* Parameter:                                                      */
+/*    lineNode **pl                                                */
+/*       scanning starts from pl;                                  */
+/*       pl also returns the last scanned line                     */
+/*    const char *pReg                                             */
+/*       points to a register (e.g. "ar0"). scan4op() tests for    */
+/*       read or write operations with this register               */
+/*    const char *untilOp                                          */
+/*       points to NULL or a opcode (e.g. "push").                 */
+/*       scan4op() returns if it hits this opcode.                 */
+/*    lineNode **plCond                                            */
+/*       If a conditional branch is met plCond points to the       */
+/*       lineNode of the conditional branch                        */
+/*                                                                 */
+/* Returns:                                                        */
+/*    S4O_ABORT                                                    */
+/*       on error                                                  */
+/*    S4O_VISITED                                                  */
+/*       hit lineNode with "visited" flag set: scan4op() already   */
+/*       scanned this opcode.                                      */
+/*    S4O_FOUNDOPCODE                                              */
+/*       found opcode and operand, to which untilOp and pReg are   */
+/*       pointing to.                                              */
+/*    S4O_RD_OP, S4O_WR_OP                                         */
+/*       hit an opcode reading or writing from pReg                */
+/*    S4O_CONDJMP                                                  */
+/*       hit a conditional jump opcode. pl and plCond return the   */
+/*       two possible branches.                                    */
+/*    S4O_TERM                                                     */
+/*       acall, lcall, ret and reti "terminate" a scan.            */
+/*-----------------------------------------------------------------*/
+static S4O_RET
+scan4op (lineNode **pl, const char *what, const char *untilOp,
+         lineNode **plCond)
+{
+  for (; *pl; *pl = (*pl)->next)
+    {
+      if (!(*pl)->line || (*pl)->isDebug || (*pl)->isComment || (*pl)->isLabel)
+        continue;
+      D(("Scanning %s for %s\n", (*pl)->line, what));
+      /* don't optimize across inline assembler,
+         e.g. isLabel doesn't work there */
+      if ((*pl)->isInline)
+        return S4O_ABORT;
+
+      if ((*pl)->visited)
+        return S4O_VISITED;
+      (*pl)->visited = TRUE;
+
+      if(z80MightRead(*pl, what))
+        {
+          D(("S4O_RD_OP\n"));
+          return S4O_RD_OP;
+        }
+
+      if(z80UncondJump(*pl))
+        {
+          *pl = findLabel (*pl);
+            if (!*pl)
+              {
+                D(("S4O_ABORT\n"));
+                return S4O_ABORT;
+              }
+        }
+      if(z80CondJump(*pl))
+        {
+          *plCond = findLabel (*pl);
+          if (!*plCond)
+            {
+              D(("S4O_ABORT\n"));
+              return S4O_ABORT;
+            }
+          D(("S4O_CONDJMP\n"));
+          return S4O_CONDJMP;
+        }
+
+      if(z80SurelyWrites(*pl, what))
+        {
+          D(("S4O_WR_OP\n"));
+          return S4O_WR_OP;
+        }
+
+      /* Don't need to check for de, hl since z80MightRead() does that */
+      if(z80SurelyReturns(*pl))
+        {
+          D(("S4O_TERM\n"));
+          return S4O_TERM;
+        }
+    }
+  D(("S4O_ABORT\n"));
+  return S4O_ABORT;
+}
+
+/*-----------------------------------------------------------------*/
+/* doTermScan - scan through area 2. This small wrapper handles:   */
+/* - action required on different return values                    */
+/* - recursion in case of conditional branches                     */
+/*-----------------------------------------------------------------*/
+static bool
+doTermScan (lineNode **pl, const char *what)
+{
+  lineNode *plConditional;
+
+  for (;; *pl = (*pl)->next)
+    {
+      switch (scan4op (pl, what, NULL, &plConditional))
+        {
+          case S4O_TERM:
+          case S4O_VISITED:
+          case S4O_WR_OP:
+            /* all these are terminating condtions */
+            return TRUE;
+          case S4O_CONDJMP:
+            /* two possible destinations: recurse */
+              {
+                lineNode *pl2 = plConditional;
+                D(("CONDJMP trying other branch first\n"));
+                if (!doTermScan (&pl2, what))
+                  return FALSE;
+                D(("Other branch OK.\n"));
+              }
+            continue;
+          case S4O_RD_OP:
+          default:
+            /* no go */
+            return FALSE;
+        }
+    }
+}
+
+static bool
+isReg(const char *what)
+{
+  if(strcmp(what, "iyl") == 0 || strcmp(what, "iyh") == 0)
+    return TRUE;
+  if(strlen(what) != 1)
+    return FALSE;
+  switch(*what)
+    {
+    case 'a':
+    case 'b':
+    case 'c':
+    case 'd':
+    case 'e':
+    case 'h':
+    case 'l':
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static bool
+isRegPair(const char *what)
+{
+  if(strlen(what) != 2)
+    return FALSE;
+  if(strcmp(what, "bc") == 0)
+    return TRUE;
+  if(strcmp(what, "de") == 0)
+    return TRUE;
+  if(strcmp(what, "hl") == 0)
+    return TRUE;
+  if(strcmp(what, "iy") == 0)
+    return TRUE;
+  return FALSE;
+}
+
+/* Check that what is never read after endPl. */
+
+bool
+z80notUsed (const char *what, lineNode *endPl, lineNode *head)
+{
+  lineNode *pl;
+  D(("Checking for %s\n", what));
+  if(isRegPair(what))
+    {
+      char low[2], high[2];
+      low[0] = what[1];
+      high[0] = what[0];
+      low[1] = 0;
+      high[1] = 0;
+      if(strcmp(what, "iy") == 0)
+        return(z80notUsed("iyl", endPl, head) && z80notUsed("iyh", endPl, head));
+      return(z80notUsed(low, endPl, head) && z80notUsed(high, endPl, head));
+    }
+
+  if(!isReg(what))
+    return FALSE;
+
+  _G.head = head;
+
+  unvisitLines (_G.head);
+
+  pl = endPl->next;
+  if (!doTermScan (&pl, what))
+    return FALSE;
+
+  return TRUE;
+}
+
diff --git a/support/regression/tests/bug1864577.c b/support/regression/tests/bug1864577.c
new file mode 100644 (file)
index 0000000..f85189a
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+    bug 1864577
+*/
+
+#include <testfwk.h>
+
+#ifdef SDCC
+#pragma std_sdcc99
+#endif
+
+typedef unsigned char uint8_t;
+
+typedef uint8_t error_t  ;
+
+enum __nesc_unnamed4247 {
+  SUCCESS = 0, 
+  FAIL = 1, 
+  ESIZE = 2, 
+  ECANCEL = 3, 
+  EOFF = 4, 
+  EBUSY = 5, 
+  EINVAL = 6, 
+  ERETRY = 7, 
+  ERESERVE = 8, 
+  EALREADY = 9
+};
+
+static inline   error_t PlatformP__LedsInit__default__init(void) {
+  return SUCCESS;
+}
+
+static  error_t PlatformP__LedsInit__init(void);
+static inline  error_t PlatformP__LedsInit__init(void){
+  unsigned char result;
+
+  result = PlatformP__LedsInit__default__init();
+
+  return result;
+}
+
+void
+testBug(void)
+{
+  ASSERT (PlatformP__LedsInit__init() == SUCCESS);
+}