]> git.sur5r.net Git - cc65/blobdiff - src/cc65/codeseg.c
cleanup
[cc65] / src / cc65 / codeseg.c
index 1ca80601b154e315a0d60d93d019690a044921f8..ba89ccddad4742ba07d0c63b81ea2f2c3c532e84 100644 (file)
@@ -39,6 +39,7 @@
 /* common */
 #include "chartype.h"
 #include "check.h"
+#include "global.h"
 #include "hashstr.h"
 #include "strutil.h"
 #include "xmalloc.h"
@@ -48,7 +49,9 @@
 #include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
+#include "datatype.h"
 #include "error.h"
+#include "symentry.h"
 #include "codeseg.h"
 
 
@@ -65,7 +68,6 @@ static void MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
     unsigned LabelCount = GetCodeLabelCount (E);
     while (LabelCount--) {
        CodeLabel* L = GetCodeLabel (E, LabelCount);
-       L->Flags &= ~LF_DEF;
        L->Owner = 0;
        CollAppend (&S->Labels, L);
     }
@@ -153,7 +155,7 @@ static const char* SkipSpace (const char* S)
 
 
 static const char* ReadToken (const char* L, const char* Term,
-                             char* Buf, unsigned BufSize)
+                             char* Buf, unsigned BufSize)
 /* Read the next token into Buf, return the updated line pointer. The
  * token is terminated by one of the characters given in term.
  */
