From e6a5e57b472f091fb48dfd749c4012f9d65c1da0 Mon Sep 17 00:00:00 2001 From: cuz Date: Sat, 5 May 2001 21:42:58 +0000 Subject: [PATCH] Working on the backend git-svn-id: svn://svn.cc65.org/cc65/trunk@718 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/cc65/codeent.c | 46 ++++++++++ src/cc65/codeent.h | 16 ++++ src/cc65/codegen.c | 74 +++++----------- src/cc65/codegen.h | 2 +- src/cc65/codeinfo.c | 204 ++++++++++++++++++++++++++++++++++++++++++++ src/cc65/codelab.c | 25 ++++++ src/cc65/codelab.h | 5 ++ src/cc65/codeopt.c | 127 +++++++++++++++++++++++---- src/cc65/codeseg.c | 168 ++++++++++++++++++++++++------------ src/cc65/codeseg.h | 18 +++- src/cc65/datatype.c | 20 +++-- src/cc65/function.c | 6 +- src/cc65/opcodes.c | 54 +++++++----- src/cc65/opcodes.h | 51 ++++++----- 14 files changed, 631 insertions(+), 185 deletions(-) diff --git a/src/cc65/codeent.c b/src/cc65/codeent.c index bdf8d268a..d8f852bc9 100644 --- a/src/cc65/codeent.c +++ b/src/cc65/codeent.c @@ -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 */ { diff --git a/src/cc65/codeent.h b/src/cc65/codeent.h index fbcc04e5a..ab0790989 100644 --- a/src/cc65/codeent.h +++ b/src/cc65/codeent.h @@ -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 */ diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index a41f9dfa2..81273b013 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -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"); } diff --git a/src/cc65/codegen.h b/src/cc65/codegen.h index 02b9fadee..7a37c98d3 100644 --- a/src/cc65/codegen.h +++ b/src/cc65/codegen.h @@ -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 */ diff --git a/src/cc65/codeinfo.c b/src/cc65/codeinfo.c index 0dc89acb1..1f89ef14a 100644 --- a/src/cc65/codeinfo.c +++ b/src/cc65/codeinfo.c @@ -36,6 +36,9 @@ #include #include +/* 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 diff --git a/src/cc65/codelab.c b/src/cc65/codelab.c index 237e50a32..97ed7e3b8 100644 --- a/src/cc65/codelab.c +++ b/src/cc65/codelab.c @@ -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 */ { diff --git a/src/cc65/codelab.h b/src/cc65/codelab.h index 619842862..0aef14857 100644 --- a/src/cc65/codelab.h +++ b/src/cc65/codelab.h @@ -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 */ diff --git a/src/cc65/codeopt.c b/src/cc65/codeopt.c index 72d425d83..241934187 100644 --- a/src/cc65/codeopt.c +++ b/src/cc65/codeopt.c @@ -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; } diff --git a/src/cc65/codeseg.c b/src/cc65/codeseg.c index 907f9db38..5c54b2231 100644 --- a/src/cc65/codeseg.c +++ b/src/cc65/codeseg.c @@ -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); + + /* 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 @@ -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); - - /* 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); diff --git a/src/cc65/codeseg.h b/src/cc65/codeseg.h index 4940f39d2..e7a2fdaf1 100644 --- a/src/cc65/codeseg.h +++ b/src/cc65/codeseg.h @@ -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. diff --git a/src/cc65/datatype.c b/src/cc65/datatype.c index 1c2f0a3ef..4da5470b9 100644 --- a/src/cc65/datatype.c +++ b/src/cc65/datatype.c @@ -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; diff --git a/src/cc65/function.c b/src/cc65/function.c index 69b653665..463c4f2c6 100644 --- a/src/cc65/function.c +++ b/src/cc65/function.c @@ -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); diff --git a/src/cc65/opcodes.c b/src/cc65/opcodes.c index fce753530..11888de9c 100644 --- a/src/cc65/opcodes.c +++ b/src/cc65/opcodes.c @@ -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; diff --git a/src/cc65/opcodes.h b/src/cc65/opcodes.h index 4f1126c73..bc827dd1a 100644 --- a/src/cc65/opcodes.h +++ b/src/cc65/opcodes.h @@ -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 */ -- 2.39.5