3

How does br_if work? I have read the docs but I didn't find anything about result value of br_if. I use WebAssembly Studio. I have this code and I don`t understand why it works so.

    (func $f (param $a i32) (result i32)
    (block (result i32)
      (br_if 0 (i32.const 5) (get_local $a))
    ))

I supposed that br_if execute only when conditional is not 0, but this function always return 5, even if param a is 0. I thought that the br_if optionally returns a value and tries to set value after block, but it does not compile. Please explain how it works.

    (func $f (param $a i32) (result i32)
    (block (result i32)
      (br_if 0 (i32.const 5) (get_local $a))
    )
    (i32.const 10))

Also I want to ask about returning value from blocks or loops, because in the docs I didn't see any mention of it. Can I optionally return a value from a loop or a block when a function returns a value in all branches?

Max Desiatov
  • 5,087
  • 3
  • 48
  • 56
  • 2
    Well structured questions get more attention on Stack-overflow. The issue here is that this is really 2 questions. I suggest you edit your post into 2 separate questions. More help here See here https://stackoverflow.com/help/how-to-ask – Nigel Savage Jan 28 '20 at 18:32
  • I agree @NigelSavage – Vendetta Feb 07 '20 at 18:21

1 Answers1

1

Your example uses folded instructions, which I didn't even know were a thing until I looked them up right now. Let's rewrite it into the more common syntax, and what's going on will become more clear:

(func $f (param $a i32) (result i32)
  block (result i32)
    i32.const 5
    local.get $a
    br_if 0
  end)

Your function takes one i32 and returns one i32. The entire body of the function is a nested block which also "returns" an i32 - i.e. when you branch to the end of that block, one value will be saved on top of the stack (aside from the 0 entries on the stack on entry into this block).

First 5 is pushed. Then $a, the function param, is pushed. Then we have the branch. The branch does do what you expect - it consumes the $a from the stack and branches to the end of the block if nonzero. However, the result afterwards is indistinguishable between the two cases: If the branch was taken, you'll be left with 5 on the stack. If the branch was not taken, you'll also be left with 5 on the stack.

After exiting the block, the single value on the stack (5) is what is returned.

This is the code I think you're looking for (one possible way):

(func $f (param $a i32) (result i32)
  local.get $a
  if (result i32)
    i32.const 5
  else
    i32.const 0
  end)

Edit: To answer the 2nd part, every instruction (or sequence of instructions) in Wasm has a statically-known effect on the stack, so there is no "optional return" from a block - if it returns a value in one path, it must return that type of value in all paths. This is why compiled code doesn't tend to have returned values on blocks at all, and uses conditional setting of locals instead.

Max Desiatov
  • 5,087
  • 3
  • 48
  • 56
D0SBoots
  • 705
  • 6
  • 18