Skip to content

stelem.i1 arithmetic emits operations in fixed order instead of preserving IL evaluation order #470

@jonathanpeppers

Description

@jonathanpeppers

Problem

The HandleStelemI1 method in IL2NESWriter.ArrayHandling.cs emits arithmetic operations in a hardcoded order rather than preserving the order from the original IL. This means expressions where the C# evaluation order differs from the hardcoded emit order will produce incorrect 6502 code.

Current behavior

Operations are emitted in a fixed sequence regardless of IL order:

Constant-index path (line ~1443): shr -> and -> add -> or -> sub
Call/variable-index paths (multiple locations): and -> sub -> add -> or or and -> add -> or -> sub

For example, (v | 0xF0) + 1 in C# compiles to IL: ldloc, ldc 0xF0, or, ldc 1, add. But the transpiler emits ADC #$01 before ORA #$F0 because ADD is hardcoded before OR, producing the wrong result (0xF6 instead of 0xF1 for v = 5).

Affected code paths

All arithmetic emission blocks in HandleStelemI1 share this pattern - at least 6 separate locations where if (hasAnd) ... if (hasAdd) ... if (hasOr) ... if (hasSub) chains appear with a fixed order:

  • Constant-index with local arithmetic (~line 1443-1456)
  • Call pattern with AND/SUB/ADD/OR (~line 1733-1750)
  • Multiply pattern (~line 1764-1768)
  • Self-referencing update (~line 1778-1792)
  • Cross-array copy (~line 1811-1825)
  • Two-locals arithmetic (~line 1832-1842)
  • Single-local value (~line 1867-1876)

Suggested approach

Instead of boolean flags (hasAdd, hasOr, etc.), record the operation sequence as an ordered list while scanning IL instructions. Then emit the 6502 operations in that recorded order. This preserves the C# evaluation semantics.

A simpler alternative: validate that the IL order matches the assumed emit order, and fall back to a non-optimized emission path (e.g., stack-based evaluation) when it doesn't match. This limits the blast radius of the fix.

Context

Discovered during review of PR #466 (adding OR support to stelem.i1). The issue predates that PR - AND, ADD, and SUB already had the same fixed-order behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions