Сохранение состояния регистров SSE/AVX

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

При работе с инструкциями расширений SSE/AVX нам может потребоваться сохранить значения регистров XMM/YMM. Рассмотрим на примере сохранения первых 6 регистров XMM/YMM:

.data
    AVXSupport = 10000000h  ; проверяем бит 28
.code
main proc 
    ; Резервируем в стеке место  для регистров AVX/SSE
    ; Для 6 регистров SSE необходимо только 96 байт
    ; Для 6 регистров AVX 196 байт 
    ; Выделяем одно пространство для двух типов расширений - 196 байт
    ; Тогда SSE просто игнорируют дополнительные 64 байта
    sub rsp, 192
    ; Определяем, доступны ли расширения AVX и соответственно регистры YMM
    mov eax, 1
    cpuid
    and ecx, AVXSupport     ; проверяем на поддержку AVX бит 28
    jnz saveAVX         ; если AVX доступно, переходим к метке preserveAVX
    ; Если поддержка расширений AVX отсутствует, сохраняет состояние регистров XMM0-XMM5
    movdqu xmmword ptr [rsp + 00], xmm0
    movdqu xmmword ptr [rsp + 16], xmm1
    movdqu xmmword ptr [rsp + 32], xmm2
    movdqu xmmword ptr [rsp + 48], xmm3
    movdqu xmmword ptr [rsp + 64], xmm4
    movdqu xmmword ptr [rsp + 80], xmm5
    jmp afterSave
    ; сохраняем состояние регистров YMM0-YMM5
saveAVX: 
    vmovdqu ymmword ptr [rsp + 000], ymm0
    vmovdqu ymmword ptr [rsp + 032], ymm1
    vmovdqu ymmword ptr [rsp + 064], ymm2
    vmovdqu ymmword ptr [rsp + 096], ymm3
    vmovdqu ymmword ptr [rsp + 128], ymm4
    vmovdqu ymmword ptr [rsp + 160], ymm5

afterSave:      ; здесь какие-нибудь действия в программе
    mov rax, 15 ; например, поместим в регистр RAX какое-нибудь число

; восстанавливаем значения регистров - в регистре ECX по прежнему значение для AVXSupport
; можно его использовать, чтобы заново не вызывать инструкцию cpuid
    and ecx, AVXSupport     ; проверяем на поддержку AVX бит 28
    jnz restoreAVX         ; если AVX доступно, переходим к метке restoreAVX

; если не доступно AVX, восстанавливаем регистры XMM
    movdqu xmm0, xmmword ptr [rsp + 00] 
    movdqu xmm1, xmmword ptr [rsp + 16] 
    movdqu xmm2, xmmword ptr [rsp + 32] 
    movdqu xmm3, xmmword ptr [rsp + 48] 
    movdqu xmm4, xmmword ptr [rsp + 64] 
    movdqu xmm5, xmmword ptr [rsp + 80] 
    jmp exit
; восстанавливаем регистры YMM
restoreAVX:
    vmovdqu ymm0, ymmword ptr [rsp + 000]
    vmovdqu ymm1, ymmword ptr [rsp + 032]
    vmovdqu ymm2, ymmword ptr [rsp + 064]
    vmovdqu ymm3, ymmword ptr [rsp + 096]
    vmovdqu ymm4, ymmword ptr [rsp + 128]
    vmovdqu ymm5, ymmword ptr [rsp + 160]
exit:
    add rsp, 192
    ret
main endp
end

Как и в общем случае, проблема может заключаться в том, что мы можем не знать точно, какие именно расширения поддерживаются на текущей машине. Поэтому сначала с помощью инструкции cpuid проверяем наличие поддержки регистров YMM. Для этого к результату инструкции в регистре ECX применяем маску AVXSupport, которая выявляет установку 28 бита (который собственно и говорит о поддержке AVX):

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

Если бит установлен, соответственно после выполнения инструкции AND результат ненулевой, то переходим к метке saveAVX для сохранения состояния регистров YMM. Если бит не установлен, то сохраняем регистры XMM.

Для сохранения 6 регистров XMM нужно 16 байт * 6 = 96 байт. На сохранение 6 регистров YMM - 196 байт. В данном случае для простоты для обоих типов регистров в стеке выделяется 196 байт. Затем последовательно сохраняем регистры:

movdqu xmmword ptr [rsp + 00], xmm0
movdqu xmmword ptr [rsp + 16], xmm1
movdqu xmmword ptr [rsp + 32], xmm2
movdqu xmmword ptr [rsp + 48], xmm3
movdqu xmmword ptr [rsp + 64], xmm4
movdqu xmmword ptr [rsp + 80], xmm5
jmp afterSave
; сохраняем состояние регистров YMM0-YMM5
saveAVX: 
vmovdqu ymmword ptr [rsp + 000], ymm0
vmovdqu ymmword ptr [rsp + 032], ymm1
vmovdqu ymmword ptr [rsp + 064], ymm2
vmovdqu ymmword ptr [rsp + 096], ymm3
vmovdqu ymmword ptr [rsp + 128], ymm4
vmovdqu ymmword ptr [rsp + 160], ymm5

При завершении программы аналогично восстанавливаем регистры.

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