Программа сборки BITswap - PullRequest
       19

Программа сборки BITswap

0 голосов
/ 27 августа 2018
%include "asm_io.inc"
segment .data
outmsg1 db    "Input Integer: ", 0
outmsg2 db    "After Operation": ", 0

segment .bss

input1  resd 1
input2  resd 1

segment .text
    global  asm_main
asm_main:
    enter 0,0
    pusha

    mov eax, outmsg1
    call print_string
    call read_int
    call print_nl
    dump_regs 1

    rol eax, 8
    rol ax, 8
    ror eax,8
    mov ebx, 0
    mov ebx, eax
    dump_regs 2

    popa
    mov eax, 0
    leave
    ret

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

Я немного застрял, может, вы мне поможете

Ответы [ 5 ]

0 голосов
/ 27 августа 2018

Хорошо, так как уже есть разные ответы, я сделаю свой "комментарий" официальным с некоторыми расширениями:

    rol    eax,1        ; get the top bit down into low 8 bits
    test   al,3         ; now test the two bits, setting parity flag
    jpe    to_ror       ; if "00" or "11", skip the bit swap
    xor    eax,3        ; flip the two lowest bits (top and bottom original position)
to_ror:
    ror    eax,1        ; restore the positions of bits (top back to b31)

Это вариант с одним условным переходом, т. Е., Вероятно, не оптимальным по производительности, но должен быть достаточно простым для понимания и не использовать никаких других ресурсов, кроме оригинального значения eax и регистра флага.

Другой вариант заключается в том, чтобы избежать условного перехода по цене еще нескольких используемых инструкций и регистров (но во многих случаях он должен быть все еще более быстрым на современном ЦП, потому что неправильно предсказанное ветвление обычно приводит к значительному увеличению ресурсов ЦП) (это в основном то, что Пришел OP, и то, что я упомянул в своем первоначальном комментарии как ", чтобы извлечь каждый бит отдельно и перекомпоновать обратно" ):

mov   ebx,eax           ; copy the original value into two new regs
mov   ecx,eax
shr   ebx, 31           ; b31 bit into b0 position (others cleared)
shl   ecx, 31           ; b0 bit into b31 position (others cleared)
and   eax, 0x7FFFFFFE   ; clear b0 and b31 in original value
or    eax,ebx           ; combining the swapped bits back into value
or    eax,ecx
0 голосов
/ 27 августа 2018

Я положительно удивлен количеством и подробностью ответов, которые были размещены здесь.Я очень благодарен за всю информацию, которую вы предоставили, потребуется некоторое время, чтобы изучить и понять некоторые из них.- тем временем я сам придумал другое решение.Возможно, это не так эффективно, как ваши решения, но я все же хотел опубликовать его и прочитать о том, что вы об этом думаете.

%include "asm_io.inc"
segment .data
outmsg1 db    "Enter integer: ", 0
outmsg2 db    "Before Operation: ", 0
outmsg3 db    "After Operation: ", 0

segment .bss

input1  resd 1
input2  resd 1

segment .text
    global  asm_main
asm_main:
    enter 0,0
    pusha

    mov eax, outmsg1
    call print_string
    call read_int
    xor esi, esi    
    mov esi, eax

    mov eax, outmsg2
    call print_string
    call print_nl
    mov eax, esi
    dump_regs 1

    mov ebx,eax
    mov ecx,eax

    shr ebx, 31
    shl ecx, 31

    shl eax, 1
    shr eax, 2
    shl eax, 1
    or eax,ebx
    or eax,ecx

    mov ebx,eax
    mov eax, outmsg3
    call print_string
    call print_nl
    dump_regs 2


    popa
    mov eax, 0
    leave
    ret
0 голосов
/ 27 августа 2018

Вы должны переключать оба бита, только если они различаются.Вам не нужно ничего делать, если биты оба установлены или оба очищены:

%include "asm_io.inc"
segment .text
    global  asm_main
asm_main:
    enter 0,0
    pusha

    ; Test values, comment it as needed
;   mov eax, 0x00123400         ; Bit0 and Bit31 are cleared
    mov eax, 0x00123401         ; Bit0 is set, Bit 31 is cleared
;   mov eax, 0x80123400         ; Bit0 is cleared, Bit31 is set
;   mov eax, 0x80123401         ; Bit0 and Bit31 are set

    dump_regs 1

    bt eax, 0                   ; Copy the least significant bit into CF
    setc cl                     ; Copy CF into register CL
    bt eax, 31                  ; Copy the most significant bit into CF
    setc ch                     ; Copy CF into register CH
    cmp cl, ch                  ; Compare the bits
    je skip                     ; No operation, if they don't differ
    btc eax, 0                  ; Toggle the least significant bit
    btc eax, 31                 ; Toggle the most significant bit
    skip:

    dump_regs 2

    popa
    mov eax, 0
    leave
    ret

