Почему этот код генерируется avr-gcc и как он работает? - PullRequest
5 голосов
/ 27 августа 2009

Это фрагмент дизассемблированного кода AVR из проекта C, над которым я работаю. Я заметил, что генерируется этот любопытный код, и я не могу понять, как он работает. Я предполагаю, что это какая-то нелепая оптимизация ...

Какое объяснение?

92:         ticks++;         // unsigned char ticks;
+0000009F:   91900104    LDS       R25,0x0104     Load direct from data space
+000000A1:   5F9F        SUBI      R25,0xFF       Subtract immediate
+000000A2:   93900104    STS       0x0104,R25     Store direct to data space
95:         if (ticks == 0) {
+000000A4:   2399        TST       R25            Test for Zero or Minus
+000000A5:   F009        BREQ      PC+0x02        Branch if equal
+000000A6:   C067        RJMP      PC+0x0068      Relative jump

В частности, почему вторая инструкция вычитает 0xFF из R25 вместо INC R25?

Ответы [ 2 ]

5 голосов
/ 27 августа 2009

Команда SUBI может использоваться для добавления / вычитания любой 8-битной константы в / из 8-битного значения. Он имеет ту же стоимость, что и INC, то есть размер инструкции и время выполнения. Поэтому SUBI предпочитает компилятор, потому что он более общий. Нет соответствующей инструкции ADDI, возможно потому, что она будет избыточной.

4 голосов
/ 27 августа 2009

tl; dr компилятор был разработан, чтобы использовать здесь более переносимое, эффективное и общее решение.

Наборы команд SUBI C (перенос) и H (половинный перенос) для использования с последующими инструкциями (в 8-битном AVR BTW нет ADDI таким образом, чтобы добавить непосредственное значение x, мы вычитаем -x из него), тогда как INC - нет. Поскольку оба SUBI & INC имеют длину 2 байта и выполняются в течение 1 такта, вы ничего не потеряете, используя SUBI - OTOH. Если вы используете счетчик 8-битного размера, вы можете легко определить, перевернулся (на BRCC / BRCS), и если у вас есть счетчик размером 16 или 32 бита, он позволяет увеличить его до очень простой способ - просто с INC, 0x00FF увеличится до 0x0000, поэтому вам нужно проверить, равен ли младший байт 0xFF перед INC ing. OTOH, с SUBI вы просто SUBI -1 младший байт, а затем ADC 0 для следующих байтов, гарантируя, что все потенциальные биты переноса учтены.

Дальнейшее чтение:

https://lists.gnu.org/archive/html/avr-gcc-list/2008-11/msg00029.html

http://avr -gcc-list.nongnu.narkive.com / SMMzdBkW / Foo-Subi-против-инк

...