1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-10 19:29:45 +00:00

Fixed a code generation bug

git-svn-id: svn://svn.cc65.org/cc65/trunk@1215 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
cuz 2002-04-06 14:51:27 +00:00
parent ad1951c068
commit c6fe12ef6b
7 changed files with 198 additions and 136 deletions

View File

@ -224,7 +224,7 @@ const char* MakeHexArg (unsigned Num)
*/
{
static char Buf[16];
xsprintf (Buf, sizeof (Buf), "$%02X", (char) Num);
xsprintf (Buf, sizeof (Buf), "$%02X", (unsigned char) Num);
return Buf;
}
@ -376,6 +376,46 @@ int CE_KnownImm (const CodeEntry* E)
int CE_UseLoadFlags (const CodeEntry* E)
/* Return true if the instruction uses any flags that are set by a load of
* a register (N and Z).
*/
{
/* A branch will use the flags */
if (E->Info & OF_FBRA) {
return 1;
}
/* Call of a boolean transformer routine will also use the flags */
if (E->OPC == OP65_JSR) {
/* Get the condition that is evaluated and check it */
switch (FindBoolCmpCond (E->Arg)) {
case CMP_EQ:
case CMP_NE:
case CMP_GT:
case CMP_GE:
case CMP_LT:
case CMP_LE:
case CMP_UGT:
case CMP_ULE:
case CMP_INV:
/* Will use the N or Z flags */
return 1;
case CMP_UGE: /* Uses only carry */
case CMP_ULT: /* Dito */
default: /* No bool transformer subroutine */
return 0;
}
}
/* Anything else */
return 0;
}
void CE_FreeRegInfo (CodeEntry* E)
/* Free an existing register info struct */
{

View File

@ -196,6 +196,11 @@ INLINE int CE_IsCall (const CodeEntry* E, const char* Name)
# define CE_IsCall(E, Name) ((E)->OPC == OP65_JSR && strcmp ((E)->Arg, (Name)) == 0)
#endif
int CE_UseLoadFlags (const CodeEntry* E);
/* Return true if the instruction uses any flags that are set by a load of
* a register (N and Z).
*/
void CE_FreeRegInfo (CodeEntry* E);
/* Free an existing register info struct */

View File

@ -56,6 +56,11 @@
/* Table with the compare suffixes */
static const char CmpSuffixTab [][4] = {
"eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
};
/* Table listing the function names and code info values for known internally
* used functions. This table should get auto-generated in the future.
*/
@ -584,3 +589,59 @@ unsigned GetKnownReg (unsigned Use, const RegContents* RC)
static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
/* Search for a compare condition by the given code using the given length */
{
unsigned I;
/* Linear search */
for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
/* Found */
return I;
}
}
/* Not found */
return CMP_INV;
}
cmp_t FindBoolCmpCond (const char* Name)
/* Check if the given string is the name of one of the boolean transformer
* subroutine, and if so, return the condition that is evaluated by this
* routine. Return CMP_INV if the condition is not recognised.
*/
{
/* Check for the correct subroutine name */
if (strncmp (Name, "bool", 4) == 0) {
/* Name is ok, search for the code in the table */
return FindCmpCond (Name+4, strlen(Name)-4);
} else {
/* Not found */
return CMP_INV;
}
}
cmp_t FindTosCmpCond (const char* Name)
/* Check if this is a call to one of the TOS compare functions (tosgtax).
* Return the condition code or CMP_INV on failure.
*/
{
unsigned Len = strlen (Name);
/* Check for the correct subroutine name */
if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
/* Name is ok, search for the code in the table */
return FindCmpCond (Name+3, Len-3-2);
} else {
/* Not found */
return CMP_INV;
}
}

View File

