Есть ли способ увеличить значение в регистре xmm?

Мне было интересно, есть ли способ увеличить значение в регистре xmm или вы можете только переместить значение в один?

Я имею в виду, что вы можете сделать это:

inc eax

или вот так:

inc [ebp+7F00F000]

Есть ли способ сделать то же самое с XMM?

Я пытался что-то напомнить, но... это не работает

  inc [rbx+08]
  movss xmm1,[rbx+08]

Я даже попробовал что-то действительно глупое, но это тоже не сработало

push edx
pextrw edx,xmm2,0
add edx,1
mov [rbx+08],edx
movss xmm1,[rbx+08]
pop edx

2 ответа

Решение

Короче говоря, нет, не так, как вы думаете.

Под SSE все исходные регистры XMM были регистрами с плавающей запятой. Для операции с плавающей запятой нет операции приращения.

SSE2 добавил несколько регистров целочисленного типа, но приращения по-прежнему нет. Эти регистры и дополнительные операции действительно предназначались для высокоскоростных арифметических операций, включая такие вещи, как точечные продукты, точные продукты с округлением и т. Д.

Операция инкремента - это то, что вы ожидаете найти примененным к общему регистру или аккумулятору.

Вы можете найти этот набор слайдов несколько информативным с точки зрения общего обзора и функции.

Нет никаких inc эквивалент для xmm regs, и нет формы непосредственного операнда paddw (так что нет эквивалента add eax, 1 или).

paddw (и другие размеры элементов) доступны только с исходными операндами xmm/m128. Поэтому, если вы хотите увеличить один элемент вектора, вам нужно загрузить константу из памяти или сгенерировать ее на лету.

Например, самый дешевый способ увеличить все элементы xmm0:

; outside the loop
pcmpeqw    xmm1,xmm1     # xmm1 = all-ones = -1

; inside the loop
psubw      xmm0, xmm1    ; xmm0 -= -1   (in each element).  i.e. xmm0++

Или же

paddw      xmm0, [ones]  ; where ones is a static constant.

Вероятно, будет хорошей идеей загрузить константу из памяти, если для ее создания требуется более двух инструкций, или если регистр давления представляет собой проблему.


Например, если вы хотите создать константу для увеличения только нижнего 32-битного элемента, вы можете использовать byte-shift для обнуления других элементов:

; hoisted out of the loop
pcmpeqw    xmm1,xmm1     # xmm1 = all-ones = -1
psrldq     xmm1, 12      # xmm1 = [ 0 0 0 -1 ]


; in the loop
psubd      xmm0, xmm1

Если ваша попытка должна была увеличить только 16-битный элемент в xmm2, то да, это была глупая попытка. ИДК, что вы делаете, сохраняя в [rbx+8] и затем загрузка в xmm1 (обнуление старших 96 бит).

Вот как написать xmm -> gp -> xmm туда и обратно менее глупым способом. (Все еще ужасно по сравнению с paddw с векторной постоянной).

# don't push/pop.  Instead, pick a register you can clobber without saving/restoring
movd    edx, xmm2       # this is the cheapest way to get the low 16.  It doesn't matter that we also get the element 1 as garbage in the high half of edx
inc     edx             # we only care about dx, but this is still the most efficient instruction
pinsrw  xmm2, edx, 0    # normally you'd just use movd again, but we actually want to merge with the old contents.

Если вы хотите работать с элементами, отличными от 16-битных, вы либо используете SSE4.1 pinsrb/d/qили вы бы использовали movd и тасует


См. Руководство по оптимизации сборки Agner Fog для получения более полезных советов по использованию векторов SSE. Также другие ссылки в теге x86 вики.

Другие вопросы по тегам