21,497
社区成员




align 16
SSE_MASK_TABLE \
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
db 0, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h, 80h
而#8说,我的memcpy怎么写的?特简单啊,就是rep movs,这样的:
push esi
push edi
mov edi, [esp+0ch] ;目标指针
mov esi, [esp+10h] ;来源指针
mov ecx, [esp+14h] ;复制长度
mov edx, ecx
and edx, 03h
shr ecx, 02h
cld
rep movsd
mov ecx, edx
rep movsb
pop edi
pop esi
retn 000ch
我测试了不管数据大还是小,用SSE来写的比我上面这段慢3、4倍呢(必须是严谨长度的复制哈,不能是只考虑全16的倍数的长度或者覆盖不在长度范围的目标数据哦);
这里有篇帖子,就是说SSE对内存复制没有啥帮助的:
http://bbs.bccn.net/thread-339988-1-1.html
虽然他其中的代码我觉得可以优化,但是道理说的是没错的。
帖子结了吧,要是有好建议、好想法、好思路和好代码,欢迎随时和我交流。。。CopyUp:
;
; First, see if we can use a "fast" copy SSE2 routine
; block size greater than min threshold?
cmp ecx,080h
jb Dword_align
; SSE2 supported?
cmp DWORD PTR __sse2_available,0
je Dword_align
; alignments equal?
push edi
push esi
and edi,15
and esi,15
cmp edi,esi
pop esi
pop edi
jne Dword_align
; do fast SSE2 copy, params already set
jmp _VEC_memcpy
; no return
jmp _SSE_ROUTINE_MAIN_LOOP
_SSE_ROUTINE_MAIN_LOOP_ALL_COPY
movdqa [edi], xmm0 ; 完整的 一次 movdqa
_SSE_ROUTINE_MAIN_LOOP:
movdqa xmm0, [esi] ; 取源内存 至 xmm0
movdqa xmm3, xmm7 ; xmm7 之前准备好的 掩码 比如想要 过滤 0xFFFFFFFF 那么 xmm7 就是 0xFFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
pcmpeqd xmm3, xmm0 ; 如果 里面有掩码字节 那么就会有 0xFFFFFFFF
movmskps ecx, xmm3 ; 提取 掩码命中次数 ... 如果 里面么有 掩码命中 那么 ecx 为 0 有的话 就不会是 0
test ecx, ecx ; 测试是否有掩码命中 ?
je _SSE_ROUTINE_MAIN_LOOP_ALL_COPY ; 继续复制 ... 当前字节中没有要过滤的字节 ...
#if 0
; 根据当前 pcmpeqd xmm3, xmm0 的时候 xmm3 中的 0xFFFFFFFF 情况 过滤指定的dword ...
#else
; 根据ecx 中的情况做张 表 ... 呵呵 这样可以精确到每次 要过滤的字节数 ...
#endif
call _GET_DWORD ;假设ecx 中存放的是要选择传送的字节数,其范围必须是 1-15(代码未对其检查)
movd xmm1, eax
add ecx, -4
jng _RET
call _GET_DWORD
pinsrw xmm1, eax, 02h
shr eax, 10h
pinsrw xmm1, eax, 03h
add ecx, -4
jng _RET
call _GET_DWORD
pinsrw xmm1, eax, 04h
shr eax, 10h
pinsrw xmm1, eax, 05h
add ecx, -4
jng _RET
call _GET_DWORD
pinsrw xmm1, eax, 06h
shr eax, 10h
pinsrw xmm1, eax, 07h
jmp _RET
_GET_DWORD:
xor eax, eax
cdq
@@:
mov al, 80h
inc edx
cmp edx, ecx
je @F
cmp edx, 04h
jnb @F
shl eax, 08h
jmp @B
@@:
ret
_RET:
;此时 xmm1 中就是移位表了。。。然后再调用 MASKMOVDQU xmm0, xmm1 即可
我觉得算是比较简单的了,至于效率我觉得肯定有提升的空间,因为现在的代码对 9-15字节的时候需要调用好几次子函数,配合其他指令应该流程会更简单些,但相应的判断跳转也会多的。。。
懂的前辈请给点建议。。。。