Вставить бит в байт в позиции n при сборке

#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. Большое спасибо, отлично!