1
0
mirror of https://github.com/cc65/cc65.git synced 2025-03-04 00:30:35 +00:00

Working on the backend

git-svn-id: svn://svn.cc65.org/cc65/trunk@718 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2001-05-05 21:42:58 +00:00
parent cc9826721b
commit e6a5e57b47
14 changed files with 631 additions and 185 deletions

View File

@ -73,6 +73,7 @@ CodeEntry* NewCodeEntry (const OPCDesc* D, am_t AM, const char* Arg, CodeLabel*
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) {
@ -119,6 +120,51 @@ int CodeEntryHasLabel (const CodeEntry* E)
int CodeEntryHasMark (const CodeEntry* E)
/* Return true if the given code entry has the CEF_USERMARK flag set */
{
return (E->Flags & CEF_USERMARK) != 0;
}
void CodeEntrySetMark (CodeEntry* E)
/* Set the CEF_USERMARK flag for the given entry */
{
E->Flags |= CEF_USERMARK;
}
void CodeEntryResetMark (CodeEntry* E)
/* Reset the CEF_USERMARK flag for the given entry */
{
E->Flags &= ~CEF_USERMARK;
}
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 */
{

View File

@ -69,6 +69,7 @@ struct CodeEntry {
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 */
@ -92,6 +93,21 @@ void FreeCodeEntry (CodeEntry* E);
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 */

View File

@ -396,77 +396,41 @@ void g_enter (unsigned flags, unsigned argsize)
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");
}

View File

@ -206,7 +206,7 @@ void g_scale (unsigned flags, long val);
void g_enter (unsigned flags, unsigned argsize);
/* Function prologue */
void g_leave (int flags, int val);
void g_leave (void);
/* Function epilogue */

View File

@ -36,6 +36,9 @@
#include <stdlib.h>
#include <string.h>
/* common */
#include "coll.h"
/* cc65 */
#include "codeinfo.h"
@ -95,6 +98,12 @@ static const FuncInfo FuncInfoTable[] = {
};
#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 */
};
/*****************************************************************************/
@ -133,6 +142,201 @@ void GetFuncInfo (const char* Name, unsigned char* Use, unsigned char* Chg)
}
}
#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

View File

@ -34,6 +34,7 @@
/* common */
#include "check.h"
#include "xmalloc.h"
/* cc65 */
@ -107,6 +108,30 @@ unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E)
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 */
{

View File

@ -95,6 +95,11 @@ 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 */
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 */

View File

@ -80,12 +80,12 @@ static void OptDeadJumps (CodeSeg* S)
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);
@ -131,13 +131,12 @@ static void OptDeadCode (CodeSeg* S)
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);
@ -189,15 +188,17 @@ static void OptJumpCascades (CodeSeg* S)
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;
@ -230,6 +231,99 @@ static void OptJumpCascades (CodeSeg* S)
/*****************************************************************************/
/* 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 */
/*****************************************************************************/
@ -243,9 +337,10 @@ void RunOpt (CodeSeg* S)
/* 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 */
@ -261,9 +356,9 @@ void RunOpt (CodeSeg* S)
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;
}

View File

@ -52,6 +52,46 @@
/*****************************************************************************/
/* 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 */
/*****************************************************************************/
@ -387,18 +427,66 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
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);
/* Remove any labels associated with this entry */
unsigned Count;
while ((Count = CollCount (&E->Labels)) > 0) {
DelCodeLabel (S, CollAt (&E->Labels, Count-1));
/* 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);
/* 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
@ -406,7 +494,7 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
*/
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);
@ -425,6 +513,14 @@ void DelCodeEntry (CodeSeg* S, unsigned Index)
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 */
{
@ -504,7 +600,7 @@ void AddCodeSegHint (CodeSeg* S, unsigned Hint)
CHECK (EntryCount > 0);
/* Get the last entry */
E = CollAt (&S->Entries, EntryCount-1);
E = GetCodeEntry (S, EntryCount-1);
/* Add the hint */
E->Hints |= Hint;
@ -522,19 +618,13 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
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;
}
@ -576,25 +666,6 @@ void OutputCodeSeg (const CodeSeg* S, FILE* F)
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.
@ -610,7 +681,7 @@ void MergeCodeLabels (CodeSeg* S)
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);
@ -619,7 +690,7 @@ void MergeCodeLabels (CodeSeg* S)
}
/* 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
@ -628,26 +699,11 @@ void MergeCodeLabels (CodeSeg* S)
*/
for (J = LabelCount-1; J >= 1; --J) {
unsigned K;
/* Get the next label */
CodeLabel* L = CollAt (&E->Labels, J);
CodeLabel* L = GetCodeLabel (E, 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);
}
/* 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);

View File

@ -51,6 +51,16 @@
/*****************************************************************************/
/* Forwards */
/*****************************************************************************/
struct CodeEntry;
/*****************************************************************************/
/* Data */
/*****************************************************************************/
@ -85,11 +95,14 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap) attribute ((forma
/* 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 */
@ -105,9 +118,6 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last);
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.

View File

@ -230,7 +230,7 @@ void PrintType (FILE* F, const type* Type)
/* Output translation of type array. */
{
type T;
unsigned long Size;
/* Walk over the complete string */
while ((T = *Type++) != T_END) {
@ -280,12 +280,20 @@ void PrintType (FILE* F, const type* Type)
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;

View File

@ -215,7 +215,6 @@ void NewFunc (SymEntry* Func)
{
int HadReturn;
int IsVoidFunc;
unsigned Flags;
/* Get the function descriptor from the function entry */
FuncDesc* D = Func->V.F.Func;
@ -321,8 +320,7 @@ void NewFunc (SymEntry* Func)
RestoreRegVars (!IsVoidFunc);
/* Generate the exit code */
Flags = IsVoidFunc? CF_NONE : CF_REG;
g_leave (Flags, 0);
g_leave ();
/* Eat the closing brace */
ConsumeRCurly ();
@ -337,7 +335,7 @@ void NewFunc (SymEntry* Func)
LeaveFunctionLevel ();
/* Switch back to the old segments */
PopSegments ();
PopSegments ();
/* Reset the current function pointer */
FreeFunction (CurrentFunc);

View File

@ -58,17 +58,17 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
{ 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 },
@ -85,16 +85,16 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
{ 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 },
@ -111,8 +111,8 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
{ 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 },
@ -214,6 +214,18 @@ const OPCDesc* GetOPCDesc (opc_t OPC)
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).
@ -234,7 +246,7 @@ unsigned char GetAMUseInfo (am_t AM)
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;

View File

@ -119,37 +119,41 @@ typedef enum {
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;
@ -171,13 +175,16 @@ unsigned GetInsnSize (opc_t OPC, am_t AM);
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 */