首页 > 解决方案 > 如何减少 constexpr 函数的编译时间?

问题描述

假设我们想在编译时构建一个非平凡的表

template<int N, int M>
constexpr auto foo()
{
    std::array<std::array<int, N>, M> a = {};
    for(int m = 1; m < M; m++)
        for(int n = 1; n < N; n++)
        {
            // For exposition only
            auto x = (m ^ 42) + (n << 3) - m;
            auto y = (n ^ 420) + (m % 420);
            a[m][n] = (a[(x + m) % m][(y + n) % n] + (x ^ y)) % 0xFACADE;
        }
    return a;
}

constexpr auto bar(int n, int m)
{
    constexpr auto dim = /* something */;
    constexpr auto table = foo<dim, dim>();
    return table[n][m];
}

将编译时间推到最高点并不需要太多。另一种方法是通过脚本将表格生成为源代码,这显然不太好。

如何减少此类函数的编译时间?


一些动机

constexpr函数与常规函数有很大不同,与常规函数相比极其缓慢。除了由编译器执行之外,它们还有边界检查、溢出检查和几乎所有防止 UB 的检查。我怀疑这会使从常规函数中收集的大多数直觉变得毫无用处。

标签: c++optimizationconstexpr

解决方案


我想编译器只是优化了以下几点,所以你可能没有任何优势,但是:

1)m ^ 42并且m % 420不依赖于n,因此您可以在内部循环之外计算它们

2)如果我没记错的话,

(x + m) % m  ==  x % m + m % m
             ==  x % m + 0
             ==  x % m

(y + n) % n  ==  y % n + n % n
             ==  y % n + 0
             ==  y % n

3)您可以尝试将一些添加constauto变量中。

所以你可以试试

template <int N, int M>
constexpr auto foo ()
{
    std::array<std::array<int, N>, M> a = {};

    for(int m = 1; m < M; m++)
    {
        auto const m42 = m ^ 42;
        auto const m420 = m % 420;

        for(int n = 1; n < N; n++)
        {
            // For exposition only
            auto const x = m42 + (n << 3) - m;
            auto const y = (n ^ 420) + m420;
            a[m][n] = (a[x % m][y % n] + (x ^ y)) % 0xFACADE;
        }
    }
    return a;
}

如果这可行,您可以尝试重新处理x % m,拆分x不依赖于n( m42 - m) 的组件和依赖的组件 ( n << 3),这样您就可以计算x % m内部循环外部的一部分。


推荐阅读