程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> 關於C語言 >> Intel大坑之一:丟失的SSE2 128bit位移指令,馬航MH370??

Intel大坑之一:丟失的SSE2 128bit位移指令,馬航MH370??

編輯:關於C語言

緣由

  最近在寫一些字符串函數的優化,興趣使然,可是寫的過程中,想要實現 128bit 的按 bit 邏輯位移,遇到了一個大坑,且聽我娓娓道來。

 

邏輯位移

對於 MMX, SSE 的位移指令,我們很自然的想到:

邏輯左移:PSLLW/PSLLD/PSLLQ,Shift Packed Data Left Logical (壓縮邏輯左移)

邏輯右移:PSRLW/PSRLD/PSRLQ,Shift Packed Data  Right Logical (壓縮邏輯右移)

顧名思義,W 指的是Word(字),D 指的 DWORD (雙字),Q 指的是 QWORD (四字),PSLLW 實現的是按 Word 的分組邏輯左移,

PSLLD 是按 DWORD 的分組邏輯左移,PSLLQ 是按 QWORD 實現的分組邏輯左移,這一切看起來都很 OK 。

這裡以邏輯左移為例:

關於具體的邏輯左移指令的說明,可參考:

http://moeto.comoj.com/project/intel/instruct32_hh/vc256.htm

或者 http://x86.renejeschke.de/html/file_module_x86_id_259.html,

右移也是類似的,在此不再螯述。

 

問題來了

  我們要實現的是 128bit 的邏輯位移,SSE2 裡面有 PSLLDQ 指令,這裡 DQ 即是 Double QWORD 的意思,

這不正好是我們需要的 128bit 按 bit 位移嗎?No!我們來看看 Intel 的文檔:

PSLLDQ--Packed Shift Left Logical Double Quadword

http://moeto.comoj.com/project/intel/instruct32_hh/vc255.htm

截圖如下:

我們看到,很遺憾,SSE2 並沒有實現 128bit 的按 bit 位移,PSLLDQ 只能實現 128bit 的按 byte 位移,即最小位移量必須是一個 byte (即8個bit),這非常不科學。考慮到 Intel 並未真正實現 128bit 數據處理(SSE 大多數指令都只實現了最多 64bit 粒度的數據處理,例如一個雙精度浮點數是 64bit 的),好吧,我們認了,但是!!但是!!Intel 你沒搞錯吧,PSLLDQ 的操作數只支持 imm8,imm8 意味著什麼?imm8 是 8 位立即數的意思,那就是說我們只能在匯編裡寫死(常數),不能使用任何寄存器來做位移量。What the fu*K??

好吧,這我們也認了。。。CPU 是你設計的,我們拿你沒辦法。說句題外話,如果 PSLLDQ 支持 reg32, reg64 寄存器位移的話, 會方便很多,因為我們可以先用 PSLLDQ 位移足夠位數的按 Byte 位移,然後再用 PSLLQ 位移剩下的剩余量(這是後話,為什麼要這麼用,到後面你就知道),可是,現在這種方法都不行!!這個 imm8 徹底讓我蛋碎了。。。PSLLQ 對於128 bit 寄存器一次只能移 16 位(先破埂了),那麼意味這我們如果要用這種方法,要 if / jump 好幾次。。。

 

大坑開始

好吧,我們退而求其次,既然你不能實現 128 bit 的按 bit 位移,那我們分成兩個 64 bit 的位移來實現好了,無非是多一次判斷,多一次合並,雖然效率沒有直接128 bit 位移的高,但是苦於你沒實現嘛,只能這麼干了。。。
好吧,我們開始吧。。。。GO!!!好了,我們換成 PSLLQ 了,執行PSLLQ xmm0, 32 或 PSLLQ xmm0, ecx (這裡ecx的值為32),咦?xmm0怎麼全為0了??啊,怎麼回事??

我們回過頭來重新看看 intel 的文檔:

重點看兩個我用紅線框起來的,當 PSLLQ 作用於 64 bit 的寄存器時,我們看到是最大支持 COUNT = 64 位的位移(嚴格意義上講是 max = 63,這個不糾結了,習慣問題,下同);

但是當 PSLLQ 作用於 128 bit 寄存器時,奇怪的事情發生了,最大只支持 COUNT = 16 位的位移(嚴格意義上是15位),如上圖所示。

如果不是重新看 Intel 的文檔,如果不是調試中發現問題,誰能想到最多只能移15位???Intel 的腦袋是被門夾了嗎??Why??MMX 寄存器上都可以實現最多 63 位的位移, SSE 寄存器為什麼就不可以?雖然我們知道 MMX 寄存器和 SSE 寄存器是不一樣的,分開的,MMX 寄存器是借用 x87 浮點寄存器來實現 MMX 指令的,可是你在 MMX 寄存器上實現了 64 bit 的位移,為什麼在 128 bit 的 SSE 寄存器上卻只能移最多 15 位??你說難以實現,我認了,我不太懂為什麼那麼難,我們只能認了,可是你卻實現了 128 bit 的按 byte 位移的 PSLLDQ 指令,這又作何解釋??本來顧名思義,PSLLDQ 就來就應該是實現 128 bit 的按 bit 位移,限於歷史原因,這個沒實現我可以理解,可是你沒有理由在 PSLLQ 作用於 128 bit 的 SSE 寄存器時卻最多只能位移 15 位吧??這真的有那麼難嗎??真的難嗎????真的那麼難,你又是怎麼實現 PSLLDQ 的 128 bit 按 Byte 位移的??

 

尋求答案

帶著這些疑問,我們問了一下 Google 老先生,搜索“128 bit shift”,發現 N 多小伙伴都遇到過這個問題,例如:

Looking for sse 128 bit shift operation for non-immediate shift value

What is SSE !@#$% good for? #2: Bit vector operations

 

最後,Google老先生告訴了我們一個最好的解答,來自 Intel 的論壇,在這裡:

Missing instruction in SSE: PSLLDQ with _bit_ shift amount?

 

是這樣的,截圖如下:

解決之道

dddd

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved