Working on the backend
git-svn-id: svn://svn.cc65.org/cc65/trunk@718 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -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->Arg = (Arg && Arg[0] != '\0')? xstrdup (Arg) : 0;
|
||||||
E->Num = 0;
|
E->Num = 0;
|
||||||
E->Flags = 0;
|
E->Flags = 0;
|
||||||
|
E->Info = D->Info;
|
||||||
E->Use = D->Use;
|
E->Use = D->Use;
|
||||||
E->Chg = D->Chg;
|
E->Chg = D->Chg;
|
||||||
if (E->OPC == OPC_JSR && E->Arg) {
|
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)
|
void OutputCodeEntry (const CodeEntry* E, FILE* F)
|
||||||
/* Output the code entry to a file */
|
/* Output the code entry to a file */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ struct CodeEntry {
|
|||||||
char* Arg; /* Argument as string */
|
char* Arg; /* Argument as string */
|
||||||
unsigned Num; /* Numeric argument */
|
unsigned Num; /* Numeric argument */
|
||||||
unsigned short Flags; /* Flags */
|
unsigned short Flags; /* Flags */
|
||||||
|
unsigned char Info; /* Additional code info */
|
||||||
unsigned char Use; /* Registers used */
|
unsigned char Use; /* Registers used */
|
||||||
unsigned char Chg; /* Registers changed/destroyed */
|
unsigned char Chg; /* Registers changed/destroyed */
|
||||||
CodeLabel* JumpTo; /* Jump label */
|
CodeLabel* JumpTo; /* Jump label */
|
||||||
@@ -92,6 +93,21 @@ void FreeCodeEntry (CodeEntry* E);
|
|||||||
int CodeEntryHasLabel (const CodeEntry* E);
|
int CodeEntryHasLabel (const CodeEntry* E);
|
||||||
/* Check if the given code entry has labels attached */
|
/* 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);
|
void OutputCodeEntry (const CodeEntry* E, FILE* F);
|
||||||
/* Output the code entry to a file */
|
/* Output the code entry to a 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 */
|
/* 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? */
|
/* 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 we didn't have a variable argument list, don't call leave */
|
||||||
if (funcargs >= 0) {
|
if (funcargs >= 0) {
|
||||||
|
|
||||||
/* Load a function return code if needed */
|
/* Drop stackframe if needed */
|
||||||
if ((flags & CF_CONST) != 0) {
|
|
||||||
g_getimmed (flags, val, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Drop stackframe or leave with rts */
|
|
||||||
k += funcargs;
|
k += funcargs;
|
||||||
if (k == 0) {
|
if (k > 0) {
|
||||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
if (k <= 8) {
|
||||||
AddCodeLine ("rts");
|
AddCodeLine ("jsr incsp%d", k);
|
||||||
} else if (k <= 8) {
|
} else {
|
||||||
AddCodeHint ("y:-"); /* Y register no longer used */
|
CheckLocalOffs (k);
|
||||||
AddCodeLine ("jmp incsp%d", k);
|
ldyconst (k);
|
||||||
} else {
|
AddCodeLine ("jsr addysp");
|
||||||
CheckLocalOffs (k);
|
}
|
||||||
ldyconst (k);
|
|
||||||
AddCodeLine ("jmp addysp");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
strcpy (buf, "\tjmp\tleave");
|
if (k == 0) {
|
||||||
if (k) {
|
/* Nothing to drop */
|
||||||
|
AddCodeLine ("jsr leave");
|
||||||
|
} else {
|
||||||
/* We've a stack frame to drop */
|
/* We've a stack frame to drop */
|
||||||
ldyconst (k);
|
ldyconst (k);
|
||||||
strcat (buf, "y");
|
AddCodeLine ("jsr leavey");
|
||||||
} else {
|
|
||||||
/* Y register no longer used */
|
|
||||||
AddCodeHint ("y:-");
|
|
||||||
}
|
}
|
||||||
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -206,7 +206,7 @@ void g_scale (unsigned flags, long val);
|
|||||||
void g_enter (unsigned flags, unsigned argsize);
|
void g_enter (unsigned flags, unsigned argsize);
|
||||||
/* Function prologue */
|
/* Function prologue */
|
||||||
|
|
||||||
void g_leave (int flags, int val);
|
void g_leave (void);
|
||||||
/* Function epilogue */
|
/* Function epilogue */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
/* common */
|
||||||
|
#include "coll.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codeinfo.h"
|
#include "codeinfo.h"
|
||||||
|
|
||||||
@@ -95,6 +98,12 @@ static const FuncInfo FuncInfoTable[] = {
|
|||||||
};
|
};
|
||||||
#define FuncInfoCount (sizeof(FuncInfoTable) / sizeof(FuncInfoTable[0]))
|
#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
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
|
#include "check.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
/* cc65 */
|
/* 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)
|
void OutputCodeLabel (const CodeLabel* L, FILE* F)
|
||||||
/* Output the code label to a file */
|
/* Output the code label to a file */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -95,6 +95,11 @@ void AddLabelRef (CodeLabel* L, struct CodeEntry* E);
|
|||||||
unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E);
|
unsigned RemoveLabelRef (CodeLabel* L, const struct CodeEntry* E);
|
||||||
/* Remove a reference to this label, return the number of remaining references */
|
/* 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);
|
void OutputCodeLabel (const CodeLabel* L, FILE* F);
|
||||||
/* Output the code label to a file */
|
/* Output the code label to a file */
|
||||||
|
|
||||||
|
|||||||
@@ -80,12 +80,12 @@ static void OptDeadJumps (CodeSeg* S)
|
|||||||
while (I < Count-1) {
|
while (I < Count-1) {
|
||||||
|
|
||||||
/* Get the next entry */
|
/* 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
|
/* Check if it's a branch, if it has a local target, and if the target
|
||||||
* is the next instruction.
|
* 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 */
|
/* Delete the dead jump */
|
||||||
DelCodeEntry (S, I);
|
DelCodeEntry (S, I);
|
||||||
@@ -131,13 +131,12 @@ static void OptDeadCode (CodeSeg* S)
|
|||||||
while (I < Count-1) {
|
while (I < Count-1) {
|
||||||
|
|
||||||
/* Get this entry */
|
/* 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
|
/* Check if it's an unconditional branch, and if the next entry has
|
||||||
* no labels attached
|
* no labels attached
|
||||||
*/
|
*/
|
||||||
if ((E->OPC == OPC_JMP || E->OPC == OPC_BRA || E->OPC == OPC_RTS || E->OPC == OPC_RTI) &&
|
if ((E->Info & OF_DEAD) != 0 && !CodeEntryHasLabel (GetCodeEntry (S, I+1))) {
|
||||||
!CodeEntryHasLabel (CollAt (&S->Entries, I+1))) {
|
|
||||||
|
|
||||||
/* Delete the next entry */
|
/* Delete the next entry */
|
||||||
DelCodeEntry (S, I+1);
|
DelCodeEntry (S, I+1);
|
||||||
@@ -189,15 +188,17 @@ static void OptJumpCascades (CodeSeg* S)
|
|||||||
CodeLabel* NewLabel;
|
CodeLabel* NewLabel;
|
||||||
|
|
||||||
/* Get this entry */
|
/* 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
|
/* 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 &&
|
if (E->AM == AM_BRA && /* It's a branch */
|
||||||
(OldLabel = E->JumpTo) != 0 &&
|
(OldLabel = E->JumpTo) != 0 && /* Label attached */
|
||||||
OldLabel->Owner->AM == AM_BRA &&
|
OldLabel->Owner->AM == AM_BRA && /* Jumps to a branch.. */
|
||||||
(NewLabel = OldLabel->Owner->JumpTo) != 0) {
|
(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 */
|
/* Get the instruction that has the new label attached */
|
||||||
CodeEntry* N = OldLabel->Owner;
|
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 */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -243,9 +337,10 @@ void RunOpt (CodeSeg* S)
|
|||||||
|
|
||||||
/* Table with optimizer steps - are called in this order */
|
/* Table with optimizer steps - are called in this order */
|
||||||
static const OptFunc OptFuncs [] = {
|
static const OptFunc OptFuncs [] = {
|
||||||
OptJumpCascades, /* Optimize jump cascades */
|
OptJumpCascades, /* Optimize jump cascades */
|
||||||
OptDeadJumps, /* Remove dead jumps */
|
OptDeadJumps, /* Remove dead jumps */
|
||||||
OptDeadCode, /* Remove dead code */
|
OptDeadCode, /* Remove dead code */
|
||||||
|
OptRTS, /* Change jsr/rts to jmp */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Repeat all steps until there are no more changes */
|
/* Repeat all steps until there are no more changes */
|
||||||
@@ -261,9 +356,9 @@ void RunOpt (CodeSeg* S)
|
|||||||
Flags = 1UL;
|
Flags = 1UL;
|
||||||
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
for (I = 0; I < sizeof(OptFuncs)/sizeof(OptFuncs[0]); ++I) {
|
||||||
if ((OptDisable & Flags) == 0) {
|
if ((OptDisable & Flags) == 0) {
|
||||||
OptFuncs[I] (S);
|
OptFuncs[I] (S);
|
||||||
} else if (Verbosity > 0 || Debug) {
|
} else if (Verbosity > 0 || Debug) {
|
||||||
printf ("Optimizer pass %u skipped\n", I);
|
printf ("Optimizer pass %u skipped\n", I);
|
||||||
}
|
}
|
||||||
Flags <<= 1;
|
Flags <<= 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 */
|
/* Functions for parsing instructions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -387,18 +427,66 @@ void AddCodeEntry (CodeSeg* S, const char* Format, va_list ap)
|
|||||||
|
|
||||||
|
|
||||||
void DelCodeEntry (CodeSeg* S, unsigned Index)
|
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
|
* labels, removing references to labels and even removing the referenced labels
|
||||||
* if the reference count drops to zero.
|
* if the reference count drops to zero.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* Get the code entry for the given index */
|
/* 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 */
|
/* If the entry has a labels, we have to move this label to the next insn.
|
||||||
unsigned Count;
|
* If there is no next insn, move the label into the code segement label
|
||||||
while ((Count = CollCount (&E->Labels)) > 0) {
|
* pool. The operation is further complicated by the fact that the next
|
||||||
DelCodeLabel (S, CollAt (&E->Labels, Count-1));
|
* 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
|
/* 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) {
|
if (E->JumpTo) {
|
||||||
|
|
||||||
/* Remove the reference */
|
/* Remove the reference */
|
||||||
if (RemoveLabelRef (E->JumpTo, E) == 0) {
|
if (RemoveLabelRef (E->JumpTo, E) == 0) {
|
||||||
/* No references remaining, remove the label */
|
/* No references remaining, remove the label */
|
||||||
DelCodeLabel (S, E->JumpTo);
|
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)
|
void AddCodeLabel (CodeSeg* S, const char* Name)
|
||||||
/* Add a code label for the next instruction to follow */
|
/* Add a code label for the next instruction to follow */
|
||||||
{
|
{
|
||||||
@@ -504,7 +600,7 @@ void AddCodeSegHint (CodeSeg* S, unsigned Hint)
|
|||||||
CHECK (EntryCount > 0);
|
CHECK (EntryCount > 0);
|
||||||
|
|
||||||
/* Get the last entry */
|
/* Get the last entry */
|
||||||
E = CollAt (&S->Entries, EntryCount-1);
|
E = GetCodeEntry (S, EntryCount-1);
|
||||||
|
|
||||||
/* Add the hint */
|
/* Add the hint */
|
||||||
E->Hints |= Hint;
|
E->Hints |= Hint;
|
||||||
@@ -522,19 +618,13 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
|
|||||||
while (Last < Count) {
|
while (Last < Count) {
|
||||||
|
|
||||||
/* Get the next entry */
|
/* 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 */
|
/* We have to transfer all labels to the code segment label pool */
|
||||||
unsigned LabelCount = CollCount (&E->Labels);
|
MoveLabelsToPool (S, E);
|
||||||
while (LabelCount--) {
|
|
||||||
CodeLabel* L = CollAt (&E->Labels, LabelCount);
|
|
||||||
L->Flags &= ~LF_DEF;
|
|
||||||
CollAppend (&S->Labels, L);
|
|
||||||
}
|
|
||||||
CollDeleteAll (&E->Labels);
|
|
||||||
|
|
||||||
/* Remove the code entry */
|
/* Remove the code entry */
|
||||||
FreeCodeEntry (CollAt (&S->Entries, Count-1));
|
FreeCodeEntry (E);
|
||||||
CollDelete (&S->Entries, Count-1);
|
CollDelete (&S->Entries, Count-1);
|
||||||
--Count;
|
--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)
|
void MergeCodeLabels (CodeSeg* S)
|
||||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||||
* one and adjust the code entries accordingly.
|
* one and adjust the code entries accordingly.
|
||||||
@@ -610,7 +681,7 @@ void MergeCodeLabels (CodeSeg* S)
|
|||||||
unsigned J;
|
unsigned J;
|
||||||
|
|
||||||
/* Get a pointer to the next entry */
|
/* 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 */
|
/* If this entry has zero labels, continue with the next one */
|
||||||
unsigned LabelCount = CollCount (&E->Labels);
|
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. */
|
/* 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
|
/* Walk through the remaining labels and change references to these
|
||||||
* labels to a reference to the one and only label. Delete the labels
|
* 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) {
|
for (J = LabelCount-1; J >= 1; --J) {
|
||||||
|
|
||||||
unsigned K;
|
|
||||||
|
|
||||||
/* Get the next label */
|
/* Get the next label */
|
||||||
CodeLabel* L = CollAt (&E->Labels, J);
|
CodeLabel* L = GetCodeLabel (E, J);
|
||||||
|
|
||||||
/* Walk through all instructions referencing this label */
|
/* Move all references from this label to the reference label */
|
||||||
unsigned RefCount = CollCount (&L->JumpFrom);
|
MoveLabelRefs (L, RefLab);
|
||||||
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);
|
|
||||||
|
|
||||||
/* Remove the label completely. */
|
/* Remove the label completely. */
|
||||||
DelCodeLabel (S, L);
|
DelCodeLabel (S, L);
|
||||||
|
|||||||
@@ -51,6 +51,16 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Forwards */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct CodeEntry;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Data */
|
/* 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 */
|
/* Add a line to the given code segment */
|
||||||
|
|
||||||
void DelCodeEntry (CodeSeg* S, unsigned Index);
|
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
|
* labels, removing references to labels and even removing the referenced labels
|
||||||
* if the reference count drops to zero.
|
* 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);
|
void AddCodeLabel (CodeSeg* S, const char* Name);
|
||||||
/* Add a code label for the next instruction to follow */
|
/* 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);
|
void OutputCodeSeg (const CodeSeg* S, FILE* F);
|
||||||
/* Output the code segment data to a file */
|
/* 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);
|
void MergeCodeLabels (CodeSeg* S);
|
||||||
/* Merge code labels. That means: For each instruction, remove all labels but
|
/* Merge code labels. That means: For each instruction, remove all labels but
|
||||||
* one and adjust the code entries accordingly.
|
* one and adjust the code entries accordingly.
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ void PrintType (FILE* F, const type* Type)
|
|||||||
/* Output translation of type array. */
|
/* Output translation of type array. */
|
||||||
{
|
{
|
||||||
type T;
|
type T;
|
||||||
|
unsigned long Size;
|
||||||
|
|
||||||
/* Walk over the complete string */
|
/* Walk over the complete string */
|
||||||
while ((T = *Type++) != T_END) {
|
while ((T = *Type++) != T_END) {
|
||||||
@@ -280,12 +280,20 @@ void PrintType (FILE* F, const type* Type)
|
|||||||
Type += DECODE_SIZE;
|
Type += DECODE_SIZE;
|
||||||
break;
|
break;
|
||||||
case T_TYPE_ARRAY:
|
case T_TYPE_ARRAY:
|
||||||
fprintf (F, "array[%lu] of ", Decode (Type));
|
/* Recursive call */
|
||||||
Type += DECODE_SIZE;
|
PrintType (F, Type + DECODE_SIZE);
|
||||||
break;
|
Size = Decode (Type);
|
||||||
|
if (Size == 0) {
|
||||||
|
fprintf (F, "[]");
|
||||||
|
} else {
|
||||||
|
fprintf (F, "[%lu]", Size);
|
||||||
|
}
|
||||||
|
return;
|
||||||
case T_TYPE_PTR:
|
case T_TYPE_PTR:
|
||||||
fprintf (F, "pointer to ");
|
/* Recursive call */
|
||||||
break;
|
PrintType (F, Type);
|
||||||
|
fprintf (F, "*");
|
||||||
|
return;
|
||||||
case T_TYPE_FUNC:
|
case T_TYPE_FUNC:
|
||||||
fprintf (F, "function returning ");
|
fprintf (F, "function returning ");
|
||||||
Type += DECODE_SIZE;
|
Type += DECODE_SIZE;
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ void NewFunc (SymEntry* Func)
|
|||||||
{
|
{
|
||||||
int HadReturn;
|
int HadReturn;
|
||||||
int IsVoidFunc;
|
int IsVoidFunc;
|
||||||
unsigned Flags;
|
|
||||||
|
|
||||||
/* Get the function descriptor from the function entry */
|
/* Get the function descriptor from the function entry */
|
||||||
FuncDesc* D = Func->V.F.Func;
|
FuncDesc* D = Func->V.F.Func;
|
||||||
@@ -321,8 +320,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
RestoreRegVars (!IsVoidFunc);
|
RestoreRegVars (!IsVoidFunc);
|
||||||
|
|
||||||
/* Generate the exit code */
|
/* Generate the exit code */
|
||||||
Flags = IsVoidFunc? CF_NONE : CF_REG;
|
g_leave ();
|
||||||
g_leave (Flags, 0);
|
|
||||||
|
|
||||||
/* Eat the closing brace */
|
/* Eat the closing brace */
|
||||||
ConsumeRCurly ();
|
ConsumeRCurly ();
|
||||||
@@ -337,7 +335,7 @@ void NewFunc (SymEntry* Func)
|
|||||||
LeaveFunctionLevel ();
|
LeaveFunctionLevel ();
|
||||||
|
|
||||||
/* Switch back to the old segments */
|
/* Switch back to the old segments */
|
||||||
PopSegments ();
|
PopSegments ();
|
||||||
|
|
||||||
/* Reset the current function pointer */
|
/* Reset the current function pointer */
|
||||||
FreeFunction (CurrentFunc);
|
FreeFunction (CurrentFunc);
|
||||||
|
|||||||
@@ -58,17 +58,17 @@ static const OPCDesc OPCTable[OPC_COUNT] = {
|
|||||||
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_ADC, "adc", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_AND, "and", 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_ASL, "asl", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_BCC, "bcc", 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_BRA },
|
{ OPC_BCS, "bcs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_BEQ, "beq", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
{ OPC_BIT, "bit", 0, REG_A, REG_NONE, OF_NONE },
|
||||||
{ OPC_BMI, "bmi", 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_BRA },
|
{ OPC_BNE, "bne", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_BPL, "bpl", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_BRA, "bra", 2, REG_NONE, REG_NONE, OF_UBRA },
|
||||||
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_BRK, "brk", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_BVC, "bvc", 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_BRA },
|
{ OPC_BVS, "bvs", 2, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_CLC, "clc", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_CLD, "cld", 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_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_INC, "inc", 0, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
{ OPC_INX, "inx", 1, REG_X, REG_X, OF_NONE },
|
||||||
{ OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
|
{ OPC_INY, "iny", 1, REG_Y, REG_Y, OF_NONE },
|
||||||
{ OPC_JCC, "jcc", 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_BRA },
|
{ OPC_JCS, "jcs", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_JEQ, "jeq", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_JMI, "jmi", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_JMP, "jmp", 3, REG_NONE, REG_NONE, OF_UBRA },
|
||||||
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_JNE, "jne", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_BRA },
|
{ OPC_JPL, "jpl", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_JSR, "jsr", 3, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_JVC, "jvc", 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_BRA },
|
{ OPC_JVS, "jvs", 5, REG_NONE, REG_NONE, OF_CBRA },
|
||||||
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_NONE },
|
{ OPC_LDA, "lda", 0, REG_NONE, REG_A, OF_NONE },
|
||||||
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_NONE },
|
{ OPC_LDX, "ldx", 0, REG_NONE, REG_X, OF_NONE },
|
||||||
{ OPC_LDY, "ldy", 0, REG_NONE, REG_Y, 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_PLY, "ply", 1, REG_NONE, REG_Y, OF_NONE },
|
||||||
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_ROL, "rol", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_ROR, "ror", 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_RTI, "rti", 1, REG_NONE, REG_NONE, OF_RET },
|
||||||
{ OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_RTS, "rts", 1, REG_NONE, REG_NONE, OF_RET },
|
||||||
{ OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
|
{ OPC_SBC, "sbc", 0, REG_A, REG_A, OF_NONE },
|
||||||
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
{ OPC_SEC, "sec", 1, REG_NONE, REG_NONE, OF_NONE },
|
||||||
{ OPC_SED, "sed", 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)
|
unsigned char GetAMUseInfo (am_t AM)
|
||||||
/* Get usage info for the given addressing mode (addressing modes that use
|
/* Get usage info for the given addressing mode (addressing modes that use
|
||||||
* index registers return REG_r info for these registers).
|
* 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)
|
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) {
|
switch (OPC) {
|
||||||
case OPC_BCC: return OPC_BCS;
|
case OPC_BCC: return OPC_BCS;
|
||||||
|
|||||||
@@ -119,37 +119,41 @@ typedef enum {
|
|||||||
OPC_TXA,
|
OPC_TXA,
|
||||||
OPC_TXS,
|
OPC_TXS,
|
||||||
OPC_TYA,
|
OPC_TYA,
|
||||||
OPC_COUNT /* Number of opcodes available */
|
OPC_COUNT /* Number of opcodes available */
|
||||||
} opc_t;
|
} opc_t;
|
||||||
|
|
||||||
/* Addressing modes (bitmapped). */
|
/* Addressing modes (bitmapped). */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
AM_IMP = 0x0001, /* implicit */
|
AM_IMP = 0x0001, /* implicit */
|
||||||
AM_ACC = 0x0002, /* accumulator */
|
AM_ACC = 0x0002, /* accumulator */
|
||||||
AM_IMM = 0x0004, /* immidiate */
|
AM_IMM = 0x0004, /* immidiate */
|
||||||
AM_ZP = 0x0008, /* zeropage */
|
AM_ZP = 0x0008, /* zeropage */
|
||||||
AM_ZPX = 0x0010, /* zeropage,X */
|
AM_ZPX = 0x0010, /* zeropage,X */
|
||||||
AM_ABS = 0x0020, /* absolute */
|
AM_ABS = 0x0020, /* absolute */
|
||||||
AM_ABSX = 0x0040, /* absolute,X */
|
AM_ABSX = 0x0040, /* absolute,X */
|
||||||
AM_ABSY = 0x0080, /* absolute,Y */
|
AM_ABSY = 0x0080, /* absolute,Y */
|
||||||
AM_ZPX_IND = 0x0100, /* (zeropage,x) */
|
AM_ZPX_IND = 0x0100, /* (zeropage,x) */
|
||||||
AM_ZP_INDY = 0x0200, /* (zeropage),y */
|
AM_ZP_INDY = 0x0200, /* (zeropage),y */
|
||||||
AM_ZP_IND = 0x0400, /* (zeropage) */
|
AM_ZP_IND = 0x0400, /* (zeropage) */
|
||||||
AM_BRA = 0x0800 /* branch */
|
AM_BRA = 0x0800 /* branch */
|
||||||
} am_t;
|
} am_t;
|
||||||
|
|
||||||
/* Opcode info */
|
/* Opcode info */
|
||||||
#define OF_NONE 0x0000U /* No additional information */
|
#define OF_NONE 0x0000U /* No additional information */
|
||||||
#define OF_BRA 0x0001U /* Operation is a jump/branch */
|
#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 */
|
/* Opcode description */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
opc_t OPC; /* Opcode */
|
opc_t OPC; /* Opcode */
|
||||||
char Mnemo[4]; /* Mnemonic */
|
char Mnemo[4]; /* Mnemonic */
|
||||||
unsigned char Size; /* Size, 0 means "check addressing mode" */
|
unsigned char Size; /* Size, 0 = check addressing mode */
|
||||||
unsigned char Use; /* Registers used by this insn */
|
unsigned char Use; /* Registers used by this insn */
|
||||||
unsigned char Chg; /* Registers changed/destroyed by this insn */
|
unsigned char Chg; /* Registers changed by this insn */
|
||||||
unsigned char Info; /* Additional information */
|
unsigned char Info; /* Additional information */
|
||||||
} OPCDesc;
|
} OPCDesc;
|
||||||
|
|
||||||
|
|
||||||
@@ -171,13 +175,16 @@ unsigned GetInsnSize (opc_t OPC, am_t AM);
|
|||||||
const OPCDesc* GetOPCDesc (opc_t OPC);
|
const OPCDesc* GetOPCDesc (opc_t OPC);
|
||||||
/* Get an opcode description */
|
/* Get an opcode description */
|
||||||
|
|
||||||
|
unsigned char GetOPCInfo (opc_t OPC);
|
||||||
|
/* Get opcode information */
|
||||||
|
|
||||||
unsigned char GetAMUseInfo (am_t AM);
|
unsigned char GetAMUseInfo (am_t AM);
|
||||||
/* Get usage info for the given addressing mode (addressing modes that use
|
/* Get usage info for the given addressing mode (addressing modes that use
|
||||||
* index registers return REG_r info for these registers).
|
* index registers return REG_r info for these registers).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
opc_t GetInverseBranch (opc_t OPC);
|
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 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user