试图理解常量大小/对齐指针上的clang/gcc\u内置内存集
基本上,我试图理解为什么gcc/clang都使用试图理解常量大小/对齐指针上的clang/gcc\u内置内存集,gcc,clang,compiler-optimization,micro-optimization,memset,Gcc,Clang,Compiler Optimization,Micro Optimization,Memset,基本上,我试图理解为什么gcc/clang都使用xmm注册它们的\uuuu内置内存集,即使内存目标和大小都可以被ymm的大小整除(或zmm),CPU也支持AVX2AVX512 为什么GCC在没有任何SIMD的中等大小的值上实现\uuu内置\u memset(同样假设CPU支持SIMD) 例如: __builtin_memset(__builtin_assume_aligned(ptr, 64), -1, 64)); 将编译为: vpcmpeqd %xmm0, %x
xmm
注册它们的\uuuu内置内存集
,即使内存目标和大小都可以被ymm
的大小整除(或zmm
),CPU也支持AVX2
AVX512
为什么GCC在没有任何SIMD的中等大小的值上实现\uuu内置\u memset
(同样假设CPU支持SIMD)
例如:
__builtin_memset(__builtin_assume_aligned(ptr, 64), -1, 64));
将编译为:
vpcmpeqd %xmm0, %xmm0, %xmm0
vmovdqa %xmm0, (%rdi)
vmovdqa %xmm0, 16(%rdi)
vmovdqa %xmm0, 32(%rdi)
vmovdqa %xmm0, 48(%rdi)
我试图理解为什么选择这个而不是像这样的东西
vpcmpeqd %ymm0, %ymm0, %ymm0
vmovdqa %ymm0, (%rdi)
vmovdqa %ymm0, 32(%rdi)
如果将\uuuu内置\u memset
与AVX2
指令混合使用,它们仍然使用xmm
,因此肯定不会保存vzeropper
第二,对于GCC的\uuuuuuuu内置\uu memset(\uuuuuu内置\uu假定\uu对齐(ptr,64),-1512)
GCC将其实现为:
movq $-1, %rdx
xorl %eax, %eax
.L8:
movl %eax, %ecx
addl $32, %eax
movq %rdx, (%rdi,%rcx)
movq %rdx, 8(%rdi,%rcx)
movq %rdx, 16(%rdi,%rcx)
movq %rdx, 24(%rdi,%rcx)
cmpl $512, %eax
jb .L8
ret
为什么gcc会选择使用xmm
(或ymm
/zmm
)寄存器的循环
是一个带有示例(和其他一些示例)的锁紧螺栓链接
多谢各位
编辑:clang使用ymm(但不是zmm)其中一些可能与此相关。谢谢!这似乎主要是关于AVX512与AVX2的优缺点,而GCC仍在使用SSE。看起来GCC不知道如何在循环中使用
vmovdqa
来内联扩展memset。对于最多256个字节,它将使用vmovdqa xmm
完全展开,但对于更多字节,它将使用4xmovq%r64,m64
在循环中使用愚蠢的索引寻址模式。(或者对于-march=sandybridge
中需要取消层压的地方,使用rep stosq
)。@Noah:rep stosq
有很多启动开销。标量循环即使在Core2这样的古老CPU上也能处理不对齐问题,在Core2中,movdqu
非常昂贵,对于小计数来说也不错。但是,对于对齐的数据,在一个循环中,它永远不会超过一半的movdqa
,即使它在奔腾M上解码到多个UOP(两个64位的一半),也可能不会。GCC的memset扩展调优可能已经有一段时间没有被关注了,也许从那以后就没有了?而且不利用对齐,非常原始。@Noah:movdqa-xmm
从来没有这个问题。使用两倍数量的标量存储总是愚蠢的。避免使用YMM有时是有意义的(如果周围的代码也不使用它们),但是movq%rdx,(%rdi,%rcx)
。。。循环从来没有任何意义。(除非在没有已知对齐的情况下为Core2或更早版本进行调整,这里两者都不正确。)其中一些可能是相关的。谢谢!这似乎主要是关于AVX512与AVX2的优缺点,而GCC仍在使用SSE。看起来GCC不知道如何在循环中使用vmovdqa
来内联扩展memset。对于最多256个字节,它将使用vmovdqa xmm
完全展开,但对于更多字节,它将使用4xmovq%r64,m64
在循环中使用愚蠢的索引寻址模式。(或者对于-march=sandybridge
中需要取消层压的地方,使用rep stosq
)。@Noah:rep stosq
有很多启动开销。标量循环即使在Core2这样的古老CPU上也能处理不对齐问题,在Core2中,movdqu
非常昂贵,对于小计数来说也不错。但是,对于对齐的数据,在一个循环中,它永远不会超过一半的movdqa
,即使它在奔腾M上解码到多个UOP(两个64位的一半),也可能不会。GCC的memset扩展调优可能已经有一段时间没有被关注了,也许从那以后就没有了?而且不利用对齐,非常原始。@Noah:movdqa-xmm
从来没有这个问题。使用两倍数量的标量存储总是愚蠢的。避免使用YMM有时是有意义的(如果周围的代码也不使用它们),但是movq%rdx,(%rdi,%rcx)
。。。循环从来没有任何意义。(除非在没有已知对齐的情况下为Core2或更早版本进行调谐,此处两者均不正确。)