Операция загрузки вектора из памяти, или загрузка скаляра из обычного register file является очень долгой, поэтому очень важно формировать основные константы на лету без загрузки. Константы
0
Основа формирования константы 0 - это векторный XOR одного операнда с самим собой. Поскольку: 0 xor 0 = 0 и 1 xor 1 = 0 то после выполнения этой операции мы получим 0 в векторном регистре.
-1
Multimedia Unit имеет команды паралельного сравнения, которые устанавливают результатирующий элемент вектора в 1...1, если условие выполняется, или в 0...0, если условие не выполняется. Мы можем использовать вариант VCMPEQ - проверяющий на равенство используя в качестве параметров один и тот же операнд два раза. Поскольку X = X, то в результате весь векторный регистр будет содержать одни 11..11, что означает -1 для каждого элемента вектора.
1
Получение единицы основано на простом соотношении: 1 = 0 - (-1) а получать 0 и -1 мы уже умеем.
-X
Основа для получения -X: -X = 0 - X ноль мы тоже умеем получать.
NOT
_ Основа для получения X - операция XOR Поскольку: 0 xor 1 = 1 1 xor 1 = 0 то получаем: _ X = X xor (-1) а -1 мы тоже умеем получать.
ABS
Для вычислений часто приходиться получать абсолютную величину числа (модуль). Принцип вычисления модуля базируется на векторной операции VMAX - которая возвращает максимальный из своих операндов. Собственно: |X| = X, если X >= 0 -X, если X < 0 или |X| = MAX(X, -X) собсвенно -X мы вычислять умеем: -X = 0 - X
NABS
То же самое действует для вычисления negative absolute value, только используется не VMAX, а VMIN -|X| = X, если X < 0 -X, если X >= 0 или -|X| = MIN(X, -X) собственно результат мы получили.
Используя команды для паралельного сравнения и логику, очень легко достичь функциональности Conditional Move, которая как известно уменьшает число ветвлений и тем самым увеличивает быстродействие - что особенно необходимо для векторных вычислений. CMOV
Пример вычисляет: destination[i] = (source1[i] > source2[i])? source1[i] : source2[i] При этом считам что: AF, C>G, D source2[i])? -1 : 0 Затем отрицательные результаты сравнения для первого операнда маскируются по маске temp1[i] = source1[i] & mask[i] а для второго операнда по инверсной маске temp2[i] = source2[i] & (~mask[i]) что означает: temp1[i] = (source1[i] > source2[i])? source1[i] : 0 и temp2[i] = (source1[i] > source2[i])? 0 : source[2] делая destination[i] = temp1[i] | temp2[i] получаем то что мы и хотели: destination[i] = (source1[i] > source2[i])? source1[i] : source2[i] 4 векторных команды и никаких ветвлений Самое интересное, что таже техника используется и для FP векторов. Поэтому есть команды типа Vector Parallel Compare и ЛОГИЧЕСКИЕ ВЕКТОРНЫЕ ОПЕРАЦИИ для FP векторов, даже если FP вектор unit - является отдельным и не в состоянии хранить integer data. Но возможность conditional move все искупает.
Bound
С помощью MAX и MIN можно делать насыщение по любым границам, таким образом держа результаты в нужном диапазоне