Язык ассемблера - вычтите edx из ecx и поместите результат в ebx - PullRequest
0 голосов
/ 05 июля 2018

Как бы я сделал это, не изменяя любой другой регистр (иначе как ecx & edx, как прежде)?

В C ++ это будет так:

int ecx = 3;
int edx = 1;
int ebx = ecx - edx;

Пока что я сделал это:

mov ecx, 1
mov edx, 3
sub ecx, edx
mov ebx, ecx

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

С инструкциями с 2 операндами в стиле x86, которые уничтожают их назначение, вы всегда можете смоделировать неразрушающую инструкцию с 3 операндами с помощью mov, чтобы скопировать один операнд в назначение , а затем выполнить деструктивную инструкцию в этом пункте назначения.

# with ecx and edx holding your inputs (which I'm calling C and D).

mov  ebx, ecx      ; ebx = C
sub  ebx, edx      ; ebx = C - D

Это оптимально для этого случая, когда вам не нужно уничтожать значения в ECX и EDX.

Если у вас мало доступных регистров, хорошим вариантом может быть сохранение ECX в стеке, а затем получение результата C - D в ECX вместо нового регистра.

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

Компиляторы, как правило, довольно хороши в распределении регистров, но их код может быть трудно читаемым, потому что они даже не пытаются согласоваться с использованием регистров. Для неразрушающих операций они часто помещают результат в новый регистр без причины. Тем не менее, вывод компилятора часто является хорошей отправной точкой для оптимизации. (Напишите крошечную функцию, которая что-то делает, и посмотрите, как она компилируется. Или напишите всю свою вещь в C с аргументами функций вместо констант в качестве входных данных и скомпилируйте ее.)


x86 имеет некоторые инструкции по копированию и работе для других операций (не sub), , в первую очередь LEA .

lea  ebx, [ecx + ecx*4]     ; ebx = C * 5
lea  ebx, [ecx + ebx - 2]   ; ebx = C + D - 2

Режимы адресации x86 могут добавлять или вычитать константы, но могут только сдвигать влево и добавлять регистры.


Форма с непосредственным операндом imul также является 3-операндом для использования с множителями, которые нельзя сделать с 1 или 2 LEA:

imul   ebx,  ecx,  0x01010101     ;  ebx = C repeated 4 times, if it was < 256

В отличие от большинства инструкций с непосредственным операндом, imul не перегружает поле /r в байте ModRM как дополнительные биты кода операции. Таким образом, у него есть место для кодирования места назначения регистра и источника reg / mem, потому что 286 выделил ему целый байт кода операции.


ISA-расширения , такие как BMI1 и BMI2, добавили некоторые новые трехзначные целочисленные инструкции, такие как ANDN и SHRX .

andn   ebx,  ecx, edx             ; ebx = (~C) & D   ; BMI1

shrx   ebx,  edx, ecx             ; ebx = D >> C     ; BMI2

Но они не доступны повсеместно, только Haswell и позже, и Ryzen. (А версии Haswell / Skylake для Pentium / Celeron по-прежнему продаются без них, что еще больше отодвигает точку, в которой они становятся базовыми. Спасибо, Intel.)

И, конечно же, для векторных инструкций AVX предоставляет неразрушающие версии всех инструкций SSE .

movaps    xmm2, xmm0         ; copy a whole register
subsd     xmm2, xmm1         ; scalar double-precision FP subtract: xmm0-xmm1

vsubsd    xmm3, xmm0, xmm1

или менее очевидный вариант использования

xorps     xmm0, xmm0    ; zero the register and break any false dependencies
cvtsi2sd  xmm0, eax     ; convert to double-precision FP, with the upper element = 0

xorps     xmm1, xmm1
cvtsi2sd  xmm1, edx

против. AVX:

vxorps    xmm1,  xmm1,xmm1   ; xmm1 = all-zero

vcvtsi2sd  xmm0, xmm1, eax
vcvtsi2sd  xmm1, xmm1, edx

При этом используется тот же обнуленный регистр, что и в месте назначения слияния, чтобы избежать ложных зависимостей (и иметь верхний 64-битный ноль 128-битного регистра).

0 голосов
/ 05 июля 2018

Вы всегда можете использовать стек для сохранения регистров:

    push ecx
    push edx
    mov ecx, 1
    mov edx, 3
    sub ecx, edx
    mov ebx, ecx
    pop edx
    pop ecx
...