1
0
mirror of https://github.com/cc65/cc65.git synced 2024-06-09 06:29:38 +00:00

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:
cuz 2002-11-25 15:05:15 +00:00
parent 1d94d18fa5
commit 70755921a9
18 changed files with 407 additions and 295 deletions

View File

@ -461,11 +461,11 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
/* We don't know the value of the carry, so the result is
* always unknown.
*/
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
break;
case OP65_AND:
if (In->RegA >= 0) {
if (RegValIsKnown (In->RegA)) {
if (CE_KnownImm (E)) {
Out->RegA = In->RegA & (short) E->Num;
} else if (E->AM == AM65_ZP) {
@ -480,11 +480,11 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegA = In->RegA & In->SRegHi;
break;
default:
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
break;
}
} else {
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
}
}
break;
@ -565,7 +565,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
break;
case OP65_DEA:
if (In->RegA >= 0) {
if (RegValIsKnown (In->RegA)) {
Out->RegA = (In->RegA - 1) & 0xFF;
}
break;
@ -592,19 +592,19 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
break;
case OP65_DEX:
if (In->RegX >= 0) {
if (RegValIsKnown (In->RegX)) {
Out->RegX = (In->RegX - 1) & 0xFF;
}
break;
case OP65_DEY:
if (In->RegY >= 0) {
if (RegValIsKnown (In->RegY)) {
Out->RegY = (In->RegY - 1) & 0xFF;
}
break;
case OP65_EOR:
if (In->RegA >= 0) {
if (RegValIsKnown (In->RegA)) {
if (CE_KnownImm (E)) {
Out->RegA = In->RegA ^ (short) E->Num;
} else if (E->AM == AM65_ZP) {
@ -619,17 +619,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegA = In->RegA ^ In->SRegHi;
break;
default:
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
break;
}
} else {
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
}
}
break;
case OP65_INA:
if (In->RegA >= 0) {
if (RegValIsKnown (In->RegA)) {
Out->RegA = (In->RegA + 1) & 0xFF;
}
break;
@ -656,13 +656,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
break;
case OP65_INX:
if (In->RegX >= 0) {
if (RegValIsKnown (In->RegX)) {
Out->RegX = (In->RegX + 1) & 0xFF;
}
break;
case OP65_INY:
if (In->RegY >= 0) {
if (RegValIsKnown (In->RegY)) {
Out->RegY = (In->RegY + 1) & 0xFF;
}
break;
@ -692,22 +692,22 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
/* Get the code info for the function */
GetFuncInfo (E->Arg, &Use, &Chg);
if (Chg & REG_A) {
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
}
if (Chg & REG_X) {
Out->RegX = -1;
Out->RegX = UNKNOWN_REGVAL;
}
if (Chg & REG_Y) {
Out->RegY = -1;
Out->RegY = UNKNOWN_REGVAL;
}
if (Chg & REG_TMP1) {
Out->Tmp1 = -1;
Out->Tmp1 = UNKNOWN_REGVAL;
}
if (Chg & REG_SREG_LO) {
Out->SRegLo = -1;
Out->SRegLo = UNKNOWN_REGVAL;
}
if (Chg & REG_SREG_HI) {
Out->SRegHi = -1;
Out->SRegHi = UNKNOWN_REGVAL;
}
/* ## FIXME: Quick hack for some known functions: */
if (strcmp (E->Arg, "tosandax") == 0) {
@ -750,12 +750,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegA = In->SRegHi;
break;
default:
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
break;
}
} else {
/* A is now unknown */
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
}
break;
@ -774,12 +774,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegX = In->SRegHi;
break;
default:
Out->RegX = -1;
Out->RegX = UNKNOWN_REGVAL;
break;
}
} else {
/* X is now unknown */
Out->RegX = -1;
Out->RegX = UNKNOWN_REGVAL;
}
break;
@ -798,12 +798,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegY = In->SRegHi;
break;
default:
Out->RegY = -1;
Out->RegY = UNKNOWN_REGVAL;
break;
}
} else {
/* Y is now unknown */
Out->RegY = -1;
Out->RegY = UNKNOWN_REGVAL;
}
break;
@ -832,7 +832,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
break;
case OP65_ORA:
if (In->RegA >= 0) {
if (RegValIsKnown (In->RegA)) {
if (CE_KnownImm (E)) {
Out->RegA = In->RegA | (short) E->Num;
} else if (E->AM == AM65_ZP) {
@ -847,12 +847,12 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
Out->RegA = In->RegA | In->SRegHi;
break;
default:
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
break;
}
} else {
/* A is now unknown */
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
}
}
break;
@ -887,17 +887,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
case OP65_ROL:
/* We don't know the value of the carry bit */
if (E->AM == AM65_ACC) {
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
} else if (E->AM == AM65_ZP) {
switch (GetKnownReg (E->Chg, In)) {
case REG_TMP1:
Out->Tmp1 = -1;
Out->Tmp1 = UNKNOWN_REGVAL;
break;
case REG_SREG_LO:
Out->SRegLo = -1;
Out->SRegLo = UNKNOWN_REGVAL;
break;
case REG_SREG_HI:
Out->SRegHi = -1;
Out->SRegHi = UNKNOWN_REGVAL;
break;
}
} else if (E->AM == AM65_ZPX) {
@ -909,17 +909,17 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
case OP65_ROR:
/* We don't know the value of the carry bit */
if (E->AM == AM65_ACC) {
Out->RegA = -1;
Out->RegA = UNKNOWN_REGVAL;
} else if (E->AM == AM65_ZP) {
switch (GetKnownReg (E->Chg, In)) {
case REG_TMP1:
Out->Tmp1 = -1;
Out->Tmp1 = UNKNOWN_REGVAL;
break;
case REG_SREG_LO:
Out->SRegLo = -1;
Out->SRegLo = UNKNOWN_REGVAL;
break;
case REG_SREG_HI:
Out->SRegHi = -1;
Out->SRegHi = UNKNOWN_REGVAL;
break;
}
} else if (E->AM == AM65_ZPX) {
@ -1052,13 +1052,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
} else {
switch (GetKnownReg (E->Chg, In)) {
case REG_TMP1:
Out->Tmp1 = -1;
Out->Tmp1 = UNKNOWN_REGVAL;
break;
case REG_SREG_LO:
Out->SRegLo = -1;
Out->SRegLo = UNKNOWN_REGVAL;
break;
case REG_SREG_HI:
Out->SRegHi = -1;
Out->SRegHi = UNKNOWN_REGVAL;
break;
}
}
@ -1085,13 +1085,13 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
} else {
switch (GetKnownReg (E->Chg, In)) {
case REG_TMP1:
Out->Tmp1 = -1;
Out->Tmp1 = UNKNOWN_REGVAL;
break;
case REG_SREG_LO:
Out->SRegLo = -1;
Out->SRegLo = UNKNOWN_REGVAL;
break;
case REG_SREG_HI:
Out->SRegHi = -1;
Out->SRegHi = UNKNOWN_REGVAL;
break;
}
}
@ -1099,7 +1099,7 @@ void CE_GenRegInfo (CodeEntry* E, RegContents* InputRegs)
break;
case OP65_TSX:
Out->RegX = -1;
Out->RegX = UNKNOWN_REGVAL;
break;
case OP65_TXA:

View File

@ -132,9 +132,9 @@ static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs)
break;
default:
Internal ("Invalid address flags");
Internal ("Invalid address flags: %04X", Flags);
}
/* Return a pointer to the static buffer */
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)
/* Save register variables */
{

View File

@ -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);
/* Save register variables */

