问题描述
在我的测试中,以下代码似乎可以正常执行:
double* ptr = _aligned_malloc(sizeof(double) * 8,64);
__m512d* vect = (__m512d*)ptr;
但是,AVX 提供了执行完全相同的功能 - _mm512_load_pd
。上面的代码在任何方面都被认为是危险的吗?我假设标准指针转换和内部函数之间的唯一区别是内部函数将立即将数据加载到 64 字节寄存器,而指针转换将等待进一步的指令这样做。我说的对吗?
解决方法
我假设标准指针转换和内部函数之间的唯一区别是内部函数将立即将数据加载到 64 字节寄存器,而指针转换将等待进一步的指令这样做。
不,一点也不。它们完全相同,生成的 asm 没有差异。在大多数编译器上,_mm512_load_pd
只是一个简单的内联函数,它执行类似 return *(__m512d *) __P;
的操作——这是 GCC 头文件的精确复制粘贴。因此,负载内在实际上已经在这样做了。
__m512d
与 double
或 int
在编译器如何分配寄存器以及决定何时实际加载恰好在内存中的 C 对象方面没有根本的不同。无论您如何编写,编译器都可以将负载折叠到后面的 ALU 指令中(或将其优化掉)。 (使用 AVX-512,可能能够折叠 _mm512_set1_pd(x)
广播加载以获取具有匹配元素宽度的指令。)
_mm*_load[u]_*
内在函数可能看起来就像您在那时要求单独的加载指令,但实际情况并非如此。如果你愿意,那只会让你的 C 看起来更像 asm。
就像两个 memcpy
对象之间的 int
可以优化掉或在方便时完成(只要结果就像是按源顺序完成的一样),因此可以存储/加载内在函数取决于您如何使用它们。就像 +
运算符不必编译为 add
指令一样,_mm_add_ps
不一定必须使用那些确切的操作数编译为 addps
,或者完全添加。
加载/存储内在函数基本上是为了向编译器传达对齐保证(通过 loadu/storeu),并为您处理类型(至少对于 ps 和 pd load[u]/store[u];整数仍然需要转换指针)。也适用于 AVX-512,以允许屏蔽加载和屏蔽存储。
以上代码是否被认为有任何危险?
没有。普通取消引用仍然是严格别名安全的,因为 __mm*
类型是特殊的。见
Is `reinterpret_cast`ing between hardware SIMD vector pointer and the corresponding type an undefined behavior?