loop
allows code to be executed repeatedly. It creates a block so you cannot see existing values of the stack. You can declare the result type. If not, remember to empty the new stack before leaving the block.
The difference from if
or block
is, when branching to a loop
, you branche to the control flow to the beginning of loop
, not the end
. For example, if you want to print 1 to 10:
(module
(import "env" "log" (func $log (param i32)))
(func $main
(local $i i32)
(set_local $i (i32.const 1)) ;; i = 1
loop $LOOP
(i32.le_s (get_local $i) (i32.const 10)) ;; i <= 10
if
get_local $i
call $log
(set_local $i ;; i = i + 1
(i32.add (get_local $i) (i32.const 1)))
br $LOOP
end
end
)
(start $main)
)
Without br $LOOP
, loop
won't execute code repeatedly. If you want to create an infinite loop, the code would be:
loop
br 0
end
Let's write something useful. For example, print the greatest common divisor (gcd) of 30 and 12.
(module
(import "env" "log" (func $log (param i32)))
(func $main
(local $m i32) (local $n i32) (local $r i32)
(set_local $m (i32.const 30)) ;; m = 30
(set_local $n (i32.const 12)) ;; n = 12
loop $LOOP
(i32.ne (get_local $n) (i32.const 0)) ;; n != 0
if
(set_local $r ;; r = m % n
(i32.rem_s (get_local $m) (get_local $n)))
(set_local $m (get_local $n)) ;; m = n
(set_local $n (get_local $r)) ;; n = r
br $LOOP
end
end
get_local $m
call $log
)
(start $main)
)
The following code computes and prints the 10th Fibonacci numbers.
(module
(import "env" "log" (func $log (param i32)))
(func $main
(local $n i32) ;; nth
(local $a i32) (local $b i32)
(local $i i32) (local $tmp i32)
(set_local $n (i32.const 10)) ;; n = 10
(i32.or ;; n == 0 || n == 1
(i32.eqz (get_local $n))
(i32.eq (get_local $n) (i32.const 1))
)
if
get_local $n
call $log
else
(set_local $b (i32.const 1)) ;; b = 1
(set_local $i (i32.const 2)) ;; i = 2
loop
(i32.le_s (get_local $i) (get_local $n)) ;; i <= n
if
(set_local $tmp (get_local $b)) ;; tmp = b
(set_local $b ;; b = a + b
(i32.add (get_local $a) (get_local $b)))
(set_local $a (get_local $tmp)) ;; a = tmp
(set_local $i ;; i = i + 1
(i32.add (get_local $i) (i32.const 1)))
br 1
end
get_local $b
call $log
end
end
)
(start $main)
)