Расчет ведущих нулей с внутренней функцией - PullRequest
4 голосов
/ 28 октября 2010

Я пытаюсь оптимизировать некоторый код, работающий во встроенной системе (декодирование FLAC, Windows CE, ARM 926 MCU).

Реализация по умолчанию использует макрос и таблицу поиска:

/* counts the # of zero MSBs in a word */
#define COUNT_ZERO_MSBS(word) ( \
 (word) <= 0xffff ? \
  ( (word) <= 0xff? byte_to_unary_table[word] + 24 : \
              byte_to_unary_table[(word) >> 8] + 16 ) : \
  ( (word) <= 0xffffff? byte_to_unary_table[word >> 16] + 8 : \
              byte_to_unary_table[(word) >> 24] ) \
)

static const unsigned char byte_to_unary_table[] = {
    8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
    3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};

Однако у большинства процессоров уже есть специальная инструкция, bsr на x86 и clz на ARM (http://www.devmaster.net/articles/fixed-point-optimizations/),, которая должна быть более эффективной.

В Windows CE у нас есть встроенная функция _CountLeadingZeros , которая должна просто вызывать это значение. Однако это в 4 раза медленнее, чем макрос (измеряется на 10 миллионов итераций).

Как возможно, что внутренняя функция, которая (должна) полагаться на специальную инструкцию ASM, работает в 4 раза медленнее?

1 Ответ

5 голосов
/ 28 октября 2010

Проверьте разборку.Вы уверены, что компилятор вставил инструкцию?В разделе «Примечания» есть следующий текст:

Эту функцию можно реализовать, вызвав функцию времени выполнения.

Я подозреваю, что это происходит в вашем случае.

Обратите внимание, что инструкция CLZ доступна только в ARMv5 и более поздних версиях.Вам нужно сообщить компилятору, если вы хотите код ARMv5:

/QRarch5 ARM5 Architecture
/QRarch5T ARM5T Architecture

(Microsoft неправильно использует «ARM5» вместо «ARMv5»)

...