mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 18:22:07 +00:00
Fix the FOR loop count formula (#1222)
This commit is contained in:
@@ -240,7 +240,11 @@ bool yywrap(void)
|
|||||||
|
|
||||||
// If this is a FOR, update the symbol value
|
// If this is a FOR, update the symbol value
|
||||||
if (contextStack->forName && fileInfo->iters[0] <= contextStack->nbReptIters) {
|
if (contextStack->forName && fileInfo->iters[0] <= contextStack->nbReptIters) {
|
||||||
contextStack->forValue += contextStack->forStep;
|
// Avoid arithmetic overflow runtime error
|
||||||
|
uint32_t forValue = (uint32_t)contextStack->forValue +
|
||||||
|
(uint32_t)contextStack->forStep;
|
||||||
|
contextStack->forValue = forValue >= 0 ? (int32_t)forValue
|
||||||
|
: -(int32_t)~forValue - 1;
|
||||||
struct Symbol *sym = sym_AddVar(contextStack->forName,
|
struct Symbol *sym = sym_AddVar(contextStack->forName,
|
||||||
contextStack->forValue);
|
contextStack->forValue);
|
||||||
|
|
||||||
@@ -513,9 +517,9 @@ void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
|||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
|
|
||||||
if (step > 0 && start < stop)
|
if (step > 0 && start < stop)
|
||||||
count = (stop - start - 1) / step + 1;
|
count = ((int64_t)stop - start - 1) / step + 1;
|
||||||
else if (step < 0 && stop < start)
|
else if (step < 0 && stop < start)
|
||||||
count = (start - stop - 1) / -step + 1;
|
count = ((int64_t)start - stop - 1) / -(int64_t)step + 1;
|
||||||
else if (step == 0)
|
else if (step == 0)
|
||||||
error("FOR cannot have a step value of 0\n");
|
error("FOR cannot have a step value of 0\n");
|
||||||
|
|
||||||
|
|||||||
19
test/asm/for-loop-count.asm
Normal file
19
test/asm/for-loop-count.asm
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
; `FOR value, start, stop, step` calculates an initial count of loop repetitions as follows:
|
||||||
|
; - if (step > 0 && start < stop) then count = (stop - start - 1) / step + 1
|
||||||
|
; - if (step < 0 && stop < start) then count = (start - stop - 1) / -step + 1
|
||||||
|
; - else count = 0
|
||||||
|
; The absolute vaue |stop - start| needs to be 64-bit for this formula to work.
|
||||||
|
; Results may be compared with Python range(start, stop, step).
|
||||||
|
|
||||||
|
MACRO test
|
||||||
|
PRINTLN STRFMT("FOR x, %d, %d, %d", \1, \2, \3)
|
||||||
|
FOR x, \1, \2, \3
|
||||||
|
PRINTLN " {08x:x} = {d:x}"
|
||||||
|
ENDR
|
||||||
|
PRINTLN " done {08x:x} = {d:x}"
|
||||||
|
ENDM
|
||||||
|
|
||||||
|
test $8000_0000, $6000_0000, $4000_0000 ; [-2147483648, -1073741824, 0, 1073741824]
|
||||||
|
test $8000_0000, $7000_0000, $4400_0000 ; [-2147483648, -1006632960, 134217728, 1275068416]
|
||||||
|
test $7fff_ffff, $8000_0000, $8000_0000 ; [2147483647, -1]
|
||||||
|
test $8000_0000, $ffff_ffff, $8000_0000 ; []
|
||||||
2
test/asm/for-loop-count.err
Normal file
2
test/asm/for-loop-count.err
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
warning: for-loop-count.asm(19) -> for-loop-count.asm::test(12): [-Wbackwards-for]
|
||||||
|
FOR goes backwards from -2147483648 to -1 by -2147483648
|
||||||
18
test/asm/for-loop-count.out
Normal file
18
test/asm/for-loop-count.out
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
FOR x, -2147483648, 1610612736, 1073741824
|
||||||
|
80000000 = -2147483648
|
||||||
|
c0000000 = -1073741824
|
||||||
|
00000000 = 0
|
||||||
|
40000000 = 1073741824
|
||||||
|
done 80000000 = -2147483648
|
||||||
|
FOR x, -2147483648, 1879048192, 1140850688
|
||||||
|
80000000 = -2147483648
|
||||||
|
c4000000 = -1006632960
|
||||||
|
08000000 = 134217728
|
||||||
|
4c000000 = 1275068416
|
||||||
|
done 90000000 = -1879048192
|
||||||
|
FOR x, 2147483647, -2147483648, -2147483648
|
||||||
|
7fffffff = 2147483647
|
||||||
|
ffffffff = -1
|
||||||
|
done 7fffffff = 2147483647
|
||||||
|
FOR x, -2147483648, -1, -2147483648
|
||||||
|
done 80000000 = -2147483648
|
||||||
Reference in New Issue
Block a user