Введение
Автоматическая векторизация, в контексте параллельных вычислений, является частным случаем автоматической параллелизации, при котором компьютерная программа преобразуется из скалярной реализации, обрабатывающей одну пару операндов за раз, в векторную реализацию, обрабатывающую одну операцию над несколькими парами операндов одновременно. Например, современные компьютеры, включая специализированные суперкомпьютеры, обычно поддерживают векторные операции, которые одновременно выполняют такие операции, как четыре сложения (с использованием аппаратного обеспечения SIMD или SPMD).
However, in most programming languages one typically writes loops that sequentially perform additions of many numbers. Here is an example of such a loop, written in C:
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
A vectorizing compiler transforms such loops into sequences of vector operations. These vector operations perform additions on blocks of elements from the arrays a, b and c. Automatic vectorization is a major research topic in computer science.
Однако, в большинстве языков программирования обычно пишутся циклы, последовательно выполняющие сложение множества чисел. Вот пример такого цикла, написанного на языке C:
However, in most programming languages one typically writes loops that sequentially perform additions of many numbers. Here is an example of such a loop, written in C:
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
A vectorizing compiler transforms such loops into sequences of vector operations. These vector operations perform additions on blocks of elements from the arrays a, b and c. Automatic vectorization is a major research topic in computer science.
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
However, in most programming languages one typically writes loops that sequentially perform additions of many numbers. Here is an example of such a loop, written in C:
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
A vectorizing compiler transforms such loops into sequences of vector operations. These vector operations perform additions on blocks of elements from the arrays a, b and c. Automatic vectorization is a major research topic in computer science.
Векторизирующий компилятор преобразует такие циклы в последовательности векторных операций. Эти операции выполняют сложение над блоками элементов массивов a, b и c. Автоматическая векторизация является важной областью исследований в информатике.
However, in most programming languages one typically writes loops that sequentially perform additions of many numbers. Here is an example of such a loop, written in C:
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
A vectorizing compiler transforms such loops into sequences of vector operations. These vector operations perform additions on blocks of elements from the arrays a, b and c. Automatic vectorization is a major research topic in computer science.
Предыстория
Ранние компьютеры обычно имели один логический блок, который выполнял одну инструкцию над одной парой операндов за раз. Поэтому языки и программы для компьютеров разрабатывались для последовательного выполнения. Однако современные компьютеры способны выполнять множество операций одновременно. Следовательно, многие оптимизирующие компиляторы выполняют автоматическую векторизацию, при которой части последовательных программ преобразуются в параллельные операции. Векторизация циклов преобразует процедурные циклы, назначая каждому блоку обработки пару операндов. Программы проводят большую часть времени в таких циклах. Поэтому векторизация может значительно ускорить их работу, особенно при обработке больших объемов данных. Векторизация циклов реализована в Intel MMX, SSE и AVX, в Power ISA AltiVec, а также в наборах инструкций ARM NEON, SVE и SVE2. Многие ограничения могут препятствовать или затруднять векторизацию. В некоторых случаях векторизация может замедлить выполнение, например, из-за синхронизации конвейера или времени перемещения данных. Анализ зависимостей циклов определяет циклы, которые можно векторизовать, основываясь на зависимостях данных инструкций внутри циклов.
Гарантии
Автоматическая векторизация, как и любая оптимизация циклов или другая оптимизация времени компиляции, должна точно сохранять поведение программы.
Зависимости данных
Все зависимости должны учитываться во время выполнения, чтобы избежать некорректных результатов. Как правило, петлевые инвариантные зависимости и лексически прямые зависимости легко поддаются векторизации, а лексически обратные зависимости можно преобразовать в лексически прямые. Однако эти преобразования должны выполняться безопасно, чтобы гарантировать сохранение исходных зависимостей между всеми операторами. Циклические зависимости должны обрабатываться отдельно от векторизованных инструкций.
Точность данных
Точность целых чисел (разрядность) должна сохраняться во время выполнения векторных инструкций. Правильная векторная инструкция должна выбираться исходя из размера и поведения внутренних целых чисел. Кроме того, при использовании смешанных целочисленных типов необходимо проявлять особую осторожность при приведении типов, чтобы не потерять точность. Особое внимание следует уделять расширению знака (поскольку несколько целых чисел упакованы в одном регистре), а также операциям сдвига или операциям с переносом, которые в противном случае учитывались бы. Точность чисел с плавающей точкой также должна сохраняться, если только не отключено соответствие стандарту IEEE 754, в этом случае операции будут выполняться быстрее, но результаты могут незначительно отличаться. Значительные отклонения, даже при игнорировании стандарта IEEE 754, обычно указывают на ошибку программиста.
Теория
Для векторизации программы оптимизатор компилятора должен сначала понять зависимости между операторами и, при необходимости, изменить их порядок. Как только зависимости установлены, оптимизатор должен правильно организовать инструкции, заменяя подходящие из них на векторные инструкции, которые оперируют с несколькими элементами данных.
Кластеризация
Используя граф, оптимизатор может затем кластеризовать сильно связанные компоненты (SCC) и отделять векторизуемые операторы от остальных. Например, рассмотрим фрагмент программы, содержащий три группы операторов внутри цикла: (SCC1 + SCC2), SCC3 и SCC4, в таком порядке, при котором только вторая группа (SCC3) может быть векторизована. В результате, итоговая программа будет содержать три цикла, по одному для каждой группы, и только средний из них будет векторизован. Оптимизатор не может объединить первый и последний циклы, не нарушив порядок выполнения операторов, что привело бы к потере необходимых гарантий.
Ручная векторизация
В большинстве компиляторов C и C++ можно использовать встроенные функции для ручной векторизации, что требует значительных усилий программиста и усложняет поддержку кода.