millfork icon indicating copy to clipboard operation
millfork copied to clipboard

Compiler assuming C clear when it isn't?

Open joshop opened this issue 2 years ago • 0 comments

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:

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?

joshop avatar Apr 01 '22 12:04 joshop