まあAVXのギャザー結局自作しないといけないのが全部悪いのだが…


というか

__m256d __attribute__((noinline, noclone))
avx_double_gather4(const double *p,
                   unsigned int idx0, unsigned int idx1, unsigned int idx2, unsigned int idx3,
                   __m256d vpred)
{
    int pred = _mm256_movemask_pd(vpred);
    __m256i mask0 = _mm256_castpd_si256(_mm256_and_pd(vpred, _mm256_set_pd( 0, 0, 0,-1)));
    __m256i mask1 = _mm256_castpd_si256(_mm256_and_pd(vpred, _mm256_set_pd( 0, 0,-1, 0)));
    __m256i mask2 = _mm256_castpd_si256(_mm256_and_pd(vpred, _mm256_set_pd( 0,-1, 0, 0)));
    __m256i mask3 = _mm256_castpd_si256(_mm256_and_pd(vpred, _mm256_set_pd(-1, 0, 0, 0)));

    __m256d v0 = _mm256_maskload_pd(&p[idx0], mask0);
    __m256d v1 = _mm256_maskload_pd(&p[idx1]-1, mask1);
    __m256d v2 = _mm256_maskload_pd(&p[idx2]-2, mask2);
    __m256d v3 = _mm256_maskload_pd(&p[idx3]-3, mask3);

    v0 = _mm256_or_pd(v0, v1);
    v2 = _mm256_or_pd(v2, v3);

    return _mm256_or_pd(v0, v2);
}
avx_double_gather4:
	movl	%esi, %esi
	movl	%edx, %edx
	movl	%ecx, %ecx
	movl	%r8d, %r8d
	vandpd	.LC0(%rip), %ymm0, %ymm4
	vandpd	.LC1(%rip), %ymm0, %ymm1
	vandpd	.LC2(%rip), %ymm0, %ymm3
	vandpd	.LC3(%rip), %ymm0, %ymm2
	vmaskmovpd	(%rdi,%rsi,8), %ymm4, %ymm4
	vmaskmovpd	-8(%rdi,%rdx,8), %ymm1, %ymm1
	vmaskmovpd	-16(%rdi,%rcx,8), %ymm3, %ymm3
	vorpd	%ymm1, %ymm4, %ymm1
	vmaskmovpd	-24(%rdi,%r8,8), %ymm2, %ymm2
	vorpd	%ymm2, %ymm3, %ymm0
	vorpd	%ymm0, %ymm1, %ymm0
	ret

なんだこの出力は??(どのGCCでも似たようなのが出る)


いやそうか今書いててわかった。movで上位32bitクリアしてるのか…そう考えると今のx86-64 の mov ってキモいな。


ちなみにこのギャザーは別バージョンより遅かったので没った。あんま見てないけど多分使ってる定数多いのが良くないのだと思う。


64bit cpu だと

  • レジスタに乗る値 → 32bitを使うと上位クリア処理が入る可能性がある
  • メモリに入る値 → 64bitを使うとキャッシュ使いすぎる可能性がある

というわけで、どういう値がレジスタに乗るのか把握しながらプログラム書く必要があるな。


つまり x32 がさいつよということ???