View File

@ -165,6 +165,9 @@ static const FuncInfo FuncInfoTable[] = {
{ "pushw0sp", REG_NONE, REG_AXY },
{ "pushwidx", REG_AXY, REG_AXY | REG_PTR1 },
{ "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 },
{ "shlax2", REG_AX, REG_AX | REG_TMP1 },
{ "shlax3", REG_AX, REG_AX | REG_TMP1 },

View File

@ -1391,19 +1391,22 @@ void CS_GenRegInfo (CodeSeg* S)
break;
}
if (J->RI->Out2.RegA != Regs.RegA) {
Regs.RegA = -1;
Regs.RegA = UNKNOWN_REGVAL;
}
if (J->RI->Out2.RegX != Regs.RegX) {
Regs.RegX = -1;
Regs.RegX = UNKNOWN_REGVAL;
}
if (J->RI->Out2.RegY != Regs.RegY) {
Regs.RegY = -1;
Regs.RegY = UNKNOWN_REGVAL;
}
if (J->RI->Out2.SRegLo != Regs.SRegLo) {
Regs.SRegLo = -1;
Regs.SRegLo = UNKNOWN_REGVAL;
}
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;
}

View File

@ -288,7 +288,7 @@ unsigned OptAdd3 (CodeSeg* S)
*
* jsr pushax
* lda xxx
* ldy yyy
* ldx yyy
* jsr tosaddax
*
* and replace it by

