Re-added register variables.
Changed/added several optimizer steps to detect register variables correctly or to handle them in a special way. git-svn-id: svn://svn.cc65.org/cc65/trunk@1636 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -461,11 +461,11 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
/* We don't know the value of the carry, so the result is
|
/* We don't know the value of the carry, so the result is
|
||||||
* always unknown.
|
* always unknown.
|
||||||
*/
|
*/
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_AND:
|
case OP65_AND:
|
||||||
if (In->RegA >= 0) {
|
if (RegValIsKnown (In->RegA)) {
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegA = In->RegA & (short) E->Num;
|
Out->RegA = In->RegA & (short) E->Num;
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
@@ -480,11 +480,11 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegA = In->RegA & In->SRegHi;
|
Out->RegA = In->RegA & In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -565,7 +565,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEA:
|
case OP65_DEA:
|
||||||
if (In->RegA >= 0) {
|
if (RegValIsKnown (In->RegA)) {
|
||||||
Out->RegA = (In->RegA - 1) & 0xFF;
|
Out->RegA = (In->RegA - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -592,19 +592,19 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEX:
|
case OP65_DEX:
|
||||||
if (In->RegX >= 0) {
|
if (RegValIsKnown (In->RegX)) {
|
||||||
Out->RegX = (In->RegX - 1) & 0xFF;
|
Out->RegX = (In->RegX - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_DEY:
|
case OP65_DEY:
|
||||||
if (In->RegY >= 0) {
|
if (RegValIsKnown (In->RegY)) {
|
||||||
Out->RegY = (In->RegY - 1) & 0xFF;
|
Out->RegY = (In->RegY - 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_EOR:
|
case OP65_EOR:
|
||||||
if (In->RegA >= 0) {
|
if (RegValIsKnown (In->RegA)) {
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegA = In->RegA ^ (short) E->Num;
|
Out->RegA = In->RegA ^ (short) E->Num;
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
@@ -619,17 +619,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegA = In->RegA ^ In->SRegHi;
|
Out->RegA = In->RegA ^ In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INA:
|
case OP65_INA:
|
||||||
if (In->RegA >= 0) {
|
if (RegValIsKnown (In->RegA)) {
|
||||||
Out->RegA = (In->RegA + 1) & 0xFF;
|
Out->RegA = (In->RegA + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -656,13 +656,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INX:
|
case OP65_INX:
|
||||||
if (In->RegX >= 0) {
|
if (RegValIsKnown (In->RegX)) {
|
||||||
Out->RegX = (In->RegX + 1) & 0xFF;
|
Out->RegX = (In->RegX + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_INY:
|
case OP65_INY:
|
||||||
if (In->RegY >= 0) {
|
if (RegValIsKnown (In->RegY)) {
|
||||||
Out->RegY = (In->RegY + 1) & 0xFF;
|
Out->RegY = (In->RegY + 1) & 0xFF;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -692,22 +692,22 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
/* Get the code info for the function */
|
/* Get the code info for the function */
|
||||||
GetFuncInfo (E->Arg, &Use, &Chg);
|
GetFuncInfo (E->Arg, &Use, &Chg);
|
||||||
if (Chg & REG_A) {
|
if (Chg & REG_A) {
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (Chg & REG_X) {
|
if (Chg & REG_X) {
|
||||||
Out->RegX = -1;
|
Out->RegX = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (Chg & REG_Y) {
|
if (Chg & REG_Y) {
|
||||||
Out->RegY = -1;
|
Out->RegY = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (Chg & REG_TMP1) {
|
if (Chg & REG_TMP1) {
|
||||||
Out->Tmp1 = -1;
|
Out->Tmp1 = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (Chg & REG_SREG_LO) {
|
if (Chg & REG_SREG_LO) {
|
||||||
Out->SRegLo = -1;
|
Out->SRegLo = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (Chg & REG_SREG_HI) {
|
if (Chg & REG_SREG_HI) {
|
||||||
Out->SRegHi = -1;
|
Out->SRegHi = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
/* ## FIXME: Quick hack for some known functions: */
|
/* ## FIXME: Quick hack for some known functions: */
|
||||||
if (strcmp (E->Arg, "tosandax") == 0) {
|
if (strcmp (E->Arg, "tosandax") == 0) {
|
||||||
@@ -750,12 +750,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegA = In->SRegHi;
|
Out->RegA = In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A is now unknown */
|
/* A is now unknown */
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -774,12 +774,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegX = In->SRegHi;
|
Out->RegX = In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegX = -1;
|
Out->RegX = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* X is now unknown */
|
/* X is now unknown */
|
||||||
Out->RegX = -1;
|
Out->RegX = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -798,12 +798,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegY = In->SRegHi;
|
Out->RegY = In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegY = -1;
|
Out->RegY = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Y is now unknown */
|
/* Y is now unknown */
|
||||||
Out->RegY = -1;
|
Out->RegY = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -832,7 +832,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_ORA:
|
case OP65_ORA:
|
||||||
if (In->RegA >= 0) {
|
if (RegValIsKnown (In->RegA)) {
|
||||||
if (CE_KnownImm (E)) {
|
if (CE_KnownImm (E)) {
|
||||||
Out->RegA = In->RegA | (short) E->Num;
|
Out->RegA = In->RegA | (short) E->Num;
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
@@ -847,12 +847,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
Out->RegA = In->RegA | In->SRegHi;
|
Out->RegA = In->RegA | In->SRegHi;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A is now unknown */
|
/* A is now unknown */
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -887,17 +887,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_ROL:
|
case OP65_ROL:
|
||||||
/* We don't know the value of the carry bit */
|
/* We don't know the value of the carry bit */
|
||||||
if (E->AM == AM65_ACC) {
|
if (E->AM == AM65_ACC) {
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
switch (GetKnownReg (E->Chg, In)) {
|
switch (GetKnownReg (E->Chg, In)) {
|
||||||
case REG_TMP1:
|
case REG_TMP1:
|
||||||
Out->Tmp1 = -1;
|
Out->Tmp1 = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_LO:
|
case REG_SREG_LO:
|
||||||
Out->SRegLo = -1;
|
Out->SRegLo = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_HI:
|
case REG_SREG_HI:
|
||||||
Out->SRegHi = -1;
|
Out->SRegHi = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (E->AM == AM65_ZPX) {
|
} else if (E->AM == AM65_ZPX) {
|
||||||
@@ -909,17 +909,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
case OP65_ROR:
|
case OP65_ROR:
|
||||||
/* We don't know the value of the carry bit */
|
/* We don't know the value of the carry bit */
|
||||||
if (E->AM == AM65_ACC) {
|
if (E->AM == AM65_ACC) {
|
||||||
Out->RegA = -1;
|
Out->RegA = UNKNOWN_REGVAL;
|
||||||
} else if (E->AM == AM65_ZP) {
|
} else if (E->AM == AM65_ZP) {
|
||||||
switch (GetKnownReg (E->Chg, In)) {
|
switch (GetKnownReg (E->Chg, In)) {
|
||||||
case REG_TMP1:
|
case REG_TMP1:
|
||||||
Out->Tmp1 = -1;
|
Out->Tmp1 = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_LO:
|
case REG_SREG_LO:
|
||||||
Out->SRegLo = -1;
|
Out->SRegLo = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_HI:
|
case REG_SREG_HI:
|
||||||
Out->SRegHi = -1;
|
Out->SRegHi = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (E->AM == AM65_ZPX) {
|
} else if (E->AM == AM65_ZPX) {
|
||||||
@@ -1052,13 +1052,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
} else {
|
} else {
|
||||||
switch (GetKnownReg (E->Chg, In)) {
|
switch (GetKnownReg (E->Chg, In)) {
|
||||||
case REG_TMP1:
|
case REG_TMP1:
|
||||||
Out->Tmp1 = -1;
|
Out->Tmp1 = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_LO:
|
case REG_SREG_LO:
|
||||||
Out->SRegLo = -1;
|
Out->SRegLo = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_HI:
|
case REG_SREG_HI:
|
||||||
Out->SRegHi = -1;
|
Out->SRegHi = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,13 +1085,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
} else {
|
} else {
|
||||||
switch (GetKnownReg (E->Chg, In)) {
|
switch (GetKnownReg (E->Chg, In)) {
|
||||||
case REG_TMP1:
|
case REG_TMP1:
|
||||||
Out->Tmp1 = -1;
|
Out->Tmp1 = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_LO:
|
case REG_SREG_LO:
|
||||||
Out->SRegLo = -1;
|
Out->SRegLo = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
case REG_SREG_HI:
|
case REG_SREG_HI:
|
||||||
Out->SRegHi = -1;
|
Out->SRegHi = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1099,7 +1099,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TSX:
|
case OP65_TSX:
|
||||||
Out->RegX = -1;
|
Out->RegX = UNKNOWN_REGVAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OP65_TXA:
|
case OP65_TXA:
|
||||||
|
|||||||
@@ -132,9 +132,9 @@ static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Internal ("Invalid address flags");
|
Internal ("Invalid address flags: %04X", Flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return a pointer to the static buffer */
|
/* Return a pointer to the static buffer */
|
||||||
return Buf;
|
return Buf;
|
||||||
}
|
}
|
||||||
@@ -485,11 +485,51 @@ void g_leave (void)
|
|||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Register variables */
|
/* Register variables */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes)
|
||||||
|
/* Swap a register variable with a location on the stack */
|
||||||
|
{
|
||||||
|
/* Calculate the actual stack offset and check it */
|
||||||
|
StackOffs -= oursp;
|
||||||
|
CheckLocalOffs (StackOffs);
|
||||||
|
|
||||||
|
/* Generate code */
|
||||||
|
if (Bytes == 1) {
|
||||||
|
|
||||||
|
if (CodeSizeFactor < 165) {
|
||||||
|
ldyconst (StackOffs);
|
||||||
|
ldxconst (RegOffs);
|
||||||
|
AddCodeLine ("jsr regswap1");
|
||||||
|
} else {
|
||||||
|
ldyconst (StackOffs);
|
||||||
|
AddCodeLine ("lda (sp),y");
|
||||||
|
AddCodeLine ("ldx regbank%+d", RegOffs);
|
||||||
|
AddCodeLine ("sta regbank%+d", RegOffs);
|
||||||
|
AddCodeLine ("txa");
|
||||||
|
AddCodeLine ("sta (sp),y");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (Bytes == 2) {
|
||||||
|
|
||||||
|
ldyconst (StackOffs);
|
||||||
|
ldxconst (RegOffs);
|
||||||
|
AddCodeLine ("jsr regswap2");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
ldyconst (StackOffs);
|
||||||
|
ldxconst (RegOffs);
|
||||||
|
ldaconst (Bytes);
|
||||||
|
AddCodeLine ("jsr regswap");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void g_save_regvars (int RegOffs, unsigned Bytes)
|
void g_save_regvars (int RegOffs, unsigned Bytes)
|
||||||
/* Save register variables */
|
/* Save register variables */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -232,6 +232,9 @@ void g_leave (void);
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void g_swap_regvars (int StackOffs, int RegOffs, unsigned Bytes);
|
||||||
|
/* Swap a register variable with a location on the stack */
|
||||||
|
|
||||||
void g_save_regvars (int RegOffs, unsigned Bytes);
|
void g_save_regvars (int RegOffs, unsigned Bytes);
|
||||||
/* Save register variables */
|
/* Save register variables */
|
||||||
|
|
||||||
|
|||||||
@@ -165,6 +165,9 @@ static const FuncInfo FuncInfoTable[] = {
|
|||||||
{ "pushw0sp", REG_NONE, REG_AXY },
|
{ "pushw0sp", REG_NONE, REG_AXY },
|
||||||
{ "pushwidx", REG_AXY, REG_AXY | REG_PTR1 },
|
{ "pushwidx", REG_AXY, REG_AXY | REG_PTR1 },
|
||||||
{ "pushwysp", REG_Y, REG_AXY },
|
{ "pushwysp", REG_Y, REG_AXY },
|
||||||
|
{ "regswap", REG_AXY, REG_AXY | REG_TMP1 },
|
||||||
|
{ "regswap1", REG_XY, REG_A },
|
||||||
|
{ "regswap2", REG_XY, REG_A | REG_Y },
|
||||||
{ "shlax1", REG_AX, REG_AX | REG_TMP1 },
|
{ "shlax1", REG_AX, REG_AX | REG_TMP1 },
|
||||||
{ "shlax2", REG_AX, REG_AX | REG_TMP1 },
|
{ "shlax2", REG_AX, REG_AX | REG_TMP1 },
|
||||||
{ "shlax3", REG_AX, REG_AX | REG_TMP1 },
|
{ "shlax3", REG_AX, REG_AX | REG_TMP1 },
|
||||||
|
|||||||
@@ -1391,19 +1391,22 @@ void CS_GenRegInfo (CodeSeg* S)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (J->RI->Out2.RegA != Regs.RegA) {
|
if (J->RI->Out2.RegA != Regs.RegA) {
|
||||||
Regs.RegA = -1;
|
Regs.RegA = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (J->RI->Out2.RegX != Regs.RegX) {
|
if (J->RI->Out2.RegX != Regs.RegX) {
|
||||||
Regs.RegX = -1;
|
Regs.RegX = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (J->RI->Out2.RegY != Regs.RegY) {
|
if (J->RI->Out2.RegY != Regs.RegY) {
|
||||||
Regs.RegY = -1;
|
Regs.RegY = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
|
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
|
||||||
Regs.SRegLo = -1;
|
Regs.SRegLo = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
if (J->RI->Out2.SRegHi != Regs.SRegHi) {
|
if (J->RI->Out2.SRegHi != Regs.SRegHi) {
|
||||||
Regs.SRegHi = -1;
|
Regs.SRegHi = UNKNOWN_REGVAL;
|
||||||
|
}
|
||||||
|
if (J->RI->Out2.Tmp1 != Regs.Tmp1) {
|
||||||
|
Regs.Tmp1 = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
++Entry;
|
++Entry;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ unsigned OptAdd3 (CodeSeg* S)
|
|||||||
*
|
*
|
||||||
* jsr pushax
|
* jsr pushax
|
||||||
* lda xxx
|
* lda xxx
|
||||||
* ldy yyy
|
* ldx yyy
|
||||||
* jsr tosaddax
|
* jsr tosaddax
|
||||||
*
|
*
|
||||||
* and replace it by
|
* and replace it by
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ unsigned OptAdd3 (CodeSeg* S);
|
|||||||
*
|
*
|
||||||
* jsr pushax
|
* jsr pushax
|
||||||
* lda xxx
|
* lda xxx
|
||||||
* ldy yyy
|
* ldx yyy
|
||||||
* jsr tosaddax
|
* jsr tosaddax
|
||||||
*
|
*
|
||||||
* and replace it by
|
* and replace it by
|
||||||
@@ -113,7 +113,7 @@ unsigned OptAdd3 (CodeSeg* S);
|
|||||||
* adc yyy
|
* adc yyy
|
||||||
* tax
|
* tax
|
||||||
* pla
|
* pla
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned OptAdd4 (CodeSeg* S);
|
unsigned OptAdd4 (CodeSeg* S);
|
||||||
/* Search for the sequence
|
/* Search for the sequence
|
||||||
|
|||||||
@@ -34,6 +34,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
/* cc65 */
|
/* cc65 */
|
||||||
#include "codeent.h"
|
#include "codeent.h"
|
||||||
@@ -66,7 +67,7 @@ struct StackOpData {
|
|||||||
|
|
||||||
/* Flags returned by DirectOp */
|
/* Flags returned by DirectOp */
|
||||||
#define OP_DIRECT 0x01 /* Direct op may be used */
|
#define OP_DIRECT 0x01 /* Direct op may be used */
|
||||||
#define OP_ONSTACK 0x02 /* Operand is on stack */
|
#define OP_RELOAD_Y 0x02 /* Must reload index register Y */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -207,11 +208,9 @@ static void CheckDirectOp (StackOpData* D)
|
|||||||
if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) {
|
if (E->AM == AM65_IMM || E->AM == AM65_ZP || E->AM == AM65_ABS) {
|
||||||
/* These insns are all ok and replaceable */
|
/* These insns are all ok and replaceable */
|
||||||
D->Flags |= OP_DIRECT;
|
D->Flags |= OP_DIRECT;
|
||||||
} else if (E->AM == AM65_ZP_INDY &&
|
} else if (E->AM == AM65_ZP_INDY && RegValIsKnown (E->RI->In.RegY)) {
|
||||||
RegValIsKnown (E->RI->In.RegY) &&
|
/* Load indirect with known offset is also ok */
|
||||||
(E->Use & REG_SP) != 0) {
|
D->Flags |= (OP_DIRECT | OP_RELOAD_Y);
|
||||||
/* Load from stack with known offset is also ok */
|
|
||||||
D->Flags |= (OP_DIRECT | OP_ONSTACK);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,7 +221,7 @@ static void ReplacePushByStore (StackOpData* D)
|
|||||||
/* Replace the call to the push subroutine by a store into the zero page
|
/* Replace the call to the push subroutine by a store into the zero page
|
||||||
* location (actually, the push is not replaced, because we need it for
|
* location (actually, the push is not replaced, because we need it for
|
||||||
* later, but the name is still ok since the push will get removed at the
|
* later, but the name is still ok since the push will get removed at the
|
||||||
* end of each routine.
|
* end of each routine).
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
CodeEntry* X;
|
||||||
@@ -240,7 +239,7 @@ static void ReplacePushByStore (StackOpData* D)
|
|||||||
|
|
||||||
static void AddOpLow (StackOpData* D, opc_t OPC)
|
static void AddOpLow (StackOpData* D, opc_t OPC)
|
||||||
/* Add an op for the low byte of an operator. This function honours the
|
/* Add an op for the low byte of an operator. This function honours the
|
||||||
* OP_DIRECT and OP_ONSTACK flags and generates the necessary instructions.
|
* OP_DIRECT and OP_RELOAD_Y flags and generates the necessary instructions.
|
||||||
* All code is inserted at the current insertion point.
|
* All code is inserted at the current insertion point.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
@@ -250,7 +249,7 @@ static void AddOpLow (StackOpData* D, opc_t OPC)
|
|||||||
/* Op with a variable location. If the location is on the stack, we
|
/* Op with a variable location. If the location is on the stack, we
|
||||||
* need to reload the Y register.
|
* need to reload the Y register.
|
||||||
*/
|
*/
|
||||||
if ((D->Flags & OP_ONSTACK) != 0) {
|
if ((D->Flags & OP_RELOAD_Y) != 0) {
|
||||||
const char* Arg = MakeHexArg (D->PrevEntry->RI->In.RegY);
|
const char* Arg = MakeHexArg (D->PrevEntry->RI->In.RegY);
|
||||||
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
|
||||||
InsertEntry (D, X, D->IP++);
|
InsertEntry (D, X, D->IP++);
|
||||||
@@ -297,6 +296,33 @@ static void RemovePushAndOp (StackOpData* D)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static const char* IsRegVar (const StackOpData* D)
|
||||||
|
/* If the value pushed is that of a register variable, return the name of the
|
||||||
|
* entry in the register bank. Otherwise return NULL.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
CodeEntry* P;
|
||||||
|
|
||||||
|
if (D->PushIndex >= 2 &&
|
||||||
|
(P = D->PrevEntry) != 0 &&
|
||||||
|
P->OPC == OP65_LDX &&
|
||||||
|
P->AM == AM65_ZP &&
|
||||||
|
strncmp (P->Arg, "regbank+", 7) == 0 &&
|
||||||
|
isdigit (P->Arg[8]) &&
|
||||||
|
(P = CS_GetEntry (D->Code, D->PushIndex-2)) != 0 &&
|
||||||
|
P->OPC == OP65_LDA &&
|
||||||
|
P->AM == AM65_ZP &&
|
||||||
|
strncmp (P->Arg, "regbank+", 7) == 0 &&
|
||||||
|
isdigit (P->Arg[8])) {
|
||||||
|
/* Ok, it loads the register variable */
|
||||||
|
return P->Arg;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Actual optimization functions */
|
/* Actual optimization functions */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -307,12 +333,20 @@ static unsigned Opt_staspidx (StackOpData* D)
|
|||||||
/* Optimize the staspidx sequence if possible */
|
/* Optimize the staspidx sequence if possible */
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
CodeEntry* X;
|
||||||
|
const char* ZPLo;
|
||||||
|
|
||||||
/* Store the value into the zeropage instead of pushing it */
|
/* Check if we're using a register variable */
|
||||||
ReplacePushByStore (D);
|
if ((ZPLo = IsRegVar (D)) == 0) {
|
||||||
|
|
||||||
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
|
/* Use the given zero page loc */
|
||||||
|
ZPLo = D->ZPLo;
|
||||||
|
}
|
||||||
|
|
||||||
/* Replace the store subroutine call by a direct op */
|
/* Replace the store subroutine call by a direct op */
|
||||||
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI);
|
||||||
InsertEntry (D, X, D->OpIndex+1);
|
InsertEntry (D, X, D->OpIndex+1);
|
||||||
|
|
||||||
/* Remove the push and the call to the staspidx function */
|
/* Remove the push and the call to the staspidx function */
|
||||||
@@ -328,12 +362,20 @@ static unsigned Opt_staxspidx (StackOpData* D)
|
|||||||
/* Optimize the staxspidx sequence if possible */
|
/* Optimize the staxspidx sequence if possible */
|
||||||
{
|
{
|
||||||
CodeEntry* X;
|
CodeEntry* X;
|
||||||
|
const char* ZPLo;
|
||||||
|
|
||||||
/* Store the value into the zeropage instead of pushing it */
|
/* Check if we're using a register variable */
|
||||||
ReplacePushByStore (D);
|
if ((ZPLo = IsRegVar (D)) == 0) {
|
||||||
|
|
||||||
|
/* Store the value into the zeropage instead of pushing it */
|
||||||
|
ReplacePushByStore (D);
|
||||||
|
|
||||||
|
/* Use the given zero page loc */
|
||||||
|
ZPLo = D->ZPLo;
|
||||||
|
}
|
||||||
|
|
||||||
/* Inline the store */
|
/* Inline the store */
|
||||||
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI);
|
||||||
InsertEntry (D, X, D->OpIndex+1);
|
InsertEntry (D, X, D->OpIndex+1);
|
||||||
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
|
||||||
InsertEntry (D, X, D->OpIndex+2);
|
InsertEntry (D, X, D->OpIndex+2);
|
||||||
@@ -346,7 +388,7 @@ static unsigned Opt_staxspidx (StackOpData* D)
|
|||||||
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, D->OpEntry->LI);
|
||||||
}
|
}
|
||||||
InsertEntry (D, X, D->OpIndex+3);
|
InsertEntry (D, X, D->OpIndex+3);
|
||||||
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, D->ZPLo, 0, D->OpEntry->LI);
|
X = NewCodeEntry (OP65_STA, AM65_ZP_INDY, ZPLo, 0, D->OpEntry->LI);
|
||||||
InsertEntry (D, X, D->OpIndex+4);
|
InsertEntry (D, X, D->OpIndex+4);
|
||||||
|
|
||||||
/* Remove the push and the call to the staspidx function */
|
/* Remove the push and the call to the staspidx function */
|
||||||
@@ -607,7 +649,7 @@ static int HarmlessCall (const char* Name)
|
|||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
static const char* Tab[] = {
|
static const char* Tab[] = {
|
||||||
"ldaxidx",
|
"ldaxidx",
|
||||||
"ldaxysp",
|
"ldaxysp",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ static type OptionalQualifiers (type Q)
|
|||||||
switch (CurTok.Tok) {
|
switch (CurTok.Tok) {
|
||||||
|
|
||||||
case TOK_CONST:
|
case TOK_CONST:
|
||||||
if (Q & T_QUAL_CONST) {
|
if (Q & T_QUAL_CONST) {
|
||||||
Error ("Duplicate qualifier: `const'");
|
Error ("Duplicate qualifier: `const'");
|
||||||
}
|
}
|
||||||
Q |= T_QUAL_CONST;
|
Q |= T_QUAL_CONST;
|
||||||
@@ -339,7 +339,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
|
|||||||
ident Ident;
|
ident Ident;
|
||||||
SymEntry* Entry;
|
SymEntry* Entry;
|
||||||
type StructType;
|
type StructType;
|
||||||
type Qualifiers; /* Type qualifiers */
|
type Qualifiers; /* Type qualifiers */
|
||||||
|
|
||||||
/* Assume we have an explicit type */
|
/* Assume we have an explicit type */
|
||||||
D->Flags &= ~DS_DEF_TYPE;
|
D->Flags &= ~DS_DEF_TYPE;
|
||||||
@@ -427,7 +427,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
|
|||||||
/* FALL THROUGH */
|
/* FALL THROUGH */
|
||||||
|
|
||||||
default:
|
default:
|
||||||
D->Type[0] = T_INT;
|
D->Type[0] = T_INT;
|
||||||
D->Type[1] = T_END;
|
D->Type[1] = T_END;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -663,14 +663,15 @@ static void ParseAnsiParamList (FuncDesc* F)
|
|||||||
/* Read the declaration specifier */
|
/* Read the declaration specifier */
|
||||||
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
|
||||||
|
|
||||||
/* We accept only auto and register as storage class specifiers, but
|
/* We accept only auto and register as storage class specifiers */
|
||||||
* we ignore all this and use auto.
|
if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
|
||||||
*/
|
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
|
||||||
if ((Spec.StorageClass & SC_AUTO) == 0 &&
|
} else if ((Spec.StorageClass & SC_REGISTER) == SC_REGISTER) {
|
||||||
(Spec.StorageClass & SC_REGISTER) == 0) {
|
Spec.StorageClass = SC_REGISTER | SC_STATIC | SC_PARAM | SC_DEF;
|
||||||
|
} else {
|
||||||
Error ("Illegal storage class");
|
Error ("Illegal storage class");
|
||||||
|
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
|
||||||
}
|
}
|
||||||
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
|
|
||||||
|
|
||||||
/* Allow parameters without a name, but remember if we had some to
|
/* Allow parameters without a name, but remember if we had some to
|
||||||
* eventually print an error message later.
|
* eventually print an error message later.
|
||||||
@@ -755,10 +756,10 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
|
|||||||
|
|
||||||
/* Check for an implicit int return in the K&R function */
|
/* Check for an implicit int return in the K&R function */
|
||||||
if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
|
if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
|
||||||
Spec->Type[0] == T_INT &&
|
Spec->Type[0] == T_INT &&
|
||||||
Spec->Type[1] == T_END) {
|
Spec->Type[1] == T_END) {
|
||||||
/* Function has an implicit int return */
|
/* Function has an implicit int return */
|
||||||
F->Flags |= FD_OLDSTYLE_INTRET;
|
F->Flags |= FD_OLDSTYLE_INTRET;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -779,7 +780,11 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
|
|||||||
Sym = GetSymTab()->SymTail;
|
Sym = GetSymTab()->SymTail;
|
||||||
while (Sym) {
|
while (Sym) {
|
||||||
unsigned Size = CheckedSizeOf (Sym->Type);
|
unsigned Size = CheckedSizeOf (Sym->Type);
|
||||||
Sym->V.Offs = Offs;
|
if (SymIsRegVar (Sym)) {
|
||||||
|
Sym->V.R.SaveOffs = Offs;
|
||||||
|
} else {
|
||||||
|
Sym->V.Offs = Offs;
|
||||||
|
}
|
||||||
Offs += Size;
|
Offs += Size;
|
||||||
F->ParamSize += Size;
|
F->ParamSize += Size;
|
||||||
Sym = Sym->PrevSym;
|
Sym = Sym->PrevSym;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* */
|
/* */
|
||||||
/* (C) 2000-2001 Ullrich von Bassewitz */
|
/* (C) 2000-2002 Ullrich von Bassewitz */
|
||||||
/* Wacholderweg 14 */
|
/* Wacholderweg 14 */
|
||||||
/* D-70597 Stuttgart */
|
/* D-70597 Stuttgart */
|
||||||
/* EMail: uz@cc65.org */
|
/* EMail: uz@cc65.org */
|
||||||
@@ -60,14 +60,18 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Maximum register variable size */
|
||||||
|
#define MAX_REG_SPACE 6
|
||||||
|
|
||||||
/* Structure that holds all data needed for function activation */
|
/* Structure that holds all data needed for function activation */
|
||||||
struct Function {
|
struct Function {
|
||||||
struct SymEntry* FuncEntry; /* Symbol table entry */
|
struct SymEntry* FuncEntry; /* Symbol table entry */
|
||||||
type* ReturnType; /* Function return type */
|
type* ReturnType; /* Function return type */
|
||||||
struct FuncDesc* Desc; /* Function descriptor */
|
struct FuncDesc* Desc; /* Function descriptor */
|
||||||
int Reserved; /* Reserved local space */
|
int Reserved; /* Reserved local space */
|
||||||
unsigned RetLab; /* Return code label */
|
unsigned RetLab; /* Return code label */
|
||||||
int TopLevelSP; /* SP at function top level */
|
int TopLevelSP; /* SP at function top level */
|
||||||
|
unsigned RegOffs; /* Register variable space offset */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Pointer to current function */
|
/* Pointer to current function */
|
||||||
@@ -94,6 +98,7 @@ static Function* NewFunction (struct SymEntry* Sym)
|
|||||||
F->Reserved = 0;
|
F->Reserved = 0;
|
||||||
F->RetLab = GetLocalLabel ();
|
F->RetLab = GetLocalLabel ();
|
||||||
F->TopLevelSP = 0;
|
F->TopLevelSP = 0;
|
||||||
|
F->RegOffs = MAX_REG_SPACE;
|
||||||
|
|
||||||
/* Return the new structure */
|
/* Return the new structure */
|
||||||
return F;
|
return F;
|
||||||
@@ -220,6 +225,108 @@ void F_AllocLocalSpace (Function* F)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int F_AllocRegVar (Function* F, const type* Type)
|
||||||
|
/* Allocate a register variable for the given variable type. If the allocation
|
||||||
|
* was successful, return the offset of the register variable in the register
|
||||||
|
* bank (zero page storage). If there is no register space left, return -1.
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
/* Allow register variables only on top level and if enabled */
|
||||||
|
if (EnableRegVars && GetLexicalLevel () == LEX_LEVEL_FUNCTION) {
|
||||||
|
|
||||||
|
/* Get the size of the variable */
|
||||||
|
unsigned Size = CheckedSizeOf (Type);
|
||||||
|
|
||||||
|
/* Do we have space left? */
|
||||||
|
if (F->RegOffs >= Size) {
|
||||||
|
/* Space left. We allocate the variables from high to low addresses,
|
||||||
|
* so the adressing is compatible with the saved values on stack.
|
||||||
|
* This allows shorter code when saving/restoring the variables.
|
||||||
|
*/
|
||||||
|
F->RegOffs -= Size;
|
||||||
|
return F->RegOffs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No space left or no allocation */
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void F_RestoreRegVars (Function* F)
|
||||||
|
/* Restore the register variables for the local function if there are any. */
|
||||||
|
{
|
||||||
|
const SymEntry* Sym;
|
||||||
|
|
||||||
|
/* If we don't have register variables in this function, bail out early */
|
||||||
|
if (F->RegOffs == MAX_REG_SPACE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save the accumulator if needed */
|
||||||
|
if (!F_HasVoidReturn (F)) {
|
||||||
|
g_save (CF_CHAR | CF_FORCECHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the first symbol from the function symbol table */
|
||||||
|
Sym = F->FuncEntry->V.F.Func->SymTab->SymHead;
|
||||||
|
|
||||||
|
/* Walk through all symbols checking for register variables */
|
||||||
|
while (Sym) {
|
||||||
|
if (SymIsRegVar (Sym)) {
|
||||||
|
|
||||||
|
/* Check for more than one variable */
|
||||||
|
int Offs = Sym->V.R.SaveOffs;
|
||||||
|
unsigned Bytes = CheckedSizeOf (Sym->Type);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
|
||||||
|
/* Find next register variable */
|
||||||
|
const SymEntry* NextSym = Sym->NextSym;
|
||||||
|
while (NextSym && !SymIsRegVar (NextSym)) {
|
||||||
|
NextSym = NextSym->NextSym;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If we have a next one, compare the stack offsets */
|
||||||
|
if (NextSym) {
|
||||||
|
|
||||||
|
/* We have a following register variable. Get the size */
|
||||||
|
int Size = CheckedSizeOf (NextSym->Type);
|
||||||
|
|
||||||
|
/* Adjacent variable? */
|
||||||
|
if (NextSym->V.R.SaveOffs + Size != Offs) {
|
||||||
|
/* No */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjacent variable */
|
||||||
|
Bytes += Size;
|
||||||
|
Offs -= Size;
|
||||||
|
Sym = NextSym;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the memory range */
|
||||||
|
g_restore_regvars (Offs, Sym->V.R.RegOffs, Bytes);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check next symbol */
|
||||||
|
Sym = Sym->NextSym;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restore the accumulator if needed */
|
||||||
|
if (!F_HasVoidReturn (F)) {
|
||||||
|
g_restore (CF_CHAR | CF_FORCECHAR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* code */
|
/* code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -230,8 +337,8 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Parse argument declarations and function body. */
|
/* Parse argument declarations and function body. */
|
||||||
{
|
{
|
||||||
int HadReturn;
|
int HadReturn;
|
||||||
int IsVoidFunc;
|
|
||||||
SymEntry* LastParam;
|
SymEntry* LastParam;
|
||||||
|
SymEntry* Param;
|
||||||
|
|
||||||
/* Get the function descriptor from the function entry */
|
/* Get the function descriptor from the function entry */
|
||||||
FuncDesc* D = Func->V.F.Func;
|
FuncDesc* D = Func->V.F.Func;
|
||||||
@@ -262,9 +369,6 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Function body now defined */
|
/* Function body now defined */
|
||||||
Func->Flags |= SC_DEF;
|
Func->Flags |= SC_DEF;
|
||||||
|
|
||||||
/* Setup register variables */
|
|
||||||
InitRegVars ();
|
|
||||||
|
|
||||||
/* Allocate code and data segments for this function */
|
/* Allocate code and data segments for this function */
|
||||||
Func->V.F.Seg = PushSegments (Func);
|
Func->V.F.Seg = PushSegments (Func);
|
||||||
|
|
||||||
@@ -281,19 +385,50 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Pointer to function */
|
/* Pointer to function */
|
||||||
Flags = CF_PTR;
|
Flags = CF_PTR;
|
||||||
} else {
|
} else {
|
||||||
Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
|
Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
|
||||||
}
|
}
|
||||||
g_push (Flags, 0);
|
g_push (Flags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If stack checking code is requested, emit a call to the helper routine */
|
|
||||||
if (CheckStack) {
|
|
||||||
g_stackcheck ();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Generate function entry code if needed */
|
/* Generate function entry code if needed */
|
||||||
g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));
|
g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));
|
||||||
|
|
||||||
|
/* If stack checking code is requested, emit a call to the helper routine */
|
||||||
|
if (CheckStack) {
|
||||||
|
g_stackcheck ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Walk through the parameter list and allocate register variable space
|
||||||
|
* for parameters declared as register. Generate code to swap the contents
|
||||||
|
* of the register bank with the save area on the stack.
|
||||||
|
*/
|
||||||
|
Param = D->SymTab->SymHead;
|
||||||
|
while (Param && (Param->Flags & SC_PARAM) != 0) {
|
||||||
|
|
||||||
|
/* Check for a register variable */
|
||||||
|
if (SymIsRegVar (Param)) {
|
||||||
|
|
||||||
|
/* Allocate space */
|
||||||
|
int Reg = F_AllocRegVar (CurrentFunc, Param->Type);
|
||||||
|
|
||||||
|
/* Could we allocate a register? */
|
||||||
|
if (Reg < 0) {
|
||||||
|
/* No register available: Convert parameter to auto */
|
||||||
|
CvtRegVarToAuto (Param);
|
||||||
|
} else {
|
||||||
|
/* Remember the register offset */
|
||||||
|
Param->V.R.RegOffs = Reg;
|
||||||
|
|
||||||
|
/* Generate swap code */
|
||||||
|
g_swap_regvars (Param->V.R.SaveOffs, Reg, CheckedSizeOf (Param->Type));
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next parameter */
|
||||||
|
Param = Param->NextSym;
|
||||||
|
}
|
||||||
|
|
||||||
/* Setup the stack */
|
/* Setup the stack */
|
||||||
oursp = 0;
|
oursp = 0;
|
||||||
|
|
||||||
@@ -318,22 +453,11 @@ void NewFunc (SymEntry* Func)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the function has a return type but no return statement, flag
|
|
||||||
* a warning
|
|
||||||
*/
|
|
||||||
IsVoidFunc = F_HasVoidReturn (CurrentFunc);
|
|
||||||
#if 0
|
|
||||||
/* Does not work reliably */
|
|
||||||
if (!F_IsVoidFunc && !HadReturn) {
|
|
||||||
Warning ("Function `%s' should return a value", Func->Name);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Output the function exit code label */
|
/* Output the function exit code label */
|
||||||
g_defcodelabel (F_GetRetLab (CurrentFunc));
|
g_defcodelabel (F_GetRetLab (CurrentFunc));
|
||||||
|
|
||||||
/* Restore the register variables */
|
/* Restore the register variables */
|
||||||
RestoreRegVars (!IsVoidFunc);
|
F_RestoreRegVars (CurrentFunc);
|
||||||
|
|
||||||
/* Generate the exit code */
|
/* Generate the exit code */
|
||||||
g_leave ();
|
g_leave ();
|
||||||
@@ -344,9 +468,6 @@ void NewFunc (SymEntry* Func)
|
|||||||
/* Emit references to imports/exports */
|
/* Emit references to imports/exports */
|
||||||
EmitExternals ();
|
EmitExternals ();
|
||||||
|
|
||||||
/* Cleanup register variables */
|
|
||||||
DoneRegVars ();
|
|
||||||
|
|
||||||
/* Leave the lexical level */
|
/* Leave the lexical level */
|
||||||
LeaveFunctionLevel ();
|
LeaveFunctionLevel ();
|
||||||
|
|
||||||
|
|||||||
@@ -98,6 +98,12 @@ void F_AllocLocalSpace (Function* F);
|
|||||||
* nothing if there is no reserved local space.
|
* nothing if there is no reserved local space.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
int F_AllocRegVar (Function* F, const type* Type);
|
||||||
|
/* Allocate a register variable for the given variable type. If the allocation
|
||||||
|
* was successful, return the offset of the register variable in the register
|
||||||
|
* bank (zero page storage). If there is no register space left, return -1.
|
||||||
|
*/
|
||||||
|
|
||||||
void NewFunc (struct SymEntry* Func);
|
void NewFunc (struct SymEntry* Func);
|
||||||
/* Parse argument declarations and function body. */
|
/* Parse argument declarations and function body. */
|
||||||
|
|
||||||
|
|||||||
@@ -51,93 +51,12 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Data */
|
|
||||||
/*****************************************************************************/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Register variable management */
|
|
||||||
unsigned MaxRegSpace = 6; /* Maximum space available */
|
|
||||||
static unsigned RegOffs = 0; /* Offset into register space */
|
|
||||||
static const SymEntry** RegSyms = 0; /* The register variables */
|
|
||||||
static unsigned RegSymCount = 0; /* Number of register variables */
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Code */
|
/* Code */
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void InitRegVars (void)
|
|
||||||
/* Initialize register variable control data */
|
|
||||||
{
|
|
||||||
/* If the register space is zero, bail out */
|
|
||||||
if (MaxRegSpace == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The maximum number of register variables is equal to the register
|
|
||||||
* variable space available. So allocate one pointer per byte. This
|
|
||||||
* will usually waste some space but we don't need to dynamically
|
|
||||||
* grow the array.
|
|
||||||
*/
|
|
||||||
RegSyms = (const SymEntry**) xmalloc (MaxRegSpace * sizeof (RegSyms[0]));
|
|
||||||
RegOffs = MaxRegSpace;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DoneRegVars (void)
|
|
||||||
/* Free the register variables */
|
|
||||||
{
|
|
||||||
xfree (RegSyms);
|
|
||||||
RegSyms = 0;
|
|
||||||
RegOffs = MaxRegSpace;
|
|
||||||
RegSymCount = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int AllocRegVar (const type* Type)
|
|
||||||
/* Allocate a register variable for the given variable type. If the allocation
|
|
||||||
* was successful, return the offset of the register variable in the register
|
|
||||||
* bank (zero page storage). If there is no register space left, return -1.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
/* Maybe register variables are disabled... */
|
|
||||||
if (EnableRegVars) {
|
|
||||||
|
|
||||||
/* Get the size of the variable */
|
|
||||||
unsigned Size = CheckedSizeOf (Type);
|
|
||||||
|
|
||||||
/* Do we have space left? */
|
|
||||||
if (RegOffs >= Size) {
|
|
||||||
/* Space left. We allocate the variables from high to low addresses,
|
|
||||||
* so the adressing is compatible with the saved values on stack.
|
|
||||||
* This allows shorter code when saving/restoring the variables.
|
|
||||||
*/
|
|
||||||
RegOffs -= Size;
|
|
||||||
return RegOffs;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* No space left or no allocation */
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void RememberRegVar (const SymEntry* Sym)
|
|
||||||
/* Remember the given register variable */
|
|
||||||
{
|
|
||||||
RegSyms[RegSymCount++] = Sym;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
||||||
/* Parse the declaration of a register variable. The function returns the
|
/* Parse the declaration of a register variable. The function returns the
|
||||||
* symbol data, which is the offset of the variable in the register bank.
|
* symbol data, which is the offset of the variable in the register bank.
|
||||||
@@ -185,7 +104,7 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* Setup the type flags for the assignment */
|
/* Setup the type flags for the assignment */
|
||||||
Flags = CF_REGVAR;
|
Flags = CF_NONE;
|
||||||
if (Size == SIZEOF_CHAR) {
|
if (Size == SIZEOF_CHAR) {
|
||||||
Flags |= CF_FORCECHAR;
|
Flags |= CF_FORCECHAR;
|
||||||
}
|
}
|
||||||
@@ -195,12 +114,15 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
|
|||||||
/* Constant expression. Adjust the types */
|
/* Constant expression. Adjust the types */
|
||||||
assignadjust (Decl->Type, &lval);
|
assignadjust (Decl->Type, &lval);
|
||||||
Flags |= CF_CONST;
|
Flags |= CF_CONST;
|
||||||
|
/* Load it into the primary */
|
||||||
|
exprhs (Flags, 0, &lval);
|
||||||
} else {
|
} else {
|
||||||
/* Expression is not constant and in the primary */
|
/* Expression is not constant and in the primary */
|
||||||
assignadjust (Decl->Type, &lval);
|
assignadjust (Decl->Type, &lval);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Store the value into the variable */
|
/* Store the value into the variable */
|
||||||
|
Flags |= CF_REGVAR;
|
||||||
g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
|
g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -456,7 +378,6 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||||||
unsigned SC; /* Storage class for symbol */
|
unsigned SC; /* Storage class for symbol */
|
||||||
unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
|
unsigned SymData = 0; /* Symbol data (offset, label name, ...) */
|
||||||
Declaration Decl; /* Declaration data structure */
|
Declaration Decl; /* Declaration data structure */
|
||||||
SymEntry* Sym; /* Symbol declared */
|
|
||||||
|
|
||||||
|
|
||||||
/* Remember the storage class for the new symbol */
|
/* Remember the storage class for the new symbol */
|
||||||
@@ -467,10 +388,10 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||||||
|
|
||||||
/* Set the correct storage class for functions */
|
/* Set the correct storage class for functions */
|
||||||
if (IsTypeFunc (Decl.Type)) {
|
if (IsTypeFunc (Decl.Type)) {
|
||||||
/* Function prototypes are always external */
|
/* Function prototypes are always external */
|
||||||
if ((SC & SC_EXTERN) == 0) {
|
if ((SC & SC_EXTERN) == 0) {
|
||||||
Warning ("Function must be extern");
|
Warning ("Function must be extern");
|
||||||
}
|
}
|
||||||
SC |= SC_FUNC | SC_EXTERN;
|
SC |= SC_FUNC | SC_EXTERN;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -489,19 +410,19 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||||||
* convert the declaration to "auto" if this is not possible.
|
* convert the declaration to "auto" if this is not possible.
|
||||||
*/
|
*/
|
||||||
int Reg = 0; /* Initialize to avoid gcc complains */
|
int Reg = 0; /* Initialize to avoid gcc complains */
|
||||||
if ((SC & SC_REGISTER) != 0 && (Reg = AllocRegVar (Decl.Type)) < 0) {
|
if ((SC & SC_REGISTER) != 0 && (Reg = F_AllocRegVar (CurrentFunc, Decl.Type)) < 0) {
|
||||||
/* No space for this register variable, convert to auto */
|
/* No space for this register variable, convert to auto */
|
||||||
SC = (SC & ~SC_REGISTER) | SC_AUTO;
|
SC = (SC & ~SC_REGISTER) | SC_AUTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check the variable type */
|
/* Check the variable type */
|
||||||
if (SC & SC_REGISTER) {
|
if ((SC & SC_REGISTER) == SC_REGISTER) {
|
||||||
/* Register variable */
|
/* Register variable */
|
||||||
SymData = ParseRegisterDecl (&Decl, &SC, Reg);
|
SymData = ParseRegisterDecl (&Decl, &SC, Reg);
|
||||||
} else if (SC & SC_AUTO) {
|
} else if ((SC & SC_AUTO) == SC_AUTO) {
|
||||||
/* Auto variable */
|
/* Auto variable */
|
||||||
SymData = ParseAutoDecl (&Decl, &SC);
|
SymData = ParseAutoDecl (&Decl, &SC);
|
||||||
} else if (SC & SC_STATIC) {
|
} else if ((SC & SC_STATIC) == SC_STATIC) {
|
||||||
/* Static variable */
|
/* Static variable */
|
||||||
SymData = ParseStaticDecl (&Decl, &SC);
|
SymData = ParseStaticDecl (&Decl, &SC);
|
||||||
} else {
|
} else {
|
||||||
@@ -515,12 +436,7 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Add the symbol to the symbol table */
|
/* Add the symbol to the symbol table */
|
||||||
Sym = AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
|
AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
|
||||||
|
|
||||||
/* If we had declared a register variable, remember it now */
|
|
||||||
if (SC & SC_REGISTER) {
|
|
||||||
RememberRegVar (Sym);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -587,70 +503,3 @@ void DeclareLocals (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RestoreRegVars (int HaveResult)
|
|
||||||
/* Restore the register variables for the local function if there are any.
|
|
||||||
* The parameter tells us if there is a return value in ax, in that case,
|
|
||||||
* the accumulator must be saved across the restore.
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
unsigned I, J;
|
|
||||||
int Bytes, Offs;
|
|
||||||
|
|
||||||
/* If we don't have register variables in this function, bail out early */
|
|
||||||
if (RegSymCount == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Save the accumulator if needed */
|
|
||||||
if (!F_HasVoidReturn (CurrentFunc) && HaveResult) {
|
|
||||||
g_save (CF_CHAR | CF_FORCECHAR);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Walk through all variables. If there are several variables in a row
|
|
||||||
* (that is, with increasing stack offset), restore them in one chunk.
|
|
||||||
*/
|
|
||||||
I = 0;
|
|
||||||
while (I < RegSymCount) {
|
|
||||||
|
|
||||||
/* Check for more than one variable */
|
|
||||||
const SymEntry* Sym = RegSyms[I];
|
|
||||||
Offs = Sym->V.R.SaveOffs;
|
|
||||||
Bytes = CheckedSizeOf (Sym->Type);
|
|
||||||
J = I+1;
|
|
||||||
|
|
||||||
while (J < RegSymCount) {
|
|
||||||
|
|
||||||
/* Get the next symbol */
|
|
||||||
const SymEntry* NextSym = RegSyms [J];
|
|
||||||
|
|
||||||
/* Get the size */
|
|
||||||
int Size = CheckedSizeOf (NextSym->Type);
|
|
||||||
|
|
||||||
/* Adjacent variable? */
|
|
||||||
if (NextSym->V.R.SaveOffs + Size != Offs) {
|
|
||||||
/* No */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Adjacent variable */
|
|
||||||
Bytes += Size;
|
|
||||||
Offs -= Size;
|
|
||||||
Sym = NextSym;
|
|
||||||
++J;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore the memory range */
|
|
||||||
g_restore_regvars (Offs, Sym->V.R.RegOffs, Bytes);
|
|
||||||
|
|
||||||
/* Next round */
|
|
||||||
I = J;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Restore the accumulator if needed */
|
|
||||||
if (!F_HasVoidReturn (CurrentFunc) && HaveResult) {
|
|
||||||
g_restore (CF_CHAR | CF_FORCECHAR);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -50,12 +50,12 @@
|
|||||||
void RC_Invalidate (RegContents* C)
|
void RC_Invalidate (RegContents* C)
|
||||||
/* Invalidate all registers */
|
/* Invalidate all registers */
|
||||||
{
|
{
|
||||||
C->RegA = -1;
|
C->RegA = UNKNOWN_REGVAL;
|
||||||
C->RegX = -1;
|
C->RegX = UNKNOWN_REGVAL;
|
||||||
C->RegY = -1;
|
C->RegY = UNKNOWN_REGVAL;
|
||||||
C->SRegLo = -1;
|
C->SRegLo = UNKNOWN_REGVAL;
|
||||||
C->SRegHi = -1;
|
C->SRegHi = UNKNOWN_REGVAL;
|
||||||
C->Tmp1 = -1;
|
C->Tmp1 = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -63,9 +63,9 @@ void RC_Invalidate (RegContents* C)
|
|||||||
void RC_InvalidateZP (RegContents* C)
|
void RC_InvalidateZP (RegContents* C)
|
||||||
/* Invalidate all ZP registers */
|
/* Invalidate all ZP registers */
|
||||||
{
|
{
|
||||||
C->SRegLo = -1;
|
C->SRegLo = UNKNOWN_REGVAL;
|
||||||
C->SRegHi = -1;
|
C->SRegHi = UNKNOWN_REGVAL;
|
||||||
C->Tmp1 = -1;
|
C->Tmp1 = UNKNOWN_REGVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -104,4 +104,4 @@ void FreeRegInfo (RegInfo* RI)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,9 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Encoding for an unknown register value */
|
||||||
|
#define UNKNOWN_REGVAL -1
|
||||||
|
|
||||||
/* Register contents */
|
/* Register contents */
|
||||||
typedef struct RegContents RegContents;
|
typedef struct RegContents RegContents;
|
||||||
struct RegContents {
|
struct RegContents {
|
||||||
|
|||||||
@@ -149,6 +149,18 @@ void DumpSymEntry (FILE* F, const SymEntry* E)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CvtRegVarToAuto (SymEntry* Sym)
|
||||||
|
/* Convert a register variable to an auto variable */
|
||||||
|
{
|
||||||
|
/* Change the storage class */
|
||||||
|
Sym->Flags = (Sym->Flags & ~(SC_REGISTER | SC_STATIC | SC_EXTERN)) | SC_AUTO;
|
||||||
|
|
||||||
|
/* Transfer the stack offset from register save area to actual offset */
|
||||||
|
Sym->V.Offs = Sym->V.R.SaveOffs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void ChangeSymType (SymEntry* Entry, type* Type)
|
void ChangeSymType (SymEntry* Entry, type* Type)
|
||||||
/* Change the type of the given symbol */
|
/* Change the type of the given symbol */
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -186,6 +186,19 @@ INLINE int SymIsRef (const SymEntry* Sym)
|
|||||||
# define SymIsRef(Sym) (((Sym)->Flags & SC_REF) == SC_REF)
|
# define SymIsRef(Sym) (((Sym)->Flags & SC_REF) == SC_REF)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAVE_INLINE)
|
||||||
|
INLINE int SymIsRegVar (const SymEntry* Sym)
|
||||||
|
/* Return true if the given entry is a register variable */
|
||||||
|
{
|
||||||
|
return ((Sym->Flags & SC_REGISTER) == SC_REGISTER);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
# define SymIsRegVar(Sym) (((Sym)->Flags & SC_REGISTER) == SC_REGISTER)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CvtRegVarToAuto (SymEntry* Sym);
|
||||||
|
/* Convert a register variable to an auto variable */
|
||||||
|
|
||||||
void ChangeSymType (SymEntry* Entry, type* Type);
|
void ChangeSymType (SymEntry* Entry, type* Type);
|
||||||
/* Change the type of the given symbol */
|
/* Change the type of the given symbol */
|
||||||
|
|
||||||
|
|||||||
@@ -81,9 +81,6 @@ SymTable EmptySymTab = {
|
|||||||
#define SYMTAB_SIZE_STRUCT 19U
|
#define SYMTAB_SIZE_STRUCT 19U
|
||||||
#define SYMTAB_SIZE_LABEL 7U
|
#define SYMTAB_SIZE_LABEL 7U
|
||||||
|
|
||||||
/* Predefined lexical levels */
|
|
||||||
#define LEX_LEVEL_GLOBAL 1U
|
|
||||||
|
|
||||||
/* The current and root symbol tables */
|
/* The current and root symbol tables */
|
||||||
static unsigned LexicalLevel = 0; /* For safety checks */
|
static unsigned LexicalLevel = 0; /* For safety checks */
|
||||||
static SymTable* SymTab0 = 0;
|
static SymTable* SymTab0 = 0;
|
||||||
@@ -198,6 +195,14 @@ static void CheckSymTable (SymTable* Tab)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned GetLexicalLevel (void)
|
||||||
|
/* Return the current lexical level */
|
||||||
|
{
|
||||||
|
return LexicalLevel;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void EnterGlobalLevel (void)
|
void EnterGlobalLevel (void)
|
||||||
/* Enter the program global lexical level */
|
/* Enter the program global lexical level */
|
||||||
{
|
{
|
||||||
@@ -241,7 +246,7 @@ void EnterFunctionLevel (void)
|
|||||||
SymTable* S;
|
SymTable* S;
|
||||||
|
|
||||||
/* New lexical level */
|
/* New lexical level */
|
||||||
++LexicalLevel;
|
PRECONDITION (++LexicalLevel == LEX_LEVEL_FUNCTION);
|
||||||
|
|
||||||
/* Get a new symbol table and make it current */
|
/* Get a new symbol table and make it current */
|
||||||
S = NewSymTable (SYMTAB_SIZE_FUNCTION);
|
S = NewSymTable (SYMTAB_SIZE_FUNCTION);
|
||||||
@@ -263,7 +268,7 @@ void RememberFunctionLevel (struct FuncDesc* F)
|
|||||||
/* Remember the symbol tables for the level and leave the level without checks */
|
/* Remember the symbol tables for the level and leave the level without checks */
|
||||||
{
|
{
|
||||||
/* Leave the lexical level */
|
/* Leave the lexical level */
|
||||||
--LexicalLevel;
|
PRECONDITION (LexicalLevel-- == LEX_LEVEL_FUNCTION);
|
||||||
|
|
||||||
/* Remember the tables */
|
/* Remember the tables */
|
||||||
F->SymTab = SymTab;
|
F->SymTab = SymTab;
|
||||||
@@ -280,7 +285,7 @@ void ReenterFunctionLevel (struct FuncDesc* F)
|
|||||||
/* Reenter the function lexical level using the existing tables from F */
|
/* Reenter the function lexical level using the existing tables from F */
|
||||||
{
|
{
|
||||||
/* New lexical level */
|
/* New lexical level */
|
||||||
++LexicalLevel;
|
PRECONDITION (++LexicalLevel == LEX_LEVEL_FUNCTION);
|
||||||
|
|
||||||
/* Make the tables current again */
|
/* Make the tables current again */
|
||||||
F->SymTab->PrevTab = SymTab;
|
F->SymTab->PrevTab = SymTab;
|
||||||
@@ -299,7 +304,7 @@ void LeaveFunctionLevel (void)
|
|||||||
/* Leave function lexical level */
|
/* Leave function lexical level */
|
||||||
{
|
{
|
||||||
/* Leave the lexical level */
|
/* Leave the lexical level */
|
||||||
--LexicalLevel;
|
PRECONDITION (LexicalLevel-- == LEX_LEVEL_FUNCTION);
|
||||||
|
|
||||||
/* Check the tables */
|
/* Check the tables */
|
||||||
CheckSymTable (SymTab);
|
CheckSymTable (SymTab);
|
||||||
|
|||||||
@@ -68,6 +68,10 @@ extern SymTable EmptySymTab;
|
|||||||
/* Forwards */
|
/* Forwards */
|
||||||
struct FuncDesc;
|
struct FuncDesc;
|
||||||
|
|
||||||
|
/* Predefined lexical levels */
|
||||||
|
#define LEX_LEVEL_GLOBAL 1U
|
||||||
|
#define LEX_LEVEL_FUNCTION 2U
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
@@ -76,6 +80,9 @@ struct FuncDesc;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned GetLexicalLevel (void);
|
||||||
|
/* Return the current lexical level */
|
||||||
|
|
||||||
void EnterGlobalLevel (void);
|
void EnterGlobalLevel (void);
|
||||||
/* Enter the program global lexical level */
|
/* Enter the program global lexical level */
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user