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

[擂台] 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. //第1趟乘开始---
  52. movq MUL_REG, qword ptr [RIGHT_REG]
  53. pshufd MUL_REG, MUL_REG, 01000100b // R[0] -> 0:3, R[1] -> 2:4
  54. movdqu PROD_1_REG, [LEFT_REG] // 将4个DWORD一次载入
  55. pshufd PROD_2_REG, PROD_1_REG, 00110010b // L[2:3] -> PROD_2_REG
  56. pshufd PROD_1_REG, PROD_1_REG, 11011100b // L[0:1] -> PROD_1_REG
  57. //-------- 第1,2次乘
  58. pmuludq PROD_1_REG, MUL_REG // L[0:1] * R[0], XXXX
  59. movd [RESULT_REG],PROD_1_REG // store low32 bit of L0 * R[0]
  60. psrldq PROD_1_REG, 4 // PROD_1_REG >>= 32, high 32 bit is full zero,shape XXX0
  61. pshufd CARRY_REG, PROD_1_REG, 11111100b // 将carry分解出来, X0000
  62. psrldq PROD_1_REG, 4 // PROD_1_REG:[D0,D1]= L1*R[0],RROD_1_REG: XX00
  63. paddq PROD_1_REG, CARRY_REG // PROD_1_REG:[D0,D1]= L1 * R[0] + carry, RROD_1_REG: XX00
  64. //----插入第3,4次乘指令
  65. pmuludq PROD_2_REG, MUL_REG //PROD_2_REG:[D0-D4]= L[2:3] * R[0], PROD_2_REG:XXXX
  66. pshufd T0_REG, PROD_1_REG, 11111100b // T0= L1 * R[0], T0_REG: X0000
  67. pshufd CARRY_REG, PROD_1_REG, 11111101b // high 32bit of L1 * R[0] -->carry, carry,X0000
  68. movd MASK_REG, ebx
  69. paddq PROD_2_REG, CARRY_REG // PROD_2_REG += carry, PROD_2_REG:XXXX
  70. movdqa T1_REG, PROD_2_REG // T1= L2 * RO, T1_REG: XXXX
  71. psrldq PROD_2_REG, 4 // PROD_2_REG: XXX0
  72. pand T1_REG, MASK_REG // T1_REG: X0000
  73. pshufd CARRY_REG, PROD_2_REG, 11111100b // 将carry分解出来, CARRY_REG:X0000
  74. psrldq PROD_2_REG, 4 // PROD_2_REG = L3 *R[0], PROD_2_REG:XX00
  75. paddq PROD_2_REG, CARRY_REG // PROD_2_REG = L3 *R[0] + carry, PROD_2_REG:XX00
  76. pshufd T2_REG, PROD_2_REG, 11111100b // PROD_2_REG:D0 -> T2, T2:X0000
  77. pshufd T3_REG, PROD_2_REG, 11111101b // PROD_2_REG:D0 -> T3, T3 :X0000
  78. //----第二趟乘开始
  79. psrldq MUL_REG, 4
  80. movdqu PROD_1_REG, [LEFT_REG] // 将4个DWORD一次载入
  81. pshufd PROD_2_REG, PROD_1_REG, 00110010b // L[2:3] -> PROD_2_REG
  82. pshufd PROD_1_REG, PROD_1_REG, 11011100b // L[0:1] -> PROD_1_REG
  83. // 第5,6次乘
  84. pmuludq PROD_1_REG, MUL_REG // L[0:1] * R[1], PROD_1_REG:XXXX
  85. paddq PROD_1_REG, T0_REG // L[0:1] * R[1] + t0, PROD_1_REG:XXXX
  86. movd [RESULT_REG+4],PROD_1_REG // PROD_1_REG:D0 -> result
  87. psrldq PROD_1_REG, 4 // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  88. pshufd CARRY_REG, PROD_1_REG, 11111100b // 将carry分解出来,PROD_1_REG:D0 -> carry
  89. psrldq PROD_1_REG, 4 // PROD_1_REG>>32, PROD_1_REG: XX00
  90. paddq PROD_1_REG, CARRY_REG // PROD_1_REG += carry, PROD_1_REG:XX00
  91. paddq PROD_1_REG, T1_REG // PROD_1_REG += T1, PROD_1_REG:XX00
  92. //- 插入第7,8次乘指令
  93. pmuludq PROD_2_REG, MUL_REG // L[2:3] * R[1], PROD_2_REG:XXXX
  94. pshufd T0_REG, PROD_1_REG, 11111100b // PROD_1_REG:D0 -> T0, T0:X000
  95. pshufd CARRY_REG, PROD_1_REG, 11111101b // PROD_1_REG:D1 -> carry, carry:X000
  96. movd MASK_REG, ebx
  97. paddq PROD_2_REG, CARRY_REG // PROD_2_REG +=carry
  98. paddq PROD_2_REG, T2_REG // PROD_2_REG += T2, PROD_2_REG:XX00
  99. movdqa T1_REG, PROD_2_REG // PROD_2_REG -> T1, T1:XXXX
  100. psrldq PROD_2_REG, 4 // PROD_2_REG: XXX0
  101. pand T1_REG, MASK_REG // T1:X000
  102. pshufd CARRY_REG, PROD_2_REG, 11111100b // 将carry分解出来, carry:X0000
  103. psrldq PROD_2_REG, 4 // PROD_2_REG>>32, PROD_2_REG: XX00
  104. paddq PROD_2_REG, CARRY_REG // PROD_2_REG += carry, PROD_2_REG:XX00
  105. paddq PROD_2_REG, T3_REG // PROD_2_REG += T3, PROD_2_REG:XX00
  106. pshufd T2_REG, PROD_2_REG, 11111100b //PROD_2_REG:D0 -> T2, T2:X000
  107. pshufd T3_REG, PROD_2_REG, 11111101b //PROD_2_REG:D1 -> T3, T3:X000
  108. // 第3趟乘开始 -
  109. movq MUL_REG, qword ptr [RIGHT_REG+8]
  110. pshufd MUL_REG, MUL_REG, 01000100b // R[0] -> 0:3, R[1] -> 2:4
  111. movdqu PROD_1_REG, [LEFT_REG] // 将4个DWORD一次载入
  112. pshufd PROD_2_REG, PROD_1_REG, 00110010b // L[2:3] -> PROD_2_REG
  113. pshufd PROD_1_REG, PROD_1_REG, 11011100b // L[0:1] -> PROD_1_REG
  114. // 第9,10 次乘
  115. pmuludq PROD_1_REG, MUL_REG // L[0:1] * R[2], PROD_1_REG:XXXX
  116. paddq PROD_1_REG, T0_REG // L[0:1] * R[2] + t0, PROD_1_REG:XXXX
  117. movd [RESULT_REG+8],PROD_1_REG // PROD_1_REG:D0 -> result
  118. psrldq PROD_1_REG, 4 // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  119. pshufd CARRY_REG, PROD_1_REG, 11111100b // 将carry分解出来,PROD_1_REG:D0 -> carry
  120. psrldq PROD_1_REG, 4 // PROD_1_REG: XX00
  121. paddq PROD_1_REG, CARRY_REG // PROD_1_REG += carry, PROD_1_REG:XX00
  122. paddq PROD_1_REG, T1_REG // PROD_1_REG += T1, PROD_1_REG:XX00
  123. //- 插入第11,12次乘指令
  124. pmuludq PROD_2_REG, MUL_REG // L[2:3] * R[2], PROD_2_REG:XXXX
  125. pshufd T0_REG, PROD_1_REG, 11111100b // PROD_1_REG:D0 -> T0, T0:X000
  126. pshufd CARRY_REG, PROD_1_REG, 11111101b // PROD_1_REG:D1 -> carry, carry:X000
  127. movd MASK_REG, ebx
  128. paddq PROD_2_REG, CARRY_REG // PROD_2_REG += carry
  129. paddq PROD_2_REG, T2_REG // PROD_1_REG += T2, PROD_1_REG:XX00
  130. movdqa T1_REG, PROD_2_REG // PROD_2_REG -> T1, T1:XXXX
  131. psrldq PROD_2_REG, 4 // PROD_2_REG>>32, PROD_2_REG: XXX0
  132. pand T1_REG, MASK_REG // T1:X000
  133. pshufd CARRY_REG, PROD_2_REG, 11111100b // 将carry分解出来, carry:X0000
  134. psrldq PROD_2_REG, 4 // PROD_2_REG>>32, PROD_2_REG: XX00
  135. paddq PROD_2_REG, CARRY_REG // PROD_2_REG += carry, PROD_2_REG:XX00
  136. paddq PROD_2_REG, T3_REG // PROD_2_REG += T3, PROD_2_REG:XX00
  137. pshufd T2_REG, PROD_2_REG, 11111100b //PROD_2_REG:D0 -> T2, T2:X000
  138. pshufd T3_REG, PROD_2_REG, 11111101b //PROD_2_REG:D1 -> T3, T3:X000
  139. // 第4 趟乘开始 -
  140. psrldq MUL_REG, 4 //
  141. movdqu PROD_1_REG, [LEFT_REG] // 将4个DWORD一次载入
  142. pshufd PROD_2_REG, PROD_1_REG, 00110010b // L[2:3] -> PROD_2_REG
  143. pshufd PROD_1_REG, PROD_1_REG, 11011100b // L[0:1] -> PROD_1_REG
  144. // 第13,14 次乘
  145. pmuludq PROD_1_REG, MUL_REG // L[0:1] * R[3], PROD_1_REG:XXXX
  146. paddq PROD_1_REG, T0_REG // L[0:1] * R[3]+ t0, PROD_1_REG:XXXX
  147. movd [RESULT_REG+12],PROD_1_REG // PROD_1_REG:D0 -> result
  148. psrldq PROD_1_REG, 4 // PROD_1_REG >>= 32, PROD_1_REG: XXX0
  149. pshufd CARRY_REG, PROD_1_REG, 11111100b // 将carry分解出来,PROD_1_REG:D0 -> carry
  150. psrldq PROD_1_REG, 4 // PROD_1_REG>>32, PROD_1_REG: XX00
  151. paddq PROD_1_REG, CARRY_REG // PROD_1_REG += carry, PROD_1_REG:XX00
  152. paddq PROD_1_REG, T1_REG
  153. //- 插入第15,16次乘指令
  154. pmuludq PROD_2_REG, MUL_REG // L[2:3] * R[3], PROD_2_REG:XXXX
  155. movd [RESULT_REG+16], PROD_1_REG // PROD_1_REG:D0
  156. pshufd CARRY_REG, PROD_1_REG, 11111101b // PROD_1_REG:D1 -> carry, carry:X000
  157. paddq PROD_2_REG, CARRY_REG // PROD_2_REG +=carry
  158. paddq PROD_2_REG, T2_REG // PROD_2_REG +=carry
  159. movd [RESULT_REG+20], PROD_2_REG // PROD_2_REG -> T1, T1:XXXX
  160. psrldq PROD_2_REG, 4 // PROD_2_REG>>32, PROD_2_REG: XXX0
  161. pshufd CARRY_REG, PROD_2_REG, 11111100b // 将carry分解出来, carry:X0000
  162. psrldq PROD_2_REG, 4 // PROD_2_REG>>32, PROD_2_REG: XX00
  163. paddq PROD_2_REG, CARRY_REG // PROD_2_REG += carry, PROD_2_REG:XX00
  164. paddq PROD_2_REG, T3_REG
  165. movq qword ptr [RESULT_REG+24],PROD_2_REG
  166. // 恢复寄存器
  167. pop ebx
  168. ret
  169. }
  170. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
