/* 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) {
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;
break;
case OP65_DEA:
- if (In->RegA >= 0) {
+ if (RegValIsKnown (In->RegA)) {
Out->RegA = (In->RegA - 1) & 0xFF;
}
break;
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) {
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;
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;
/* 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) {
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;
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;
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;
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) {
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;
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) {
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) {
} 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;
}
}
} 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;
}
}
break;
case OP65_TSX:
- Out->RegX = -1;
+ Out->RegX = UNKNOWN_REGVAL;
break;
case OP65_TXA:
break;
default:
- Internal ("Invalid address flags");
+ Internal ("Invalid address flags: %04X", Flags);
}
-
+
/* Return a pointer to the static buffer */
return Buf;
}
/*****************************************************************************/
-/* 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 */
{
+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 */
{ "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 },
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;
}
*
* jsr pushax
* lda xxx
- * ldy yyy
+ * ldx yyy
* jsr tosaddax
*
* and replace it by
*
* jsr pushax
* lda xxx
- * ldy yyy
+ * ldx yyy
* jsr tosaddax
*
* and replace it by
* adc yyy
* tax
* pla
- */
+ */
unsigned OptAdd4 (CodeSeg* S);
/* Search for the sequence
#include <stdlib.h>
+#include <ctype.h>
/* cc65 */
#include "codeent.h"
/* 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 */
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);
}
}
}
/* 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;
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.
*/
{
/* 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++);
+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 */
/*****************************************************************************/
/* 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 */
/* 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);
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 */
*/
{
static const char* Tab[] = {
- "ldaxidx",
+ "ldaxidx",
"ldaxysp",
};
switch (CurTok.Tok) {
case TOK_CONST:
- if (Q & T_QUAL_CONST) {
+ if (Q & T_QUAL_CONST) {
Error ("Duplicate qualifier: `const'");
}
Q |= T_QUAL_CONST;
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;
/* FALL THROUGH */
default:
- D->Type[0] = T_INT;
+ D->Type[0] = T_INT;
D->Type[1] = T_END;
break;
}
/* 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.
/* 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;
}
}
}
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;
/* */
/* */
/* */
-/* (C) 2000-2001 Ullrich von Bassewitz */
+/* (C) 2000-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@cc65.org */
+/* 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 */
F->Reserved = 0;
F->RetLab = GetLocalLabel ();
F->TopLevelSP = 0;
+ F->RegOffs = MAX_REG_SPACE;
/* Return the new structure */
return 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 */
/*****************************************************************************/
/* 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;
/* 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);
/* Pointer to function */
Flags = CF_PTR;
} else {
- Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
+ Flags = TypeOf (LastParam->Type) | CF_FORCECHAR;
}
g_push (Flags, 0);
}
+ /* 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 ();
+ g_stackcheck ();
}
- /* Generate function entry code if needed */
- g_enter (TypeOf (Func->Type), F_GetParamSize (CurrentFunc));
+ /* 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;
}
}
- /* 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 ();
/* Emit references to imports/exports */
EmitExternals ();
- /* Cleanup register variables */
- DoneRegVars ();
-
/* Leave the lexical level */
LeaveFunctionLevel ();
* 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. */
-/*****************************************************************************/
-/* 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.
} else {
/* Setup the type flags for the assignment */
- Flags = CF_REGVAR;
+ Flags = CF_NONE;
if (Size == SIZEOF_CHAR) {
Flags |= CF_FORCECHAR;
}
/* 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);
}
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 */
/* 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;
}
* 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 {
}
/* 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);
}
-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);
- }
-}
-
-
-
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;
}
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;
}
-
+
+/* Encoding for an unknown register value */
+#define UNKNOWN_REGVAL -1
+
/* Register contents */
typedef struct RegContents RegContents;
struct RegContents {
+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 */
{
# 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 */
#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;
+unsigned GetLexicalLevel (void)
+/* Return the current lexical level */
+{
+ return LexicalLevel;
+}
+
+
+
void EnterGlobalLevel (void)
/* Enter the program global lexical level */
{
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);
/* 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;
/* 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;
/* Leave function lexical level */
{
/* Leave the lexical level */
- --LexicalLevel;
+ PRECONDITION (LexicalLevel-- == LEX_LEVEL_FUNCTION);
/* Check the tables */
CheckSymTable (SymTab);
/* Forwards */
struct FuncDesc;
+/* Predefined lexical levels */
+#define LEX_LEVEL_GLOBAL 1U
+#define LEX_LEVEL_FUNCTION 2U
+
/*****************************************************************************/
+unsigned GetLexicalLevel (void);
+/* Return the current lexical level */
+
void EnterGlobalLevel (void);
/* Enter the program global lexical level */