Skip to content

Optimized path: br_if to a forward block end still unresolved for if/else and sequential-block shapes (#483 class, broader) #500

Description

@avrabe

Summary

#483 fixed block+br_if branch resolution for a single forward block (and a simple nested block + br). A multi-modal sweep of optimized-path (non---relocatable) control-flow shapes shows the bug class is broader: an if/else lowered as nested block+br_if+br, and two sequential blocks, both still emit the conditional branch as an unpatched offset-0 placeholder (bne.n encoding 0xD100) — so br_if lands mid-block, skips the guarded address-materialization, and stores to a garbage address. The --relocatable direct path is unaffected.

These were NOT covered by #483's differential (which exercised only the single-block repro and a light nested case), so the targeted fix passed while these shapes remained broken.

Repro A — if/else (nested block + br_if + br)

(func (export "ifelse") (param $c i32)
  (block $end
    (block $else
      (br_if $else (i32.eqz (local.get $c)))
      (i32.store (i32.const 4) (i32.const 100))
      (br $end))
    (i32.store (i32.const 4) (i32.const 200))))

synth compile … -b arm --target cortex-m4 --all-exports, then arm-none-eabi-objdump -d -M force-thumb:

 d2:	d100      	bne.n	d6        ; offset 0 = UNRESOLVED placeholder
 d4:	2504      	movs	r5, #4     ; address const for store-100 — SKIPPED when br_if taken
 d6:	2664      	movs	r6, #100   ; br_if lands here → stores 100 at garbage r5

ifelse(0) (br_if taken → should store 200 at addr 4) executes both stores to garbage addresses under unicorn vs wasmtime {4:200}.

Repro B — two sequential blocks

(func (export "seqblocks") (param $a i32) (param $b i32)
  (block $b1 (br_if $b1 (i32.eqz (local.get $a))) (i32.store   (i32.const 8)  (i32.const 11)))
  (block $b2 (br_if $b2 (i32.eqz (local.get $b))) (i32.store16 (i32.const 12) (i32.const 22))))

Both bne.n are 0xD100 (offset-0 placeholders). seqblocks(0,1) writes 11 (should have skipped it) to a wrong address.

Root-cause direction

The br_if target id is not present in ir_to_arm_idx at resolution time (line ~5380), so the placeholder is never patched — same mechanism as #483, but the End-label fix (End labels with the closed block's id) does not cover these shapes. Suspects: the block+br_if early-exit pattern matcher (optimizer_bridge.rs ~line 391, "Pattern 3") partially matching and re-routing the lowering; or the id pushed by Block not matching what br_if computes when a store / br sits between the br_if and the block end across multiple/nested blocks.

Scope

Belongs to the patch-accreting-codegen class the VCR-* program (#242) replaces. Next gated fix: extend the End-label/branch-resolution handling to these shapes and add them to the block_brif_483 differential corpus. (A loop-with-locals fixture in the same sweep showed a resolved backward branch but a possibly-separate locals issue — tracking only the branch-resolution class here.)

Activity

  1. avrabe commented on Jun 25, 2026

    @avrabe
    ContributorAuthor

    [issue-hunt loop] Root-cause correction. Ruled out the Pattern-3 early-exit matcher (preprocess_wasm_ops, ~line 386): it only fires on the exact Block, val1, cond, BrIf(0), Drop, val2, End select-idiom (value + Drop, no stores), which neither repro matches. So these go through the normal block/br_if/End lowering, and the br_if target id is still absent from ir_to_arm_idx at resolution (placeholder left unpatched, bne.n = 0xD100).

    Notably seqblocks is the cleaner signal: its FIRST of two non-nested sequential blocks is unresolved, while #483's single-block init_branch resolves correctly — so the trigger is having a block followed by more top-level content (a second block / an outer block), not nesting depth per se. The #483 End-label fix (End labels with the closed block's id) is necessary but not sufficient for these shapes; the next gated fix needs to trace why end $b1's Label{b1.id} isn't landing in ir_to_arm_idx (or why br_if's computed target id diverges) when more ops follow the block. Belongs to #242.

  2. added a commit that references this issue on Jul 8, 2026
  3. added 3 commits that reference this issue on Jul 8, 2026
  4. added 4 commits that reference this issue on Aug 20, 2026
  5. added 2 commits that reference this issue on Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions