mirror of
https://github.com/cc65/cc65.git
synced 2025-01-11 11:30:13 +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:
parent
e6a5e57b47
commit
989aacec2c
@ -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 */
|
||||
|
@ -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:
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
|
Loading…
x
Reference in New Issue
Block a user