Другая идея заключается в использовании TEST и работе в соответствии с флагами - преимущество: вы не делаетеНеобходим дополнительный регистр:

%include "asm_io.inc"

segment .text
    global  asm_main
asm_main:
    enter 0,0
    pusha

    ; Test values, comment it as needed
;   mov eax, 0x00123400         ; ZF PF
    mov eax, 0x00123401         ; -  -
;   mov eax, 0x80123400         ; SF PF
;   mov eax, 0x80123401         ; SF


    test eax, 0x80000001

    dump_regs 1

    jns j1
    jnp skip
    j1:
    jz skip

    doit:                       ; Touch the bits if (SF & PF) or (!SF & !PF)
    btc eax, 0                  ; Toggle the least significant bit
    btc eax, 31                 ; Toggle the most significant bit
    skip:

    dump_regs 2

    popa
    mov eax, 0
    leave
    ret
0 голосов
/ 27 августа 2018

Используйте временный регистр (кроме EFLAGS), чтобы сделать эту меньшую задержку на процессорах без однократного цикла adc:

mov    ecx, eax

bswap  eax
shl    eax, 7             ; top bit in place
shr    ax, 7+7            ; bottom bit in place (without disturbing top bit)

and    ecx, 0x7ffffffe    ; could optimize mov+and with BMI1 andn
and    eax, 0x80000001
or     eax, ecx           ; merge the non-moving bits with the swapped bits

На процессорах Intel до Sandybridge, shr ax и последующее чтение EAX будут отстойными (частичное зависание регистра).

Это похоже на 5-тактовую задержку от входа к выходу, то же самое, что и adc / adc версия @ Fuz для ЦП, где это задержка на один цикл. (AMD и Intel со времен Broadwell). Но на Haswell и ранее это может быть лучше.

Мы могли бы сохранить mov, используя либо BMI1 andn с константой в регистре, либо, возможно, BMI2 rorx ecx, eax, 16 для копирования и замены вместо выполнения bswap на месте. Но тогда биты находятся в менее удобных местах.


@ rkhb Идея проверить, отличаются ли биты и перевернуть их, хороша, особенно если использовать PF для проверки, установлены ли 0 или 2 бита против 1. PF устанавливается только на основе младшего байта результата, поэтому мы можем ' * просто and 0x80000001 без вращения первым.

Вы можете сделать это без ответвлений с cmov

; untested, but I think I have the parity correct
rorx    ecx, eax, 31     ; ecx = rotate left by 1.  low 2 bits are the ones we want
xor     edx,edx
test    cl, 3            ; sets PF=1 iff they're the same: even parity
mov     ecx, 0x80000001
cmovpo  edx, ecx         ; edx=0 if bits match, 0x80000001 if they need swapping
xor     eax, edx

При однократном включении cmov (Broadwell и более поздние версии или AMD) эта задержка составляет 4 цикла . Обнуление XOR и MOV-немедленного находятся на критическом пути. MOV-немедленный может быть выведен из цикла, если вы используете регистр, отличный от ECX.


Или с setcc, но он хуже (больше мопов), или привязан к процессорам с 2-мегапиксельной cmov:

; untested, I might have the parity reversed.
rorx    ecx, eax, 31     ; ecx = rotate left by 1.  low 2 bits are the ones we want
xor     edx,edx
and     ecx, 3           ; sets PF=1 iff they're the same: even parity
setpe   dl
dec     edx              ; 0 or -1
and     edx, 0x80000001
xor     eax, edx
0 голосов
/ 27 августа 2018

Как насчет этого?Вход находится в ecx или любом другом регистре, который вам нравится.

                   // initial state: ECX = A...B
ror ecx            // ECX = BA..., CF = B
bt ecx, 30         // ECX = BA..., CF = A
rcl ecx, 2         // ECX = ...AB, CF = A
ror ecx            // ECX = B...A

Как указал Питер Кордес, если вы оптимизируете производительность, вы можете изменить код следующим образом:

ror ecx
bt ecx, 30
adc ecx, ecx
adc ecx, ecx
ror ecx

Это потому, что adc r,r работает лучше, чем rcl r,imm или rcl r на современных микроархитектурах.

...