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

src/cc65/asmcode.c
src/cc65/codeent.c
src/cc65/codeent.h
src/cc65/codelab.c
src/cc65/codelab.h
src/cc65/codeopt.c
src/cc65/codeseg.c
src/cc65/codeseg.h
src/cc65/opcodes.c
src/cc65/opcodes.h

index 046043f2b43c6fa8cf9dbb3379e6bd1396d4b056..b139af1c8510c39a8bdbf7e4515d5ce79f32a8a6 100644 (file)
@@ -63,7 +63,7 @@ void AddCodeHint (const char* Hint)
 CodeMark GetCodePos (void)
 /* Get a marker pointing to the current output position */
 {
-    return GetCodeSegEntries (CS->Code);
+    return GetCodeEntryCount (CS->Code);
 }
 
 
@@ -83,7 +83,7 @@ void WriteOutput (FILE* F)
     SymEntry* Entry;
 
     /* Output the global data segment */
-    CHECK (GetCodeSegEntries (CS->Code) == 0);
+    CHECK (GetCodeEntryCount (CS->Code) == 0);
     OutputSegments (CS, F);
 
     /* Output all global or referenced functions */
index d8f852bc9507c6429d8f22f724d263f4f27079c9..f2661e1e5e9379b93ca48a52f6653d60d1ceaa7d 100644 (file)
@@ -33,6 +33,8 @@
 
 
 
+#include <string.h>
+
 /* common */
 #include "check.h"
 #include "xmalloc.h"
 
 
 
+/* Empty argument */
+static char EmptyArg[] = "";
+
+
+
+/*****************************************************************************/
+/*                            Helper functions                              */
+/*****************************************************************************/
+
+
+
+static void FreeArg (char* Arg)
+/* Free a code entry argument */
+{
+    if (Arg != EmptyArg) {
+       xfree (Arg);
+    }
+}
+
+
+
+static char* GetArgCopy (const char* Arg)
+/* Create an argument copy for assignment */
+{
+    if (Arg && Arg[0] != '\0') {
+       /* Create a copy */
+       return xstrdup (Arg);
+    } else {
+       /* Use the empty argument string */
+       return EmptyArg;
+    }
+}
+
+
+
 /*****************************************************************************/
 /*                                          Code                                    */
 /*****************************************************************************/
@@ -70,17 +107,17 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
     E->AM      = AM;
     E->Size    = GetInsnSize (E->OPC, E->AM);
     E->Hints   = 0;
