"i32" 类型的值在 WebAssembly 中是如何求值的?

How the value of type "i32" is evaluated in WebAssembly?

根据规范中的文本如下:

Note that the value types i32 and i64 are not inherently signed or unsigned. The interpretation of these types is determined by individual operators.

既然不知道传递的i32类型参数的符号,那么i32.add如何对这两个参数进行加法运算呢?如果我们将这个函数导出到 JavaScript,结果应该如何评估?例如,0xffffffff 可以计算为具有不同符号的不同数字(4294967295 或 -1)。

(module
  (func (export "addTwo") (param i32 i32) (result i32)
    local.get 0
    local.get 1
    i32.add))

WebAssembly 要求将 -a + b 写成 b - a

使用 WebAssembly Explorer,这个:

int add(int a, int b) { return a + b; }

编译为:

(i32.add(get_local )(get_local [=11=]))

同时(注意负数 -a):

int add(int a, int b) { return -a + b; }

编译成这个(注意 subtract 而不是 add):

(i32.sub(get_local [=13=])(get_local ))

加号无所谓。如果您有一些位 X,那么它们可以被解释为有符号值 S_X 或无符号值 U_X。重要的是两者之间的差异是 02^32,因为二进制补码的工作原理。

例如,如果X全为1,则S_X == -1U_X == 2^32 - 1。请注意差异是 2^32。如果X全为0那么两个值都是0,差就是0.

所以你可以写 S_X = U_X + D_X 其中 D_X 是差值,要么是 0 要么是 2^32XY 的有符号加法是

S_X + S_Y = U_X + D_X + U_Y + D_Y = U_X + U_Y

最后一步是重要的一步:我们可以忽略 D_* 值,因为它们是 2^32 的倍数,我们假设我们环绕 - 即更高的位超过 32 个被忽略。

并非所有操作都如此。例如,出于这个原因,除法有两个操作,有符号和无符号。但是加减乘法等等,不用在意符号。