まあ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 がさいつよということ???