On this page

Loops

Most algorithms repeat the same block of code over and over until some condition is met. These types of loops can be performed in WAT using a small number of instructions. They do look different compared to other programming languages but they are simple to understand and easy to use.

Loop

Repeating the same block of code is normally called looping, and therefore the WAT loop keyword is used to denote one of these sections of code, but it doesn't really work in the way you may think.

;; Create loop section
loop $name_of_loop_section
  ;; Do something
end
;; After loop section  

To look at this example, you may think that the execution will enter the loop, do something, and then return to the start of the loop again. This is not what happens however. Once the execution gets to the end of the loop, it will just continue moving on after it. It will not automatically return to the top of the loop.

To move back to the start of the section you need to call either the br or br_if instruction. The “br” part does not stand for “break” but for “branch”. These commands move the execution to the start of a loop block, it branches back up to the top, so that the inner part of the loop can be performed again.

;; Create loop section
loop $name_of_loop_section
  ;; Do something

  ;; We want to do it again
  br $name_of_loop_section
end  

The br instruction needs the name of the loop section, so it knows where to branch back to, where the next execution will be located at. In this example we enter the loop section, do something and then branch back to the top, to repeat the loop again (forever in this case).

The br_if instruction can only be used if the stack contains an i32 integer value that is non-zero. It will pop the value off the stack and if it is zone then it does nothing and moves on to the next instruction.

;; Create loop section
loop $name_of_loop_section
  ;; Do something

  ;; Push i32 value 1 onto the stack
  i32.const 1

  ;; Check if we need to loop again
  br_if $name_of_loop_section
end    

Here we enter the loop block, do something, and then push a condition value onto the stack. Following this is the br_if instruction, which pops the condition value off the stack, checks if it is non-zero, and if it is then it moves the execution up to the top of the loop section, ready to do something again. If the value is zero then it will move past the instruction and continue on with the next instruction.

Nested Loops

You will sometimes need to have a loop inside another loop. When branching to the start of the loop section you will need to make sure you are moving to the right parent loop location. To show how this is done we need to look at an example.

;; Create loop section 1
loop $loop_1
  ;; Create loop section 2
  loop $loop_2
    ;; Do something

    ;; Push i32 value 0 onto the stack
    i32.const 0

    ;; Check if we need to loop again
    br_if $loop_2

    ;; Push i32 value 1 onto the stack
    i32.const 1

    ;; Check if we need to loop again
    br_if $loop_1
  end
end    

In this example we have two loops, one inside the other. We have named each one differently, with the outer one called $loop_1 and the inner one named $loop_2. You can name the loops anyway you want.

As you can see, the branch instructions are given the name of the loop section they should jump to. In this example, the first br_if instruction will not branch, but the second one will, and will move the execution to the top of $loop_1.

The branch instructions can be used with numbers instead of labels. For example, the inner most loop is number 0 $loop_2 and the loop one level up from this is number 1 $loop_1. These numbers increase by one for each parent loop section. It can get too complicated using numbers instead of labels, so I recommend you always use labels for your loops and blocks.

Block

The block instruction is just like the loop instruction but instead of branching the execution to the top of the section, it moves it to the end.

;; Create block section
block $name_of_block_section
  ;; Do something

  ;; We want to stop and move past section
  br $name_of_block_section

  ;; Do something else (will not get here)
end

Here we create the block and move inside it, performing the first part within, but we then call the branch instruction, which sends the execution to the end of the block section. This will bypass everything inside the section that comes after the branch instruction.

;; Create block section
block $name_of_block_section
  ;; Do something

  ;; Push i32 value 1 onto the stack
  i32.const 1

  ;; Check if we need to branch to end of section
  br_if $name_of_block_section

  ;; If condition is not met then this will be done
end    

In this example we use the br_if instruction to see if we need to branch to the end of the block section. If the condition is not met then it will not branch and will just continue on to the next instruction. Once the execution gets to the end of the block it continues on, and will not move to the top of the block.

What you need to remember is, for loops the branch instructions move the execution to the top of the section, and for blocks, the branching moves to the end of the section. For loops the branch instruction is similar to the “continue” keyword in other programming languages, and for blocks they are similar to the “break” keyword.

