SIMD

Расширения SSE и AVX/AVX2

Последнее обновление: 02.07.2023

SIMD (Single-Instruction, Multiple-Data - "Одна инструкция, много данных") представляет специальный набор инструкций, которые предоставляют параллельную обработку данных. То есть некоторые группы данных могут обрабатываться одновременно, благодаря чему увеличивается производительность и ускоряется выполнение программы. В архитектуре x86-64 инструкции SIMD представлены специальными расширениями SSE/AVX, которые имеют три поколения:

  • Архитектура SSE (Streaming SIMD Extensions), которая предоставляет шестнадцать 128-битных регистров XMM (поддерживают как целочисленные типы данных, так и типы с плавающей точкой)

  • Архитектура AVX/AVX2, которая поддерживает шестнадцать 256-битных регистров YMM (также поддерживают как целочисленные типы данных, так и типы с плавающей точкой)

  • Архитектура AVX-512, которая поддерживает до 32-х 512-битных регистров ZMM.

Архитектуры SSE и AVX поддерживают два основных типа данных: скалярные значения (отдельные числа) и векторы (наборы чисел). Скалярные значения представляют отдельные значения с плавающей точкой одинарной или двойной точности. Векторы содержат несколько значений с плавающей точкой или целых чисел (от 2 до 32 значений, в зависимости от типа данных: byte, word, dword, qword, real4 или real8, а также регистра и размера памяти) .

Регистры XMM (XMM0-XMM15) могут хранить одно 32-разрядное значение с плавающей точкой (то есть значение типа real4) или четыре значения с плавающей точкой одинарной точности (то есть вектор из 4-х значений). Регистры YMM (YMM0-YMM15) могут хранить 8 чисел с плавающей точкой одинарной точности (32-разрядных):

Хранение чисел с плавающей точкой одинарной точности в SIMD в архитектуре x86-64

Регистры XMM могут также хранить одно число с плавающей точкой двойной точности - real8 или вектор из двух значений чисел real8. Регистры YMM могут хранить вектор из четырех чисел с плавающей точкой двойной точности

Хранение чисел с плавающей точкой двойной точности в SIMD в архитектуре x86-64

Аналогичным образом, регистр XMM может хранить вектор с 16 значениями byte (YMM - вектор с 32 байтами), с 8 значениями word (YMM - вектор с 16 word), 4 числами dword ((YMM - вектор с 8 dword)) и 2 числами qword (YMM - 4 qword)

Хранение целых чисел в SIMD в архитектуре x86-64

Элементы вектора еще называются дорожками (lane) регистров XMM и YMM. Например, 128-битный регистр XMM может хранить вектор из 16 байтов. Биты с 0 по 7 — это дорожка 0, биты с 8 по 15 — дорожка 1, биты с 16 по 23 — дорожка 2, и так далее. Последние биты со 120 по 127 образуют дорожку 15. 256-битный регистр YMM имеет 32 байтовые дорожки, а 512-битный регистр ZMM имеет 64 байтовые дорожки.

Аналогично 128-битный регистр XMM имеет восемь дорожек размером для типов word (дорожки с 0 по 7). 256-битный регистр YMM имеет шестнадцать дорожек размером в слово (дорожки с 0 по 15). На процессорах с поддержкой AVX-512 регистр ZMM (размер 512 бит) имеет 32 дорожки для типов word, пронумерованные от 0 до 31. Регистр XMM имеет 4 дорожки размером с dword и real4 (дорожки с 0 по 3). Регистр YMM имеет 8 дорожек для dword и real4 (дорожки с 0 по 7). Регистр ZMM имеет 16 дорожек размера двойного слова или одинарной точности (номера от 0 до 15).

Для работы с этими расширениями MASM добавляет три типа данных:

  • xmmword: вектор размером 128 байт, который представляет регистр XMM

  • ymmword: вектор размером 256 байт, который представляет регистр YMM

  • zmmword: вектор размером 512 байт, который представляет регистр ZMM

Проверка доступности расширений для SIMD

Разные процессоры имеют разную поддержку расширений для SIMD. Более новые версии расширений могут быть доступны для более новых версий процессоров. Расширения SSE 4.2 было аннонсировано в 2006, и таким образом, есть очень большая вероятность, что компьютер, на котором будет запускаться программа, поддерживает это расширение (не говооря уже о более ранних версиях SSE). Расширения AVX были предложены в 2008 году, а первый процессор с этими расширениями - Sandy Bridge вышел в 2011 году. Расширения AVX2 вышли в свет с процессором Haswell в 2013 году. Расширения AVX-512, которые добавили поддержку 512-битных регистров, были предложены в 2013 г\оду и были впервые релизованы в процессорах Xeon Phi x200 и Skylake-X в 2015/2016 году.

Чтобы определить, поддерживает ли тот или иной процессор определенные расширения, мы можем применять инструкцию cpuid. Она принимает один параметр, который передавается через регистр EAX. В зависимости от значения, переданного в EAX, эта инструкция возвращает различную информацию о процессоре. Приложение может проверить возвращаемую информацию, чтобы узнать, доступны ли определенные функции процессора.

Например, чтобы узнать поддержку расширений для SIMD, в EAX передается значение 1. В этом случае результат инструкции помещается в регистр ECX. Определенные биты результат могут указывать на поддержку определенных возможностей:

Бит

Описание

0

Доступно SSE3

1

Доступно PCLMULQDQ

9

Доступно SSSE3

19

Доступно SSE4.1

20

Доступно SSE4.2

28

Доступно AVX (Advanced Vector Extensions)

Простейший пример:

.code
main proc       
    mov eax, 1
    cpuid
    mov eax, ecx
    ret
main endp
end

Например, на моем компьютере результатом инструкции cpuid является число -2428017 или 11111111110110101111001110001111 в бинарной форме. Исходя из установленных битов, можно узнать, какие именно версии расширений поддерживаются.

Дополнительную информацию можно получить, установив значения EAX = 7 и ECX = 0. В этом случае информация с битами будет помещаться в регистр EBX

Бит

Описание

3

Доступно BMI1 (Bit Manipulation Instruction - набор инструкций для манипуляции с битами)

5

Доступно AVX2

8

Доступно BMI2

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

.data
    SSE42Support = 00180000h       ; проверяем биты 19 и 20
    AVXSupport = 10000000h  ; проверяем бит 28
    AVX2Support = 20h   ; проверяем бит 5
.code
main proc 
    ; Определяем, доступны ли расширения AVX и соответственно регистры YMM
    mov eax, 7
    xor ecx, ecx
    cpuid
    and ebx, AVX2Support     ; проверяем на поддержку AVX2 бит 5
    jnz AVX2         ; если AVX доступно, переходим к метке AVX2

    mov eax, 1
    cpuid
    and ecx, AVXSupport     ; проверяем на поддержку AVX бит 28
    jnz AVX         ; если AVX доступно, переходим к метке AVX

    and ecx, SSE42Support     ; проверяем на поддержку SSE42 бит 19 и 20
    jnz SSE42         ; если AVX доступно, переходим к метке SSE42

    mov eax, 0      ; если ни одно из трех расширений не установлено
    jmp exit
AVX2: 
    mov rax, 52
    jmp exit
AVX: 
    mov rax, 50
    jmp exit
SSE42: 
    mov rax, 42
    jmp exit

exit:
    ret
end

В данном случае применяем к результату инструкции cpuid одну из масок и по результатам сравнения помещаем в регистр RAX то или иное число.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850