仅使用avx而非avx2转置64位元素

时间:2016-06-14 09:08:12

标签: avx avx2

我想仅使用avx而不是avx2来实现64位转置操作。应该这样做:

// in  = Hh Hl Lh Ll
//        |   X   |
// out = Hh Lh Hl Ll

这是 avx2:

的样子
#define SIMD_INLINE inline __attribute__ ((always_inline))

static SIMD_INLINE __m256i
x_mm256_transpose4x64_epi64(__m256i a)
{
  return _mm256_permute4x64_epi64(a, _MM_SHUFFLE(3,1,2,0));
}

这是最有效的解决方法没有 avx2我可以提出(使用3个avx说明):

static SIMD_INLINE __m256i
x_mm256_transpose4x64_epi64(__m256i a)
{
  __m256d in, x1, x2;
  // in = Hh Hl Lh Ll
  in = _mm256_castsi256_pd(a);
  // only lower 4 bit are used
  // in = Hh Hl Lh Ll
  //       0  1  0  1  = (0,0,1,1)
  // x1 = Hl Hh Ll Lh
  x1 = _mm256_permute_pd(in, _MM_SHUFFLE(0,0,1,1));
  // all 8 bit are used
  // x1 = Hl Hh Ll Lh
  //       0  0  1  1
  // x2 = Ll Lh Hl Hh
  x2 = _mm256_permute2f128_pd(x1, x1, _MM_SHUFFLE(0,0,1,1));
  // only lower 4 bit are used
  // in = Hh Hl Lh Ll
  // x2 = Ll Lh Hl Hh
  //       0  1  1  0 = (0,0,1,2)
  // ret: Hh Lh Hl Ll
  return _mm256_castpd_si256(_mm256_blend_pd(in, x2, _MM_SHUFFLE(0,0,1,2)));
}

问题是大多数avx混合操作(例如解压缩)都在128位通道上运行,并且不会跨越通道边界。

任何人都可以提高效率吗?非常感谢!

1 个答案:

答案 0 :(得分:4)

我认为3条指令是你能做的最好的。 _mm256_blend_pd非常便宜(如vblendpsvpblendd),在SnB / IvB中的2个端口上运行,以及Haswell及更高版本中的所有3个向量执行端口。 (即与矢量XOR或AND一样便宜。)其他两个都需要shuffle端口,这是不可避免的。

vblendpd将其数据从FP域转发为整数指令时,SnB系列CPU的旁路延迟为1个周期。虽然使用AVX1,但没有任何256b整数指令可以转发。

(来源:参见Agner Fog的insn表,链接自标签wiki。他的优化装配指南也有一些很好的洗牌表,但并不专注于 - AVX / AVX2的车道挑战。)

这种模式几乎可以通过两条指令实现,但并不完全。

vshufpd (_mm256_shuffle_pd)为您提供了一个内置2源shuffle,但数据移动受到限制。与原始SSE2版本一样,每个目标元素只能来自固定的源元素。 8位立即数有空间对来自四个源元素的两个选项进行编码,但它们保持硬件简单,并且每个dest元素仅使用1位选择器。对于每个128b通道,256b版本允许不同的随机播放,因此对于vpshufd ymm,imm8的4位是重要的。

无论如何,由于上部通道需要从原始部分获取其高元素,但是低通道需要从perm128向量中获取其高元素,因此src1,src2排序的选择都不能满足我们的需要。

vshufpd我认为编码比vpermilpd imm8短一个字节。 vpermilps / vpermilpd的直接形式的唯一用例似乎是一种加载和改变。 (vshufpd仅在两个源操作数相同时作为完整的通道内洗牌工作)。 IDK如果vpermildp可能会使用更少的能量或其他东西,因为它只有一个来源。

当然,编译器可以使用他们想要的任何指令来完成工作;他们允许使用内在函数优化代码,就像使用+运算符(它不总是编译为add指令)优化代码一样。 Clang实际上基本上忽略了使用内在函数进行指令选择的尝试,因为它以自己的内部格式表示shuffle,并对它们进行优化。