Оптимизация изменяемой и неизменяемой векторной математики

Какой стиль кодирования лучше подходит для оптимизации компилятора? В частности, меня интересует 1) минимизация количества временных значений, которые сразу выбрасываются, и 2) автоматическая векторизация, т.е. генерация SIMD-инструкций для арифметики.

Предположим, у меня есть эта структура:

#define FOR_EACH for (int i = 0; i < N; ++i)

template<typename T, unsigned N>
struct Vector {
    void scale(T scalar) {
        FOR_EACH v[i] *= scalar;
    }

    void add(const Vector<T, N>& other) {
        FOR_EACH v[i] += other.v[i];
    }

    void mul(const Vector<T, N>& other) {
        FOR_EACH v[i] *= other.v[i];
    }

    T v[N];
};

Пример использования этой структуры:

Vector<int, 3> v1 = ...;
Vector<int, 3> v2 = ...;
v1.scale(10);
v1.add(v2);
v1.mul(v2);

Это изменчивый подход.

Альтернативный неизменяемый подход может выглядеть так:

template<typename T, unsigned N>
struct Vector {
    Vector(const Vector<T, N>& other) {
        memcpy(v, other.v, sizeof(v));
    }

    Vector<T, N> operator+(const Vector<T, N>& other) const {
        Vector<T, N> result(*this);
        FOR_EACH result.v[i] += other.v[i];
        return result;
    }

    Vector<T, N> operator*(T scalar) const {
        Vector<T, N> result(*this);
        FOR_EACH result.v[i] *= scalar;
        return result;
    }

    Vector<T, N> operator*(const Vector<T, N>& other) const {
        Vector<T, N> result(*this);
        FOR_EACH result.v[i] *= other.v[i];
        return result;
    }

    T v[N];
};

Пример использования:

Vector<int, 3> v1 = ...;
Vector<int, 3> v2 = ...;
auto result = (v1 * 10 + v2) * v2;

Теперь меня не интересует дизайн API в этом вопросе. Предположим, что оба решения жизнеспособны в этом отношении.

Кроме того, вместо int в примере кода может быть также float или double.

Меня интересует вот что: какой дизайн легче анализировать современным компилятором C++? Я не нацелен на какой-то конкретный компилятор. Если у вас есть опыт работы с каким-либо компилятором и вы знаете, как он работает с оптимизациями, о которых я спрашиваю, поделитесь своим опытом.

  • Вторая версия выдает много временных значений. Может ли компилятор избавиться от них, если он в конечном итоге встроит все вызовы операторов и увидит все содержащиеся в них арифметические выражения? (Я предполагаю, что без встраивания ни один компилятор не может устранить временные файлы из-за возможных побочных эффектов)

  • Первая версия минимизирует количество временных, но строит строго последовательный расчет. Может ли компилятор по-прежнему определить намерение и переупорядочить операции таким образом, чтобы свести к минимуму количество операций и обеспечить их распараллеливание (на уровне инструкций ЦП)?

  • Насколько сложно современному компилятору векторизовать циклы выше?


person Alexei Sholik    schedule 14.07.2013    source источник
comment
Прямая индексация элементов упрощает компилятору их векторизацию. Когда индексы применяются косвенно со сложными алгоритмами, компилятор может дать сбой.   -  person huseyin tugrul buyukisik    schedule 14.07.2013


Ответы (1)


Насколько я понимаю, первый пример легко векторизовать, пока есть поддержка в целевой архитектуре. Это связано с тем, что между элементами в последовательных итерациях нет зависимости от данных.

Если у вас есть циклы, в которых существуют зависимости данных между элементами в последовательной итерации, в некоторых случаях их можно удалить с помощью программной конвейерной обработки. Конвейерная обработка программного обеспечения помогает векторизации.

В некоторых архитектурах вычисления с плавающей запятой нелегко векторизовать из-за ограниченного количества исполнительных блоков с плавающей запятой.

Во втором примере есть временные файлы, которые можно удалить путем встраивания.

Полезные ссылки:

person A. K.    schedule 14.07.2013
comment
Спасибо за ссылки. Мне все еще любопытна другая часть вопроса, а именно оптимизация временных файлов. Думаю, мне нужно просто сравнить вывод разных компиляторов, чтобы быть уверенным. - person Alexei Sholik; 15.07.2013
comment
Проверьте мой ответ здесь stackoverflow.com/a/17476463/811335, это может помочь. - person A. K.; 15.07.2013