Skip to content

Back-merge riina #11 — structured WASM control flow for selagi/ulang - #82

Merged
ib823 merged 5 commits into
mainfrom
claude/riina-backmerge-11
Aug 25, 2026
Merged

Back-merge riina #11 — structured WASM control flow for selagi/ulang#82
ib823 merged 5 commits into
mainfrom
claude/riina-backmerge-11

Conversation

@ib823

@ib823 ib823 commented Aug 24, 2026

Copy link
Copy Markdown
Owner

A fourth riina commit that landed while #81 was in flight. My earlier "the fork is closed" was premature — this is the correction.

ib823/riina main is now f20e7ba8a, not c83f0e0c9. I caught it because the mirror-safety check I ran before considering a force-push showed proof's loops_differential.rs was 250 lines smaller than riina's, which had no business being true after #81. That traced to a commit that did not exist when I first surveyed the divergence.

Had I trusted the earlier survey and run the normal sync path, this commit would have been destroyed.

What it does

The WASM backend refused every loop. emit_structured knew only forward if/else regions, so a back edge had no structure to map onto — it failed closed (REQ-78) rather than emit the one-shot shape that loops were introduced to fix. So after #8 made loops work in the interpreter and C, WASM still could not compile one.

It now emits a block wrapping a loop, condition re-tested inside the loop so it observes the body's writes, br_if to leave, br 0 for the back edge and lanjut, br 1 for putus. Depths come from a frame stack, so nesting and loop control from inside an if arm resolve to the right label.

Back edges are found by dominance over reachable blocks, not block order — and the commit is explicit that both halves are load-bearing: the lowerer allocates a loop's exit block before the body it follows, so putus branches to a lower index than the block it leaves. Index order would read that as a back edge and invent loops that are not there. Dominators are Cooper/Harvey/Kennedy; the set-of-dominators fixpoint was written first and measured 1.8× the cost of all other WASM emission on a ~2,400-block function.

It also fixes a second WASM-only silent wrong answer it uncovered: the lowerer typed every + result Int unless an operand was in the numeric tower, so string concatenation came out Ty::Int. WASM dispatches cetak/cetakln on the static type — its values are untagged, unlike C's runtime tags — so every cetakln("x=" + ke_teks(x)) sent a pointer through the integer path.

Verification

Cherry-picked cleanly onto main (no conflicts). The check that matters is three-backend agreement on a program exercising both fixes — a loop, a mutable local, and a string concatenation in the printed value:

biar ubah i = 0;
selagi i < 5 { cetakln("i=" + ke_teks(i)); i = i + 1; }
backend output
interpreter i=0 i=1 i=2 i=3 i=4
C i=0 i=1 i=2 i=3 i=4
WASM (wasmtime) i=0 i=1 i=2 i=3 i=4

Byte-identical. Before #11 the WASM column would have been a build refusal; before the concat fix it would have printed a pointer.

  • 3322 Rust tests, 0 failed (+4)
  • corpus holds at 97/172
  • clippy clean; audit-docs.sh 0 discrepancies, 0 warnings

The mirror is still not safe to force-push

riina/main is a moving target — it gained a commit during a single session's work. Until the mirror direction is settled, sync-public.sh should still only be run with --reconcile, and any future mirror push should be preceded by the same content check that caught this one rather than by a remembered survey.


Generated by Claude Code

claude and others added 3 commits August 24, 2026 02:13
riinac verify --full at a30830e: 3318 Rust tests, 0 clippy warnings, 331 .vo
compiled, 0 admits, 0 axioms — the tree with the riina back-merge in it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
The WASM backend refused every loop. `emit_structured` knew only forward
if/else regions, so a back edge had no structure to map onto; it failed
closed (REQ-78) rather than emit the one-shot shape that loops were
introduced to fix.

It now emits real structured control flow: a `block` wrapping a `loop`,
with the condition re-tested INSIDE the `loop` so it observes the body's
writes, `br_if` to leave, `br 0` for the back edge and `lanjut`, and
`br 1` for `putus`. Depths come from a frame stack, so nesting and loop
control from inside an `if` arm resolve to the right label.

