При работе с инструкциями расширений 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
При завершении программы аналогично восстанавливаем регистры.