]> git.sur5r.net Git - cc65/commitdiff
Adjust SP on gotos between blocks with local variables.
authorlaubzega <mileksmyk@gmail.com>
Tue, 25 Sep 2018 07:56:08 +0000 (00:56 -0700)
committerOliver Schmidt <ol.sc@web.de>
Tue, 2 Oct 2018 16:49:53 +0000 (18:49 +0200)
src/cc65/codegen.c
src/cc65/codegen.h
src/cc65/symentry.h
src/cc65/symtab.c

index 9e510272813172c61533f77179cde7fde890d91b..c878c7bf698ead8d79e27f91e90d07b25f08966d 100644 (file)
@@ -2425,6 +2425,19 @@ void g_falsejump (unsigned flags attribute ((unused)), unsigned label)
 }
 
 
+void g_lateadjustSP (unsigned label)
+{
+/* Adjust stack based on non-immediate data */
+    AddCodeLine ("pha");
+    AddCodeLine ("lda %s", LocalLabelName (label));
+    AddCodeLine ("clc");
+    AddCodeLine ("adc sp");
+    AddCodeLine ("sta sp");
+    AddCodeLine ("lda %s+1", LocalLabelName (label));
+    AddCodeLine ("adc sp+1");
+    AddCodeLine ("sta sp+1");
+    AddCodeLine ("pla");
+}
 
 void g_drop (unsigned Space)
 /* Drop space allocated on the stack */
index bbad0f125eb6ab4c65e535a213c55b937b2fa847..6f61b33a6d92e101f4417ffc1eabca7b303a736d 100644 (file)
@@ -406,6 +406,9 @@ void g_truejump (unsigned flags, unsigned label);
 void g_falsejump (unsigned flags, unsigned label);
 /* Jump to label if zero flag set */
 
+void g_lateadjustSP (unsigned label);
+/* Adjust stack based on non-immediate data */
+
 void g_drop (unsigned Space);
 /* Drop space allocated on the stack */
 
index 24b647234f4d8321d0ce89967120abe4eb448c23..03a63a7d2cca6dc9b6a4cb51eeb5985ea4c444ec 100644 (file)
@@ -107,6 +107,9 @@ struct DefOrRef {
     unsigned            Line;
     long                LocalsBlockNum;
     unsigned            Flags;
+    int                 StackPtr;
+    unsigned            Depth;
+    unsigned            LateSP_Label;
 };
 
 /* Symbol table entry */
index fe3787f00c012f41d19c18e634f88493bed0d271..c2edcb344b0e41f16e66f0db106518df2ecabb34 100644 (file)
@@ -670,6 +670,9 @@ DefOrRef* AddDefOrRef(SymEntry* E, unsigned Flags)
     DOR->Line = GetCurrentLine ();
     DOR->LocalsBlockNum = (long)CollLast (&CurrentFunc->LocalsBlockStack);
     DOR->Flags = Flags;
+    DOR->StackPtr = StackPtr;
+    DOR->Depth = CollCount(&CurrentFunc->LocalsBlockStack);
+    DOR->LateSP_Label = GetLocalLabel();
 
     return DOR;
 }
@@ -679,7 +682,8 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
 /* Add a goto label to the label table */
 {
     unsigned i;
-    DefOrRef *DOR;
+    DefOrRef *DOR, *NewDOR;
+
     /* Do we have an entry with this name already? */
     SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
     if (Entry) {
@@ -689,6 +693,8 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
             Error ("Label `%s' is defined more than once", Name);
         }
 
+        NewDOR = AddDefOrRef (Entry, Flags);
+
         /* 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. */
@@ -698,13 +704,41 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
              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)) &&
+                (CollCount(&CurrentFunc->LocalsBlockStack) == DOR->Depth) &&
                 (DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)))
                 Error ("Goto from line %d to label \'%s\' can result in a "
                     "trashed stack", Flags & SC_DEF ? DOR->Line : GetCurrentLine (), Name);
-        }
+            */
+            if((DOR->Flags & SC_DEF) && (Flags & SC_REF)) {
+                /* We're processing a goto and here is its destination label.
+                 This means the difference between SP values is also known, so
+                 we simply emit SP adjustment code. */
+                 if(StackPtr != DOR->StackPtr)
+                    g_space(StackPtr - DOR->StackPtr);
+
+                if (CollCount(&CurrentFunc->LocalsBlockStack) <= DOR->Depth &&
+                    DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)) {
+                    Warning ("Goto from line %d to label \'%s\' can result in a "
+                        "trashed stack", DOR->Line, Name);
+                }
+            }
 
-        AddDefOrRef (Entry, Flags);
+            if((DOR->Flags & SC_REF) && (Flags & SC_DEF)) {
+                /* We're processing a label, let's update all gotos encountered
+                so far */
+                g_defdatalabel(DOR->LateSP_Label);
+                g_defdata(CF_CONST | CF_INT, StackPtr - DOR->StackPtr, 0);
+
+                if (CollCount(&CurrentFunc->LocalsBlockStack) >= DOR->Depth &&
+                    DOR->LocalsBlockNum != (long)CollLast (&CurrentFunc->LocalsBlockStack)) {
+                    Warning ("Goto from line %d to label \'%s\' can result in a "
+                        "trashed stack", DOR->Line, Name);
+                }
+             }
+
+        }
 
         Entry->Flags |= Flags;
 
@@ -718,7 +752,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 +762,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)) {
+        g_lateadjustSP(NewDOR->LateSP_Label);
+    }
+
     /* Return the entry */
     return Entry;
 }