是否可以在不加载到内存的情况下使用SIMD?我可以让它工作的唯一方法是将其值加载到内存中,然后从内存中读取它。这真的是与 SIMD 值交互的唯一方法吗?不能从堆栈中读写吗?
这是我可以编译的唯一解决方案,我是否遗漏了什么或者这是唯一的方法?
(module
(import "console" "log" (func $log (param i32 i32 i32 i32)))
(func $main
i32.const 0
v128.const i32x4 1 2 3 4
v128.store
i32.const 0
i32.load
i32.const 4
i32.load
i32.const 8
i32.load
i32.const 12
i32.load
call $log
)
(start $main)
(memory $memory (export "memory") 1)
)
(其他语言的解决方案也很有帮助,只要它们不需要内存来读写 SIMD 值。)
我是 SIMD 新手,因此我们将不胜感激!
我远非 Wasm SIMD 专家,但我尝试使用来自两个
i8x16.popcnt
参数的 i64
指令来计算总体计数(汉明权重):
(module
(func (export "v128.popcnt") (param i64 i64) (result i32)
(local $v v128)
;; cf. https://godbolt.org/z/GfzM9Y83d
local.get 0
i64x2.splat
local.get 1
i64x2.replace_lane 1
i8x16.popcnt
i16x8.extadd_pairwise_i8x16_u
i32x4.extadd_pairwise_i16x8_u
local.tee $v
i32x4.extract_lane 0
local.get $v
i32x4.extract_lane 1
local.get $v
i32x4.extract_lane 2
local.get $v
i32x4.extract_lane 3
i32.add
i32.add
i32.add))
使用如下测试程序将其插入https://webassemble.github.io/wabt/demo/wat2wasm/
const wasmInstance =
new WebAssembly.Instance(wasmModule, {});
const popcnt = wasmInstance.exports['v128.popcnt'];
const uint64max = 0xFFFF_FFFF_FFFF_FFFFn;
console.log(popcnt(uint64max, uint64max - 1n));
确实产生了预期的结果(在本例中为 127)。正如 @ovinus-real 所建议的,这是 replace_lane
的组合,以向量形式获取数据,然后
extract_lane
再次将其返回。无需记忆!也就是说,除了功能之外,我不能保证手头的权衡,例如是使用
splat
和一个
replace_lane
更好,还是使用
v128.const 0
和两个
replace_lane
更好?就进一步的指针而言:使用
--print-wasm-code
arg 在节点中运行该 js 测试程序会生成在我的平台上生成的程序集的列表,并通过添加
for (let i = 0; i < 100_000; i++) popcnt(0n, 0n)
来“预热”它,使优化编译器参与其中产生另一个列表。我想 x86 SIMD 专家可能会查看这些内容并进行一些有针对性的基准测试来评估不同的选项。至少,“如何使这个特定于平台的指令序列更有效地使用平台”是一个比“如何使这个独立于平台的指令序列在许多不同平台上以最佳方式工作”有更多现成答案的问题。