Арифметические операции с векторами чисел с плавающей точкой

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

Расширения SSE/AVX предоставляют инструкции для паралелльных операций с плавающей точкой:

  • addps: складывает 4 дорожки операндов с 32-разрядными числами с плавающей точкой

  • addpd: складывает 2 дорожки операндов с 64-разрядными числами с плавающей точкой

  • vaddps: складывает 4 дорожки (128-битная версия) или 8 дорожек (256-битная версия) с 32-разрядными числами с плавающей точкой

  • vaddpd: складывает 2 дорожки (128-битная версия) или 4 дорожки (256-битная версия) с 64-разрядными числами с плавающей точкой

  • subps: вычитает 4 дорожки операндов с 32-разрядными числами с плавающей точкой

  • subpd: вычитает 2 дорожки операндов с 64-разрядными числами с плавающей точкой

  • vsubps: вычитает 4 дорожки (128-битная версия) или 8 дорожек (256-битная версия) с 32-разрядными числами с плавающей точкой

  • vsubpd: вычитает 2 дорожки (128-битная версия) или 4 дорожки (256-битная версия) с 64-разрядными числами с плавающей точкой

  • mulps: перемножает 4 дорожки операндов с 32-разрядными числами с плавающей точкой

  • mulpd: перемножает 2 дорожки операндов с 64-разрядными числами с плавающей точкой

  • vmulps: перемножает 4 дорожки (128-битная версия) или 8 дорожек (256-битная версия) с 32-разрядными числами с плавающей точкой

  • vmulpd: перемножает 2 дорожки (128-битная версия) или 4 дорожки (256-битная версия) с 64-разрядными числами с плавающей точкой

  • divps: делит 4 дорожки операндов с 32-разрядными числами с плавающей точкой

  • divpd: делит 2 дорожки операндов с 64-разрядными числами с плавающей точкой

  • vdivps: делит 4 дорожки (128-битная версия) или 8 дорожек (256-битная версия) с 32-разрядными числами с плавающей точкой

  • vdivpd: делит 2 дорожки (128-битная версия) или 4 дорожки (256-битная версия) с 64-разрядными числами с плавающей точкой

  • maxps: вычисляет максимальное в каждой из 4 пар чисел с плавающей точкой одинарной точности

  • maxpd: вычисляет максимальное в каждой из 2 пар чисел с плавающей точкой двойной точности

  • vmaxps: вычисляет максимальное в каждой из 4 (для 128-битной версии) или 8 (для 256-битной версии) пар чисел с плавающей точкой одинарной точности

  • vmaxpd: вычисляет максимальное в каждой из 2 (для 128-битной версии) или 4 (для 256-битной версии) пар чисел с плавающей точкой двойной точности

  • minps: вычисляет минимальное в каждой из 4 пар чисел с плавающей точкой одинарной точности

  • minpd: вычисляет минимальное в каждой из 2 пар чисел с плавающей точкой двойной точности

  • vminps: вычисляет минимальное в каждой из 4 (для 128-битной версии) или 8 (для 256-битной версии) пар чисел с плавающей точкой одинарной точности

  • vminpd: вычисляет минимальное в каждой из 2 (для 128-битной версии) или 4 (для 256-битной версии) пар чисел с плавающей точкой двойной точности

  • sqrtps: вычисляет квадратный корень для каждого из 4 чисел с плавающей точкой одинарной точности

  • sqrtpd: вычисляет квадратный корень для 2 чисел с плавающей точкой двойной точности

  • vsqrtps: вычисляет квадратный корень для каждого из 4 (для 128-битной версии) или 8 (для 256-битной версии) чисел с плавающей точкой одинарной точности

  • vsqrtpd: вычисляет квадратный корень для каждого из 2 (для 128-битной версии) или 4 (для 256-битной версии) чисел с плавающей точкой двойной точности

  • rsqrtps: вычисляет приблизительно обратный квадратный корень для каждого из 4 чисел с плавающей точкой одинарной точности

  • vrsqrtps: вычисляет приблизительно обратный квадратный корень для каждого из 4 (для 128-битной версии) или 8 (для 256-битной версии) чисел с плавающей точкой одинарной точности

Общий синтаксис инструкций на примере v(addps):

addps xmmsrc/mem128, xmmdest

vaddps xmmsrc2/mem128, xmmsrc1, xmmdest 
vaddps ymmsrc2/mem256, ymmsrc1, ymmdest

Инструкции вычисления квадратного корня принимают два операнда:

sqrtps xmmsrc/mem128, xmmdest

vsqrtps xmmsrc/mem128, xmmdest
vsqrtps ymmsrc/mem256, ymmdest

Применение инструкций на примере сложения:

.globl main

.data
nums0: .single 1.1, 2.2, 3.3, 4.4
nums1: .single 1.2, 2.3, 3.4, 4.5
       
format_str: .asciz "%.1f, %.1f, %.1f, %.1f\n"

.text
main: 
    subq $8, %rsp       # выравниваение по 16 байтам для функции printf
    movaps nums0, %xmm0
    movaps nums1, %xmm1
    vaddps %xmm1, %xmm0, %xmm5  # xmm5 = xmm0+xmm1

    # выводим данные на консоль
    movss %xmm5, %xmm0    # помещаем число float в регистр для передачи в функцию printf
    cvtss2sd %xmm0, %xmm0   # преобразуем float в double
    psrldq $4, %xmm5    # сдвиг вправо на 4 байта для получения следующего числа
    movss %xmm5, %xmm1
    cvtss2sd %xmm1, %xmm1
    psrldq $4, %xmm5
    movss %xmm5, %xmm2
    cvtss2sd %xmm2, %xmm2
    psrldq $4, %xmm5
    movss %xmm5, %xmm3
    cvtss2sd %xmm3, %xmm3

    movq $format_str, %rdi
    call printf

    addq $8, %rsp
    ret

Здесь складываются два вектора 32-разрядных чисел nums0 и nums1. Для упрощения тестирования для вывода результата на консоль здесь используется функция printf. Компиляция и консольный вывод программы:

root@Eugene:~/asm# gcc -static hello.s -o hello
root@Eugene:~/asm# ./hello
2.3, 4.5, 6.7, 8.9
root@Eugene:~/asm#
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850