未对齐的向量指针怪异性(AVX512)

问题描述 投票:0回答:1

我的问题是关于派生一个不对齐的__m512指针到一个包含浮点数的内存空间。我发现 GCC 和 Clang 在通过这样的装置访问内存时,在生成正确的 uop(unaligned vs aligned)方面有些不稳定。

首先,工作情况。

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和一个segfault。GCC仍然会产生MOVUPS,但也会产生三条do-nothing指令(push rbp,load rsp to 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又会产生fluff指令 而Clang会产生MOVAPS. 在这里使用auto也会得到同样的结果。

那么,有谁知道这里面到底发生了什么,有没有什么方法可以解决这个问题呢?安全的 的方法来进行转换。虽然有一个可行的解决方案,但我认为由typedefusing和explicitauto产生的差异使得它太不可靠了,无法放心使用--至少我需要一个静态断言来检查当dereferencing指针时产生的uop是否未对齐,而AFAIK并不存在。

在某些情况下,我可能希望有一个MyFloatVector-reference到内存区域,这就排除了使用本征。

示例代码。https:/godbolt.orgzcaxScz. 包括 "好玩 "的ICC,它在整个过程中生成MOVUPS。

gcc clang vectorization simd avx512
1个回答
2
投票

当你使用 reinterpret_cast 你在告诉编译器,这个参数指向一个有效的请求类型的对象。 这意味着它有相同的对齐要求。

ICC在这里比较保守,而clang和GCC则试图通过假设你确实遵守了标准来让你的代码更快。

请记住,对齐属性只能用于 增加 的对齐要求,而不是减少它们,所以在您的代码中,您只是说类型有一个 最低 4个字节的对齐方式。 如果你添加一个 static_assert(alignof(MyFloatVector) == 4, "Alignment should be 4") 你可能会看到一些失败,这取决于你如何准确地声明它。

因为你没有使用 __m512, _mm512_loadu_ps 行不通 真的 正确的方法,我认为。 加载未对齐数据的正确方法是使用 memcpy (或 __builtin_memcpy因为你使用的是矢量扩展)。) 编译器在优化已知大小的memcpy方面真的很不错,只要你使用的是相对较新的编译器,你就应该在x86上使用启用AVX-512F的vmovups。

© www.soinside.com 2019 - 2024. All rights reserved.