-    E->Arg     = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
+    E->Arg             = GetArgCopy (Arg);
     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) {
-       /* A subroutine call */
+    if (E->OPC == OPC_JSR) {
+       /* A subroutine call */
        GetFuncInfo (E->Arg, &E->Use, &E->Chg);
     } else {
-       /* Some other instruction */
+       /* Some other instruction */
        E->Use |= GetAMUseInfo (AM);
     }
     E->JumpTo  = JumpTo;
@@ -88,7 +125,7 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
 
     /* If we have a label given, add this entry to the label */
     if (JumpTo) {
-       CollAppend (&JumpTo->JumpFrom, E);
+       CollAppend (&JumpTo->JumpFrom, E);
     }
 
     /* Return the initialized struct */
@@ -101,7 +138,7 @@ void FreeCodeEntry (CodeEntry* E)
 /* Free the given code entry */
 {
     /* Free the string argument if we have one */
-    xfree (E->Arg);
+    FreeArg (E->Arg);
 
     /* Cleanup the collection */
     DoneCollection (&E->Labels);
@@ -112,34 +149,41 @@ void FreeCodeEntry (CodeEntry* E)
 
 
 
-int CodeEntryHasLabel (const CodeEntry* E)
-/* Check if the given code entry has labels attached */
+int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
+/* Check if both code entries are equal */
 {
-    return (CollCount (&E->Labels) > 0);
+    return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
 }
 
 
 
-int CodeEntryHasMark (const CodeEntry* E)
-/* Return true if the given code entry has the CEF_USERMARK flag set */
+void AttachCodeLabel (CodeEntry* E, CodeLabel* L)
+/* Attach the label to the entry */
 {
-    return (E->Flags & CEF_USERMARK) != 0;
+    /* Mark the label as defined */
+    L->Flags |= LF_DEF;
+
+    /* Add it to the entries label list */
+    CollAppend (&E->Labels, L);
+
+    /* Tell the label about it's owner */
+    L->Owner = E;
 }
 
 
 
-void CodeEntrySetMark (CodeEntry* E)
-/* Set the CEF_USERMARK flag for the given entry */
+int CodeEntryHasLabel (const CodeEntry* E)
+/* Check if the given code entry has labels attached */
 {
-    E->Flags |= CEF_USERMARK;
+    return (CollCount (&E->Labels) > 0);
 }
 
 
 
-void CodeEntryResetMark (CodeEntry* E)
-/* Reset the CEF_USERMARK flag for the given entry */
+unsigned GetCodeLabelCount (const CodeEntry* E)
+/* Get the number of labels attached to this entry */
 {
-    E->Flags &= ~CEF_USERMARK;
+    return CollCount (&E->Labels);
 }
 
 
@@ -165,11 +209,48 @@ void MoveCodeLabel (CodeLabel* L, 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;
+}
+
+
+
+void CodeEntrySetArg (CodeEntry* E, const char* Arg)
+/* Set a new argument for the given code entry. An old string is deleted. */
+{
+    /* Free the old argument */
+    FreeArg (E->Arg);
+
+    /* Assign the new one */
+    E->Arg = GetArgCopy (Arg);
+}
+
+
+
 void OutputCodeEntry (const CodeEntry* E, FILE* F)
 /* Output the code entry to a file */
 {
     const OPCDesc* D;
     unsigned Chars;
+    const char* Target;
 
     /* If we have a label, print that */
     unsigned LabelCount = CollCount (&E->Labels);
@@ -235,8 +316,8 @@ void OutputCodeEntry (const CodeEntry* E, FILE* F)
 
        case AM_BRA:
            /* branch */
-           CHECK (E->JumpTo != 0);
-           Chars += fprintf (F, "%*s%s", 9-Chars, "", E->JumpTo->Name);
+           Target = E->JumpTo? E->JumpTo->Name : E->Arg;
+           Chars += fprintf (F, "%*s%s", 9-Chars, "", Target);
            break;
 
        default:
index ab0790989a656c3672ef913728b5c2017106baf4..ba704eb2836ffb08f9f47b37485a29a3934e2151 100644 (file)
@@ -90,9 +90,24 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
 void FreeCodeEntry (CodeEntry* E);
 /* Free the given code entry */
 
+int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2);
+/* Check if both code entries are equal */
+
+void AttachCodeLabel (CodeEntry* E, CodeLabel* L);
+/* Attach the label to the entry */
+
 int CodeEntryHasLabel (const CodeEntry* E);
 /* Check if the given code entry has labels attached */
 
+unsigned GetCodeLabelCount (const CodeEntry* E);
+/* Get the number of labels attached to this 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. */
+
 int CodeEntryHasMark (const CodeEntry* E);
 /* Return true if the given code entry has the CEF_USERMARK flag set */
 
@@ -102,11 +117,8 @@ void CodeEntrySetMark (CodeEntry* E);
 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 CodeEntrySetArg (CodeEntry* E, const char* Arg);
+/* Set a new argument for the given code entry. An old string is deleted. */
 
 void OutputCodeEntry (const CodeEntry* E, FILE* F);
 /* Output the code entry to a file */
index 97ed7e3b8d8addcf6e0dca2aa5dcb577cac8ceeb..89b45b0e6d4d9a0fb45699aad9460ea584fa11db 100644 (file)
@@ -96,18 +96,6 @@ 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 */
-{
-    /* Delete the item */
-    CollDeleteItem (&L->JumpFrom, E);
-
-    /* Return the number of remaining references */
-    return CollCount (&L->JumpFrom);
-}
-
-
-
 void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
 /* Move all references to OldLabel to point to NewLabel. OldLabel will have no
  * more references on return.
index 0aef14857b015242d922b6ffd356ac9e771bbe29..bd24fc5d5cad584a7ed958b85f1b9edd2c289860 100644 (file)
@@ -92,9 +92,6 @@ void FreeCodeLabel (CodeLabel* L);
 void AddLabelRef (CodeLabel* L, struct CodeEntry* E);
 /* Let the CodeEntry E reference the label L */
 
-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.
index 24193418748bf9eda60bd4a5756faa0d87bd754b..90417a53734e7343516455c2f34f15776b255e28 100644 (file)
@@ -37,6 +37,7 @@
 #include "print.h"
 
 /* cc65 */
+#include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
 #include "global.h"
@@ -70,7 +71,7 @@ static void OptDeadJumps (CodeSeg* S)
     unsigned I;
 
     /* Get the number of entries, bail out if we have less than two entries */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
     if (Count < 2) {
        return;
     }
@@ -121,7 +122,7 @@ static void OptDeadCode (CodeSeg* S)
     unsigned I;
 
     /* Get the number of entries, bail out if we have less than two entries */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
     if (Count < 2) {
        return;
     }
@@ -175,7 +176,7 @@ static void OptJumpCascades (CodeSeg* S)
     unsigned I;
 
     /* Get the number of entries, bail out if we have no entries */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
     if (Count == 0) {
        return;
     }
@@ -184,45 +185,72 @@ static void OptJumpCascades (CodeSeg* S)
     I = 0;
     while (I < Count) {
 
-       CodeLabel* OldLabel;
-       CodeLabel* NewLabel;
-
        /* Get this entry */
        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, and (important) if
-        * both instructions are not identical.
+               /* Check if it's a branch, if it has a jump label, and if this jump
+        * label is not attached to the instruction itself.
         */
-               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 */
+       if ((E->Info & OF_BRA) != 0 && E->JumpTo != 0 && E->JumpTo->Owner != E) {
+
+           /* Get the label this insn is branching to */
+           CodeLabel* OldLabel = E->JumpTo;
 
-           /* Get the instruction that has the new label attached */
-           CodeEntry* N = OldLabel->Owner;
+           /* Get the entry we're branching to */
+           CodeEntry* N = OldLabel->Owner;
 
-           /* Remove the reference to our label and delete it if this was
-            * the last reference.
+           /* If the entry we're branching to is not itself a branch, it is
+            * not what we're searching for.
             */
-           if (RemoveLabelRef (OldLabel, E) == 0) {
-               /* Delete it */
-               DelCodeLabel (S, OldLabel);
+           if ((N->Info & OF_BRA) == 0) {
+               goto NextEntry;
            }
 
-           /* Use the usage information from the new instruction */
-           E->Use = N->Use;
-           E->Chg = N->Chg;
+           /* Check if we can use the final target label. This is the case,
+            * if the target branch is an absolut branch, or if it is a
+            * conditional branch checking the same condition as the first one.
+            */
+           if ((N->Info & OF_UBRA) != 0 ||
+                       ((E->Info & OF_CBRA) != 0 &&
+                GetBranchCond (E->OPC)  == GetBranchCond (N->OPC))) {
+
+               /* This is a jump cascade and we may jump to the final target.
+                * If we have a label, move the reference to this label. If
+                * we don't have a label, use the argument instead.
+                */
+               if (N->JumpTo) {
+                   /* Move the reference to the new insn */
+                   MoveCodeLabelRef (S, E, N->JumpTo);
+               } else {
+                   /* Remove the reference to the old label */
+                   RemoveCodeLabelRef (S, E);
+               }
+
+               /* Use the new argument */
+               CodeEntrySetArg (E, N->Arg);
+
+               /* Use the usage information from the new instruction */
+               E->Use = N->Use;
+               E->Chg = N->Chg;
+
+               /* Remember, we had changes */
+               ++OptChanges;
+
+               /* Done */
+               goto NextEntry;
 
-           /* Use the new label */
-           AddLabelRef (NewLabel, E);
+           }
 
-           /* Remember ,we had changes */
-           ++OptChanges;
+           /* Check if both are conditional branches, and the condition of
+            * the second is the inverse of that of the first. In this case,
+            * the second branch will never be taken, and we may jump directly
+            * to the instruction behind this one.
+            */
+           goto NextEntry;
 
        }
 
+NextEntry:
        /* Next entry */
        ++I;
 
@@ -232,7 +260,7 @@ static void OptJumpCascades (CodeSeg* S)
 
 
 /*****************************************************************************/
-/*                            Optimize jsr/rts                              */
+/*                            Optimize jsr/rts                              */
 /*****************************************************************************/
 
 
@@ -246,7 +274,7 @@ static void OptRTS (CodeSeg* S)
     unsigned I;
 
     /* Get the number of entries, bail out if we have less than 2 entries */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
     if (Count < 2) {
        return;
     }
@@ -261,12 +289,11 @@ static void OptRTS (CodeSeg* S)
        /* 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 */
+           /* Change the jsr to a jmp and use the additional info for a jump */
+           E->OPC  = OPC_JMP;
+           E->AM   = AM_BRA;
            E->Info = GetOPCInfo (OPC_JMP);
-                                          
+
                    /* Remember, we had changes */
            ++OptChanges;
 
@@ -293,29 +320,76 @@ static void OptJumpTarget (CodeSeg* S)
  * the branch gets removed.
  */
 {
+    CodeEntry* E1;     /* Entry 1 */
+    CodeEntry* E2;     /* Entry 2 */
+    CodeEntry* T1;     /* Jump target entry 1 */
+    CodeEntry* T2;     /* Jump target entry 2 */
+    CodeLabel* TL1;    /* Target label 1 */
+    unsigned TI;       /* Target index */
     unsigned I;
 
     /* Get the number of entries, bail out if we have not enough */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
     if (Count < 3) {
        return;
     }
 
-    /* Walk over all entries minus the first one */
-    I = 1;
-    while (I < Count) {
+    /* Walk over the entries */
+    I = 0;
+    while (I < Count-1) {
 
-       /* Get this entry and the entry before this one */
-       CodeEntry* E = GetCodeEntry (S, I);
+       /* Get next entry */
+               E2 = GetCodeEntry (S, I+1);
 
        /* Check if we have a jump or branch, and a matching label */
-       if ((E->Info & OF_UBRA) != 0 && E->JumpTo) {
+               if ((E2->Info & OF_UBRA) != 0 && E2->JumpTo) {
+
+           /* Get the target instruction for the label */
+           T2 = E2->JumpTo->Owner;
+
+           /* Get the entry preceeding this one (if possible) */
+           TI = GetCodeEntryIndex (S, T2);
+           if (TI == 0) {
+               /* There is no entry before this one */
+               goto NextEntry;
+           }
+           T1 = GetCodeEntry (S, TI-1);
+
+           /* Get the entry preceeding the jump */
+           E1 = GetCodeEntry (S, I);
+
+           /* Check if both preceeding instructions are identical */
+           if (!CodeEntriesAreEqual (E1, T1)) {
+               /* Not equal, try next */
+               goto NextEntry;
+           }
+
+           /* Get the label for the instruction preceeding the jump target.
+            * This routine will create a new label if the instruction does
+            * not already have one.
+            */
+           TL1 = GenCodeLabel (S, T1);
+
+           /* Change the jump target to point to this new label */
+           MoveCodeLabelRef (S, E2, TL1);
+
+           /* If the instruction preceeding the jump has labels attached,
+            * move references to this label to the new label.
+            */
+           if (CodeEntryHasLabel (E1)) {
+               MoveCodeLabels (S, E1, T1);
+           }
+
+           /* Remove the entry preceeding the jump */
+           DelCodeEntry (S, I);
+           --Count;
 
                    /* Remember, we had changes */
            ++OptChanges;
 
        }
 
+NextEntry:
        /* Next entry */
        ++I;
 
@@ -325,7 +399,7 @@ static void OptJumpTarget (CodeSeg* S)
 
 
 /*****************************************************************************/
-/*                                          Code                                    */
+/*                                          Code                                    */
 /*****************************************************************************/
 
 
@@ -341,6 +415,7 @@ void RunOpt (CodeSeg* S)
                OptDeadJumps,           /* Remove dead jumps */
        OptDeadCode,            /* Remove dead code */
        OptRTS,                 /* Change jsr/rts to jmp */
+       OptJumpTarget,          /* Optimize jump targets */
     };
 
     /* Repeat all steps until there are no more changes */
index 5c54b223154b1502c9a5356c1210630c08b44484..62642e0bf101f686ca070ecc9652b773226264c5 100644 (file)
@@ -45,6 +45,7 @@
 #include "xsprintf.h"
 
 /* cc65 */
+#include "asmlabel.h"
 #include "codeent.h"
 #include "codeinfo.h"
 #include "error.h"
@@ -61,7 +62,7 @@
 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);
+    unsigned LabelCount = GetCodeLabelCount (E);
     while (LabelCount--) {
        CodeLabel* L = GetCodeLabel (E, LabelCount);
        L->Flags &= ~LF_DEF;
@@ -405,14 +406,12 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
        unsigned I;
        unsigned LabelCount = CollCount (&S->Labels);
        for (I = 0; I < LabelCount; ++I) {
+
            /* Get the label */
            CodeLabel* L = CollAt (&S->Labels, I);
-           /* Mark it as defined */
-           L->Flags |= LF_DEF;
-           /* Move it to the code entry */
-           CollAppend (&E->Labels, L);
-           /* Tell the label about it's owner */
-           L->Owner = E;
+
+           /* Attach it to the entry */
+           AttachCodeLabel (E, L);
        }
 
        /* Delete the transfered labels */
@@ -441,13 +440,13 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
      * 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);
+    unsigned Count = GetCodeLabelCount (E);
     if (Count > 0) {
 
        /* The instruction has labels attached. Check if there is a next
         * instruction.
         */
-       if (Index == GetCodeSegEntries (S)-1) {
+       if (Index == GetCodeEntryCount (S)-1) {
 
            /* No next instruction, move to the codeseg label pool */
            MoveLabelsToPool (S, E);
@@ -457,35 +456,9 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
            /* 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);
-
-                   /* Move references */
-                   MoveLabelRefs (L, NewLabel);
-
-                   /* Delete the label */
-                   DelCodeLabel (S, L);
+           /* Move labels to the next entry */
+           MoveCodeLabels (S, E, N);
 
-               }
-
-           } 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);
-
-               }
-
-           }
        }
     }
 
@@ -493,15 +466,8 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
      * the reference count for this label drops to zero, remove this label.
      */
     if (E->JumpTo) {
-
                /* Remove the reference */
-               if (RemoveLabelRef (E->JumpTo, E) == 0) {
-           /* No references remaining, remove the label */
-           DelCodeLabel (S, E->JumpTo);
-       }
-
-       /* Reset the label pointer to avoid problems later */
-       E->JumpTo = 0;
+               RemoveCodeLabelRef (S, E);
     }
 
     /* Delete the pointer to the insn */
@@ -521,6 +487,16 @@ struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
 
 
 
+unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E)
+/* Return the index of a code entry */
+{
+    int Index = CollIndex (&S->Entries, E);
+    CHECK (Index >= 0);
+    return Index;
+}
+
+
+
 void AddCodeLabel (CodeSeg* S, const char* Name)
 /* Add a code label for the next instruction to follow */
 {
@@ -545,6 +521,40 @@ void AddCodeLabel (CodeSeg* S, const char* Name)
 
 
 
+CodeLabel* GenCodeLabel (CodeSeg* S, struct CodeEntry* E)
+/* If the code entry E does already have a label, return it. Otherwise
+ * create a new label, attach it to E and return it.
+ */
+{
+    CodeLabel* L;
+
+    if (CodeEntryHasLabel (E)) {
+
+       /* Get the label from this entry */
+       L = GetCodeLabel (E, 0);
+
+    } else {
+
+       /* Get a new name */
+       const char* Name = LocalLabelName (GetLocalLabel ());
+
+       /* Generate the hash over the name */
+       unsigned Hash = HashStr (Name) % CS_LABEL_HASH_SIZE;
+
+       /* Create a new label */
+       L = NewCodeSegLabel (S, Name, Hash);
+
+       /* Attach this label to the code entry */
+       AttachCodeLabel (E, L);
+
+    }
+
+    /* Return the label */
+    return L;
+}
+
+
+
 void DelCodeLabel (CodeSeg* S, CodeLabel* L)
 /* Remove references from this label and delete it. */
 {
@@ -588,13 +598,158 @@ void DelCodeLabel (CodeSeg* S, CodeLabel* L)
 
 
 
+void MergeCodeLabels (CodeSeg* S)
+/* Merge code labels. That means: For each instruction, remove all labels but
+ * one and adjust references accordingly.
+ */
+{
+    unsigned I;
+
+    /* Walk over all code entries */
+    unsigned EntryCount = GetCodeEntryCount (S);
+    for (I = 0; I < EntryCount; ++I) {
+
+               CodeLabel* RefLab;
+       unsigned   J;
+
+       /* Get a pointer to the next entry */
+       CodeEntry* E = GetCodeEntry (S, I);
+
+       /* If this entry has zero labels, continue with the next one */
+       unsigned LabelCount = GetCodeLabelCount (E);
+       if (LabelCount == 0) {
+           continue;
+       }
+
+       /* We have at least one label. Use the first one as reference label. */
+       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
+        * that are no longer used. To increase performance, walk backwards
+        * through the list.
+        */
+       for (J = LabelCount-1; J >= 1; --J) {
+
+           /* Get the next label */
+           CodeLabel* L = GetCodeLabel (E, J);
+
+           /* Move all references from this label to the reference label */
+           MoveLabelRefs (L, RefLab);
+
+                   /* Remove the label completely. */
+                   DelCodeLabel (S, L);
+       }
+
+       /* The reference label is the only remaining label. Check if there
+        * are any references to this label, and delete it if this is not
+        * the case.
+        */
+               if (CollCount (&RefLab->JumpFrom) == 0) {
+           /* Delete the label */
+                   DelCodeLabel (S, RefLab);
+       }
+    }
+}
+
+
+
+void MoveCodeLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New)
+/* Move all labels from Old to New. The routine will move the labels itself
+ * if New does not have any labels, and move references if there is at least
+ * a label for new. If references are moved, the old label is deleted
+ * afterwards.
+ */
+{
+    /* Get the number of labels to move */
+    unsigned OldLabelCount = GetCodeLabelCount (Old);
+
+    /* Does the new entry have itself a label? */
+    if (CodeEntryHasLabel (New)) {
+
+       /* The new entry does already have a label - move references */
+       CodeLabel* NewLabel = GetCodeLabel (New, 0);
+       while (OldLabelCount--) {
+
+           /* Get the next label */
+           CodeLabel* OldLabel = GetCodeLabel (Old, OldLabelCount);
+
+           /* Move references */
+           MoveLabelRefs (OldLabel, NewLabel);
+
+           /* Delete the label */
+           DelCodeLabel (S, OldLabel);
+
+       }
+
+    } else {
+
+       /* The new entry does not have a label, just move them */
+       while (OldLabelCount--) {
+
+           /* Move the label to the new entry */
+           MoveCodeLabel (GetCodeLabel (Old, OldLabelCount), New);
+
+       }
+
+    }
+}
+
+
+
+void RemoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E)                        
+/* Remove the reference between E and the label it jumps to. The reference
+ * will be removed on both sides and E->JumpTo will be 0 after that. If
+ * the reference was the only one for the label, the label will get
+ * deleted.
+ */
+{
+    /* Get a pointer to the label and make sure it exists */
+    CodeLabel* L = E->JumpTo;
+    CHECK (L != 0);
+
+    /* Delete the entry from the label */
+    CollDeleteItem (&L->JumpFrom, E);
+
+    /* The entry jumps no longer to L */
+    E->JumpTo = 0;
+
+    /* If there are no more references, delete the label */
+    if (CollCount (&L->JumpFrom) == 0) {
+       DelCodeLabel (S, L);
+    }
+}
+
+
+
+void MoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L)
+/* Change the reference of E to L instead of the current one. If this
+ * was the only reference to the old label, the old label will get
+ * deleted.
+ */
+{
+    /* Get the old label */
+    CodeLabel* OldLabel = E->JumpTo;
+
+    /* Be sure that code entry references a label */
+    PRECONDITION (OldLabel != 0);
+
+    /* Remove the reference to our label */
+    RemoveCodeLabelRef (S, E);
+
+    /* Use the new label */
+    AddLabelRef (L, E);
+}
+
+
+
 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 = CollCount (&S->Entries);
