정태영

대강 생각을 해보니 정말 mmx 를 이용해서 빠르게 연산을 하려면 위와 같이 하는게 가장 빠르겠군요. 다만 레지스터를 많이 쓰고 완전히 asm 코딩을 해야한다는 게 조금 귀찮겠군요. ;)

위의 다이아그램에 있는 과정을 통해 4x4 matrix * 4x4 matrix 의 한 row 씩을 계산해낼 수 있습니다. 대강 계산했을 때 3배 이상의 속도 향상이 있을거라고 예상되던데 과연~

C:
  1. #include <stdio .h>
  2.  
  3. // A matrix
  4. short s1[16] = {
  5.      1234,
  6.      5678,
  7.      9, 10, 11, 12,
  8.     13, 14, 15, 16,
  9. };
  10.  
  11. // Transpose(B matrix)
  12. short s2[16] = {
  13.     17, 21, 25, 29,
  14.     18, 22, 26, 30,
  15.     19, 23, 27, 31,
  16.     20, 24, 28, 32
  17. };
  18.  
  19.  
  20. // Destination matrix
  21. short d[16];
  22.  
  23. int j, i;
  24. int main( int argc, char** argv ){
  25.  
  26.     __asm__("movq (s1), %mm0" );
  27.     __asm__("movq %mm0, %mm1" );
  28.     __asm__("movq %mm0, %mm2" );
  29.     __asm__("punpckhdq %mm2, %mm0" );
  30.     __asm__("punpckldq %mm2, %mm1" );
  31.  
  32.     __asm__("movq %mm0, %mm6");
  33.     __asm__("movq %mm1, %mm7");
  34.  
  35.     __asm__("movq (s2), %mm2" );
  36.     __asm__("mov $1, %eax" );
  37.     __asm__("movq s2(,%eax,8), %mm4");
  38.  
  39.     __asm__("movq %mm2, %mm3" );
  40.     __asm__("punpckhdq %mm4, %mm2");
  41.     __asm__("punpckldq %mm4, %mm3");
  42.  
  43.     __asm__("pmaddwd %mm2, %mm0");
  44.     __asm__("pmaddwd %mm3, %mm1");
  45.  
  46.     __asm__("paddw  %mm1, %mm0");
  47.  
  48.     __asm__("movq %mm6, %mm1");
  49.     __asm__("movq %mm7, %mm2");
  50.  
  51.     __asm__("mov $2, %eax" );
  52.     __asm__("movq s2(,%eax,8), %mm3" );
  53.     __asm__("mov $3, %eax" );
  54.     __asm__("movq s2(,%eax,8), %mm5");
  55.     __asm__("movq %mm3, %mm4" );
  56.     __asm__("punpckhdq %mm5, %mm3");
  57.     __asm__("punpckldq %mm5, %mm4");
  58.  
  59.     __asm__("pmaddwd %mm3, %mm1");
  60.     __asm__("pmaddwd %mm4, %mm2");
  61.     __asm__("paddw %mm2, %mm1");
  62.  
  63.     __asm__("packssdw %mm1, %mm0");
  64.     __asm__("movq %mm0, (d)");
  65.  
  66.     for( j = 0 ; j <4 ; j++ ){
  67.         for( i = 0 ; i <4 ; i++ ){
  68.             fprintf( stderr, "\t%3d", d[j*4+i] );
  69.         }
  70.         fprintf( stderr, "\n" );
  71.     }
  72.  
  73.     return 0;
  74.  
  75. }

코드로 옮기니 위와 같군요. 중간에 실수로 바이트오더를 헷갈려서 연산 결과가 뒤집혔었습니다. 정상적인 결과는 250 260 270 280 이 나와야 하는데 280 270 260 250 이 나와버리더군요. 아아 이거 다시 하고 싶은 작업이 아니네요;

흐흣 그래도 오랫만에 어셈블리 관련된 것들을 생각하고 있는데, 이것도 가끔 하니까 재밌네요. 근데 길어지면 할만하지 않다는거 -_-!

p.s) 전체 연산 코드를 보고 싶으시면 http://mytears.org/resources/mysrc/c/mmx.c 를 보시길 ;)

Tags: , , , , ,

This entry was posted on Sunday, January 14th, 2007 at 12:49 am and is filed under MyLife. You can follow any responses to this entry through the RSS 2.0 feed. You can leave a response, or trackback from your own site.

3 Responses to “matrix multiply with mmx #2”

  1. 이정훈 Says:

    아우~ 머리야~~ @_@

  2. Jenix Says:

    헉 -ㅇ- 저거 옴니 그래플로 그린게 더 대단해보이는 =_=;;

  3. 정태영 Says:

    jenix// 흐흐 먼저 연습장에 그려놓고 옮긴거라;; 흐흐 하지만 노가다 ㅠ_ㅠ

    막상 좀 더 생각해보니 pmaddsw 후에 paddw 를 두 번 해주고 packssdw 는 것도 가능하고, packssdw 를 두 번 해주고 pmaddsw 를 해주는 것도 가능한데 과연 어떤게 더 빠를까 고민이…

    아무래도 pack 은 거의 register 내에서의 값 이동 정도밖에는 안되고 add 는 그래도 산술연산이니까 pack 을 두 번 하고 add 를 한 번하는게 더 빠를거 같은데…

Leave a Reply