Цикл на ассемблере

Рейтинг: 14Ответов: 6Опубликовано: 17.01.2011

Пусть A и B – два 8-разрядных регистра в обыкновенном 16-разрядном процессоре. Следующая процедура выполняет сдвиг регистра A на число разрядов, заданное в регистре B.

Loop:
  SHR A  ;shift right A
  DEC B  ;decrement B
  JNZ Loop  ;loop again

Задача - Написать программу, которая выполняет сдвиг быстрее. Пользоваться многократным сдвигом запрещено.

ЗЫ Эту задачу когда-то мне предложили на собеседовании. Я ее решил не верно. У кого какие мысли? Гугл не поможет :) Надо думать самому!

UPD: Нашел свое неверное решение

 MOV AH,A
 MOV AL,B
Label:  
 SHR AH
 DEC AL
 JNE Label

Ответы

▲ 16Принят

И третий вариант:) Предложен моим коллегой. Развернуть цикл.

jmp $+sizeof(shr a)*(8-b) // $ - это адрес следующей за jmp инструкции
shr a
shr a
shr a
shr a
shr a
shr a
shr a
shr a
▲ 6

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

Да, первое, что приходит на ум это вопрос: о каком "обыкновенном" процессоре речь? Если это RISC, то можно оперется на delay slot при бранчевании и написать так:

loop:
dec B
jnz loop
shr A

Т.е., здесь "shr A" выполнится в delay slot предыдущей инструкции бранчевания "jnz loop", что позволит нам сэкономить 'B' операций. Для RISC процессоров этот и приведенный выше коды эквивалентны.

Да, на этом моя мысль заканчивается))

▲ 5

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

    and B, 7
    jz fin
loop: 
    shr A
    dec B
    jnz loop
fin:
▲ 4
mov cl,b
shr a,cl
▲ 4

Есть еще идейка, возможно это хотели увидеть ваши экзаменаторы).

mov dx, a
mov bx, b //кол-во сдвигов до правого края DL
mov ax, 8
sub ax, bx //кол-во сдвигов до правого края DH
cmp ax, bx
jbe loop_shl: // если ax <= bx двигаем влево на ax, берем результат из DH
loop_shr: // иначе двигаем вправо на bx, берем результат из DL
shr dx
dec bx
jnz loop_shr
jmp end:

loop_shl:
shl dx
dec ax
jnz loop_shl

end:
▲ 4

Можно сделать следующим образом:

; прошу прощения за ошибки, давно не писал..

data segment
       ; 0 1 2 3  4  5  6   7   8
array db 1,2,4,8,16,32,64,128,256
data ends

code segment
...
start:
...
mov cx,[bx+array]
mul cx
...
code ends
end start

суть идеи: при умножении или делении числа на два, его двоичный код смещается влево или вправо соответственно, это я и попытался использовать. В массиве мы храним числа, на которые мы должны умножить исходное число(значение ax), число сдвигов(значение bx) используется как смещение в массиве.