Skip to content

Branches: block, br, br_if, br_table

Branching in WebAssembly is always relative to a labeled construct — never to a raw memory address. The br family of instructions targets the nesting level, not a line number. This makes the behaviour of br depend entirely on what kind of construct it targets.

A block is a forward-only group of instructions. When br $label targets a block, execution jumps to the instruction immediately after the block’s closing end. Think of it as a labeled break.

(module
(func (export "earlyExit") (result i32)
(block $b (result i32)
i32.const 42
br $b ;; exits the block; 42 is the block result
i32.const 99) ;; never reached
))

The (result i32) annotation on the block declares that the block leaves one i32 on the stack when it exits — either by falling through to end or by branching out with br.

The same br instruction behaves differently depending on what it targets:

flowchart LR
  A["block $b\n  ...body...\n  br $b"] --> B["jumps to END\nof block (forward)"]
  C["loop $l\n  ...body...\n  br $l"] --> D["jumps to START\nof loop (backward)"]
br in a block exits forward; br in a loop repeats backward

br_if $label pops an i32 condition from the stack. If it is non-zero the branch fires; otherwise execution continues with the next instruction. This is the idiomatic way to write a conditional early exit.

(module
(func (export "relu") (param $x i32) (result i32)
(block $done (result i32)
i32.const 0 ;; block result if we exit early
local.get $x
i32.const 0
i32.lt_s ;; x < 0?
br_if $done ;; if yes, exit block — 0 is already on stack
drop ;; discard the 0; x >= 0
local.get $x))) ;; return x

br_table takes a list of labels and a default. It pops an i32 index and jumps to the label at that index, or to the default if the index is out of range. It is the WAT equivalent of a switch statement.

(module
(func (export "describe") (param $n i32) (result i32)
(block $two
(block $one
(block $zero
local.get $n
br_table $zero $one $two $two) ;; index 0→$zero, 1→$one, ≥2→$two
i32.const 0) ;; $zero case: return 0
i32.const 1) ;; $one case: return 1
i32.const 2)) ;; $two case: return 2
WebAssembly
Where does `br $b` jump when `$b` is a `block` label?
What does `br_if $l` pop from the stack?
Which instruction implements a jump table in WAT?