g ++, диапазон на основе и векторизация

учитывая следующий диапазон на основе цикла в C ++ 11

for ( T k : j )
{
...
}

имеются g++ или же clang++ флаги оптимизации, которые могут ускорить скомпилированный код?

Я не говорю о каких-либо for цикл Я рассматриваю только эту новую конструкцию C ++ 11.

1

Решение

Оптимизация циклов очень редко связана с оптимизацией реального кода итерации цикла (for ( T k : j ) в этом случае), но очень много об оптимизации того, что в цикле.

Теперь, так как это ... в этом случае невозможно сказать, поможет ли, например, развертывание цикла, или объявить функции как встроенные [или просто переместить их так, чтобы компилятор мог их видеть, и поместить их как встроенные], используя автоматическую векторизацию или, возможно, используя совершенно другой алгоритм внутри цикла.

Примеры в параграфе выше немного подробнее:

  1. Развертывание цикла — по сути, выполните несколько итераций цикла, не возвращаясь к началу цикла. Это наиболее полезно, когда содержимое цикла очень мало. Существует автоматическое развертывание, при котором компилятор выполняет развертывание, или вы можете развернуть код вручную, просто выполнив, скажем, четыре элемента в каждой итерации цикла, а затем переместив четыре элемента вперед в каждом обновлении переменной цикла или обновив итератор несколько раз в течение сам цикл [но это, конечно, означает, что не использовать основанный на диапазоне цикл for].
  2. Встроенные функции — компилятор будет брать (обычно небольшие) функции и помещать их в сам цикл, вместо того, чтобы вызывать их. Это экономит время, необходимое процессору для вызова другого места в коде и возврата назад. Большинство компиляторов делают это только для функций, которые «видны» компилятору во время компиляции, поэтому исходный код должен находиться либо в том же исходном файле, либо в заголовочном файле, который включен в исходный файл, который компилируется.
  3. Автоматическая векторизация — использование инструкций SSE, MMX или AVX для обработки нескольких элементов данных в одной инструкции (например, одна инструкция SSE может добавить четыре float значения еще четыре float в одной инструкции). Это быстрее, чем работать с одним элементом данных за раз (в большинстве случаев, иногда это бесполезно из-за дополнительных сложностей с попыткой объединить различные элементы данных, а затем с сортировкой, что происходит, когда вычисление закончено).
  4. Выберите другой алгоритм — часто есть несколько способов решить конкретную проблему. В зависимости от того, чего вы пытаетесь достичь, цикл for [любого рода] может быть не самым правильным решением, во-первых, или код внутри цикла может, возможно, использовать более умный способ вычисления / перестановки / что-либо еще -действует для достижения необходимого вам результата.

Но ... Слишком расплывчато, чтобы сказать, какое из перечисленных выше решений поможет улучшить ваш код.

3

Другие решения

НКУ документация об автовекторизации ничего не говорит о диапазоне на основе for петля. Кроме того, его код сводится к:

{
auto && __range = range_expression ;
for (auto __begin = begin_expr,
__end = end_expr;
__begin != __end; ++__begin) {
range_declaration = *__begin;
loop_statement
}
}

Таким образом, технически говоря, любой флаг помогает автоматически векторизовать конструкции в этом виде регулярных for должен автоматически векторизовать подобный диапазон на основе for петля. Я действительно делаю это, компиляторы переводят только на основе диапазона for петли к регулярному for циклы, а затем пусть векторизация делает свою работу на этих старых циклах. Это означает, что нет необходимости в флаге, чтобы ваш компилятор автоматически векторизовал ваш диапазон for Зацикливается на любом сценарии.


Так как реализация GCC была запрошена, вот соответствующий комментарий в исходном коде, описывающий, что на самом деле делается для основанного на диапазоне for цикл (вы можете проверить файл реализации parser.c, если хотите взглянуть на код):

/* Converts a range-based for-statement into a normal
for-statement, as per the definition.

for (RANGE_DECL : RANGE_EXPR)
BLOCK

should be equivalent to:

{
auto &&__range = RANGE_EXPR;
for (auto __begin = BEGIN_EXPR, end = END_EXPR;
__begin != __end;
++__begin)
{
RANGE_DECL = *__begin;
BLOCK
}
}

If RANGE_EXPR is an array:
BEGIN_EXPR = __range
END_EXPR = __range + ARRAY_SIZE(__range)
Else if RANGE_EXPR has a member 'begin' or 'end':
BEGIN_EXPR = __range.begin()
END_EXPR = __range.end()
Else:
BEGIN_EXPR = begin(__range)
END_EXPR = end(__range);

If __range has a member 'begin' but not 'end', or vice versa, we must
still use the second alternative (it will surely fail, however).
When calling begin()/end() in the third alternative we must use
argument dependent lookup, but always considering 'std' as an associated
namespace.  */

Как вы можете видеть, они не делают ничего, кроме того, что фактически описывает стандарт.

3

По вопросам рекламы [email protected]