Skip to content

Conditionals: if, else, and select

WebAssembly’s if construct is both a control-flow branch and an expression. It pops an i32 condition from the stack, executes one of two arms, and — if given a result type — leaves a value on the stack. This makes if feel more like a ternary operator than a traditional if statement.

if pops the top i32. A non-zero value executes the then arm; zero executes the optional else arm. The construct ends with end.

(module
(func (export "sign") (param $x i32) (result i32)
local.get $x
i32.const 0
i32.gt_s ;; x > 0?
if (result i32)
i32.const 1 ;; then: return 1
else
i32.const -1 ;; else: return -1
end))

The (result i32) annotation declares that the if expression leaves one i32 on the stack regardless of which arm executes. Both arms must leave the same number and types of values.

When the condition is purely for side effects — for example calling an imported function — you can omit the result type:

(module
(func (export "clampNeg") (param $x i32) (result i32)
local.get $x
i32.const 0
i32.lt_s
if
i32.const 0
local.set $x ;; clamp $x to 0 if negative
end
local.get $x))

Here the if has no result; it just conditionally updates a local.

select is a compact alternative to if for simple value choices. It pops three values: condition, val_if_false, val_if_true (in push order: push true-val, push false-val, push condition). It pushes the chosen value. No branch is taken — the CPU evaluates both values before the select.

(module
(func (export "minVal") (param $a i32) (param $b i32) (result i32)
local.get $a ;; val if condition is true ($a <= $b)
local.get $b ;; val if condition is false
local.get $a
local.get $b
i32.le_s ;; condition: a <= b?
select)) ;; choose $a if true, $b if false
WebAssembly
What does `if` pop to decide which branch to take?
What is `select` in WAT?
What keyword closes an `if` block in WAT?