簡體   English   中英

WebAssembly 中的位旋轉

[英]Bit rotations in WebAssembly

我在 TypeScript 中有一段熱代碼,它做了一堆算術——特別是幾個 32 位旋轉。 例如,

  let a = t << 16 | t >>> 16; // rotate left by 16 bits
  let b = t << 12 | t >>> 20; // rotate left by 12 bits
  let c = t << 8 | t >>> 24; // rotate left by 8 bits
  let d = t << 7 | t >>> 25; // rotate left by 7 bits

我正在嘗試將包含這些操作的 function 移植到 WebAssembly 以獲得更好的性能,因為很多數學正是 WebAssembly 應該擅長的。 不幸的是,WebAssembly 版本最終給出了不正確的結果,我已經設法將錯誤縮小到精確的這些位旋轉操作。

現在,WebAssembly 有一個方便的i32.rotl操作碼,它應該自己替換雙移位和按位或全部,但是在例如t = 1634760805 (0x61707865) 的情況下,TypeScript 代碼給出的結果為 2019917000 (0x7665) ) 當旋轉 16 位時,對十六進制數字的簡單檢查表明是正確的。 但是,將這一操作轉移到 WebAssembly 會得到 512 的結果。

所以,我想也許對rotl操作有一些我不理解的地方,我嘗試直接將 double-shift-and-or 轉換為 WebAssembly ......它仍然產生 512 的結果。

我使用rotl操作碼的測試代碼如下所示:

  (func $rot (param $a i32) (param $r i32) (result i32)
    (local $xa i32)

    ;; x[a] = x[a] rotl r;
    (local.set $xa (i32.rotl (local.get $r) (i32.load (local.get $a))))
    (i32.store (local.get $a) (local.get $xa))
    (local.get $xa)
  )

它只是從 memory(由 $a 指向)中讀取一個 32 位值,將其旋轉 $r,將結果存儲回線性 memory 並返回它。

使用移位和按位或按位模擬rotl的版本如下所示:

  (func $rot (param $a i32) (param $r i32) (result i32)
    (local $xa i32)

    ;; x[a] = x[a] rotl r;
    (local.set $xa (i32.load (local.get $a)))
    (local.set $xa (i32.or
      (i32.shl   (local.get $r) (local.get $xa))
      (i32.shr_u (i32.sub (i32.const 32) (local.get $r)) (local.get $xa))))
    (i32.store (local.get $a) (local.get $xa))
    (local.get $xa)
  )

所以......關於出了什么問題的任何想法?

(我已經驗證了,是的,正確的起始值實際上是我期望它們在線性 memory 中的位置,既可以通過直接檢查 TypeScript/JavaScript 端的 memory 緩沖區,也可以使用真正基本的 WASM 調試(func $read (param $a i32) (result i32) (i32.load (local.get $a))) )

嗯,我想通了。 這一切都歸結為這個表達:

(i32.rotl (local.get $r) (i32.load (local.get $a)))

倒退。 結果是 arguments go 以其他順序:將其更改為:

(i32.rotl (i32.load (local.get $a)) (local.get $r))

使一切正常。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM