CodeMark GetCodePos (void)
/* Get a marker pointing to the current output position */
{
- return GetCodeSegEntries (CS->Code);
+ return GetCodeEntryCount (CS->Code);
}
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 */
+#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 */
/*****************************************************************************/
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;
/* 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 */
/* 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);
-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);
}
+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);
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:
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 */
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 */
-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.
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.
#include "print.h"
/* cc65 */
+#include "asmlabel.h"
#include "codeent.h"
#include "codeinfo.h"
#include "global.h"
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;
}
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;
}
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;
}
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;
/*****************************************************************************/
-/* Optimize jsr/rts */
+/* Optimize jsr/rts */
/*****************************************************************************/
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;
}
/* 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;
* 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;
/*****************************************************************************/
-/* Code */
+/* Code */
/*****************************************************************************/
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 */
#include "xsprintf.h"
/* cc65 */
+#include "asmlabel.h"
#include "codeent.h"
#include "codeinfo.h"
#include "error.h"
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;
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 */
* 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);
/* 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);
-
- }
-
- }
}
}
* 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 */
+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 */
{
+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. */
{
+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);
/* 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) {
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) {
-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);
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 */
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 */
/* cc65 */
#include "codeinfo.h"
+#include "cpu.h"
#include "error.h"
#include "opcodes.h"
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);
}
}
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 */
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 */