Spec-Zone.ru › GCC 4

6.49 Использование векторных инструкций через встроенные функции

В некоторых целевых системах набор инструкций содержит векторные SIMD-инструкции, которые работают с несколькими значениями, содержащимися в одном большом регистре одновременно. Например, на i386 можно использовать расширения MMX, 3DNow! и SSE.

Первый шаг в использовании этих расширений — предоставление необходимых типов данных. Это должно быть сделано с использованием соответствующего typedef:

typedef int v4si __attribute__ ((vector_size (16)));

Тип int определяет базовый тип, а атрибут — размер вектора для переменной, измеряемый в байтах. Например, объявление выше приводит к тому, что компилятор устанавливает режим для типа v4si в 16 байт и делит его на блоки размером int. Для 32-битного int это означает вектор из 4 блоков по 4 байта, а соответствующий режим foo — V4SI.

Атрибут vector_size применим только к целочисленным и плавающим скалярам, хотя массивы, указатели и значения возвращаемых функций допускаются в сочетании с этим конструктом. В настоящее время допускаются только размеры, являющиеся степенью двойки.

Все основные целочисленные типы могут использоваться в качестве базовых типов, как со знаком, так и без знака: char, short, int, long, long long. Кроме того, float и double можно использовать для построения вещественных векторных типов.

Указание комбинации, которая не допустима для текущей архитектуры, заставляет GCC синтезировать инструкции с использованием более узкого режима. Например, если вы указываете переменную типа V4SI, а ваша архитектура не поддерживает этот конкретный тип SIMD, GCC генерирует код, использующий 4 SIs.

Определенные таким образом типы можно использовать с подмножеством обычных операций C. В настоящее время GCC разрешает использование следующих операторов для этих типов: +, -, *, /, unary minus, ^, |, &, ~, %.

Операции ведут себя как C++ valarrays. Сложение определяется как сложение соответствующих элементов операндов. Например, в коде ниже каждый из 4 элементов в a складывается с соответствующими 4 элементами в b, а полученный вектор сохраняется в c.

typedef int v4si __attribute__ ((vector_size (16)));

v4si a, b, c;

c = a + b;

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

Можно использовать операторы сдвига <<, >> для векторов целочисленного типа. Операция определяется следующим образом: {a0, a1, ..., an} >> {b0, b1, ..., bn} == {a0 >> b0, a1 >> b1, ..., an >> bn}. Векторные операнды должны иметь одинаковое количество элементов.

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

typedef int v4si __attribute__ ((vector_size (16)));

v4si a, b, c;
long l;

a = b + 1;    /* a = b + {1,1,1,1}; */
a = 2 * b;    /* a = {2,2,2,2} * b; */

a = l + a;    /* Error, cannot convert long to int. */

Векторы могут индексироваться так, как если бы вектор был массивом с тем же количеством элементов и базовым типом. Доступ за пределы границ вызывает неопределённое поведение во время выполнения. Предупреждения о доступе за пределы границ для индексирования векторов можно включить с помощью -Warray-bounds.

Поддержка сравнения векторов с стандартными операторами сравнения: ==, !=, <, <=, >, >=. Операнды сравнения могут быть векторными выражениями целочисленного или вещественного типа. Сравнение между векторами целочисленного типа и вещественного типа не поддерживается. Результатом сравнения является вектор той же ширины и числа элементов, что и операнды сравнения, с целочисленным элементом типа со знаком.

Векторы сравниваются по элементам, производя 0, когда сравнение ложно, и -1 (константа соответствующего типа, где все биты установлены) в противном случае. Рассмотрим следующий пример.

typedef int v4si __attribute__ ((vector_size (16)));

v4si a = {1,2,3,4};
v4si b = {3,2,1,4};
v4si c;

c = a >  b;     /* The result would be {0, 0,-1, 0}  */
c = a == b;     /* The result would be {0,-1, 0,-1}  */

В C++ доступен тернарный оператор ?:. a?b:c, где b и c — векторы одного типа, а a — целочисленный вектор с тем же числом элементов того же размера, что и b и c, вычисляет все три аргумента и создаёт вектор {a[0]?b[0]:c[0], a[1]?b[1]:c[1], ...}. Обратите внимание, что в отличие от OpenCL, a интерпретируется как a != 0, а не a < 0. Как и в случае с бинарными операциями, этот синтаксис также принимается, когда один из b или c является скаляром, который затем преобразуется в вектор. Если оба b и c являются скалярами, а тип true?b:c имеет тот же размер, что и тип элемента a, тогда b и c преобразуются в векторный тип, элементы которого имеют этот тип и с тем же количеством элементов, что и a.

Векторное перемешивание доступно с помощью функций __builtin_shuffle (vec, mask) и __builtin_shuffle (vec0, vec1, mask). Обе функции строят перестановку элементов из одного или двух векторов и возвращают вектор того же типа, что и входной(е) вектор(ы). mask — целочисленный вектор с той же шириной (W) и количеством элементов (N) , что и выходной вектор.

Элементы входных векторов нумеруются в порядке памяти vec0, начиная с 0, и vec1, начиная с N. Элементы mask рассматриваются по модулю N в случае одного операнда и по модулю 2*N в случае двух операндов.

Рассмотрим следующий пример,

typedef int v4si __attribute__ ((vector_size (16)));

v4si a = {1,2,3,4};
v4si b = {5,6,7,8};
v4si mask1 = {0,1,1,3};
v4si mask2 = {0,4,2,5};
v4si res;

res = __builtin_shuffle (a, mask1);       /* res is {1,2,2,4}  */
res = __builtin_shuffle (a, b, mask2);    /* res is {1,5,3,6}  */

Обратите внимание, что __builtin_shuffle намеренно семантически совместим с OpenCL-функциями shuffle и shuffle2.

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

Нельзя выполнять операции между векторами разной длины или разной знаковости без преобразования типа.

© Free Software Foundation
Licensed under the GNU Free Documentation License, Version 1.3.
https://gcc.gnu.org/onlinedocs/gcc-4.9.4/gcc/Vector-Extensions.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API