mirror of
https://github.com/cc65/cc65.git
synced 2025-02-11 15:30:52 +00:00
Track usage of the sreg and several other zero page registers and remove
unused stores into these registers. Because of this, the old code using regsave does no longer work. Started to rewrite it. git-svn-id: svn://svn.cc65.org/cc65/trunk@966 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
f28be6d657
commit
f4fbbc3dcc
@ -412,6 +412,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_ASL:
|
case OP65_ASL:
|
||||||
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
||||||
Out->RegA = (In->RegA << 1) & 0xFF;
|
Out->RegA = (In->RegA << 1) & 0xFF;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if ((E->Chg & REG_SREG_LO) != 0 && In->SRegLo >= 0) {
|
||||||
|
Out->SRegLo = (In->SRegLo << 1) & 0xFF;
|
||||||
|
} else if ((E->Chg & REG_SREG_HI) != 0 && In->SRegHi >= 0) {
|
||||||
|
Out->SRegHi = (In->SRegHi << 1) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -471,25 +477,31 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
|
|
||||||
case OP65_DEA:
|
case OP65_DEA:
|
||||||
if (In->RegA >= 0) {
|
if (In->RegA >= 0) {
|
||||||
Out->RegA = In->RegA - 1;
|
Out->RegA = (In->RegA - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEC:
|
case OP65_DEC:
|
||||||
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
||||||
Out->RegA = In->RegA - 1;
|
Out->RegA = (In->RegA - 1) & 0xFF;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if ((E->Chg & REG_SREG_LO) != 0 && In->SRegLo >= 0) {
|
||||||
|
Out->SRegLo = (In->SRegLo - 1) & 0xFF;
|
||||||
|
} else if ((E->Chg & REG_SREG_HI) != 0 && In->SRegHi >= 0) {
|
||||||
|
Out->SRegHi = (In->SRegHi - 1) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEX:
|
case OP65_DEX:
|
||||||
if (In->RegX >= 0) {
|
if (In->RegX >= 0) {
|
||||||
Out->RegX = In->RegX - 1;
|
Out->RegX = (In->RegX - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEY:
|
case OP65_DEY:
|
||||||
if (In->RegY >= 0) {
|
if (In->RegY >= 0) {
|
||||||
Out->RegY = In->RegY - 1;
|
Out->RegY = (In->RegY - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -505,25 +517,31 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
|
|
||||||
case OP65_INA:
|
case OP65_INA:
|
||||||
if (In->RegA >= 0) {
|
if (In->RegA >= 0) {
|
||||||
Out->RegA = In->RegA + 1;
|
Out->RegA = (In->RegA + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INC:
|
case OP65_INC:
|
||||||
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
||||||
Out->RegA = In->RegA + 1;
|
Out->RegA = (In->RegA + 1) & 0xFF;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if ((E->Chg & REG_SREG_LO) != 0 && In->SRegLo >= 0) {
|
||||||
|
Out->SRegLo = (In->SRegLo + 1) & 0xFF;
|
||||||
|
} else if ((E->Chg & REG_SREG_HI) != 0 && In->SRegHi >= 0) {
|
||||||
|
Out->SRegHi = (In->SRegHi + 1) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INX:
|
case OP65_INX:
|
||||||
if (In->RegX >= 0) {
|
if (In->RegX >= 0) {
|
||||||
Out->RegX = In->RegX + 1;
|
Out->RegX = (In->RegX + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INY:
|
case OP65_INY:
|
||||||
if (In->RegY >= 0) {
|
if (In->RegY >= 0) {
|
||||||
Out->RegY = In->RegY + 1;
|
Out->RegY = (In->RegY + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -560,6 +578,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
if (Chg & REG_Y) {
|
if (Chg & REG_Y) {
|
||||||
Out->RegY = -1;
|
Out->RegY = -1;
|
||||||
}
|
}
|
||||||
|
if (Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = -1;
|
||||||
|
}
|
||||||
|
if (Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = -1;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_JVC:
|
case OP65_JVC:
|
||||||
@ -571,6 +595,14 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_LDA:
|
case OP65_LDA:
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegA = (unsigned char) E->Num;
|
Out->RegA = (unsigned char) E->Num;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Use & REG_SREG_LO) {
|
||||||
|
Out->RegA = In->SRegLo;
|
||||||
|
} else if (E->Use & REG_SREG_HI) {
|
||||||
|
Out->RegA = In->SRegHi;
|
||||||
|
} else {
|
||||||
|
Out->RegA = -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A is now unknown */
|
/* A is now unknown */
|
||||||
Out->RegA = -1;
|
Out->RegA = -1;
|
||||||
@ -580,6 +612,14 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_LDX:
|
case OP65_LDX:
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegX = (unsigned char) E->Num;
|
Out->RegX = (unsigned char) E->Num;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Use & REG_SREG_LO) {
|
||||||
|
Out->RegX = In->SRegLo;
|
||||||
|
} else if (E->Use & REG_SREG_HI) {
|
||||||
|
Out->RegX = In->SRegHi;
|
||||||
|
} else {
|
||||||
|
Out->RegX = -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* X is now unknown */
|
/* X is now unknown */
|
||||||
Out->RegX = -1;
|
Out->RegX = -1;
|
||||||
@ -589,6 +629,14 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_LDY:
|
case OP65_LDY:
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegY = (unsigned char) E->Num;
|
Out->RegY = (unsigned char) E->Num;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Use & REG_SREG_LO) {
|
||||||
|
Out->RegY = In->SRegLo;
|
||||||
|
} else if (E->Use & REG_SREG_HI) {
|
||||||
|
Out->RegY = In->SRegHi;
|
||||||
|
} else {
|
||||||
|
Out->RegY = -1;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Y is now unknown */
|
/* Y is now unknown */
|
||||||
Out->RegY = -1;
|
Out->RegY = -1;
|
||||||
@ -598,6 +646,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_LSR:
|
case OP65_LSR:
|
||||||
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
if (E->AM == AM65_ACC && In->RegA >= 0) {
|
||||||
Out->RegA = (In->RegA >> 1) & 0xFF;
|
Out->RegA = (In->RegA >> 1) & 0xFF;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if ((E->Chg & REG_SREG_LO) != 0 && In->SRegLo >= 0) {
|
||||||
|
Out->SRegLo = (In->SRegLo >> 1) & 0xFF;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = (In->SRegHi >> 1) & 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -643,11 +697,27 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_ROL:
|
case OP65_ROL:
|
||||||
|
if (E->AM == AM65_ACC) {
|
||||||
Out->RegA = -1;
|
Out->RegA = -1;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = -1;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_ROR:
|
case OP65_ROR:
|
||||||
|
if (E->AM == AM65_ACC) {
|
||||||
Out->RegA = -1;
|
Out->RegA = -1;
|
||||||
|
} else if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = -1;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_RTI:
|
case OP65_RTI:
|
||||||
@ -671,12 +741,33 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_STA:
|
case OP65_STA:
|
||||||
|
if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = In->RegA;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = In->RegA;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_STX:
|
case OP65_STX:
|
||||||
|
if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = In->RegX;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = In->RegX;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_STY:
|
case OP65_STY:
|
||||||
|
if (E->AM == AM65_ZP) {
|
||||||
|
if (E->Chg & REG_SREG_LO) {
|
||||||
|
Out->SRegLo = In->RegY;
|
||||||
|
} else if (E->Chg & REG_SREG_HI) {
|
||||||
|
Out->SRegHi = In->RegY;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TAX:
|
case OP65_TAX:
|
||||||
@ -725,7 +816,8 @@ static char* RegInfoDesc (unsigned U, char* Buf)
|
|||||||
{
|
{
|
||||||
Buf[0] = '\0';
|
Buf[0] = '\0';
|
||||||
|
|
||||||
strcat (Buf, U & REG_SREG? "E" : "_");
|
strcat (Buf, U & REG_SREG_HI? "H" : "_");
|
||||||
|
strcat (Buf, U & REG_SREG_LO? "L" : "_");
|
||||||
strcat (Buf, U & REG_A? "A" : "_");
|
strcat (Buf, U & REG_A? "A" : "_");
|
||||||
strcat (Buf, U & REG_X? "X" : "_");
|
strcat (Buf, U & REG_X? "X" : "_");
|
||||||
strcat (Buf, U & REG_Y? "Y" : "_");
|
strcat (Buf, U & REG_Y? "Y" : "_");
|
||||||
@ -834,7 +926,7 @@ void CE_Output (const CodeEntry* E, FILE* F)
|
|||||||
char Use [128];
|
char Use [128];
|
||||||
char Chg [128];
|
char Chg [128];
|
||||||
fprintf (F,
|
fprintf (F,
|
||||||
"%*s; USE: %-19s CHG: %-19s SIZE: %u\n",
|
"%*s; USE: %-20s CHG: %-20s SIZE: %u\n",
|
||||||
30-Chars, "",
|
30-Chars, "",
|
||||||
RegInfoDesc (E->Use, Use),
|
RegInfoDesc (E->Use, Use),
|
||||||
RegInfoDesc (E->Chg, Chg),
|
RegInfoDesc (E->Chg, Chg),
|
||||||
|
@ -1011,12 +1011,8 @@ void g_putlocal (unsigned Flags, int Offs, long Val)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
|
if ((Flags & CF_NOKEEP) == 0 || CodeSizeFactor < 160) {
|
||||||
if (Offs) {
|
|
||||||
ldyconst (Offs);
|
ldyconst (Offs);
|
||||||
AddCodeLine ("jsr staxysp");
|
AddCodeLine ("jsr staxysp");
|
||||||
} else {
|
|
||||||
AddCodeLine ("jsr stax0sp");
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (CPU == CPU_65C02 && Offs == 0) {
|
if (CPU == CPU_65C02 && Offs == 0) {
|
||||||
AddCodeLine ("sta (sp)");
|
AddCodeLine ("sta (sp)");
|
||||||
|
@ -172,7 +172,8 @@ static const ZPInfo ZPInfoTable[] = {
|
|||||||
{ 7, "regbank", REG_BANK },
|
{ 7, "regbank", REG_BANK },
|
||||||
{ 7, "regsave", REG_SAVE },
|
{ 7, "regsave", REG_SAVE },
|
||||||
{ 2, "sp", REG_SP },
|
{ 2, "sp", REG_SP },
|
||||||
{ 4, "sreg", REG_SREG },
|
{ 0, "sreg", REG_SREG_LO },
|
||||||
|
{ 0, "sreg+1", REG_SREG_HI },
|
||||||
{ 4, "tmp1", REG_TMP1 },
|
{ 4, "tmp1", REG_TMP1 },
|
||||||
{ 4, "tmp2", REG_TMP2 },
|
{ 4, "tmp2", REG_TMP2 },
|
||||||
{ 4, "tmp3", REG_TMP3 },
|
{ 4, "tmp3", REG_TMP3 },
|
||||||
@ -277,6 +278,11 @@ static int CompareZPInfo (const void* Name, const void* Info)
|
|||||||
/* Do the compare. Be careful because of the length (Info may contain
|
/* Do the compare. Be careful because of the length (Info may contain
|
||||||
* more than just the zeropage name).
|
* more than just the zeropage name).
|
||||||
*/
|
*/
|
||||||
|
if (E->Len == 0) {
|
||||||
|
/* Do a full compare */
|
||||||
|
return strcmp (N, E->Name);
|
||||||
|
} else {
|
||||||
|
/* Only compare the first part */
|
||||||
int Res = strncmp (N, E->Name, E->Len);
|
int Res = strncmp (N, E->Name, E->Len);
|
||||||
if (Res == 0 && (N[E->Len] != '\0' && N[E->Len] != '+')) {
|
if (Res == 0 && (N[E->Len] != '\0' && N[E->Len] != '+')) {
|
||||||
/* Name is actually longer than Info->Name */
|
/* Name is actually longer than Info->Name */
|
||||||
@ -284,6 +290,7 @@ static int CompareZPInfo (const void* Name, const void* Info)
|
|||||||
}
|
}
|
||||||
return Res;
|
return Res;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -312,22 +319,13 @@ int IsZPName (const char* Name, unsigned short* RegInfo)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned GetRegInfo1 (CodeSeg* S,
|
|
||||||
CodeEntry* E,
|
|
||||||
int Index,
|
|
||||||
Collection* Visited,
|
|
||||||
unsigned Used,
|
|
||||||
unsigned Unused);
|
|
||||||
/* Recursively called subfunction for GetRegInfo. */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned GetRegInfo2 (CodeSeg* S,
|
static unsigned GetRegInfo2 (CodeSeg* S,
|
||||||
CodeEntry* E,
|
CodeEntry* E,
|
||||||
int Index,
|
int Index,
|
||||||
Collection* Visited,
|
Collection* Visited,
|
||||||
unsigned Used,
|
unsigned Used,
|
||||||
unsigned Unused)
|
unsigned Unused,
|
||||||
|
unsigned Wanted)
|
||||||
/* Recursively called subfunction for GetRegInfo. */
|
/* Recursively called subfunction for GetRegInfo. */
|
||||||
{
|
{
|
||||||
/* Follow the instruction flow recording register usage. */
|
/* Follow the instruction flow recording register usage. */
|
||||||
@ -373,7 +371,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* If we know about all registers now, bail out */
|
/* If we know about all registers now, bail out */
|
||||||
if ((Used | Unused) == REG_AXY) {
|
if (((Used | Unused) & Wanted) == Wanted) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -411,7 +409,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
|||||||
unsigned U1;
|
unsigned U1;
|
||||||
unsigned U2;
|
unsigned U2;
|
||||||
|
|
||||||
U1 = GetRegInfo1 (S, E->JumpTo->Owner, -1, Visited, Used, Unused);
|
U1 = GetRegInfo2 (S, E->JumpTo->Owner, -1, Visited, Used, Unused, Wanted);
|
||||||
if (U1 == REG_AXY) {
|
if (U1 == REG_AXY) {
|
||||||
/* All registers used, no need for second call */
|
/* All registers used, no need for second call */
|
||||||
return REG_AXY;
|
return REG_AXY;
|
||||||
@ -422,7 +420,7 @@ static unsigned GetRegInfo2 (CodeSeg* S,
|
|||||||
if ((E = CS_GetEntry (S, ++Index)) == 0) {
|
if ((E = CS_GetEntry (S, ++Index)) == 0) {
|
||||||
Internal ("GetRegInfo2: No next entry!");
|
Internal ("GetRegInfo2: No next entry!");
|
||||||
}
|
}
|
||||||
U2 = GetRegInfo1 (S, E, Index, Visited, Used, Unused);
|
U2 = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted);
|
||||||
return U1 | U2; /* Used in any of the branches */
|
return U1 | U2; /* Used in any of the branches */
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
@ -457,14 +455,15 @@ static unsigned GetRegInfo1 (CodeSeg* S,
|
|||||||
int Index,
|
int Index,
|
||||||
Collection* Visited,
|
Collection* Visited,
|
||||||
unsigned Used,
|
unsigned Used,
|
||||||
unsigned Unused)
|
unsigned Unused,
|
||||||
|
unsigned Wanted)
|
||||||
/* Recursively called subfunction for GetRegInfo. */
|
/* Recursively called subfunction for GetRegInfo. */
|
||||||
{
|
{
|
||||||
/* Remember the current count of the line collection */
|
/* Remember the current count of the line collection */
|
||||||
unsigned Count = CollCount (Visited);
|
unsigned Count = CollCount (Visited);
|
||||||
|
|
||||||
/* Call the worker routine */
|
/* Call the worker routine */
|
||||||
unsigned R = GetRegInfo2 (S, E, Index, Visited, Used, Unused);
|
unsigned R = GetRegInfo2 (S, E, Index, Visited, Used, Unused, Wanted);
|
||||||
|
|
||||||
/* Restore the old count, unmarking all new entries */
|
/* Restore the old count, unmarking all new entries */
|
||||||
unsigned NewCount = CollCount (Visited);
|
unsigned NewCount = CollCount (Visited);
|
||||||
@ -480,7 +479,7 @@ static unsigned GetRegInfo1 (CodeSeg* S,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index)
|
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted)
|
||||||
/* Determine register usage information for the instructions starting at the
|
/* Determine register usage information for the instructions starting at the
|
||||||
* given index.
|
* given index.
|
||||||
*/
|
*/
|
||||||
@ -500,7 +499,7 @@ unsigned GetRegInfo (struct CodeSeg* S, unsigned Index)
|
|||||||
InitCollection (&Visited);
|
InitCollection (&Visited);
|
||||||
|
|
||||||
/* Call the recursive subfunction */
|
/* Call the recursive subfunction */
|
||||||
R = GetRegInfo1 (S, E, Index, &Visited, REG_NONE, REG_NONE);
|
R = GetRegInfo1 (S, E, Index, &Visited, REG_NONE, REG_NONE, Wanted);
|
||||||
|
|
||||||
/* Delete the line collection */
|
/* Delete the line collection */
|
||||||
DoneCollection (&Visited);
|
DoneCollection (&Visited);
|
||||||
@ -514,7 +513,7 @@ unsigned GetRegInfo (struct CodeSeg* S, unsigned Index)
|
|||||||
int RegAUsed (struct CodeSeg* S, unsigned Index)
|
int RegAUsed (struct CodeSeg* S, unsigned Index)
|
||||||
/* Check if the value in A is used. */
|
/* Check if the value in A is used. */
|
||||||
{
|
{
|
||||||
return (GetRegInfo (S, Index) & REG_A) != 0;
|
return (GetRegInfo (S, Index, REG_A) & REG_A) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -522,7 +521,7 @@ int RegAUsed (struct CodeSeg* S, unsigned Index)
|
|||||||
int RegXUsed (struct CodeSeg* S, unsigned Index)
|
int RegXUsed (struct CodeSeg* S, unsigned Index)
|
||||||
/* Check if the value in X is used. */
|
/* Check if the value in X is used. */
|
||||||
{
|
{
|
||||||
return (GetRegInfo (S, Index) & REG_X) != 0;
|
return (GetRegInfo (S, Index, REG_X) & REG_X) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -530,7 +529,7 @@ int RegXUsed (struct CodeSeg* S, unsigned Index)
|
|||||||
int RegYUsed (struct CodeSeg* S, unsigned Index)
|
int RegYUsed (struct CodeSeg* S, unsigned Index)
|
||||||
/* Check if the value in Y is used. */
|
/* Check if the value in Y is used. */
|
||||||
{
|
{
|
||||||
return (GetRegInfo (S, Index) & REG_Y) != 0;
|
return (GetRegInfo (S, Index, REG_Y) & REG_Y) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,20 +59,22 @@ struct CodeSeg;
|
|||||||
#define REG_A 0x0001U
|
#define REG_A 0x0001U
|
||||||
#define REG_X 0x0002U
|
#define REG_X 0x0002U
|
||||||
#define REG_Y 0x0004U
|
#define REG_Y 0x0004U
|
||||||
#define REG_TMP1 0x0010U
|
#define REG_TMP1 0x0008U
|
||||||
#define REG_TMP2 0x0020U
|
#define REG_TMP2 0x0010U
|
||||||
#define REG_TMP3 0x0040U
|
#define REG_TMP3 0x0020U
|
||||||
#define REG_TMP4 0x0080U
|
#define REG_TMP4 0x0040U
|
||||||
#define REG_PTR1 0x0100U
|
#define REG_PTR1 0x0080U
|
||||||
#define REG_PTR2 0x0200U
|
#define REG_PTR2 0x0100U
|
||||||
#define REG_PTR3 0x0400U
|
#define REG_PTR3 0x0200U
|
||||||
#define REG_PTR4 0x0800U
|
#define REG_PTR4 0x0400U
|
||||||
#define REG_SREG 0x1000U
|
#define REG_SREG_LO 0x0800U
|
||||||
|
#define REG_SREG_HI 0x1000U
|
||||||
#define REG_SP 0x2000U
|
#define REG_SP 0x2000U
|
||||||
#define REG_SAVE 0x4000U
|
#define REG_SAVE 0x4000U
|
||||||
#define REG_BANK 0x8000U
|
#define REG_BANK 0x8000U
|
||||||
|
|
||||||
/* Combined register defines */
|
/* Combined register defines */
|
||||||
|
#define REG_SREG (REG_SREG_LO | REG_SREG_HI)
|
||||||
#define REG_AX (REG_A | REG_X)
|
#define REG_AX (REG_A | REG_X)
|
||||||
#define REG_AY (REG_A | REG_Y)
|
#define REG_AY (REG_A | REG_Y)
|
||||||
#define REG_XY (REG_X | REG_Y)
|
#define REG_XY (REG_X | REG_Y)
|
||||||
@ -102,7 +104,7 @@ int IsZPName (const char* Name, unsigned short* RegInfo);
|
|||||||
* zero page location found.
|
* zero page location found.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index);
|
unsigned GetRegInfo (struct CodeSeg* S, unsigned Index, unsigned Wanted);
|
||||||
/* Determine register usage information for the instructions starting at the
|
/* Determine register usage information for the instructions starting at the
|
||||||
* given index.
|
* given index.
|
||||||
*/
|
*/
|
||||||
|
@ -697,7 +697,7 @@ static unsigned OptAdd2 (CodeSeg* S)
|
|||||||
L[6]->OPC == OP65_JSR &&
|
L[6]->OPC == OP65_JSR &&
|
||||||
strcmp (L[6]->Arg, "addeqysp") == 0 &&
|
strcmp (L[6]->Arg, "addeqysp") == 0 &&
|
||||||
!CE_HasLabel (L[6]) &&
|
!CE_HasLabel (L[6]) &&
|
||||||
(GetRegInfo (S, I+7) & REG_AX) == 0) {
|
(GetRegInfo (S, I+7, REG_AX) & REG_AX) == 0) {
|
||||||
|
|
||||||
char Buf [20];
|
char Buf [20];
|
||||||
CodeEntry* X;
|
CodeEntry* X;
|
||||||
@ -2580,6 +2580,7 @@ static OptFunc OptFuncs [] = {
|
|||||||
OptEntry (OptTest1, optMain),
|
OptEntry (OptTest1, optMain),
|
||||||
/* Remove unused loads */
|
/* Remove unused loads */
|
||||||
OptEntry (OptUnusedLoads, optMain),
|
OptEntry (OptUnusedLoads, optMain),
|
||||||
|
OptEntry (OptUnusedStores, optMain),
|
||||||
OptEntry (OptDuplicateLoads, optMain),
|
OptEntry (OptDuplicateLoads, optMain),
|
||||||
OptEntry (OptStoreLoad, optMain),
|
OptEntry (OptStoreLoad, optMain),
|
||||||
OptEntry (OptTransfers, optMain),
|
OptEntry (OptTransfers, optMain),
|
||||||
|
@ -414,8 +414,7 @@ CodeSeg* NewCodeSeg (const char* SegName, SymEntry* Func)
|
|||||||
/* If we have a function given, get the return type of the function.
|
/* If we have a function given, get the return type of the function.
|
||||||
* Assume ANY return type besides void will use the A and X registers.
|
* Assume ANY return type besides void will use the A and X registers.
|
||||||
*/
|
*/
|
||||||
RetType = GetFuncReturn (Func->Type);
|
if (S->Func && !IsTypeVoid ((RetType = GetFuncReturn (Func->Type)))) {
|
||||||
if (S->Func && !IsTypeVoid (RetType)) {
|
|
||||||
if (SizeOf (RetType) == SizeOf (type_long)) {
|
if (SizeOf (RetType) == SizeOf (type_long)) {
|
||||||
S->ExitRegs = REG_EAX;
|
S->ExitRegs = REG_EAX;
|
||||||
} else {
|
} else {
|
||||||
@ -1059,7 +1058,7 @@ void CS_GenRegInfo (CodeSeg* S)
|
|||||||
RC_Invalidate (&Regs);
|
RC_Invalidate (&Regs);
|
||||||
CurrentRegs = &Regs;
|
CurrentRegs = &Regs;
|
||||||
|
|
||||||
/* First pass. Walk over all insns an note just the changes from one
|
/* First pass. Walk over all insns and note just the changes from one
|
||||||
* insn to the next one.
|
* insn to the next one.
|
||||||
*/
|
*/
|
||||||
WasJump = 0;
|
WasJump = 0;
|
||||||
@ -1115,6 +1114,12 @@ void CS_GenRegInfo (CodeSeg* S)
|
|||||||
if (J->RI->Out2.RegY != Regs.RegY) {
|
if (J->RI->Out2.RegY != Regs.RegY) {
|
||||||
Regs.RegY = -1;
|
Regs.RegY = -1;
|
||||||
}
|
}
|
||||||
|
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
|
||||||
|
Regs.SRegLo = -1;
|
||||||
|
}
|
||||||
|
if (J->RI->Out2.SRegHi != Regs.SRegHi) {
|
||||||
|
Regs.SRegHi = -1;
|
||||||
|
}
|
||||||
++Entry;
|
++Entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -579,7 +579,7 @@ unsigned OptCondBranches (CodeSeg* S)
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Remove unused loads */
|
/* Remove unused loads and stores */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
@ -623,7 +623,7 @@ unsigned OptUnusedLoads (CodeSeg* S)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Get register usage and check if the register value is used later */
|
/* Get register usage and check if the register value is used later */
|
||||||
if ((GetRegInfo (S, I+1) & R) == 0) {
|
if ((GetRegInfo (S, I+1, R) & R) == 0) {
|
||||||
|
|
||||||
/* Register value is not used, remove the load */
|
/* Register value is not used, remove the load */
|
||||||
CS_DelEntry (S, I);
|
CS_DelEntry (S, I);
|
||||||
@ -646,6 +646,51 @@ NextEntry:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned OptUnusedStores (CodeSeg* S)
|
||||||
|
/* Remove stores into zero page registers that aren't used later */
|
||||||
|
{
|
||||||
|
unsigned Changes = 0;
|
||||||
|
|
||||||
|
/* Walk over the entries */
|
||||||
|
unsigned I = 0;
|
||||||
|
while (I < CS_GetEntryCount (S)) {
|
||||||
|
|
||||||
|
/* Get next entry */
|
||||||
|
CodeEntry* E = CS_GetEntry (S, I);
|
||||||
|
|
||||||
|
/* Check if it's a register load or transfer insn */
|
||||||
|
if ((E->Info & OF_STORE) != 0 &&
|
||||||
|
E->AM == AM65_ZP &&
|
||||||
|
(E->Chg & REG_ZP) != 0) {
|
||||||
|
|
||||||
|
/* Check for the zero page location. We know that there cannot be
|
||||||
|
* more than one zero page location involved in the store.
|
||||||
|
*/
|
||||||
|
unsigned R = E->Chg & REG_ZP;
|
||||||
|
|
||||||
|
/* Get register usage and check if the register value is used later */
|
||||||
|
if ((GetRegInfo (S, I+1, R) & R) == 0) {
|
||||||
|
|
||||||
|
/* Register value is not used, remove the load */
|
||||||
|
CS_DelEntry (S, I);
|
||||||
|
|
||||||
|
/* Remember, we had changes */
|
||||||
|
++Changes;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next entry */
|
||||||
|
++I;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of changes made */
|
||||||
|
return Changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned OptDuplicateLoads (CodeSeg* S)
|
unsigned OptDuplicateLoads (CodeSeg* S)
|
||||||
/* Remove loads of registers where the value loaded is already in the register. */
|
/* Remove loads of registers where the value loaded is already in the register. */
|
||||||
{
|
{
|
||||||
@ -667,13 +712,16 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
/* Assume we won't delete the entry */
|
/* Assume we won't delete the entry */
|
||||||
int Delete = 0;
|
int Delete = 0;
|
||||||
|
|
||||||
|
/* Get a pointer to the input registers of the insn */
|
||||||
|
const RegContents* In = &E->RI->In;
|
||||||
|
|
||||||
/* Handle the different instructions */
|
/* Handle the different instructions */
|
||||||
switch (E->OPC) {
|
switch (E->OPC) {
|
||||||
|
|
||||||
case OP65_LDA:
|
case OP65_LDA:
|
||||||
if (E->RI->In.RegA >= 0 && /* Value of A is known */
|
if (In->RegA >= 0 && /* Value of A is known */
|
||||||
CE_KnownImm (E) && /* Value to be loaded is known */
|
CE_KnownImm (E) && /* Value to be loaded is known */
|
||||||
E->RI->In.RegA == (long) E->Num && /* Both are equal */
|
In->RegA == (long) E->Num && /* Both are equal */
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
||||||
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
||||||
Delete = 1;
|
Delete = 1;
|
||||||
@ -681,9 +729,9 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_LDX:
|
case OP65_LDX:
|
||||||
if (E->RI->In.RegX >= 0 && /* Value of X is known */
|
if (In->RegX >= 0 && /* Value of X is known */
|
||||||
CE_KnownImm (E) && /* Value to be loaded is known */
|
CE_KnownImm (E) && /* Value to be loaded is known */
|
||||||
E->RI->In.RegX == (long) E->Num && /* Both are equal */
|
In->RegX == (long) E->Num && /* Both are equal */
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
||||||
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
||||||
Delete = 1;
|
Delete = 1;
|
||||||
@ -691,24 +739,51 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_LDY:
|
case OP65_LDY:
|
||||||
if (E->RI->In.RegY >= 0 && /* Value of Y is known */
|
if (In->RegY >= 0 && /* Value of Y is known */
|
||||||
CE_KnownImm (E) && /* Value to be loaded is known */
|
CE_KnownImm (E) && /* Value to be loaded is known */
|
||||||
E->RI->In.RegY == (long) E->Num && /* Both are equal */
|
In->RegY == (long) E->Num && /* Both are equal */
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
|
||||||
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
|
||||||
Delete = 1;
|
Delete = 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case OP65_STA:
|
||||||
|
/* If we store into a known zero page location, and this
|
||||||
|
* location does already contain the value to be stored,
|
||||||
|
* remove the store.
|
||||||
|
*/
|
||||||
|
if (In->RegA >= 0 && /* Value of A is known */
|
||||||
|
E->AM == AM65_ZP && /* Store into zp */
|
||||||
|
(((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */
|
||||||
|
In->RegA == In->SRegLo) || /* Value identical */
|
||||||
|
((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */
|
||||||
|
In->RegA == In->SRegHi))) { /* Value identical */
|
||||||
|
Delete = 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case OP65_STX:
|
case OP65_STX:
|
||||||
|
/* If we store into a known zero page location, and this
|
||||||
|
* location does already contain the value to be stored,
|
||||||
|
* remove the store.
|
||||||
|
*/
|
||||||
|
if (In->RegX >= 0 && /* Value of A is known */
|
||||||
|
E->AM == AM65_ZP && /* Store into zp */
|
||||||
|
(((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */
|
||||||
|
In->RegX == In->SRegLo) || /* Value identical */
|
||||||
|
((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */
|
||||||
|
In->RegX == In->SRegHi))) { /* Value identical */
|
||||||
|
Delete = 1;
|
||||||
|
|
||||||
/* If the value in the X register is known and the same as
|
/* If the value in the X register is known and the same as
|
||||||
* that in the A register, replace the store by a STA. The
|
* that in the A register, replace the store by a STA. The
|
||||||
* optimizer will then remove the load instruction for X
|
* optimizer will then remove the load instruction for X
|
||||||
* later. STX does support the zeropage,y addressing mode,
|
* later. STX does support the zeropage,y addressing mode,
|
||||||
* so be sure to check for that.
|
* so be sure to check for that.
|
||||||
*/
|
*/
|
||||||
if (E->RI->In.RegX >= 0 &&
|
} else if (In->RegX >= 0 &&
|
||||||
E->RI->In.RegX == E->RI->In.RegA &&
|
In->RegX == In->RegA &&
|
||||||
E->AM != AM65_ABSY &&
|
E->AM != AM65_ABSY &&
|
||||||
E->AM != AM65_ZPY) {
|
E->AM != AM65_ZPY) {
|
||||||
/* Use the A register instead */
|
/* Use the A register instead */
|
||||||
@ -717,6 +792,17 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_STY:
|
case OP65_STY:
|
||||||
|
/* If we store into a known zero page location, and this
|
||||||
|
* location does already contain the value to be stored,
|
||||||
|
* remove the store.
|
||||||
|
*/
|
||||||
|
if (In->RegX >= 0 && /* Value of A is known */
|
||||||
|
E->AM == AM65_ZP && /* Store into zp */
|
||||||
|
(((E->Chg & REG_SREG_LO) != 0 && /* Store into sreg */
|
||||||
|
In->RegX == In->SRegLo) || /* Value identical */
|
||||||
|
((E->Chg & REG_SREG_HI) != 0 && /* Store into sreg+1 */
|
||||||
|
In->RegX == In->SRegHi))) { /* Value identical */
|
||||||
|
Delete = 1;
|
||||||
/* If the value in the Y register is known and the same as
|
/* If the value in the Y register is known and the same as
|
||||||
* that in the A register, replace the store by a STA. The
|
* that in the A register, replace the store by a STA. The
|
||||||
* optimizer will then remove the load instruction for Y
|
* optimizer will then remove the load instruction for Y
|
||||||
@ -724,10 +810,10 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
* replacement by X, but check for invalid addressing modes
|
* replacement by X, but check for invalid addressing modes
|
||||||
* in this case.
|
* in this case.
|
||||||
*/
|
*/
|
||||||
if (E->RI->In.RegY >= 0) {
|
} else if (In->RegY >= 0) {
|
||||||
if (E->RI->In.RegY == E->RI->In.RegA) {
|
if (In->RegY == In->RegA) {
|
||||||
CE_ReplaceOPC (E, OP65_STA);
|
CE_ReplaceOPC (E, OP65_STA);
|
||||||
} else if (E->RI->In.RegY == E->RI->In.RegX &&
|
} else if (In->RegY == In->RegX &&
|
||||||
E->AM != AM65_ABSX &&
|
E->AM != AM65_ABSX &&
|
||||||
E->AM != AM65_ZPX) {
|
E->AM != AM65_ZPX) {
|
||||||
CE_ReplaceOPC (E, OP65_STX);
|
CE_ReplaceOPC (E, OP65_STX);
|
||||||
@ -736,8 +822,8 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TAX:
|
case OP65_TAX:
|
||||||
if (E->RI->In.RegA >= 0 &&
|
if (In->RegA >= 0 &&
|
||||||
E->RI->In.RegA == E->RI->In.RegX &&
|
In->RegA == In->RegX &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
(N->Info & OF_FBRA) == 0) {
|
(N->Info & OF_FBRA) == 0) {
|
||||||
/* Value is identical and not followed by a branch */
|
/* Value is identical and not followed by a branch */
|
||||||
@ -746,8 +832,8 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TAY:
|
case OP65_TAY:
|
||||||
if (E->RI->In.RegA >= 0 &&
|
if (In->RegA >= 0 &&
|
||||||
E->RI->In.RegA == E->RI->In.RegY &&
|
In->RegA == In->RegY &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
(N->Info & OF_FBRA) == 0) {
|
(N->Info & OF_FBRA) == 0) {
|
||||||
/* Value is identical and not followed by a branch */
|
/* Value is identical and not followed by a branch */
|
||||||
@ -756,8 +842,8 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TXA:
|
case OP65_TXA:
|
||||||
if (E->RI->In.RegX >= 0 &&
|
if (In->RegX >= 0 &&
|
||||||
E->RI->In.RegX == E->RI->In.RegA &&
|
In->RegX == In->RegA &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
(N->Info & OF_FBRA) == 0) {
|
(N->Info & OF_FBRA) == 0) {
|
||||||
/* Value is identical and not followed by a branch */
|
/* Value is identical and not followed by a branch */
|
||||||
@ -766,8 +852,8 @@ unsigned OptDuplicateLoads (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TYA:
|
case OP65_TYA:
|
||||||
if (E->RI->In.RegY >= 0 &&
|
if (In->RegY >= 0 &&
|
||||||
E->RI->In.RegY == E->RI->In.RegA &&
|
In->RegY == In->RegA &&
|
||||||
(N = CS_GetNextEntry (S, I)) != 0 &&
|
(N = CS_GetNextEntry (S, I)) != 0 &&
|
||||||
(N->Info & OF_FBRA) == 0) {
|
(N->Info & OF_FBRA) == 0) {
|
||||||
/* Value is identical and not followed by a branch */
|
/* Value is identical and not followed by a branch */
|
||||||
|
@ -89,6 +89,9 @@ unsigned OptCondBranches (CodeSeg* S);
|
|||||||
unsigned OptUnusedLoads (CodeSeg* S);
|
unsigned OptUnusedLoads (CodeSeg* S);
|
||||||
/* Remove loads of registers where the value loaded is not used later. */
|
/* Remove loads of registers where the value loaded is not used later. */
|
||||||
|
|
||||||
|
unsigned OptUnusedStores (CodeSeg* S);
|
||||||
|
/* Remove stores into zero page registers that aren't used later */
|
||||||
|
|
||||||
unsigned OptDuplicateLoads (CodeSeg* S);
|
unsigned OptDuplicateLoads (CodeSeg* S);
|
||||||
/* Remove loads of registers where the value loaded is already in the register. */
|
/* Remove loads of registers where the value loaded is already in the register. */
|
||||||
|
|
||||||
|
@ -682,22 +682,22 @@ int IsQualVolatile (const type* T)
|
|||||||
|
|
||||||
|
|
||||||
int IsFastCallFunc (const type* T)
|
int IsFastCallFunc (const type* T)
|
||||||
/* Return true if this is a function type with __fastcall__ calling conventions */
|
/* Return true if this is a function type or pointer to function with
|
||||||
|
* __fastcall__ calling conventions
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
FuncDesc* F;
|
FuncDesc* F = GetFuncDesc (T);
|
||||||
CHECK (IsTypeFunc (T));
|
|
||||||
F = (FuncDesc*) DecodePtr (T+1);
|
|
||||||
return (F->Flags & FD_FASTCALL) != 0;
|
return (F->Flags & FD_FASTCALL) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int IsVariadicFunc (const type* T)
|
int IsVariadicFunc (const type* T)
|
||||||
/* Return true if this is a function type with variable parameter list */
|
/* Return true if this is a function type or pointer to function type with
|
||||||
|
* variable parameter list
|
||||||
|
*/
|
||||||
{
|
{
|
||||||
FuncDesc* F;
|
FuncDesc* F = GetFuncDesc (T);
|
||||||
CHECK (IsTypeFunc (T));
|
|
||||||
F = (FuncDesc*) DecodePtr (T+1);
|
|
||||||
return (F->Flags & FD_VARIADIC) != 0;
|
return (F->Flags & FD_VARIADIC) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,10 +287,14 @@ int IsQualVolatile (const type* T) attribute ((const));
|
|||||||
/* Return true if the given type has a volatile type qualifier */
|
/* Return true if the given type has a volatile type qualifier */
|
||||||
|
|
||||||
int IsFastCallFunc (const type* T) attribute ((const));
|
int IsFastCallFunc (const type* T) attribute ((const));
|
||||||
/* Return true if this is a function type with __fastcall__ calling conventions */
|
/* Return true if this is a function type or pointer to function with
|
||||||
|
* __fastcall__ calling conventions
|
||||||
|
*/
|
||||||
|
|
||||||
int IsVariadicFunc (const type* T) attribute ((const));
|
int IsVariadicFunc (const type* T) attribute ((const));
|
||||||
/* Return true if this is a function type with variable parameter list */
|
/* Return true if this is a function type or pointer to function type with
|
||||||
|
* variable parameter list
|
||||||
|
*/
|
||||||
|
|
||||||
int IsTypeFuncPtr (const type* T) attribute ((const));
|
int IsTypeFuncPtr (const type* T) attribute ((const));
|
||||||
/* Return true if this is a function pointer */
|
/* Return true if this is a function pointer */
|
||||||
|
@ -807,12 +807,12 @@ static void Decl (Declaration* D, unsigned Mode)
|
|||||||
/* Parse the function */
|
/* Parse the function */
|
||||||
Decl (D, Mode);
|
Decl (D, Mode);
|
||||||
/* Set the fastcall flag */
|
/* Set the fastcall flag */
|
||||||
if (!IsTypeFunc (T)) {
|
if (!IsTypeFunc (T) && !IsTypeFuncPtr (T)) {
|
||||||
Error ("__fastcall__ modifier applied to non function");
|
Error ("__fastcall__ modifier applied to non function");
|
||||||
} else if (IsVariadicFunc (T)) {
|
} else if (IsVariadicFunc (T)) {
|
||||||
Error ("Cannot apply __fastcall__ to functions with variable parameter list");
|
Error ("Cannot apply __fastcall__ to functions with variable parameter list");
|
||||||
} else {
|
} else {
|
||||||
FuncDesc* F = (FuncDesc*) DecodePtr (T+1);
|
FuncDesc* F = GetFuncDesc (T);
|
||||||
F->Flags |= FD_FASTCALL;
|
F->Flags |= FD_FASTCALL;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
134
src/cc65/expr.c
134
src/cc65/expr.c
@ -707,53 +707,122 @@ static unsigned FunctionParamList (FuncDesc* Func)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void FunctionCall (ExprDesc* lval)
|
static void FunctionCall (int k, ExprDesc* lval)
|
||||||
/* Perform a function call. Called from hie11, this routine will
|
/* Perform a function call. */
|
||||||
* either call the named function, or the function pointer in a/x.
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
FuncDesc* Func; /* Function descriptor */
|
FuncDesc* Func; /* Function descriptor */
|
||||||
|
int IsFuncPtr; /* Flag */
|
||||||
unsigned ParamSize; /* Number of parameter bytes */
|
unsigned ParamSize; /* Number of parameter bytes */
|
||||||
CodeMark Mark;
|
CodeMark Mark = 0; /* Initialize to keep gcc silent */
|
||||||
|
int PtrOffs = 0; /* Offset of function pointer on stack */
|
||||||
|
int IsFastCall = 0; /* True if it's a fast call function */
|
||||||
|
int PtrOnStack = 0; /* True if a pointer copy is on stack */
|
||||||
|
|
||||||
/* Get a pointer to the function descriptor from the type string */
|
/* Get a pointer to the function descriptor from the type string */
|
||||||
Func = GetFuncDesc (lval->Type);
|
Func = GetFuncDesc (lval->Type);
|
||||||
|
|
||||||
/* Initialize vars to keep gcc silent */
|
/* Handle function pointers transparently */
|
||||||
Mark = 0;
|
IsFuncPtr = IsTypeFuncPtr (lval->Type);
|
||||||
|
if (IsFuncPtr) {
|
||||||
|
|
||||||
/* Check if this is a function pointer. If so, save it. If not, check for
|
/* Check wether it's a fastcall function */
|
||||||
* special known library functions that may be inlined.
|
IsFastCall = IsFastCallFunc (lval->Type + 1);
|
||||||
|
|
||||||
|
/* Things may be difficult, depending on where the function pointer
|
||||||
|
* resides. If the function pointer is an expression of some sort
|
||||||
|
* (not a local or global variable), we have to evaluate this
|
||||||
|
* expression now and save the result for later. Since calls to
|
||||||
|
* function pointers may be nested, we must save it onto the stack.
|
||||||
|
* For fastcall functions we do also need to place a copy of the
|
||||||
|
* pointer on stack, since we cannot use a/x.
|
||||||
*/
|
*/
|
||||||
if (lval->Flags & E_MEXPR) {
|
PtrOnStack = IsFastCall || ((lval->Flags & (E_MGLOBAL | E_MLOCAL)) == 0);
|
||||||
/* Function pointer is in primary register, save it */
|
if (PtrOnStack) {
|
||||||
|
|
||||||
|
/* Not a global or local variable, or a fastcall function. Load
|
||||||
|
* the pointer into the primary and mark it as an expression.
|
||||||
|
*/
|
||||||
|
exprhs (CF_NONE, k, lval);
|
||||||
|
lval->Flags |= E_MEXPR;
|
||||||
|
|
||||||
|
/* Remember the code position */
|
||||||
Mark = GetCodePos ();
|
Mark = GetCodePos ();
|
||||||
g_save (CF_PTR);
|
|
||||||
|
/* Push the pointer onto the stack and remember the offset */
|
||||||
|
g_push (CF_PTR, 0);
|
||||||
|
PtrOffs = oursp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for known standard functions and inline them if requested */
|
||||||
} else if (InlineStdFuncs && IsStdFunc ((const char*) lval->Name)) {
|
} else if (InlineStdFuncs && IsStdFunc ((const char*) lval->Name)) {
|
||||||
|
|
||||||
/* Inline this function */
|
/* Inline this function */
|
||||||
HandleStdFunc (lval);
|
HandleStdFunc (lval);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the parameter list */
|
/* Parse the parameter list */
|
||||||
ParamSize = FunctionParamList (Func);
|
ParamSize = FunctionParamList (Func);
|
||||||
|
|
||||||
/* We need the closing bracket here */
|
/* We need the closing paren here */
|
||||||
ConsumeRParen ();
|
ConsumeRParen ();
|
||||||
|
|
||||||
/* */
|
/* Special handling for function pointers */
|
||||||
if (lval->Flags & E_MEXPR) {
|
if (IsFuncPtr) {
|
||||||
/* Function called via pointer: Restore it and call function */
|
|
||||||
if (ParamSize != 0) {
|
/* If the function is not a fastcall function, load the pointer to
|
||||||
g_restore (CF_PTR);
|
* the function into the primary.
|
||||||
} else {
|
*/
|
||||||
/* We had no parameters - remove save code */
|
if (!IsFastCallFunc (lval->Type)) {
|
||||||
|
|
||||||
|
/* Not a fastcall function - we may use the primary */
|
||||||
|
if (PtrOnStack) {
|
||||||
|
/* If we have no parameters, the pointer is still in the
|
||||||
|
* primary. Remove the code to push it and correct the
|
||||||
|
* stack pointer.
|
||||||
|
*/
|
||||||
|
if (ParamSize == 0) {
|
||||||
RemoveCode (Mark);
|
RemoveCode (Mark);
|
||||||
}
|
pop (CF_PTR);
|
||||||
g_callind (TypeOf (lval->Type), ParamSize);
|
PtrOnStack = 0;
|
||||||
} else {
|
} else {
|
||||||
|
/* Load from the saved copy */
|
||||||
|
g_getlocal (CF_PTR, PtrOffs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* Load from original location */
|
||||||
|
exprhs (CF_NONE, k, lval);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Call the function */
|
||||||
|
g_callind (TypeOf (lval->Type), ParamSize);
|
||||||
|
|
||||||
|
/* If we have a pointer on stack, remove it */
|
||||||
|
if (PtrOnStack) {
|
||||||
|
g_space (- (int) sizeofarg (CF_PTR));
|
||||||
|
pop (CF_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Fastcall function. We cannot use the primary for the function
|
||||||
|
* pointer and must therefore use an offset to the stack location.
|
||||||
|
* Since fastcall functions may never be variadic, we can use the
|
||||||
|
* index register for this purpose.
|
||||||
|
*/
|
||||||
|
Error ("Not implemented");
|
||||||
|
pop (CF_PTR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip T_PTR */
|
||||||
|
++lval->Type;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* Normal function */
|
||||||
g_call (TypeOf (lval->Type), (const char*) lval->Name, ParamSize);
|
g_call (TypeOf (lval->Type), (const char*) lval->Name, ParamSize);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1253,16 +1322,17 @@ static int hie11 (ExprDesc *lval)
|
|||||||
/* Function call. Skip the opening parenthesis */
|
/* Function call. Skip the opening parenthesis */
|
||||||
NextToken ();
|
NextToken ();
|
||||||
tptr = lval->Type;
|
tptr = lval->Type;
|
||||||
if (IsTypeFunc (tptr) || IsTypeFuncPtr (tptr)) {
|
if (IsTypeFunc (lval->Type) || IsTypeFuncPtr (lval->Type)) {
|
||||||
if (IsTypeFuncPtr (tptr)) {
|
|
||||||
/* Pointer to function. Handle transparently */
|
/* Call the function */
|
||||||
exprhs (CF_NONE, k, lval); /* Function pointer to A/X */
|
FunctionCall (k, lval);
|
||||||
++lval->Type; /* Skip T_PTR */
|
|
||||||
lval->Flags |= E_MEXPR;
|
/* Result is in the primary register */
|
||||||
}
|
|
||||||
FunctionCall (lval);
|
|
||||||
lval->Flags = E_MEXPR;
|
lval->Flags = E_MEXPR;
|
||||||
lval->Type += DECODE_SIZE + 1; /* Set to result */
|
|
||||||
|
/* Set to result */
|
||||||
|
lval->Type = GetFuncReturn (lval->Type);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Error ("Illegal function call");
|
Error ("Illegal function call");
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user