找回密码
 欢迎注册
楼主: 无心人

[擂台] x86上128位二进制乘法最快速算法征解

[复制链接]
 楼主| 发表于 2008-3-27 13:39:04 | 显示全部楼层
想到一个节约指令的拆解方法
假设数据在mm0
mm7=0
movq mm1, mm0
punpckhdq mm1, mm7  
punpckldq mm0, mm7
则分解mm0=mm1:mm0
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-27 14:46:54 | 显示全部楼层
void UInt128x128To256_SSE2_92F( UINT32 * const result,
                                const UINT32 * const left,
                                const UINT32 * const right )
{
        __asm
    {
        mov eax, [left]
                mov edx, [right]
        mov ecx, [result]
                movd mm0, [eax]
                pmuludq mm0, [edx] //mm0 = 0:0
                pxor mm7, mm7 //mm7 = 0
        movd [ecx], mm0
                punpckhdq mm0, mm7

                movd mm1, [eax]
                pmuludq mm1, [edx+4] //mm1=0:1
                movd mm2, [edx]
                pmuludq mm2, [eax+4] //mm2=1:0
                movq mm3, mm1
                punpckhdq mm3, mm7
        punpckldq mm1, mm7
                movq mm4, mm2
                punpckhdq mm4, mm7
                punpckldq mm2, mm7
                paddq mm0, mm1
                paddq mm0, mm2
                paddq mm3, mm4
        movd [ecx+4], mm0
        punpckhdq mm0, mm7
                paddq mm0, mm3

                movd mm1, [eax+4]
                pmuludq mm1, [edx+4] //mm1=1:1
        movd mm2, [eax]
                pmuludq mm2, [edx+8] //mm2=0:2
                movd mm3, [edx]
                pmuludq mm3, [eax+8] //mm3=2:0
        movq mm4, mm1
                punpckhdq mm4, mm7
                punpckldq mm1, mm7
                movq mm5, mm2
                punpckhdq mm5, mm7
                punpckldq mm2, mm7
                movq mm6, mm3
                punpckhdq mm6, mm7
                punpckldq mm3, mm7
                paddq mm0, mm1
                paddq mm4, mm5
                paddq mm0, mm2
                paddq mm4, mm6
                paddq mm0, mm3
                movd [ecx+8], mm0
                punpckhdq mm0, mm7
                paddq mm0, mm4
        
                movd mm1, [eax]
                pmuludq mm1, [edx+12] //mm1=0:3
                movd mm2, [eax+12]
                pmuludq mm2, [edx] //mm2=3:0
                movq mm4, mm1
                punpckhdq mm4, mm7
                punpckldq mm1, mm7
                movq mm5, mm2
                punpckhdq mm5, mm7
                punpckldq mm2, mm7
        paddq mm0, mm1
                paddq mm4, mm5
                paddq mm0, mm2
        
                movd mm1, [eax+4]
                pmuludq mm1, [edx+8] //mm1=1:2
                movd mm2, [edx+4]
                pmuludq mm2, [eax+8] //mm2=2:1
        movq mm5, mm1
                punpckhdq mm5, mm7
                punpckldq mm1, mm7
                movq mm6, mm2
                punpckhdq mm6, mm7
                punpckldq mm2, mm7
                paddq mm0, mm1
                paddq mm4, mm5
                paddq mm0, mm2
                paddq mm4, mm6
                movd [ecx+12], mm0
                punpckhdq mm0, mm7
                paddq mm0, mm4

               
                movd mm1, [eax+8]
                pmuludq mm1, [edx+8] //mm1=2:2
        movd mm2, [eax+4]
                pmuludq mm2, [edx+12] //mm2=1:3
                movd mm3, [edx+4]
                pmuludq mm3, [eax+12] //mm3=3:1
        movq mm4, mm1
                punpckhdq mm4, mm7
                punpckldq mm1, mm7
                movq mm5, mm2
                punpckhdq mm5, mm7
                punpckldq mm2, mm7
                movq mm6, mm3
                punpckhdq mm6, mm7
                punpckldq mm3, mm7
                paddq mm0, mm1
                paddq mm4, mm5
                paddq mm0, mm2
                paddq mm4, mm6
                paddq mm0, mm3
                movd [ecx+16], mm0
                punpckhdq mm0, mm7
                paddq mm0, mm4

                movd mm1, [eax+8]
                pmuludq mm1, [edx+12] //mm1=2:3
                movd mm2, [edx+8]
                pmuludq mm2, [eax+12] //mm2=3:2
                movq mm3, mm1
                punpckhdq mm3, mm7
        punpckldq mm1, mm7
                movq mm4, mm2
                punpckhdq mm4, mm7
                punpckldq mm2, mm7
                paddq mm0, mm1
                paddq mm0, mm2
                paddq mm3, mm4
        movd [ecx+20], mm0
        punpckhdq mm0, mm7
                paddq mm0, mm3

                movd mm1, [eax+12]
                pmuludq mm1, [edx+12]
                paddq mm0, mm1
                movq [ecx+24], mm0

                emms
    }
}
时间不理想
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-27 21:32:25 | 显示全部楼层
76有问题
        movq           [RESULT_REG+24], mm5
                psrlq           mm5, 32                        //carry
               
                //------保存最高DWORD
                movq           [RESULT_REG+28], mm5                        //mm3,中间结果
   =================================
                就是movq  [RESULT_REG+24],  mm5
                不知道后面两条啥意思?
                   另外最后一条应该是movd 如果写movq 存在内存溢出危险
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-27 22:30:59 | 显示全部楼层
完全采用SSE2指令的一个版本,指令数110条,比预期的指令少要多,仅仅比76楼少一条指令。这个版本全部使用XMM寄存器。解包主要采用pshufd指令来实现。尽管指令数不多,但却比采用我的另一个使用MMX寄存器的版本慢上好多(在PIV 2.6G上测试的结果).
   个人感觉,一次计算2组 32bit * 32bit 的SSE2指令并没有带来多大收益,就这个题目而言,使用MMX寄存器可能是一个好的选择。下面是完整的源代码。
  1. _declspec(naked)
  2. void UInt128x128To256_SSE2_94F( UINT32 * const result,
  3.                                 const UINT32 * const left,
  4.                                 const UINT32 * const right )
  5. // 使用XMM寄存器
  6. // 16次乘法,分4趟,
  7. // 操作数一律在xmm 寄存器中进行,每次乘法 计算2 组 32bit * 32 bit 乘法,每次加法 仅仅使用低64bit
  8. // 第1趟计算 left[] * right[0]
  9. // 第2趟计算 left[] * right[1]
  10. // 第3趟计算 left[] * right[2]
  11. // 第4趟计算 left[] * right[3]

  12. // 每趟的计算结果为 5 DWORD,最低位DWORD 直接存储到result, 前3趟的计算结果的高4个DWORD(中间结果)存储到一组寄存器

  13. // 寄存器的使用
  14. // 1. 中间结果 放入 xmm0,xmm1,xmm2,xmm3
  15. // 2。乘数  使用 xmm4
  16. // 2. 乘积1 使用 xmm5
  17. // 3. 乘积2 使用 xmm6
  18. // 4. 进位  使用 xmm7
  19. // 5. 掩码  依然使用xmm5, 和 乘积1 分时复用
  20. // 可以看到8个mmx寄存器全部派上用场

  21. {
  22. #define LEFT_REG        eax
  23. #define RIGHT_REG        edx       
  24. #define RESULT_REG        ecx

  25. #define T0_REG          xmm0
  26. #define T1_REG          xmm1
  27. #define T2_REG          xmm2
  28. #define T3_REG          xmm3

  29. #undef  MUL_REG
  30. #define MUL_REG                xmm4

  31. #undef  MASK_REG
  32. #define MASK_REG        xmm5

  33. #define PROD_1_REG        xmm5
  34. #define PROD_2_REG        xmm6
  35. #define CARRY_REG        xmm7

  36. //  记号 XX00, 表示当前 128bit 寄存器的 值状态,每个字符表示32bit, X表示有数,0表示这部分为0
  37. //        第1个字符bit0-bit31,  第2个表示bit32-bit63,
  38. //        第3个字符bit64-bit95, 最后1个字符表示bit96-bit127
  39. //  D0: 表示寄存器的 bit0-bit31
  40. //  D1: 表示寄存器的 bit32-bit63,        
  41. //  D2: 表示寄存器的 bit64-bit95,       
  42. //  D3: 表示寄存器的 bit96-bit127
  43. // -〉表示传送

  44.         __asm
  45.     {
  46.         mov                 RIGHT_REG, dword ptr[esp + 0Ch]   ;  right
  47.         mov                 LEFT_REG,  dword ptr [esp + 08h]   ; left
  48.         mov                 RESULT_REG, dword ptr[esp + 04h]   ; result
  49.         push                ebx
  50.         mov                ebx,0xffffffff                                        //置掩码,用来清除高位,仅仅保留低32bit
  51.      
  52.         //第1趟乘开始---
  53.         movq                MUL_REG,  qword ptr [RIGHT_REG]
  54.         pshufd                MUL_REG,  MUL_REG, 01000100b         // R[0] -> 0:3, R[1] -> 2:4

  55.         movdqu                PROD_1_REG, [LEFT_REG]                                // 将4个DWORD一次载入
  56.         pshufd                PROD_2_REG,        PROD_1_REG, 00110010b        // L[2:3] -> PROD_2_REG
  57.         pshufd                PROD_1_REG,        PROD_1_REG, 11011100b        // L[0:1] -> PROD_1_REG
  58.                
  59.         //-------- 第1,2次乘
  60.         pmuludq                PROD_1_REG, MUL_REG                // L[0:1] * R[0],  XXXX
  61.         movd                [RESULT_REG],PROD_1_REG        // store low32 bit of L0 * R[0]
  62.         psrldq              PROD_1_REG, 4                        // PROD_1_REG >>= 32, high 32 bit is full zero,shape XXX0
  63.         pshufd                CARRY_REG,         PROD_1_REG, 11111100b        // 将carry分解出来, X0000
  64.         psrldq              PROD_1_REG, 4                        // PROD_1_REG:[D0,D1]= L1*R[0],RROD_1_REG: XX00
  65.         paddq                PROD_1_REG, CARRY_REG        // PROD_1_REG:[D0,D1]= L1 * R[0] + carry, RROD_1_REG: XX00

  66.         //----插入第3,4次乘指令
  67.         pmuludq                PROD_2_REG, MUL_REG                //PROD_2_REG:[D0-D4]= L[2:3] * R[0],  PROD_2_REG:XXXX

  68.         pshufd                T0_REG,         PROD_1_REG, 11111100b        // T0= L1 * R[0],   T0_REG: X0000
  69.         pshufd                CARRY_REG,         PROD_1_REG, 11111101b        // high 32bit of  L1 * R[0] -->carry, carry,X0000
  70.                
  71.         movd                MASK_REG,        ebx
  72.         paddq                PROD_2_REG, CARRY_REG         // PROD_2_REG +=  carry, PROD_2_REG:XXXX
  73.         movdqa                T1_REG,                PROD_2_REG         // T1= L2 * RO,  T1_REG: XXXX

  74.         psrldq              PROD_2_REG, 4                        //         PROD_2_REG:  XXX0
  75.         pand                T1_REG,                MASK_REG        //  T1_REG: X0000
  76.                
  77.         pshufd                CARRY_REG,         PROD_2_REG, 11111100b        // 将carry分解出来, CARRY_REG:X0000
  78.         psrldq              PROD_2_REG, 4                        // PROD_2_REG = L3 *R[0],        PROD_2_REG:XX00
  79.         paddq                PROD_2_REG, CARRY_REG        // PROD_2_REG = L3 *R[0] + carry,        PROD_2_REG:XX00

  80.         pshufd                T2_REG,                PROD_2_REG, 11111100b        // PROD_2_REG:D0 -> T2, T2:X0000
  81.         pshufd                T3_REG,                PROD_2_REG, 11111101b        // PROD_2_REG:D0 -> T3, T3 :X0000


  82.         //----第二趟乘开始
  83.         psrldq              MUL_REG, 4                               
  84.        
  85.         movdqu                PROD_1_REG, [LEFT_REG]                                // 将4个DWORD一次载入
  86.         pshufd                PROD_2_REG,        PROD_1_REG, 00110010b        // L[2:3] -> PROD_2_REG
  87.         pshufd                PROD_1_REG,        PROD_1_REG, 11011100b        // L[0:1] -> PROD_1_REG
  88.                
  89.         //   第5,6次乘
  90.         pmuludq                PROD_1_REG, MUL_REG                //  L[0:1] * R[1],  PROD_1_REG:XXXX
  91.         paddq                PROD_1_REG, T0_REG                //  L[0:1] * R[1] +  t0,   PROD_1_REG:XXXX
  92.         movd                [RESULT_REG+4],PROD_1_REG        // PROD_1_REG:D0 -> result
  93.         psrldq              PROD_1_REG, 4                // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  94.         pshufd                CARRY_REG,         PROD_1_REG, 11111100b        // 将carry分解出来,PROD_1_REG:D0  -> carry
  95.         psrldq              PROD_1_REG, 4                // PROD_1_REG>>32, PROD_1_REG: XX00
  96.         paddq                PROD_1_REG, CARRY_REG        // PROD_1_REG += carry, PROD_1_REG:XX00
  97.         paddq                PROD_1_REG, T1_REG                // PROD_1_REG += T1, PROD_1_REG:XX00

  98.         //- 插入第7,8次乘指令
  99.         pmuludq                PROD_2_REG, MUL_REG                // L[2:3] * R[1], PROD_2_REG:XXXX

  100.         pshufd                T0_REG,         PROD_1_REG, 11111100b        // PROD_1_REG:D0 -> T0, T0:X000
  101.         pshufd                CARRY_REG,         PROD_1_REG, 11111101b        // PROD_1_REG:D1 -> carry, carry:X000

  102.         movd                MASK_REG,        ebx
  103.         paddq                PROD_2_REG, CARRY_REG         // PROD_2_REG +=carry
  104.         paddq                PROD_2_REG, T2_REG                 // PROD_2_REG += T2, PROD_2_REG:XX00
  105.         movdqa                T1_REG,                PROD_2_REG         // PROD_2_REG -> T1, T1:XXXX

  106.         psrldq              PROD_2_REG, 4        //  PROD_2_REG: XXX0
  107.         pand                T1_REG,                MASK_REG        //  T1:X000
  108.                
  109.         pshufd                CARRY_REG,         PROD_2_REG, 11111100b        // 将carry分解出来, carry:X0000
  110.         psrldq              PROD_2_REG, 4                // PROD_2_REG>>32, PROD_2_REG: XX00
  111.         paddq                PROD_2_REG, CARRY_REG        // PROD_2_REG += carry, PROD_2_REG:XX00
  112.         paddq                PROD_2_REG, T3_REG                // PROD_2_REG += T3, PROD_2_REG:XX00

  113.         pshufd                T2_REG,                PROD_2_REG, 11111100b        //PROD_2_REG:D0 -> T2, T2:X000
  114.         pshufd                T3_REG,                PROD_2_REG, 11111101b        //PROD_2_REG:D1 -> T3, T3:X000


  115.         //  第3趟乘开始 -
  116.         movq                MUL_REG,  qword ptr [RIGHT_REG+8]
  117.         pshufd                MUL_REG,  MUL_REG, 01000100b         // R[0] -> 0:3, R[1] -> 2:4

  118.         movdqu                PROD_1_REG, [LEFT_REG]                                // 将4个DWORD一次载入
  119.         pshufd                PROD_2_REG,        PROD_1_REG, 00110010b        // L[2:3] -> PROD_2_REG
  120.         pshufd                PROD_1_REG,        PROD_1_REG, 11011100b        // L[0:1] -> PROD_1_REG
  121.                

  122.         //   第9,10 次乘
  123.         pmuludq                PROD_1_REG, MUL_REG                // L[0:1] * R[2],  PROD_1_REG:XXXX
  124.         paddq                PROD_1_REG, T0_REG                // L[0:1] * R[2] + t0,   PROD_1_REG:XXXX
  125.         movd                [RESULT_REG+8],PROD_1_REG        // PROD_1_REG:D0 -> result
  126.         psrldq              PROD_1_REG, 4                // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  127.         pshufd                CARRY_REG,         PROD_1_REG, 11111100b        // 将carry分解出来,PROD_1_REG:D0  -> carry
  128.         psrldq              PROD_1_REG, 4                 // PROD_1_REG: XX00
  129.         paddq                PROD_1_REG, CARRY_REG        // PROD_1_REG += carry, PROD_1_REG:XX00
  130.         paddq                PROD_1_REG, T1_REG                // PROD_1_REG += T1, PROD_1_REG:XX00

  131.         //- 插入第11,12次乘指令
  132.         pmuludq                PROD_2_REG, MUL_REG                // L[2:3] * R[2], PROD_2_REG:XXXX

  133.         pshufd                T0_REG,         PROD_1_REG, 11111100b        // PROD_1_REG:D0 -> T0, T0:X000
  134.         pshufd                CARRY_REG,         PROD_1_REG, 11111101b        // PROD_1_REG:D1 -> carry, carry:X000
  135.                
  136.         movd                MASK_REG,        ebx
  137.         paddq                PROD_2_REG, CARRY_REG         // PROD_2_REG += carry
  138.         paddq                PROD_2_REG, T2_REG                // PROD_1_REG += T2, PROD_1_REG:XX00
  139.         movdqa                T1_REG,                PROD_2_REG         // PROD_2_REG -> T1, T1:XXXX

  140.         psrldq              PROD_2_REG, 4                // PROD_2_REG>>32,  PROD_2_REG: XXX0
  141.         pand                T1_REG,                MASK_REG        // T1:X000
  142.                
  143.         pshufd                CARRY_REG,         PROD_2_REG, 11111100b        // 将carry分解出来, carry:X0000
  144.         psrldq              PROD_2_REG, 4                // PROD_2_REG>>32, PROD_2_REG: XX00
  145.         paddq                PROD_2_REG, CARRY_REG        // PROD_2_REG += carry, PROD_2_REG:XX00
  146.         paddq                PROD_2_REG, T3_REG                // PROD_2_REG += T3, PROD_2_REG:XX00

  147.         pshufd                T2_REG,                PROD_2_REG, 11111100b        //PROD_2_REG:D0 -> T2, T2:X000
  148.         pshufd                T3_REG,                PROD_2_REG, 11111101b        //PROD_2_REG:D1 -> T3, T3:X000

  149.                
  150.         //     第4 趟乘开始 -
  151.         psrldq              MUL_REG, 4        //  
  152.                
  153.         movdqu                PROD_1_REG, [LEFT_REG]                                // 将4个DWORD一次载入
  154.         pshufd                PROD_2_REG,        PROD_1_REG, 00110010b        // L[2:3] -> PROD_2_REG
  155.         pshufd                PROD_1_REG,        PROD_1_REG, 11011100b        // L[0:1] -> PROD_1_REG
  156.                
  157.         //   第13,14 次乘
  158.         pmuludq                PROD_1_REG, MUL_REG                //  L[0:1] * R[3],  PROD_1_REG:XXXX
  159.         paddq                PROD_1_REG, T0_REG                //  L[0:1] * R[3]+  t0,   PROD_1_REG:XXXX
  160.         movd                [RESULT_REG+12],PROD_1_REG        // PROD_1_REG:D0 -> result
  161.         psrldq              PROD_1_REG, 4                // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  162.         pshufd                CARRY_REG, PROD_1_REG, 11111100b        // 将carry分解出来,PROD_1_REG:D0  -> carry
  163.         psrldq              PROD_1_REG, 4                // PROD_1_REG>>32, PROD_1_REG: XX00
  164.         paddq                PROD_1_REG, CARRY_REG        // PROD_1_REG += carry, PROD_1_REG:XX00
  165.         paddq                PROD_1_REG, T1_REG

  166.         //- 插入第15,16次乘指令
  167.         pmuludq                PROD_2_REG, MUL_REG                // L[2:3] * R[3], PROD_2_REG:XXXX

  168.         movd                [RESULT_REG+16], PROD_1_REG                                // PROD_1_REG:D0
  169.         pshufd                CARRY_REG,         PROD_1_REG, 11111101b                // PROD_1_REG:D1 -> carry, carry:X000
  170.                
  171.         paddq                PROD_2_REG, CARRY_REG         // PROD_2_REG +=carry
  172.         paddq                PROD_2_REG, T2_REG                 // PROD_2_REG +=carry
  173.         movd                [RESULT_REG+20],        PROD_2_REG         // PROD_2_REG -> T1, T1:XXXX

  174.         psrldq              PROD_2_REG, 4                //  PROD_2_REG>>32, PROD_2_REG: XXX0
  175.                
  176.         pshufd                CARRY_REG,         PROD_2_REG, 11111100b        // 将carry分解出来, carry:X0000
  177.         psrldq              PROD_2_REG, 4                        // PROD_2_REG>>32, PROD_2_REG: XX00
  178.         paddq                PROD_2_REG, CARRY_REG        // PROD_2_REG += carry, PROD_2_REG:XX00
  179.         paddq                PROD_2_REG, T3_REG
  180.         movq                qword ptr [RESULT_REG+24],PROD_2_REG
  181.                
  182.         // 恢复寄存器
  183.         pop                ebx
  184.         ret
  185.     }
  186. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-27 22:37:41 | 显示全部楼层
原帖由 无心人 于 2008-3-27 21:32 发表
76有问题
        movq           [RESULT_REG+24], mm5
                psrlq           mm5, 32                        //carry
               
                //------保存最高DWORD
                 ...


    movq 表示一次写2个DWORD(8个byte)和movdqa不同,并不需要16字节对齐。如果不是特别处理,right,left,result应为DWORD数组,一定是4字节对齐的,所以使用这条指令不会出错。

  关于最后的指令,我仔细看了下,确实有问题,下面的2条指令应该删除。
    “psrlq     mm5, 32” 和 “  movq        [RESULT_REG+28], mm5”,如此速度更快些。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-27 22:50:57 | 显示全部楼层
正如无心人所言,第76#程序有个bug,就是对result缓冲区多写了4个byte,不过结果却是正确的。修复后的版本见下,减少了2条指令,加上Emms指令,指令条数和94楼,56楼持平(110 条)。不知有谁会破了这个记录。
  1. _declspec(naked)
  2. void UInt128x128To256_SSE2_96F( UINT32 * const result,
  3.                                 const UINT32 * const left,
  4.                                 const UINT32 * const right )
  5. // 使用MMX寄存器, 但用SSE2指令
  6. // 指令的使用,乘法 使用 32bit * 32bit 的MMX指令,加法使用 64 bit + 64 bit 的SSE2指令

  7. // 16次乘法,分4趟, 操作数一律在mmx 寄存器中进行
  8. // 第1趟计算 left[] * right[0]
  9. // 第2趟计算 left[] * right[1]
  10. // 第3趟计算 left[] * right[2]
  11. // 第4趟计算 left[] * right[3]

  12. // 每趟的计算结果为 5 DWORD,最低位DWORD 直接存储到result, 前3趟的计算结果的高4个DWORD(中间结果)存储到一组寄存器

  13. // 寄存器的使用

  14. // 中间结果 放入 mm0,mm1,mm2,mm3

  15. // 掩码寄存器 mm7,  用来请64位寄存器的高32bit
  16. // 进位 寄存器 和 当前乘积寄存器 为 mm4 和 mm5,轮换使用
  17. // 乘数 寄存器 mm6
  18. // 可以看到8个mmx寄存器全部派上用场

  19. {
  20. #define LEFT_REG        eax
  21. #define RIGHT_REG        edx       
  22. #define RESULT_REG        ecx
  23. #define MASK_REG        mm7
  24. #define MUL_REG                mm6
  25.        
  26.         __asm
  27.     {
  28.         mov                    eax, 0xffffffff
  29.         mov         RESULT_REG, dword ptr[esp + 04h]   ; result
  30.         movd                MASK_REG, eax

  31.         mov         RIGHT_REG, dword ptr[esp + 0Ch]   ; right
  32.         movq        MUL_REG,   [RIGHT_REG]
  33.         mov         LEFT_REG,  dword ptr [esp + 08h]   ; left
  34.         
  35.                
  36.         //--------第1次乘
  37.         movd          mm4,        [LEFT_REG+0]
  38.         pmuludq          mm4, MUL_REG
  39.         movd          [RESULT_REG], mm4
  40.         psrlq          mm4, 32                //carry

  41.         //------第2次乘
  42.         movd           mm5,        [LEFT_REG+4]
  43.         pmuludq           mm5, MUL_REG
  44.         paddq           mm5, mm4                //64bit + 32 bit carry
  45.         movq           mm0, mm5
  46.         psrlq           mm5, 32                        //carry
  47.         pand           mm0, MASK_REG        //mm0,中间结果
  48.                
  49.         //------第3次乘
  50.         movd           mm4,        [LEFT_REG+8]
  51.         pmuludq           mm4, MUL_REG
  52.         paddq           mm4, mm5                        //64bit + 32 bit carry
  53.         movq           mm1, mm4
  54.         psrlq           mm4, 32                        //carry
  55.         pand           mm1, MASK_REG        //mm1,中间结果
  56.                
  57.         //------第4次乘
  58.         movd           mm5,        [LEFT_REG+12]
  59.         pmuludq           mm5, MUL_REG
  60.         paddq           mm5, mm4                //64bit + 32 bit carry
  61.         movq           mm2, mm5
  62.         psrlq           mm5, 32                        //carry
  63.         pand           mm2, MASK_REG        //mm2,中间结果
  64.         movq           mm3, mm5                        //mm3,中间结果

  65.         //----得到乘数
  66.         psrlq          MUL_REG, 32                //得到right[1]

  67.                
  68.         //---第二趟乘---------
  69.                
  70.         //--------第5次乘
  71.         movd          mm4,        [LEFT_REG+0]
  72.         pmuludq          mm4, MUL_REG
  73.         paddq          mm4, mm0                // 64bit + 32 bit 中间结果
  74.         movd          [RESULT_REG+4], mm4
  75.         psrlq          mm4, 32                //carry

  76.         //------第6次乘
  77.         movd           mm5,        [LEFT_REG+4]
  78.         pmuludq           mm5, MUL_REG
  79.         paddq           mm5, mm4                //64bit + 32 bit carry
  80.         paddq           mm5, mm1                //64bit + 32 bit 中间结果
  81.         movq           mm0, mm5
  82.         psrlq           mm5, 32                        //carry
  83.         pand           mm0, MASK_REG        //mm0,中间结果
  84.                
  85.         //------第7次乘
  86.         movd           mm4,        [LEFT_REG+8]
  87.         pmuludq           mm4, MUL_REG
  88.         paddq           mm4, mm5                        //64bit + 32 bit carry
  89.         paddq           mm4, mm2                        //64bit + 32 bit 中间结果
  90.         movq           mm1, mm4
  91.         psrlq           mm4, 32                        //carry
  92.         pand           mm1, MASK_REG        //mm1,中间结果
  93.                
  94.         //------第8次乘
  95.         movd           mm5,        [LEFT_REG+12]
  96.         pmuludq           mm5, MUL_REG
  97.         paddq           mm5, mm4                //64bit + 32 bit carry
  98.         paddq           mm5, mm3                //64bit + 32 bit 中间结果
  99.         movq           mm2, mm5
  100.         psrlq           mm5, 32                        //carry
  101.         pand           mm2, MASK_REG        //mm2,中间结果
  102.         movq           mm3, mm5                        //mm3,中间结果

  103.         //----得到乘数
  104.         movq                MUL_REG,   [RIGHT_REG+8]
  105.                
  106.         //--------第9次乘
  107.         movd          mm4,        [LEFT_REG+0]
  108.         pmuludq          mm4, MUL_REG
  109.         paddq          mm4, mm0                // 64bit + 32 bit 中间结果
  110.         movd          [RESULT_REG+8], mm4
  111.         psrlq          mm4, 32                //carry

  112.         //------第10次乘
  113.         movd           mm5,        [LEFT_REG+4]
  114.         pmuludq           mm5, MUL_REG
  115.         paddq           mm5, mm4                //64bit + 32 bit carry
  116.         paddq           mm5, mm1                //64bit + 32 bit 中间结果
  117.         movq           mm0, mm5
  118.         psrlq           mm5, 32                        //carry
  119.         pand           mm0, MASK_REG        //mm0,中间结果
  120.                
  121.         //------第11次乘
  122.         movd           mm4,        [LEFT_REG+8]
  123.         pmuludq           mm4, MUL_REG
  124.         paddq           mm4, mm5                        //64bit + 32 bit carry
  125.         paddq           mm4, mm2                        //64bit + 32 bit 中间结果
  126.         movq           mm1, mm4
  127.         psrlq           mm4, 32                        //carry
  128.         pand           mm1, MASK_REG        //mm1,中间结果
  129.                
  130.         //------第12次乘
  131.         movd           mm5,        [LEFT_REG+12]
  132.         pmuludq           mm5, MUL_REG
  133.         paddq           mm5, mm4                //64bit + 32 bit carry
  134.         paddq           mm5, mm3                //64bit + 32 bit 中间结果
  135.         movq           mm2, mm5
  136.         psrlq           mm5, 32                        //carry
  137.         pand           mm2, MASK_REG        //mm2,中间结果
  138.         movq           mm3, mm5                        //mm3,中间结果

  139.                
  140.         //----得到乘数
  141.         psrlq          MUL_REG, 32                //得到right[1]
  142.                
  143.         //--------第13次乘
  144.         movd          mm4,        [LEFT_REG+0]
  145.         pmuludq          mm4, MUL_REG
  146.         paddq          mm4, mm0                // 64bit + 32 bit 中间结果
  147.         movd          [RESULT_REG+12], mm4
  148.         psrlq          mm4, 32                //carry

  149.         //------第14次乘
  150.         movd           mm5,        [LEFT_REG+4]
  151.         pmuludq           mm5, MUL_REG
  152.         paddq           mm5, mm4                //64bit + 32 bit carry
  153.         paddq           mm5, mm1                //64bit + 32 bit 中间结果
  154.         movd           [RESULT_REG+16], mm5
  155.         psrlq           mm5, 32                        //carry
  156.        
  157.                
  158.         //------第15次乘
  159.         movd           mm4,        [LEFT_REG+8]
  160.         pmuludq           mm4, MUL_REG
  161.         paddq           mm4, mm5                        //64bit + 32 bit carry
  162.         paddq           mm4, mm2                        //64bit + 32 bit 中间结果
  163.         movd           [RESULT_REG+20], mm4
  164.         psrlq           mm4, 32                        //carry
  165.                
  166.                
  167.         //------第16次乘
  168.         movd           mm5,        [LEFT_REG+12]
  169.         pmuludq           mm5, MUL_REG
  170.         paddq           mm5, mm4                //64bit + 32 bit carry
  171.         paddq           mm5, mm3                //64bit + 32 bit
  172.         movq           [RESULT_REG+24], mm5

  173.         emms
  174.         ret
  175.     }
  176. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-28 07:58:00 | 显示全部楼层
我说的并不是他指令错误
而是最后还4个字节位置
用8字节写,至少在我的VC2008肯定是抛出异常的
:)
========================================
另外,我觉得
双乘并不弱于MMX,关键在我们的指令安排可能存在问题
现在想起来,16个乘,如果每条用6个指令加结果,就至少100条了
而我想,减少每次乘法后结果的指令数是很困难的

如果仔细比较,你们会发现,这次时间已逼近你们96bit的算法的时间了
而按照比率,这次最佳时间是上次的1.5倍以上
现在是否突破了上次的1.5倍呢?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-31 11:09:15 | 显示全部楼层
怎么停顿了
不想讨论了么?
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 2008-3-31 11:31:24 | 显示全部楼层
原帖由 无心人 于 2008-3-31 11:09 发表
怎么停顿了
不想讨论了么?

好吧, 我将编写一个完全使用X86指令(不使用任何MMX,SSE,SSE2指令的版本)的版本,再对比现在的SSE2,MMX版本,看看使用 SIMD 指令的 最高加速比是多少。
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 2008-3-31 11:36:15 | 显示全部楼层
SSE2代码似乎还存在优化可能
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
您需要登录后才可以回帖 登录 | 欢迎注册

本版积分规则

小黑屋|手机版|数学研发网 ( 苏ICP备07505100号 )

GMT+8, 2024-5-16 02:30 , Processed in 0.076133 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表