【发布时间】:2020-09-22 09:23:59
【问题描述】:
我的问题涉及派生未对齐的 __m512 指向包含浮点数的内存空间的指针。我发现在通过这样的装置访问内存时,GCC 和 Clang 在生成正确的 uop(未对齐与对齐)方面有些不稳定。
首先,工作案例:
typedef float MyFloatVector __attribute__((vector_size(64), aligned(4)));
MyFloatVector* vec_ptr = reinterpret_cast<MyFloatVector*>(float_ptr);
Something(*vec_ptr);
Clang 和 GCC 都为上述内容生成 MOVUPS。但是,如果 vec_ptr 的类型留给编译器:
typedef float MyFloatVector __attribute__((vector_size(64), aligned(4)));
auto vec_ptr = reinterpret_cast<MyFloatVector *>(float_ptr);
Something(*vec_ptr);
现在,Clang 将生成 MOVAPS 和一个段错误。 GCC 仍然会生成 MOVUPS,但也会生成三个无操作指令(push rbp、将 rsp 加载到 rbp、pop rbp)。
另外,如果我从 typedef 更改为 using:
using MyFloatVector = float __attribute__((vector_size(64), aligned(4)));
MyFloatVector*vec_ptr = reinterpret_cast<MyFloatVector*>(float_ptr);
Something(*vec_ptr);
GCC 再次生成绒毛指令,Clang 生成 MOVAPS。在此处使用 auto 会产生相同的结果。
那么,有没有人知道幕后发生了什么,是否有一种安全的方法来进行转换。虽然存在一个可行的解决方案,但 IMO 由 typedef/using 和显式/自动生成的差异使得它太不可靠而无法放心使用——至少我需要一个静态断言来检查在取消引用指针时生成的 uop未对齐,不存在 AFAIK。
在某些情况下,我可能希望对内存区域有一个 MyFloatVector 引用,这排除了使用内在函数。
示例代码:https://godbolt.org/z/caxScz。包括“乐趣”的 ICC,它会在整个过程中生成 MOVUPS。
【问题讨论】:
-
reinterpret_cast经常使用不安全。_mm512_loadu_ps有什么问题? -
它排除了使用引用,例如MyFloatVector& vec_ref = *vec_ptr;目标是实现一个类似 std::vector 的容器,该容器可以对矢量化数据类型进行操作,因此例如[]-operator 需要能够形成对内部存储的引用。
-
也许实现一个自定义引用对象(它内部包含一个指针,但重载了
operator __m512()和operator=(__m512)——类似于vector<bool>中处理引用的方式。 -
是的——这似乎是唯一的出路。我是有点希望在这里变得懒惰,只依靠编译器来做魔术:-) 不过谢谢你的帮助!
标签: gcc clang vectorization simd avx512