Clang 是否为 WebAssembly 的 memory.fill 和 memory.copy 提供内在函数?

Does Clang provide intrinsics for WebAssembly's memory.fill and memory.copy?

我正在用 C 语言开发 WebAssembly 模块,并一直在尝试使用 WebAssembly specmemory.copy 中定义的指令。

我知道 Clang (v11.1.0) 已经 supports other memory-related wasm intrinsics__builtin_wasm_memory_size__builtin_wasm_memory_grow,但我一直很难弄清楚它是否支持 memory.fillmemory.copy.

我不太熟悉 Clang/LLVM 的内部工作原理,但在一些地方似乎暗示了对这些说明的引用 [1] [2](除非我误解了某些内容)。

我尝试使用 __builtin_memcpy__builtin_memset:

__attribute__((export_name("memcpy")))
void memcpy_test(void* mem_dst, void* mem_src) {
    __builtin_memcpy(mem_dst, mem_src, 128);
}

__attribute__((export_name("memset")))
void memset_test(void* mem_src) {
    __builtin_memset(mem_src, 0, 128);
}

编译,但对 __builtin_memcpy__builtin_memset 的调用在程序集中被替换为导入函数:

...
  (import "env" "memcpy" (func $memcpy (type $t0)))
  (import "env" "memset" (func $memset (type $t0)))
  (func $__wasm_call_ctors (type $t1))
  (func $memcpy_test (type $t2) (param $p0 i32) (param $p1 i32)
    local.get $p0
    local.get $p1
    i32.const 128
    call $memcpy
    drop)
  (func $memset_test (type $t3) (param $p0 i32)
    local.get $p0
    i32.const 0
    i32.const 128
    call $memset
    drop)
...

此时我有点卡住了,这些内在函数似乎还不可用,但我对此并不肯定。

如果能得到任何帮助,我将不胜感激!

[快速说明:我目前对使用 emscripten 不感兴趣,因为我试图避免它附带的大量胶水代码。]

but the calls to __builtin_memcpy and __builtin_memset are replaced with imported functions in the assembly:

原因是这些指令不是核心 (MVP) WebAssembly 指令集的一部分,而是稍后添加到 bulk-memory proposal

需要明确选择后来的提案,因为存在您可能针对的给定 WebAssembly 引擎尚不支持它们的风险。可以肯定的是,您可以检查 my support table on webassembly.org.

最后,如果您已经选中此项,则可以通过 -mbulk-memory 标志在 Clang 中选择启用此功能。例如,启用此标志和优化

clang temp.c -mbulk-memory -O -c -o temp.wasm

这是我从上面的示例中得到的:

(module
  (type $t0 (func (param i32 i32)))
  (type $t1 (func (param i32)))
  (import "env" "__linear_memory" (memory $env.__linear_memory 0))
  (import "env" "__indirect_function_table" (table $env.__indirect_function_table 0 funcref))
  (func $memcpy_test (type $t0) (param $p0 i32) (param $p1 i32)
    (memory.copy
      (local.get $p0)
      (local.get $p1)
      (i32.const 128)))
  (func $memset_test (type $t1) (param $p0 i32)
    (memory.fill
      (local.get $p0)
      (i32.const 0)
      (i32.const 128)))
  (export "memcpy" (func $memcpy_test))
  (export "memset" (func $memset_test)))

这似乎是预期的结果。