我的问题是导出指向包含浮点数的内存空间的未对齐__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,但也有三种不需要操作的指令(推送rbp、将rsp加载到rbp、pop rbp)。
另外,如果我从typedef更改为使用:
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所产生的差异--ty胡枝子/使用和显式/自动--使得它太不可靠,无法自信地使用--至少我需要静态断言来检查在去引用指针时生成的uop是否未对齐,而这并不存在AFAIK。
在某些情况下,我可能希望有一个对内存区域的MyFloatVector,这就排除了使用本质。
示例代码:https://godbolt.org/z/caxScz。包括国际商会的“乐趣”,这将生成MOVUPS始终。
发布于 2020-06-03 19:00:04
当您使用reinterpret_cast时,您是在告诉编译器,参数指向请求类型的有效对象。这意味着它具有相同的对齐要求。
ICC在这里比较保守,而clang和GCC则试图通过假设您实际上遵守了标准来使您的代码运行得更快。
请记住,对齐的属性只能用于增加对齐需求,而不是减少它们,所以在您的代码中,您只是说类型的最小对齐度为4字节。如果添加一个static_assert(alignof(MyFloatVector) == 4, "Alignment should be 4"),您可能会看到一些失败,具体取决于您如何声明它。
由于您没有使用__m512,所以_mm512_loadu_ps可以工作,但可能并不是真正正确的方法。加载未对齐数据的正确方法是使用memcpy (或__builtin_memcpy,因为您使用的是向量扩展)。编译器非常擅长在已知大小的情况下优化memcpy,只要您使用的是一个相对较新的编译器,您就应该在启用AVX-512 F的x86上获得一个vmovup。
https://stackoverflow.com/questions/62176908
复制相似问题