与__m256联合和两个__m128的数组

Ben*_*Uri 4 c performance sse vectorization avx

我可以拥有这样的工会吗?

  union eight_floats_t
  {
    __m256 a;
    __m128 b[2];
  };
  eight_floats_t eight_floats;
Run Code Online (Sandbox Code Playgroud)

能够即时访问256位寄存器的两个128位部分吗?

编辑:我要求了解这种方法对性能的影响.

Mys*_*ial 10

你当然可以做到这一点.C和C++语言允许您这样做.它很可能会做你想做的事情.

但是,您使用AVX的事实意味着您关心性能.因此,知道这是SSE程序员陷入的最常见(性能)陷阱之一可能是有用的.(许多人没有注意到)

问题1:

当前的编译器使用存储器位置实现这种联合.所以这是第一个问题,每次从不同的字段访问联合时,它都会强制数据到内存并将其读回.这是一个减速.

以下是MSVC2010为其生成的内容(通过优化):

eight_floats a;
a.a = vecA[0];

__m128 fvecA = a.b[0];
__m128 fvecB = a.b[1];
fvecA = _mm_add_ps(fvecA,fvecB);
Run Code Online (Sandbox Code Playgroud)

vmovaps YMMWORD PTR a$[rbp], ymm0
movaps  xmm1, XMMWORD PTR a$[rbp+16]
addps   xmm1, XMMWORD PTR a$[rbp]
movaps  XMMWORD PTR fvecA$[rbp], xmm1
movss   xmm1, DWORD PTR fvecA$[rbp]
Run Code Online (Sandbox Code Playgroud)

你可以看到它被刷新到内存中.

问题2:

第二次放缓甚至更糟.当您向内存写入内容并立即使用不同的字大小访问它时,您可能会触发存储到加载停顿.(通常大于10个周期)

这是因为当前处理器上的加载存储队列通常不是为处理这种(异常)情况而设计的.所以他们通过简单地将队列刷新到内存来处理它.


访问AVX数据类型的上半部分和上半部分的"正确"方法是使用:

  • _mm256_extractf128_ps()
  • _mm256_insertf128_ps()
  • _mm256_castps256_ps128()

和家人.同样对于其他数据类型也是如此.

也就是说,编译器可能足够聪明,无法识别您正在做什么并使用这些指令.(至少MSVC2010没有.)