mirror of
https://github.com/cc65/cc65.git
synced 2024-12-23 04:30:10 +00:00
Reenable register variables
git-svn-id: svn://svn.cc65.org/cc65/trunk@1625 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
parent
b6898c3f1e
commit
ede471904c
@ -72,7 +72,7 @@ void MoveCode (CodeMark Start, CodeMark End, CodeMark Target)
|
||||
/* Move the code between Start (inclusive) and End (exclusive) to
|
||||
* (before) Target.
|
||||
*/
|
||||
{
|
||||
{
|
||||
CS_MoveEntries (CS->Code, Start, End - Start, Target);
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ void WriteOutput (FILE* F)
|
||||
Entry = SymTab->SymHead;
|
||||
while (Entry) {
|
||||
if (IsTypeFunc (Entry->Type) &&
|
||||
(Entry->Flags & SC_DEF) != 0 &&
|
||||
SymIsDef (Entry) &&
|
||||
(Entry->Flags & (SC_REF | SC_EXTERN)) != 0) {
|
||||
/* Function which is defined and referenced or extern */
|
||||
CS_MergeLabels (Entry->V.F.Seg->Code);
|
||||
|
@ -134,7 +134,7 @@ static const char* GetLabelName (unsigned Flags, unsigned long Label, long Offs)
|
||||
default:
|
||||
Internal ("Invalid address flags");
|
||||
}
|
||||
|
||||
|
||||
/* Return a pointer to the static buffer */
|
||||
return Buf;
|
||||
}
|
||||
@ -3981,6 +3981,21 @@ void g_zerobytes (unsigned n)
|
||||
|
||||
|
||||
|
||||
void g_initregister (unsigned Label, unsigned Reg, unsigned Size)
|
||||
/* Initialize a register variable from static initialization data */
|
||||
{
|
||||
/* Register variables do always have less than 128 bytes */
|
||||
unsigned CodeLabel = GetLocalLabel ();
|
||||
ldxconst (Size-1);
|
||||
g_defcodelabel (CodeLabel);
|
||||
AddCodeLine ("lda %s,x", GetLabelName (CF_STATIC, Label, 0));
|
||||
AddCodeLine ("sta %s,x", GetLabelName (CF_REGVAR, Reg, 0));
|
||||
AddCodeLine ("dex");
|
||||
AddCodeLine ("bpl %s", LocalLabelName (CodeLabel));
|
||||
}
|
||||
|
||||
|
||||
|
||||
void g_initauto (unsigned Label, unsigned Size)
|
||||
/* Initialize a local variable at stack offset zero from static data */
|
||||
{
|
||||
|
@ -432,6 +432,9 @@ void g_defbytes (const void* bytes, unsigned count);
|
||||
void g_zerobytes (unsigned n);
|
||||
/* Output n bytes of data initialized with zero */
|
||||
|
||||
void g_initregister (unsigned Label, unsigned Reg, unsigned Size);
|
||||
/* Initialize a register variable from static initialization data */
|
||||
|
||||
void g_initauto (unsigned Label, unsigned Size);
|
||||
/* Initialize a local variable at stack offset zero from static data */
|
||||
|
||||
|
@ -1391,7 +1391,8 @@ static OptFunc DOpt65C02Ind = { Opt65C02Ind, "Opt65C02Ind", 100, 0,
|
||||
static OptFunc DOpt65C02Stores = { Opt65C02Stores, "Opt65C02Stores", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptAdd1 = { OptAdd1, "OptAdd1", 125, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptAdd2 = { OptAdd2, "OptAdd2", 200, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 40, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptAdd3 = { OptAdd3, "OptAdd3", 90, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptAdd4 = { OptAdd4, "OptAdd4", 40, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptBoolTrans = { OptBoolTrans, "OptBoolTrans", 100, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptBranchDist = { OptBranchDist, "OptBranchDist", 0, 0, 0, 0, 0, 0 };
|
||||
static OptFunc DOptCmp1 = { OptCmp1, "OptCmp1", 85, 0, 0, 0, 0, 0 };
|
||||
@ -1454,6 +1455,7 @@ static OptFunc* OptFuncs[] = {
|
||||
&DOptAdd1,
|
||||
&DOptAdd2,
|
||||
&DOptAdd3,
|
||||
&DOptAdd4,
|
||||
&DOptBoolTrans,
|
||||
&DOptBranchDist,
|
||||
&DOptCmp1,
|
||||
@ -1752,6 +1754,7 @@ static unsigned RunOptGroup1 (CodeSeg* S)
|
||||
Changes += RunOptFunc (S, &DOptNegAX4, 1);
|
||||
Changes += RunOptFunc (S, &DOptAdd1, 1);
|
||||
Changes += RunOptFunc (S, &DOptAdd2, 1);
|
||||
Changes += RunOptFunc (S, &DOptAdd3, 1);
|
||||
Changes += RunOptFunc (S, &DOptShift1, 1);
|
||||
Changes += RunOptFunc (S, &DOptShift2, 1);
|
||||
Changes += RunOptFunc (S, &DOptShift3, 1);
|
||||
|
@ -231,16 +231,16 @@ static void Parse (void)
|
||||
|
||||
/* Function */
|
||||
if (!comma) {
|
||||
|
||||
if (CurTok.Tok == TOK_SEMI) {
|
||||
|
||||
/* Prototype only */
|
||||
NextToken ();
|
||||
|
||||
} else {
|
||||
if (Entry) {
|
||||
NewFunc (Entry);
|
||||
}
|
||||
} else if (Entry) {
|
||||
/* Function body definition */
|
||||
if (SymIsDef (Entry)) {
|
||||
Error ("Body for function `%s' has already been defined",
|
||||
Entry->Name);
|
||||
}
|
||||
NewFunc (Entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,6 +284,95 @@ unsigned OptAdd2 (CodeSeg* S)
|
||||
|
||||
|
||||
unsigned OptAdd3 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* lda xxx
|
||||
* ldy yyy
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
*/
|
||||
{
|
||||
unsigned Changes = 0;
|
||||
|
||||
/* Walk over the entries */
|
||||
unsigned I = 0;
|
||||
while (I < CS_GetEntryCount (S)) {
|
||||
|
||||
CodeEntry* L[4];
|
||||
|
||||
/* Get next entry */
|
||||
L[0] = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (CE_IsCallTo (L[0], "pushax") &&
|
||||
CS_GetEntries (S, L+1, I+1, 3) &&
|
||||
!CS_RangeHasLabel (S, I+1, 3) &&
|
||||
L[1]->OPC == OP65_LDA &&
|
||||
(L[1]->AM == AM65_ABS || L[1]->AM == AM65_ZP) &&
|
||||
L[2]->OPC == OP65_LDX &&
|
||||
(L[2]->AM == AM65_ABS || L[2]->AM == AM65_ZP) &&
|
||||
CE_IsCallTo (L[3], "tosaddax")) {
|
||||
|
||||
CodeEntry* X;
|
||||
|
||||
/* Insert new code behind the sequence */
|
||||
X = NewCodeEntry (OP65_CLC, AM65_IMP, 0, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+4);
|
||||
|
||||
/* adc xxx */
|
||||
X = NewCodeEntry (OP65_ADC, L[1]->AM, L[1]->Arg, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+5);
|
||||
|
||||
/* pha */
|
||||
X = NewCodeEntry (OP65_PHA, AM65_IMP, 0, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+6);
|
||||
|
||||
/* txa */
|
||||
X = NewCodeEntry (OP65_TXA, AM65_IMP, 0, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+7);
|
||||
|
||||
/* adc yyy */
|
||||
X = NewCodeEntry (OP65_ADC, L[2]->AM, L[2]->Arg, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+8);
|
||||
|
||||
/* tax */
|
||||
X = NewCodeEntry (OP65_TAX, AM65_IMP, 0, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+9);
|
||||
|
||||
/* pla */
|
||||
X = NewCodeEntry (OP65_PLA, AM65_IMP, 0, 0, L[3]->LI);
|
||||
CS_InsertEntry (S, X, I+10);
|
||||
|
||||
/* Delete the old code */
|
||||
CS_DelEntries (S, I, 4);
|
||||
|
||||
/* Remember, we had changes */
|
||||
++Changes;
|
||||
|
||||
}
|
||||
|
||||
/* Next entry */
|
||||
++I;
|
||||
|
||||
}
|
||||
|
||||
/* Return the number of changes made */
|
||||
return Changes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
unsigned OptAdd4 (CodeSeg* S)
|
||||
/* Search for the sequence
|
||||
*
|
||||
* adc ...
|
||||
@ -306,7 +395,7 @@ unsigned OptAdd3 (CodeSeg* S)
|
||||
CodeEntry* E = CS_GetEntry (S, I);
|
||||
|
||||
/* Check for the sequence */
|
||||
if (E->OPC == OP65_ADC &&
|
||||
if (E->OPC == OP65_ADC &&
|
||||
CS_GetEntries (S, L, I+1, 3) &&
|
||||
(L[0]->OPC == OP65_BCC || L[0]->OPC == OP65_JCC) &&
|
||||
L[0]->JumpTo != 0 &&
|
||||
@ -335,4 +424,3 @@ unsigned OptAdd3 (CodeSeg* S)
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/* (C) 2001 Ullrich von Bassewitz */
|
||||
/* (C) 2001-2002 Ullrich von Bassewitz */
|
||||
/* Wacholderweg 14 */
|
||||
/* D-70597 Stuttgart */
|
||||
/* EMail: uz@cc65.org */
|
||||
@ -97,6 +97,25 @@ unsigned OptAdd2 (CodeSeg* S);
|
||||
*/
|
||||
|
||||
unsigned OptAdd3 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* jsr pushax
|
||||
* lda xxx
|
||||
* ldy yyy
|
||||
* jsr tosaddax
|
||||
*
|
||||
* and replace it by
|
||||
*
|
||||
* clc
|
||||
* adc xxx
|
||||
* pha
|
||||
* txa
|
||||
* adc yyy
|
||||
* tax
|
||||
* pla
|
||||
*/
|
||||
|
||||
unsigned OptAdd4 (CodeSeg* S);
|
||||
/* Search for the sequence
|
||||
*
|
||||
* adc ...
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
/* common */
|
||||
#include "attrib.h"
|
||||
#include "inline.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "funcdesc.h"
|
||||
|
@ -297,8 +297,11 @@ static SymEntry* ParseStructDecl (const char* Name, type StructType)
|
||||
Declaration Decl;
|
||||
ParseDecl (&Spec, &Decl, 0);
|
||||
|
||||
/* Get the offset of this field */
|
||||
Offs = (StructType == T_STRUCT)? Size : 0;
|
||||
|
||||
/* Add a field entry to the table */
|
||||
AddLocalSym (Decl.Ident, Decl.Type, SC_SFLD, (StructType == T_STRUCT)? Size : 0);
|
||||
AddLocalSym (Decl.Ident, Decl.Type, SC_STRUCTFIELD, Offs);
|
||||
|
||||
/* Calculate offset of next field/size of the union */
|
||||
Offs = CheckedSizeOf (Decl.Type);
|
||||
@ -516,7 +519,7 @@ static void ParseTypeSpec (DeclSpec* D, int Default)
|
||||
|
||||
case TOK_IDENT:
|
||||
Entry = FindSym (CurTok.Ident);
|
||||
if (Entry && IsTypeDef (Entry)) {
|
||||
if (Entry && SymIsTypeDef (Entry)) {
|
||||
/* It's a typedef */
|
||||
NextToken ();
|
||||
TypeCpy (D->Type, Entry->Type);
|
||||
@ -746,7 +749,7 @@ static FuncDesc* ParseFuncDecl (const DeclSpec* Spec)
|
||||
* if it's some other identifier, it's an old style parameter list.
|
||||
*/
|
||||
Sym = FindSym (CurTok.Ident);
|
||||
if (Sym == 0 || !IsTypeDef (Sym)) {
|
||||
if (Sym == 0 || !SymIsTypeDef (Sym)) {
|
||||
/* Old style (K&R) function. Assume variable param list. */
|
||||
F->Flags |= (FD_OLDSTYLE | FD_VARIADIC);
|
||||
|
||||
|
@ -183,7 +183,7 @@ static unsigned typeadjust (ExprDesc* lhs, ExprDesc* rhs, int NoPush)
|
||||
}
|
||||
flags = g_typeadjust (ltype, rtype);
|
||||
|
||||
/* Set the type of the result */
|
||||
/* Set the type of the result */
|
||||
lhs->Type = promoteint (lhst, rhst);
|
||||
|
||||
/* Return the code generator flags */
|
||||
@ -437,7 +437,7 @@ static int istypeexpr (void)
|
||||
(NextTok.Tok == TOK_CONST) ||
|
||||
(NextTok.Tok == TOK_IDENT &&
|
||||
(Entry = FindSym (NextTok.Ident)) != 0 &&
|
||||
IsTypeDef (Entry)));
|
||||
SymIsTypeDef (Entry)));
|
||||
}
|
||||
|
||||
|
||||
@ -941,7 +941,7 @@ static int primary (ExprDesc* lval)
|
||||
} else if ((Sym->Flags & SC_REGISTER) == SC_REGISTER) {
|
||||
/* Register variable, zero page based */
|
||||
lval->Flags = E_MGLOBAL | E_MCONST | E_TREGISTER;
|
||||
lval->Name = Sym->V.Offs;
|
||||
lval->Name = Sym->V.R.RegOffs;
|
||||
lval->ConstVal = 0;
|
||||
} else if ((Sym->Flags & SC_STATIC) == SC_STATIC) {
|
||||
/* Static variable */
|
||||
|
@ -101,28 +101,25 @@ void DoneRegVars (void)
|
||||
|
||||
|
||||
|
||||
static int AllocRegVar (const SymEntry* Sym, const type* tarray)
|
||||
/* Allocate a register variable with the given amount of storage. 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.
|
||||
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 (tarray);
|
||||
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;
|
||||
RegSyms [RegSymCount++] = Sym;
|
||||
return RegOffs;
|
||||
}
|
||||
}
|
||||
@ -133,6 +130,96 @@ static int AllocRegVar (const SymEntry* Sym, const type* tarray)
|
||||
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
{
|
||||
unsigned Flags;
|
||||
unsigned InitLabel;
|
||||
|
||||
/* Determine if this is a compound variable */
|
||||
int IsCompound = IsClassStruct (Decl->Type) || IsTypeArray (Decl->Type);
|
||||
|
||||
/* Get the size of the variable */
|
||||
unsigned Size = SizeOf (Decl->Type);
|
||||
|
||||
/* Save the current contents of the register variable on stack */
|
||||
F_AllocLocalSpace (CurrentFunc);
|
||||
g_save_regvars (Reg, Size);
|
||||
|
||||
/* Check for an optional initialization */
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
ExprDesc lval;
|
||||
|
||||
/* Skip the '=' */
|
||||
NextToken ();
|
||||
|
||||
/* Special handling for compound types */
|
||||
if (IsCompound) {
|
||||
|
||||
/* Switch to read only data */
|
||||
g_userodata ();
|
||||
|
||||
/* Define a label for the initialization data */
|
||||
InitLabel = GetLocalLabel ();
|
||||
g_defdatalabel (InitLabel);
|
||||
|
||||
/* Parse the initialization generating a memory image of the
|
||||
* data in the RODATA segment.
|
||||
*/
|
||||
ParseInit (Decl->Type);
|
||||
|
||||
/* Generate code to copy this data into the variable space */
|
||||
g_initregister (InitLabel, Reg, Size);
|
||||
|
||||
} else {
|
||||
|
||||
/* Setup the type flags for the assignment */
|
||||
Flags = CF_REGVAR;
|
||||
if (Size == SIZEOF_CHAR) {
|
||||
Flags |= CF_FORCECHAR;
|
||||
}
|
||||
|
||||
/* Get the expression into the primary */
|
||||
if (evalexpr (Flags, hie1, &lval) == 0) {
|
||||
/* Constant expression. Adjust the types */
|
||||
assignadjust (Decl->Type, &lval);
|
||||
Flags |= CF_CONST;
|
||||
} else {
|
||||
/* Expression is not constant and in the primary */
|
||||
assignadjust (Decl->Type, &lval);
|
||||
}
|
||||
|
||||
/* Store the value into the variable */
|
||||
g_putstatic (Flags | TypeOf (Decl->Type), Reg, 0);
|
||||
|
||||
}
|
||||
|
||||
/* Mark the variable as referenced */
|
||||
*SC |= SC_REF;
|
||||
}
|
||||
|
||||
/* Cannot allocate a variable of zero size */
|
||||
if (Size == 0) {
|
||||
Error ("Variable `%s' has unknown size", Decl->Ident);
|
||||
}
|
||||
|
||||
/* Return the symbol data */
|
||||
return Reg;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
||||
/* Parse the declaration of an auto variable. The function returns the symbol
|
||||
* data, which is the offset for variables on the stack, and the label for
|
||||
@ -152,8 +239,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
||||
/* Check if this is a variable on the stack or in static memory */
|
||||
if (StaticLocals == 0) {
|
||||
|
||||
/* Change SC in case it was register */
|
||||
*SC = (*SC & ~SC_REGISTER) | SC_AUTO;
|
||||
/* Check for an optional initialization */
|
||||
if (CurTok.Tok == TOK_ASSIGN) {
|
||||
|
||||
ExprDesc lval;
|
||||
@ -226,7 +312,7 @@ static unsigned ParseAutoDecl (Declaration* Decl, unsigned* SC)
|
||||
} else {
|
||||
|
||||
/* Static local variables. */
|
||||
*SC = (*SC & ~(SC_REGISTER | SC_AUTO)) | SC_STATIC;
|
||||
*SC = (*SC & ~SC_AUTO) | SC_STATIC;
|
||||
|
||||
/* Put them into the BSS */
|
||||
g_usebss ();
|
||||
@ -369,7 +455,9 @@ 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 */
|
||||
Declaration Decl; /* Declaration data structure */
|
||||
SymEntry* Sym; /* Symbol declared */
|
||||
|
||||
|
||||
/* Remember the storage class for the new symbol */
|
||||
SC = Spec->StorageClass;
|
||||
@ -391,33 +479,48 @@ static void ParseOneDecl (const DeclSpec* Spec)
|
||||
* To avoid problems later, use an anonymous name here.
|
||||
*/
|
||||
if (Decl.Ident[0] == '\0') {
|
||||
AnonName (Decl.Ident, "param");
|
||||
AnonName (Decl.Ident, "param");
|
||||
}
|
||||
|
||||
/* Handle anything that needs storage (no functions, no typdefs) */
|
||||
if ((SC & SC_FUNC) != SC_FUNC && (SC & SC_TYPEDEF) != SC_TYPEDEF) {
|
||||
|
||||
/* */
|
||||
if (SC & (SC_AUTO | SC_REGISTER)) {
|
||||
/* If we have a register variable, try to allocate a register and
|
||||
* 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) {
|
||||
/* No space for this register variable, convert to auto */
|
||||
SC = (SC & ~SC_REGISTER) | SC_AUTO;
|
||||
}
|
||||
|
||||
/* Check the variable type */
|
||||
if (SC & SC_REGISTER) {
|
||||
/* Register variable */
|
||||
SymData = ParseRegisterDecl (&Decl, &SC, Reg);
|
||||
} else if (SC & SC_AUTO) {
|
||||
/* Auto variable */
|
||||
SymData = ParseAutoDecl (&Decl, &SC);
|
||||
|
||||
} else if ((SC & SC_STATIC) == SC_STATIC) {
|
||||
|
||||
} else if (SC & SC_STATIC) {
|
||||
/* Static variable */
|
||||
SymData = ParseStaticDecl (&Decl, &SC);
|
||||
|
||||
}
|
||||
} else {
|
||||
Internal ("Invalid storage class in ParseOneDecl: %04X", SC);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the symbol is not marked as external, it will be defined */
|
||||
/* If the symbol is not marked as external, it will be defined now */
|
||||
if ((SC & SC_EXTERN) == 0) {
|
||||
SC |= SC_DEF;
|
||||
SC |= SC_DEF;
|
||||
}
|
||||
|
||||
/* Add the symbol to the symbol table */
|
||||
AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
|
||||
Sym = AddLocalSym (Decl.Ident, Decl.Type, SC, SymData);
|
||||
|
||||
/* If we had declared a register variable, remember it now */
|
||||
if (SC & SC_REGISTER) {
|
||||
RememberRegVar (Sym);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -510,8 +613,8 @@ void RestoreRegVars (int HaveResult)
|
||||
while (I < RegSymCount) {
|
||||
|
||||
/* Check for more than one variable */
|
||||
const SymEntry* Sym = RegSyms[I];
|
||||
Offs = Sym->V.Offs;
|
||||
const SymEntry* Sym = RegSyms[I];
|
||||
Offs = Sym->V.R.SaveOffs;
|
||||
Bytes = CheckedSizeOf (Sym->Type);
|
||||
J = I+1;
|
||||
|
||||
@ -524,7 +627,7 @@ void RestoreRegVars (int HaveResult)
|
||||
int Size = CheckedSizeOf (NextSym->Type);
|
||||
|
||||
/* Adjacent variable? */
|
||||
if (NextSym->V.Offs + Size != Offs) {
|
||||
if (NextSym->V.R.SaveOffs + Size != Offs) {
|
||||
/* No */
|
||||
break;
|
||||
}
|
||||
@ -537,7 +640,7 @@ void RestoreRegVars (int HaveResult)
|
||||
}
|
||||
|
||||
/* Restore the memory range */
|
||||
g_restore_regvars (Offs, Sym->V.Offs, Bytes);
|
||||
g_restore_regvars (Offs, Sym->V.R.RegOffs, Bytes);
|
||||
|
||||
/* Next round */
|
||||
I = J;
|
||||
|
@ -91,6 +91,7 @@ static void Usage (void)
|
||||
" -h\t\t\tHelp (this text)\n"
|
||||
" -j\t\t\tDefault characters are signed\n"
|
||||
" -o name\t\tName the output file\n"
|
||||
" -r\t\t\tEnable register variables\n"
|
||||
" -t sys\t\tSet the target system\n"
|
||||
" -v\t\t\tIncrease verbosity\n"
|
||||
"\n"
|
||||
@ -112,6 +113,7 @@ static void Usage (void)
|
||||
" --help\t\tHelp (this text)\n"
|
||||
" --include-dir dir\tSet an include directory search path\n"
|
||||
" --list-opt-steps\tList all optimizer steps and exit\n"
|
||||
" --register-vars\tEnable register variables\n"
|
||||
" --rodata-name seg\tSet the name of the RODATA segment\n"
|
||||
" --signed-chars\tDefault characters are signed\n"
|
||||
" --static-locals\tMake local variables static\n"
|
||||
@ -528,6 +530,15 @@ static void OptListOptSteps (const char* Opt attribute ((unused)),
|
||||
|
||||
|
||||
|
||||
static void OptRegisterVars (const char* Opt attribute ((unused)),
|
||||
const char* Arg attribute ((unused)))
|
||||
/* Handle the --register-vars option */
|
||||
{
|
||||
EnableRegVars = 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void OptRodataName (const char* Opt attribute ((unused)), const char* Arg)
|
||||
/* Handle the --rodata-name option */
|
||||
{
|
||||
@ -607,10 +618,11 @@ int main (int argc, char* argv[])
|
||||
{ "--help", 0, OptHelp },
|
||||
{ "--include-dir", 1, OptIncludeDir },
|
||||
{ "--list-opt-steps", 0, OptListOptSteps },
|
||||
{ "--register-vars", 0, OptRegisterVars },
|
||||
{ "--rodata-name", 1, OptRodataName },
|
||||
{ "--signed-chars", 0, OptSignedChars },
|
||||
{ "--static-locals", 0, OptStaticLocals },
|
||||
{ "--target", 1, OptTarget },
|
||||
{ "--target", 1, OptTarget },
|
||||
{ "--verbose", 0, OptVerbose },
|
||||
{ "--version", 0, OptVersion },
|
||||
};
|
||||
@ -666,6 +678,10 @@ int main (int argc, char* argv[])
|
||||
OutputFile = GetArg (&I, 2);
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
OptRegisterVars (Arg, 0);
|
||||
break;
|
||||
|
||||
case 't':
|
||||
OptTarget (Arg, GetArg (&I, 2));
|
||||
break;
|
||||
@ -690,8 +706,8 @@ int main (int argc, char* argv[])
|
||||
OptStaticLocals (Arg, 0);
|
||||
break;
|
||||
default:
|
||||
UnknownOption (Arg);
|
||||
break;
|
||||
UnknownOption (Arg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -94,22 +94,22 @@ void DumpSymEntry (FILE* F, const SymEntry* E)
|
||||
unsigned Val;
|
||||
} Flags [] = {
|
||||
/* Beware: Order is important! */
|
||||
{ "SC_TYPEDEF", SC_TYPEDEF },
|
||||
{ "SC_SFLD", SC_SFLD },
|
||||
{ "SC_STRUCT", SC_STRUCT },
|
||||
{ "SC_AUTO", SC_AUTO },
|
||||
{ "SC_REGISTER", SC_REGISTER },
|
||||
{ "SC_STATIC", SC_STATIC },
|
||||
{ "SC_EXTERN", SC_EXTERN },
|
||||
{ "SC_ENUM", SC_ENUM },
|
||||
{ "SC_CONST", SC_CONST },
|
||||
{ "SC_LABEL", SC_LABEL },
|
||||
{ "SC_PARAM", SC_PARAM },
|
||||
{ "SC_FUNC", SC_FUNC },
|
||||
{ "SC_STORAGE", SC_STORAGE },
|
||||
{ "SC_DEF", SC_DEF },
|
||||
{ "SC_REF", SC_REF },
|
||||
{ "SC_ZEROPAGE", SC_ZEROPAGE },
|
||||
{ "SC_TYPEDEF", SC_TYPEDEF },
|
||||
{ "SC_STRUCTFIELD", SC_STRUCTFIELD },
|
||||
{ "SC_STRUCT", SC_STRUCT },
|
||||
{ "SC_AUTO", SC_AUTO },
|
||||
{ "SC_REGISTER", SC_REGISTER },
|
||||
{ "SC_STATIC", SC_STATIC },
|
||||
{ "SC_EXTERN", SC_EXTERN },
|
||||
{ "SC_ENUM", SC_ENUM },
|
||||
{ "SC_CONST", SC_CONST },
|
||||
{ "SC_LABEL", SC_LABEL },
|
||||
{ "SC_PARAM", SC_PARAM },
|
||||
{ "SC_FUNC", SC_FUNC },
|
||||
{ "SC_STORAGE", SC_STORAGE },
|
||||
{ "SC_DEF", SC_DEF },
|
||||
{ "SC_REF", SC_REF },
|
||||
{ "SC_ZEROPAGE", SC_ZEROPAGE },
|
||||
};
|
||||
|
||||
unsigned I;
|
||||
@ -149,14 +149,6 @@ void DumpSymEntry (FILE* F, const SymEntry* E)
|
||||
|
||||
|
||||
|
||||
int IsTypeDef (const SymEntry* E)
|
||||
/* Return true if the given entry is a typedef entry */
|
||||
{
|
||||
return ((E->Flags & SC_TYPEDEF) == SC_TYPEDEF);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ChangeSymType (SymEntry* Entry, type* Type)
|
||||
/* Change the type of the given symbol */
|
||||
{
|
||||
|
@ -40,6 +40,9 @@
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
/* common */
|
||||
#include "inline.h"
|
||||
|
||||
/* cc65 */
|
||||
#include "datatype.h"
|
||||
|
||||
@ -81,7 +84,7 @@ struct Segments;
|
||||
|
||||
#define SC_TYPE 0x4000U /* This is a type, struct, typedef, etc. */
|
||||
#define SC_STRUCT 0x4001U /* Struct or union */
|
||||
#define SC_SFLD 0x4002U /* Struct or union field */
|
||||
#define SC_STRUCTFIELD 0x4002U /* Struct or union field */
|
||||
#define SC_TYPEDEF 0x4003U /* A typedef */
|
||||
|
||||
#define SC_ZEROPAGE 0x8000U /* Symbol marked as zeropage */
|
||||
@ -103,13 +106,21 @@ struct SymEntry {
|
||||
/* Data that differs for the different symbol types */
|
||||
union {
|
||||
|
||||
/* Offset for locals or struct members */
|
||||
int Offs;
|
||||
/* Offset for locals or struct members */
|
||||
int Offs;
|
||||
|
||||
/* Label name for static symbols */
|
||||
unsigned Label;
|
||||
/* Label name for static symbols */
|
||||
unsigned Label;
|
||||
|
||||
/* Value for constants (including enums) */
|
||||
/* Register bank offset and offset of the saved copy on stack for
|
||||
* register variables.
|
||||
*/
|
||||
struct {
|
||||
int RegOffs;
|
||||
int SaveOffs;
|
||||
} R;
|
||||
|
||||
/* Value for constants (including enums) */
|
||||
long ConstVal;
|
||||
|
||||
/* Data for structs/unions */
|
||||
@ -145,8 +156,35 @@ void FreeSymEntry (SymEntry* E);
|
||||
void DumpSymEntry (FILE* F, const SymEntry* E);
|
||||
/* Dump the given symbol table entry to the file in readable form */
|
||||
|
||||
int IsTypeDef (const SymEntry* E);
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymIsTypeDef (const SymEntry* Sym)
|
||||
/* Return true if the given entry is a typedef entry */
|
||||
{
|
||||
return ((Sym->Flags & SC_TYPEDEF) == SC_TYPEDEF);
|
||||
}
|
||||
#else
|
||||
# define SymIsTypeDef(Sym) (((Sym)->Flags & SC_TYPEDEF) == SC_TYPEDEF)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymIsDef (const SymEntry* Sym)
|
||||
/* Return true if the given entry is defined */
|
||||
{
|
||||
return ((Sym->Flags & SC_DEF) == SC_DEF);
|
||||
}
|
||||
#else
|
||||
# define SymIsDef(Sym) (((Sym)->Flags & SC_DEF) == SC_DEF)
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_INLINE)
|
||||
INLINE int SymIsRef (const SymEntry* Sym)
|
||||
/* Return true if the given entry is referenced */
|
||||
{
|
||||
return ((Sym->Flags & SC_REF) == SC_REF);
|
||||
}
|
||||
#else
|
||||
# define SymIsRef(Sym) (((Sym)->Flags & SC_REF) == SC_REF)
|
||||
#endif
|
||||
|
||||
void ChangeSymType (SymEntry* Entry, type* Type);
|
||||
/* Change the type of the given symbol */
|
||||
|
@ -163,7 +163,7 @@ static void CheckSymTable (SymTable* Tab)
|
||||
* defined but not used.
|
||||
*/
|
||||
if (((Flags & SC_AUTO) || (Flags & SC_STATIC)) && (Flags & SC_EXTERN) == 0) {
|
||||
if ((Flags & SC_DEF) && !(Flags & SC_REF)) {
|
||||
if (SymIsDef (Entry) && !SymIsRef (Entry)) {
|
||||
if (Flags & SC_PARAM) {
|
||||
Warning ("Parameter `%s' is never used", Entry->Name);
|
||||
} else {
|
||||
@ -174,10 +174,10 @@ static void CheckSymTable (SymTable* Tab)
|
||||
|
||||
/* If the entry is a label, check if it was defined in the function */
|
||||
if (Flags & SC_LABEL) {
|
||||
if ((Flags & SC_DEF) == 0) {
|
||||
if (!SymIsDef (Entry)) {
|
||||
/* Undefined label */
|
||||
Error ("Undefined label: `%s'", Entry->Name);
|
||||
} else if ((Flags & SC_REF) == 0) {
|
||||
} else if (!SymIsRef (Entry)) {
|
||||
/* Defined but not used */
|
||||
Warning ("`%s' is defined but never used", Entry->Name);
|
||||
}
|
||||
@ -614,7 +614,7 @@ SymEntry* AddLabelSym (const char* Name, unsigned Flags)
|
||||
SymEntry* Entry = FindSymInTable (LabelTab, Name, HashStr (Name));
|
||||
if (Entry) {
|
||||
|
||||
if ((Entry->Flags & SC_DEF) != 0 && (Flags & SC_DEF) != 0) {
|
||||
if (SymIsDef (Entry) && (Flags & SC_DEF) != 0) {
|
||||
/* Trying to define the label more than once */
|
||||
Error ("Label `%s' is defined more than once", Name);
|
||||
}
|
||||
@ -656,7 +656,18 @@ SymEntry* AddLocalSym (const char* Name, const type* Type, unsigned Flags, int O
|
||||
|
||||
/* Set the symbol attributes */
|
||||
Entry->Type = TypeDup (Type);
|
||||
Entry->V.Offs = Offs;
|
||||
if ((Flags & SC_AUTO) == SC_AUTO) {
|
||||
Entry->V.Offs = Offs;
|
||||
} else if ((Flags & SC_REGISTER) == SC_REGISTER) {
|
||||
Entry->V.R.RegOffs = Offs;
|
||||
Entry->V.R.SaveOffs = oursp; /* ### Cleaner! */
|
||||
} else if ((Flags & SC_STATIC) == SC_STATIC) {
|
||||
Entry->V.Label = Offs;
|
||||
} else if ((Flags & SC_STRUCTFIELD) == SC_STRUCTFIELD) {
|
||||
Entry->V.Offs = Offs;
|
||||
} else {
|
||||
Internal ("Invalid flags in AddLocalSym: %04X", Flags);
|
||||
}
|
||||
|
||||
/* Add the entry to the symbol table */
|
||||
AddSymEntry (SymTab, Entry);
|
||||
@ -856,10 +867,10 @@ void EmitExternals (void)
|
||||
unsigned Flags = Entry->Flags;
|
||||
if (Flags & SC_EXTERN) {
|
||||
/* Only defined or referenced externs */
|
||||
if ((Flags & SC_REF) != 0 && (Flags & SC_DEF) == 0) {
|
||||
if (SymIsRef (Entry) && !SymIsDef (Entry)) {
|
||||
/* An import */
|
||||
g_defimport (Entry->Name, Flags & SC_ZEROPAGE);
|
||||
} else if (Flags & SC_DEF) {
|
||||
} else if (SymIsDef (Entry)) {
|
||||
/* An export */
|
||||
g_defexport (Entry->Name, Flags & SC_ZEROPAGE);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user