]> git.sur5r.net Git - cc65/blobdiff - src/cc65/symtab.c
Stack adjustment code optimizations.
[cc65] / src / cc65 / symtab.c
index 51b43b4c91a7c04df2f3e52f560522353ca82873..8db6a741c8c1ad547c89e5a96e1225d78557fc4f 100644 (file)
@@ -92,7 +92,7 @@ static SymTable*        SymTab          = 0;
 static SymTable*        TagTab0         = 0;
 static SymTable*        TagTab          = 0;
 static SymTable*        LabelTab        = 0;
-
+static SymTable*        SPAdjustTab     = 0;
 
 
 /*****************************************************************************/
@@ -225,6 +225,8 @@ void EnterGlobalLevel (void)
 
     /* Create and assign the tag table */
     TagTab0 = TagTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
+
+    SPAdjustTab = NewSymTable (SYMTAB_SIZE_GLOBAL);
 }
 
 
@@ -405,7 +407,7 @@ void LeaveStructLevel (void)
 
 
 
-static SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned Hash)
+SymEntry* FindSymInTable (const SymTable* T, const char* Name, unsigned Hash)
 /* Search for an entry in one table */
 {
     /* Get the start of the hash chain */
@@ -660,7 +662,7 @@ SymEntry* AddConstSym (const char* Name, const Type* T, unsigned Flags, long Val
 }
 
 
-DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags)
+DefOrRef* AddDefOrRef (SymEntry* E, unsigned Flags)
 /* Add definition or reference to the SymEntry and preserve its attributes */
 {
     DefOrRef *DOR;
@@ -668,18 +670,37 @@ DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags)
     DOR = xmalloc (sizeof (DefOrRef));
     CollAppend (E->V.L.DefsOrRefs, DOR);
     DOR->Line = GetCurrentLine ();
-    DOR->LocalsBlockNum = (long)CollLast (&CurrentFunc->LocalsBlockStack);
+    DOR->LocalsBlockId = (long)CollLast (&CurrentFunc->LocalsBlockStack);
     DOR->Flags = Flags;
+    DOR->StackPtr = StackPtr;
+    DOR->Depth = CollCount (&CurrentFunc->LocalsBlockStack);
+    DOR->LateSP_Label = GetLocalLabel ();
 
     return DOR;
 }
 
+unsigned short FindSPAdjustment (const char* Name)
+{
+    SymEntry* Entry = FindSymInTable (SPAdjustTab, Name, HashStr (Name));
+
+    if (Entry) {
+            printf("L: %s sa: %d\n", Name, Entry->V.G.SPAdjustment);
+            return Entry->V.G.SPAdjustment;
+    }
+
+    Fatal("ICE: No label entry found");
+
+    return 0;
+}
 
 SymEntry* AddLabelSym (const char* Name, unsigned Flags)
 /* Add a goto label to the label table */
 {
     unsigned i;
-    DefOrRef *DOR;
+    DefOrRef *DOR, *NewDOR;
+    /* We juggle it so much that a shortcut will help with clarity */
+    Collection *AIC = &CurrentFunc->LocalsBlockStack;
+
     /* Do we have an entry with this name already? */
     SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
     if (Entry) {
@@ -689,22 +710,61 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
             Error ("Label `%s' is defined more than once", Name);
         }
 
-        /* Walk through all occurrences of the label so far and check
-           if any of them is in a region that would be risky to jump from/to
-           from the place where we are right now. */
+        NewDOR = AddDefOrRef (Entry, Flags);
+
+        /* Walk through all occurrences of the label so far and evaluate
+        ** their relationship with the one passed to the function.
+        */
         for (i = 0; i < CollCount (Entry->V.L.DefsOrRefs); i++) {
             DOR = CollAt (Entry->V.L.DefsOrRefs, i);
-            /* We are only interested in label occurences of type opposite to
-             the one currently being added, i.e.  if we are processing the
-             definition, we will only check the gotos; if we are processing
-             a goto statement, we will only look for the label definition. */
-            if (((DOR->Flags & SC_DEF) != (Flags & SC_DEF)) &&
-                (DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)))
-                Warning ("Goto from line %d to label \'%s\' can result in a "
-                    "trashed stack", Flags & SC_DEF ? DOR->Line : GetCurrentLine (), Name);
-        }
 
