* src/z80/peep.c,
authorMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 20 Apr 2008 20:14:22 +0000 (20:14 +0000)
committerMaartenBrock <MaartenBrock@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 20 Apr 2008 20:14:22 +0000 (20:14 +0000)
* src/mcs51/peep.c: Use werror for error messages.
* src/SDCCicode.c (geniCodeConditional),
* src/SDCCsymt.c (structElemType): fixed bug 1839321
* src/z80/Makefile.bcc,
* src/z80/z80.dsp: added src/z80/peep.c/h
* support/regression/tests/bug1839321.c: new, added

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

ChangeLog
src/SDCCicode.c
src/SDCCsymt.c
src/mcs51/peep.c
src/z80/Makefile.bcc
src/z80/peep.c
src/z80/z80.dsp
support/regression/tests/bug1839321.c [new file with mode: 0644]

index b8712bfd64c4c63a4dd9ce27fb5cbee5d744590b..646a53cefc2fd01245edcd177862c3a56666b347 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-04-20 Maarten Brock <sourceforge.brock AT dse.nl>
+
+       * src/z80/peep.c,
+       * src/mcs51/peep.c: Use werror for error messages.
+       * src/SDCCicode.c (geniCodeConditional),
+       * src/SDCCsymt.c (structElemType): fixed bug 1839321
+       * src/z80/Makefile.bcc,
+       * src/z80/z80.dsp: added src/z80/peep.c/h
+       * support/regression/tests/bug1839321.c: new, added
+
 2008-04-20 Raphael Neider <rneider AT web.de>
 
        * device/include/pic16/pic18f2455.h: added bitfields for port C
@@ -22,7 +32,7 @@
          struct),
        * src/port.h (removed dependency on mcs51/peep.h, added declaration
          for notUsed()): Implemented generic (that is not port-specific) part
-         of RFE #1880202.      
+         of RFE #1880202.
 
 2008-04-17 Maarten Brock <sourceforge.brock AT dse.nl>
 
index cd1a85ad832a935a8b5f5a4a6af9cebd0f6253eb..6c8ee8a8ac6fd200f8f1298b87b2acb29b2850aa 100644 (file)
@@ -3191,7 +3191,7 @@ geniCodeConditional (ast * tree,int lvl)
   ast *astTrue  = tree->right->left;
   ast *astFalse = tree->right->right;
   operand *cond = ast2iCode (tree->left, lvl+1);
-  operand *result = newiTempOperand (tree->right->ftype, 0);
+  operand *result = newiTempOperand (tree->ftype, 0);
   operand *opTrue, *opFalse;
 
   ic = newiCodeCondition (geniCodeRValue (cond, FALSE), NULL, falseLabel);
index 95228673de2130475328ddd33c044ce59e380624..94ad4d70705893e2e8879f845a49f35395165c9f 100644 (file)
@@ -1213,6 +1213,8 @@ structElemType (sym_link * stype, value * id)
             etype = getSpec (type);
             SPEC_SCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
                                  SPEC_SCLS (etype) : SPEC_SCLS (petype));
+            SPEC_OCLS (etype) = (SPEC_SCLS (petype) == S_REGISTER ?
+                                 SPEC_OCLS (etype) : SPEC_OCLS (petype));
             if (IS_SPEC (type))
               SPEC_CONST (type) |= SPEC_CONST (stype);
             else
index 3210746119292ebf83fd4d805b02dc5233108111..c0dcb01652fd568c2e3ab369eb94839690878cfe 100644 (file)
@@ -26,7 +26,7 @@
 #include "ralloc.h"
 
 #define D(x) x
-#define DEADMOVEERROR "SDCC internal error: deadmove in " __FILE__" line %d\n", __LINE__
+#define DEADMOVEERROR() do {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in deadmove");} while(0)
 
 typedef enum
 {
@@ -177,7 +177,7 @@ findLabel (const lineNode *pl)
   /* sanity check */
   if (p == pl->line)
     {
-      D(fprintf (stderr, DEADMOVEERROR);)
+      DEADMOVEERROR();
       return NULL;
     }
 
@@ -305,7 +305,7 @@ scan4op (lineNode **pl, const char *pReg, const char *untilOp,
   /* sanity check */
   if (rIdx >= mcs51_nRegs)
     {
-      D(fprintf (stderr, DEADMOVEERROR);)
+      DEADMOVEERROR();
       return S4O_ABORT;
     }
 
@@ -374,7 +374,7 @@ scan4op (lineNode **pl, const char *pReg, const char *untilOp,
           /* register passing this label */
           if (!setLabelRefPassedLabel (label))
             {
-              D(fprintf (stderr, DEADMOVEERROR);)
+              DEADMOVEERROR();
               return S4O_ABORT;
             }
           continue;
@@ -529,7 +529,7 @@ doPushScan (lineNode **pl, const char *pReg)
           case S4O_VISITED:
             if (!pushPl)
               {
-                D(fprintf (stderr, DEADMOVEERROR);)
+                DEADMOVEERROR();
                 return FALSE;
               }
             *pl = pushPl;
index b0427df82d63622e246383d8698565cf3d771910..093b84dde84d18c9067d12af28b150637984b13a 100644 (file)
@@ -1,8 +1,8 @@
-# Makefile for Borlad C++
+# Makefile for Borland C++
 
 PRJDIR = ../..
 
-OBJ = gen.obj ralloc.obj main.obj support.obj
+OBJ = gen.obj ralloc.obj main.obj support.obj peep.obj
 LIB = port.lib
 
 !include $(PRJDIR)/Bcc.inc
index 1900dbc65ebb63cbbd3d98a6ca200e3e64a39eac..03aae37ae3ad1dff9790e34b3505df2ae453b087 100644 (file)
-/*-------------------------------------------------------------------------
-  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 {werror(E_INTERNAL_ERROR, __FILE__, __LINE__, "error in notUsed()");}
-
-/*#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;
-}
-
+/*-------------------------------------------------------------------------\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
index 7e9d5c9e5645f50c0fd2451f343b70bffc210b94..eb7774803a8519f7d558ae2443393db670f6a270 100644 (file)
@@ -102,6 +102,10 @@ SOURCE=.\main.c
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\peep.c\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\ralloc.c\r
 # End Source File\r
 # Begin Source File\r
@@ -122,6 +126,10 @@ SOURCE=.\gen.h
 # End Source File\r
 # Begin Source File\r
 \r
+SOURCE=.\peep.h\r
+# End Source File\r
+# Begin Source File\r
+\r
 SOURCE=.\ralloc.h\r
 # End Source File\r
 # Begin Source File\r
diff --git a/support/regression/tests/bug1839321.c b/support/regression/tests/bug1839321.c
new file mode 100644 (file)
index 0000000..3ed58d7
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+    bug 1839321
+*/
+
+#include <testfwk.h>
+
+xdata char Global = 2;
+
+code struct Value {
+  char xdata * Name[2];
+} Value_1 = {{&Global, 0}},
+  Value_2 = {{&Global, 0}};
+
+char i = 1;
+
+// note: this function expects its first parameter to be passed in
+//        2 bytes on **stack** (not registers)
+char bar(char xdata* code* ptr, ...)
+{
+       return **ptr;
+}
+
+void foo (void) {
+}
+
+
+void
+testBug(void)
+{
+       ASSERT (bar(i ? Value_1.Name : Value_2.Name) == 2);
+}