Вычисление ведущих нулей с внутренней функцией

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

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

/* 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 (https://web.archive.org/web/20080704062813/http://www.devmaster.net/articles/fixed-point-optimizations), это должно быть более эффективным.

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

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


person lornova    schedule 28.10.2010    source источник


Ответы (1)


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

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

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

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

/QRarch5 ARM5 Architecture
/QRarch5T ARM5T Architecture

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

person Igor Skochinsky    schedule 28.10.2010
comment
Я проверю сгенерированный код. И если это действительно вызов функции (а не настоящая встроенная функция), накладные расходы на вызов объяснят, почему он такой медленный. - person lornova; 28.10.2010