为什么 clang 在以 wasm32 为目标时发出 i64 指令?

Why does clang emit i64 instructions when targeting wasm32?

我使用 clang --target=wasm32-unknown-wasi ... 将一个 Hello World C 程序编译成 WebAssembly。一切顺利,.wasm 文件可以在 运行 时间内像 wasmer 一样正确地 运行。

但是当我检查 .wasm 文件(.wat 格式)时,我发现了一些 i64 指令,例如:

(func $__lseek (type $t1) (param $p0 i32) (param $p1 i64) (param $p2 i32) (result i64)
    (local $l3 i32)
    global.get $g0
    i32.const 16
    i32.sub
    local.tee $l3
    global.set $g0
    block $B0
      block $B1
        local.get $p0
        local.get $p1
        local.get $p2
        i32.const 255
        i32.and
        local.get $l3
        i32.const 8
        i32.add
        call $__wasi_fd_seek
        local.tee $p0
        i32.eqz
        br_if $B1
        i32.const 0
        i32.const 70
        local.get $p0
        local.get $p0
        i32.const 76
        i32.eq
        select
        i32.store offset=3696
        i64.const -1
        local.set $p1
        br $B0
      end
      local.get $l3
      i64.load offset=8
      local.set $p1
    end
    local.get $l3
    i32.const 16
    i32.add
    global.set $g0
    local.get $p1)

看起来很奇怪:为什么 clang 在以 wasm32 为目标时会发出 i64 指令?

根据https://github.com/WebAssembly/wasi-libc/issues/158中的讨论,我认为这可能是因为在link期间引入了一些包含i64指令的wasi API。 我说的对吗?

感谢您的关注!

我看不出有什么不妥。 Targeting 32bits 意味着内存 addressing 是 32bits。由于这个原因,在内存存储指令之前,你只有 32 位指令(即偏移量和值是 i32)你在某个时候有这个:

i32.store offset=3696

这是隐式内存索引 0 中的存储(今天唯一可用的)。存储的值是 32 位整数,偏移量为 i32(在此之前计算 + 3696)。在这种情况下,偏移量 是您关心的,即 i32,它 首先计算偏移量,然后计算值。

WebAssembly 的 MVP 支持“开箱即用”的 64 位整数。这意味着您可以自由使用这些值,以及 f32 和 f64。然而,这是您程序中的值,MVP 仅支持 i32 内存寻址。就在最近 BitInt 成为 WebAssembly 中匹配 i64 的 JS 类型, memory64 post-MVP 正准备进入生产系统。

详细信息你有这个:

(; push 0 (i32 type) ;)
i32.const 0
(; stack depth from here = 1 ;)

(; push 70 (i32 type) ;)
i32.const 70
(; stack depth from here = 2 ;)

(; push the first parameter two times (that is of i32 type) ;)
local.get $p0
local.get $p0
(; stack depth from here = 4 ;)

(; push 76 (i32 type))
i32.const 76
(; stack depth from here = 5 ;)

(; check is 76 equal to $p0, pop 2, push 1 all i32 types ;) 
i32.eq
(; stack depth from here = 4 ;)

(; [t t i32] -> [t], i.e. pop 3, push 1, all i32 types ;)
select
(; stack depth from here = 2 ;)

(; [offset i32, value i32] -> [], pop 2, push zero ;)
i32.store offset=3696

(; stack depth 0 ;)

立即数 offset=3696 是一个偏移量,它将添加到堆栈的计算偏移量以接收 effective address 值将被准确写入的位置。