loop construct


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)
)