Compiler assuming C clear when it isn't?
- Dominant language
- Scala
- Stars
- 279
- Forks
- 21
- PR merge metrics
- No merged PRs in 30d
Description
Millfork has been great for developing my homebrew NES game, and so far it's been totally stable, but either I messed something up or the compiler is getting a bit overeager with an optimization. In my collision detection routine, I have this code:
```c
level_idx = (lo(player_x >> 4) & $1f) | (word(player_y & $f0) << 1)
if (hi(vel_x) & $80 == 0) {
level_idx += 1
}
if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
k += 1
}
```
Using optimization level 8 (same thing happens with 4), I get this assembly:
```
;
;line:89:main.mfk
; level_idx = (lo(player_x >> 4) & $1f) | (word(player_y & $f0) << 1)
LDA player_x
STA __reg
LDA player_x + 1
LSR
ROR __reg
LSR
ROR __reg
LSR
LDA __reg
ROR
ALR #$3E
STA __reg
TXA
PHA
LDA __reg
PHA
LDA player_y
AND #$F0
PHA
ROL
ROL
AND #1
STA __reg + 1
PLA
ASL
STA __reg
PLA
ORA __reg
STA main$level_idx
PLA
ORA __reg + 1
STA main$level_idx + 1
;
;line:90:main.mfk
; if (hi(vel_x) & $80 == 0) {
BIT vel_x + 1
BMI .fi__00221
;
;line:91:main.mfk
; level_idx += 1
INC main$level_idx
BNE .in__00220
INC main$level_idx + 1
.in__00220:
;
;line:90:main.mfk
; if (hi(vel_x) & $80 == 0) {
.fi__00221:
;
;line:93:main.mfk
; if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
LDY main$level_idx
LDA main$level_idx + 1
ADC #3 ; THIS IS WHERE THE BUG IS
STA __reg + 1
STX __reg
LDA (__reg), Y
TAY
LDA solidity.array, Y
BNE .or__00223
LDA player_y
AND #$F
BEQ .fi__00222
LDY main$level_idx
LDA main$level_idx + 1
CLC
ADC #3
STA __reg + 1
LDA #$20
STA __reg
LDA (__reg), Y
TAY
LDA solidity.array, Y
BEQ .fi__00222
.or__00223:
;
;line:94:main.mfk
; k += 1
INX
;
;line:93:main.mfk
; if (solidity[level_shadow[level_idx]] || (player_y & $0f != 0 && solidity[level_shadow[level_idx+32]])) {
.fi__00222:
```
`level_shadow` is located at `$0300`, so the address computation optimization makes sense, but that `ADC` is causing a bug when carry is set from the most recent `ASL`. When I add a `CLC` explicitly, or use optimization level 2, the bug disappears. Did I forget something or did the optimizer?
Contributor guide
Research direction
Reproduce the shown collision-detection case with optimization level 8, then compare its generated assembly with optimization level 2 and with the explicit CLC variant. Focus on the level_shadow address computation at $0300 and the ADC shown after the preceding ASL; done means the optimized assembly preserves carry semantics and the reported case no longer misbehaves.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- scala
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100