可能能节约时间
不过要占两个XMM
刚粗略看了,似乎可抽出XMM5, XMM6缓存left, right
==============
想到另外一种拆解方法
假设xmm0 = 1:0/0:1
movq xmm1, xmm0
pshufd xmm1, xmm1, 11011100b
psrldq mm0, 8
pshufd xmm0, xmm0, 11011100b
paddq xmm0, xmm1
明天测试, 感觉指令安排比原来的好, 运算冲突少, 还能节约个xmm7
另外
GxQ在CSDN上的96bit算法不知道怎么处理的进位?
通篇没有比较和置位处理
或者我没看懂?
恐怕128bit再加就没这么容易了 我将续写“诡异”算法的传奇,请稍候。。。:) 64位长加?
我考虑下
不过感觉应该不能达到最优化效果
即比我上面写的SSE2 107条代码做多节约30%时间
你先别发, 等我代码调试好了发上去
你再发,好对比 void UInt128x128To256_SSE2_54F( UINT32 * const result,
const UINT32 * const left,
const UINT32 * const right )
{
//全SSE2版本
__asm
{
/* 具体代码在下一个代码区,需登陆才可见 */
mov esi, dword ptr
mov edi, dword ptr
mov ebx, dword ptr
movdqu xmm5,
movdqu xmm6,
pshufd xmm0, xmm5, 11011100b//2008-03-21 有修改
pshufd xmm1, xmm6, 11011100b//2008-03-21 有修改
pmuludq xmm0, xmm1
pcmpeqd xmm7, xmm7
psrlq xmm7, 32 //00000000FFFFFFFF00000000FFFFFFFF
movd , xmm0 //0:0结果低位保存
pshufd xmm1, xmm5, 00010000b
pshufd xmm2, xmm6, 00000001b
pmuludq xmm1, xmm2 //xmm1= 1:0/0:1
movq xmm4, xmm0
pshufd xmm4, xmm4, 11111101b
pshufd xmm3, xmm1, 00010000b
pand xmm3, xmm7
pshufd xmm2, xmm1, 00110010b
pand xmm2, xmm7
paddq xmm2, xmm3 //0:1+1:0=xmm2
paddq xmm2, xmm4
psrldq xmm0, 8
//xmm0=1:1
movd , xmm2
psrldq xmm2, 4
pshufd xmm3, xmm2, 11111001b
pshufd xmm2, xmm2, 11111100b
paddq xmm2, xmm3
//2:0 0:2
pshufd xmm4, xmm5, 00100000b
pshufd xmm3, xmm6, 00000010b
pmuludq xmm4, xmm3 //xmm4=2:0/0:2
pshufd xmm3, xmm4, 00010000b
pand xmm3, xmm7
pshufd xmm4, xmm4, 00110010b
pand xmm4, xmm7
paddq xmm3, xmm4 //xmm3=2:0 + 0:2 xmm0=1:1 xmm2=进位
pshufd xmm0, xmm0, 11011100b
paddq xmm3, xmm2
paddq xmm3, xmm0
movd , xmm3
psrldq xmm3, 4
pshufd xmm0, xmm3, 11111001b
pshufd xmm3, xmm3, 11111100b
paddq xmm0, xmm3 //xmm0=进位
//1:2 2:1 3:0 0:3
pshufd xmm1, xmm5, 00010010b
pshufd xmm4, xmm6, 00100001b
pmuludq xmm1, xmm4
pshufd xmm2, xmm5, 00110000b
pshufd xmm3, xmm6, 00000011b
pmuludq xmm2, xmm3 //xmm0进位 xmm1=1:2/2:1 xmm2=3:0/0:3
pshufd xmm4, xmm1, 00010000b
pand xmm4, xmm7
pshufd xmm1, xmm1, 00110010b
pand xmm1, xmm7
paddq xmm1, xmm4
paddq xmm0, xmm1
pshufd xmm3, xmm2, 00010000b
pand xmm3, xmm7
pshufd xmm2, xmm2, 00110010b
pand xmm2, xmm7
paddq xmm2, xmm3
paddq xmm0, xmm2
movd , xmm0
psrldq xmm0, 4
pshufd xmm3, xmm0, 11111001b
pshufd xmm0, xmm0, 11111100b
paddq xmm0, xmm3 //xmm0进位
//1:3 2:2 3:1
pshufd xmm1, xmm5, 00110010b
pshufd xmm3, xmm6, 00110010b
pmuludq xmm1, xmm3 //xmm1=3:3/2:2
pshufd xmm2, xmm5, 00110001b
pshufd xmm4, xmm6, 00010011b
pmuludq xmm2, xmm4 //xmm2=3:1/1:3
movdqa xmm4, xmm1
psrldq xmm4, 8 //xmm4=3:3
movq xmm1, xmm1 //xmm1=2:2
pshufd xmm3, xmm2, 00110010b
pand xmm3, xmm7
pshufd xmm2, xmm2, 00010000b
pand xmm2, xmm7
paddq xmm2, xmm3
pshufd xmm1, xmm1, 11011100b
paddq xmm1, xmm2
paddq xmm0, xmm1
movd , xmm0
psrldq xmm0, 4
pshufd xmm3, xmm0, 11111001b
pshufd xmm0, xmm0, 11111100b
paddq xmm0, xmm3 //xmm0=进位
//2:3 3:2
pshufd xmm1, xmm5, 00100011b
pshufd xmm2, xmm6, 00110010b
pmuludq xmm1, xmm2
pshufd xmm3, xmm1, 00010000b
pand xmm3, xmm7
pshufd xmm1, xmm1, 00110010b
pand xmm1, xmm7
paddq xmm1, xmm3
paddq xmm0, xmm1
movd , xmm0
psrldq xmm0, 4
pshufd xmm2, xmm0, 11111001b
pshufd xmm0, xmm0, 11111100b
paddq xmm0, xmm2 //进位
pshufd xmm4, xmm4, 11011100b
paddq xmm0, xmm4
movd , xmm0
psrldq xmm0, 4
pshufd xmm1, xmm0, 11111001b
pshufd xmm0, xmm0, 11111100b
paddq xmm0, xmm1
movd , xmm0
// ret;
}
}
//MMX 1 681 885us
//SSE2s 1 841 345us
//SSE2 1 841 528us 111行
我的“诡异”算法
_declspec(naked)void UInt128x128To256_SSE2_56F( UINT32 * const result,
const UINT32 * const left,
const UINT32 * const right )
{
__asm
{
mov ecx, dword ptr ; result
mov eax, dword ptr ; left
mov edx, dword ptr ; right
movdqa xmm2, xmmword ptr ; load left
movdqa xmm0, xmmword ptr ; load right
pshufd xmm7, xmm2, 11111111b ; xmm7 = L3:L3:L3:L3
pshufd xmm1, xmm0, 11110101b ; xmm1 = R3:R3:R1:R1
movdqa xmm6, xmm7 ; xmm6 = L3:L3:L3:L3
pmuludq xmm7, xmm1 ; xmm7 = L3*R3:L3*R1 ->V7-4
pmuludq xmm6, xmm0 ; xmm6 = L3*R2:L3*R0 ->V6-3
movdqa xmm5, xmm7 ;
movdqa xmm4, xmm6 ;
movdqa xmm3, xmm6 ;
pslldq xmm5, 4 ; xmm5 <<= 32
psrldq xmm4, 4 ; xmm4 >>= 32
pslldq xmm3, 12 ; L3*R2:L3*R0 ->V3-0
paddq xmm6, xmm5 ; L3*R3:L3*R1 ->V6-3
paddq xmm7, xmm4 ; L3*R2:L3*R0 ->V7-4
pshufd xmm5, xmm2, 10101010b ; xmm5 = L2:L2:L2:L2
pmuludq xmm5, xmm1 ; xmm5 = L2*R3:L2*R1
paddq xmm6, xmm5 ; L2*R3:L2*R1 ->V6-3
movdqa xmm4, xmm5 ;
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm4, 12 ; xmm4 <<= 96
paddq xmm7, xmm5 ; L2*R3:L2*R1 ->V7-4
paddq xmm3, xmm4 ; L2*R3:L2*R1 ->V3-0
pshufd xmm5, xmm2, 10101010b ; xmm5 = L2:L2:L2:L2
pshufd xmm4, xmm2, 01010101b ; xmm4 = L1:L1:L1:L1
pshufd xmm2, xmm2, 00000000b ; xmm2 = L0:L0:L0:L0
pmuludq xmm5, xmm0 ; xmm5 = L2*R2:L2*R0
movdqa xmmword ptr, xmm4 ; xmm4 = L1:L1:L1:L1
movdqa xmmword ptr, xmm2 ; xmm2 = L0:L0:L0:L0
movdqa xmm2, xmm5 ; xmm2 = L2*R2:L2*R0
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm2, 8 ; xmm4 <<= 64
paddq xmm6, xmm5 ; L2*R2:L2*R0 ->V6-3
paddq xmm3, xmm2 ; L2*R2:L2*R0 ->V3-0
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm2, 4 ; L2*R2:L2*R0 ->V2-1H
paddq xmm7, xmm5 ; L2*R2:L2*R0 ->V7-4
movdqa xmm5, xmmword ptr ; xmm5 = L1:L1:L1:L1
pmuludq xmm5, xmm1 ; xmm5 = L1*R3:L1*R1
movdqa xmm4, xmm5 ;
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm4, 8 ; xmm4 >>= 64
paddq xmm6, xmm5 ; L1*R3:L1*R1 ->V6-3
paddq xmm3, xmm4 ; L1*R3:L1*R1 ->V3-0
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm7, xmm5 ; L1*R3:L1*R1 ->V7-4
paddq xmm2, xmm4 ; L1*R3:L1*R1 ->V2-1H
movdqa xmm5, xmmword ptr ; xmm5 = L1:L1:L1:L1
pmuludq xmm5, xmm0 ; xmm5 = L1*R2:L1*R0
movdqa xmm4, xmm5 ;
psrldq xmm5, 8 ; xmm5 >>= 64
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm6, xmm5 ; L1*R2:L1*R0 ->V6-3
paddq xmm3, xmm4 ; L1*R2:L1*R0 ->V3-0
psrldq xmm5, 4 ; xmm5 >>= 32
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm7, xmm5 ; L1*R2:L1*R0 ->V7-4
paddq xmm2, xmm4 ; L1*R2:L1*R0 ->V2-1H
movdqa xmm5, xmmword ptr ; xmm5 = L0:L0:L0:L0
pmuludq xmm5, xmm1 ; xmm5 = L0*R3:L0*R1
movdqa xmm4, xmm5 ;
psrldq xmm5, 8 ; xmm5 >>= 64
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm6, xmm5 ; L0*R3:L0*R1 ->V6-3
paddq xmm3, xmm4 ; L0*R3:L0*R1 ->V3-0
psrldq xmm5, 4 ; xmm5 >>= 64
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm7, xmm5 ; L0*R3:L0*R1 ->V7-4
paddq xmm2, xmm4 ; L0*R3:L0*R1 ->V2-1H
movdqa xmm5, xmmword ptr ; xmm5 = L0:L0:L0:L0
pmuludq xmm5, xmm0 ; xmm5 = L0*R2:L0*R0
paddq xmm3, xmm5 ; L0*R2:L0*R0 ->V3-0
movdqa xmm4, xmm5 ;
psrldq xmm5, 12 ; xmm5 >>= 96
pslldq xmm4, 4 ; xmm4 >>= 32
paddq xmm6, xmm5 ; L0*R2:L0*R0 ->V6-3
paddq xmm2, xmm4 ; L0*R2:L0*R0 ->V2-1H
; now, V=xmm3 ->OK
psrldq xmm2, 4 ; xmm2 >>= 32
movdqa xmm4, xmm3 ;
pcmpeqd xmm0, xmm0 ; xmm0 = FF:FF:FF:FF
pandn xmm4, xmm2 ;
psubd xmm2, xmm3 ; xmm2 -= xmm3
psrldq xmm0, 12 ; xmm0 = 00:00:00:FF
pslldq xmm4, 4 ; xmm4 <<= 32
psrld xmm4, 31 ; CF
pshufd xmm1, xmm0, 01001110b ; xmm1 = 00:FF:00:00
paddd xmm2, xmm4 ;
pand xmm2, xmm1 ;
paddq xmm3, xmm2 ; V=xmm3 ->OK
movdqa xmmword ptr, xmm3 ; store V
psrldq xmm3, 12 ; xmm3 >>= 96
psubd xmm3, xmm6 ; xmm3 -= xmm6
pand xmm3, xmm0 ;
paddq xmm6, xmm3 ; V=xmm6 ->OK
pxor xmm1, xmm0 ; xmm1 = 00:FF:00:FF
psrldq xmm6, 4 ; V=xmm6 ->OK
movdqa xmm2, xmm6 ; xmm2 = xmm6
psubd xmm6, xmm7 ; xmm6 -= xmm0
pand xmm6, xmm1 ;
paddq xmm7, xmm6 ; now, xmm7 bits OK!
psubusb xmm2, xmm7 ;
psrlq xmm2, 63 ; CF
pslldq xmm2, 8 ;
paddq xmm7, xmm2 ; xmm7 += CF
movdqa xmmword ptr, xmm7 ; store V
ret;
}
}SSE2 指令,XMM 寄存器,110行(包含最后那个 ret 指令)。
(费了不少功夫,但效果没有预期的好) 你算法优势不大了
movdqa xmm2, xmmword ptr ; load left
movdqa xmm0, xmmword ptr ; load right
最好用pshufd代替, 有性能改进的
==============================================================================
就不另外开新回复了
我想在我代码测试里你也看到了
明明SSE2一次乘两个,却和一个乘一个的差不多,更离谱的是和用MMX寄存器的时间差了好多
关键是
1、目前的乘法,SSE2乘一次延迟是5,用MMX一次是3,这个影响不大
2、简单乘一个导致后期处理简单
3、似乎某些设计导致MMX寄存器快
如果有Core 2的结果最好了,Core 2应该能改进甚至导致SSE2的双乘算法超过MMX寄存器
改进版
在 56# 基础上改进,主要目的是让 pmuludq 指令集中执行,消除其延时,代码如下:_declspec(naked)void UInt128x128To256_SSE2_58F( UINT32 * const result,
const UINT32 * const left,
const UINT32 * const right )
{
__asm
{
mov ecx, dword ptr ; result
mov eax, dword ptr ; left
mov edx, dword ptr ; right
movdqa xmm5, xmmword ptr ; load left
movdqa xmm4, xmmword ptr ; load right
mov eax, esp ;
sub esp, 0x4F ;
and esp, -16 ;
pshufd xmm0, xmm5, 00000000b ; xmm0 = L0:L0:L0:L0
pshufd xmm1, xmm5, 01010101b ; xmm1 = L1:L1:L1:L1
pshufd xmm2, xmm5, 10101010b ; xmm2 = L2:L2:L2:L2
pshufd xmm3, xmm5, 11111111b ; xmm3 = L3:L3:L3:L3
movdqa xmmword ptr, xmm0 ; xmm0 = L0:L0:L0:L0
movdqa xmmword ptr, xmm1 ; xmm1 = L1:L1:L1:L1
movdqa xmm6, xmm2 ; xmm6 = L2:L2:L2:L2
movdqa xmm7, xmm3 ; xmm7 = L3:L3:L3:L3
pmuludq xmm0, xmm4 ; xmm0 = L0*R2:L0*R0
pmuludq xmm1, xmm4 ; xmm1 = L1*R2:L1*R0
pmuludq xmm2, xmm4 ; xmm2 = L2*R2:L2*R0
pmuludq xmm3, xmm4 ; xmm3 = L3*R2:L3*R0
movdqa xmmword ptr, xmm0 ;
movdqa xmmword ptr, xmm1 ;
movdqa xmmword ptr, xmm2 ;
movdqa xmmword ptr, xmm3 ;
psrldq xmm4, 4 ; xmm4 = 00:R3:R2:R1
movdqa xmm1, xmmword ptr ; xmm1 = L1:L1:L1:L1
movdqa xmm0, xmmword ptr ; xmm0 = L0:L0:L0:L0
pmuludq xmm7, xmm4 ; xmm3 = L3*R3:L3*R1 ->V7-4
pmuludq xmm6, xmm4 ; xmm2 = L2*R3:L2*R1 ->V6-3
pmuludq xmm1, xmm4 ; xmm1 = L1*R3:L1*R1
pmuludq xmm0, xmm4 ; xmm0 = L0*R3:L0*R1
movdqa xmm5, xmm7 ;
movdqa xmm4, xmm6 ;
movdqa xmm3, xmm6 ;
pslldq xmm5, 4 ; xmm5 <<= 32
psrldq xmm4, 4 ; xmm4 >>= 32
pslldq xmm3, 12 ; L3*R3:L3*R1 ->V3-0
paddq xmm7, xmm4 ; L2*R3:L2*R1 ->V7-4
paddq xmm6, xmm5 ; L3*R3:L3*R1 ->V6-3
movdqa xmm2, xmm0 ;
movdqa xmm4, xmm0 ;
movdqa xmm5, xmm1 ;
psrldq xmm0, 8 ; xmm0 >>= 64
psrldq xmm1, 4 ; xmm1 >>= 32
pslldq xmm2, 8 ; L0*R3:L0*R1 ->V2-1H
pslldq xmm4, 4 ; xmm4 <<= 32
pslldq xmm5, 8 ; xmm5 <<= 64
paddq xmm6, xmm0 ; L0*R3:L0*R1 ->V6-3
paddq xmm3, xmm4 ; L0*R3:L0*R1 ->V3-0
paddq xmm6, xmm1 ; L1*R3:L1*R1 ->V6-3
paddq xmm3, xmm5 ; L1*R3:L1*R1 ->V3-0
psrldq xmm0, 4 ; xmm0 >>= 32
psrldq xmm1, 4 ; xmm1 >>= 32
pslldq xmm5, 4 ; xmm5 <<= 32
paddq xmm7, xmm0 ; L0*R3:L0*R1 ->V7-4
paddq xmm2, xmm5 ; L1*R3:L1*R1 ->V2-1H
paddq xmm7, xmm1 ; L1*R3:L1*R1 ->V7-4
movdqa xmm5, xmmword ptr ; xmm5 = L3*R2:L3*R0
movdqa xmm4, xmmword ptr ; xmm4 = L2*R2:L2*R0
movdqa xmm1, xmm5 ;
movdqa xmm0, xmm4 ;
paddq xmm6, xmm5 ; L3*R2:L3*R0 ->V6-3
psrldq xmm0, 4 ; xmm0 >>= 32
psrldq xmm1, 4 ; xmm1 >>= 32
pslldq xmm4, 8 ; xmm4 <<= 64
pslldq xmm5, 12 ; xmm5 <<= 96
paddq xmm6, xmm0 ; L2*R2:L2*R0 ->V6-3
paddq xmm3, xmm4 ; L2*R2:L2*R0 ->V3-0
paddq xmm7, xmm1 ; L3*R2:L3*R0 ->V7-4
paddq xmm3, xmm5 ; L3*R2:L3*R0 ->V3-0
psrldq xmm0, 4 ; xmm0 >>= 32
pslldq xmm4, 4 ; xmm4 <<= 32
paddq xmm7, xmm0 ; L2*R2:L2*R0 ->V7-4
paddq xmm2, xmm4 ; L2*R2:L2*R0 ->V2-1H
movdqa xmm0, xmmword ptr ; xmm0 = L0*R2:L0*R0
movdqa xmm1, xmmword ptr ; xmm1 = L1*R2:L1*R0
mov esp, eax ;
paddq xmm3, xmm0 ; L0*R2:L0*R0 ->V3-0
movdqa xmm4, xmm0 ;
movdqa xmm5, xmm1 ;
pslldq xmm0, 4 ; xmm0 <<= 32
pslldq xmm1, 4 ; xmm1 <<= 32
psrldq xmm4, 12 ; xmm4 >>= 96
psrldq xmm5, 8 ; xmm5 >>= 64
paddq xmm2, xmm0 ; L0*R2:L0*R0 ->V2-1H
paddq xmm6, xmm4 ; L0*R2:L0*R0 ->V6-3
paddq xmm3, xmm1 ; L1*R2:L1*R0 ->V3-0
paddq xmm6, xmm5 ; L1*R2:L1*R0 ->V6-3
pslldq xmm1, 4 ; xmm1 <<= 32
psrldq xmm5, 4 ; xmm5 >>= 32
paddq xmm2, xmm1 ; L1*R2:L1*R0 ->V2-1H
paddq xmm7, xmm5 ; L1*R2:L1*R0 ->V7-4
; now, V=xmm3 ->OK
psrldq xmm2, 4 ; xmm2 >>= 32
movdqa xmm4, xmm3 ;
pcmpeqd xmm0, xmm0 ; xmm0 = FF:FF:FF:FF
pandn xmm4, xmm2 ;
psubd xmm2, xmm3 ; xmm2 -= xmm3
psrldq xmm0, 12 ; xmm0 = 00:00:00:FF
pslldq xmm4, 4 ; xmm4 <<= 32
psrld xmm4, 31 ; CF
pshufd xmm1, xmm0, 01001110b ; xmm1 = 00:FF:00:00
paddd xmm2, xmm4 ;
pand xmm2, xmm1 ;
paddq xmm3, xmm2 ; V=xmm3 ->OK
movdqa xmmword ptr, xmm3 ; store V
psrldq xmm3, 12 ; xmm3 >>= 96
psubd xmm3, xmm6 ; xmm3 -= xmm6
pand xmm3, xmm0 ;
paddq xmm6, xmm3 ; V=xmm6 ->OK
pxor xmm1, xmm0 ; xmm1 = 00:FF:00:FF
psrldq xmm6, 4 ; V=xmm6 ->OK
movdqa xmm2, xmm6 ; xmm2 = xmm6
psubd xmm6, xmm7 ; xmm6 -= xmm0
pand xmm6, xmm1 ;
paddq xmm7, xmm6 ; now, xmm7 bits OK!
psubusb xmm2, xmm7 ;
psrlq xmm2, 63 ; CF
pslldq xmm2, 8 ;
paddq xmm7, xmm2 ; xmm7 += CF
movdqa xmmword ptr, xmm7 ; store V
ret;
}
}全函数 121 条汇编指令(含 ret 指令),无跳转,无 adc 指令。
测试结果如下:UInt128x128To256_ANSI_C32(..): 679.753ms
UInt128x128To256_SSE2_40F(..): 479.048ms
UInt128x128To256_SSE2_42F(..): 809.487ms
UInt128x128To256_SSE2_54F(..): 754.158ms
UInt128x128To256_SSE2_56F(..): 640.666ms
UInt128x128To256_SSE2_58F(..): 625.339ms
测试环境:Windows XP SP2,AMD Athlon 64 Processor 3200+,1GB DDR - 200MHz
(欢迎大家在本地机上测试)
当前所有版本测试源代码及编译好的程序压缩包:
(注意:在 69# 有更新更全的压缩包) 报个到先. 本来说不打算参与了,看你们写了这么多版本,我也试一试写SSE2版的。
主要采用SSE2指令乘,一次只做一个32bit*32bit,进位部分采用利用 SSE2指令做 64bit + 32bit的运算,中间结果使用 MMX存储。
预期的速度应该难以超越gxq,但应该不会太慢。 我写的仍无法超越楼主在 40# 里的“SSE2指令/MMX寄存器”版本。:)
不知在 Core 2 上的结果会如何?:o
这次与先前的 UInt96x96To192 不一样,对进位处理更麻烦,
而我的所谓“诡异算法”似乎并不凑效,所以比我快的可能性仍很高。:)