1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-09 22:29:35 +00:00

Working on the backend

git-svn-id: svn://svn.cc65.org/cc65/trunk@719 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-05-06 20:57:58 +00:00
parent e6a5e57b47
commit 989aacec2c
10 changed files with 678 additions and 222 deletions

View 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 */

View File

@ -33,6 +33,8 @@
#include <string.h>
/* 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,6 +149,29 @@ void FreeCodeEntry (CodeEntry* E)
int CodeEntriesAreEqual (const CodeEntry* E1, const CodeEntry* E2)
/* Check if both code entries are equal */
{
return E1->OPC == E2->OPC && E1->AM == E2->AM && strcmp (E1->Arg, E2->Arg) == 0;
}
void AttachCodeLabel (CodeEntry* E, CodeLabel* L)
/* Attach the label to the entry */
{
/* 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;
}
int CodeEntryHasLabel (const CodeEntry* E)
/* Check if the given code entry has labels attached */
{
@ -120,6 +180,35 @@ int CodeEntryHasLabel (const CodeEntry* E)
unsigned GetCodeLabelCount (const CodeEntry* E)
/* Get the number of labels attached to this entry */
{
return CollCount (&E->Labels);
}
CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
/* Get a label from this code entry */
{
return CollAt (&E->Labels, Index);
}
void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
/* Move the code label L from it's former owner to the code entry E. */
{
/* Delete the label from the owner */
CollDeleteItem (&L->Owner->Labels, L);
/* Set the new owner */
CollAppend (&E->Labels, L);
L->Owner = E;
}
int CodeEntryHasMark (const CodeEntry* E)
/* Return true if the given code entry has the CEF_USERMARK flag set */
{
@ -144,23 +233,14 @@ void CodeEntryResetMark (CodeEntry* E)
CodeLabel* GetCodeLabel (CodeEntry* E, unsigned Index)
/* Get a label from this code entry */
void CodeEntrySetArg (CodeEntry* E, const char* Arg)
/* Set a new argument for the given code entry. An old string is deleted. */
{
return CollAt (&E->Labels, Index);
}
/* Free the old argument */
FreeArg (E->Arg);
void MoveCodeLabel (CodeLabel* L, CodeEntry* E)
/* Move the code label L from it's former owner to the code entry E. */
{
/* Delete the label from the owner */
CollDeleteItem (&L->Owner->Labels, L);
/* Set the new owner */
CollAppend (&E->Labels, L);
L->Owner = E;
/* Assign the new one */
E->Arg = GetArgCopy (Arg);
}
@ -170,6 +250,7 @@ void OutputCodeEntry (const CodeEntry* E, FILE* F)
{
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:

View 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 */

View 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.

View 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.

View 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 instruction that has the new label attached */
CodeEntry* N = OldLabel->Owner;
/* Get the label this insn is branching to */
CodeLabel* OldLabel = E->JumpTo;
/* Remove the reference to our label and delete it if this was
* the last reference.
/* Get the entry we're branching to */
CodeEntry* N = OldLabel->Owner;
/* 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))) {
/* Use the new label */
AddLabelRef (NewLabel, E);
/* 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);
}
/* Remember ,we had changes */
++OptChanges;
/* 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;
}
/* 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 */

View 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)) {
/* Move labels to the next entry */
MoveCodeLabels (S, E, 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);
}
} 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,93 +598,15 @@ void DelCodeLabel (CodeSeg* S, CodeLabel* L)
void AddCodeSegHint (CodeSeg* S, unsigned Hint)
/* Add a hint for the preceeding instruction */
{
CodeEntry* E;
/* Get the number of entries in this segment */
unsigned EntryCount = CollCount (&S->Entries);
/* Must have at least one entry */
CHECK (EntryCount > 0);
/* Get the last entry */
E = GetCodeEntry (S, EntryCount-1);
/* Add the hint */
E->Hints |= Hint;
}
void DelCodeSegAfter (CodeSeg* S, unsigned Last)
/* Delete all entries including the given one */
{
/* Get the number of entries in this segment */
unsigned Count = CollCount (&S->Entries);
/* Remove all entries after the given one */
while (Last < Count) {
/* Get the next entry */
CodeEntry* E = GetCodeEntry (S, Count-1);
/* We have to transfer all labels to the code segment label pool */
MoveLabelsToPool (S, E);
/* Remove the code entry */
FreeCodeEntry (E);
CollDelete (&S->Entries, Count-1);
--Count;
}
}
void OutputCodeSeg (const CodeSeg* S, FILE* F)
/* Output the code segment data to a file */
{
unsigned I;
/* Get the number of entries in this segment */
unsigned Count = CollCount (&S->Entries);
/* If the code segment is empty, bail out here */
if (Count == 0) {
return;
}
/* Output the segment directive */
fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
/* If this is a segment for a function, enter a function */
if (S->Func) {
fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
}
/* Output all entries */
for (I = 0; I < Count; ++I) {
OutputCodeEntry (CollConstAt (&S->Entries, I), F);
}
/* If this is a segment for a function, leave the function */
if (S->Func) {
fprintf (F, "\n.endproc\n\n");
}
}
void MergeCodeLabels (CodeSeg* S)
/* Merge code labels. That means: For each instruction, remove all labels but
* one and adjust the code entries accordingly.
* one and adjust references accordingly.
*/
{
unsigned I;
/* Walk over all code entries */
unsigned EntryCount = CollCount (&S->Entries);
unsigned EntryCount = GetCodeEntryCount (S);
for (I = 0; I < EntryCount; ++I) {
CodeLabel* RefLab;
@ -684,7 +616,7 @@ void MergeCodeLabels (CodeSeg* S)
CodeEntry* E = GetCodeEntry (S, I);
/* If this entry has zero labels, continue with the next one */
unsigned LabelCount = CollCount (&E->Labels);
unsigned LabelCount = GetCodeLabelCount (E);
if (LabelCount == 0) {
continue;
}
@ -722,7 +654,174 @@ void MergeCodeLabels (CodeSeg* S)
unsigned GetCodeSegEntries (const CodeSeg* S)
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 = GetCodeEntryCount (S);
/* Must have at least one entry */
CHECK (EntryCount > 0);
/* Get the last entry */
E = GetCodeEntry (S, EntryCount-1);
/* Add the hint */
E->Hints |= Hint;
}
void DelCodeSegAfter (CodeSeg* S, unsigned Last)
/* Delete all entries including the given one */
{
/* Get the number of entries in this segment */
unsigned Count = GetCodeEntryCount (S);
/* Remove all entries after the given one */
while (Last < Count) {
/* Get the next entry */
CodeEntry* E = GetCodeEntry (S, Count-1);
/* We have to transfer all labels to the code segment label pool */
MoveLabelsToPool (S, E);
/* Remove the code entry */
FreeCodeEntry (E);
CollDelete (&S->Entries, Count-1);
--Count;
}
}
void OutputCodeSeg (const CodeSeg* S, FILE* F)
/* Output the code segment data to a file */
{
unsigned I;
/* Get the number of entries in this segment */
unsigned Count = GetCodeEntryCount (S);
/* If the code segment is empty, bail out here */
if (Count == 0) {
return;
}
/* Output the segment directive */
fprintf (F, ".segment\t\"%s\"\n\n", S->SegName);
/* If this is a segment for a function, enter a function */
if (S->Func) {
fprintf (F, ".proc\t_%s\n\n", S->Func->Name);
}
/* Output all entries */
for (I = 0; I < Count; ++I) {
OutputCodeEntry (CollConstAt (&S->Entries, I), F);
}
/* If this is a segment for a function, leave the function */
if (S->Func) {
fprintf (F, "\n.endproc\n\n");
}
}
unsigned GetCodeEntryCount (const CodeSeg* S)
/* Return the number of entries for the given code segment */
{
return CollCount (&S->Entries);

View 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 */

View 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);
}
}

View 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 */