Back edges are found by DOMINANCE over reachable blocks, not block order.
Both parts are load-bearing: the lowerer allocates a loop's exit block
BEFORE the body it follows, so `putus` branches to a lower index than the
block it leaves; and it leaves an unreachable block behind after a `putus`
that branches back into the middle of the loop it was cut out of. Index
order accepts both as back edges and invents loops that are not there.
Dominators are Cooper/Harvey/Kennedy (immediate-dominator array over
reverse postorder) — the set-of-dominators fixpoint was written first and
measured 1.8x the cost of all other WASM emission on a ~2,400-block
function, worsening quadratically.

Also fixes a WASM-only silent wrong answer this uncovered: the lowerer
typed every `+` result `Int` unless an operand was in the numeric tower,
so string concatenation came out `Ty::Int`. The concat was emitted
correctly, but WASM dispatches `cetak`/`cetakln` on the static type (its
values are untagged, unlike C's runtime tags), so it sent the result
pointer through the integer path — every `cetakln("x=" + ke_teks(x))`
printed a heap ADDRESS as a decimal number.

`loops_are_refused_by_the_wasm_backend` is replaced by four differential
tests asserting the opposite, and the four pre-existing loop tests gain a
WASM leg. `untuk` keeps a refusal test, retargeted at the reason that
actually blocks it (list literals, REQ-79). corpus_differential: 34 -> 35
dual-backend examples, all byte-equal.
The four tests riina's #11 adds move the count that 47 doc banners quote.
Re-derived by command.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
ib823 pushed a commit that referenced this pull request Aug 24, 2026
Metrics provenance stamp, rebuilt playground WASM, refreshed reports. Counts
unchanged. riina/main was NOT pushed — this chain used --reconcile throughout,
and riina/main is at f20e7ba8a, which carries a fourth commit (#11, structured
WASM control flow) that proof is still landing via PR #82.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
claude added 2 commits August 24, 2026 03:32
main moved during the #81 sync chain — metrics provenance and deploy artifacts.
The only conflict was website/public/metrics.json, generated content, resolved
to main's side and then RE-DERIVED rather than hand-picked. No source conflicts.

Re-derived on the merged tree, not carried over: 3322 tests, 47 banner docs
re-synced, doc/metrics parity test green, audit-docs 0 discrepancies and 0
warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
riinac verify --full on the merged tree: 3322 Rust tests, 0 clippy warnings,
331 .vo compiled, 0 admits, 0 axioms.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
@ib823
ib823 marked this pull request as ready for review August 25, 2026 15:44
@ib823
ib823 merged commit ee777d8 into main Aug 25, 2026
11 checks passed
ib823 pushed a commit that referenced this pull request Aug 25, 2026
The four tests riina's #11 adds move the count 47 doc banners quote.
Re-derived by command on main after the merge.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
ib823 pushed a commit that referenced this pull request Aug 25, 2026
Byproducts of scripts/deploy-website.sh — metrics provenance stamp, rebuilt
playground WASM, report timestamps. Derived counts unchanged.

riina main was again NOT pushed: it carries commit e71160270 (the OpenSSL wire
differential fix), which is back-merging via PR #83 and does not yet exist here.
This chain used --reconcile throughout; only gh-pages was updated.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
ib823 pushed a commit that referenced this pull request Aug 25, 2026
riinac verify --full at 5f2c631 — the tree with riina's structured WASM
control flow merged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
ib823 pushed a commit that referenced this pull request Aug 25, 2026
main moved during the #82 sync chain — the 3318 -> 3322 banner sync plus deploy
artifacts. 120 files conflicted, ALL generated content: metrics.json and the doc
banners quoting it (3322 on main vs 3323 here). No source conflicts; the
OpenSSL port-race fix is untouched.

Resolved to main's side and then RE-DERIVED rather than hand-picked, per Prime
Directive 8. Re-verified on the merged tree: 3323 tests / 0 failed, 47 banners
re-synced, audit-docs 0 discrepancies and 0 warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uu28z8CdRQ1SLzTv8yszth
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants