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:
parent
30835e3d9d
commit
09bcff0862
@ -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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user