强制编译器通过0和1优化乘法的一种方法是手动展开循环。 为了简单起见,我们使用
#include
#include
constexpr std::size_t n = 12;
using Array = std::array;
然后,我们可以使用折叠表达式(或递归(如果不可用,则递归))实现一个简单的for (std::size_t i = 0; i < n; ++i) ...函数:
template<:size_t... is>
double dot(const Array& x, const Array& y, std::index_sequence)
{
return ((x[is] * y[is]) + ...);
}
double dot(const Array& x, const Array& y)
{
return dot(x, y, std::make_index_sequence{});
}
现在让我们来看一下您的功能
double test(const Array& b)
{
const Array a{1}; // = {1, 0, ...}
return dot(a, b);
}
gcc 8.2使用for (std::size_t i = 0; i < n; ++i) ... gcc产生:
test(std::array const&):
movsd xmm0, QWORD PTR [rdi]
ret
clang 6.0.0遵循相同的原则:
test(std::array const&): # @test(std::array const&)
movsd xmm0, qword ptr [rdi] # xmm0 = mem[0],zero
ret
例如,对于
double test(const Array& b)
{
const Array a{1, 1}; // = {1, 1, 0...}
return dot(a, b);
}
我们得到
test(std::array const&):
movsd xmm0, QWORD PTR [rdi]
addsd xmm0, QWORD PTR [rdi+8]
ret
加成。 Clang展开了for (std::size_t i = 0; i < n; ++i) ...循环,没有所有这些折叠表达式的技巧,gcc却没有,并且需要一些帮助。