From 989aacec2c0a5aa83b7c719d1f5292c8cd0183df Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 6 May 2001 20:57:58 +0000 Subject: [PATCH] Working on the backend git-svn-id: svn://svn.cc65.org/cc65/trunk@719 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/asmcode.c | 4 +- src/cc65/codeent.c | 121 +++++++++++++++--- src/cc65/codeent.h | 22 +++- src/cc65/codelab.c | 12 -- src/cc65/codelab.h | 3 - src/cc65/codeopt.c | 161 ++++++++++++++++------- src/cc65/codeseg.c | 309 ++++++++++++++++++++++++++++++--------------- src/cc65/codeseg.h | 40 +++++- src/cc65/opcodes.c | 143 ++++++++++++++++++++- src/cc65/opcodes.h | 35 +++++ 10 files changed, 653 insertions(+), 197 deletions(-) diff --git a/src/cc65/asmcode.c b/src/cc65/asmcode.c index 046043f2b..b139af1c8 100644 --- a/src/cc65/asmcode.c +++ b/src/cc65/asmcode.c @@ -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 */ diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index d8f852bc9..f2661e1e5 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -33,6 +33,8 @@ +#include + /* common */ #include "check.h" #include "xmalloc.h" @@ -53,6 +55,41 @@ +/* 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: diff --git a/src/cc65/codeent.h b/src/cc65/codeent.h index ab0790989..ba704eb28 100644 --- a/src/cc65/codeent.h +++ b/src/cc65/codeent.h @@ -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 */ diff --git a/src/cc65/codelab.c b/src/cc65/codelab.c index 97ed7e3b8..89b45b0e6 100644 --- a/src/cc65/codelab.c +++ b/src/cc65/codelab.c @@ -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. diff --git a/src/cc65/codelab.h b/src/cc65/codelab.h index 0aef14857..bd24fc5d5 100644 --- a/src/cc65/codelab.h +++ b/src/cc65/codelab.h @@ -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. diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 241934187..90417a537 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -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 */ diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 5c54b2231..62642e0bf 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -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); diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index e7a2fdaf1..a90e31b1a 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -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 */ diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index 11888de9c..79f6658f5 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -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); } } diff --git a/src/cc65/opcodes.h b/src/cc65/opcodes.h index bc827dd1a..df590fd14 100644 --- a/src/cc65/opcodes.h +++ b/src/cc65/opcodes.h @@ -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 */ -- 2.39.5