c - union __m256 和两个 __m128 数组

标签 c performance sse vectorization avx

我能有这样的 union 吗

  union eight_floats_t
  {
    __m256 a;
    __m128 b[2];
  };
  eight_floats_t eight_floats;

立即访问 256 位寄存器的两个 128 位部分?

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

最佳答案

你当然可以做到。 C 和 C++ 语言允许您这样做。而且它很可能会做您希望它做的事情。

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

问题 1:

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

这是 MSVC2010 生成的内容(经过优化):

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

__m128 fvecA = a.b[0];
__m128 fvecB = a.b[1];
fvecA = _mm_add_ps(fvecA,fvecB);

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]

您可以看到它正在被刷新到内存中。

问题 2:

第二次减速甚至更糟。当您将内容写入内存并立即以不同的字长访问它时,您可能会触发存储到加载停顿。 (通常大约 > 10 个周期)

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


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

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

和家人。其他数据类型也是如此。

也就是说,编译器可能足够聪明,可以识别您在做什么,并且无论如何都会使用这些指令。 (至少 MSVC2010 没有。)

关于c - union __m256 和两个 __m128 数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13183258/

相关文章:

c# - 在 ToDictionary 之前执行 ToList() 是否更好?

c++ - 带符号的 16 位 SSE 平均值

x86 - 像 Denormals-Are-Zero (DAZ) 这样的非规范标志会影响比较的相等性吗?

c - 如何使用 C 将二进制字符串转换为十六进制?

c - C套接字中奇怪的while循环?

c - (对于初学者) : Input Array of Characters w/no specific size. 使用 : Array of Characters. 创建一个实现间隔的条件。 (在C中)

android - Android 中的最佳实践是什么,创建新的字符串对象(静态最终)还是仅使用 string.xml 文件(并调用许多 getter)?

java - 编译器使用关联性有什么问题?

c++ - 内联汇编中的 sse 约束不起作用

c - Linux 上 C 语言的 Dirent 迭代