Better code for compares
git-svn-id: svn://svn.cc65.org/cc65/trunk@1150 b7a2c559-68d2-44c3-8de9-860c34a00d81
This commit is contained in:
@@ -1748,7 +1748,7 @@ void g_subeqstatic (unsigned flags, unsigned long label, long offs,
|
|||||||
AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
|
AddCodeLine ("sbc #$%02X", (int)(val & 0xFF));
|
||||||
AddCodeLine ("sta %s", lbuf);
|
AddCodeLine ("sta %s", lbuf);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("eor #$FF");
|
AddCodeLine ("eor #$FF");
|
||||||
AddCodeLine ("sec");
|
AddCodeLine ("sec");
|
||||||
AddCodeLine ("adc %s", lbuf);
|
AddCodeLine ("adc %s", lbuf);
|
||||||
@@ -1783,7 +1783,7 @@ void g_subeqstatic (unsigned flags, unsigned long label, long offs,
|
|||||||
AddCodeLine ("tax");
|
AddCodeLine ("tax");
|
||||||
AddCodeLine ("lda %s", lbuf);
|
AddCodeLine ("lda %s", lbuf);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("eor #$FF");
|
AddCodeLine ("eor #$FF");
|
||||||
AddCodeLine ("adc %s", lbuf);
|
AddCodeLine ("adc %s", lbuf);
|
||||||
AddCodeLine ("sta %s", lbuf);
|
AddCodeLine ("sta %s", lbuf);
|
||||||
@@ -3219,9 +3219,9 @@ void g_eq (unsigned flags, unsigned long val)
|
|||||||
{
|
{
|
||||||
static char* ops [12] = {
|
static char* ops [12] = {
|
||||||
"toseq00", "toseqa0", "toseqax",
|
"toseq00", "toseqa0", "toseqax",
|
||||||
"toseq00", "toseqa0", "toseqax",
|
"toseq00", "toseqa0", "toseqax",
|
||||||
0, 0, "toseqeax",
|
0, 0, "toseqeax",
|
||||||
0, 0, "toseqeax",
|
0, 0, "toseqeax",
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned L;
|
unsigned L;
|
||||||
@@ -3332,7 +3332,7 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
static char* ops [12] = {
|
static char* ops [12] = {
|
||||||
"toslt00", "toslta0", "tosltax",
|
"toslt00", "toslta0", "tosltax",
|
||||||
"tosult00", "tosulta0", "tosultax",
|
"tosult00", "tosulta0", "tosultax",
|
||||||
0, 0, "toslteax",
|
0, 0, "toslteax",
|
||||||
0, 0, "tosulteax",
|
0, 0, "tosulteax",
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3344,6 +3344,8 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
/* Give a warning in some special cases */
|
/* Give a warning in some special cases */
|
||||||
if ((flags & CF_UNSIGNED) && val == 0) {
|
if ((flags & CF_UNSIGNED) && val == 0) {
|
||||||
Warning ("Condition is never true");
|
Warning ("Condition is never true");
|
||||||
|
AddCodeLine ("jsr return0");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at the type */
|
/* Look at the type */
|
||||||
@@ -3353,7 +3355,7 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
if (flags & CF_FORCECHAR) {
|
if (flags & CF_FORCECHAR) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
AddCodeLine ("jsr boolult");
|
AddCodeLine ("jsr boolult");
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("jsr boollt");
|
AddCodeLine ("jsr boollt");
|
||||||
}
|
}
|
||||||
@@ -3370,16 +3372,32 @@ void g_lt (unsigned flags, unsigned long val)
|
|||||||
AddCodeLine ("jsr boollt");
|
AddCodeLine ("jsr boollt");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* Direct code only for unsigned data types */
|
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
unsigned L = GetLocalLabel();
|
/* Unsigned compare */
|
||||||
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
/* If the low byte is zero, we must only test the high
|
||||||
AddCodeLine ("bne %s", LocalLabelName (L));
|
* byte. Or, citing Piotr Fusik:
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
* Another interpretation: the code is effectively:
|
||||||
g_defcodelabel (L);
|
* if (ax >= 0xAB00) goto L2;
|
||||||
|
* It's equivalent to:
|
||||||
|
* if ((ax >> 8) >= 0xAB) goto L2;
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
||||||
|
if ((val & 0xFF) != 0) {
|
||||||
|
unsigned L = GetLocalLabel();
|
||||||
|
AddCodeLine ("bne %s", LocalLabelName (L));
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
|
g_defcodelabel (L);
|
||||||
|
}
|
||||||
AddCodeLine ("jsr boolult");
|
AddCodeLine ("jsr boolult");
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
/* Signed compare */
|
||||||
|
if ((val & 0xFF) == 0) {
|
||||||
|
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
||||||
|
AddCodeLine ("jsr boollt");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CF_LONG:
|
case CF_LONG:
|
||||||
@@ -3426,26 +3444,30 @@ void g_le (unsigned flags, unsigned long val)
|
|||||||
*/
|
*/
|
||||||
if (flags & CF_CONST) {
|
if (flags & CF_CONST) {
|
||||||
|
|
||||||
/* <= is not very effective on the 6502, so try to convert
|
|
||||||
* it into < if the value is in a valid range.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Look at the type */
|
/* Look at the type */
|
||||||
switch (flags & CF_TYPE) {
|
switch (flags & CF_TYPE) {
|
||||||
|
|
||||||
case CF_CHAR:
|
case CF_CHAR:
|
||||||
if (flags & CF_FORCECHAR) {
|
if (flags & CF_FORCECHAR) {
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
|
/* Unsigned compare */
|
||||||
if (val < 255) {
|
if (val < 255) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
|
/* Use < instead of <= because the former gives
|
||||||
|
* better code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)(val+1));
|
||||||
AddCodeLine ("jsr boolult");
|
AddCodeLine ("jsr boolult");
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
AddCodeLine ("jsr boolule");
|
AddCodeLine ("jsr boolule");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
/* Signed compare */
|
||||||
if (val < 127) {
|
if (val < 127) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
|
/* Use < instead of <= because the former gives
|
||||||
|
* better code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)(val+1));
|
||||||
AddCodeLine ("jsr boollt");
|
AddCodeLine ("jsr boollt");
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
@@ -3458,18 +3480,27 @@ void g_le (unsigned flags, unsigned long val)
|
|||||||
|
|
||||||
case CF_INT:
|
case CF_INT:
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
unsigned L = GetLocalLabel();
|
/* Unsigned compare */
|
||||||
const char* Name = "boolule";
|
|
||||||
if (val < 65535) {
|
if (val < 65535) {
|
||||||
++val;
|
/* Use < instead of <= because the former gives
|
||||||
Name = "boolult";
|
* better code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
g_lt (flags, val+1);
|
||||||
|
} else {
|
||||||
|
unsigned L = GetLocalLabel();
|
||||||
|
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
||||||
|
AddCodeLine ("bne %s", LocalLabelName (L));
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
|
g_defcodelabel (L);
|
||||||
|
AddCodeLine ("jsr %s", "boolule");
|
||||||
}
|
}
|
||||||
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
|
||||||
AddCodeLine ("bne %s", LocalLabelName (L));
|
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
|
||||||
g_defcodelabel (L);
|
|
||||||
AddCodeLine ("jsr %s", Name);
|
|
||||||
return;
|
return;
|
||||||
|
} else {
|
||||||
|
/* Signed compare */
|
||||||
|
if (val < 32767) {
|
||||||
|
g_lt (flags, val+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -3509,34 +3540,36 @@ void g_gt (unsigned flags, unsigned long val)
|
|||||||
*/
|
*/
|
||||||
if (flags & CF_CONST) {
|
if (flags & CF_CONST) {
|
||||||
|
|
||||||
/* > is not very effective on the 6502, so try to convert
|
|
||||||
* it into >= if the value is in a valid range.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Look at the type */
|
/* Look at the type */
|
||||||
switch (flags & CF_TYPE) {
|
switch (flags & CF_TYPE) {
|
||||||
|
|
||||||
case CF_CHAR:
|
case CF_CHAR:
|
||||||
if (flags & CF_FORCECHAR) {
|
if (flags & CF_FORCECHAR) {
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
/* If we have a compare > 0, we will replace it by
|
|
||||||
* != 0 here, since both are identical but the latter
|
|
||||||
* is easier to optimize.
|
|
||||||
*/
|
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
/* If we have a compare > 0, we will replace it by
|
||||||
|
* != 0 here, since both are identical but the
|
||||||
|
* latter is easier to optimize.
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
AddCodeLine ("jsr boolne");
|
AddCodeLine ("jsr boolne");
|
||||||
} else if (val < 255) {
|
} else if (val < 255) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
|
/* Use >= instead of > because the former gives
|
||||||
|
* better code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)(val+1));
|
||||||
AddCodeLine ("jsr booluge");
|
AddCodeLine ("jsr booluge");
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
AddCodeLine ("jsr boolugt");
|
AddCodeLine ("jsr boolugt");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (val < 127) {
|
if (val < 127) {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val+1);
|
/* Use >= instead of > because the former gives
|
||||||
AddCodeLine ("jsr boolge");
|
* better code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)(val+1));
|
||||||
|
AddCodeLine ("jsr boolge");
|
||||||
} else {
|
} else {
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
AddCodeLine ("jsr boolgt");
|
AddCodeLine ("jsr boolgt");
|
||||||
@@ -3548,29 +3581,36 @@ void g_gt (unsigned flags, unsigned long val)
|
|||||||
|
|
||||||
case CF_INT:
|
case CF_INT:
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
/* If we have a compare > 0, we will replace it by
|
/* Unsigned compare */
|
||||||
* != 0 here, since both are identical but the latter
|
|
||||||
* is easier to optimize.
|
|
||||||
*/
|
|
||||||
if (val == 0) {
|
if (val == 0) {
|
||||||
|
/* If we have a compare > 0, we will replace it by
|
||||||
|
* != 0 here, since both are identical but the latter
|
||||||
|
* is easier to optimize.
|
||||||
|
*/
|
||||||
AddCodeLine ("stx tmp1");
|
AddCodeLine ("stx tmp1");
|
||||||
AddCodeLine ("ora tmp1");
|
AddCodeLine ("ora tmp1");
|
||||||
AddCodeLine ("jsr boolne");
|
AddCodeLine ("jsr boolne");
|
||||||
} else {
|
} else if (val < 65535U) {
|
||||||
|
/* Use >= instead of > because the former gives better
|
||||||
|
* code on the 6502 than the latter.
|
||||||
|
*/
|
||||||
|
g_ge (flags, val+1);
|
||||||
|
} else {
|
||||||
unsigned L = GetLocalLabel();
|
unsigned L = GetLocalLabel();
|
||||||
const char* Name = "boolugt";
|
|
||||||
if (val < 65535) {
|
|
||||||
++val;
|
|
||||||
Name = "booluge";
|
|
||||||
}
|
|
||||||
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
||||||
AddCodeLine ("bne %s", LocalLabelName (L));
|
AddCodeLine ("bne %s", LocalLabelName (L));
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
g_defcodelabel (L);
|
g_defcodelabel (L);
|
||||||
AddCodeLine ("jsr %s", Name);
|
AddCodeLine ("jsr %s", "boolugt");
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
/* Signed compare */
|
||||||
|
if (val < 32767) {
|
||||||
|
g_ge (flags, val+1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CF_LONG:
|
case CF_LONG:
|
||||||
@@ -3612,6 +3652,8 @@ void g_ge (unsigned flags, unsigned long val)
|
|||||||
/* Give a warning in some special cases */
|
/* Give a warning in some special cases */
|
||||||
if ((flags & CF_UNSIGNED) && val == 0) {
|
if ((flags & CF_UNSIGNED) && val == 0) {
|
||||||
Warning ("Condition is always true");
|
Warning ("Condition is always true");
|
||||||
|
AddCodeLine ("jsr return1");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look at the type */
|
/* Look at the type */
|
||||||
@@ -3640,14 +3682,30 @@ void g_ge (unsigned flags, unsigned long val)
|
|||||||
}
|
}
|
||||||
/* Direct code only for unsigned data types */
|
/* Direct code only for unsigned data types */
|
||||||
if (flags & CF_UNSIGNED) {
|
if (flags & CF_UNSIGNED) {
|
||||||
unsigned L = GetLocalLabel();
|
/* If the low byte is zero, we must only test the high
|
||||||
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
* byte. Or, citing Piotr Fusik:
|
||||||
AddCodeLine ("bne %s", LocalLabelName (L));
|
* Another interpretation: the code is effectively:
|
||||||
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
* if (ax >= 0xAB00) goto L2;
|
||||||
g_defcodelabel (L);
|
* It's equivalent to:
|
||||||
|
* if ((ax >> 8) >= 0xAB) goto L2;
|
||||||
|
*/
|
||||||
|
AddCodeLine ("cpx #$%02X", (unsigned char)(val >> 8));
|
||||||
|
if ((val & 0xFF) != 0) {
|
||||||
|
unsigned L = GetLocalLabel();
|
||||||
|
AddCodeLine ("bne %s", LocalLabelName (L));
|
||||||
|
AddCodeLine ("cmp #$%02X", (unsigned char)val);
|
||||||
|
g_defcodelabel (L);
|
||||||
|
}
|
||||||
AddCodeLine ("jsr booluge");
|
AddCodeLine ("jsr booluge");
|
||||||
return;
|
return;
|
||||||
}
|
} else {
|
||||||
|
/* Signed compare */
|
||||||
|
if ((val & 0xFF) == 0) {
|
||||||
|
AddCodeLine ("cpx #$%02X", (unsigned char) (val >> 8));
|
||||||
|
AddCodeLine ("jsr boolge");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CF_LONG:
|
case CF_LONG:
|
||||||
|
|||||||
Reference in New Issue
Block a user