View File

@ -101,7 +101,7 @@ unsigned OptAdd3 (CodeSeg* S);
*
* jsr pushax
* lda xxx
* ldy yyy
* ldx yyy
* jsr tosaddax
*
* and replace it by
@ -113,7 +113,7 @@ unsigned OptAdd3 (CodeSeg* S);
* adc yyy
* tax
* pla
*/
*/
unsigned OptAdd4 (CodeSeg* S);
/* Search for the sequence

View File

@ -34,6 +34,7 @@
#include <stdlib.h>
#include <ctype.h>
/* cc65 */
#include "codeent.h"
@ -66,7 +67,7 @@ struct StackOpData {
/* Flags returned by DirectOp */
#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) {
/* These insns are all ok and replaceable */
D->Flags |= OP_DIRECT;
} else if (E->AM == AM65_ZP_INDY &&
RegValIsKnown (E->RI->In.RegY) &&
(E->Use & REG_SP) != 0) {
/* Load from stack with known offset is also ok */
D->Flags |= (OP_DIRECT | OP_ONSTACK);
} else if (E->AM == AM65_ZP_INDY && RegValIsKnown (E->RI->In.RegY)) {
/* Load indirect with known offset is also ok */
D->Flags |= (OP_DIRECT | OP_RELOAD_Y);
}
}
}
@ -222,7 +221,7 @@ static void ReplacePushByStore (StackOpData* D)
/* 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
* 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;
@ -240,7 +239,7 @@ static void ReplacePushByStore (StackOpData* D)
static void AddOpLow (StackOpData* D, opc_t OPC)
/* 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.
*/
{
@ -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
* 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);
X = NewCodeEntry (OP65_LDY, AM65_IMM, Arg, 0, D->OpEntry->LI);
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 */
/*****************************************************************************/
@ -307,12 +333,20 @@ static unsigned Opt_staspidx (StackOpData* D)
/* Optimize the staspidx sequence if possible */
{
CodeEntry* X;
const char* ZPLo;
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
/* Check if we're using a register variable */
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 */
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);
/* 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 */
{
CodeEntry* X;
const char* ZPLo;
/* Store the value into the zeropage instead of pushing it */
ReplacePushByStore (D);
/* Check if we're using a register variable */
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 */
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);
X = NewCodeEntry (OP65_INY, AM65_IMP, 0, 0, D->OpEntry->LI);
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);
}
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);
/* Remove the push and the call to the staspidx function */
@ -607,7 +649,7 @@ static int HarmlessCall (const char* Name)
*/
{
static const char* Tab[] = {
"ldaxidx",
"ldaxidx",
"ldaxysp",
};

View File

@ -83,7 +83,7 @@ static type OptionalQualifiers (type Q)
switch (CurTok.Tok) {
case TOK_CONST:
if (Q & T_QUAL_CONST) {
if (Q & T_QUAL_CONST) {
Error ("Duplicate qualifier: `const'");
}
Q |= T_QUAL_CONST;
@ -339,7 +339,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
ident Ident;
SymEntry* Entry;
type StructType;
type Qualifiers; /* Type qualifiers */
type Qualifiers; /* Type qualifiers */
/* Assume we have an explicit type */
D->Flags &= ~DS_DEF_TYPE;
@ -427,7 +427,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
/* FALL THROUGH */
default:
D->Type[0] = T_INT;
D->Type[0] = T_INT;
D->Type[1] = T_END;
break;
}
@ -663,14 +663,15 @@ static void ParseAnsiParamList (FuncDesc* F)
/* Read the declaration specifier */
ParseDeclSpec (&Spec, SC_AUTO, T_INT);
/* We accept only auto and register as storage class specifiers, but
* we ignore all this and use auto.
*/
if ((Spec.StorageClass & SC_AUTO) == 0 &&
(Spec.StorageClass & SC_REGISTER) == 0) {
/* We accept only auto and register as storage class specifiers */
if ((Spec.StorageClass & SC_AUTO) == SC_AUTO) {
Spec.StorageClass = SC_AUTO | SC_PARAM | SC_DEF;
} else if ((Spec.StorageClass & SC_REGISTER) == SC_REGISTER) {
Spec.StorageClass = SC_REGISTER | SC_STATIC | SC_PARAM | SC_DEF;
} else {
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
* 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 */
if ((Spec->Flags & DS_DEF_TYPE) != 0 &&
Spec->Type[0] == T_INT &&
Spec->Type[1] == T_END) {
/* Function has an implicit int return */
F->Flags |= FD_OLDSTYLE_INTRET;
Spec->Type[0] == T_INT &&
Spec->Type[1] == T_END) {
/* Function has an implicit int return */
F->Flags |= FD_OLDSTYLE_INTRET;
}
}
}
@ -779,7 +780,11 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
Sym = GetSymTab()->SymTail;
while (Sym) {
unsigned Size = CheckedSizeOf (Sym->Type);
Sym->V.Offs = Offs;
if (SymIsRegVar (Sym)) {
Sym->V.R.SaveOffs = Offs;
} else {
Sym->V.Offs = Offs;
}
Offs += Size;
F->ParamSize += Size;
Sym = Sym->PrevSym;

View File

@ -6,7 +6,7 @@
/* */
/* */
/* */
/* (C) 2000-2001 Ullrich von Bassewitz */
/* (C) 2000-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* 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 */
struct Function {
struct SymEntry* FuncEntry; /* Symbol table entry */
type* ReturnType; /* Function return type */
struct FuncDesc* Desc; /* Function descriptor */
int Reserved; /* Reserved local space */
struct SymEntry* FuncEntry; /* Symbol table entry */
type* ReturnType; /* Function return type */
struct FuncDesc* Desc; /* Function descriptor */
int Reserved; /* Reserved local space */
unsigned RetLab; /* Return code label */
int TopLevelSP; /* SP at function top level */
unsigned RegOffs; /* Register variable space offset */
};
/* Pointer to current function */
@ -94,6 +98,7 @@ static Function* NewFunction (struct SymEntry* Sym)
F->Reserved = 0;
F->RetLab = GetLocalLabel ();
F->TopLevelSP = 0;
F->RegOffs = MAX_REG_SPACE;
/* Return the new structure */
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 */
/*****************************************************************************/
@ -230,8 +337,8 @@ void NewFunc (SymEntry* Func)
/* Parse argument declarations and function body. */
{
int HadReturn;
int IsVoidFunc;
SymEntry* LastParam;
SymEntry* Param;
/* Get the function descriptor from the function entry */
FuncDesc* D = Func->V.F.Func;
@ -262,9 +369,6 @@ void NewFunc (SymEntry* Func)
/* Function body now defined */
Func->Flags |= SC_DEF;
/* Setup register variables */
InitRegVars ();
/* Allocate code and data segments for this function */
Func->V.F.Seg = PushSegments (Func);
@ -281,19 +385,50 @@ void NewFunc (SymEntry* Func)
/* Pointer to function */
Flags = CF_PTR;
} else {
Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
}
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 */
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 */
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 */
g_defcodelabel (F_GetRetLab (CurrentFunc));
/* Restore the register variables */
RestoreRegVars (!IsVoidFunc);
F_RestoreRegVars (CurrentFunc);
/* Generate the exit code */
g_leave ();
@ -344,9 +468,6 @@ void NewFunc (SymEntry* Func)
/* Emit references to imports/exports */
EmitExternals ();
/* Cleanup register variables */
DoneRegVars ();
/* Leave the lexical level */
LeaveFunctionLevel ();

View File

@ -98,6 +98,12 @@ void F_AllocLocalSpace (Function* F);
* 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);
/* Parse argument declarations and function body. */

View File

@ -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 */
/*****************************************************************************/
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)
/* Parse the declaration of a register variable. The function returns the
* 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 {
/* Setup the type flags for the assignment */
Flags = CF_REGVAR;
Flags = CF_NONE;
if (Size == SIZEOF_CHAR) {
Flags |= CF_FORCECHAR;
}
@ -195,12 +114,15 @@ static unsigned ParseRegisterDecl (Declaration* Decl, unsigned* SC, int Reg)
/* Constant expression. Adjust the types */
assignadjust (Decl->Type, &lval);
Flags |= CF_CONST;
/* Load it into the primary */
exprhs (Flags, 0, &lval);
} else {
/* Expression is not constant and in the primary */
assignadjust (Decl->Type, &lval);
}
/* Store the value into the variable */
Flags |= CF_REGVAR;
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 SymData = 0; /* Symbol data (offset, label name, ...) */
Declaration Decl; /* Declaration data structure */
SymEntry* Sym; /* Symbol declared */
/* 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 */
if (IsTypeFunc (Decl.Type)) {
/* Function prototypes are always external */
if ((SC & SC_EXTERN) == 0) {
/* Function prototypes are always external */
if ((SC & SC_EXTERN) == 0) {
Warning ("Function must be 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.
*/
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 */
SC = (SC & ~SC_REGISTER) | SC_AUTO;
}
/* Check the variable type */
if (SC & SC_REGISTER) {
if ((SC & SC_REGISTER) == SC_REGISTER) {
/* Register variable */
SymData = ParseRegisterDecl (&Decl, &SC, Reg);
} else if (SC & SC_AUTO) {
} else if ((SC & SC_AUTO) == SC_AUTO) {
/* Auto variable */
SymData = ParseAutoDecl (&Decl, &SC);
} else if (SC & SC_STATIC) {
} else if ((SC & SC_STATIC) == SC_STATIC) {
/* Static variable */
SymData = ParseStaticDecl (&Decl, &SC);
} else {
@ -515,12 +436,7 @@ static void ParseOneDecl (const DeclSpec* Spec)
}
/* Add the symbol to the symbol table */
Sym = AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
/* If we had declared a register variable, remember it now */
if (SC & SC_REGISTER) {
RememberRegVar (Sym);
}
AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
}
@ -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);
}
}

