E->Arg = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
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) {
+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;
+}
+
+
+
+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;
+}
+
+
+
void OutputCodeEntry (const CodeEntry* E, FILE* F)
/* Output the code entry to a file */
{
char* Arg; /* Argument as string */
unsigned Num; /* Numeric argument */
unsigned short Flags; /* Flags */
+ unsigned char Info; /* Additional code info */
unsigned char Use; /* Registers used */
unsigned char Chg; /* Registers changed/destroyed */
CodeLabel* JumpTo; /* Jump label */
int CodeEntryHasLabel (const CodeEntry* E);
/* Check if the given code entry has labels attached */
+int CodeEntryHasMark (const CodeEntry* E);
+/* Return true if the given code entry has the CEF_USERMARK flag set */
+
+void CodeEntrySetMark (CodeEntry* E);
+/* Set the CEF_USERMARK flag for the given entry */
+
+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 OutputCodeEntry (const CodeEntry* E, FILE* F);
/* Output the code entry to a file */
-void g_leave (int flags, int val)
+void g_leave (void)
/* Function epilogue */
{
- int k;
- char buf [40];
-
- /* CF_REG is set if we're returning a value from the function */
- if ((flags & CF_REG) == 0) {
- AddCodeHint ("x:-");
- AddCodeHint ("a:-");
- }
-
/* How many bytes of locals do we have to drop? */
- k = -oursp;
+ int k = -oursp;
/* If we didn't have a variable argument list, don't call leave */
if (funcargs >= 0) {
- /* Load a function return code if needed */
- if ((flags & CF_CONST) != 0) {
- g_getimmed (flags, val, 0);
- }
-
- /* Drop stackframe or leave with rts */
+ /* Drop stackframe if needed */
k += funcargs;
- if (k == 0) {
- AddCodeHint ("y:-"); /* Y register no longer used */
- AddCodeLine ("rts");
- } else if (k <= 8) {
- AddCodeHint ("y:-"); /* Y register no longer used */
- AddCodeLine ("jmp incsp%d", k);
- } else {
- CheckLocalOffs (k);
- ldyconst (k);
- AddCodeLine ("jmp addysp");
+ if (k > 0) {
+ if (k <= 8) {
+ AddCodeLine ("jsr incsp%d", k);
+ } else {
+ CheckLocalOffs (k);
+ ldyconst (k);
+ AddCodeLine ("jsr addysp");
+ }
}
} else {
- strcpy (buf, "\tjmp\tleave");
- if (k) {
+ if (k == 0) {
+ /* Nothing to drop */
+ AddCodeLine ("jsr leave");
+ } else {
/* We've a stack frame to drop */
ldyconst (k);
- strcat (buf, "y");
- } else {
- /* Y register no longer used */
- AddCodeHint ("y:-");
+ AddCodeLine ("jsr leavey");
}
- if (flags & CF_CONST) {
- if ((flags & CF_TYPE) != CF_LONG) {
- /* Constant int sized value given for return code */
- if (val == 0) {
- /* Special case: return 0 */
- strcat (buf, "00");
- } else if (((val >> 8) & 0xFF) == 0) {
- /* Special case: constant with high byte zero */
- ldaconst (val); /* Load low byte */
- strcat (buf, "0");
- } else {
- /* Others: arbitrary constant value */
- g_getimmed (flags, val, 0); /* Load value */
- }
- } else {
- /* Constant long value: No shortcut possible */
- g_getimmed (flags, val, 0);
- }
- }
-
- /* Output the jump */
- AddCodeLine (buf);
}
+
+ /* Add the final rts */
+ AddCodeLine ("rts");
}
void g_enter (unsigned flags, unsigned argsize);
/* Function prologue */
-void g_leave (int flags, int val);
+void g_leave (void);
/* Function epilogue */
#include <stdlib.h>
#include <string.h>
+/* common */
+#include "coll.h"
+
/* cc65 */
#include "codeinfo.h"
};
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
+/* Structure used to pass information to the RegValUsedInt1 and 2 functions */
+typedef struct RVUInfo RVUInfo;
+struct RVUInfo {
+ Collection VisitedLines; /* Lines already visited */
+};
+
/*****************************************************************************/
}
}
+
+#if 0
+
+static unsigned RVUInt2 (Line* L,
+ LineColl* LC, /* To remember visited lines */
+ unsigned Used, /* Definitely used registers */
+ unsigned Unused) /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+ int I;
+
+ /* Check the following instructions. We classifiy them into primary
+ * loads (register value not used), neutral (check next instruction),
+ * and unknown (assume register was used).
+ */
+ while (1) {
+
+ unsigned R;
+
+ /* Get the next line and follow jumps */
+ do {
+
+ /* Handle jumps to local labels (continue there) */
+ if (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL")) {
+ /* Get the target of the jump */
+ L = GetTargetLine (L->Line+5);
+ }
+
+ /* Get the next line, skip local labels */
+ do {
+ L = NextCodeSegLine (L);
+ } while (L && (IsLocalLabel (L) || L->Line[0] == '\0'));
+
+ /* Bail out if we're done */
+ if (L == 0 || IsExtLabel (L)) {
+ /* End of function reached */
+ goto ExitPoint;
+ }
+
+ /* Check if we had this line already. If so, bail out, if not,
+ * add it to the list of known lines.
+ */
+ if (LCHasLine (LC, L) || !LCAddLine (LC, L)) {
+ goto ExitPoint;
+ }
+
+ } while (LineMatch (L, "\tjmp\tL") || LineMatch (L, "\tbra\tL"));
+
+ /* Special handling of code hints */
+ if (IsHintLine (L)) {
+
+ if (IsHint (L, "a:-") && (Used & REG_A) == 0) {
+ Unused |= REG_A;
+ } else if (IsHint (L, "x:-") && (Used & REG_X) == 0) {
+ Unused |= REG_X;
+ } else if (IsHint (L, "y:-") && (Used & REG_Y) == 0) {
+ Unused |= REG_Y;
+ }
+
+ /* Special handling for branches */
+ } else if (LineMatchX (L, ShortBranches) >= 0 ||
+ LineMatchX (L, LongBranches) >= 0) {
+ const char* Target = L->Line+5;
+ if (Target[0] == 'L') {
+ /* Jump to local label. Check the register usage starting at
+ * the branch target and at the code following the branch.
+ * All registers that are unused in both execution flows are
+ * returned as unused.
+ */
+ unsigned U1, U2;
+ U2 = RVUInt1 (GetTargetLine (Target), LC, Used, Unused);
+ U1 = RVUInt1 (L, LC, Used, Unused);
+ return U1 | U2; /* Used in any of the branches */
+ }
+ } else {
+
+ /* Search for the instruction in this line */
+ I = FindCmd (L);
+
+ /* If we don't find it, assume all other registers are used */
+ if (I < 0) {
+ break;
+ }
+
+ /* Evaluate the use flags, check for addressing modes */
+ R = CmdDesc[I].Use;
+ if (IsXAddrMode (L)) {
+ R |= REG_X;
+ } else if (IsYAddrMode (L)) {
+ R |= REG_Y;
+ }
+ if (R) {
+ /* Remove registers that were already new loaded */
+ R &= ~Unused;
+
+ /* Remember the remaining registers */
+ Used |= R;
+ }
+
+ /* Evaluate the load flags */
+ R = CmdDesc[I].Load;
+ if (R) {
+ /* Remove registers that were already used */
+ R &= ~Used;
+
+ /* Remember the remaining registers */
+ Unused |= R;
+ }
+
+ }
+
+ /* If we know about all registers, bail out */
+ if ((Used | Unused) == REG_ALL) {
+ break;
+ }
+ }
+
+ExitPoint:
+ /* Return to the caller the complement of all unused registers */
+ return ~Unused & REG_ALL;
+}
+
+
+
+static unsigned RVUInt1 (Line* L,
+ LineColl* LC, /* To remember visited lines */
+ unsigned Used, /* Definitely used registers */
+ unsigned Unused) /* Definitely unused registers */
+/* Subfunction for RegValUsed. Will be called recursively in case of branches. */
+{
+ /* Remember the current count of the line collection */
+ unsigned Count = LC->Count;
+
+ /* Call the worker routine */
+ unsigned R = RVUInt2 (L, LC, Used, Unused);
+
+ /* Restore the old count */
+ LC->Count = Count;
+
+ /* Return the result */
+ return R;
+}
+
+
+
+static unsigned RegValUsed (Line* Start)
+/* Check the next instructions after the one in L for register usage. If
+ * a register is used as an index, or in a store or other instruction, it
+ * is assumed to be used. If a register is loaded with a value, before it
+ * was used by one of the actions described above, it is assumed unused.
+ * If the end of the lookahead is reached, all registers that are uncertain
+ * are marked as used.
+ * The result of the search is returned.
+ */
+{
+ unsigned R;
+
+ /* Create a new line collection and enter the start line */
+ LineColl* LC = NewLineColl (256);
+ LCAddLine (LC, Start);
+
+ /* Call the recursive subfunction */
+ R = RVUInt1 (Start, LC, REG_NONE, REG_NONE);
+
+ /* Delete the line collection */
+ FreeLineColl (LC);
+
+ /* Return the registers used */
+ return R;
+}
+
+
+
+static int RegAUsed (Line* Start)
+/* Check if the value in A is used. */
+{
+ return (RegValUsed (Start) & REG_A) != 0;
+}
+
+
+
+static int RegXUsed (Line* Start)
+/* Check if the value in X is used. */
+{
+ return (RegValUsed (Start) & REG_X) != 0;
+}
+
+
+
+static int RegYUsed (Line* Start)
+/* Check if the value in Y is used. */
+{
+ return (RegValUsed (Start) & REG_Y) != 0;
+}
+#endif
/* common */
+#include "check.h"
#include "xmalloc.h"
/* cc65 */
+void MoveLabelRefs (CodeLabel* OldLabel, CodeLabel* NewLabel)
+/* Move all references to OldLabel to point to NewLabel. OldLabel will have no
+ * more references on return.
+ */
+{
+ /* Walk through all instructions referencing the old label */
+ unsigned Count = CollCount (&OldLabel->JumpFrom);
+ while (Count--) {
+
+ /* Get the instruction that references the old label */
+ CodeEntry* E = CollAt (&OldLabel->JumpFrom, Count);
+
+ /* Change the reference to the new label */
+ CHECK (E->JumpTo == OldLabel);
+ AddLabelRef (NewLabel, E);
+
+ }
+
+ /* There are no more references to the old label */
+ CollDeleteAll (&OldLabel->JumpFrom);
+}
+
+
+
void OutputCodeLabel (const CodeLabel* L, FILE* F)
/* Output the code label to a file */
{
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.
+ */
+
void OutputCodeLabel (const CodeLabel* L, FILE* F);
/* Output the code label to a file */
while (I < Count-1) {
/* Get the next entry */
- E = CollAt (&S->Entries, I);
+ E = GetCodeEntry (S, I);
/* Check if it's a branch, if it has a local target, and if the target
* is the next instruction.
*/
- if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == CollAt (&S->Entries, I+1)) {
+ if (E->AM == AM_BRA && E->JumpTo && E->JumpTo->Owner == GetCodeEntry (S, I+1)) {
/* Delete the dead jump */
DelCodeEntry (S, I);
while (I < Count-1) {
/* Get this entry */
- CodeEntry* E = CollAt (&S->Entries, I);
+ CodeEntry* E = GetCodeEntry (S, I);
/* Check if it's an unconditional branch, and if the next entry has
* no labels attached
*/
- if ((E->OPC == OPC_JMP || E->OPC == OPC_BRA || E->OPC == OPC_RTS || E->OPC == OPC_RTI) &&
- !CodeEntryHasLabel (CollAt (&S->Entries, I+1))) {
+ if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
/* Delete the next entry */
DelCodeEntry (S, I+1);
CodeLabel* NewLabel;
/* Get this entry */
- CodeEntry* E = CollAt (&S->Entries, I);
+ 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.
+ * instruction at this label is also a branch, and (important) if
+ * both instructions are not identical.
*/
- if (E->AM == AM_BRA &&
- (OldLabel = E->JumpTo) != 0 &&
- OldLabel->Owner->AM == AM_BRA &&
- (NewLabel = OldLabel->Owner->JumpTo) != 0) {
+ 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 */
/* Get the instruction that has the new label attached */
CodeEntry* N = OldLabel->Owner;
+/*****************************************************************************/
+/* Optimize jsr/rts */
+/*****************************************************************************/
+
+
+
+static void OptRTS (CodeSeg* S)
+/* Optimize subroutine calls followed by an RTS. The subroutine call will get
+ * replaced by a jump. Don't bother to delete the RTS if it does not have a
+ * label, the dead code elimination should take care of it.
+ */
+{
+ unsigned I;
+
+ /* Get the number of entries, bail out if we have less than 2 entries */
+ unsigned Count = CollCount (&S->Entries);
+ if (Count < 2) {
+ return;
+ }
+
+ /* Walk over all entries minus the last one */
+ I = 0;
+ while (I < Count-1) {
+
+ /* Get this entry */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* 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 */
+ E->Info = GetOPCInfo (OPC_JMP);
+
+ /* Remember, we had changes */
+ ++OptChanges;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+}
+
+
+
+/*****************************************************************************/
+/* Optimize jump targets */
+/*****************************************************************************/
+
+
+
+static void OptJumpTarget (CodeSeg* S)
+/* If the instruction preceeding an unconditional branch is the same as the
+ * instruction preceeding the jump target, the jump target may be moved
+ * one entry back. This is a size optimization, since the instruction before
+ * the branch gets removed.
+ */
+{
+ unsigned I;
+
+ /* Get the number of entries, bail out if we have not enough */
+ unsigned Count = CollCount (&S->Entries);
+ if (Count < 3) {
+ return;
+ }
+
+ /* Walk over all entries minus the first one */
+ I = 1;
+ while (I < Count) {
+
+ /* Get this entry and the entry before this one */
+ CodeEntry* E = GetCodeEntry (S, I);
+
+ /* Check if we have a jump or branch, and a matching label */
+ if ((E->Info & OF_UBRA) != 0 && E->JumpTo) {
+
+ /* Remember, we had changes */
+ ++OptChanges;
+
+ }
+
+ /* Next entry */
+ ++I;
+
+ }
+}
+
+
+
/*****************************************************************************/
/* Code */
/*****************************************************************************/
/* Table with optimizer steps - are called in this order */
static const OptFunc OptFuncs [] = {
- OptJumpCascades, /* Optimize jump cascades */
- OptDeadJumps, /* Remove dead jumps */
- OptDeadCode, /* Remove dead code */
+ OptJumpCascades, /* Optimize jump cascades */
+ OptDeadJumps, /* Remove dead jumps */
+ OptDeadCode, /* Remove dead code */
+ OptRTS, /* Change jsr/rts to jmp */
};
/* Repeat all steps until there are no more changes */
Flags = 1UL;
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
if ((OptDisable & Flags) == 0) {
- OptFuncs[I] (S);
+ OptFuncs[I] (S);
} else if (Verbosity > 0 || Debug) {
- printf ("Optimizer pass %u skipped\n", I);
+ printf ("Optimizer pass %u skipped\n", I);
}
Flags <<= 1;
}
+/*****************************************************************************/
+/* Helper functions */
+/*****************************************************************************/
+
+
+
+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);
+ while (LabelCount--) {
+ CodeLabel* L = GetCodeLabel (E, LabelCount);
+ L->Flags &= ~LF_DEF;
+ L->Owner = 0;
+ CollAppend (&S->Labels, L);
+ }
+ CollDeleteAll (&E->Labels);
+}
+
+
+
+static CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
+/* Find the label with the given name. Return the label or NULL if not found */
+{
+ /* Get the first hash chain entry */
+ CodeLabel* L = S->LabelHash[Hash];
+
+ /* Search the list */
+ while (L) {
+ if (strcmp (Name, L->Name) == 0) {
+ /* Found */
+ break;
+ }
+ L = L->Next;
+ }
+ return L;
+}
+
+
+
/*****************************************************************************/
/* Functions for parsing instructions */
/*****************************************************************************/
void DelCodeEntry (CodeSeg* S, unsigned Index)
-/* Delete an entry from the code segment. This includes deleting any associated
+/* Delete an entry from the code segment. This includes moving any associated
* labels, removing references to labels and even removing the referenced labels
* if the reference count drops to zero.
*/
{
/* Get the code entry for the given index */
- CodeEntry* E = CollAt (&S->Entries, Index);
+ CodeEntry* E = GetCodeEntry (S, Index);
+
+ /* If the entry has a labels, we have to move this label to the next insn.
+ * If there is no next insn, move the label into the code segement label
+ * pool. The operation is further complicated by the fact that the next
+ * 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);
+ if (Count > 0) {
+
+ /* The instruction has labels attached. Check if there is a next
+ * instruction.
+ */
+ if (Index == GetCodeSegEntries (S)-1) {
+
+ /* No next instruction, move to the codeseg label pool */
+ MoveLabelsToPool (S, E);
+
+ } else {
+
+ /* 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);
- /* Remove any labels associated with this entry */
- unsigned Count;
- while ((Count = CollCount (&E->Labels)) > 0) {
- DelCodeLabel (S, CollAt (&E->Labels, Count-1));
+ /* 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);
+
+ }
+
+ }
+ }
}
/* If this insn references a label, remove the reference. And, if the
*/
if (E->JumpTo) {
- /* Remove the reference */
+ /* Remove the reference */
if (RemoveLabelRef (E->JumpTo, E) == 0) {
/* No references remaining, remove the label */
DelCodeLabel (S, E->JumpTo);
+struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index)
+/* Get an entry from the given code segment */
+{
+ return CollAt (&S->Entries, Index);
+}
+
+
+
void AddCodeLabel (CodeSeg* S, const char* Name)
/* Add a code label for the next instruction to follow */
{
CHECK (EntryCount > 0);
/* Get the last entry */
- E = CollAt (&S->Entries, EntryCount-1);
+ E = GetCodeEntry (S, EntryCount-1);
/* Add the hint */
E->Hints |= Hint;
while (Last < Count) {
/* Get the next entry */
- CodeEntry* E = CollAt (&S->Entries, Count-1);
+ CodeEntry* E = GetCodeEntry (S, Count-1);
/* We have to transfer all labels to the code segment label pool */
- unsigned LabelCount = CollCount (&E->Labels);
- while (LabelCount--) {
- CodeLabel* L = CollAt (&E->Labels, LabelCount);
- L->Flags &= ~LF_DEF;
- CollAppend (&S->Labels, L);
- }
- CollDeleteAll (&E->Labels);
+ MoveLabelsToPool (S, E);
/* Remove the code entry */
- FreeCodeEntry (CollAt (&S->Entries, Count-1));
+ FreeCodeEntry (E);
CollDelete (&S->Entries, Count-1);
--Count;
}
-CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash)
-/* Find the label with the given name. Return the label or NULL if not found */
-{
- /* Get the first hash chain entry */
- CodeLabel* L = S->LabelHash[Hash];
-
- /* Search the list */
- while (L) {
- if (strcmp (Name, L->Name) == 0) {
- /* Found */
- break;
- }
- L = L->Next;
- }
- return L;
-}
-
-
-
void MergeCodeLabels (CodeSeg* S)
/* Merge code labels. That means: For each instruction, remove all labels but
* one and adjust the code entries accordingly.
unsigned J;
/* Get a pointer to the next entry */
- CodeEntry* E = CollAt (&S->Entries, I);
+ CodeEntry* E = GetCodeEntry (S, I);
/* If this entry has zero labels, continue with the next one */
unsigned LabelCount = CollCount (&E->Labels);
}
/* We have at least one label. Use the first one as reference label. */
- RefLab = CollAt (&E->Labels, 0);
+ 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
*/
for (J = LabelCount-1; J >= 1; --J) {
- unsigned K;
-
/* Get the next label */
- CodeLabel* L = CollAt (&E->Labels, J);
-
- /* Walk through all instructions referencing this label */
- unsigned RefCount = CollCount (&L->JumpFrom);
- for (K = 0; K < RefCount; ++K) {
-
- /* Get the next instruction that references this label */
- CodeEntry* E = CollAt (&L->JumpFrom, K);
-
- /* Change the reference */
- CHECK (E->JumpTo == L);
- AddLabelRef (RefLab, E);
-
- }
+ CodeLabel* L = GetCodeLabel (E, J);
- /* There are no more instructions jumping to this label now */
- CollDeleteAll (&L->JumpFrom);
+ /* Move all references from this label to the reference label */
+ MoveLabelRefs (L, RefLab);
/* Remove the label completely. */
DelCodeLabel (S, L);
+/*****************************************************************************/
+/* Forwards */
+/*****************************************************************************/
+
+
+
+struct CodeEntry;
+
+
+
/*****************************************************************************/
/* Data */
/*****************************************************************************/
/* Add a line to the given code segment */
void DelCodeEntry (CodeSeg* S, unsigned Index);
-/* Delete an entry from the code segment. This includes deleting any associated
+/* Delete an entry from the code segment. This includes moving any associated
* labels, removing references to labels and even removing the referenced labels
* if the reference count drops to zero.
*/
+struct CodeEntry* GetCodeEntry (CodeSeg* S, unsigned Index);
+/* Get an entry from the given code segment */
+
void AddCodeLabel (CodeSeg* S, const char* Name);
/* Add a code label for the next instruction to follow */
void OutputCodeSeg (const CodeSeg* S, FILE* F);
/* Output the code segment data to a file */
-CodeLabel* FindCodeLabel (CodeSeg* S, const char* Name, unsigned Hash);
-/* Find the label with the given name. Return the label or NULL if not found */
-
void MergeCodeLabels (CodeSeg* S);
/* Merge code labels. That means: For each instruction, remove all labels but
* one and adjust the code entries accordingly.
/* Output translation of type array. */
{
type T;
-
+ unsigned long Size;
/* Walk over the complete string */
while ((T = *Type++) != T_END) {
Type += DECODE_SIZE;
break;
case T_TYPE_ARRAY:
- fprintf (F, "array[%lu] of ", Decode (Type));
- Type += DECODE_SIZE;
- break;
+ /* Recursive call */
+ PrintType (F, Type + DECODE_SIZE);
+ Size = Decode (Type);
+ if (Size == 0) {
+ fprintf (F, "[]");
+ } else {
+ fprintf (F, "[%lu]", Size);
+ }
+ return;
case T_TYPE_PTR:
- fprintf (F, "pointer to ");
- break;
+ /* Recursive call */
+ PrintType (F, Type);
+ fprintf (F, "*");
+ return;
case T_TYPE_FUNC:
fprintf (F, "function returning ");
Type += DECODE_SIZE;
{
int HadReturn;
int IsVoidFunc;
- unsigned Flags;
/* Get the function descriptor from the function entry */
FuncDesc* D = Func->V.F.Func;
RestoreRegVars (!IsVoidFunc);
/* Generate the exit code */
- Flags = IsVoidFunc? CF_NONE : CF_REG;
- g_leave (Flags, 0);
+ g_leave ();
/* Eat the closing brace */
ConsumeRCurly ();
LeaveFunctionLevel ();
/* Switch back to the old segments */
- PopSegments ();
+ PopSegments ();
/* Reset the current function pointer */
FreeFunction (CurrentFunc);
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
{ OPC_AND, "and", 0, REG_A, REG_A, OF_NONE },
{ OPC_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
- { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_BRA },
+ { OPC_BCC, "bcc", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA },
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
- { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_BRA },
+ { OPC_BMI, "bmi", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_BRA },
- { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_BRA },
+ { OPC_BVC, "bvc", 2, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
{ OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
{ OPC_CLD, "cld", 1, REG_NONE, REG_NONE, OF_NONE },
{ OPC_CLI, "cli", 1, REG_NONE, REG_NONE, OF_NONE },
{ OPC_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
{ OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
- { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_BRA },
+ { OPC_JCC, "jcc", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA },
+ { OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA },
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
- { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_BRA },
- { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_BRA },
+ { OPC_JVC, "jvc", 5, REG_NONE, REG_NONE, OF_CBRA },
+ { OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA },
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_NONE },
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_NONE },
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, OF_NONE },
{ OPC_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
{ OPC_ROR, "ror", 0, REG_A, REG_A, OF_NONE },
- { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_NONE },
- { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_NONE },
+ { OPC_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
+ { OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
{ OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
{ OPC_SED, "sed", 1, REG_NONE, REG_NONE, OF_NONE },
+unsigned char GetOPCInfo (opc_t OPC)
+/* Get opcode information */
+{
+ /* Check the range */
+ PRECONDITION (OPC >= (opc_t)0 && OPC < OPC_COUNT);
+
+ /* Return the info */
+ return OPCTable[OPC].Info;
+}
+
+
+
unsigned char GetAMUseInfo (am_t AM)
/* Get usage info for the given addressing mode (addressing modes that use
* index registers return REG_r info for these registers).
opc_t GetInverseBranch (opc_t OPC)
-/* Return a brahcn that reverse the condition of the branch given in OPC */
+/* Return a branch that reverse the condition of the branch given in OPC */
{
switch (OPC) {
case OPC_BCC: return OPC_BCS;
OPC_TXA,
OPC_TXS,
OPC_TYA,
- OPC_COUNT /* Number of opcodes available */
+ OPC_COUNT /* Number of opcodes available */
} opc_t;
/* Addressing modes (bitmapped). */
typedef enum {
- AM_IMP = 0x0001, /* implicit */
- AM_ACC = 0x0002, /* accumulator */
- AM_IMM = 0x0004, /* immidiate */
- AM_ZP = 0x0008, /* zeropage */
- AM_ZPX = 0x0010, /* zeropage,X */
- AM_ABS = 0x0020, /* absolute */
- AM_ABSX = 0x0040, /* absolute,X */
- AM_ABSY = 0x0080, /* absolute,Y */
- AM_ZPX_IND = 0x0100, /* (zeropage,x) */
- AM_ZP_INDY = 0x0200, /* (zeropage),y */
- AM_ZP_IND = 0x0400, /* (zeropage) */
- AM_BRA = 0x0800 /* branch */
+ AM_IMP = 0x0001, /* implicit */
+ AM_ACC = 0x0002, /* accumulator */
+ AM_IMM = 0x0004, /* immidiate */
+ AM_ZP = 0x0008, /* zeropage */
+ AM_ZPX = 0x0010, /* zeropage,X */
+ AM_ABS = 0x0020, /* absolute */
+ AM_ABSX = 0x0040, /* absolute,X */
+ AM_ABSY = 0x0080, /* absolute,Y */
+ AM_ZPX_IND = 0x0100, /* (zeropage,x) */
+ AM_ZP_INDY = 0x0200, /* (zeropage),y */
+ AM_ZP_IND = 0x0400, /* (zeropage) */
+ AM_BRA = 0x0800 /* branch */
} am_t;
/* Opcode info */
-#define OF_NONE 0x0000U /* No additional information */
-#define OF_BRA 0x0001U /* Operation is a jump/branch */
+#define OF_NONE 0x0000U /* No additional information */
+#define OF_UBRA 0x0001U /* Unconditional branch */
+#define OF_CBRA 0x0002U /* Conditional branch */
+#define OF_RET 0x0004U /* Return from function */
+#define OF_BRA (OF_UBRA|OF_CBRA) /* Operation is a jump/branch */
+#define OF_DEAD (OF_UBRA|OF_RET) /* Dead end - no exec behind this point */
/* Opcode description */
typedef struct {
- opc_t OPC; /* Opcode */
- char Mnemo[4]; /* Mnemonic */
- unsigned char Size; /* Size, 0 means "check addressing mode" */
- unsigned char Use; /* Registers used by this insn */
- unsigned char Chg; /* Registers changed/destroyed by this insn */
- unsigned char Info; /* Additional information */
+ opc_t OPC; /* Opcode */
+ char Mnemo[4]; /* Mnemonic */
+ unsigned char Size; /* Size, 0 = check addressing mode */
+ unsigned char Use; /* Registers used by this insn */
+ unsigned char Chg; /* Registers changed by this insn */
+ unsigned char Info; /* Additional information */
} OPCDesc;
const OPCDesc* GetOPCDesc (opc_t OPC);
/* Get an opcode description */
+unsigned char GetOPCInfo (opc_t OPC);
+/* Get opcode information */
+
unsigned char GetAMUseInfo (am_t AM);
/* Get usage info for the given addressing mode (addressing modes that use
* index registers return REG_r info for these registers).
*/
opc_t GetInverseBranch (opc_t OPC);
-/* Return a brahcn that reverse the condition of the branch given in OPC */
+/* Return a branch that reverse the condition of the branch given in OPC */