Как уменьшить время компиляции для функций constexpr? - PullRequest
0 голосов
/ 11 ноября 2018

Предположим, что мы хотим построить нетривиальную таблицу во время компиляции

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 на месте. Я подозреваю, что это делает большую часть интуиции, собранной из обычных функций, бесполезной.

1 Ответ

0 голосов
/ 11 ноября 2018

Полагаю, компилятор просто оптимизировал следующие моменты, поэтому, вероятно, вы не получите никаких преимуществ, но:

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) вы можете попробовать добавить некоторые const к auto переменным.

Так что вы можете попробовать с

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 вне внутреннего цикла.

...