Почему 16-разрядный регистр используется с инструкцией BSR в этом фрагменте кода?

StackOverflow https://stackoverflow.com/questions/1818374

  •  10-07-2019
  •  | 
  •  

Вопрос

В этой хардкорной статье есть функция < code> find_maskwidth () , который в основном определяет количество битов, необходимое для представления точных значений itemCount :

unsigned int find_maskwidth( unsigned int itemCount )
{
    unsigned int maskWidth, count = itemCount;
    __asm {
        mov eax, count
        mov ecx, 0
        mov maskWidth, ecx
        dec eax
        bsr cx, ax
        jz next
        inc cx
        mov maskWidth, ecx
    next:
    }
    return maskWidth; 
} 

вопрос в том, почему они используют регистры ax и cx вместо eax и ecx ?

Это было полезно?

Решение

Я могу только догадываться, что они ожидают когда-либо иметь дело только с полями, которые имеют не более 16 бит. Поскольку он используется для определения количества битов, которые можно использовать для сообщения таких вещей, как количество ядер или логических процессоров в пакете, вероятно, пройдет некоторое время, прежде чем он превысит 65535.

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

И просто к сведению - если вы хотите сделать что-то подобное, не переходя на сборку x86 (хотя я предполагаю, что для цели статьи непереносимость в значительной степени само собой разумеющееся), На странице Bit Twiddling Hacks вы уже рассмотрели.

Другие советы

Полагаю, исходные данные имеют ширину всего 16 бит. Поскольку cx получает битовое число, нет никаких шансов, что оно все равно может быть больше очень маленького числа.

Интересно отметить, что на одном уровне коды операций для 16-разрядных и 32-разрядных команд ia32 одинаковы, за исключением префиксного байта, поэтому более эффективно вводить все 32-разрядные или все 16-разрядные инструкции, в зависимости от в каком режиме вы находитесь. Наверное, поэтому вы задали вопрос ...

Учитывая тот факт, что этот код действительно очень плохо написан (например, абсолютно нет необходимости в переменных maskWidth и count - кроме того, что код запутан), я думаю, вы можете быть уверены, что это просто еще один " «плохая вещь» в этом коде.

Подпрограмма в основном определяет двоичный (основание два) логарифм itemCount.

Он выдаст совершенно неправильные значения, если itemCount > 2 ^ 16. Это не насыщает или что-то, это просто неправильно. Входным параметром является «unsigned int», что делает его еще более неправильным. Так что перестанет работать на более 65536 ядер.

Я предполагаю, что кто-то в Intel выкопал какой-то действительно древний кусок кода, датируемый 16-ти битным временем, не понимая его, и использовал его, потому что 65536 будет достаточно навсегда, точно так же, как 640 КБ памяти будет достаточно навсегда или так как двухзначных чисел года будет достаточно до конца времени.

Я бы сказал, что это потому, что автор этого кода, вероятно, не знал, что делает :-). 16-битные версии этих инструкций длиннее и не быстрее. Фактически, они, вероятно, вызовут частичное зависание регистра в следующей инструкции, которая использует ECX (то есть MOV).

Также обратите внимание, что переход может быть безопасно перемещен одной инструкцией ранее (после DEC), так как DEC уже устанавливает ZF, когда его выход равен нулю. Это может немного упростить код.

Вот как я бы написал этот фрагмент кода:

  mov eax, [count]
  xor ecx, ecx
  dec eax
  jz next
  bsr ecx, eax
  inc ecx
next:
  mov [maskWidth], ecx

Кроме того, мотивация для перехода к сборке здесь, кажется, использует инструкцию BSR, которая не имеет никакого эквивалента в языке C или библиотеке. Вы можете избежать использования ассемблера, используя для этого встроенную функцию, специфичную для компилятора. Хотя они по своей природе не являются переносимыми, ни одна из них не является встроенной сборкой.

В GCC эквивалентная функция будет выглядеть следующим образом:

unsigned int find_maskwidth(unsigned int itemCount)
{
   if(itemCount <= 1)
      return 0;
   else
      return 32 - __builtin_clz(itemCount - 1);
}

Гораздо более читабельно, не так ли?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top