Развертывание переносимого цикла с параметром шаблона в C++ с помощью GCC/ICC

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

Это можно легко сделать для фиксированного количества циклов с помощью директив компилятора: #pragma GCC unroll (16) распознается обоими компиляторами, к которым я стремлюсь, компилятором Intel C++ ICC и GCC, в то время как #pragma unroll (16), к сожалению, игнорируется GCC. Я также могу использовать параметры шаблона или директивы препроцессора в качестве ограничений с ICC (аналогично тому, что вы можете сделать с nvcc), например

template <int N>
// ...
#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

or

#define N 16

#pragma unroll (N)
for (int i = 0; i < N; ++i) {
// ...
}

не выдавать ошибки или предупреждения с -Wall -w2 -w3 при компиляции с ICC, в то время как дополнительный синтаксис #pragma GCC unroll (N) с GCC (-Wall -pedantic) выдает ошибку в GCC 9.2.1 20191102 в Ubuntu 18.04:

error: ‘#pragma GCC unroll’ requires an assignment-expression that evaluates to a non-negative integral constant less than 65535
#pragma GCC unroll (N)

Кто-нибудь знает способ сделать развертку цикла на основе параметра шаблона с директивами компилятора переносимым способом (по крайней мере, работая с GCC и ICC)? На самом деле мне нужно только полное развертывание всего цикла, так что что-то вроде #pragma GCC unroll (all) мне уже очень помогло бы.

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


person 2b-t    schedule 13.08.2020    source источник
comment
Идиоматический подход GCC для полного развертывания данного цикла, на самом деле, к сожалению, будет подходом с опциями push/pop, #pragma GCC push_options, #pragma GCC optimize ("unroll-loops"), for ... , #pragma GCC pop_options, который, однако, не будет переносимым с ICC.   -  person dfrib    schedule 14.08.2020


Ответы (1)


К сожалению, в настоящее время не существует последовательного способа сделать это.

В итоге я использовал директиву препроцессора, которая решает, следует ли развертывать в зависимости от параметра шаблона, если доступен ICC компилятора Intel C++, или использовать постоянный коэффициент для развертывания для любого другого компилятора (например, GCC ). Эту идею можно объединить с комментарием пользователя dfri и отключить параметры push/pop с помощью соответствующей директивы препроцессора. Вот небольшой пример:

template <int N>
void exampleContainingLoop()
{
    #if defined(__ICC) || defined(__ICL)
    #pragma unroll (N)
    #else
    #pragma GCC unroll (4)
    #endif
    for (int i = 0; i < N; ++i)
    {
        // ...
    }
    
    return;
}
person 2b-t    schedule 06.09.2020