@@ -182,7 +184,7 @@ static const char* ReadToken (const char* L, const char* Term,
 
 
 
-static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
+static CodeEntry* ParseInsn (CodeSeg* S, LineInfo* LI, const char* L)
 /* Parse an instruction nnd generate a code entry from it. If the line contains
  * errors, output an error message and return NULL.
  * For simplicity, we don't accept the broad range of input a "real" assembler
@@ -195,7 +197,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
     am_t               AM = 0;         /* Initialize to keep gcc silent */
     char               Arg[64];
     char               Reg;
-    CodeEntry*         E;
+    CodeEntry*         E;
     CodeLabel*         Label;
 
     /* Mnemonic */
@@ -294,8 +296,15 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
            /* Absolute, maybe indexed */
            L = ReadToken (L, ",", Arg, sizeof (Arg));
            if (*L == '\0') {
-               /* Assume absolute */
-               AM = AM_ABS;
+               /* Absolute, zeropage or branch */
+               if ((OPC->Info & OF_BRA) != 0) {
+                   /* Branch */
+                   AM = AM_BRA;
+               } else if (IsZPName (Arg)) {
+                   AM = AM_ZP;
+               } else {
+                   AM = AM_ABS;
+               }
            } else if (*L == ',') {
                /* Indexed */
                L = SkipSpace (L+1);
@@ -306,7 +315,11 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
                    Reg = toupper (*L);
                    L = SkipSpace (L+1);
                    if (Reg == 'X') {
-                       AM = AM_ABSX;
+                       if (IsZPName (Arg)) {
+                           AM = AM_ZPX;
+                       } else {
+                           AM = AM_ABSX;
+                       }
                    } else if (Reg == 'Y') {
                        AM = AM_ABSY;
                    } else {
@@ -327,18 +340,10 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
      * if it does not exist. Ignore anything but local labels here.
      */
     Label = 0;
-    if ((OPC->Info & OF_BRA) != 0 && Arg[0] == 'L') {
-
-       unsigned Hash;
-
-       /* Addressing mode must be alsobute or something is really wrong */
-       CHECK (AM == AM_ABS);
-
-       /* Addressing mode is a branch/jump */
-       AM = AM_BRA;
+    if (AM == AM_BRA && Arg[0] == 'L') {
 
        /* Generate the hash over the label, then search for the label */
-       Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
+       unsigned Hash = HashStr (Arg) % CS_LABEL_HASH_SIZE;
        Label = FindCodeLabel (S, Arg, Hash);
 
        /* If we don't have the label, it's a forward ref - create it */
@@ -351,7 +356,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
     /* We do now have the addressing mode in AM. Allocate a new CodeEntry
      * structure and initialize it.
      */
-    E = NewCodeEntry (OPC, AM, Arg, Label);
+    E = NewCodeEntry (OPC->OPC, AM, Arg, Label, LI);
 
     /* Return the new code entry */
     return E;
@@ -360,7 +365,7 @@ static CodeEntry* ParseInsn (CodeSeg* S, const char* L)
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
@@ -382,13 +387,22 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
        S->LabelHash[I] = 0;
     }
 
+    /* If we have a function given, get the return type of the function.
+     * Assume ANY return type besides void will use the A and X registers.
+     */
+    if (S->Func && !IsTypeVoid (GetFuncReturn (Func->Type))) {
+       S->ExitRegs = REG_AX;
+    } else {
+       S->ExitRegs = REG_NONE;
+    }
+
     /* Return the new struct */
     return S;
 }
 
 
 
-void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
+void AddCodeEntry (CodeSeg* S, LineInfo* LI, const char* Format, va_list ap)
 /* Add a line to the given code segment */
 {
     const char* L;
@@ -421,7 +435,7 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
            break;
 
        default:
-           E = ParseInsn (S, L);
+           E = ParseInsn (S, LI, L);
            break;
     }
 
@@ -451,6 +465,17 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
 
 
 
+void InsertCodeEntry (CodeSeg* S, struct CodeEntry* E, unsigned Index)
+/* Insert the code entry at the index given. Following code entries will be
+ * moved to slots with higher indices.
+ */
+{
+    /* Insert the entry into the collection */
+    CollInsert (&S->Entries, E, Index);
+}
+
+
+
 void DelCodeEntry (CodeSeg* S, unsigned Index)
 /* Delete an entry from the code segment. This includes moving any associated
  * labels, removing references to labels and even removing the referenced labels
@@ -505,10 +530,76 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
 
 
 
-struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
-/* Get an entry from the given code segment */
+void DelCodeEntries (CodeSeg* S, unsigned Start, unsigned Count)
+/* Delete a range of code entries. This includes removing references to labels,
+ * labels attached to the entries and so on.
+ */
 {
-    return CollAt (&S->Entries, Index);
+    /* Start deleting the entries from the rear, because this involves less
+     * memory moving.
+     */
+    while (Count--) {
+       DelCodeEntry (S, Start + Count);
+    }
+}
+
+
+
+void MoveCodeEntry (CodeSeg* S, unsigned OldPos, unsigned NewPos)
+/* Move an entry from one position to another. OldPos is the current position
+ * of the entry, NewPos is the new position of the entry.
+ */
+{
+    /* Get the code entry and remove it from the collection */
+    CodeEntry* E = GetCodeEntry (S, OldPos);
+    CollDelete (&S->Entries, OldPos);
+
+    /* Correct NewPos if needed */
+    if (NewPos >= OldPos) {
+       /* Position has changed with removal */
+       --NewPos;
+    }
+
+    /* Now insert it at the new position */
+    CollInsert (&S->Entries, E, NewPos);
+}
+
+
+
+struct CodeEntry* GetNextCodeEntry (CodeSeg* S, unsigned Index)
+/* Get the code entry following the one with the index Index. If there is no
+ * following code entry, return NULL.
+ */
+{
+    if (Index >= CollCount (&S->Entries)-1) {
+       /* This is the last entry */
+       return 0;
+    } else {
+       /* Code entries left */
+               return CollAtUnchecked (&S->Entries, Index+1);
+    }
+}
+
+
+
+int GetCodeEntries (CodeSeg* S, struct CodeEntry** List,
+                           unsigned Start, unsigned Count)
+/* Get Count code entries into List starting at index start. Return true if
+ * we got the lines, return false if not enough lines were available.
+ */
+{
+    /* Check if enough entries are available */
+    if (Start + Count > CollCount (&S->Entries)) {
+       return 0;
+    }
+
+    /* Copy the entries */
+    while (Count--) {
+       *List++ = CollAtUnchecked (&S->Entries, Start++);
+    }
+
+    /* We have the entries */
+    return 1;
 }
 
 
@@ -610,7 +701,7 @@ void DelCodeLabel (CodeSeg* S, CodeLabel* L)
      * errors to slip through.
      */
     if (L->Owner) {
-       CollDeleteItem (&L->Owner->Labels, L);
+       CollDeleteItem (&L->Owner->Labels, L);
     }
 
     /* All references removed, delete the label itself */
@@ -737,7 +828,7 @@ void RemoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E)
 
     /* If there are no more references, delete the label */
     if (CollCount (&L->JumpFrom) == 0) {
-       DelCodeLabel (S, L);
+               DelCodeLabel (S, L);
     }
 }
 
@@ -764,55 +855,61 @@ void MoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
 
 
 
-void AddCodeSegHint (CodeSeg* S, unsigned Hint)
-/* Add a hint for the preceeding instruction */
-{
-    CodeEntry* E;
-
-    /* Get the number of entries in this segment */
-    unsigned EntryCount = GetCodeEntryCount (S);
-
-    /* Must have at least one entry */
-    CHECK (EntryCount > 0);
-
-    /* Get the last entry */
-    E = GetCodeEntry (S, EntryCount-1);
-
-    /* Add the hint */
-    E->Hints |= Hint;
-}
-
-
-
 void DelCodeSegAfter (CodeSeg* S, unsigned Last)
 /* Delete all entries including the given one */
 {
     /* Get the number of entries in this segment */
     unsigned Count = GetCodeEntryCount (S);
 
-    /* Check if we have to delete anything */
-    if (Last < Count) {
+    /* First pass: Delete all references to labels. If the reference count
+     * for a label drops to zero, delete it.
+     */
+    unsigned C = Count;
+    while (Last < C--) {
+
+       /* Get the next entry */
+       CodeEntry* E = GetCodeEntry (S, C);
+
+       /* Check if this entry has a label reference */
+       if (E->JumpTo) {
+           /* If the label is a label in the label pool and this is the last
+            * reference to the label, remove the label from the pool.
+            */
+           CodeLabel* L = E->JumpTo;
+           int Index = CollIndex (&S->Labels, L);
+           if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
+               /* Delete it from the pool */
+               CollDelete (&S->Labels, Index);
+           }
 
-       /* Remove all entries after the given one */
-       while (Last < Count--) {
+           /* Remove the reference to the label */
+           RemoveCodeLabelRef (S, E);
+       }
 
-           /* Get the next entry */
-           CodeEntry* E = GetCodeEntry (S, Count);
+    }
 
-           /* If the code entry has labels, delete them */
-           while (CodeEntryHasLabel (E)) {
+    /* Second pass: Delete the instructions. If a label attached to an
+     * instruction still has references, it must be references from outside
+     * the deleted area. Don't delete the label in this case, just make it
+     * ownerless and move it to the label pool.
+     */
+    C = Count;
+    while (Last < C--) {
 
-               /* Get the label */
-               CodeLabel* L = GetCodeLabel (E, 0);
+       /* Get the next entry */
+       CodeEntry* E = GetCodeEntry (S, C);
 
-               /* Delete it */
-               DelCodeLabel (S, L);
+       /* Check if this entry has a label attached */
+       if (CodeEntryHasLabel (E)) {
+           /* Move the labels to the pool and clear the owner pointer */
+           MoveLabelsToPool (S, E);
+       }
 
-           }
+       /* Delete the pointer to the entry */
+       CollDelete (&S->Entries, C);
 
-           /* Delete the entry itself */
-           DelCodeEntry (S, Count);
-       }
+       /* Delete the entry itself */
+       FreeCodeEntry (E);
     }
 }
 
@@ -822,6 +919,7 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
 /* Output the code segment data to a file */
 {
     unsigned I;
+    const LineInfo* LI;
 
     /* Get the number of entries in this segment */
     unsigned Count = GetCodeEntryCount (S);
@@ -839,9 +937,37 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
        fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
     }
 
-    /* Output all entries */
+    /* Output all entries, prepended by the line information if it has changed */
+    LI = 0;
     for (I = 0; I < Count; ++I) {
-       OutputCodeEntry (CollConstAt (&S->Entries, I), F);
+       /* Get the next entry */
+       const CodeEntry* E = CollConstAt (&S->Entries, I);
+       /* Check if the line info has changed. If so, output the source line
+        * if the option is enabled and output debug line info if the debug
+        * option is enabled.
+        */
+       if (E->LI != LI) {
+           /* Line info has changed, remember the new line info */
+           LI = E->LI;
+
+           /* Add the source line as a comment */
+           if (AddSource) {
+               fprintf (F, ";\n; %s\n;\n", LI->Line);
+           }
+
+           /* Add line debug info */
+           if (DebugInfo) {
+               fprintf (F, "\t.dbg\tline, \"%s\", %u\n",
+                        GetInputName (LI), GetInputLine (LI));
+           }
+       }
+       /* Output the code */
+       OutputCodeEntry (E, F);
+    }
+
+    /* If debug info is enabled, terminate the last line number information */
+    if (DebugInfo) {
+       fprintf (F, "\t.dbg\tline\n");
     }
 
     /* If this is a segment for a function, leave the function */
@@ -852,11 +978,6 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
 
 
 
-unsigned GetCodeEntryCount (const CodeSeg* S)
-/* Return the number of entries for the given code segment */
-{
-    return CollCount (&S->Entries);
-}