Working
git-svn-id: svn://svn.cc65.org/cc65/trunk@735 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -42,7 +42,9 @@
|
|||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codeent.h"
|
#include "codeent.h"
|
||||||
#include "codeseg.h"
|
#include "codeseg.h"
|
||||||
|
#include "datatype.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
|
#include "symtab.h"
|
||||||
#include "codeinfo.h"
|
#include "codeinfo.h"
|
||||||
|
|
||||||
|
|
||||||
@@ -132,20 +134,63 @@ void GetFuncInfo (const char* Name, unsigned char* Use, unsigned char* Chg)
|
|||||||
* load all registers.
|
* load all registers.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
/* Search for the function */
|
/* If the function name starts with an underline, it is an external
|
||||||
const FuncInfo* Info = bsearch (Name, FuncInfoTable, FuncInfoCount,
|
* function. Search for it in the symbol table. If the function does
|
||||||
sizeof(FuncInfo), CompareFuncInfo);
|
* not start with an underline, it may be a runtime support function.
|
||||||
|
* Search for it in the list of builtin functions.
|
||||||
|
*/
|
||||||
|
if (Name[0] == '_') {
|
||||||
|
|
||||||
|
/* Search in the symbol table, skip the leading underscore */
|
||||||
|
SymEntry* E = FindSym (Name+1);
|
||||||
|
|
||||||
|
/* Did we find it in the top level table? */
|
||||||
|
if (E && E->Owner->PrevTab == 0 && IsTypeFunc (E->Type)) {
|
||||||
|
|
||||||
|
/* A function may use the A or A/X registers if it is a fastcall
|
||||||
|
* function. Otherwise it does not use any registers passed by
|
||||||
|
* the caller. However, we assume that any function will destroy
|
||||||
|
* all registers.
|
||||||
|
*/
|
||||||
|
FuncDesc* D = E->V.F.Func;
|
||||||
|
if ((D->Flags & FD_FASTCALL) != 0 && D->ParamCount > 0) {
|
||||||
|
/* Will use registers depending on the last param */
|
||||||
|
SymEntry* LastParam = D->SymTab->SymTail;
|
||||||
|
if (SizeOf (LastParam->Type) == 1) {
|
||||||
|
*Use = REG_A;
|
||||||
|
} else {
|
||||||
|
*Use = REG_AX;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Will not use any registers */
|
||||||
|
*Use = REG_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Will destroy all registers */
|
||||||
|
*Chg = REG_AXY;
|
||||||
|
|
||||||
|
/* Done */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Do we know the function? */
|
|
||||||
if (Info) {
|
|
||||||
/* Use the information we have */
|
|
||||||
*Use = Info->Use;
|
|
||||||
*Chg = Info->Chg;
|
|
||||||
} else {
|
} else {
|
||||||
/* Assume all registers used */
|
|
||||||
*Use = REG_AXY;
|
/* Search for the function in the list of builtin functions */
|
||||||
*Chg = REG_AXY;
|
const FuncInfo* Info = bsearch (Name, FuncInfoTable, FuncInfoCount,
|
||||||
|
sizeof(FuncInfo), CompareFuncInfo);
|
||||||
|
|
||||||
|
/* Do we know the function? */
|
||||||
|
if (Info) {
|
||||||
|
/* Use the information we have */
|
||||||
|
*Use = Info->Use;
|
||||||
|
*Chg = Info->Chg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Function not found - assume all registers used */
|
||||||
|
*Use = REG_AXY;
|
||||||
|
*Chg = REG_AXY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ static int IsLocalLoad16 (CodeSeg* S, unsigned Index,
|
|||||||
L[3]->OPC == OPC_DEY &&
|
L[3]->OPC == OPC_DEY &&
|
||||||
!CodeEntryHasLabel (L[3]) &&
|
!CodeEntryHasLabel (L[3]) &&
|
||||||
IsSpLoad (L[4]) &&
|
IsSpLoad (L[4]) &&
|
||||||
!CodeEntryHasLabel (L[4]));
|
!CodeEntryHasLabel (L[4]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -420,6 +420,196 @@ NextEntry:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Optimize subtractions */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned OptSub1 (CodeSeg* S)
|
||||||
|
/* Search for the sequence
|
||||||
|
*
|
||||||
|
* sbc ...
|
||||||
|
* bcs L
|
||||||
|
* dex
|
||||||
|
* L:
|
||||||
|
*
|
||||||
|
* and remove the handling of the high byte if X is not used later.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
unsigned I = 0;
|
||||||
|
while (I < GetCodeEntryCount (S)) {
|
||||||
|
|
||||||
|
CodeEntry* L[3];
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = GetCodeEntry (S, I);
|
||||||
|
|
||||||
|
/* Check for the sequence */
|
||||||
|
if (E->OPC == OPC_SBC &&
|
||||||
|
GetCodeEntries (S, L, I+1, 3) &&
|
||||||
|
(L[0]->OPC == OPC_BCS || L[0]->OPC == OPC_JCS) &&
|
||||||
|
L[0]->JumpTo != 0 &&
|
||||||
|
!CodeEntryHasLabel (L[0]) &&
|
||||||
|
L[1]->OPC == OPC_DEX &&
|
||||||
|
!CodeEntryHasLabel (L[1]) &&
|
||||||
|
L[0]->JumpTo->Owner == L[2] &&
|
||||||
|
!RegXUsed (S, I+3)) {
|
||||||
|
|
||||||
|
/* Remove the bcs/dex */
|
||||||
|
DelCodeEntries (S, I+1, 2);
|
||||||
|
|
||||||
|
/* Remember, we had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned OptSub2 (CodeSeg* S)
|
||||||
|
/* Search for the sequence
|
||||||
|
*
|
||||||
|
* lda xx
|
||||||
|
* sec
|
||||||
|
* sta tmp1
|
||||||
|
* lda yy
|
||||||
|
* sbc tmp1
|
||||||
|
* sta yy
|
||||||
|
*
|
||||||
|
* and replace it by
|
||||||
|
*
|
||||||
|
* sec
|
||||||
|
* lda yy
|
||||||
|
* sbc xx
|
||||||
|
* sta yy
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
unsigned I = 0;
|
||||||
|
while (I < GetCodeEntryCount (S)) {
|
||||||
|
|
||||||
|
CodeEntry* L[5];
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = GetCodeEntry (S, I);
|
||||||
|
|
||||||
|
/* Check for the sequence */
|
||||||
|
if (E->OPC == OPC_LDA &&
|
||||||
|
GetCodeEntries (S, L, I+1, 5) &&
|
||||||
|
L[0]->OPC == OPC_SEC &&
|
||||||
|
!CodeEntryHasLabel (L[0]) &&
|
||||||
|
L[1]->OPC == OPC_STA &&
|
||||||
|
strcmp (L[1]->Arg, "tmp1") == 0 &&
|
||||||
|
!CodeEntryHasLabel (L[1]) &&
|
||||||
|
L[2]->OPC == OPC_LDA &&
|
||||||
|
!CodeEntryHasLabel (L[2]) &&
|
||||||
|
L[3]->OPC == OPC_SBC &&
|
||||||
|
strcmp (L[3]->Arg, "tmp1") == 0 &&
|
||||||
|
!CodeEntryHasLabel (L[3]) &&
|
||||||
|
L[4]->OPC == OPC_STA &&
|
||||||
|
strcmp (L[4]->Arg, L[2]->Arg) == 0 &&
|
||||||
|
!CodeEntryHasLabel (L[4])) {
|
||||||
|
|
||||||
|
/* Remove the store to tmp1 */
|
||||||
|
DelCodeEntry (S, I+2);
|
||||||
|
|
||||||
|
/* Remove the subtraction */
|
||||||
|
DelCodeEntry (S, I+3);
|
||||||
|
|
||||||
|
/* Move the lda to the position of the subtraction and change the
|
||||||
|
* op to SBC.
|
||||||
|
*/
|
||||||
|
MoveCodeEntry (S, I, I+3);
|
||||||
|
ReplaceOPC (E, OPC_SBC);
|
||||||
|
|
||||||
|
/* Remember, we had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Optimize additions */
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned OptAdd1 (CodeSeg* S)
|
||||||
|
/* Search for the sequence
|
||||||
|
*
|
||||||
|
* adc ...
|
||||||
|
* bcc L
|
||||||
|
* inx
|
||||||
|
* L:
|
||||||
|
*
|
||||||
|
* and remove the handling of the high byte if X is not used later.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
unsigned I = 0;
|
||||||
|
while (I < GetCodeEntryCount (S)) {
|
||||||
|
|
||||||
|
CodeEntry* L[3];
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = GetCodeEntry (S, I);
|
||||||
|
|
||||||
|
/* Check for the sequence */
|
||||||
|
if (E->OPC == OPC_ADC &&
|
||||||
|
GetCodeEntries (S, L, I+1, 3) &&
|
||||||
|
(L[0]->OPC == OPC_BCC || L[0]->OPC == OPC_JCC) &&
|
||||||
|
L[0]->JumpTo != 0 &&
|
||||||
|
!CodeEntryHasLabel (L[0]) &&
|
||||||
|
L[1]->OPC == OPC_INX &&
|
||||||
|
!CodeEntryHasLabel (L[1]) &&
|
||||||
|
L[0]->JumpTo->Owner == L[2] &&
|
||||||
|
!RegXUsed (S, I+3)) {
|
||||||
|
|
||||||
|
/* Remove the bcs/dex */
|
||||||
|
DelCodeEntries (S, I+1, 2);
|
||||||
|
|
||||||
|
/* Remember, we had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Optimizations for compares */
|
/* Optimizations for compares */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -1007,6 +1197,11 @@ struct OptFunc {
|
|||||||
|
|
||||||
/* Table with optimizer steps - are called in this order */
|
/* Table with optimizer steps - are called in this order */
|
||||||
static OptFunc OptFuncs [] = {
|
static OptFunc OptFuncs [] = {
|
||||||
|
/* Optimize subtractions */
|
||||||
|
{ OptSub1, "OptSub1", 0 },
|
||||||
|
{ OptSub2, "OptSub2", 0 },
|
||||||
|
/* Optimize additions */
|
||||||
|
{ OptAdd1, "OptAdd1", 0 },
|
||||||
/* Optimize jump cascades */
|
/* Optimize jump cascades */
|
||||||
{ OptJumpCascades, "OptJumpCascades", 0 },
|
{ OptJumpCascades, "OptJumpCascades", 0 },
|
||||||
/* Remove dead jumps */
|
/* Remove dead jumps */
|
||||||
@@ -1025,21 +1220,15 @@ static OptFunc OptFuncs [] = {
|
|||||||
{ OptBoolTransforms, "OptBoolTransforms", 0 },
|
{ OptBoolTransforms, "OptBoolTransforms", 0 },
|
||||||
/* Optimize calls to nega */
|
/* Optimize calls to nega */
|
||||||
{ OptNegA1, "OptNegA1", 0 },
|
{ OptNegA1, "OptNegA1", 0 },
|
||||||
/* Optimize calls to nega */
|
|
||||||
{ OptNegA2, "OptNegA2", 0 },
|
{ OptNegA2, "OptNegA2", 0 },
|
||||||
/* Optimize calls to negax */
|
/* Optimize calls to negax */
|
||||||
{ OptNegAX1, "OptNegAX1", 0 },
|
{ OptNegAX1, "OptNegAX1", 0 },
|
||||||
/* Optimize calls to negax */
|
|
||||||
{ OptNegAX2, "OptNegAX2", 0 },
|
{ OptNegAX2, "OptNegAX2", 0 },
|
||||||
/* Optimize calls to negax */
|
|
||||||
{ OptNegAX3, "OptNegAX3", 0 },
|
{ OptNegAX3, "OptNegAX3", 0 },
|
||||||
/* Optimize compares */
|
/* Optimize compares */
|
||||||
{ OptCmp1, "OptCmp1", 0 },
|
{ OptCmp1, "OptCmp1", 0 },
|
||||||
/* Optimize compares */
|
|
||||||
{ OptCmp2, "OptCmp2", 0 },
|
{ OptCmp2, "OptCmp2", 0 },
|
||||||
/* Optimize compares */
|
|
||||||
{ OptCmp3, "OptCmp3", 0 },
|
{ OptCmp3, "OptCmp3", 0 },
|
||||||
/* Optimize compares */
|
|
||||||
{ OptCmp4, "OptCmp4", 0 },
|
{ OptCmp4, "OptCmp4", 0 },
|
||||||
/* Remove unused loads */
|
/* Remove unused loads */
|
||||||
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
{ OptUnusedLoads, "OptUnusedLoads", 0 },
|
||||||
|
|||||||
@@ -889,6 +889,16 @@ void DelCodeSegAfter (CodeSeg* S, unsigned Last)
|
|||||||
|
|
||||||
/* Check if this entry has a label reference */
|
/* Check if this entry has a label reference */
|
||||||
if (E->JumpTo) {
|
if (E->JumpTo) {
|
||||||
|
/* If the label is a label in the label pool and this is the last
|
||||||
|
* reference to the label, remove the label from the pool.
|
||||||
|
*/
|
||||||
|
CodeLabel* L = E->JumpTo;
|
||||||
|
int Index = CollIndex (&S->Labels, L);
|
||||||
|
if (Index >= 0 && CollCount (&L->JumpFrom) == 1) {
|
||||||
|
/* Delete it from the pool */
|
||||||
|
CollDelete (&S->Labels, Index);
|
||||||
|
}
|
||||||
|
|
||||||
/* Remove the reference to the label */
|
/* Remove the reference to the label */
|
||||||
RemoveCodeLabelRef (S, E);
|
RemoveCodeLabelRef (S, E);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,10 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "../common/xmalloc.h"
|
/* common */
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
/* cc65 */
|
||||||
#include "funcdesc.h"
|
#include "funcdesc.h"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ struct FuncDesc {
|
|||||||
FuncDesc* NewFuncDesc (void);
|
FuncDesc* NewFuncDesc (void);
|
||||||
/* Create a new symbol table with the given name */
|
/* Create a new symbol table with the given name */
|
||||||
|
|
||||||
void FreeFuncDesc (FuncDesc* E);
|
void FreeFuncDesc (FuncDesc* D);
|
||||||
/* Free a function descriptor */
|
/* Free a function descriptor */
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user