发表于 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. __asm
  26. {
  27. mov eax, 0xffffffff
  28. mov RESULT_REG, dword ptr[esp + 04h] ; result
  29. movd MASK_REG, eax
  30. mov RIGHT_REG, dword ptr[esp + 0Ch] ; right
  31. movq MUL_REG, [RIGHT_REG]
  32. mov LEFT_REG, dword ptr [esp + 08h] ; left
  33. //--------第1次乘
  34. movd mm4, [LEFT_REG+0]
  35. pmuludq mm4, MUL_REG
  36. movd [RESULT_REG], mm4
  37. psrlq mm4, 32 //carry
  38. //------第2次乘
  39. movd mm5, [LEFT_REG+4]
  40. pmuludq mm5, MUL_REG
  41. paddq mm5, mm4 //64bit + 32 bit carry
  42. movq mm0, mm5
  43. psrlq mm5, 32 //carry
  44. pand mm0, MASK_REG //mm0,中间结果
  45. //------第3次乘
  46. movd mm4, [LEFT_REG+8]
  47. pmuludq mm4, MUL_REG
  48. paddq mm4, mm5 //64bit + 32 bit carry
  49. movq mm1, mm4
  50. psrlq mm4, 32 //carry
  51. pand mm1, MASK_REG //mm1,中间结果
  52. //------第4次乘
  53. movd mm5, [LEFT_REG+12]
  54. pmuludq mm5, MUL_REG
  55. paddq mm5, mm4 //64bit + 32 bit carry
  56. movq mm2, mm5
  57. psrlq mm5, 32 //carry
  58. pand mm2, MASK_REG //mm2,中间结果
  59. movq mm3, mm5 //mm3,中间结果
  60. //----得到乘数
  61. psrlq MUL_REG, 32 //得到right[1]
  62. //---第二趟乘---------
  63. //--------第5次乘
  64. movd mm4, [LEFT_REG+0]
  65. pmuludq mm4, MUL_REG
  66. paddq mm4, mm0 // 64bit + 32 bit 中间结果
  67. movd [RESULT_REG+4], mm4
  68. psrlq mm4, 32 //carry
  69. //------第6次乘
  70. movd mm5, [LEFT_REG+4]
  71. pmuludq mm5, MUL_REG
  72. paddq mm5, mm4 //64bit + 32 bit carry
  73. paddq mm5, mm1 //64bit + 32 bit 中间结果
  74. movq mm0, mm5
  75. psrlq mm5, 32 //carry
  76. pand mm0, MASK_REG //mm0,中间结果
  77. //------第7次乘
  78. movd mm4, [LEFT_REG+8]
  79. pmuludq mm4, MUL_REG
  80. paddq mm4, mm5 //64bit + 32 bit carry
  81. paddq mm4, mm2 //64bit + 32 bit 中间结果
  82. movq mm1, mm4
  83. psrlq mm4, 32 //carry
  84. pand mm1, MASK_REG //mm1,中间结果
  85. //------第8次乘
  86. movd mm5, [LEFT_REG+12]
  87. pmuludq mm5, MUL_REG
  88. paddq mm5, mm4 //64bit + 32 bit carry
  89. paddq mm5, mm3 //64bit + 32 bit 中间结果
  90. movq mm2, mm5
  91. psrlq mm5, 32 //carry
  92. pand mm2, MASK_REG //mm2,中间结果
  93. movq mm3, mm5 //mm3,中间结果
  94. //----得到乘数
  95. movq MUL_REG, [RIGHT_REG+8]
  96. //--------第9次乘
  97. movd mm4, [LEFT_REG+0]
  98. pmuludq mm4, MUL_REG
  99. paddq mm4, mm0 // 64bit + 32 bit 中间结果
  100. movd [RESULT_REG+8], mm4
  101. psrlq mm4, 32 //carry
  102. //------第10次乘
  103. movd mm5, [LEFT_REG+4]
  104. pmuludq mm5, MUL_REG
  105. paddq mm5, mm4 //64bit + 32 bit carry
  106. paddq mm5, mm1 //64bit + 32 bit 中间结果
  107. movq mm0, mm5
  108. psrlq mm5, 32 //carry
  109. pand mm0, MASK_REG //mm0,中间结果
  110. //------第11次乘
  111. movd mm4, [LEFT_REG+8]
  112. pmuludq mm4, MUL_REG
  113. paddq mm4, mm5 //64bit + 32 bit carry
  114. paddq mm4, mm2 //64bit + 32 bit 中间结果
  115. movq mm1, mm4
  116. psrlq mm4, 32 //carry
  117. pand mm1, MASK_REG //mm1,中间结果
  118. //------第12次乘
  119. movd mm5, [LEFT_REG+12]
  120. pmuludq mm5, MUL_REG
  121. paddq mm5, mm4 //64bit + 32 bit carry
  122. paddq mm5, mm3 //64bit + 32 bit 中间结果
  123. movq mm2, mm5
  124. psrlq mm5, 32 //carry
  125. pand mm2, MASK_REG //mm2,中间结果
  126. movq mm3, mm5 //mm3,中间结果
  127. //----得到乘数
  128. psrlq MUL_REG, 32 //得到right[1]
  129. //--------第13次乘
  130. movd mm4, [LEFT_REG+0]
  131. pmuludq mm4, MUL_REG
  132. paddq mm4, mm0 // 64bit + 32 bit 中间结果
  133. movd [RESULT_REG+12], mm4
  134. psrlq mm4, 32 //carry
  135. //------第14次乘
  136. movd mm5, [LEFT_REG+4]
  137. pmuludq mm5, MUL_REG
  138. paddq mm5, mm4 //64bit + 32 bit carry
  139. paddq mm5, mm1 //64bit + 32 bit 中间结果
  140. movd [RESULT_REG+16], mm5
  141. psrlq mm5, 32 //carry
  142. //------第15次乘
  143. movd mm4, [LEFT_REG+8]
  144. pmuludq mm4, MUL_REG
  145. paddq mm4, mm5 //64bit + 32 bit carry
  146. paddq mm4, mm2 //64bit + 32 bit 中间结果
  147. movd [RESULT_REG+20], mm4
  148. psrlq mm4, 32 //carry
  149. //------第16次乘
  150. movd mm5, [LEFT_REG+12]
  151. pmuludq mm5, MUL_REG
  152. paddq mm5, mm4 //64bit + 32 bit carry
  153. paddq mm5, mm3 //64bit + 32 bit
  154. movq [RESULT_REG+24], mm5
  155. emms
  156. ret
  157. }
  158. }
复制代码
毋因群疑而阻独见  毋任己意而废人言
毋私小惠而伤大体  毋借公论以快私情
 楼主| 发表于 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-11-21 20:47 , Processed in 0.026090 second(s), 15 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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