]> git.sur5r.net Git - cc65/commitdiff
Working on the backend
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 May 2001 21:42:58 +0000 (21:42 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 5 May 2001 21:42:58 +0000 (21:42 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@718 b7a2c559-68d2-44c3-8de9-860c34a00d81

14 files changed:
src/cc65/codeent.c
src/cc65/codeent.h
src/cc65/codegen.c
src/cc65/codegen.h
src/cc65/codeinfo.c
src/cc65/codelab.c
src/cc65/codelab.h
src/cc65/codeopt.c
src/cc65/codeseg.c
src/cc65/codeseg.h
src/cc65/datatype.c
src/cc65/function.c
src/cc65/opcodes.c
src/cc65/opcodes.h

index bdf8d268a8c050de4e81cbc286558713c49b1bd4..d8f852bc9507c6429d8f22f724d263f4f27079c9 100644 (file)
@@ -73,6 +73,7 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
     E->Arg     = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
     E->Num     = 0;
     E->Flags   = 0;
+    E->Info    = D->Info;
     E->Use     = D->Use;
     E->Chg     = D->Chg;
     if (E->OPC == OPC_JSR && E->Arg) {
@@ -119,6 +120,51 @@ int CodeEntryHasLabel (const CodeEntry* E)
 
 
 
+int CodeEntryHasMark (const CodeEntry* E)
+/* Return true if the given code entry has the CEF_USERMARK flag set */
+{
+    return (E->Flags & CEF_USERMARK) != 0;
+}
+
+
+
+void CodeEntrySetMark (CodeEntry* E)
+/* Set the CEF_USERMARK flag for the given entry */
+{
+    E->Flags |= CEF_USERMARK;
+}
+
+
+
+void CodeEntryResetMark (CodeEntry* E)
+/* Reset the CEF_USERMARK flag for the given entry */
+{
+    E->Flags &= ~CEF_USERMARK;
+}
+
+
+
+CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
+/* Get a label from this code entry */
+{
+    return CollAt (&E->Labels, Index);
+}
+
+
+
+void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
+/* Move the code label L from it's former owner to the code entry E. */
+{
+    /* Delete the label from the owner */
+    CollDeleteItem (&L->Owner->Labels, L);
+
+    /* Set the new owner */
+    CollAppend (&E->Labels, L);
+    L->Owner = E;
+}
+
+
+
 void OutputCodeEntry (const CodeEntry* E, FILE* F)
 /* Output the code entry to a file */
 {
index fbcc04e5ae9b0fb2b8eda2785405169855887285..ab0790989a656c3672ef913728b5c2017106baf4 100644 (file)
@@ -69,6 +69,7 @@ struct CodeEntry {
     char*                      Arg;            /* Argument as string */
     unsigned           Num;            /* Numeric argument */
     unsigned short     Flags;          /* Flags */
+    unsigned char      Info;           /* Additional code info */
     unsigned char      Use;            /* Registers used */
     unsigned char      Chg;            /* Registers changed/destroyed */
     CodeLabel*         JumpTo;         /* Jump label */
@@ -92,6 +93,21 @@ void FreeCodeEntry (CodeEntry* E);
 int CodeEntryHasLabel (const CodeEntry* E);
 /* Check if the given code entry has labels attached */
 
+int CodeEntryHasMark (const CodeEntry* E);
+/* Return true if the given code entry has the CEF_USERMARK flag set */
+
+void CodeEntrySetMark (CodeEntry* E);
+/* Set the CEF_USERMARK flag for the given entry */
+
+void CodeEntryResetMark (CodeEntry* E);
+/* Reset the CEF_USERMARK flag for the given entry */
+
+CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index);
+/* Get a label from this code entry */
+
+void MoveCodeLabel (CodeLabel* L, CodeEntry* E);
+/* Move the code label L from it's former owner to the code entry E. */
+
 void OutputCodeEntry (const CodeEntry* E, FILE* F);
 /* Output the code entry to a file */
 
index a41f9dfa21b8ff16b8eed04c5fcff62fa9a72778..81273b01396196ef79d500396e21f7c545f98169 100644 (file)
@@ -396,77 +396,41 @@ void g_enter (unsigned flags, unsigned argsize)
 
 
 
-void g_leave (int flags, int val)
+void g_leave (void)
 /* Function epilogue */
 {
-    int k;
-    char buf [40];
-
-    /* CF_REG is set if we're returning a value from the function */
-    if ((flags & CF_REG) == 0) {
-       AddCodeHint ("x:-");
-       AddCodeHint ("a:-");
-    }
-
     /* How many bytes of locals do we have to drop? */
-    k = -oursp;
+    int k = -oursp;
 
     /* If we didn't have a variable argument list, don't call leave */
     if (funcargs >= 0) {
 
-       /* Load a function return code if needed */
-       if ((flags & CF_CONST) != 0) {
-           g_getimmed (flags, val, 0);
-       }
-
-       /* Drop stackframe or leave with rts */
+       /* Drop stackframe if needed */
        k += funcargs;
-       if (k == 0) {
-           AddCodeHint ("y:-");        /* Y register no longer used */
-           AddCodeLine ("rts");
-       } else if (k <= 8) {
-           AddCodeHint ("y:-");        /* Y register no longer used */
-           AddCodeLine ("jmp incsp%d", k);
-       } else {
-           CheckLocalOffs (k);
-           ldyconst (k);
-           AddCodeLine ("jmp addysp");
+               if (k > 0) {
+           if (k <= 8) {
+           AddCodeLine ("jsr incsp%d", k);
+           } else {
+               CheckLocalOffs (k);
+               ldyconst (k);
+               AddCodeLine ("jsr addysp");
+           }
        }
 
     } else {
 
-       strcpy (buf, "\tjmp\tleave");
-       if (k) {
+       if (k == 0) {
+           /* Nothing to drop */
+           AddCodeLine ("jsr leave");
+       } else {
            /* We've a stack frame to drop */
            ldyconst (k);
-           strcat (buf, "y");
-       } else {
-           /* Y register no longer used */
-           AddCodeHint ("y:-");
+           AddCodeLine ("jsr leavey");
        }
-       if (flags & CF_CONST) {
-           if ((flags & CF_TYPE) != CF_LONG) {
-               /* Constant int sized value given for return code */
-               if (val == 0) {
-                   /* Special case: return 0 */
-                   strcat (buf, "00");
-                       } else if (((val >> 8) & 0xFF) == 0) {
-                   /* Special case: constant with high byte zero */
-                   ldaconst (val);             /* Load low byte */
-                   strcat (buf, "0");
-               } else {
-                   /* Others: arbitrary constant value */
-                   g_getimmed (flags, val, 0); /* Load value */
-               }
-           } else {
-               /* Constant long value: No shortcut possible */
-               g_getimmed (flags, val, 0);
-           }
-       }
-
-       /* Output the jump */
-       AddCodeLine (buf);
     }
+
+    /* Add the final rts */
+    AddCodeLine ("rts");
 }
 
 
index 02b9fadeee440a8ec2425799cb19c526c5c56859..7a37c98d3f32b821ea96c40645ff4861f8197acc 100644 (file)
@@ -206,7 +206,7 @@ void g_scale (unsigned flags, long val);
 void g_enter (unsigned flags, unsigned argsize);
 /* Function prologue */
 
-void g_leave (int flags, int val);
+void g_leave (void);
 /* Function epilogue */
 
 
index 0dc89acb1baf92fe185b55fce8850d69fc0128bd..1f89ef14a050c2fb4f9611ccf44860e02ffc0125 100644 (file)
@@ -36,6 +36,9 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* common */
+#include "coll.h"
+
 /* cc65 */
 #include "codeinfo.h"
 
@@ -95,6 +98,12 @@ static const FuncInfo FuncInfoTable[] = {
 };
 #define FuncInfoCount  (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
 
+/* Structure used to pass information to the RegValUsedInt1 and 2 functions */
+typedef struct RVUInfo RVUInfo;
+struct RVUInfo {
+    Collection VisitedLines;           /* Lines already visited */
+};
+
 
 
 /*****************************************************************************/
@@ -133,6 +142,201 @@ void GetFuncInfo (const char* Name, unsigned char* Use, unsigned char* Chg)
     }
 }
 
+                                       
+#if 0
+
+static unsigned RVUInt2 (Line* L,
+                        LineColl* LC,      /* To remember visited lines */
+                        unsigned Used,     /* Definitely used registers */
+                        unsigned Unused)   /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+    int I;
+
+    /* Check the following instructions. We classifiy them into primary
+     * loads (register value not used), neutral (check next instruction),
+     * and unknown (assume register was used).
+     */
+    while (1) {
+
+       unsigned R;
+
+       /* Get the next line and follow jumps */
+       do {
+
+           /* Handle jumps to local labels (continue there) */
+                   if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) {
+               /* Get the target of the jump */
+               L = GetTargetLine (L->Line+5);
+           }
+
+           /* Get the next line, skip local labels */
+           do {
+                       L = NextCodeSegLine (L);
+           } while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
+
+           /* Bail out if we're done */
+           if (L == 0 || IsExtLabel (L)) {
+               /* End of function reached */
+               goto ExitPoint;
+           }
+
+           /* Check if we had this line already. If so, bail out, if not,
+            * add it to the list of known lines.
+            */
+           if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
+               goto ExitPoint;
+           }
+
+       } while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
+
+       /* Special handling of code hints */
+               if (IsHintLine (L)) {
+
+           if (IsHint (L, "a:-") && (Used & REG_A) == 0) {
+               Unused |= REG_A;
+           } else if (IsHint (L, "x:-") && (Used & REG_X) == 0) {
+               Unused |= REG_X;
+           } else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) {
+               Unused |= REG_Y;
+           }
+
+       /* Special handling for branches */
+       } else if (LineMatchX (L, ShortBranches) >= 0 ||
+           LineMatchX (L, LongBranches) >= 0) {
+           const char* Target = L->Line+5;
+           if (Target[0] == 'L') {
+               /* Jump to local label. Check the register usage starting at
+                * the branch target and at the code following the branch.
+                * All registers that are unused in both execution flows are
+                * returned as unused.
+                */
+               unsigned U1, U2;
+                       U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
+               U1 = RVUInt1 (L, LC, Used, Unused);
+               return U1 | U2;         /* Used in any of the branches */
+           }
+       } else {
+
+           /* Search for the instruction in this line */
+           I = FindCmd (L);
+
+           /* If we don't find it, assume all other registers are used */
+           if (I < 0) {
+               break;
+           }
+
+           /* Evaluate the use flags, check for addressing modes */
+           R = CmdDesc[I].Use;
+           if (IsXAddrMode (L)) {
+               R |= REG_X;
+           } else if (IsYAddrMode (L)) {
+               R |= REG_Y;
+           }
+           if (R) {
+               /* Remove registers that were already new loaded */
+               R &= ~Unused;
+
+               /* Remember the remaining registers */
+               Used |= R;
+           }
+
+           /* Evaluate the load flags */
+           R = CmdDesc[I].Load;
+           if (R) {
+               /* Remove registers that were already used */
+               R &= ~Used;
+
+               /* Remember the remaining registers */
+               Unused |= R;
+           }
+
+       }
+
+               /* If we know about all registers, bail out */
+               if ((Used | Unused) == REG_ALL) {
+           break;
+       }
+    }
+
+ExitPoint:
+    /* Return to the caller the complement of all unused registers */
+    return ~Unused & REG_ALL;
+}
+
+
+
+static unsigned RVUInt1 (Line* L,
+                        LineColl* LC,      /* To remember visited lines */
+                        unsigned Used,     /* Definitely used registers */
+                        unsigned Unused)   /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+    /* Remember the current count of the line collection */
+    unsigned Count = LC->Count;
+
+    /* Call the worker routine */
+    unsigned R = RVUInt2 (L, LC, Used, Unused);
+
+    /* Restore the old count */
+    LC->Count = Count;
+
+    /* Return the result */
+    return R;
+}
+
+
+
+static unsigned RegValUsed (Line* Start)
+/* Check the next instructions after the one in L for register usage. If
+ * a register is used as an index, or in a store or other instruction, it
+ * is assumed to be used. If a register is loaded with a value, before it
+ * was used by one of the actions described above, it is assumed unused.
+ * If the end of the lookahead is reached, all registers that are uncertain
+ * are marked as used.
+ * The result of the search is returned.
+ */
+{
+    unsigned R;
+
+    /* Create a new line collection and enter the start line */
+    LineColl* LC = NewLineColl (256);
+    LCAddLine (LC, Start);
+
+    /* Call the recursive subfunction */
+    R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
+
+    /* Delete the line collection */
+    FreeLineColl (LC);
+
+    /* Return the registers used */
+    return R;
+}
+
+
+
+static int RegAUsed (Line* Start)
+/* Check if the value in A is used. */
+{
+    return (RegValUsed (Start) & REG_A) != 0;
+}
+
+
+
+static int RegXUsed (Line* Start)
+/* Check if the value in X is used. */
+{
+    return (RegValUsed (Start) & REG_X) != 0;
+}
+
+
+
+static int RegYUsed (Line* Start)
+/* Check if the value in Y is used. */
+{
+    return (RegValUsed (Start) & REG_Y) != 0;
+}
 
 
 