-        AddDefOrRef (Entry, Flags);
+            if ((DOR->Flags & SC_DEF) && (Flags & SC_REF) && (Flags & SC_GOTO)) {
+                /* We're processing a goto and here is its destination label.
+                ** This means the difference between SP values is already known,
+                ** so we simply emit the SP adjustment code.
+                */
+                if (StackPtr != DOR->StackPtr) {
+                    g_space (StackPtr - DOR->StackPtr);
+                }
+
+                /* Are we jumping into a block with initalization of an object that
+                ** has automatic storage duration? Let's emit a warning.
+                */
+                if ((long)CollLast (AIC) != DOR->LocalsBlockId &&
+                    (CollCount (AIC) < DOR->Depth ||
+                    (long)CollAt (AIC, DOR->Depth - 1) != DOR->LocalsBlockId)) {
+                    Warning ("Goto at line %d to label %s jumps into a block with "
+                    "initialization of an object that has automatic storage duration",
+                    GetCurrentLine (), Name);
+                }
+            }
+
+
+            if ((DOR->Flags & SC_REF) && (DOR->Flags & SC_GOTO) && (Flags & SC_DEF)) {
+                /* We're processing a label, let's update all gotos encountered
+                ** so far
+                */
+                SymEntry *E;
+                g_userodata();
+                g_defdatalabel (DOR->LateSP_Label);
+                g_defdata (CF_CONST | CF_INT, StackPtr - DOR->StackPtr, 0);
+                E = NewSymEntry (LocalLabelName(DOR->LateSP_Label), SC_SPADJUSTMENT);
+                E->V.G.SPAdjustment = StackPtr - DOR->StackPtr;
+                AddSymEntry (SPAdjustTab, E);
+
+
+                /* Are we jumping into a block with initalization of an object that
+                ** has automatic storage duration? Let's emit a warning.
+                */
+                if ((long)CollLast (AIC) != DOR->LocalsBlockId &&
+                    (CollCount (AIC) >= DOR->Depth ||
+                    (long)CollLast (AIC) >= (long)DOR->Line))
+                    Warning ("Goto at line %d to label %s jumps into a block with "
+                    "initialization of an object that has automatic storage duration",
+                    DOR->Line, Name);
+             }
+
+        }
 
         Entry->Flags |= Flags;
 
@@ -718,7 +778,7 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
 
         /* Create Collection for label definition and references */
         Entry->V.L.DefsOrRefs = NewCollection ();
-        AddDefOrRef (Entry, Flags);
+        NewDOR = AddDefOrRef (Entry, Flags);
 
         /* Generate the assembler name of the label */
         Entry->AsmName = xstrdup (LocalLabelName (Entry->V.L.Label));
@@ -728,6 +788,11 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
 
     }
 
+    /* We are processing a goto, but the label has not yet been defined */
+    if (!SymIsDef (Entry) && (Flags & SC_REF) && (Flags & SC_GOTO)) {
+        g_lateadjustSP (NewDOR->LateSP_Label);
+    }
+
     /* Return the entry */
     return Entry;
 }
@@ -792,9 +857,15 @@ SymEntry* AddGlobalSym (const char* Name, const Type* T, unsigned Flags)
     /* Do we have an entry with this name already? */
     SymEntry* Entry = FindSymInTable (Tab, Name, HashStr (Name));
     if (Entry) {
-
         Type* EType;
 
+        /* If the existing symbol is an enumerated constant,
+        ** then avoid a compiler crash.  See GitHub issue #728.
+        */
+        if (Entry->Flags & SC_ENUM) {
+            Fatal ("Can't redeclare enum constant `%s' as global variable", Name);
+        }
+
         /* We have a symbol with this name already */
         if (Entry->Flags & SC_TYPE) {
             Error ("Multiple definition for `%s'", Name);