#include <cstddef>
float cast(size_t sz){return sz;}
Run Code Online (Sandbox Code Playgroud)
在 Clang 13.0.1 上编译上述代码会-mavx2 -O3生成以下代码:
cast(unsigned long): # @cast(unsigned long)
test rdi, rdi
js .LBB0_1
vcvtsi2ss xmm0, xmm0, rdi
ret
.LBB0_1:
mov rax, rdi
shr rax
and edi, 1
or rdi, rax
vcvtsi2ss xmm0, xmm0, rdi
vaddss xmm0, xmm0, xmm0
ret
Run Code Online (Sandbox Code Playgroud)
GCC、MSVC 和 Intel 编译器以及旧版本也可以生成类似的代码。
我理解该算法的总体目标是解决以下事实:在 AVX-512 之前,没有从 64 位无符号 int 到 float 或 double 的转换指令。
因此,如果数字大到足以被解释为负数,则会将其减半、转换,然后将其加倍。但是,如果在原始整数中设置最低有效位,那么设置它的目的是什么?
这似乎是浪费时间,因为浮点数只有 23 个有效位,并且该位保证不重要。也许如果它是增量指令,则在某些情况下可能会影响有效位。但仅仅一个 or 指令似乎没有做任何事情。
为什么 clang 17.0.1 不会矢量化以下函数中的循环:
void adapt(std::span<const F, N + 1> signal)
{
F true_val = signal.back();
F y = dot_prod<F, N>(&signal[0], w.begin());
F e = true_val - y;
F dot = dot_prod<F, N>(&signal[0], &signal[0]);
F nu = mu / (eps + dot);
for (size_t i = 0; i < N; i++)
{
w[i] += nu * e * signal[i];
}
}
Run Code Online (Sandbox Code Playgroud)
不存在浮点关联性的附带依赖性或问题,并且 GCC 13.2 对其进行矢量化没有任何问题。
其背景是我正在尝试优化我的代码以使用矢量化点积。std::inner_product由于浮点关联性问题,通常会发出标量实现,除非您使用-ffast-math. 但是,我只想-ffast-math应用于单个函数,并且我一直在寻找一种可移植的方法来为 clang 和 GCC 执行此操作。在查看输出时,我注意到 clang 不会矢量化另一个循环。 …