我想构建一个表示多个(比如说N
)算术类型的数据类型,并使用运算符重载提供与算术类型相同的接口,这样我就得到了像 Agner Fog 的vectorclass这样的数据类型。
请看这个例子:Godbolt
#include <array>
using std::size_t;
template<class T, size_t S>
class LoopSIMD : std::array<T,S>
{
public:
friend LoopSIMD operator*(const T a, const LoopSIMD& x){
LoopSIMD result;
for(size_t i=0;i<S;++i)
result[i] = a*x[i];
return result;
}
LoopSIMD& operator +=(const LoopSIMD& x){
for(size_t i=0;i<S;++i){
(*this)[i] += x[i];
}
return *this;
}
};
constexpr size_t N = 7;
typedef LoopSIMD<double,N> SIMD;
SIMD foo(double a, SIMD x, SIMD y){
x += a*y;
return x;
}
对于一定数量的元素,这似乎工作得很好,gcc-10 为 6,clang-11 为 27。对于大量元素,编译器不再使用 FMA(例如vfmadd213pd
)操作。相反,它们分别进行乘法(例如vmulpd
)和加法(例如vaddpd
)。
问题:
- 这种行为有充分的理由吗?
- 是否有任何编译器标志可以让我可以为 gcc 增加 6 和为 clang 增加 27 的上述值?
谢谢!