View File

@ -50,12 +50,12 @@
void RC_Invalidate (RegContents* C)
/* Invalidate all registers */
{
C->RegA = -1;
C->RegX = -1;
C->RegY = -1;
C->SRegLo = -1;
C->SRegHi = -1;
C->Tmp1 = -1;
C->RegA = UNKNOWN_REGVAL;
C->RegX = UNKNOWN_REGVAL;
C->RegY = UNKNOWN_REGVAL;
C->SRegLo = UNKNOWN_REGVAL;
C->SRegHi = UNKNOWN_REGVAL;
C->Tmp1 = UNKNOWN_REGVAL;
}
@ -63,9 +63,9 @@ void RC_Invalidate (RegContents* C)
void RC_InvalidateZP (RegContents* C)
/* Invalidate all ZP registers */
{
C->SRegLo = -1;
C->SRegHi = -1;
C->Tmp1 = -1;
C->SRegLo = UNKNOWN_REGVAL;
C->SRegHi = UNKNOWN_REGVAL;
C->Tmp1 = UNKNOWN_REGVAL;
}
@ -104,4 +104,4 @@ void FreeRegInfo (RegInfo* RI)

View File

@ -49,6 +49,9 @@
/* Encoding for an unknown register value */
#define UNKNOWN_REGVAL -1
/* Register contents */
typedef struct RegContents RegContents;
struct RegContents {

View File

@ -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)
/* Change the type of the given symbol */
{

View File

@ -186,6 +186,19 @@ INLINE int SymIsRef (const SymEntry* Sym)
# define SymIsRef(Sym) (((Sym)->Flags & SC_REF) == SC_REF)
#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);
/* Change the type of the given symbol */

View File

@ -81,9 +81,6 @@ SymTable EmptySymTab = {
#define SYMTAB_SIZE_STRUCT 19U
#define SYMTAB_SIZE_LABEL 7U
/* Predefined lexical levels */
#define LEX_LEVEL_GLOBAL 1U
/* The current and root symbol tables */
static unsigned LexicalLevel = 0; /* For safety checks */
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)
/* Enter the program global lexical level */
{
@ -241,7 +246,7 @@ void EnterFunctionLevel (void)
SymTable* S;
/* New lexical level */
++LexicalLevel;
PRECONDITION (++LexicalLevel == LEX_LEVEL_FUNCTION);
/* Get a new symbol table and make it current */
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 */
{
/* Leave the lexical level */
--LexicalLevel;
PRECONDITION (LexicalLevel-- == LEX_LEVEL_FUNCTION);
/* Remember the tables */
F->SymTab = SymTab;
@ -280,7 +285,7 @@ void ReenterFunctionLevel (struct FuncDesc* F)
/* Reenter the function lexical level using the existing tables from F */
{
/* New lexical level */
++LexicalLevel;
PRECONDITION (++LexicalLevel == LEX_LEVEL_FUNCTION);
/* Make the tables current again */
F->SymTab->PrevTab = SymTab;
@ -299,7 +304,7 @@ void LeaveFunctionLevel (void)
/* Leave function lexical level */
{
/* Leave the lexical level */
--LexicalLevel;
PRECONDITION (LexicalLevel-- == LEX_LEVEL_FUNCTION);
/* Check the tables */
CheckSymTable (SymTab);

View File

@ -68,6 +68,10 @@ extern SymTable EmptySymTab;
/* Forwards */
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);
/* Enter the program global lexical level */