Blocks can be nested just like loops can. You can nest different loops and blocks together as well if you want. You need to make all loop and block labels unique within each function.

For Each Example

Let's take a look at an example that puts all these parts together. In the below code we are adding up all the odd numbers together, between 0 and 99, to get a total amount.

(local $index i32)
(local $total i32)

;; Set starting value of $index
i32.const 0
local.set $index

;; for (var $index = 0; $index < 100; $index++)
loop $loop_index
block $block_index
  ;; Check if $index is odd
  local.get $index
  i32.const 1
  i32.and

  ;; If odd
  if
    ;; Add index to total
    local.get $total
    local.get $index
    i32.add
    local.set $total
  end

  ;; Check $index is over 100
  local.get $index
  i32.const 100
  i32.ge_s
  br_if $block_index

  ;; Increase $index
  local.get $index
  i32.const 0x01
  i32.add
  local.set $index

  ;; Loop again
  br $loop_index
end
end  

At the start we are declaring two local variables. For looping will use the $index integer, which will increase this from 0 to 100 for each cycle of the loop that it goes through. The $total integer will keep the total amount, the sum of all the odd numbers.

Before we start the loops we need to set the starting value of the $index variable to the value 0.

We will want to branch to the start of the loop, but we will also want to break out of the block after we have looped 100 times. To do this we have included both a loop and a block together. The order you do this does not matter. We are nesting the block inside the loop but we have written it so that it looks like it is on the same level. Both have a similar looking name too, so we can quickly see if we are branching the loop or the block section.

Inside the sections there are the looping tasks. The first thing we do is check if the $index is odd or not. If it is odd then its value is added to the total.

After this we want to check if the $index value has reached the 100 upper limit. This uses the br_if instruction, comparing it to 100, and if the condition is met then it will branch to the end of the $block_index section. This is the end of the block section and the end of the looping process.

If the index value is under the limit then it continues on within the loop section. The next part is to increase the $index value by one. The final instruction inside the loop section is to branch to the start of the $loop_index section, which moves the execution point to the start of the loop again.

After the loop has been performed 100 times the $total value will contain the result.

Stack

Within the loop or block section we may need to pop values off the stack that were pushed onto it beforehand. You may also need to push something onto the stack before exiting the section, so that it can be used afterwards. Let's take a look at what this could look like.

;; Push i32 value 10 onto the stack
i32.const 10

;; Create block section
block $name_of_block_section
  ;; Push i32 value 20 onto the stack
  i32.const 20

  ;; Add the 10 and 20 together
  i32.add
  
  ;; Set $total value
  local.set $total
end  

In this example we are trying to add the value pushed onto the stack before the block began, the value 10, to the value pushed onto the stack within the block, the value 20. It looks like it should work, but it will not compile, and you will end up with an error message.

;; Create block section
block $name_of_block_section
  ;; Push i32 value 20 onto the stack
  i32.const 20
end

;; Push i32 value 10 onto the stack
i32.const 10

;; Add the 10 and 20 together
i32.add

;; Set $total value
local.set $total    

This time we are pushing a value onto the stack inside the block section, exiting the block section, then pushing another value onto the stack, but this time outside the block section, and finally adding them together. Again, this will not compile, and you will get another error message.

If you want to bring in data from off the stack when you are inside the section, or if you want to send out values from within the section, by pushing them onto the stack, then you need to treat the section like a small internal function, with parameters and results. This is similar to how the stack is used with the if instruction.

;; Push i32 value 10 onto the stack
i32.const 10

;; Create block section
block $name_of_block_section (param i32)
  ;; Push i32 value 20 onto the stack
  i32.const 20

  ;; Add the 10 and 20 together
  i32.add

  ;; Set $total value
  local.set $total
end

We have changed the block line to include a param statement. This is saying that it expects there to be an i32 value on the stack before it enters the block section.

;; Create block section
block $name_of_block_section (result i32)
  ;; Push i32 value 20 onto the stack
  i32.const 20
end

;; Push i32 value 10 onto the stack
i32.const 10

;; Add the 10 and 20 together
i32.add

;; Set $total value
local.set $total

The block line has been changed with the result statement. This states that the block section will push an i32 value onto the stack before it exits.

You can declare any number of parameters of any data type. You can also declare, at the same time if needed, any number of results with any data types required.