MMX開發文件 (轉)

worldblog發表於2007-12-12
MMX開發文件 (轉)[@more@] 

MMX開發文件:namespace prefix = o ns = "urn:schemas--com::office" />

I  MMX簡介

  的MMX™技術是對Intel體系結構(IA)指令集的擴充套件。該技術使用了單指令多資料技術(SIMD)技術,以並行方式處理多個資料元素,從而提高了多和通訊的執行速度。MMX™指令集增加了57條新的操作碼和一個新的64位四字資料型別。

MMX™技術提高了很多應用的,例如活動影像、視訊會議、二維圖形和三維圖形。幾乎每一個具有重複性和順序性整數計算的應用程式都可以從MMX™技術中受益。對於8位、16位和32位資料元素的處理,改善了程式的效能。一個MMX™指令可一次操作8個位元組,且在一個時鐘週期內完成兩條指令,也就是說,可在一個時鐘週期內處理16個資料元素。另外,為增強效能,MMX™技術為其它功能釋放了額外的週期。以前需要其它支援的應用程式,現在僅需軟體就能執行。更小的處理器佔用率給更高程度的併發技術提供了條件,在當今眾多的操作中這些併發技術得到了利用。在基於Intel的分析系統中,某些功能的效能提高了50%到400%。這種數量級的效能擴充套件可以在新一代處理器中得到體現。在軟體核心中,其速度得到更大的提高,其幅度為原有速度的三至五倍。

MMX的缺點:由於MMX的運算指令必須在資料配對整齊的時候才能使用,所以使用MMX指令要比普通的指令多餘許多分組配對的指令,如果運算不是特別的整齊的話,就要浪費大量的時間在資料的配對上,所以說MMX指令也不是萬能的,也有其很大的缺陷。同時MMX指令在處理16位資料的時候才能發揮最大的作用,處理8位資料要有一點技巧。而處理32位資料,MMX指令幾乎沒有什麼加速能力。(考慮分組耗時的話)

II  MMX基本指令集

  具體細節請參閱《INTEL 體系結構MMX技術程式設計師參考手冊》第五章 

2.1 複製指令

  movq:64位資料複製,如果8位對齊的話,是一個64位寫,否則2個32位寫。

  movd:32位資料複製,注意:如果從記憶體向MMX暫存器複製,MMX高32位清零!

2.2 分組指令

  分組指令是MMX特有的,所以對於它我們要特別的關注。分組指令基本上可以分為2類,一類是不帶符號緊縮的,一類是帶符號緊縮的。現在我們分別予以介紹:

①punpcklbw / punpcklwd / punpckldq (l表示低位分組,bw8位,wd16位,dq32位):它是簡單的將兩個MMX暫存器的低32位交錯組合為一個64位資料。所以它是不能將長資料轉換為短資料的。

②packuswb 將16位資料轉換為無符號的8位資料。所以可以將兩個MMX暫存器不交錯的合為一個64位資料。

③packsswb/packssdw 將32位-》16位,16位-》8位,都是有符號的資料。

2.3 運算指令

  加法運算指令:pad(w)(d):沒有越界保護的加法,當越界的時候僅僅丟棄超出範圍的高位位元,(b)(w)(d)分別為8,16,32位加法;paddsb(w):具有越界保護的有符號加法,當上溢的時候為0x7fff,下溢的時候為0x8000;padd(w):具有越界保護的無符號加法,當上溢的時候為0x7fff,下溢的時候為0x0。

  減法運算指令同上;add改為sub。

  乘法指令:pmullw  / pmulhw 是4個16位資料的乘法,pmullw中是結果的低16位,pmulhw是結果的高16位。pmaddwd 乘加指令。

2.4 邏輯指令,移位指令和EMMS指令

  細節參見《INTEL 體系結構MMX技術程式設計師參考手冊》。

III  MMX經典處理策略

①資料輸入輸出:

在輸入資料的時候,經典的處理方法是將一個陣列整個“Load”到MMX暫存器中。這樣簡單同時利用了MMX64位讀寫資料的能力,提高了效能。同樣在輸出的時候,也是將一個64位MMX暫存器中的資料內容整個“Store”到記憶體中。

如果實在是不能這樣處理的話,就要利用移位指令了。比如說將一個MMX內的4個16位資料分別複製到不同的記憶體變數(或者16位通用暫存器中)x1,x2,x3,x4,那麼可以這樣處理:

movd   eax,mm1

psrlq  mm1,32

movd   ebx,mm1

mov   x1,ax

mov   x2,bx

shr  eax,16

shr  ebx,16

mov  x3,ax

mov  x4,bx

可見如果不採用陣列形式的話,輸入輸出將十分的麻煩。

 

②資料分組以及求絕對值的方法等:

  細節請參閱《INTEL 體系結構MMX™ 技術開發者手冊》第五章   

IV  自定義組合指令

①八位無符號數的移位:

  在MMX指令集中是沒有8位資料的移位指令的,但是有的時候我們確實需要,所以可以用以下兩個指令來實現:

  psrlq  mm0,1

  pand  mm0,0x7f7f7f7f7f7f7f7f