+    unsigned EntryCount = GetCodeEntryCount (S);
 
     /* Must have at least one entry */
     CHECK (EntryCount > 0);
@@ -612,7 +767,7 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
 /* Delete all entries including the given one */
 {
     /* Get the number of entries in this segment */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
 
     /* Remove all entries after the given one */
     while (Last < Count) {
@@ -638,7 +793,7 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
     unsigned I;
 
     /* Get the number of entries in this segment */
-    unsigned Count = CollCount (&S->Entries);
+    unsigned Count = GetCodeEntryCount (S);
 
     /* If the code segment is empty, bail out here */
     if (Count == 0) {
@@ -666,63 +821,7 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
 
 
 
-void MergeCodeLabels (CodeSeg* S)
-/* Merge code labels. That means: For each instruction, remove all labels but
- * one and adjust the code entries accordingly.
- */
-{
-    unsigned I;
-
-    /* Walk over all code entries */
-    unsigned EntryCount = CollCount (&S->Entries);
-    for (I = 0; I < EntryCount; ++I) {
-
-               CodeLabel* RefLab;
-       unsigned   J;
-
-       /* Get a pointer to the next entry */
-       CodeEntry* E = GetCodeEntry (S, I);
-
-       /* If this entry has zero labels, continue with the next one */
-       unsigned LabelCount = CollCount (&E->Labels);
-       if (LabelCount == 0) {
-           continue;
-       }
-
-       /* We have at least one label. Use the first one as reference label. */
-       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
-        * that are no longer used. To increase performance, walk backwards
-        * through the list.
-        */
-       for (J = LabelCount-1; J >= 1; --J) {
-
-           /* Get the next label */
-           CodeLabel* L = GetCodeLabel (E, J);
-
-           /* Move all references from this label to the reference label */
-           MoveLabelRefs (L, RefLab);
-
-                   /* Remove the label completely. */
-                   DelCodeLabel (S, L);
-       }
-
-       /* The reference label is the only remaining label. Check if there
-        * are any references to this label, and delete it if this is not
-        * the case.
-        */
-               if (CollCount (&RefLab->JumpFrom) == 0) {
-           /* Delete the label */
-                   DelCodeLabel (S, RefLab);
-       }
-    }
-}
-
-
-
-unsigned GetCodeSegEntries (const CodeSeg* S)
+unsigned GetCodeEntryCount (const CodeSeg* S)
 /* Return the number of entries for the given code segment */
 {
     return CollCount (&S->Entries);
index e7a2fdaf1e9b58e6c0aea96b7f355f20ba4acfea..a90e31b1a7a5b8d2d2c49c3aaa29e76a96144ae4 100644 (file)
@@ -103,12 +103,45 @@ void DelCodeEntry (CodeSeg* S, unsigned Index);
 struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index);
 /* Get an entry from the given code segment */
 
+unsigned GetCodeEntryIndex (CodeSeg* S, struct CodeEntry* E);
+/* Return the index of a code entry */
+
 void AddCodeLabel (CodeSeg* S, const char* Name);
 /* Add a code label for the next instruction to follow */
 
+CodeLabel* GenCodeLabel (CodeSeg* S, struct CodeEntry* E);
+/* If the code entry E does already have a label, return it. Otherwise
+ * create a new label, attach it to E and return it.
+ */
+
 void DelCodeLabel (CodeSeg* S, CodeLabel* L);
 /* Remove references from this label and delete it. */
 
+void MergeCodeLabels (CodeSeg* S);
+/* Merge code labels. That means: For each instruction, remove all labels but
+ * one and adjust references accordingly.
+ */
+
+void MoveCodeLabels (CodeSeg* S, struct CodeEntry* Old, struct CodeEntry* New);
+/* Move all labels from Old to New. The routine will move the labels itself
+ * if New does not have any labels, and move references if there is at least
+ * a label for new. If references are moved, the old label is deleted
+ * afterwards.
+ */
+
+void RemoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E);
+/* Remove the reference between E and the label it jumps to. The reference
+ * will be removed on both sides and E->JumpTo will be 0 after that. If
+ * the reference was the only one for the label, the label will get
+ * deleted.
+ */
+
+void MoveCodeLabelRef (CodeSeg* S, struct CodeEntry* E, CodeLabel* L);
+/* Change the reference of E to L instead of the current one. If this
+ * was the only reference to the old label, the old label will get
+ * deleted.
+ */
+
 void AddCodeSegHint (CodeSeg* S, unsigned Hint);
 /* Add a hint for the preceeding instruction */
 
@@ -118,12 +151,7 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
 void OutputCodeSeg (const CodeSeg* S, FILE* F);
 /* Output the code segment data to a file */
 
-void MergeCodeLabels (CodeSeg* S);
-/* Merge code labels. That means: For each instruction, remove all labels but
- * one and adjust the code entries accordingly.
- */
-
-unsigned GetCodeSegEntries (const CodeSeg* S);
+unsigned GetCodeEntryCount (const CodeSeg* S);
 /* Return the number of entries for the given code segment */
 
 
index 11888de9ca4fa17d0e215ada9059ef4414150c9e..79f6658f5672c7e54a78a25e5fac8d2adb9647d7 100644 (file)
@@ -42,6 +42,7 @@
 
 /* cc65 */
 #include "codeinfo.h"
+#include "cpu.h"
 #include "error.h"
 #include "opcodes.h"
 
@@ -265,7 +266,147 @@ opc_t GetInverseBranch (opc_t OPC)
                case OPC_JPL:   return OPC_JMI;
                case OPC_JVC:   return OPC_JVS;
                case OPC_JVS:   return OPC_JVC;
-       default:        Internal ("GetInverseBranch: Invalid opcode: %d", OPC);
+       default:        Internal ("GetInverseBranch: Invalid opcode: %d", OPC);
+    }
+}
+
+
+
+opc_t MakeShortBranch (opc_t OPC)
+/* Return the short version of the given branch. If the branch is already
+ * a short branch, return the opcode unchanged.
+ */
+{
+    switch (OPC) {
+               case OPC_BCC:
+               case OPC_JCC:   return OPC_BCC;
+               case OPC_BCS:
+               case OPC_JCS:   return OPC_BCS;
+               case OPC_BEQ:
+               case OPC_JEQ:   return OPC_BEQ;
+               case OPC_BMI:
+               case OPC_JMI:   return OPC_BMI;
+               case OPC_BNE:
+               case OPC_JNE:   return OPC_BNE;
+               case OPC_BPL:
+               case OPC_JPL:   return OPC_BPL;
+               case OPC_BVC:
+               case OPC_JVC:   return OPC_BVC;
+               case OPC_BVS:
+               case OPC_JVS:   return OPC_BVS;
+               case OPC_BRA:
+       case OPC_JMP:   return (CPU == CPU_65C02)? OPC_BRA : OPC_JMP;
+               default:        Internal ("GetShortBranch: Invalid opcode: %d", OPC);
+    }
+}
+
+
+
+opc_t MakeLongBranch (opc_t OPC)
+/* Return the long version of the given branch. If the branch is already
+ * a long branch, return the opcode unchanged.
+ */
+{
+    switch (OPC) {
+               case OPC_BCC:
+               case OPC_JCC:   return OPC_JCC;
+               case OPC_BCS:
+               case OPC_JCS:   return OPC_JCS;
+               case OPC_BEQ:
+               case OPC_JEQ:   return OPC_JEQ;
+               case OPC_BMI:
+               case OPC_JMI:   return OPC_JMI;
+               case OPC_BNE:
+               case OPC_JNE:   return OPC_JNE;
+               case OPC_BPL:
+               case OPC_JPL:   return OPC_JPL;
+               case OPC_BVC:
+               case OPC_JVC:   return OPC_JVC;
+               case OPC_BVS:
+               case OPC_JVS:   return OPC_JVS;
+       case OPC_BRA:
+       case OPC_JMP:   return OPC_JMP;
+               default:        Internal ("GetShortBranch: Invalid opcode: %d", OPC);
+    }
+}
+
+
+
+bc_t GetBranchCond (opc_t OPC)
+/* Get the condition for the conditional branch in OPC */
+{
+    switch (OPC) {
+               case OPC_BCC:   return BC_CC;
+               case OPC_BCS:   return BC_CS;
+               case OPC_BEQ:   return BC_EQ;
+               case OPC_BMI:   return BC_MI;
+               case OPC_BNE:   return BC_NE;
+               case OPC_BPL:   return BC_PL;
+               case OPC_BVC:   return BC_VC;
+               case OPC_BVS:   return BC_VS;
+               case OPC_JCC:   return BC_CC;
+               case OPC_JCS:   return BC_CS;
+               case OPC_JEQ:   return BC_EQ;
+               case OPC_JMI:   return BC_MI;
+               case OPC_JNE:   return BC_NE;
+               case OPC_JPL:   return BC_PL;
+               case OPC_JVC:   return BC_VC;
+               case OPC_JVS:   return BC_VS;
+       default:        Internal ("GetBranchCond: Invalid opcode: %d", OPC);
+    }
+}
+
+
+
+bc_t GetInverseCond (bc_t BC)
+/* Return the inverse condition of the given one */
+{
+    switch (BC) {
+               case BC_CC:     return BC_CS;
+               case BC_CS:     return BC_CC;
+               case BC_EQ:     return BC_NE;
+               case BC_MI:     return BC_PL;
+               case BC_NE:     return BC_EQ;
+               case BC_PL:     return BC_MI;
+               case BC_VC:     return BC_VS;
+               case BC_VS:     return BC_VC;
+       default:        Internal ("GetInverseCond: Invalid condition: %d", BC);
+    }
+}
+
+
+
+opc_t GetLongBranch (bc_t BC)
+/* Return a long branch for the given branch condition */
+{
+    switch (BC) {
+       case BC_CC:     return OPC_JCC;
+       case BC_CS:     return OPC_JCS;
+       case BC_EQ:     return OPC_JEQ;
+       case BC_MI:     return OPC_JMI;
+       case BC_NE:     return OPC_JNE;
+       case BC_PL:     return OPC_JPL;
+       case BC_VC:     return OPC_JVC;
+       case BC_VS:     return OPC_JVS;
+               default:        Internal ("GetLongBranch: Invalid condition: %d", BC);
+    }
+}
+
+
+
+opc_t GetShortBranch (bc_t BC)
+/* Return a short branch for the given branch condition */
+{
+    switch (BC) {
+               case BC_CC:     return OPC_BCC;
+               case BC_CS:     return OPC_BCS;
+               case BC_EQ:     return OPC_BEQ;
+               case BC_MI:     return OPC_BMI;
+               case BC_NE:     return OPC_BNE;
+               case BC_PL:     return OPC_BPL;
+               case BC_VC:     return OPC_BVC;
+               case BC_VS:     return OPC_BVS;
+               default:        Internal ("GetShortBranch: Invalid condition: %d", BC);
     }
 }
 
