为什么Visual Studio Compiler不在我的Mersenne-Twister实现中循环展开?



我目前正在C++年开发我自己的Mersenne Twister实现。该算法涉及多次调用以下函数:

void twistIteration(uint32_t i)
{
uint32_t x = (mt[i] & MASK_UPPER) + (mt[(i + 1) % N] & MASK_LOWER);
uint32_t xA = x >> 1;
if (x & 1)
{
xA ^= A;
}
mt[i] = mt[(i + M) % N] ^ xA;
}

请注意,N、M 和 MASK_UPPER 是模板参数,因此它们在编译时是已知的。我在另一个函数中调用此函数:

void twist()
{
for (uint32_t i = 0; i < N; i++)
{
twistIteration(i);
}
index = 0;
}

在我的机器上,使用此算法生成 128.000.000 个随机数大约需要 0.95 秒。但是,我找到了一种方法,通过稍微更改扭曲函数来显着加快算法速度:

void twist()
{
for (uint32_t i = 0; i < N - 1; i++)
{
twistIteration(i);
}
twistIteration(N - 1);
index = 0;
}

换句话说,我展开循环的最后一次迭代,以便可以在编译时计算表达式(i + 1) % N(i + M) % N。相同数量的随机数现在只需要 0,60 秒,这是一个巨大的改进。 我的问题是:为什么编译器不为我执行此操作?我使用默认的VS2017发布模式进行编译,并将"快速代码优化但代码更大"设置为true。我是否缺少一些标志,或者这只是Visual Studio编译器的一些奇怪行为?

依靠编译器优化来处理这样的事情可能会很棘手。你最好的选择是尝试不同的标志,看看你是否能得到明显的差异。

也就是说,我会尝试显着增加您生成的元素数量。这 0.35 秒很可能只是方差,可能取决于各种其他因素。尝试对需要一分钟(或更长时间(才能运行的东西进行压力测试,看看差异是否仍然如此显着。

即使有 thay 设置,它也可能抵抗展开更大的循环。

template<std::size_t...Is>
inline auto index_over(std::index_sequence<Is...>){
return [](auto&&f)->decltype(auto){
return decltype(f)(f)(std::integral_constant<std::size_t,Is>{}...);
}
}
template<std::size_t N>
inline auto index_upto(std::integral_constant<std::size_t,N> ={}){
return index_over(std::make_index_sequence<N>{});
}
template<class F>
inline auto foreacher(F&&f){
return [&](auto&&...args){
using discard=int[];
(void)discard{0,(void(
f(decltype(args)(args))
),0)...};
};
}

现在

auto index=index_upto<N>();
index(foreacher([&](auto I){
twistIteration(I);
));

是强制循环展开到疯狂的程度(需要一个聪明的编译器来重新滚动该循环(。

对任何错别字表示歉意,在电话中。 你可以谷歌site:stackoverflow.com yakk加上index_uptotomfind变体,拼写错误可能更少。

最新更新