②如何防止計算過程中越界:

  比如在計算的時候,我們有(x1+x2+1)>>1,這個時候x1+x2就會越界(8位資料),那麼我們就不得不使用替代了辦法,比如(x1>>1+x2>>1)這個處理是不精確的,在不需要很精確的場合,是可以使用的,但是如果結果差錯1都不可容忍的話,就要進行一點處理:

  pand  mm0,0x01010101010101  //保留資料的最後一位數

  pand  mm1,0x01010101010101  //保留資料的最後一位數

  por  mm0,mm1 

  paddusb  mmx,mm0  //修正資料

(x1>>2+x2>>2):這個處理是通用的

  pand  mm0,0x03030303030303  //保留資料的最後兩位數

  pand  mm1, 0x03030303030303  //保留資料的最後兩位數

  paddusb  mm0,mm1

  psrlq  mm0,2

  pand  mm0,0x3f3f3f3f3f3f3f3f

  paddusb  mmx,mm0

③符號擴充套件指令:

  mm0:*,*,A,B  =>  現在要符號擴充套件為 mm0:(A符號)A, (A符號)B

  movq  mm1,mm0 

pcgtm    mm1,0  //比較mm0,生成mm1:(A符號) (B符號)()()

punpcklwd  mm0,mm1

④分組指令

  除了基本的分組指令以外,我們還可以利用移位指令和pand por指令來實現分組的功能,移位主要是要產生0,這樣por mm0,mm1就可以將mm0和mm1合併了。

比如:mm0(*,*,A,B) mm1(0,0,C,D)  則

  psllq  mm0,32

  por  mm0,mm1  => (A,B,C,D) 當然這個例子我們可以用普通的分組指令實現,但是在某些複雜的處理中,這樣的處理是必須的。

總之,要靈活運用MMX的現有指令來實現自己需要的功能。

V  MMX心得

  使用MMX技術進行程式設計,目的就是要提高運算速度,所以,對於如何儘可能的提高程式碼的,我們是要特別關注的。這裡,我介紹一些需要注意的事項。

① 儘可能的提高記憶體訪問的容量,我們可以看看下面的程式碼:

  for (j=0; j

  {

  d[0] = s[0];

  d[1] = s[1];

  d[2] = s[2];

  d[3] = s[3];

  d[4] = s[4];

  d[5] = s[5];

  d[6] = s[6];

  d[7] = s[7];

  d[8] = s[8];

  d[9] = s[9];

  d[10] = s[10];

  d[11] = s[11];

  d[12] = s[12];

  d[13] = s[13];

  d[14] = s[14];

  d[15] = s[15];

  s+= lx2;

  d+= lx;

  }

 

__asm{

  pushf

    mov edx,d ptr h

  xor  ecx,ecx

  mov esi,dword ptr s

  mov edi,dword ptr d

  mov eax,lx2

  mov ebx,lx

AGAIN:

  movq  mm0,byte ptr [esi]

  movq  mm1,byte ptr [esi+8]

  movq  byte ptr [edi],mm0

  movq  byte ptr [edi+8],mm1

  add  esi,eax

  add  edi,ebx

  add  ecx,1

  cmp  ecx,edx

  jl  AGAIN

  emms

  popf

  }

 

僅僅將幾個8位的寫,改為64位的寫,測試得到速度提升了25%,同樣的道理,我們要儘可能的將幾個movq寫在一起,這樣可以提高5%左右的速度。原C程式碼的效率也是很高的,它不用陣列的【】【】來定址,而是將s+= lx2; 從而將二維陣列的定址改為一維陣列的定址。儘可能的減少定址的複雜度,這也是一種高效的辦法。 還有一點就是如果將原來的簡單賦值改為memcpy()的話,可以提高大約10%的速度。這也是提高了資料流通容量的關係。

 

② 一些要注意的地方:

1.  儘可能的使用static變數, 訪問這樣的變數是很快的=訪問立即數的速度

2.  由於只有一個mmx移位暫存器, (移位分組指令) 是不能配對的

3.  不要在eax使用完, 使用ax, 不要使用完一個mm1,就立即使用它

4.  可以這樣立即使用mm1, movq  mm2,mm1  movq mm1,mm3 (Z順序是可以的)

5.  (4個以上)movq儘可能的在一起, 前提是在一起的mov不要使用一樣的mmx暫存器

6.  mov eax, [esi] ([esi+2*eax]) 訪問定址的記憶體是特別的慢的

7.  同上 stow 也是很慢的 (mov cx,n;  l是很慢的,如果可能,要展開迴圈)

8.  儘可能的在暫存器中完成操作,不要去訪問記憶體

9.  用變數名訪問變數,尤其是static的,是很快.

10.  訪問定址的記憶體的速度下降 》 資料不對齊8位的速度下降 》 指令不配對的速度下降

11.  所以在傳統的程式碼的方法中,構造陣列,然後將運算變為查表的方法,有的時候在MMX技術內反而會降低速度。(這個時候,如果真的用查表有提升速度的話,建議採用段地址+偏移量的辦法)

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-992338/,如需轉載,請註明出處,否則將追究法律責任。

相關文章