1
0
mirror of https://github.com/cc65/cc65.git synced 2025-01-05 15:30:44 +00:00

Added support for changing divisions by negative power-of-2 denominators into bit shifts,

and fixed #169 including the case of -2147483648 which is negative but appears positive.
This commit is contained in:
acqn 2020-07-02 10:30:02 +08:00 committed by Oliver Schmidt
parent 30835e3d9d
commit 09bcff0862

View File

@ -2628,24 +2628,34 @@ void g_div (unsigned flags, unsigned long val)
unsigned DoShiftLabel, EndLabel; unsigned DoShiftLabel, EndLabel;
/* -Val truncated to the correct size */ /* Deal with negative values as well as different sizes */
int Negation;
unsigned long NegatedVal; unsigned long NegatedVal;
unsigned MaskedVal;
/* Do strength reduction if the value is constant and a power of two */ /* Do strength reduction if the value is constant and a power of two */
int p2; int p2;
if ((flags & CF_CONST) && (p2 = PowerOf2 (val)) >= 0) { if (flags & CF_CONST) {
/* Generate a shift instead */ Negation = (flags & CF_UNSIGNED) == 0 && (signed long)val < 0;
if (flags & CF_UNSIGNED) { NegatedVal = (unsigned long)-(signed long)val;
g_asr (flags, p2); p2 = PowerOf2 (Negation ? NegatedVal : val);
} else if (p2 > 0) { if (p2 >= 0) {
/* GitHub #169 - if abs(expr) < abs(val), the result is always 0 */ /* Generate a shift instead */
DoShiftLabel = GetLocalLabel (); if (flags & CF_UNSIGNED) {
EndLabel = GetLocalLabel (); g_asr (flags, p2);
NegatedVal = (unsigned long)-(signed long)val; return;
switch (flags & CF_TYPEMASK) { }
/* Generate a conditional shift instead */
if (p2 > 0) {
/* GitHub #169 - if abs(expr) < abs(val), the result is always 0 */
DoShiftLabel = GetLocalLabel ();
EndLabel = GetLocalLabel ();
MaskedVal = Negation ? val : NegatedVal;
switch (flags & CF_TYPEMASK) {
case CF_CHAR: case CF_CHAR:
if (flags & CF_FORCECHAR) { if (flags & CF_FORCECHAR) {
NegatedVal &= 0xFF; MaskedVal &= 0xFF;
AddCodeLine ("cmp #$00"); AddCodeLine ("cmp #$00");
AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel));
break; break;
@ -2653,13 +2663,13 @@ void g_div (unsigned flags, unsigned long val)
/* FALLTHROUGH */ /* FALLTHROUGH */
case CF_INT: case CF_INT:
NegatedVal &= 0xFFFF; MaskedVal &= 0xFFFF;
AddCodeLine ("cpx #$00"); AddCodeLine ("cpx #$00");
AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel));
break; break;
case CF_LONG: case CF_LONG:
NegatedVal &= 0xFFFFFFFF; MaskedVal &= 0xFFFFFFFF;
AddCodeLine ("ldy sreg+1"); AddCodeLine ("ldy sreg+1");
AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel)); AddCodeLine ("bpl %s", LocalLabelName (DoShiftLabel));
break; break;
@ -2667,27 +2677,38 @@ void g_div (unsigned flags, unsigned long val)
default: default:
typeerror (flags); typeerror (flags);
break; break;
}
g_save (flags);
g_le (flags | CF_UNSIGNED, MaskedVal);
AddCodeLine ("lsr a");
g_restore (flags);
AddCodeLine ("bcs %s", LocalLabelName (DoShiftLabel));
g_getimmed (flags | CF_ABSOLUTE, 0, 0);
g_jump (EndLabel);
g_defcodelabel (DoShiftLabel);
g_asr (flags, p2);
g_defcodelabel (EndLabel);
} }
g_save (flags);
g_le (flags | CF_UNSIGNED, NegatedVal); /* Negate the result if val is negative */
AddCodeLine ("lsr a"); if (Negation) {
g_restore (flags); g_neg (flags);
AddCodeLine ("bcs %s", LocalLabelName (DoShiftLabel)); }
g_getimmed (flags | CF_ABSOLUTE, 0, 0);
g_jump (EndLabel); /* Done */
g_defcodelabel (DoShiftLabel); return;
g_asr (flags, p2);
g_defcodelabel (EndLabel);
} }
} else {
/* Generate a division */ /* If we go here, we didn't emit code. Push the lhs on stack and fall
if (flags & CF_CONST) { ** into the normal, non-optimized stuff.
/* lhs is not on stack */ */
flags &= ~CF_FORCECHAR; /* Handle chars as ints */ flags &= ~CF_FORCECHAR; /* Handle chars as ints */
g_push (flags & ~CF_CONST, 0); g_push (flags & ~CF_CONST, 0);
}
oper (flags, val, ops);
} }
/* Generate a division */
oper (flags, val, ops);
} }