Fixed the cc65 code that optimizes 16-bit compares when the high bytes are known to be equal.

Only the low bytes are compared.  Originally, signed 16-bit compares were optimized into signed 8-bit compares.  But, the sign bits are in the high bytes; and, they're equal.  Therefore, the low bytes always must be compared as unsigned numbers.
Fixes #1348.
This commit is contained in:
Greg King 2020-12-24 12:27:09 -05:00
parent 0f4cb443b4
commit b2c1a77bb3
3 changed files with 37 additions and 77 deletions

View File

@ -287,7 +287,7 @@ static unsigned Opt_tosshift (StackOpData* D, const char* Name)
/* ldx */
X = NewCodeEntry (OP65_LDX, LoadX->AM, LoadX->Arg, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
/* Lhs load entries can be removed if not used later */
D->Lhs.X.Flags |= LI_REMOVE;
D->Lhs.A.Flags |= LI_REMOVE;
@ -1100,7 +1100,7 @@ static unsigned Opt_tosxorax (StackOpData* D)
static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
/* Optimize the tos compare sequence with a bool transformer */
/* Optimize the TOS compare sequence with a bool transformer */
{
CodeEntry* X;
cmp_t Cond;
@ -1119,9 +1119,8 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
D->Rhs.A.Flags |= LI_REMOVE;
} else if ((D->Lhs.A.Flags & LI_DIRECT) != 0) {
/* If the lhs is direct (but not stack relative), encode compares with lhs
** effectively reverting the order (which doesn't matter for ==).
/* If the lhs is direct (but not stack relative), encode compares with lhs,
** effectively reversing the order (which doesn't matter for == and !=).
*/
Cond = FindBoolCmpCond (BoolTransformer);
Cond = GetRevertedCond (Cond);
@ -1138,7 +1137,6 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
D->Lhs.A.Flags |= LI_REMOVE;
} else {
/* We'll do reverse-compare */
Cond = FindBoolCmpCond (BoolTransformer);
Cond = GetRevertedCond (Cond);
@ -1162,7 +1160,7 @@ static unsigned Opt_a_toscmpbool (StackOpData* D, const char* BoolTransformer)
X = NewCodeEntry (OP65_JSR, AM65_ABS, BoolTransformer, 0, D->OpEntry->LI);
InsertEntry (D, X, D->IP++);
/* Remove the push and the call to the tosgeax function */
/* Remove the push and the call to the TOS function */
RemoveRemainders (D);
/* We changed the sequence */
@ -1179,22 +1177,6 @@ static unsigned Opt_a_toseq (StackOpData* D)
static unsigned Opt_a_tosge (StackOpData* D)
/* Optimize the tosgeax sequence */
{
return Opt_a_toscmpbool (D, "boolge");
}
static unsigned Opt_a_tosgt (StackOpData* D)
/* Optimize the tosgtax sequence */
{
return Opt_a_toscmpbool (D, "boolgt");
}
static unsigned Opt_a_tosicmp (StackOpData* D)
/* Replace tosicmp with CMP */
{
@ -1236,7 +1218,7 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
}
InsertEntry (D, X, D->IP++);
/* cmp src,y OR cmp (sp),y*/
/* cmp src,y OR cmp (sp),y */
if (D->Rhs.A.LoadEntry->OPC == OP65_JSR) {
/* opc (sp),y */
X = NewCodeEntry (OP65_CMP, AM65_ZP_INDY, "sp", 0, D->OpEntry->LI);
@ -1268,18 +1250,18 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
InsertEntry (D, X, D->IP-3);
} else {
/* Just clear A,Z,N and set C */
/* Just clear A,Z,N; and set C */
Arg = MakeHexArg (0);
if ((RI = GetLastChangedRegInfo (D, &D->Lhs.A)) != 0 &&
RegValIsKnown (RI->Out.RegA) &&
(RI->Out.RegA & 0xFF) == 0) {
Arg = MakeHexArg (0);
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
InsertEntry (D, X, D->OpIndex + 1);
} else {
Arg = MakeHexArg (0);
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
X = NewCodeEntry (OP65_LDA, AM65_IMM, Arg, 0, D->OpEntry->LI);
InsertEntry (D, X, D->OpIndex + 1);
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
X = NewCodeEntry (OP65_CMP, AM65_IMM, Arg, 0, D->OpEntry->LI);
InsertEntry (D, X, D->OpIndex + 2);
}
}
@ -1292,24 +1274,8 @@ static unsigned Opt_a_tosicmp (StackOpData* D)
static unsigned Opt_a_tosle (StackOpData* D)
/* Optimize the tosleax sequence */
{
return Opt_a_toscmpbool (D, "boolle");
}
static unsigned Opt_a_toslt (StackOpData* D)
/* Optimize the tosltax sequence */
{
return Opt_a_toscmpbool (D, "boollt");
}
static unsigned Opt_a_tosne (StackOpData* D)
/* Optimize the toseqax sequence */
/* Optimize the tosneax sequence */
{
return Opt_a_toscmpbool (D, "boolne");
}
@ -1317,7 +1283,7 @@ static unsigned Opt_a_tosne (StackOpData* D)
static unsigned Opt_a_tosuge (StackOpData* D)
/* Optimize the tosugeax sequence */
/* Optimize the tosgeax and tosugeax sequences */
{
return Opt_a_toscmpbool (D, "booluge");
}
@ -1325,7 +1291,7 @@ static unsigned Opt_a_tosuge (StackOpData* D)
static unsigned Opt_a_tosugt (StackOpData* D)
/* Optimize the tosugtax sequence */
/* Optimize the tosgtax and tosugtax sequences */
{
return Opt_a_toscmpbool (D, "boolugt");
}
@ -1333,7 +1299,7 @@ static unsigned Opt_a_tosugt (StackOpData* D)
static unsigned Opt_a_tosule (StackOpData* D)
/* Optimize the tosuleax sequence */
/* Optimize the tosleax and tosuleax sequences */
{
return Opt_a_toscmpbool (D, "boolule");
}
@ -1341,7 +1307,7 @@ static unsigned Opt_a_tosule (StackOpData* D)
static unsigned Opt_a_tosult (StackOpData* D)
/* Optimize the tosultax sequence */
/* Optimize the tosltax and tosultax sequences */
{
return Opt_a_toscmpbool (D, "boolult");
}
@ -1354,6 +1320,8 @@ static unsigned Opt_a_tosult (StackOpData* D)
/* The first column of these two tables must be sorted in lexical order */
static const OptFuncDesc FuncTable[] = {
{ "__bzero", Opt___bzero, REG_NONE, OP_X_ZERO | OP_A_KNOWN },
{ "staspidx", Opt_staspidx, REG_NONE, OP_NONE },
@ -1379,11 +1347,11 @@ static const OptFuncDesc FuncTable[] = {
static const OptFuncDesc FuncRegATable[] = {
{ "toseqax", Opt_a_toseq, REG_NONE, OP_NONE },
{ "tosgeax", Opt_a_tosge, REG_NONE, OP_NONE },
{ "tosgtax", Opt_a_tosgt, REG_NONE, OP_NONE },
{ "tosgeax", Opt_a_tosuge, REG_NONE, OP_NONE },
{ "tosgtax", Opt_a_tosugt, REG_NONE, OP_NONE },
{ "tosicmp", Opt_a_tosicmp, REG_NONE, OP_NONE },
{ "tosleax", Opt_a_tosle, REG_NONE, OP_NONE },
{ "tosltax", Opt_a_toslt, REG_NONE, OP_NONE },
{ "tosleax", Opt_a_tosule, REG_NONE, OP_NONE },
{ "tosltax", Opt_a_tosult, REG_NONE, OP_NONE },
{ "tosneax", Opt_a_tosne, REG_NONE, OP_NONE },
{ "tosugeax", Opt_a_tosuge, REG_NONE, OP_NONE },
{ "tosugtax", Opt_a_tosugt, REG_NONE, OP_NONE },

View File

@ -117,14 +117,6 @@ $(WORKDIR)/endless.$1.$2.prg: endless.c | $(WORKDIR)
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
$(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
# this one fails when optimization are enabled
$(WORKDIR)/bug1348.$1.$2.prg: bug1348.c | $(WORKDIR)
$(if $(QUIET),echo misc/bug1348.$1.$2.prg)
$(CC65) -Osr -t sim$2 -$1 -o $$(@:.prg=.s) $$< $(NULLERR)
$(CA65) -t sim$2 -o $$(@:.prg=.o) $$(@:.prg=.s) $(NULLERR)
$(LD65) -t sim$2 -o $$@ $$(@:.prg=.o) sim$2.lib $(NULLERR)
$(NOT) $(SIM65) $(SIM65FLAGS) $$@ $(NULLOUT) $(NULLERR)
# these need reference data that can't be generated by a host-compiled program,
# in a useful way
$(WORKDIR)/limits.$1.$2.prg: limits.c $(ISEQUAL) | $(WORKDIR)

View File

@ -1,27 +1,26 @@
/* bug#1348, wrongly optimized integer promotion in comparison */
/* bug #1348, wrongly optimized integer promotion in comparison */
#include <stdio.h>
int notrandtab[] = {
static const int notrandtab[] = {
0xffff, 0x7fff, 0x3fff, 0x1fff,
0x0fff, 0x07ff, 0x03ff, 0x01ff,
0x00ff, 0x007f, 0x003f, 0x001f,
0x000f, 0x0007, 0x0003, 0x0001
};
unsigned char notrandcount = 0;
static unsigned char notrandcount = 0;
int notrand(void)
static int notrand(void)
{
return notrandtab[notrandcount & 0x0f];
}
unsigned char n1, n2;
unsigned char i, ii, s;
unsigned char err = 0;
static unsigned char n1, n2;
static unsigned char i, ii, s;
static unsigned char err = 0;
unsigned char cmptab[] = {
static const unsigned char cmptab[] = {
0xff, 0x7f, 0x3f, 0x1f,
0x0f, 0x07, 0x03, 0x01,
0x80, 0x40, 0x20, 0x10,
@ -40,13 +39,14 @@ int main(void)
if ((notrand() & 0xffu) > s) {
n2 = 1;
}
printf("%5d>%3d %d(%02x) %d(%02x) %s\n",
notrandtab[notrandcount & 0x0f], s,
printf("%5d > %3d %u(%02x) %u(%02x) %s\n",
notrandtab[i], s,
n1, (notrand() & 0xff),
n2, (notrand() & 0xffu),
n1 == n2 ? "=" : "!="
);
if (n1 != n2) err = 1;
n1 == n2 ? "=" : "!=");
if (n1 != n2) {
err = 1;
}
notrandcount++;
}
}