codegen: lower if/else/else-if to WASM if instruction (closes #49)#60
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #49.
Cleave-compiled WASM modules can branch now. The v0.3 codegen rejected
ifstatements with the diagnostic "statement kind StmtIf not yet supported in v0 codegen"; this PR lifts that.What landed
Codegen
emit_iflowersif cond { ... },if cond { ... } else { ... }, andelse ifchains to WASM's nativeif 0x40 ... else ... endinstructionifat expression positionelse ifchains nest naturally (anAST_STMT_IFin the else slot just recurses intoemit_if)leaves_i32_on_stackhelper distinguishes comparison ops (already return i32 per WASM spec) from everything else (i64). Codegen emitsi32.wrap_i64(0xA7) only when the cond expression leaves i64, avoiding redundant coercions on comparison conditions.leaves_value_on_stackhelper that returns false for assignments. Used by bothemit_if_branch(don't drop after an assignment branch) andemit_fn_body(don't suppress the synthetic default-zero when the trailing expression is an assignment). This fixes a latent bug: a fn body ending inx = exprwas producing invalid WASM before this PR. No example hit the path so the v0.3 release had it silently broken.Opcodes added in
wasm.hWASM_OP_BLOCK 0x02,WASM_OP_LOOP 0x03,WASM_OP_IF 0x04,WASM_OP_ELSE 0x05,WASM_OP_I32_WRAP_I64 0xA7. New constantWASM_BLOCKTYPE_EMPTY 0x40.Tests (6 new, byte-level)
if 0x40substrings in the output)i32.wrap_i64i32.wrap_i64drop(the bug found during development)Bench
codegen_if_heavyexercises a 5-way else-if chain. ~249K ops/sec on M3 Pro, slowest of the codegen benches as expected.End-to-end demo
Compiles cleanly,
wasm-validate-clean, runs correctly:Debugging note worth flagging
When I first ran the smoke test,
wasm-validatefailed with "type mismatch in drop, expected [any] but got []" at offsets inside the if branches. Root cause: the parser puts a trailing assignment (the last statement of a block, no semicolon, sitting before}) intoblock.resultrather thanblock.stmts. My initialemit_if_branchtreatedbranch.result != NULLas "a value is on the stack" and emitted adrop. But an assignment expression leaves nothing on the stack (state_set is a void hostcall; local.set consumes its value). The fix isleaves_value_on_stack, which also fixed the latent v0.3 bug where a fn ending inx = exprproduced invalid WASM.The new CI gates (#59) would have caught this immediately.
wasm-validatefailed locally on the first compile. Worth recording the value of that gate.What this PR does NOT yet do
let x = if c { 1 } else { 2 }): parser does not acceptifat expression position; codegen is ready for it once the parser ismatchcodegen (Codegen: match statements #43)What unblocks next
Result::Err/Result::Okbranches need if-style control flow