Как понять br_if в wasm?

Как работает br_if. Я читал документы, но ничего не нашел о результирующем значении br_if. Я использую https://webassembly.studio/. У меня есть этот код, и я не понимаю, почему он так работает.

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

Я предполагал, что br_if выполняется только тогда, когда условное значение не равно 0, но эта функция всегда возвращает 5, даже если параметр a равен 0. Я думал, что br_if является необязательным возвращаемым значением и пытается установить значение после блока, но оно не компилируется. Объясните, пожалуйста, как это работает.

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

Также я хочу спросить о возврате значения из блоков или циклов, потому что в документах я не видел ни одного предложения об этом. Могу ли я опционально возвращать значение из цикла или блока, когда функция возвращает значение во всех ветвях?

1 ответ

В вашем примере используются свернутые инструкции , о которых я даже не знал, пока не посмотрел их прямо сейчас. Давайте перепишем его в более распространенном синтаксисе, и станет понятнее, что происходит:

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

Ваша функция принимает один i32 и возвращает один i32. Все тело функции представляет собой вложенный блок, который также «возвращает» i32, т. е. когда вы переходите к концу этого блока, одно значение будет сохранено на вершине стека (кроме 0 записей в стеке при входе). в этот блок).

Первые 5 нажаты. Затем вводится параметр функции. Тогда у нас есть филиал. Ветка делает то, что вы ожидаете - она ​​потребляетиз стека и переходит в конец блока, если он не равен нулю. Однако результат после этого неотличим между двумя случаями: если ветвь была принята, в стеке останется 5. Если ветвь не была взята, у вас также останется 5 в стеке.

После выхода из блока возвращается единственное значение в стеке (5).

Это код, который, я думаю, вы ищете (один из возможных способов):

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

Редактировать: Чтобы ответить на вторую часть, каждая инструкция (или последовательность инструкций) в WASM имеет статически известный эффект на стек, поэтому нет «необязательного возврата» из блока — если он возвращает значение по одному пути, он должен возвращать этот тип значения во всех путях. Вот почему скомпилированный код, как правило, вообще не возвращает значения для блоков, а вместо этого использует условную настройку локальных переменных.

Другие вопросы по тегам