Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

4.6KB


story: E04-S04 owner: e04_control status: done started: 2026-11-09 depends-on: [E04-S03, E03-S03]

E04-S04 Claim

Intended change

Add src/compiler/flow.s, the control-flow layer above the scalar emitter: labels, absolute jumps for loop back edges, conditional branches with a fixed five-byte short/long encoding, calls that discard frame arguments, and prologue/epilogue helpers for the software-frame ABI. Add a counting mode to codegen.s so one pass measures a routine without writing the buffer and the next pass emits it; both passes must produce identical label offsets and lengths. The x128 fixture generates a nested routine (while, if/else, for, call, return), sizes it twice, verifies both branch encodings in memory, and executes it.

The story is limited to the emitter: parser-to-emitter wiring, method address assignment (sizing.s), and compiler pass 3 remain open and are recorded as remaining risk.

File area

  • src/compiler/flow.s, src/common/flow.inc (new)
  • src/compiler/codegen.s (counting mode), src/runtime/frames.s (frame_discard preserves A/X)
  • tests/codegen/control-test.s (new)
  • scripts/build-control-test.ps1, scripts/verify-control-test.ps1 (new)
  • docs/decisions.md, docs/architecture.md
  • planning/claims/E04-S04.md
  • generated files under build/

Acceptance evidence

  • Emits if, else, while, for, calls, and return: the generated routine runs with the expected mailbox signature A5 11 05 0A 04 5A 00 00 03 (status PASS, return 17, a 5, if/else path 10, i 4, long-branch result 5A, wrong path 0, zero sizing mismatches, both branch forms verified).
  • Pass-2 sizing matches emission: the fixture runs the same generator with FL_MODE_COUNT (label offsets recorded, no stores) and FL_MODE_EMIT, then compares every main-routine label offset and the total length; mismatches 0.
  • Long branches are correct: a conditional branch over 125 bytes of filler is patched as the inverted BEQ +3 / JMP, jumps over the wrong path (v_bad stays 0), and reaches the target (v_long is $5A).
  • Nested-control fixture executes expected mailbox signatures: while exits at 5, if/else takes the then path, for reaches 4 and sums 16, add(sum) returns 17 through the frame ABI.

Coordination notes

  • E04-S03 is done; this story uses its scalar emitter and adds the control transfer it deferred.
  • D131 records the emitter contract, including the long-form opcode inversion and the result-preserving call/return helpers.
  • frame_discard now preserves A/X; the earlier implementation left its count in A, which destroyed a callee's result during argument cleanup. The frame regression still passes.
  • Compiler pass 2/3 integration is not attempted here: sizing.s, method addresses, and parser statement emission remain the next backend story.

Work log

  • Added count mode to cg_put; cg_init clears it and fl_init sets it.
  • Added label/fixup tables (16 labels, 32 fixups), absolute JMP patching, and five-byte conditional branches. The long form inverts the branch opcode at patch time so a true condition falls through to the JMP.
  • Added fl_call/fl_call_byte/fl_call_word: JSR, save the result on the hardware stack, discard argument bytes, restore. Added fl_ret, fl_ret_byte, and fl_ret_word, preserving results across frame_leave.
  • Fixed an infinite filler loop in the fixture: the emit macros clobber X, so the filler counter moved to BSS.
  • Fixed the fixture's branch-offset capture: cg_here is a routine, so it must be called (jsr cg_here), not read as a variable. This was why the in-memory branch-form checks inspected the wrong byte.

Completion

  • Tests run:
    • scripts/verify-control-test.ps1
    • scripts/verify-frame-test.ps1 -Port 6541
    • scripts/verify-scalar-test.ps1 -Port 6542
  • Results: control PASS (4E 38 03 A5 00 00 00 00 11 05 0A 04 5A 00 00 03); frame PASS; scalar PASS with its unchanged 231-byte golden stream.
  • Files changed: src/compiler/flow.s, src/common/flow.inc, src/compiler/codegen.s, src/runtime/frames.s, tests/codegen/control-test.s, scripts/build-control-test.ps1, scripts/verify-control-test.ps1, docs/decisions.md, docs/architecture.md, this claim.
  • Remaining risks: parser statement emission and pass-2 address assignment are not wired yet; labels (16), fixups (32), and the 255-byte code buffer bound each routine; fl_branch targets must be forward (loops use fl_jmp); interface dispatch calls and void calls through the control layer are not separately exercised; the long-branch expansion adds three NOPs to short branches.

Powered by TurnKey Linux.