#assembly #arm #micro-optimization #cortex-m
#сборка #arm #микрооптимизация #cortex-m
Вопрос:
Есть ли более быстрый способ сделать это с помощью assembly, чем с обычным C?
Это прототип функции в C:
uint8_t InsertBit(uint8_t input, uint16_t idx, uint8_t insbit)
Функция должна вернуть новое значение. Я работаю над встроенной arm cortex M.
Подпрограмма C содержит около 18 инструкций.
Процедура C:
__attribute__((optimize("O1")))
uint8_t InsertBit(uint8_t input, uint16_t idx, uint8_t insbit)
{
//Split the input into two parts, one shifted and one not
uint8_t bottom = input;
uint8_t top = (input << 1);
//insert a '0' or '1' before the shifted part
if (insbit)
top |= (1 << idx);
else
top amp;= (~(1 << idx));
//keep the top bits of top
top amp;= (-1 << idx);
//keep the bottom bits of bottom
bottom amp;= ~(-1 << idx);
//combine the two parts.
return (bottom | top);
}
Ответ №1:
Подход Erik (сдвиг битов выше точки вставки влево путем добавления замаскированной версии ввода) может быть выражен как
uint8_t InsertBit(uint8_t input, uint16_t idx, uint8_t insbit)
{
return ((insbit (input >> idx)) << idx) input;
}
который компилируется в основном до двух инструкций на ARM из-за свободных сдвигов:
add r2, r2, r0, lsr r1
add r0, r0, r2, lsl r1
and r0, r0, #255
bx lr
Комментарии:
1. Хорошо, да, версия Эрика компилируется со значительно большим количеством инструкций. godbolt.org/z/4hThYK
2. Отлично, мне это нравится!
Ответ №2:
uint8_t InsertBit(uint8_t input, uint16_t idx, uint8_t insbit)
{
return (input (input amp; (-1 << idx))) | (insbit << idx);
}
Примечания:
- x x умножает x на 2, аналогично сдвигу влево на 1
- мы хотим вставить бит, поэтому мы добавляем только верхние биты x к исходному x.
abcdefgh x
abc00000 x amp; (-1 << 5) // idx is 5
--------( )
abc0defgh <--- one bit inserted at position 5
-
здесь
abc abc
результатabc0
, т.е.abc
сдвинут влево на 1 бит -
оставляя
defgh
в покое, без сдвига -
затем просто
or
вставьте нужный бит в нужную позицию. -
довольно просто и без условной логики
Комментарии:
1. Большое спасибо, отлично!