@ -103,6 +103,23 @@ struct ZPInfo {
/* Defines for the conditions in a compare */
typedef enum {
CMP_INV = -1,
CMP_EQ,
CMP_NE,
CMP_GT,
CMP_GE,
CMP_LT,
CMP_LE,
CMP_UGT,
CMP_UGE,
CMP_ULT,
CMP_ULE
} cmp_t;
/*****************************************************************************/
/* Code */
/*****************************************************************************/
@ -143,6 +160,17 @@ unsigned GetKnownReg (unsigned Use, const struct RegContents* RC);
* register in question does not have a known value, return REG_NONE.
*/
cmp_t FindBoolCmpCond (const char* Name);
/* Check if the given string is the name of one of the boolean transformer
* subroutine, and if so, return the condition that is evaluated by this
* routine. Return CMP_INV if the condition is not recognised.
*/
cmp_t FindTosCmpCond (const char* Name);
/* Check if this is a call to one of the TOS compare functions (tosgtax).
* Return the condition code or CMP_INV on failure.
*/
/* End of codeinfo.h */

View File

@ -49,26 +49,6 @@
/* Defines for the conditions in a compare */
typedef enum {
CMP_INV = -1,
CMP_EQ,
CMP_NE,
CMP_GT,
CMP_GE,
CMP_LT,
CMP_LE,
CMP_UGT,
CMP_UGE,
CMP_ULT,
CMP_ULE
} cmp_t;
/* Table with the compare suffixes */
static const char CmpSuffixTab [][4] = {
"eq", "ne", "gt", "ge", "lt", "le", "ugt", "uge", "ult", "ule"
};
/* Table used to invert a condition, indexed by condition */
static const unsigned char CmpInvertTab [] = {
CMP_NE, CMP_EQ,
@ -89,59 +69,6 @@ static const char CmpSignedTab [] = {
static cmp_t FindCmpCond (const char* Code, unsigned CodeLen)
/* Search for a compare condition by the given code using the given length */
{
unsigned I;
/* Linear search */
for (I = 0; I < sizeof (CmpSuffixTab) / sizeof (CmpSuffixTab [0]); ++I) {
if (strncmp (Code, CmpSuffixTab [I], CodeLen) == 0) {
/* Found */
return I;
}
}
/* Not found */
return CMP_INV;
}
static cmp_t FindBoolCmpCond (const char* Name)
/* Map a condition suffix to a code. Return the code or CMP_INV on failure */
{
/* Check for the correct subroutine name */
if (strncmp (Name, "bool", 4) == 0) {
/* Name is ok, search for the code in the table */
return FindCmpCond (Name+4, strlen(Name)-4);
} else {
/* Not found */
return CMP_INV;
}
}
static cmp_t FindTosCmpCond (const char* Name)
/* Check if this is a call to one of the TOS compare functions (tosgtax).
* Return the condition code or CMP_INV on failure.
*/
{
unsigned Len = strlen (Name);
/* Check for the correct subroutine name */
if (strncmp (Name, "tos", 3) == 0 && strcmp (Name+Len-2, "ax") == 0) {
/* Name is ok, search for the code in the table */
return FindCmpCond (Name+3, Len-3-2);
} else {
/* Not found */
return CMP_INV;
}
}
static void ReplaceCmp (CodeSeg* S, unsigned I, cmp_t Cond)
/* Helper function for the replacement of routines that return a boolean
* followed by a conditional jump. Instead of the boolean value, the condition

View File

@ -655,7 +655,7 @@ unsigned OptCondBranches (CodeSeg* S)
/*****************************************************************************/
/* Remove unused loads and stores */
/* Remove unused loads and stores */
/*****************************************************************************/
@ -675,24 +675,24 @@ unsigned OptUnusedLoads (CodeSeg* S)
CodeEntry* E = CS_GetEntry (S, I);
/* Check if it's a register load or transfer insn */
if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_FBRA) == 0) {
if ((E->Info & (OF_LOAD | OF_XFR | OF_REG_INCDEC)) != 0 &&
(N = CS_GetNextEntry (S, I)) != 0 &&
!CE_UseLoadFlags (N)) {
/* Check which sort of load or transfer it is */
unsigned R;
switch (E->OPC) {
case OP65_DEA:
case OP65_INA:
case OP65_LDA:
case OP65_DEA:
case OP65_INA:
case OP65_LDA:
case OP65_TXA:
case OP65_TYA: R = REG_A; break;
case OP65_DEX:
case OP65_INX:
case OP65_LDX:
case OP65_DEX:
case OP65_INX:
case OP65_LDX:
case OP65_TAX: R = REG_X; break;
case OP65_DEY:
case OP65_INY:
case OP65_DEY:
case OP65_INY:
case OP65_LDY:
case OP65_TAY: R = REG_Y; break;
default: goto NextEntry; /* OOPS */
@ -799,7 +799,7 @@ unsigned OptDupLoads (CodeSeg* S)
CE_KnownImm (E) && /* Value to be loaded is known */
In->RegA == (long) E->Num && /* Both are equal */
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
!CE_UseLoadFlags (N)) { /* Which does not use the flags */
Delete = 1;
}
break;
@ -809,7 +809,7 @@ unsigned OptDupLoads (CodeSeg* S)
CE_KnownImm (E) && /* Value to be loaded is known */
In->RegX == (long) E->Num && /* Both are equal */
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
!CE_UseLoadFlags (N)) { /* Which does not use the flags */
Delete = 1;
}
break;
@ -819,7 +819,7 @@ unsigned OptDupLoads (CodeSeg* S)
CE_KnownImm (E) && /* Value to be loaded is known */
In->RegY == (long) E->Num && /* Both are equal */
(N = CS_GetNextEntry (S, I)) != 0 && /* There is a next entry */
(N->Info & OF_FBRA) == 0) { /* Which is not a cond branch */
!CE_UseLoadFlags (N)) { /* Which does not use the flags */
Delete = 1;
}
break;
@ -908,37 +908,37 @@ unsigned OptDupLoads (CodeSeg* S)
if (In->RegA >= 0 &&
In->RegA == In->RegX &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_FBRA) == 0) {
!CE_UseLoadFlags (N)) {
/* Value is identical and not followed by a branch */
Delete = 1;
}
break;
case OP65_TAY:
if (In->RegA >= 0 &&
In->RegA == In->RegY &&
if (In->RegA >= 0 &&
In->RegA == In->RegY &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_FBRA) == 0) {
!CE_UseLoadFlags (N)) {
/* Value is identical and not followed by a branch */
Delete = 1;
}
break;
case OP65_TXA:
if (In->RegX >= 0 &&
In->RegX == In->RegA &&
if (In->RegX >= 0 &&
In->RegX == In->RegA &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_FBRA) == 0) {
!CE_UseLoadFlags (N)) {
/* Value is identical and not followed by a branch */
Delete = 1;
}
break;
case OP65_TYA:
if (In->RegY >= 0 &&
In->RegY == In->RegA &&
if (In->RegY >= 0 &&
In->RegY == In->RegA &&
(N = CS_GetNextEntry (S, I)) != 0 &&
(N->Info & OF_FBRA) == 0) {
!CE_UseLoadFlags (N)) {
/* Value is identical and not followed by a branch */
Delete = 1;
}
@ -1003,7 +1003,7 @@ unsigned OptStoreLoad (CodeSeg* S)
(E->OPC == OP65_STY && N->OPC == OP65_LDY)) &&
strcmp (E->Arg, N->Arg) == 0 &&
(X = CS_GetNextEntry (S, I+1)) != 0 &&
(X->Info & OF_FBRA) == 0) {
!CE_UseLoadFlags (X)) {
/* Register has already the correct value, remove the load */
CS_DelEntry (S, I+1);
@ -1061,7 +1061,7 @@ unsigned OptTransfers (CodeSeg* S)
if ((X = CS_GetNextEntry (S, I+1)) == 0) {
goto NextEntry;
}
if ((X->Info & OF_FBRA) != 0) {
if (CE_UseLoadFlags (X)) {
if (I == 0) {
/* No preceeding entry */
goto NextEntry;

View File

@ -281,16 +281,16 @@ unsigned assignadjust (type* lhst, ExprDesc* rhs)
void DefineData (ExprDesc* lval)
void DefineData (ExprDesc* Expr)
/* Output a data definition for the given expression */
{
unsigned flags = lval->Flags;
unsigned Flags = Expr->Flags;
switch (flags & E_MCTYPE) {
switch (Flags & E_MCTYPE) {
case E_TCONST:
/* Number */
g_defdata (TypeOf (lval->Type) | CF_CONST, lval->ConstVal, 0);
g_defdata (TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0);
break;
case E_TREGISTER:
@ -305,33 +305,33 @@ void DefineData (ExprDesc* lval)
case E_TGLAB:
case E_TLLAB:
/* Local or global symbol */
g_defdata (GlobalModeFlags (flags), lval->Name, lval->ConstVal);
g_defdata (GlobalModeFlags (Flags), Expr->Name, Expr->ConstVal);
break;
case E_TLIT:
/* a literal of some kind */
g_defdata (CF_STATIC, LiteralPoolLabel, lval->ConstVal);
g_defdata (CF_STATIC, LiteralPoolLabel, Expr->ConstVal);
break;
default:
Internal ("Unknown constant type: %04X", flags);
Internal ("Unknown constant type: %04X", Flags);
}
}
static void lconst (unsigned flags, ExprDesc* lval)
/* Load primary reg with some constant value. */
static void lconst (unsigned Flags, ExprDesc* Expr)
/* Load the primary register with some constant value. */
{
switch (lval->Flags & E_MCTYPE) {
switch (Expr->Flags & E_MCTYPE) {
case E_TLOFFS:
g_leasp (lval->ConstVal);
g_leasp (Expr->ConstVal);
break;
case E_TCONST:
/* Number constant */
g_getimmed (flags | TypeOf (lval->Type) | CF_CONST, lval->ConstVal, 0);
g_getimmed (Flags | TypeOf (Expr->Type) | CF_CONST, Expr->ConstVal, 0);
break;
case E_TREGISTER:
@ -346,18 +346,18 @@ static void lconst (unsigned flags, ExprDesc* lval)
case E_TGLAB:
case E_TLLAB:
/* Local or global symbol, load address */
flags |= GlobalModeFlags (lval->Flags);
flags &= ~CF_CONST;
g_getimmed (flags, lval->Name, lval->ConstVal);
Flags |= GlobalModeFlags (Expr->Flags);
Flags &= ~CF_CONST;
g_getimmed (Flags, Expr->Name, Expr->ConstVal);
break;
case E_TLIT:
/* Literal string */
g_getimmed (CF_STATIC, LiteralPoolLabel, lval->ConstVal);
g_getimmed (CF_STATIC, LiteralPoolLabel, Expr->ConstVal);
break;
default:
Internal ("Unknown constant type: %04X", lval->Flags);
Internal ("Unknown constant type: %04X", Expr->Flags);
}
}
@ -411,9 +411,10 @@ static int kcalc (int tok, long val1, long val2)
static GenDesc* FindGen (token_t Tok, GenDesc** Table)
static const GenDesc* FindGen (token_t Tok, const GenDesc** Table)
/* Find a token in a generator table */
{
GenDesc* G;
const GenDesc* G;
while ((G = *Table) != 0) {
if (G->Tok == Tok) {
return G;
@ -1760,7 +1761,7 @@ static int hie10 (ExprDesc* lval)
static int hie_internal (GenDesc** ops, /* List of generators */
static int hie_internal (const GenDesc** ops, /* List of generators */
ExprDesc* lval, /* parent expr's lval */
int (*hienext) (ExprDesc*),
int* UsedGen) /* next higher level */
@ -1770,7 +1771,7 @@ static int hie_internal (GenDesc** ops, /* List of generators */
ExprDesc lval2;
CodeMark Mark1;
CodeMark Mark2;
GenDesc* Gen;
const GenDesc* Gen;
token_t tok; /* The operator token */
unsigned ltype, type;
int rconst; /* Operand is a constant */
@ -1870,8 +1871,8 @@ static int hie_internal (GenDesc** ops, /* List of generators */
static int hie_compare (GenDesc** ops, /* List of generators */
ExprDesc* lval, /* parent expr's lval */
static int hie_compare (const GenDesc** ops, /* List of generators */
ExprDesc* lval, /* parent expr's lval */
int (*hienext) (ExprDesc*))
/* Helper function for the compare operators */
{
@ -1879,7 +1880,7 @@ static int hie_compare (GenDesc** ops, /* List of generators */
ExprDesc lval2;
CodeMark Mark1;
CodeMark Mark2;
GenDesc* Gen;
const GenDesc* Gen;
token_t tok; /* The operator token */
unsigned ltype;
int rconst; /* Operand is a constant */
@ -1997,7 +1998,7 @@ static int hie_compare (GenDesc** ops, /* List of generators */
static int hie9 (ExprDesc *lval)
/* Process * and / operators. */
{
static GenDesc* hie9_ops [] = {
static const GenDesc* hie9_ops [] = {
&GenMUL, &GenDIV, &GenMOD, 0
};
int UsedGen;
@ -2421,7 +2422,7 @@ static int hie8 (ExprDesc* lval)
static int hie7 (ExprDesc *lval)
/* Parse << and >>. */
{
static GenDesc* hie7_ops [] = {
static const GenDesc* hie7_ops [] = {
&GenASL, &GenASR, 0
};
int UsedGen;
@ -2434,7 +2435,7 @@ static int hie7 (ExprDesc *lval)
static int hie6 (ExprDesc *lval)
/* process greater-than type comparators */
{
static GenDesc* hie6_ops [] = {
static const GenDesc* hie6_ops [] = {
&GenLT, &GenLE, &GenGE, &GenGT, 0
};
return hie_compare (hie6_ops, lval, hie7);
@ -2444,7 +2445,7 @@ static int hie6 (ExprDesc *lval)
static int hie5 (ExprDesc *lval)
{
static GenDesc* hie5_ops[] = {
static const GenDesc* hie5_ops[] = {
&GenEQ, &GenNE, 0
};
return hie_compare (hie5_ops, lval, hie6);
@ -2455,7 +2456,7 @@ static int hie5 (ExprDesc *lval)
static int hie4 (ExprDesc* lval)
/* Handle & (bitwise and) */
{
static GenDesc* hie4_ops [] = {
static const GenDesc* hie4_ops [] = {
&GenAND, 0
};
int UsedGen;
@ -2468,7 +2469,7 @@ static int hie4 (ExprDesc* lval)
static int hie3 (ExprDesc *lval)
/* Handle ^ (bitwise exclusive or) */
{
static GenDesc* hie3_ops [] = {
static const GenDesc* hie3_ops [] = {
&GenXOR, 0
};
int UsedGen;
@ -2481,7 +2482,7 @@ static int hie3 (ExprDesc *lval)
static int hie2 (ExprDesc *lval)
/* Handle | (bitwise or) */
{
static GenDesc* hie2_ops [] = {
static const GenDesc* hie2_ops [] = {
&GenOR, 0
};
int UsedGen;
@ -2810,7 +2811,7 @@ static int hieQuest (ExprDesc *lval)
static void opeq (GenDesc* Gen, ExprDesc *lval, int k)
static void opeq (const GenDesc* Gen, ExprDesc *lval, int k)
/* Process "op=" operators. */
{
ExprDesc lval2;
@ -2891,7 +2892,7 @@ static void opeq (GenDesc* Gen, ExprDesc *lval, int k)
static void addsubeq (GenDesc* Gen, ExprDesc *lval, int k)
static void addsubeq (const GenDesc* Gen, ExprDesc *lval, int k)
/* Process the += and -= operators */
{
ExprDesc lval2;