+#endif     
index 237e50a326113a3984ef74636fa56fc0878eba28..97ed7e3b8d8addcf6e0dca2aa5dcb577cac8ceeb 100644 (file)
@@ -34,6 +34,7 @@
 
 
 /* common */
+#include "check.h"
 #include "xmalloc.h"
 
 /* cc65 */
@@ -107,6 +108,30 @@ unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E)
 
 
 
+void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
+/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
+ * more references on return.
+ */
+{
+    /* Walk through all instructions referencing the old label */
+    unsigned Count = CollCount (&OldLabel->JumpFrom);
+    while (Count--) {
+
+       /* Get the instruction that references the old label */
+       CodeEntry* E = CollAt (&OldLabel->JumpFrom, Count);
+
+       /* Change the reference to the new label */
+       CHECK (E->JumpTo == OldLabel);
+       AddLabelRef (NewLabel, E);
+
+    }
+
+    /* There are no more references to the old label */
+    CollDeleteAll (&OldLabel->JumpFrom);
+}
+
+
+
 void OutputCodeLabel (const CodeLabel* L, FILE* F)
 /* Output the code label to a file */
 {
index 6198428625fcf0605350c98b9bb879062d047e0d..0aef14857b015242d922b6ffd356ac9e771bbe29 100644 (file)
@@ -95,6 +95,11 @@ void AddLabelRef (CodeLabel* L, struct CodeEntry* E);
 unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E);
 /* Remove a reference to this label, return the number of remaining references */
 
