From 2ac2ffcd430a412241a25c6dcb5645a7343a645f Mon Sep 17 00:00:00 2001 From: laubzega Date: Tue, 25 Sep 2018 00:56:08 -0700 Subject: [PATCH] Adjust SP on gotos between blocks with local variables. --- src/cc65/codegen.c | 13 +++++++++++++ src/cc65/codegen.h | 3 +++ src/cc65/symentry.h | 3 +++ src/cc65/symtab.c | 47 +++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index 9e5102728..c878c7bf6 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -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 */ diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index bbad0f125..6f61b33a6 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -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 */ diff --git a/src/cc65/symentry.h b/src/cc65/symentry.h index 24b647234..03a63a7d2 100644 --- a/src/cc65/symentry.h +++ b/src/cc65/symentry.h @@ -107,6 +107,9 @@ struct DefOrRef { unsigned Line; long LocalsBlockNum; unsigned Flags; + int StackPtr; + unsigned Depth; + unsigned LateSP_Label; }; /* Symbol table entry */ diff --git a/src/cc65/symtab.c b/src/cc65/symtab.c index fe3787f00..c2edcb344 100644 --- a/src/cc65/symtab.c +++ b/src/cc65/symtab.c @@ -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); - AddDefOrRef (Entry, Flags); + 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); + } + } + + 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; }