index bc827dd1a9ca4cbf67efe877cc4af9fc6ed155fb..df590fd147341d5eec44f1b2a1f93113dd1f12f1 100644 (file)
@@ -138,6 +138,19 @@ typedef enum {
     AM_BRA             = 0x0800                /* branch */
 } am_t;
 
+/* Branch conditions */
+typedef enum {
+    BC_CC,
+    BC_CS,
+    BC_EQ,
+    BC_MI,
+    BC_NE,
+    BC_PL,
+    BC_SR,
+    BC_VC,
+    BC_VS
+} bc_t;
+
 /* Opcode info */
 #define OF_NONE        0x0000U                 /* No additional information */
 #define OF_UBRA        0x0001U                 /* Unconditional branch */
@@ -186,6 +199,28 @@ unsigned char GetAMUseInfo (am_t AM);
 opc_t GetInverseBranch (opc_t OPC);
 /* Return a branch that reverse the condition of the branch given in OPC */
 
+opc_t MakeShortBranch (opc_t OPC);
+/* Return the short version of the given branch. If the branch is already
+ * a short branch, return the opcode unchanged.
+ */
+
+opc_t MakeLongBranch (opc_t OPC);
+/* Return the long version of the given branch. If the branch is already
+ * a long branch, return the opcode unchanged.
+ */
+
+bc_t GetBranchCond (opc_t OPC);
+/* Get the condition for the conditional branch in OPC */
+
+bc_t GetInverseCond (bc_t BC);
+/* Return the inverse condition of the given one */
+
+opc_t GetLongBranch (bc_t BC);
+/* Return a long branch for the given branch condition */
+
+opc_t GetShortBranch (bc_t BC);
+/* Return a short branch for the given branch condition */
+
 
 
 /* End of opcodes.h */