+void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel);
+/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
+ * more references on return.
+ */
+
 void OutputCodeLabel (const CodeLabel* L, FILE* F);
 /* Output the code label to a file */
 
index 72d425d830775edadd42c0cb598447d65a1e77c6..24193418748bf9eda60bd4a5756faa0d87bd754b 100644 (file)
@@ -80,12 +80,12 @@ static void OptDeadJumps (CodeSeg* S)
     while (I < Count-1) {
 
        /* Get the next entry */
-       E = CollAt (&S->Entries, I);
+       E = GetCodeEntry (S, I);
 
        /* Check if it's a branch, if it has a local target, and if the target
         * is the next instruction.
         */
-       if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
+       if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
 
            /* Delete the dead jump */
            DelCodeEntry (S, I);
@@ -131,13 +131,12 @@ static void OptDeadCode (CodeSeg* S)
     while (I < Count-1) {
 
        /* Get this entry */
-       CodeEntry* E = CollAt (&S->Entries, I);
+       CodeEntry* E = GetCodeEntry (S, I);
 
                /* Check if it's an unconditional branch, and if the next entry has
         * no labels attached
         */
-               if ((E->OPC == OPC_JMP || E->OPC == OPC_BRA || E->OPC == OPC_RTS || E->OPC == OPC_RTI) &&
-                   !CodeEntryHasLabel (CollAt (&S->Entries, I+1))) {
+               if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
 
            /* Delete the next entry */
            DelCodeEntry (S, I+1);
@@ -189,15 +188,17 @@ static void OptJumpCascades (CodeSeg* S)
        CodeLabel* NewLabel;
 
        /* Get this entry */
-       CodeEntry* E = CollAt (&S->Entries, I);
+       CodeEntry* E = GetCodeEntry (S, I);
 
                /* Check if it's a branch, if it has a label attached, and if the
-        * instruction at this label is also a branch.
+        * instruction at this label is also a branch, and (important) if
+        * both instructions are not identical.
         */
-       if (E->AM == AM_BRA                             &&
-           (OldLabel = E->JumpTo) != 0                 &&
-                   OldLabel->Owner->AM == AM_BRA               &&
-           (NewLabel = OldLabel->Owner->JumpTo) != 0) {
+               if (E->AM == AM_BRA                             &&      /* It's a branch */
+           (OldLabel = E->JumpTo) != 0                 &&      /* Label attached */
+                   OldLabel->Owner->AM == AM_BRA               &&      /* Jumps to a branch.. */
+           (NewLabel = OldLabel->Owner->JumpTo) != 0   &&      /* ..which has a label */
+           OldLabel->Owner != E) {                             /* And both are distinct */
 
            /* Get the instruction that has the new label attached */
            CodeEntry* N = OldLabel->Owner;
@@ -230,6 +231,99 @@ static void OptJumpCascades (CodeSeg* S)
 
 
 
+/*****************************************************************************/
+/*                            Optimize jsr/rts                              */
+/*****************************************************************************/
+
+
+
+static void OptRTS (CodeSeg* S)
+/* Optimize subroutine calls followed by an RTS. The subroutine call will get
+ * replaced by a jump. Don't bother to delete the RTS if it does not have a
+ * label, the dead code elimination should take care of it.
+ */
+{
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have less than 2 entries */
+    unsigned Count = CollCount (&S->Entries);
+    if (Count < 2) {
+       return;
+    }
+
+    /* Walk over all entries minus the last one */
+    I = 0;
+    while (I < Count-1) {
+
+       /* Get this entry */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+       /* Check if it's a subroutine call and if the following insn is RTS */
+       if (E->OPC == OPC_JSR && GetCodeEntry(S,I+1)->OPC == OPC_RTS) {
+
+           /* Change the jsr to a jmp */
+           E->OPC = OPC_JMP;
+
+           /* Change the opcode info to that of the jump */
+           E->Info = GetOPCInfo (OPC_JMP);
+                                          
+                   /* Remember, we had changes */
+           ++OptChanges;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+}
+
+
+
+/*****************************************************************************/
+/*                          Optimize jump targets                           */
+/*****************************************************************************/
+
+
+
+static void OptJumpTarget (CodeSeg* S)
+/* If the instruction preceeding an unconditional branch is the same as the
+ * instruction preceeding the jump target, the jump target may be moved
+ * one entry back. This is a size optimization, since the instruction before
+ * the branch gets removed.
+ */
+{
+    unsigned I;
+
+    /* Get the number of entries, bail out if we have not enough */
+    unsigned Count = CollCount (&S->Entries);
+    if (Count < 3) {
+       return;
+    }
+
+    /* Walk over all entries minus the first one */
+    I = 1;
+    while (I < Count) {
+
+       /* Get this entry and the entry before this one */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+       /* Check if we have a jump or branch, and a matching label */
+       if ((E->Info & OF_UBRA) != 0 && E->JumpTo) {
+
+                   /* Remember, we had changes */
+           ++OptChanges;
+
+       }
+
+       /* Next entry */
+       ++I;
+
+    }
+}
+
+
+
 /*****************************************************************************/
 /*                                          Code                                    */
 /*****************************************************************************/
@@ -243,9 +337,10 @@ void RunOpt (CodeSeg* S)
 
     /* Table with optimizer steps -  are called in this order */
     static const OptFunc OptFuncs [] = {
-       OptJumpCascades,        /* Optimize jump cascades */
-               OptDeadJumps,           /* Remove dead jumps */
-       OptDeadCode,            /* Remove dead code */
+       OptJumpCascades,        /* Optimize jump cascades */
+               OptDeadJumps,           /* Remove dead jumps */
+       OptDeadCode,            /* Remove dead code */
+       OptRTS,                 /* Change jsr/rts to jmp */
     };
 
     /* Repeat all steps until there are no more changes */
@@ -261,9 +356,9 @@ void RunOpt (CodeSeg* S)
        Flags = 1UL;
                for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
            if ((OptDisable & Flags) == 0) {
-               OptFuncs[I] (S);
+               OptFuncs[I] (S);
            } else if (Verbosity > 0 || Debug) {
-               printf ("Optimizer pass %u skipped\n", I);
+               printf ("Optimizer pass %u skipped\n", I);
            }
            Flags <<= 1;
        }
index 907f9db385bc4cbca8deb50abfb7b8401af27133..5c54b223154b1502c9a5356c1210630c08b44484 100644 (file)
 
 
 
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static void MoveLabelsToPool (CodeSeg* S, CodeEntry* E)
+/* Move the labels of the code entry E to the label pool of the code segment */
+{
+    unsigned LabelCount = CollCount (&E->Labels);
+    while (LabelCount--) {
+       CodeLabel* L = GetCodeLabel (E, LabelCount);
+       L->Flags &= ~LF_DEF;
+       L->Owner = 0;
+       CollAppend (&S->Labels, L);
+    }
+    CollDeleteAll (&E->Labels);
+}
+
+
+
+static CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
+/* Find the label with the given name. Return the label or NULL if not found */
+{
+    /* Get the first hash chain entry */
+    CodeLabel* L = S->LabelHash[Hash];
+
+    /* Search the list */
+    while (L) {
+       if (strcmp (Name, L->Name) == 0) {
+           /* Found */
+           break;
+       }
+       L = L->Next;
+    }
+    return L;
+}
+
+
+
 /*****************************************************************************/
 /*                   Functions for parsing instructions                     */
 /*****************************************************************************/
@@ -387,18 +427,66 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
 
 
 void DelCodeEntry (CodeSeg* S, unsigned Index)
-/* Delete an entry from the code segment. This includes deleting any associated
+/* Delete an entry from the code segment. This includes moving any associated
  * labels, removing references to labels and even removing the referenced labels
  * if the reference count drops to zero.
  */
 {
     /* Get the code entry for the given index */
-    CodeEntry* E = CollAt (&S->Entries, Index);
+    CodeEntry* E = GetCodeEntry (S, Index);
+
+    /* If the entry has a labels, we have to move this label to the next insn.
+     * If there is no next insn, move the label into the code segement label
+     * pool. The operation is further complicated by the fact that the next
+     * insn may already have a label. In that case change all reference to
+     * this label and delete the label instead of moving it.
+     */
+    unsigned Count = CollCount (&E->Labels);
+    if (Count > 0) {
+
+       /* The instruction has labels attached. Check if there is a next
+        * instruction.
+        */
+       if (Index == GetCodeSegEntries (S)-1) {
+
+           /* No next instruction, move to the codeseg label pool */
+           MoveLabelsToPool (S, E);
+
+       } else {
+
+           /* There is a next insn, get it */
+           CodeEntry* N = GetCodeEntry (S, Index+1);
+
+           /* Does this next insn have itself a label? */
+           if (CodeEntryHasLabel (N)) {
+
+               /* The next insn does already have a label - move references */
+               CodeLabel* NewLabel = GetCodeLabel (N, 0);
+               while (Count--) {
+
+                   /* Get the next label */
+                   CodeLabel* L = GetCodeLabel (E, Count);
 
-    /* Remove any labels associated with this entry */
-    unsigned Count;
-    while ((Count = CollCount (&E->Labels)) > 0) {
-       DelCodeLabel (S, CollAt (&E->Labels, Count-1));
+                   /* Move references */
+                   MoveLabelRefs (L, NewLabel);
+
+                   /* Delete the label */
+                   DelCodeLabel (S, L);
+
+               }
+
+           } else {
+
+               /* The next insn does not have a label, just move them */
+               while (Count--) {
+
+                   /* Move the label to the new entry */
+                   MoveCodeLabel (GetCodeLabel (E, Count), N);
+
+               }
+
+           }
+       }
     }
 
     /* If this insn references a label, remove the reference. And, if the
@@ -406,7 +494,7 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
      */
     if (E->JumpTo) {
 
-       /* Remove the reference */
+               /* Remove the reference */
                if (RemoveLabelRef (E->JumpTo, E) == 0) {
            /* No references remaining, remove the label */
            DelCodeLabel (S, E->JumpTo);
@@ -425,6 +513,14 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
 
 
 
+struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
+/* Get an entry from the given code segment */
+{
+    return CollAt (&S->Entries, Index);
+}
+
+
+
 void AddCodeLabel (CodeSeg* S, const char* Name)
 /* Add a code label for the next instruction to follow */
 {
@@ -504,7 +600,7 @@ void AddCodeSegHint (CodeSeg* S, unsigned Hint)
     CHECK (EntryCount > 0);
 
     /* Get the last entry */
-    E = CollAt (&S->Entries, EntryCount-1);
+    E = GetCodeEntry (S, EntryCount-1);
 
     /* Add the hint */
     E->Hints |= Hint;
@@ -522,19 +618,13 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
     while (Last < Count) {
 
        /* Get the next entry */
-       CodeEntry* E = CollAt (&S->Entries, Count-1);
+       CodeEntry* E = GetCodeEntry (S, Count-1);
 
        /* We have to transfer all labels to the code segment label pool */
-       unsigned LabelCount = CollCount (&E->Labels);
-       while (LabelCount--) {
-           CodeLabel* L = CollAt (&E->Labels, LabelCount);
-           L->Flags &= ~LF_DEF;
-           CollAppend (&S->Labels, L);
-       }
-       CollDeleteAll (&E->Labels);
+       MoveLabelsToPool (S, E);
 
        /* Remove the code entry */
-       FreeCodeEntry (CollAt (&S->Entries, Count-1));
+       FreeCodeEntry (E);
        CollDelete (&S->Entries, Count-1);
        --Count;
     }
@@ -576,25 +666,6 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
 
 
 
-CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
-/* Find the label with the given name. Return the label or NULL if not found */
-{
-    /* Get the first hash chain entry */
-    CodeLabel* L = S->LabelHash[Hash];
-
-    /* Search the list */
-    while (L) {
-       if (strcmp (Name, L->Name) == 0) {
-           /* Found */
-           break;
-       }
-       L = L->Next;
-    }
-    return L;
-}
-
-
-
 void MergeCodeLabels (CodeSeg* S)
 /* Merge code labels. That means: For each instruction, remove all labels but
  * one and adjust the code entries accordingly.
@@ -610,7 +681,7 @@ void MergeCodeLabels (CodeSeg* S)
        unsigned   J;
 
        /* Get a pointer to the next entry */
-       CodeEntry* E = CollAt (&S->Entries, I);
+       CodeEntry* E = GetCodeEntry (S, I);
 
        /* If this entry has zero labels, continue with the next one */
        unsigned LabelCount = CollCount (&E->Labels);
@@ -619,7 +690,7 @@ void MergeCodeLabels (CodeSeg* S)
        }
 
        /* We have at least one label. Use the first one as reference label. */
-       RefLab = CollAt (&E->Labels, 0);
+       RefLab = GetCodeLabel (E, 0);
 
        /* Walk through the remaining labels and change references to these
         * labels to a reference to the one and only label. Delete the labels
@@ -628,26 +699,11 @@ void MergeCodeLabels (CodeSeg* S)
         */
        for (J = LabelCount-1; J >= 1; --J) {
 
-           unsigned K;
-
            /* Get the next label */
-           CodeLabel* L = CollAt (&E->Labels, J);
-
-           /* Walk through all instructions referencing this label */
-           unsigned RefCount = CollCount (&L->JumpFrom);
-           for (K = 0; K < RefCount; ++K) {
-
-               /* Get the next instruction that references this label */
-               CodeEntry* E = CollAt (&L->JumpFrom, K);
-
-               /* Change the reference */
-               CHECK (E->JumpTo == L);
-               AddLabelRef (RefLab, E);
-
-           }
+           CodeLabel* L = GetCodeLabel (E, J);
 
-           /* There are no more instructions jumping to this label now */
-           CollDeleteAll (&L->JumpFrom);
+           /* Move all references from this label to the reference label */
+           MoveLabelRefs (L, RefLab);
 
                    /* Remove the label completely. */
                    DelCodeLabel (S, L);
index 4940f39d2f1ee548c090d67d18fe7920931e6835..e7a2fdaf1e9b58e6c0aea96b7f355f20ba4acfea 100644 (file)
 
 
 
+/*****************************************************************************/
+/*                                Forwards                                  */
+/*****************************************************************************/
+
+
+
+struct CodeEntry;
+
+
+
 /*****************************************************************************/
 /*                                  Data                                    */
 /*****************************************************************************/
@@ -85,11 +95,14 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap) attribute ((forma
 /* Add a line to the given code segment */
 
 void DelCodeEntry (CodeSeg* S, unsigned Index);
-/* Delete an entry from the code segment. This includes deleting any associated
+/* Delete an entry from the code segment. This includes moving any associated
  * labels, removing references to labels and even removing the referenced labels
  * if the reference count drops to zero.
  */
 
+struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index);
+/* Get an entry from the given code segment */
+
 void AddCodeLabel (CodeSeg* S, const char* Name);
 /* Add a code label for the next instruction to follow */
 
@@ -105,9 +118,6 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
 void OutputCodeSeg (const CodeSeg* S, FILE* F);
 /* Output the code segment data to a file */
 
-CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash);
-/* Find the label with the given name. Return the label or NULL if not found */
-
 void MergeCodeLabels (CodeSeg* S);
 /* Merge code labels. That means: For each instruction, remove all labels but
  * one and adjust the code entries accordingly.
index 1c2f0a3efbfc7f195ef87cd6ec38cde786348f8d..4da5470b98b8e84c20ad2860e49a6d5b0aa3b01c 100644 (file)
@@ -230,7 +230,7 @@ void PrintType (FILE* F, const type* Type)
 /* Output translation of type array. */
 {
     type T;
-
+    unsigned long Size;
 
     /* Walk over the complete string */
     while ((T = *Type++) != T_END) {
@@ -280,12 +280,20 @@ void PrintType (FILE* F, const type* Type)
                Type += DECODE_SIZE;
                break;
            case T_TYPE_ARRAY:
-                       fprintf (F, "array[%lu] of ", Decode (Type));
-               Type += DECODE_SIZE;
-               break;
+               /* Recursive call */
+               PrintType (F, Type + DECODE_SIZE);
+               Size = Decode (Type);
+               if (Size == 0) {
+                   fprintf (F, "[]");
+               } else {
+                   fprintf (F, "[%lu]", Size);
+               }
+               return;
            case T_TYPE_PTR:
-               fprintf (F, "pointer to ");
-               break;
+               /* Recursive call */
+               PrintType (F, Type);
+               fprintf (F, "*");
+               return;
            case T_TYPE_FUNC:
                fprintf (F, "function returning ");
                Type += DECODE_SIZE;
index 69b6536658375595e59aeeef39f8d02c8b28b723..463c4f2c6353e93093db2f20bfd8b63780634091 100644 (file)
@@ -215,7 +215,6 @@ void NewFunc (SymEntry* Func)
 {
     int HadReturn;
     int IsVoidFunc;
-    unsigned Flags;
 
     /* Get the function descriptor from the function entry */
     FuncDesc* D = Func->V.F.Func;
@@ -321,8 +320,7 @@ void NewFunc (SymEntry* Func)
     RestoreRegVars (!IsVoidFunc);
 
     /* Generate the exit code */
-    Flags = IsVoidFunc? CF_NONE : CF_REG;
-    g_leave (Flags, 0);
+    g_leave ();
 
     /* Eat the closing brace */
     ConsumeRCurly ();
@@ -337,7 +335,7 @@ void NewFunc (SymEntry* Func)
     LeaveFunctionLevel ();
 
     /* Switch back to the old segments */
-    PopSegments ();                  
+    PopSegments ();
 
     /* Reset the current function pointer */
     FreeFunction (CurrentFunc);
index fce75353020ad3fe8a23a362e4984a3cebc16915..11888de9ca4fa17d0e215ada9059ef4414150c9e 100644 (file)
@@ -58,17 +58,17 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
     { OPC_ADC, "adc", 0, REG_A,           REG_A,    OF_NONE    },
     { OPC_AND, "and", 0, REG_A,    REG_A,    OF_NONE   },
     { OPC_ASL, "asl", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_BRA    },
+    { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA   },
     { OPC_BIT, "bit", 0, REG_A,    REG_NONE, OF_NONE   },
-    { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_BRA    },
+    { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA   },
     { OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_BRA    },
+    { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA   },
     { OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE   },
     { OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE   },
     { OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE   },
@@ -85,16 +85,16 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
     { OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE   },
     { OPC_INX, "inx", 1, REG_X,    REG_X,    OF_NONE   },
     { OPC_INY, "iny", 1, REG_Y,    REG_Y,    OF_NONE   },
-    { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_BRA    },
+    { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA           },
+    { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA   },
     { OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_BRA    },
-    { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_BRA    },
+    { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA   },
+    { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA   },
     { OPC_LDA, "lda", 0, REG_NONE, REG_A,    OF_NONE   },
     { OPC_LDX, "ldx", 0, REG_NONE, REG_X,    OF_NONE   },
     { OPC_LDY, "ldy", 0, REG_NONE, REG_Y,    OF_NONE   },
@@ -111,8 +111,8 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
     { OPC_PLY, "ply", 1, REG_NONE, REG_Y,    OF_NONE   },
     { OPC_ROL, "rol", 0, REG_A,    REG_A,    OF_NONE   },
     { OPC_ROR, "ror", 0, REG_A,    REG_A,    OF_NONE   },
-    { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_NONE   },
-    { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_NONE   },
+    { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET    },
+    { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET    },
     { OPC_SBC, "sbc", 0, REG_A,    REG_A,    OF_NONE   },
     { OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE   },
     { OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE   },
@@ -214,6 +214,18 @@ const OPCDesc* GetOPCDesc (opc_t OPC)
 
 
 
+unsigned char GetOPCInfo (opc_t OPC)
+/* Get opcode information */
+{
+    /* Check the range */
+    PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
+
+    /* Return the info */
+    return OPCTable[OPC].Info;
+}
+
+
+
 unsigned char GetAMUseInfo (am_t AM)
 /* Get usage info for the given addressing mode (addressing modes that use
  * index registers return REG_r info for these registers).
@@ -234,7 +246,7 @@ unsigned char GetAMUseInfo (am_t AM)
 
 
 opc_t GetInverseBranch (opc_t OPC)
-/* Return a brahcn that reverse the condition of the branch given in OPC */
+/* Return a branch that reverse the condition of the branch given in OPC */
 {
     switch (OPC) {
        case OPC_BCC:   return OPC_BCS;
index 4f1126c73485c3a61daa3411350251c9f76adde2..bc827dd1a9ca4cbf67efe877cc4af9fc6ed155fb 100644 (file)
@@ -119,37 +119,41 @@ typedef enum {
     OPC_TXA,
     OPC_TXS,
     OPC_TYA,
-    OPC_COUNT                  /* Number of opcodes available */
+    OPC_COUNT                                  /* Number of opcodes available */
 } opc_t;
 
 /* Addressing modes (bitmapped). */
 typedef enum {
-    AM_IMP     = 0x0001,       /* implicit */
-    AM_ACC     = 0x0002,       /* accumulator */
-    AM_IMM     = 0x0004,       /* immidiate */
-    AM_ZP              = 0x0008,       /* zeropage */
-    AM_ZPX     = 0x0010,       /* zeropage,X */
-    AM_ABS     = 0x0020,       /* absolute */
-    AM_ABSX    = 0x0040,       /* absolute,X */
-    AM_ABSY            = 0x0080,       /* absolute,Y */
-    AM_ZPX_IND = 0x0100,       /* (zeropage,x) */
-    AM_ZP_INDY = 0x0200,       /* (zeropage),y */
-    AM_ZP_IND  = 0x0400,       /* (zeropage) */
-    AM_BRA     = 0x0800        /* branch */
+    AM_IMP             = 0x0001,               /* implicit */
+    AM_ACC             = 0x0002,               /* accumulator */
+    AM_IMM             = 0x0004,               /* immidiate */
+    AM_ZP              = 0x0008,               /* zeropage */
+    AM_ZPX             = 0x0010,               /* zeropage,X */
+    AM_ABS             = 0x0020,               /* absolute */
+    AM_ABSX            = 0x0040,               /* absolute,X */
+    AM_ABSY            = 0x0080,               /* absolute,Y */
+    AM_ZPX_IND         = 0x0100,               /* (zeropage,x) */
+    AM_ZP_INDY         = 0x0200,               /* (zeropage),y */
+    AM_ZP_IND          = 0x0400,               /* (zeropage) */
+    AM_BRA             = 0x0800                /* branch */
 } am_t;
 
 /* Opcode info */
-#define OF_NONE        0x0000U         /* No additional information */
-#define OF_BRA         0x0001U         /* Operation is a jump/branch */
+#define OF_NONE        0x0000U                 /* No additional information */
+#define OF_UBRA        0x0001U                 /* Unconditional branch */
+#define OF_CBRA        0x0002U                 /* Conditional branch */
+#define OF_RET         0x0004U                 /* Return from function */
+#define OF_BRA         (OF_UBRA|OF_CBRA)       /* Operation is a jump/branch */
+#define OF_DEAD        (OF_UBRA|OF_RET)        /* Dead end - no exec behind this point */
 
 /* Opcode description */
 typedef struct {
-    opc_t          OPC;        /* Opcode */
-    char                   Mnemo[4];   /* Mnemonic */
-    unsigned char   Size;              /* Size, 0 means "check addressing mode" */
-    unsigned char   Use;       /* Registers used by this insn */
-    unsigned char   Chg;       /* Registers changed/destroyed by this insn */
-    unsigned char   Info;      /* Additional information */
+    opc_t                  OPC;                /* Opcode */
+    char                   Mnemo[4];           /* Mnemonic */
+    unsigned char   Size;                      /* Size, 0 = check addressing mode */
+    unsigned char   Use;                       /* Registers used by this insn */
+    unsigned char   Chg;                       /* Registers changed by this insn */
+    unsigned char   Info;                      /* Additional information */
 } OPCDesc;
 
 
@@ -171,13 +175,16 @@ unsigned GetInsnSize (opc_t OPC, am_t AM);
 const OPCDesc* GetOPCDesc (opc_t OPC);
 /* Get an opcode description */
 
+unsigned char GetOPCInfo (opc_t OPC);
+/* Get opcode information */
+
 unsigned char GetAMUseInfo (am_t AM);
 /* Get usage info for the given addressing mode (addressing modes that use
  * index registers return REG_r info for these registers).
  */
 
 opc_t GetInverseBranch (opc_t OPC);
-/* Return a brahcn that reverse the condition of the branch given in OPC */
+/* Return a branch that reverse the condition of the branch given in OPC */