Почему этот код генерируется avr-gcc и как он работает?

Это фрагмент дизассемблированного кода 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 ответа

Решение

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

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

SUBI наборы инструкций C (нести) и H (половина переноса) Флаги процессора для использования с последующими инструкциями (нет ADDI в 8-битном AVR BTW, так что добавить немедленное значение x мы вычитаем -x от этого), тогда как INC не. Поскольку оба SUBI & INC имеют длину 2 байта и выполняются в течение 1 такта, вы ничего не потеряете при использовании SUBI - OTOH, если вы используете 8-битный счетчик, вы можете легко определить, перевернулся ли он (BRCC / BRCS), и если у вас есть счетчик размером 16 или 32 бита, он позволяет увеличить его очень простым способом - просто INC, 0x00FF будет увеличен до 0x0000 так что вам нужно проверить, является ли младший байт 0xFF до INC ING. ОТОХ, с 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-vs-inc

Другие вопросы по тегам